835a48fe9d
Build and Deploy / build-and-push (push) Failing after 58s
Adds a new `solitaire_web` crate that compiles the full `solitaire_engine` to `wasm32-unknown-unknown` and renders to a `<canvas id="bevy-canvas">` element in `play.html` — the same ECS code path as desktop and Android. Changes to enable the WASM target: - .cargo/config.toml: add wasm32-unknown-unknown rustflags for getrandom - Workspace Cargo.toml: add solitaire_web member - solitaire_data/Cargo.toml: gate tokio/reqwest/dirs/keyring to non-wasm - solitaire_data/src: add wasm32 branch to data_dir() (returns None); cfg-gate sync_client network types, auth_tokens, matomo_client - solitaire_engine/Cargo.toml: gate tokio/reqwest/kira/arboard/dirs/zip to non-wasm (mio/cpal/arboard don't compile for wasm32-unknown-unknown) - solitaire_engine/src/lib.rs: cfg-gate module declarations and re-exports for analytics, audio, sync, sync_setup, avatar, leaderboard plugins - solitaire_engine/src/core_game_plugin.rs: cfg-gate plugin registrations that require TokioRuntime (audio, sync, analytics, leaderboard, avatar) - solitaire_engine/src/resources.rs: cfg-gate TokioRuntimeResource - solitaire_engine/src/game_plugin.rs: cfg-gate std::fs::remove_file (x10) - solitaire_engine/src/theme/mod.rs: cfg-gate importer module (uses dirs+zip) - solitaire_engine/src/settings_plugin.rs: cfg-gate theme ZIP import UI - solitaire_engine/src/assets/sources.rs: cfg-gate FileAssetReader/user_theme_dir - solitaire_engine/src/auto_complete_plugin.rs: cfg-gate audio system - solitaire_engine/src/daily_challenge_plugin.rs: cfg-gate server fetch - solitaire_engine/src/hud_plugin.rs: cfg-gate AvatarResource import - solitaire_engine/src/profile_plugin.rs: cfg-gate AvatarResource import - solitaire_server/web/play.html: minimal HTML canvas shell - solitaire_web/: new crate (Cargo.toml + src/lib.rs) - build_wasm.sh: add Bevy WASM build step (cargo + wasm-bindgen + wasm-opt) All tests pass; clippy --workspace -- -D warnings clean; native build (solitaire_engine, solitaire_app) unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
133 lines
5.5 KiB
Rust
133 lines
5.5 KiB
Rust
//! Central plugin that groups all gameplay plugins.
|
|
//!
|
|
//! Register [`CoreGamePlugin`] once in the app instead of the individual
|
|
//! plugins. Plugin registration lives here rather than directly in the app
|
|
//! entry point.
|
|
|
|
use std::sync::Mutex;
|
|
|
|
use bevy::prelude::*;
|
|
|
|
use crate::platform::{
|
|
ClipboardBackendResource, StorageBackendResource, default_clipboard_backend,
|
|
default_storage_backend,
|
|
};
|
|
use crate::{
|
|
AchievementPlugin, AnimationPlugin, AssetSourcesPlugin, AutoCompletePlugin,
|
|
CardAnimationPlugin, CardPlugin, ChallengePlugin, CursorPlugin, DailyChallengePlugin,
|
|
DiagnosticsHudPlugin, DifficultyPlugin, FeedbackAnimPlugin, FontPlugin, GamePlugin, HelpPlugin,
|
|
HomePlugin, HudPlugin, InputPlugin, OnboardingPlugin, PausePlugin, PlayBySeedPlugin,
|
|
ProfilePlugin, ProgressPlugin, RadialMenuPlugin, ReplayOverlayPlugin, ReplayPlaybackPlugin,
|
|
SafeAreaInsetsPlugin, SelectionPlugin, SettingsPlugin, SplashPlugin, StatsPlugin, SyncProvider,
|
|
TablePlugin, ThemePlugin, ThemeRegistryPlugin, TimeAttackPlugin, TouchSelectionPlugin,
|
|
UiFocusPlugin, UiModalPlugin, UiTooltipPlugin, WeeklyGoalsPlugin, WinSummaryPlugin,
|
|
};
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
use crate::{
|
|
AnalyticsPlugin, AudioPlugin, AvatarPlugin, LeaderboardPlugin, SyncPlugin, SyncSetupPlugin,
|
|
};
|
|
|
|
/// Groups all Ferrous Solitaire gameplay plugins.
|
|
pub struct CoreGamePlugin {
|
|
sync_provider: Mutex<Option<Box<dyn SyncProvider + Send + Sync>>>,
|
|
}
|
|
|
|
impl CoreGamePlugin {
|
|
/// Create a new [`CoreGamePlugin`] with the sync provider used by [`SyncPlugin`].
|
|
pub fn new(sync_provider: Box<dyn SyncProvider + Send + Sync>) -> Self {
|
|
Self {
|
|
sync_provider: Mutex::new(Some(sync_provider)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Plugin for CoreGamePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
let mut sync_provider = match self.sync_provider.lock() {
|
|
Ok(guard) => guard,
|
|
Err(poisoned) => poisoned.into_inner(),
|
|
};
|
|
#[cfg_attr(target_arch = "wasm32", allow(unused_variables))]
|
|
let sync_provider = sync_provider
|
|
.take()
|
|
.expect("CoreGamePlugin::build called twice");
|
|
|
|
match default_storage_backend() {
|
|
Ok(storage) => {
|
|
app.insert_resource(StorageBackendResource(storage));
|
|
}
|
|
Err(err) => {
|
|
warn!("storage: failed to initialize platform backend: {err}");
|
|
}
|
|
}
|
|
match default_clipboard_backend() {
|
|
Ok(clipboard) => {
|
|
app.insert_resource(ClipboardBackendResource(clipboard));
|
|
}
|
|
Err(err) => {
|
|
warn!("clipboard: failed to initialize platform backend: {err}");
|
|
}
|
|
}
|
|
|
|
app.add_plugins(AssetSourcesPlugin)
|
|
.add_plugins(ThemePlugin)
|
|
.add_plugins(ThemeRegistryPlugin)
|
|
.add_plugins(FontPlugin)
|
|
.add_plugins(GamePlugin)
|
|
.add_plugins(TablePlugin)
|
|
.add_plugins(CardPlugin)
|
|
// Cursor-icon feedback is desktop-only; Android has no pointer cursor.
|
|
// The drop-target highlight systems (update_drop_highlights,
|
|
// update_drop_target_overlays) live in CursorPlugin but ARE useful
|
|
// on Android — they've been left running because their Bevy system
|
|
// params compile and function on Android; only the CursorIcon insert
|
|
// is inert. Gate the whole plugin if the cursor APIs ever cause
|
|
// Android linker issues; for now it's harmless to leave it registered.
|
|
.add_plugins(CursorPlugin)
|
|
.add_plugins(InputPlugin)
|
|
.add_plugins(RadialMenuPlugin)
|
|
.add_plugins(SelectionPlugin)
|
|
.add_plugins(TouchSelectionPlugin)
|
|
.add_plugins(AnimationPlugin)
|
|
.add_plugins(FeedbackAnimPlugin)
|
|
.add_plugins(CardAnimationPlugin)
|
|
.add_plugins(AutoCompletePlugin)
|
|
.add_plugins(ReplayPlaybackPlugin)
|
|
.add_plugins(ReplayOverlayPlugin)
|
|
.add_plugins(StatsPlugin::default())
|
|
.add_plugins(ProgressPlugin::default())
|
|
.add_plugins(AchievementPlugin::default())
|
|
.add_plugins(DailyChallengePlugin)
|
|
.add_plugins(WeeklyGoalsPlugin)
|
|
.add_plugins(ChallengePlugin)
|
|
.add_plugins(PlayBySeedPlugin)
|
|
.add_plugins(DifficultyPlugin)
|
|
.add_plugins(TimeAttackPlugin)
|
|
.add_plugins(SafeAreaInsetsPlugin)
|
|
.add_plugins(HudPlugin)
|
|
.add_plugins(HelpPlugin)
|
|
.add_plugins(HomePlugin::default())
|
|
.add_plugins(ProfilePlugin)
|
|
.add_plugins(PausePlugin)
|
|
.add_plugins(SettingsPlugin::default())
|
|
.add_plugins(OnboardingPlugin)
|
|
.add_plugins(WinSummaryPlugin)
|
|
.add_plugins(UiModalPlugin)
|
|
.add_plugins(UiFocusPlugin)
|
|
.add_plugins(UiTooltipPlugin)
|
|
.add_plugins(SplashPlugin)
|
|
.add_plugins(DiagnosticsHudPlugin);
|
|
|
|
// Plugins that use kira/cpal audio or multi-threaded Tokio are not
|
|
// compatible with the single-threaded wasm32 runtime. Gate them out
|
|
// so the browser build boots silently and without a sync backend.
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
app.add_plugins(AvatarPlugin)
|
|
.add_plugins(AudioPlugin)
|
|
.add_plugins(SyncPlugin::new(sync_provider))
|
|
.add_plugins(SyncSetupPlugin)
|
|
.add_plugins(AnalyticsPlugin)
|
|
.add_plugins(LeaderboardPlugin);
|
|
}
|
|
}
|