From 45ef3a2058ae3bab89582c0fd4128dc6727f807f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 27 Apr 2026 01:02:05 +0000 Subject: [PATCH] fix(engine): reset weekly goals at app startup if the ISO week changed evaluate_weekly_goals only ran the roll on GameWonEvent, so stale goal progress from a prior week would linger until the player's next win. A new Startup system calls roll_weekly_goals_if_new_week on launch and persists immediately when the week has rolled over. Co-Authored-By: Claude Sonnet 4.6 --- solitaire_engine/src/weekly_goals_plugin.rs | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/solitaire_engine/src/weekly_goals_plugin.rs b/solitaire_engine/src/weekly_goals_plugin.rs index 142ff69..7c2eb29 100644 --- a/solitaire_engine/src/weekly_goals_plugin.rs +++ b/solitaire_engine/src/weekly_goals_plugin.rs @@ -27,6 +27,7 @@ impl Plugin for WeeklyGoalsPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() + .add_systems(Startup, roll_weekly_goals_on_startup) // Run after GameMutation (so GameWonEvent is available) and // ProgressUpdate (so we don't fight ProgressPlugin's add_xp). .add_systems( @@ -38,6 +39,22 @@ impl Plugin for WeeklyGoalsPlugin { } } +/// Rolls weekly-goal counters at startup so stale progress from a previous +/// week never shows in the UI when the player launches the game. +fn roll_weekly_goals_on_startup( + mut progress: ResMut, + path: Res, +) { + let week_key = current_iso_week_key(Local::now().date_naive()); + if progress.0.roll_weekly_goals_if_new_week(&week_key) { + if let Some(target) = &path.0 { + if let Err(e) = save_progress_to(target, &progress.0) { + warn!("failed to save progress after weekly reset on startup: {e}"); + } + } + } +} + fn evaluate_weekly_goals( mut wins: EventReader, game: Res, @@ -200,6 +217,35 @@ mod tests { assert!(fired.iter().any(|e| e.goal_id == "weekly_3_fast")); } + #[test] + fn stale_weekly_progress_is_cleared_on_startup() { + let mut app = headless_app(); + // Inject progress from a past week. + { + let mut p = app.world_mut().resource_mut::(); + p.0.weekly_goal_week_iso = Some("1970-W01".to_string()); + p.0.weekly_goal_progress + .insert("weekly_5_wins".to_string(), 3); + } + // A second Startup run (re-init) is hard to trigger directly; instead + // call the helper through a fresh app that starts with stale data. + // Here we simulate the effect: roll_weekly_goals_if_new_week clears. + let current_week = current_iso_week_key(Local::now().date_naive()); + let rolled = app + .world_mut() + .resource_mut::() + .0 + .roll_weekly_goals_if_new_week(¤t_week); + assert!(rolled, "expected stale week to trigger a roll"); + assert!( + app.world() + .resource::() + .0 + .weekly_goal_progress + .is_empty() + ); + } + #[test] fn weekly_goal_description_resolves_known_and_unknown() { assert_eq!(