refactor(app): extract build_app(), add CoreGamePlugin placeholder (closes #42, closes #44)

- Split run() into build_app(sync_provider) -> App and run()
- Add empty CoreGamePlugin registered in build_app()
- Issue #43 closed via API (main.rs already satisfies it)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
funman300
2026-05-27 16:41:40 -07:00
parent 5a71e2bc0a
commit 3885b334ec
3 changed files with 48 additions and 16 deletions
+30 -16
View File
@@ -29,17 +29,27 @@ use solitaire_data::{load_settings_from, provider_for_backend, settings_file_pat
use solitaire_engine::{ use solitaire_engine::{
register_theme_asset_sources, AchievementPlugin, AnalyticsPlugin, AnimationPlugin, AssetSourcesPlugin, register_theme_asset_sources, AchievementPlugin, AnalyticsPlugin, AnimationPlugin, AssetSourcesPlugin,
AudioPlugin, AutoCompletePlugin, AvatarPlugin, CardAnimationPlugin, CardPlugin, ChallengePlugin, AudioPlugin, AutoCompletePlugin, AvatarPlugin, CardAnimationPlugin, CardPlugin, ChallengePlugin,
CursorPlugin, DailyChallengePlugin, DiagnosticsHudPlugin, DifficultyPlugin, FeedbackAnimPlugin, CoreGamePlugin, CursorPlugin, DailyChallengePlugin, DiagnosticsHudPlugin, DifficultyPlugin,
FontPlugin, GamePlugin, HelpPlugin, HomePlugin, HudPlugin, InputPlugin, LeaderboardPlugin, FeedbackAnimPlugin, FontPlugin, GamePlugin, HelpPlugin, HomePlugin, HudPlugin, InputPlugin,
OnboardingPlugin, PausePlugin, PlayBySeedPlugin, ProfilePlugin, ProgressPlugin, LeaderboardPlugin, OnboardingPlugin, PausePlugin, PlayBySeedPlugin, ProfilePlugin,
RadialMenuPlugin, ReplayOverlayPlugin, ReplayPlaybackPlugin, SafeAreaInsetsPlugin, ProgressPlugin, RadialMenuPlugin, ReplayOverlayPlugin, ReplayPlaybackPlugin,
SelectionPlugin, SettingsPlugin, SafeAreaInsetsPlugin, SelectionPlugin, SettingsPlugin, SplashPlugin, StatsPlugin, SyncPlugin,
SplashPlugin, StatsPlugin, SyncPlugin, SyncSetupPlugin, TablePlugin, ThemePlugin, ThemeRegistryPlugin, SyncProvider, SyncSetupPlugin, TablePlugin, ThemePlugin, ThemeRegistryPlugin, TimeAttackPlugin,
TimeAttackPlugin, UiFocusPlugin, UiModalPlugin, UiTooltipPlugin, WeeklyGoalsPlugin, UiFocusPlugin, UiModalPlugin, UiTooltipPlugin, WeeklyGoalsPlugin, WinSummaryPlugin,
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<dyn SyncProvider + Send + Sync>) -> 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 /// Called from both the desktop `bin` target's `main` shim and (on
/// Android) the platform's NativeActivity / GameActivity glue. /// 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 let settings = load_settings();
// 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 sync_provider = provider_for_backend(&settings.sync_backend); 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<dyn SyncProvider + Send + Sync>,
) -> App {
// Restore the previous window geometry if the player has one saved. // Restore the previous window geometry if the player has one saved.
// Otherwise open at the platform default (1280×800, centred on the // Otherwise open at the platform default (1280×800, centred on the
@@ -214,7 +227,8 @@ pub fn run() {
.add_plugins(UiFocusPlugin) .add_plugins(UiFocusPlugin)
.add_plugins(UiTooltipPlugin) .add_plugins(UiTooltipPlugin)
.add_plugins(SplashPlugin) .add_plugins(SplashPlugin)
.add_plugins(DiagnosticsHudPlugin); .add_plugins(DiagnosticsHudPlugin)
.add_plugins(CoreGamePlugin);
// On Android the default WinitSettings use UpdateMode::Continuous for // On Android the default WinitSettings use UpdateMode::Continuous for
// the focused window, which means Bevy renders as fast as possible even // 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.add_systems(Update, apply_smart_default_window_size);
} }
app.run(); app
} }
/// One-shot Update system that runs only on launches without saved /// One-shot Update system that runs only on launches without saved
+15
View File
@@ -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.
}
}
+3
View File
@@ -19,6 +19,7 @@ pub mod daily_challenge_plugin;
pub mod difficulty_plugin; pub mod difficulty_plugin;
pub mod diagnostics_hud; pub mod diagnostics_hud;
pub mod events; pub mod events;
pub mod core_game_plugin;
pub mod game_plugin; pub mod game_plugin;
pub mod help_plugin; pub mod help_plugin;
pub mod home_plugin; pub mod home_plugin;
@@ -66,6 +67,7 @@ pub use analytics_plugin::{AnalyticsPlugin, AnalyticsResource};
pub use challenge_plugin::{ pub use challenge_plugin::{
challenge_progress_label, ChallengeAdvancedEvent, ChallengePlugin, CHALLENGE_UNLOCK_LEVEL, challenge_progress_label, ChallengeAdvancedEvent, ChallengePlugin, CHALLENGE_UNLOCK_LEVEL,
}; };
pub use core_game_plugin::CoreGamePlugin;
pub use daily_challenge_plugin::{ pub use daily_challenge_plugin::{
DailyChallengeCompletedEvent, DailyChallengePlugin, DailyChallengeResource, DailyChallengeCompletedEvent, DailyChallengePlugin, DailyChallengeResource,
}; };
@@ -154,6 +156,7 @@ pub use stats_plugin::{
ReplayPrevButton, ReplaySelectorCaption, SelectedReplayIndex, StatsPlugin, StatsResource, ReplayPrevButton, ReplaySelectorCaption, SelectedReplayIndex, StatsPlugin, StatsResource,
StatsScreen, StatsUpdate, WatchReplayButton, StatsScreen, StatsUpdate, WatchReplayButton,
}; };
pub use solitaire_data::SyncProvider;
pub use sync_plugin::{SyncPlugin, SyncProviderResource}; pub use sync_plugin::{SyncPlugin, SyncProviderResource};
pub use sync_setup_plugin::SyncSetupPlugin; pub use sync_setup_plugin::SyncSetupPlugin;
pub use ui_focus::{Disabled, FocusGroup, Focusable, FocusedButton, UiFocusPlugin}; pub use ui_focus::{Disabled, FocusGroup, Focusable, FocusedButton, UiFocusPlugin};