feat(engine): add resources, events, and GamePlugin event routing

Introduces the plumbing layer for Phase 3: GameStateResource wraps
solitaire_core::GameState, DragState tracks in-progress drags, and
SyncStatusResource holds runtime sync status. GamePlugin routes
Draw/Move/Undo/NewGame request events into GameState and emits
StateChangedEvent and GameWonEvent for downstream systems.

Also adds the Phase 3 implementation plan under docs/superpowers/plans/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-04-23 16:15:38 -07:00
parent 3831fe691c
commit c393eab17d
8 changed files with 530 additions and 3 deletions
+55
View File
@@ -0,0 +1,55 @@
//! Bevy resources owned by the engine crate.
use bevy::math::Vec2;
use bevy::prelude::Resource;
use chrono::{DateTime, Utc};
use solitaire_core::game_state::GameState;
use solitaire_core::pile::PileType;
/// Wraps the currently active `GameState`. Single source of truth for the in-progress game.
#[derive(Resource, Debug, Clone)]
pub struct GameStateResource(pub GameState);
/// Tracks an in-progress drag operation.
///
/// When `cards` is empty there is no active drag. When non-empty, the listed cards
/// are being moved by the user and should be rendered at the cursor position.
#[derive(Resource, Debug, Clone, Default)]
pub struct DragState {
pub cards: Vec<u32>,
pub origin_pile: Option<PileType>,
pub cursor_offset: Vec2,
pub origin_z: f32,
}
impl DragState {
/// Returns true when no drag is currently in progress.
pub fn is_idle(&self) -> bool {
self.cards.is_empty()
}
/// Clears the drag state.
pub fn clear(&mut self) {
self.cards.clear();
self.origin_pile = None;
self.cursor_offset = Vec2::ZERO;
self.origin_z = 0.0;
}
}
/// Current sync activity — shown in the settings screen.
///
/// Defined here rather than in `solitaire_data` because it is a UI/runtime
/// status value, not part of the persistence layer.
#[derive(Debug, Clone, Default)]
pub enum SyncStatus {
#[default]
Idle,
Syncing,
LastSynced(DateTime<Utc>),
Error(String),
}
/// Bevy resource wrapping the current `SyncStatus`.
#[derive(Resource, Debug, Clone, Default)]
pub struct SyncStatusResource(pub SyncStatus);