use std::collections::HashMap; use godot::{ classes::{ Button, CheckBox, Control, GridContainer, IPanel, Label, LineEdit, OptionButton, Panel, SpinBox, VBoxContainer, }, prelude::*, }; use crate::{ bgm::{Music, MusicManager}, cli_parser::CliParser, game::{ Game, GameManager, opts::{GameOption, GameOptionValue, GameOptions}, }, net::network_manager::{NetworkManager, Package, PeerKind}, ui::lobby_player_listing::LobbyPlayerListing, }; #[derive(GodotClass)] #[class(base=Panel, init)] pub struct LobbyPanel { #[export] players_list: Option>, #[export] name_field: Option>, #[export] player_listing_prefab: Option>, #[export] ready_button: Option>, #[export] map_selection: Option>, #[export] options_panel: Option>, #[export] options_grid: Option>, option_nodes: HashMap>, is_ready: bool, base: Base, } #[godot_api] impl IPanel for LobbyPanel { fn ready(&mut self) { GameManager::singleton() .signals() .on_new_player() .connect_other(self, |s, _| s.update_players(true)); GameManager::singleton() .signals() .on_player_disconnected() .connect_other(self, |s, _| s.update_players(true)); GameManager::singleton() .signals() .on_players_updated() .connect_other(self, |s| s.update_players(false)); GameManager::singleton() .signals() .on_map_changed() .connect_other(self, |s, id| s.update_map_selection(id)); if let Some(ready_button) = &self.ready_button { ready_button .signals() .pressed() .connect_other(self, |s| s.on_ready()); } if let Some(map_selection) = &self.map_selection { map_selection .signals() .item_selected() .connect_other(self, |s, _| { if let Some(map_selection) = &s.map_selection { s.update_map_selection(map_selection.get_selected_id() as u8); } }); } if let Some(game) = Game::singleton() { game.signals().options_changed().connect_other(self, |s| { s.run_deferred(|s| { if let Some(game) = Game::singleton() { s.on_game_opts_update( &game.bind().opts, NetworkManager::singleton().bind().is_host(), ); } }); }); let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer { peer.is_host() } else { false }; if let Some(mut map_selection) = self.map_selection.clone() { let mut prev_selection = game.bind().selected_map_idx; let prev_selection_hidden = if let Some(map) = game.bind().maps.get(prev_selection as usize) { map.bind().hidden } else { false }; if prev_selection_hidden && !game.bind().forced_map_selection { if let Some((id, _)) = game .bind() .maps .iter_shared() .enumerate() .find(|(_, m)| !m.bind().hidden) { prev_selection = id as u8; } } for (id, map) in game.bind().maps.iter_shared().enumerate() { if map.bind().hidden { continue; } if let Some(icon) = &map.bind().icon { map_selection .add_icon_item_ex(icon, &map.bind().name) .id(id as i32) .done(); } else { map_selection .add_item_ex(&map.bind().name) .id(id as i32) .done(); } } let idx = self.find_idx(prev_selection); map_selection.select(idx); if is_host { self.update_map_selection(prev_selection as u8); } } self.on_game_opts_update(&game.bind().opts, is_host); } if let Some(name_field) = &self.name_field { name_field .signals() .text_changed() .connect_other(self, |_, value| { if let Some(game) = &mut Game::singleton() { let player_id = game.bind().self_id; if let Some(player_id) = player_id { game.bind_mut() .update_player_nick(player_id, value.to_string()); } } NetworkManager::singleton() .bind_mut() .update_nick(value.to_string()); }); } self.update_players(true); if let Some(peer) = &NetworkManager::singleton().bind().peer && peer.is_host() { if let Some(button) = &mut self.ready_button { button.set_text("Start Game"); button.set_disabled(true); } } self.update_ready_button(); let mut nodes = Vec::new(); if let Some(game) = Game::singleton() { for (option, value) in &game.bind().opts.values { let mut label = Label::new_alloc(); label.set_text(&format!("{}:", option.to_string())); nodes.push(label.upcast()); let value_node = match value { GameOptionValue::Boolean(value) => { let mut checkbox = CheckBox::new_alloc(); checkbox.set_pressed(*value); checkbox.set_disabled(!NetworkManager::singleton().bind().is_host()); let checkbox_clone = checkbox.clone(); let option = option.clone(); checkbox.signals().pressed().connect_other(self, move |s| { s.option_changed( option, GameOptionValue::Boolean(checkbox_clone.is_pressed()), ); }); self.option_nodes.insert(option, checkbox.clone().upcast()); checkbox.upcast::() } GameOptionValue::Number(value) => { let mut spinbox = SpinBox::new_alloc(); spinbox.set_value(*value); spinbox.set_editable(NetworkManager::singleton().bind().is_host()); let option = option.clone(); spinbox.signals().value_changed().connect_other( self, move |s, new_value| { s.option_changed(option, GameOptionValue::Number(new_value)); }, ); self.option_nodes.insert(option, spinbox.clone().upcast()); spinbox.upcast() } }; nodes.push(value_node); } } if let Some(grid) = &mut self.options_grid { for node in nodes { grid.add_child(&node); } } MusicManager::singleton() .bind_mut() .play(Some(Music::MainMenu), false); } } #[godot_api] impl LobbyPanel { #[func] fn open_options(&mut self) { if let Some(panel) = &mut self.options_panel { panel.set_visible(true); } } #[func] fn close_options(&mut self) { if let Some(panel) = &mut self.options_panel { panel.set_visible(false); } } #[func] pub fn exit(&mut self) { GameManager::singleton().bind_mut().exit_game(); NetworkManager::singleton().bind_mut().disconnect(); } fn option_changed(&mut self, key: GameOption, value: GameOptionValue) { if let Some(game) = &mut Game::singleton() { game.bind_mut().change_option(key, value); } } fn on_game_opts_update(&mut self, opts: &GameOptions, is_host: bool) { if let Some(selection) = &mut self.map_selection { selection.set_disabled(!is_host && !opts.is_true(GameOption::AllowAnyMap)); } let values = opts.values.clone(); let nodes = self.option_nodes.clone(); self.run_deferred_gd(move |_| { for (key, value) in values { if let Some(control) = nodes.get(&key).cloned() { match value { GameOptionValue::Boolean(value) => { if let Ok(mut checkbox) = control.try_cast::() { checkbox.set_pressed(value); } } GameOptionValue::Number(value) => { if let Ok(mut spinbox) = control.try_cast::() { spinbox.set_value(value); } } } } } }); } fn update_ready_button(&mut self) { if let Some(game) = Game::singleton() && let Some(peer) = &NetworkManager::singleton().bind().peer { if let PeerKind::Server(_, _) = peer && let Some(button) = &mut self.ready_button { let all_ready = game.bind().players.iter().all(|p| p.data.ready); button.set_disabled(!all_ready); } } } pub fn update_players(&mut self, replace: bool) { if let Some(game) = &Game::singleton() && let Some(player) = game.bind().find_player(game.bind().self_id.unwrap_or(0)) && let Some(name_label) = &mut self.name_field { if player.data.name != name_label.get_text().to_string() { name_label.set_text(&player.data.name); } } self.update_ready_button(); if let Some(list) = &mut self.players_list { if replace { for child in list.get_children().iter_shared() { list.remove_child(&child); } if let Some(game) = &Game::singleton() { if let Some(prefab) = &self.player_listing_prefab { for player in &game.bind().players { if let Some(node) = prefab.instantiate() { let mut listing = node.cast::(); listing.bind_mut().player_id = Some(player.id()); listing.bind_mut().update_teams(game.bind().get_teams()); listing.bind_mut().update(); list.add_child(&listing); } } } } } else { for child in list.get_children().iter_shared() { let mut listing = child.cast::(); if let Some(game) = Game::singleton() { listing.bind_mut().update_teams(game.bind().get_teams()); } listing.bind_mut().update(); } } } } pub fn on_ready(&mut self) { let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer { peer.is_host() } else { false }; if !is_host { self.is_ready = !self.is_ready; if let Some(button) = &mut self.ready_button { if self.is_ready { button.set_text("Ready"); } else { button.set_text("Not Ready"); } } if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { if let PeerKind::Client(peer, socket_addr) = peer { peer.send_reliable(&socket_addr, Package::SetReady(0, self.is_ready)); } } } else { if let Some(game) = &mut Game::singleton() { game.bind_mut().start_game(); } } } pub fn update_map_selection(&mut self, id: u8) { godot_print!("update map selection"); if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { match peer { PeerKind::Client(peer, addr) => { if let Some(mut map_selection) = self.map_selection.clone() { map_selection.select(self.find_idx(id)); self.run_deferred(|s| s.update_players(false)); peer.send_reliable(addr, Package::SelectMap(id)); } } PeerKind::Server(peer, _) => { if let Some(mut map_selection) = self.map_selection.clone() { map_selection.select(self.find_idx(id)); } if let Some(game) = &mut Game::singleton() { game.bind_mut().change_map_selection(id, false); } self.run_deferred(|s| s.update_players(false)); peer.broadcast_reliable(Package::SelectMap(id)); } } } } pub fn find_idx(&self, map_id: u8) -> i32 { let mut idx = 0; if let Some(map_selection) = &self.map_selection { for i in 0..map_selection.get_item_count() { if map_selection.get_item_id(i) == map_id as i32 { idx = i; } } } idx } }