From 912b08c7191db6f7b4b459a3da4c0cfd7b88bce7 Mon Sep 17 00:00:00 2001 From: funman300 Date: Fri, 1 May 2026 03:15:36 +0000 Subject: [PATCH] feat(engine): skip splash on subsequent launches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 1.6 s brand beat is delightful on first launch and tedious on every subsequent one. spawn_splash now reads SettingsResource and returns early when first_run_complete is true — the player has already seen the splash at least once and the onboarding flow that follows it, so dropping straight into gameplay is the right move. Reuses the existing first_run_complete signal rather than introducing a separate splash_seen field; the two states ("I've been here") line up naturally and avoid carrying a one-shot flag forever. The first run, a save reset (settings.json deleted), or a headless test fixture that doesn't register SettingsResource all still see the full splash — Option> defaults to "show" when absent, so the existing test fixture observes the same spawn it always did. Two new tests pin the split: splash_skipped_when_first_run_complete asserts no SplashRoot spawns when settings say so, and splash_still_shows_when_first_run_incomplete asserts the first-run path is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- solitaire_engine/src/splash_plugin.rs | 62 ++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/solitaire_engine/src/splash_plugin.rs b/solitaire_engine/src/splash_plugin.rs index 0aa079b..5b8b4b6 100644 --- a/solitaire_engine/src/splash_plugin.rs +++ b/solitaire_engine/src/splash_plugin.rs @@ -42,6 +42,7 @@ use bevy::input::touch::Touches; use bevy::prelude::*; use crate::font_plugin::FontResource; +use crate::settings_plugin::SettingsResource; use crate::ui_theme::{ ACCENT_PRIMARY, BG_BASE, MOTION_SPLASH_FADE_SECS, MOTION_SPLASH_TOTAL_SECS, TEXT_SECONDARY, TYPE_CAPTION, TYPE_DISPLAY, VAL_SPACE_2, Z_SPLASH, @@ -108,7 +109,25 @@ struct SplashSubtitle; /// at full alpha (the first `advance_splash` tick will overwrite the /// alpha based on age), centres a "Solitaire Quest" title in /// [`ACCENT_PRIMARY`], and pins a small build-version line below. -fn spawn_splash(mut commands: Commands, font_res: Option>) { +/// +/// **Skipped on subsequent launches.** If `SettingsResource` reports +/// `first_run_complete == true`, the player has already seen the brand +/// beat at least once and we go straight to gameplay — having to wait +/// 1.6 s on every launch wears thin fast. The splash still shows on +/// first run, after a save reset (settings.json deleted), and under +/// `MinimalPlugins` (no `SettingsResource` registered) so the test +/// fixture observes the same spawn it always did. +fn spawn_splash( + mut commands: Commands, + font_res: Option>, + settings: Option>, +) { + if let Some(settings) = settings.as_deref() + && settings.0.first_run_complete + { + return; + } + let font_handle = font_res.map(|f| f.0.clone()).unwrap_or_default(); let title_font = TextFont { font: font_handle.clone(), @@ -371,6 +390,47 @@ mod tests { ); } + #[test] + fn splash_skipped_when_first_run_complete() { + use solitaire_data::Settings; + let mut app = App::new(); + app.add_plugins(MinimalPlugins).add_plugins(SplashPlugin); + app.init_resource::>(); + app.init_resource::>(); + // Insert a SettingsResource that says "I've been here before" + // before any Startup system runs. spawn_splash should observe + // first_run_complete and decline to spawn the overlay. + app.insert_resource(SettingsResource(Settings { + first_run_complete: true, + ..Settings::default() + })); + app.update(); + assert_eq!( + count_splash_roots(&mut app), + 0, + "SplashRoot must NOT spawn on subsequent launches" + ); + } + + #[test] + fn splash_still_shows_when_first_run_incomplete() { + use solitaire_data::Settings; + let mut app = App::new(); + app.add_plugins(MinimalPlugins).add_plugins(SplashPlugin); + app.init_resource::>(); + app.init_resource::>(); + app.insert_resource(SettingsResource(Settings { + first_run_complete: false, + ..Settings::default() + })); + app.update(); + assert_eq!( + count_splash_roots(&mut app), + 1, + "SplashRoot must spawn for first-run players (first_run_complete = false)" + ); + } + #[test] fn splash_despawns_after_total_duration() { let mut app = headless_app();