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:
@@ -183,7 +183,12 @@ pub struct Layout {
|
||||
/// - Top row (stock, waste, 4 foundations) aligns with tableau columns
|
||||
/// 0, 1, 3, 4, 5, 6 — column 2 is intentionally empty to separate the
|
||||
/// waste/stock cluster from the foundations.
|
||||
pub fn compute_layout(window: Vec2, safe_area_top: f32, safe_area_bottom: f32, hud_visible: bool) -> Layout {
|
||||
pub fn compute_layout(
|
||||
window: Vec2,
|
||||
safe_area_top: f32,
|
||||
safe_area_bottom: f32,
|
||||
hud_visible: bool,
|
||||
) -> Layout {
|
||||
let window = window.max(MIN_WINDOW);
|
||||
let band_h = if hud_visible { HUD_BAND_HEIGHT } else { 0.0 };
|
||||
|
||||
@@ -213,7 +218,8 @@ pub fn compute_layout(window: Vec2, safe_area_top: f32, safe_area_bottom: f32, h
|
||||
|
||||
let fan_factor = 1.0 + (MAX_TABLEAU_CARDS - 1.0) * TABLEAU_FAN_FRAC;
|
||||
let height_denom = 0.5 + (1.0 + fan_factor + VERTICAL_GAP_FRAC) * CARD_ASPECT;
|
||||
let card_width_height_based = (window.y - safe_area_top - effective_safe_bottom - band_h).max(0.0) / height_denom;
|
||||
let card_width_height_based =
|
||||
(window.y - safe_area_top - effective_safe_bottom - band_h).max(0.0) / height_denom;
|
||||
|
||||
let card_width = card_width_width_based.min(card_width_height_based);
|
||||
let card_height = card_width * CARD_ASPECT;
|
||||
@@ -262,7 +268,8 @@ pub fn compute_layout(window: Vec2, safe_area_top: f32, safe_area_bottom: f32, h
|
||||
//
|
||||
// avail = distance from the top of the first tableau card to the bottom
|
||||
// margin — i.e. the space available for 12 fan steps.
|
||||
let avail = (tableau_y - (-window.y / 2.0 + effective_safe_bottom + h_gap) - card_height / 2.0).max(0.0);
|
||||
let avail = (tableau_y - (-window.y / 2.0 + effective_safe_bottom + h_gap) - card_height / 2.0)
|
||||
.max(0.0);
|
||||
let ideal_fan_frac = if card_height > 0.0 {
|
||||
avail / ((MAX_TABLEAU_CARDS - 1.0) * card_height)
|
||||
} else {
|
||||
@@ -298,7 +305,9 @@ mod tests {
|
||||
assert!(layout.pile_positions.contains_key(&PileType::Waste));
|
||||
for slot in 0..4_u8 {
|
||||
assert!(
|
||||
layout.pile_positions.contains_key(&PileType::Foundation(slot)),
|
||||
layout
|
||||
.pile_positions
|
||||
.contains_key(&PileType::Foundation(slot)),
|
||||
"missing foundation slot {slot}",
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user