diff --git a/liberica/src/lib/bindings.ts b/liberica/src/lib/bindings.ts index 778940d..6f122c1 100644 --- a/liberica/src/lib/bindings.ts +++ b/liberica/src/lib/bindings.ts @@ -5,27 +5,27 @@ */ export type Stop = { name: string; id: string; lat: number; lon: number } -export type MrXGadget = { AlternativeFacts: { stop_id: string } } | { Midjourney: { image: number[] } } | "NotFound" | "Teleport" | "Shifter" - -export type DetectiveGadget = { Stop: { stop_id: string } } | "OutOfOrder" | "Shackles" - -export type CreateTeamError = "InvalidName" | "NameAlreadyExists" +export type ClientResponse = { GameState: GameState } | { MrXGadget: MrXGadget } | { DetectiveGadget: DetectiveGadget } | { MrXPosition: MrXPosition } | "GameStart" | "DetectiveStart" | "GameEnd" -export type CreateTeam = { name: string; color: string; kind: TeamKind } +export type MrXGadget = { AlternativeFacts: { stop_id: string } } | { Midjourney: { image: number[] } } | "NotFound" | "Teleport" | "Shifter" -export type ClientResponse = { GameState: GameState } | { MrXGadget: MrXGadget } | { DetectiveGadget: DetectiveGadget } | { MrXPosition: MrXPosition } +export type MrXPosition = { Stop: string } | { Image: number[] } | "NotFound" -export type GameState = { teams: TeamState[]; trains: Train[]; position_cooldown?: number | null; detective_gadget_cooldown?: number | null; mr_x_gadget_cooldown?: number | null; blocked_stop?: string | null } +export type TeamState = { team: Team; long: number; lat: number; on_train: string | null } -export type ClientMessage = { Position: { long: number; lat: number } } | { SetTeamPosition: { long: number; lat: number } } | { JoinTeam: { team_id: number } } | { EmbarkTrain: { train_id: string } } | "DisembarkTrain" | { MrXGadget: MrXGadget } | { DetectiveGadget: DetectiveGadget } | { Message: string } +export type DetectiveGadget = { Stop: { stop_id: string } } | "OutOfOrder" | "Shackles" export type TeamKind = "MrX" | "Detective" | "Observer" -export type MrXPosition = { Stop: string } | { Image: number[] } | "NotFound" +export type CreateTeam = { name: string; color: string; kind: TeamKind } export type Train = { id: number; long: number; lat: number; line_id: string; line_name: string; direction: string } -export type TeamState = { team: Team; long: number; lat: number; on_train: string | null } +export type ClientMessage = { Position: { long: number; lat: number } } | { SetTeamPosition: { long: number; lat: number } } | { JoinTeam: { team_id: number } } | { EmbarkTrain: { train_id: string } } | "DisembarkTrain" | { MrXGadget: MrXGadget } | { DetectiveGadget: DetectiveGadget } | { Message: string } export type Team = { id: number; name: string; color: string; kind: TeamKind } +export type GameState = { teams: TeamState[]; trains: Train[]; position_cooldown?: number | null; detective_gadget_cooldown?: number | null; mr_x_gadget_cooldown?: number | null; blocked_stop?: string | null } + +export type CreateTeamError = "InvalidName" | "NameAlreadyExists" + diff --git a/robusta/src/main.rs b/robusta/src/main.rs index 353ee9c..9cafcb3 100644 --- a/robusta/src/main.rs +++ b/robusta/src/main.rs @@ -389,8 +389,10 @@ async fn run_game_loop(mut recv: Receiver, state: SharedState) { // the time for a single frame let mut interval = tokio::time::interval(Duration::from_millis(500)); - let running_state = Arc::new(tokio::sync::Mutex::new(RunningState::new())); - start_game(Arc::clone(&state), Arc::clone(&running_state)).await; + let mut running_state = RunningState::new(); + start_game(&state.lock().await.connections, &mut running_state).await; + let running_state = Arc::new(tokio::sync::Mutex::new(running_state)); + run_timer_loop(Arc::clone(&state), Arc::clone(&running_state)).await; loop { interval.tick().await; @@ -594,6 +596,9 @@ async fn broadcast(connections: &[ClientConnection], message: ClientResponse) { ClientResponse::MrXPosition(_) => "Mr. X position", ClientResponse::MrXGadget(_) => "Mr. X gadget", ClientResponse::DetectiveGadget(_) => "Detective gadget", + ClientResponse::GameStart => "game start", + ClientResponse::DetectiveStart => "detective start", + ClientResponse::GameEnd => "game end", }; error!("failed to send {} to client {}: {}", message_type, connection.id, err); } @@ -620,7 +625,17 @@ impl RunningState { } } -async fn start_game(state: SharedState, running_state: Arc>) { +async fn start_game(connections: &[ClientConnection], running_state: &mut RunningState) { + broadcast(connections, ClientResponse::GameStart).await; + running_state.position_cooldown = Some(COOLDOWN); +} + +async fn end_game(connections: &[ClientConnection], running_state: &mut RunningState) { + broadcast(connections, ClientResponse::GameEnd).await; + *running_state = RunningState::new(); +} + +async fn run_timer_loop(state: SharedState, running_state: Arc>) { tokio::spawn(async move { let mut warmup = true; @@ -639,7 +654,7 @@ async fn start_game(state: SharedState, running_state: Arc