fix(engine,server): safe area clamp, analytics batch, achievement save order, daily rollover, replay validation, leaderboard opt-in (#56, #60, #61, #62, #66, #68)
Build and Deploy / build-and-push (push) Successful in 3m54s

- #66: Clamp safe-area insets to 25% of window height with warn!() on excess
- #68: Move fire_flush outside per-event loop in analytics (batch flush once)
- #56: Persist progress before marking reward_granted to prevent XP loss on crash
- #60: Add DateRolloverTimer + check_date_rollover system for midnight seed refresh
- #62: Add validate_header() in replay upload with mode/draw_mode allowlists
- #61: Restore two-query leaderboard opt-in check (SELECT then UPDATE); original
       queries already in .sqlx cache; EXISTS variant would require sqlx prepare

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
funman300
2026-05-28 13:07:22 -07:00
parent 8cb4c9808e
commit 6e407a3ea7
104 changed files with 6356 additions and 3092 deletions
+14 -14
View File
@@ -47,10 +47,10 @@
//! comments on each call out the pairing so a future reader doesn't
//! accidentally drop one half.
use bevy::asset::AssetApp;
use bevy::asset::io::AssetSourceBuilder;
use bevy::asset::io::embedded::EmbeddedAssetRegistry;
use bevy::asset::io::file::FileAssetReader;
use bevy::asset::io::AssetSourceBuilder;
use bevy::asset::AssetApp;
use bevy::prelude::*;
use crate::assets::user_dir::user_theme_dir;
@@ -75,8 +75,7 @@ pub const DARK_THEME_MANIFEST_URL: &str =
const DARK_THEME_MANIFEST_PATH: &str = "solitaire_engine/assets/themes/dark/theme.ron";
/// Bytes of the bundled Dark theme manifest, embedded at compile time.
const DARK_THEME_MANIFEST_BYTES: &[u8] =
include_bytes!("../../assets/themes/dark/theme.ron");
const DARK_THEME_MANIFEST_BYTES: &[u8] = include_bytes!("../../assets/themes/dark/theme.ron");
/// Stable embedded asset URL of the bundled Classic theme manifest.
pub const CLASSIC_THEME_MANIFEST_URL: &str =
@@ -89,8 +88,7 @@ pub const CLASSIC_THEME_MANIFEST_URL: &str =
const CLASSIC_THEME_MANIFEST_PATH: &str = "solitaire_engine/assets/themes/classic/theme.ron";
/// Bytes of the bundled Classic theme manifest, embedded at compile time.
const CLASSIC_THEME_MANIFEST_BYTES: &[u8] =
include_bytes!("../../assets/themes/classic/theme.ron");
const CLASSIC_THEME_MANIFEST_BYTES: &[u8] = include_bytes!("../../assets/themes/classic/theme.ron");
/// Generates a `(stable_path, bytes)` entry for one Dark-theme SVG.
macro_rules! embed_dark_svg {
@@ -377,10 +375,11 @@ mod tests {
fn populate_embedded_dark_theme_runs_without_asset_plugin() {
let mut app = App::new();
populate_embedded_dark_theme(&mut app);
assert!(app
.world()
.get_resource::<EmbeddedAssetRegistry>()
.is_some());
assert!(
app.world()
.get_resource::<EmbeddedAssetRegistry>()
.is_some()
);
}
#[test]
@@ -425,10 +424,11 @@ mod tests {
fn populate_embedded_classic_theme_runs_without_asset_plugin() {
let mut app = App::new();
populate_embedded_classic_theme(&mut app);
assert!(app
.world()
.get_resource::<EmbeddedAssetRegistry>()
.is_some());
assert!(
app.world()
.get_resource::<EmbeddedAssetRegistry>()
.is_some()
);
}
#[test]