diff --git a/solitaire_app/src/lib.rs b/solitaire_app/src/lib.rs index 840b445..f86373e 100644 --- a/solitaire_app/src/lib.rs +++ b/solitaire_app/src/lib.rs @@ -29,17 +29,27 @@ use solitaire_data::{load_settings_from, provider_for_backend, settings_file_pat use solitaire_engine::{ register_theme_asset_sources, AchievementPlugin, AnalyticsPlugin, AnimationPlugin, AssetSourcesPlugin, AudioPlugin, AutoCompletePlugin, AvatarPlugin, CardAnimationPlugin, CardPlugin, ChallengePlugin, - CursorPlugin, DailyChallengePlugin, DiagnosticsHudPlugin, DifficultyPlugin, FeedbackAnimPlugin, - FontPlugin, GamePlugin, HelpPlugin, HomePlugin, HudPlugin, InputPlugin, LeaderboardPlugin, - OnboardingPlugin, PausePlugin, PlayBySeedPlugin, ProfilePlugin, ProgressPlugin, - RadialMenuPlugin, ReplayOverlayPlugin, ReplayPlaybackPlugin, SafeAreaInsetsPlugin, - SelectionPlugin, SettingsPlugin, - SplashPlugin, StatsPlugin, SyncPlugin, SyncSetupPlugin, TablePlugin, ThemePlugin, ThemeRegistryPlugin, - TimeAttackPlugin, UiFocusPlugin, UiModalPlugin, UiTooltipPlugin, WeeklyGoalsPlugin, - WinSummaryPlugin, + CoreGamePlugin, CursorPlugin, DailyChallengePlugin, DiagnosticsHudPlugin, DifficultyPlugin, + FeedbackAnimPlugin, FontPlugin, GamePlugin, HelpPlugin, HomePlugin, HudPlugin, InputPlugin, + LeaderboardPlugin, OnboardingPlugin, PausePlugin, PlayBySeedPlugin, ProfilePlugin, + ProgressPlugin, RadialMenuPlugin, ReplayOverlayPlugin, ReplayPlaybackPlugin, + SafeAreaInsetsPlugin, SelectionPlugin, SettingsPlugin, SplashPlugin, StatsPlugin, SyncPlugin, + SyncProvider, SyncSetupPlugin, TablePlugin, ThemePlugin, ThemeRegistryPlugin, TimeAttackPlugin, + UiFocusPlugin, UiModalPlugin, UiTooltipPlugin, WeeklyGoalsPlugin, WinSummaryPlugin, }; -/// App entry point — builds and runs the Bevy app. +fn load_settings() -> Settings { + settings_file_path() + .map(|p| load_settings_from(&p)) + .unwrap_or_default() +} + +/// Build the Bevy app without entering the event loop. +pub fn build_app(sync_provider: Box) -> App { + build_app_with_settings(load_settings(), sync_provider) +} + +/// App entry point — configures runtime services, builds, and runs the app. /// /// Called from both the desktop `bin` target's `main` shim and (on /// Android) the platform's NativeActivity / GameActivity glue. @@ -68,12 +78,15 @@ pub fn run() { ); } - // Load settings before building the app so we can construct the right - // sync provider. Falls back to defaults if no settings file exists yet. - let settings: Settings = settings_file_path() - .map(|p| load_settings_from(&p)) - .unwrap_or_default(); + let settings = load_settings(); let sync_provider = provider_for_backend(&settings.sync_backend); + build_app_with_settings(settings, sync_provider).run(); +} + +fn build_app_with_settings( + settings: Settings, + sync_provider: Box, +) -> App { // Restore the previous window geometry if the player has one saved. // Otherwise open at the platform default (1280×800, centred on the @@ -214,7 +227,8 @@ pub fn run() { .add_plugins(UiFocusPlugin) .add_plugins(UiTooltipPlugin) .add_plugins(SplashPlugin) - .add_plugins(DiagnosticsHudPlugin); + .add_plugins(DiagnosticsHudPlugin) + .add_plugins(CoreGamePlugin); // On Android the default WinitSettings use UpdateMode::Continuous for // the focused window, which means Bevy renders as fast as possible even @@ -257,7 +271,7 @@ pub fn run() { app.add_systems(Update, apply_smart_default_window_size); } - app.run(); + app } /// One-shot Update system that runs only on launches without saved diff --git a/solitaire_engine/src/core_game_plugin.rs b/solitaire_engine/src/core_game_plugin.rs new file mode 100644 index 0000000..56f1119 --- /dev/null +++ b/solitaire_engine/src/core_game_plugin.rs @@ -0,0 +1,15 @@ +//! Central plugin that groups all gameplay systems. +//! +//! Register [`CoreGamePlugin`] once in the app instead of the individual +//! plugins. Systems are added here rather than directly in the app entry point. + +use bevy::prelude::*; + +/// Groups all Ferrous Solitaire gameplay plugins. +pub struct CoreGamePlugin; + +impl Plugin for CoreGamePlugin { + fn build(&self, _app: &mut App) { + // Gameplay systems will be migrated here in follow-up issues. + } +} diff --git a/solitaire_engine/src/lib.rs b/solitaire_engine/src/lib.rs index 79a7a93..71a678b 100644 --- a/solitaire_engine/src/lib.rs +++ b/solitaire_engine/src/lib.rs @@ -19,6 +19,7 @@ pub mod daily_challenge_plugin; pub mod difficulty_plugin; pub mod diagnostics_hud; pub mod events; +pub mod core_game_plugin; pub mod game_plugin; pub mod help_plugin; pub mod home_plugin; @@ -66,6 +67,7 @@ pub use analytics_plugin::{AnalyticsPlugin, AnalyticsResource}; pub use challenge_plugin::{ challenge_progress_label, ChallengeAdvancedEvent, ChallengePlugin, CHALLENGE_UNLOCK_LEVEL, }; +pub use core_game_plugin::CoreGamePlugin; pub use daily_challenge_plugin::{ DailyChallengeCompletedEvent, DailyChallengePlugin, DailyChallengeResource, }; @@ -154,6 +156,7 @@ pub use stats_plugin::{ ReplayPrevButton, ReplaySelectorCaption, SelectedReplayIndex, StatsPlugin, StatsResource, StatsScreen, StatsUpdate, WatchReplayButton, }; +pub use solitaire_data::SyncProvider; pub use sync_plugin::{SyncPlugin, SyncProviderResource}; pub use sync_setup_plugin::SyncSetupPlugin; pub use ui_focus::{Disabled, FocusGroup, Focusable, FocusedButton, UiFocusPlugin};