fix(multi): resolve 26 bugs found in comprehensive codebase review
Build and Deploy / build-and-push (push) Successful in 3m40s
Build and Deploy / build-and-push (push) Successful in 3m40s
Core fixes (issues #12, #13, #22): - #12: undo now preserves score delta instead of restoring snapshot score - #13: take_from_foundation defaults to false (non-standard house rule) - #22: check_win validates full suit sequence, not just card count Engine fixes: - #8: replay keyboard input guard against non-replay state - #9: help modal scrims.is_empty() guard added - #10: settings modal scrims.is_empty() guard added - #11: sync_plugin builds payload at poll time (not task-spawn time) - #14: server replay mode case-sensitivity fix ("Classic") - #15: play_by_seed_plugin confirmed flag set to true on launch - #16: replay back-step debounce via Local<bool> + StateChangedEvent; register StateChangedEvent in ReplayOverlayPlugin (fixes 52 tests) - #17: time-attack timer ignores win-summary overlay - #18: HUD dropdown glyphs U+25BE → U+2193 (FiraMono-safe arrow) - #19: theme plugin applies immediate visual update on A→B→A switch - #20: SyncAuthError / SyncBusyOverlay split into separate entities so auth errors are visible after busy overlay is hidden - #21: handle_forfeit ordered before update_stats_on_new_game - #23: server merge uses correct avg_time_seconds and games_lost math - #24: win_summary migrated to ModalScrim pattern - #25: card_animation apply_deferred between animation systems - #26: cursor_plugin HashMap access uses .get() with fallback - #27: auto_complete mid-sequence deactivation guard - #28: feedback_anim SettleAnim ordered before FoundationFlourish - #29: achievement_plugin iterates all win events; adds scrims guard - #30: leaderboard modal scrims.is_empty() guard added - #31: server auth tmp file cleanup on rename failure - #32: sync_setup modal scrims.is_empty() guard added - #33: font_plugin uses match fallback; TokioRuntimeResource graceful current-thread fallback on runtime init failure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use bevy::math::Vec2;
|
||||
use bevy::prelude::Resource;
|
||||
use bevy::prelude::{warn, Resource};
|
||||
use chrono::{DateTime, Utc};
|
||||
use solitaire_core::game_state::GameState;
|
||||
use solitaire_core::pile::PileType;
|
||||
@@ -131,15 +131,48 @@ pub struct GameInputConsumedResource(pub bool);
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct TokioRuntimeResource(pub Arc<tokio::runtime::Runtime>);
|
||||
|
||||
impl Default for TokioRuntimeResource {
|
||||
fn default() -> Self {
|
||||
// Building the Tokio runtime is startup-time initialization; failure
|
||||
// here means the OS refused to create threads, which is unrecoverable.
|
||||
impl TokioRuntimeResource {
|
||||
/// Attempts to build the shared multi-threaded Tokio runtime.
|
||||
///
|
||||
/// Returns `Err` if the OS refuses to create worker threads (e.g. resource
|
||||
/// limits on Android). Callers should log the error and disable sync
|
||||
/// features rather than panicking.
|
||||
pub fn new() -> Result<Self, tokio::io::Error> {
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(2)
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("failed to build shared Tokio runtime");
|
||||
Self(Arc::new(rt))
|
||||
.build()?;
|
||||
Ok(Self(Arc::new(rt)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TokioRuntimeResource {
|
||||
fn default() -> Self {
|
||||
// Try multi-threaded first; fall back to current-thread (single
|
||||
// worker) if the OS refuses to create additional threads. Neither
|
||||
// path uses `.expect()` so this never panics at startup.
|
||||
match tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(2)
|
||||
.enable_all()
|
||||
.build()
|
||||
{
|
||||
Ok(rt) => Self(Arc::new(rt)),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"sync: failed to build multi-thread Tokio runtime ({e}); \
|
||||
falling back to current-thread runtime"
|
||||
);
|
||||
// current_thread runtime never spawns OS threads, so it
|
||||
// succeeds even under tight sandboxing.
|
||||
let rt = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect(
|
||||
"current-thread Tokio runtime failed — \
|
||||
the process cannot do any async I/O",
|
||||
);
|
||||
Self(Arc::new(rt))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user