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:
@@ -38,7 +38,11 @@ pub fn score_flip() -> i32 {
|
||||
/// Subsequent recycles cost -100 (Draw-1) or -20 (Draw-3).
|
||||
/// `recycle_count` is the new total count **after** this recycle.
|
||||
pub fn score_recycle(recycle_count: u32, is_draw_three: bool) -> i32 {
|
||||
let (free, penalty) = if is_draw_three { (3_u32, -20_i32) } else { (1_u32, -100_i32) };
|
||||
let (free, penalty) = if is_draw_three {
|
||||
(3_u32, -20_i32)
|
||||
} else {
|
||||
(1_u32, -100_i32)
|
||||
};
|
||||
if recycle_count > free { penalty } else { 0 }
|
||||
}
|
||||
|
||||
@@ -58,7 +62,10 @@ mod tests {
|
||||
#[test]
|
||||
fn move_to_foundation_scores_ten() {
|
||||
assert_eq!(score_move(&PileType::Waste, &PileType::Foundation(2)), 10);
|
||||
assert_eq!(score_move(&PileType::Tableau(0), &PileType::Foundation(0)), 10);
|
||||
assert_eq!(
|
||||
score_move(&PileType::Tableau(0), &PileType::Foundation(0)),
|
||||
10
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -94,10 +101,12 @@ mod tests {
|
||||
#[test]
|
||||
fn foundation_to_tableau_penalises_fifteen() {
|
||||
// Moving a card back off a foundation (take_from_foundation rule) costs -15.
|
||||
assert_eq!(score_move(&PileType::Foundation(0), &PileType::Tableau(0)), -15);
|
||||
assert_eq!(
|
||||
score_move(&PileType::Foundation(0), &PileType::Tableau(0)),
|
||||
-15
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn move_to_stock_or_waste_scores_zero() {
|
||||
// These destinations are illegal moves in practice, but the function
|
||||
@@ -110,7 +119,10 @@ mod tests {
|
||||
fn time_bonus_is_capped_at_i32_max_for_huge_values() {
|
||||
// Very short elapsed time would overflow without the .min() guard.
|
||||
let bonus = compute_time_bonus(1);
|
||||
assert!(bonus >= 0, "time bonus must be non-negative after u64→i32 cast");
|
||||
assert!(
|
||||
bonus >= 0,
|
||||
"time bonus must be non-negative after u64→i32 cast"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user