curltastic/backend/src/protocol.rs
Jason Dekarske 1e720c22cb refactor: express foot-derived constants via FEET_TO_METERS
House radius (12ft diameter -> 6ft radius), button (6in -> 0.5ft), four-ft, eight-ft, twelve-ft radii now computed at compile time from FEET_TO_METERS = 0.3048.

Ultraworked + Co-authored-by
2026-07-10 23:19:45 -07:00

124 lines
3.0 KiB
Rust

use serde::{Deserialize, Serialize};
use std::fmt;
pub const TICK_RATE_HZ: u16 = 120;
pub const SAMPLE_RATE_HZ: u16 = 40;
pub const PHYSICS_DT: f32 = 1.0 / TICK_RATE_HZ as f32;
pub const FEET_TO_METERS: f32 = 0.3048;
pub const STONES_PER_TEAM: u8 = 8;
pub const ENDS: u8 = 10;
// World coordinates in meters, y along sheet toward house.
pub const SHEET_WIDTH: f32 = 5.0;
pub const SHEET_LENGTH: f32 = 45.0;
pub const HOUSE_CENTER: (f32, f32) = (0.0, 38.5);
pub const HOUSE_RADIUS: f32 = 6.0 * FEET_TO_METERS; // 12 ft diameter → 6 ft radius
pub const HOG_LINE_Y: f32 = 21.0;
pub const BACK_LINE_Y: f32 = 42.0;
pub const HACK_Y: f32 = 2.0;
// Stone physical properties
pub const STONE_RADIUS: f32 = 0.15;
pub const STONE_MASS: f32 = 20.0;
pub const STONE_FRICTION: f32 = 0.015;
pub const STONE_RESTITUTION: f32 = 0.05;
pub const MIN_SPEED: f32 = 3.0;
pub const MAX_SPEED: f32 = 6.45;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, Default)]
#[serde(rename_all = "snake_case")]
pub enum Team {
#[default]
Red,
Yellow,
}
impl Team {
pub fn other(self) -> Self {
match self {
Team::Red => Team::Yellow,
Team::Yellow => Team::Red,
}
}
}
impl fmt::Display for Team {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Team::Red => write!(f, "red"),
Team::Yellow => write!(f, "yellow"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ClientMessage {
Throw {
team: Team,
broom_x: f32,
broom_y: f32,
weight: u8,
#[serde(default = "default_curl")]
curl: i8,
#[serde(default = "default_friction")]
friction: f32,
},
}
fn default_curl() -> i8 { 1 }
fn default_friction() -> f32 { 1.0 }
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ServerMessage {
Joined { room: String },
Waiting { message: String },
GameState {
end: u8,
scores: [i32; 2], // red, yellow
hammer: Team,
turn_team: Team,
stones: Vec<StoneState>,
phase: Phase,
},
Trajectory {
paths: Vec<StoneTrajectory>,
},
EndScored { end: u8, points: i32, scoring_team: Option<Team> },
GameOver {
scores: [i32; 2],
winner: Option<Team>,
},
Error { message: String },
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Phase {
#[default]
Waiting,
Playing,
Simulating,
Scoring,
EndComplete,
GameComplete,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoneTrajectory {
pub stone_id: u32,
pub path: Vec<(f32, f32, f32)>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoneState {
pub id: u32,
pub team: Team,
pub x: f32,
pub y: f32,
pub rotation: f32,
pub active: bool,
}