feat(engine): add AchievementPlugin with persistent unlock tracking
On GameWonEvent, build an AchievementContext from StatsResource + GameState + wall-clock hour, evaluate ALL_ACHIEVEMENTS, flip newly-satisfied records to unlocked, persist atomically, and emit AchievementUnlockedEvent for each new unlock. AnimationPlugin's toast resolves the event's ID to the achievement's display name via achievement_plugin::display_name_for. Introduces StatsUpdate system set so AchievementPlugin can reliably run after StatsResource reflects the win. AchievementPlugin::headless() used in tests to avoid touching ~/.local/share/solitaire_quest/achievements.json. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,11 @@ pub struct StatsResource(pub StatsSnapshot);
|
||||
#[derive(Resource, Debug, Clone)]
|
||||
pub struct StatsStoragePath(pub Option<PathBuf>);
|
||||
|
||||
/// System set for the stats-mutating systems. Downstream plugins that read
|
||||
/// `StatsResource` after a win/abandon should run `.after(StatsUpdate)`.
|
||||
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct StatsUpdate;
|
||||
|
||||
/// Marker component on the stats overlay root node.
|
||||
#[derive(Component, Debug)]
|
||||
pub struct StatsScreen;
|
||||
@@ -63,11 +68,17 @@ impl Plugin for StatsPlugin {
|
||||
.add_event::<NewGameRequestEvent>()
|
||||
// record_abandoned must read `move_count` BEFORE handle_new_game
|
||||
// clobbers it with a fresh game.
|
||||
.add_systems(Update, update_stats_on_new_game.before(GameMutation))
|
||||
.add_systems(
|
||||
Update,
|
||||
(update_stats_on_win, toggle_stats_screen).after(GameMutation),
|
||||
);
|
||||
update_stats_on_new_game
|
||||
.before(GameMutation)
|
||||
.in_set(StatsUpdate),
|
||||
)
|
||||
.add_systems(
|
||||
Update,
|
||||
update_stats_on_win.after(GameMutation).in_set(StatsUpdate),
|
||||
)
|
||||
.add_systems(Update, toggle_stats_screen.after(GameMutation));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user