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
+8 -13
View File
@@ -222,10 +222,7 @@ pub fn start_replay_playback(
/// [`start_replay_playback`] signature — leaves room to hook in
/// cleanup (e.g. despawning playback-only overlays) without a future
/// API break.
pub fn stop_replay_playback(
_commands: &mut Commands,
state: &mut ResMut<ReplayPlaybackState>,
) {
pub fn stop_replay_playback(_commands: &mut Commands, state: &mut ResMut<ReplayPlaybackState>) {
**state = ReplayPlaybackState::Inactive;
}
@@ -566,9 +563,9 @@ mod tests {
/// so we drive 200 ms steps and call `update` enough times to pass
/// the requested duration.
fn advance_by(app: &mut App, total_secs: f32) {
app.insert_resource(TimeUpdateStrategy::ManualDuration(
Duration::from_secs_f32(0.2),
));
app.insert_resource(TimeUpdateStrategy::ManualDuration(Duration::from_secs_f32(
0.2,
)));
let ticks = (total_secs / 0.2).ceil() as usize + 1;
for _ in 0..ticks {
app.update();
@@ -651,9 +648,7 @@ mod tests {
let state = app.world().resource::<ReplayPlaybackState>();
match state {
ReplayPlaybackState::Playing {
cursor,
replay: r,
..
cursor, replay: r, ..
} => {
assert_eq!(*cursor, 0);
assert_eq!(r.seed, replay.seed);
@@ -931,9 +926,9 @@ mod tests {
.add_systems(Update, collect_draws);
start_playback(&mut app, ten_draws_replay());
app.update();
app.insert_resource(TimeUpdateStrategy::ManualDuration(
Duration::from_secs_f32(tick_secs),
));
app.insert_resource(TimeUpdateStrategy::ManualDuration(Duration::from_secs_f32(
tick_secs,
)));
let ticks = (total_secs / tick_secs).ceil() as usize + 1;
for _ in 0..ticks {
app.update();