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
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:
@@ -11,9 +11,9 @@ pub mod svg_loader;
|
||||
pub mod user_dir;
|
||||
|
||||
pub use sources::{
|
||||
AssetSourcesPlugin, CLASSIC_THEME_MANIFEST_URL, DARK_THEME_MANIFEST_URL, USER_THEMES,
|
||||
bundled_theme_url, classic_theme_svg_bytes, dark_theme_svg_bytes,
|
||||
populate_embedded_classic_theme, populate_embedded_dark_theme, register_theme_asset_sources,
|
||||
AssetSourcesPlugin, CLASSIC_THEME_MANIFEST_URL, DARK_THEME_MANIFEST_URL, USER_THEMES,
|
||||
};
|
||||
pub use svg_loader::{rasterize_svg, SvgLoader, SvgLoaderError, SvgLoaderSettings};
|
||||
pub use svg_loader::{SvgLoader, SvgLoaderError, SvgLoaderSettings, rasterize_svg};
|
||||
pub use user_dir::{set_user_theme_dir, user_theme_dir};
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -248,8 +248,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn rasterizes_svg_with_unmatched_font_family() {
|
||||
let image =
|
||||
rasterize_svg(TEST_SVG_WITH_TEXT, UVec2::new(64, 96)).expect("rasterisation");
|
||||
let image = rasterize_svg(TEST_SVG_WITH_TEXT, UVec2::new(64, 96)).expect("rasterisation");
|
||||
assert_eq!(image.size().x, 64);
|
||||
assert_eq!(image.size().y, 96);
|
||||
}
|
||||
@@ -262,9 +261,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn pixmap_data_is_rgba_with_target_byte_count() {
|
||||
let image =
|
||||
rasterize_svg(TEST_SVG, UVec2::new(32, 48)).expect("rasterisation");
|
||||
let pixels = image.data.as_ref().expect("rasterised image carries pixel data");
|
||||
let image = rasterize_svg(TEST_SVG, UVec2::new(32, 48)).expect("rasterisation");
|
||||
let pixels = image
|
||||
.data
|
||||
.as_ref()
|
||||
.expect("rasterised image carries pixel data");
|
||||
// 32 × 48 × 4 (RGBA bytes) = 6144 bytes
|
||||
assert_eq!(pixels.len(), 32 * 48 * 4);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,10 @@ mod tests {
|
||||
// user's `$HOME` on desktop, but it must at least be a
|
||||
// non-empty path with a parent component.
|
||||
let dir = detected_platform_data_dir();
|
||||
assert!(dir.parent().is_some(), "data dir {dir:?} should be absolute");
|
||||
assert!(
|
||||
dir.parent().is_some(),
|
||||
"data dir {dir:?} should be absolute"
|
||||
);
|
||||
}
|
||||
|
||||
// The OnceLock-based override is intentionally NOT covered here:
|
||||
|
||||
Reference in New Issue
Block a user