handle ending games

This commit is contained in:
Joey Hines 2025-06-13 19:02:30 -06:00
parent d129911b8e
commit d08c0c0f5c
Signed by: joeyahines
GPG Key ID: 38BA6F25C94C9382
9 changed files with 89 additions and 42 deletions

View File

@ -12,6 +12,7 @@ pub type HostClientMessages {
ResetAllBuzers ResetAllBuzers
ResetPlayerBuzzer(user_id: Int) ResetPlayerBuzzer(user_id: Int)
UpdateScore(user_id: Int, diff: Int) UpdateScore(user_id: Int, diff: Int)
EndGame
} }
pub fn host_client_messages_decoder() -> decode.Decoder(HostClientMessages) { pub fn host_client_messages_decoder() -> decode.Decoder(HostClientMessages) {
@ -27,6 +28,7 @@ pub fn host_client_messages_decoder() -> decode.Decoder(HostClientMessages) {
use diff <- decode.field("diff", decode.int) use diff <- decode.field("diff", decode.int)
decode.success(UpdateScore(user_id:, diff:)) decode.success(UpdateScore(user_id:, diff:))
} }
"EndGame" -> decode.success(EndGame)
_ -> decode.failure(ResetAllBuzers, "HostClientMessages") _ -> decode.failure(ResetAllBuzers, "HostClientMessages")
} }
} }
@ -34,6 +36,7 @@ pub fn host_client_messages_decoder() -> decode.Decoder(HostClientMessages) {
pub type HostServerMessages { pub type HostServerMessages {
Ack Ack
UpdatePlayerStates(players: dict.Dict(Int, player.Player)) UpdatePlayerStates(players: dict.Dict(Int, player.Player))
ExitGame
} }
pub fn encode_host_server_messages( pub fn encode_host_server_messages(
@ -53,5 +56,6 @@ pub fn encode_host_server_messages(
), ),
), ),
]) ])
ExitGame -> json.object([#("type", json.string("ExitGame"))])
} }
} }

View File

@ -18,6 +18,7 @@ pub type PlayerServerMessages {
Ack Ack
UpdatePointTotal(score: Int) UpdatePointTotal(score: Int)
ResetBuzzer ResetBuzzer
ExitGame
} }
pub fn encode_player_server_messages( pub fn encode_player_server_messages(
@ -31,5 +32,6 @@ pub fn encode_player_server_messages(
#("score", json.int(player_server_messages.score)), #("score", json.int(player_server_messages.score)),
]) ])
ResetBuzzer -> json.object([#("type", json.string("ResetBuzzer"))]) ResetBuzzer -> json.object([#("type", json.string("ResetBuzzer"))])
ExitGame -> json.object([#("type", json.string("ExitGame"))])
} }
} }

View File

@ -173,14 +173,12 @@ fn handle_ws_message(
conn, conn,
message: mist.WebsocketMessage(String), message: mist.WebsocketMessage(String),
) { ) {
io.println("Got WS message")
case message { case message {
mist.Text(msg) -> { mist.Text(msg) -> {
echo msg echo msg
let #(state, resp) = web.handle_client_msg(state, msg) let #(state, resp) = web.handle_client_msg(state, msg)
echo resp
let assert Ok(_) = mist.send_text_frame(conn, resp) let assert Ok(_) = mist.send_text_frame(conn, resp)
actor.continue(state) actor.continue(state)

View File

@ -174,6 +174,12 @@ fn handle_host(
#(socket_state, host_client.Ack) #(socket_state, host_client.Ack)
} }
host_client.EndGame -> {
let assert Ok(_) =
session_manager.end_game(socket_state.ctx.sessions, host_state.game_id)
#(socket_state, host_client.Ack)
}
} }
let resp = json.to_string(host_client.encode_host_server_messages(resp)) let resp = json.to_string(host_client.encode_host_server_messages(resp))

View File

@ -289,7 +289,21 @@ fn end_game_internal(
state: State, state: State,
game_id: String, game_id: String,
) -> Result(actor.Next(Request, State), SessionError) { ) -> Result(actor.Next(Request, State), SessionError) {
use _ <- result.try(get_game(state, game_id)) use game <- result.try(get_game(state, game_id))
broadcast_msg_to_players(state, game, player_client.ExitGame)
send_message_to_host(state, game.host_user_id, host_client.ExitGame)
game.players
|> dict.each(fn(key, _) {
let _ = player_manager.remove_player(state.internal.player_manager, key)
})
let _ =
player_manager.remove_player(
state.internal.player_manager,
game.host_user_id,
)
let games = dict.delete(state.internal.games, game_id) let games = dict.delete(state.internal.games, game_id)

View File

@ -6,7 +6,10 @@ use macroquad::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{font::FontSize, model::player::Player, screen::Screen, ui_scaling::window_width}; use crate::{
font::FontSize, model::player::Player, screen::Screen, ui_scaling::window_width,
util::refresh_page,
};
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Serialize)] #[derive(Serialize)]
@ -15,6 +18,7 @@ enum HostClientMessages {
ResetAllBuzers, ResetAllBuzers,
ResetPlayerBuzzer { user_id: u64 }, ResetPlayerBuzzer { user_id: u64 },
UpdateScore { user_id: u64, diff: i32 }, UpdateScore { user_id: u64, diff: i32 },
EndGame,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -22,6 +26,7 @@ enum HostClientMessages {
enum HostServerMessages { enum HostServerMessages {
Ack, Ack,
UpdatePlayerStates { players: HashMap<String, Player> }, UpdatePlayerStates { players: HashMap<String, Player> },
ExitGame,
} }
#[derive(Default)] #[derive(Default)]
@ -125,27 +130,24 @@ impl Screen for HostScreen {
for user_id in &players { for user_id in &players {
self.draw_user(ctx, user_id, ui, width); self.draw_user(ctx, user_id, ui, width);
} }
ui.group(
hash!("Host Control"),
Vec2::new(width, window_size.y * 0.25),
|ui| {
if ui.button(Vec2::new(width * 0.05, 0.0), "Clear All") {
let msg = HostClientMessages::ResetAllBuzers;
ctx.send_msg(&msg);
}
if ui.button(Vec2::new(width * 0.55, 0.0), "End Game") {
let msg = HostClientMessages::EndGame;
ctx.send_msg(&msg);
}
},
);
}); });
let button_size = screen_width() * 0.025;
let button_location = Vec2::new(screen_width() * 0.50, screen_height() * 0.90);
draw_circle(
button_location.x,
button_location.y,
button_size * 1.1,
DARKBROWN,
);
draw_circle(button_location.x, button_location.y, button_size, RED);
if is_mouse_button_pressed(MouseButton::Left) {
let loc = Vec2::from(mouse_position());
let normalize = loc - button_location;
if normalize.length() < button_size {
ctx.send_msg(&HostClientMessages::ResetAllBuzers);
}
}
root_ui().pop_skin(); root_ui().pop_skin();
} }
@ -162,6 +164,10 @@ impl Screen for HostScreen {
info!("Got new player state: {:?}", players); info!("Got new player state: {:?}", players);
self.players = players; self.players = players;
} }
HostServerMessages::ExitGame => {
info!("Exiting Game");
refresh_page();
}
}; };
} }

View File

@ -10,6 +10,8 @@ use macroquad::{
use player_screen::PlayerScreen; use player_screen::PlayerScreen;
use screen::Screen; use screen::Screen;
use crate::util::get_ws_url;
mod cfg; mod cfg;
mod context; mod context;
mod font; mod font;
@ -19,6 +21,7 @@ mod model;
mod player_screen; mod player_screen;
mod screen; mod screen;
mod ui_scaling; mod ui_scaling;
mod util;
pub enum State { pub enum State {
Init, Init,
@ -98,25 +101,6 @@ pub fn default_skin() -> Skin {
} }
} }
fn get_ws_url() -> String {
let location = web_sys::window()
.unwrap()
.document()
.unwrap()
.location()
.unwrap();
let protocol = if location.protocol().unwrap() == "https" {
"wss"
} else {
"ws"
};
format!("{}://{}/ws", protocol, location.host().unwrap())
}
mod modname {}
#[macroquad::main("Play of the Game")] #[macroquad::main("Play of the Game")]
async fn main() { async fn main() {
let cfg = Cfg::load_from_cookies().unwrap(); let cfg = Cfg::load_from_cookies().unwrap();

View File

@ -5,6 +5,7 @@ use crate::StateTransition;
use crate::context::Context; use crate::context::Context;
use crate::font::FontSize; use crate::font::FontSize;
use crate::screen::Screen; use crate::screen::Screen;
use crate::util::refresh_page;
use macroquad::prelude::*; use macroquad::prelude::*;
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
@ -19,6 +20,7 @@ pub enum PlayerServerMessages {
Ack, Ack,
UpdatePointTotal { score: i32 }, UpdatePointTotal { score: i32 },
ResetBuzzer, ResetBuzzer,
ExitGame,
} }
#[derive(Default)] #[derive(Default)]
@ -45,6 +47,10 @@ impl Screen for PlayerScreen {
info!("Score updated to: {}", score); info!("Score updated to: {}", score);
self.score = score; self.score = score;
} }
PlayerServerMessages::ExitGame => {
info!("Exiting Game");
refresh_page();
}
} }
} }

27
frontend/src/util.rs Normal file
View File

@ -0,0 +1,27 @@
pub fn refresh_page() {
let location = web_sys::window()
.unwrap()
.document()
.unwrap()
.location()
.unwrap();
location.reload().unwrap();
}
pub fn get_ws_url() -> String {
let location = web_sys::window()
.unwrap()
.document()
.unwrap()
.location()
.unwrap();
let protocol = if location.protocol().unwrap() == "https" {
"wss"
} else {
"ws"
};
format!("{}://{}/ws", protocol, location.host().unwrap())
}