diff --git a/rust/src/game/mod.rs b/rust/src/game/mod.rs index 2a5d3d4..879de2f 100644 --- a/rust/src/game/mod.rs +++ b/rust/src/game/mod.rs @@ -341,6 +341,8 @@ impl Game { pub fn on_pickup_ball(player_id: u16); #[signal] pub fn on_drop_ball(); + #[signal] + pub fn on_host_privileges_changed(); pub fn singleton() -> Option> { if GameManager::singleton().get_children().len() > 0 { @@ -352,11 +354,15 @@ impl Game { } } - pub fn set_host_privileges(&mut self, privileges: bool) { - if privileges { - self.set_ready(true); + pub fn set_host_privileges(&mut self, player_id: u16, privileges: bool) { + if self.self_id.map(|s| s == player_id).unwrap_or(false) { + self.set_ready(privileges); + self.host_privileges = privileges; } - self.host_privileges = privileges; + if let Some(player) = self.find_player_mut(player_id) { + player.data.has_host_privileges = privileges; + } + self.signals().on_host_privileges_changed().emit(); } pub fn has_host_privileges(&self) -> bool { @@ -705,6 +711,7 @@ impl Game { ping: 0, team: 0, ready: false, + has_host_privileges: host_privileges, }, stats: Default::default(), killing_spree: 0, @@ -712,7 +719,6 @@ impl Game { character: None, last_held_weapon: WeaponType::Raygun, last_position: Vector3::ZERO, - has_host_privileges: host_privileges, }); self.run_deferred(move |s| s.signals().on_new_player().emit(id)); @@ -790,6 +796,25 @@ impl Game { } self.players.retain(|p| p.id() != id); self.run_deferred(move |s| s.signals().on_player_disconnected().emit(id)); + + self.run_deferred(|s| { + if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer + && let PeerKind::Server(peer, _) = peer + { + let players_with_host = s + .players + .iter() + .filter(|p| p.data.has_host_privileges) + .count(); + if players_with_host == 0 + && let Some(player) = s.players.iter_mut().next() + { + player.data.has_host_privileges = true; + peer.broadcast_reliable(Package::SetHostPrivileges(player.id(), true)); + s.signals().on_host_privileges_changed().emit(); + } + } + }); } pub fn update_player_nick(&mut self, player_id: u16, nick: String) { @@ -1700,7 +1725,6 @@ pub struct Player { pub killing_spree_cd: f64, pub last_held_weapon: WeaponType, pub last_position: Vector3, - pub has_host_privileges: bool, } impl Player { @@ -1874,6 +1898,7 @@ pub struct NetPlayer { pub name: String, pub ping: u128, pub team: u8, + pub has_host_privileges: bool, } impl From for Player { @@ -1887,7 +1912,6 @@ impl From for Player { killing_spree_cd: 0., last_held_weapon: WeaponType::Raygun, last_position: Vector3::ZERO, - has_host_privileges: false, } } } diff --git a/rust/src/net/network_manager.rs b/rust/src/net/network_manager.rs index 37422f7..62b55a4 100644 --- a/rust/src/net/network_manager.rs +++ b/rust/src/net/network_manager.rs @@ -368,6 +368,7 @@ pub enum Package { SelectMap(u8), GameStarted, MapLoaded, + SetHostPrivileges(u16, bool), // Game packages SpawnPlayer(u16, NetTransform), diff --git a/rust/src/net/protocol.rs b/rust/src/net/protocol.rs index e520049..de55b2f 100644 --- a/rust/src/net/protocol.rs +++ b/rust/src/net/protocol.rs @@ -104,10 +104,16 @@ impl NetworkManager { ); game.bind_mut().set_self(self_id); if host_privileges { - game.bind_mut().set_host_privileges(true); + game.bind_mut().set_host_privileges(self_id, true); } } } + Package::SetHostPrivileges(player_id, host_privileges) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut() + .set_host_privileges(player_id, host_privileges); + } + } Package::SetNick(id, nick) => { if let Some(game) = &mut Game::singleton() { game.bind_mut().update_player_nick(id, nick); @@ -501,7 +507,7 @@ impl NetworkManager { if let Some(player) = player { if game.bind().opts.is_true(GameOption::AllowAnyTeam) || player.id() == player_id - || player.has_host_privileges + || player.data.has_host_privileges { game.bind_mut().try_set_player_team(player_id, team); } @@ -515,7 +521,7 @@ impl NetworkManager { if game.bind().opts.is_true(GameOption::AllowAnyMap) { game.bind_mut().change_map_selection(map_idx, false); } else if let Some(player) = player - && player.has_host_privileges + && player.data.has_host_privileges { game.bind_mut().change_map_selection(map_idx, false); } @@ -567,7 +573,7 @@ impl NetworkManager { let player = game.bind().find_player_by_addr(&conn.address).cloned(); if let Some(player) = player - && player.has_host_privileges + && player.data.has_host_privileges { game.bind_mut().start_game(); } @@ -578,7 +584,7 @@ impl NetworkManager { let player = game.bind().find_player_by_addr(&conn.address).cloned(); if let Some(player) = player - && player.has_host_privileges + && player.data.has_host_privileges { game.bind_mut().change_option(key, value, false); } @@ -589,7 +595,7 @@ impl NetworkManager { let player = game.bind().find_player_by_addr(&conn.address).cloned(); if let Some(player) = player - && player.has_host_privileges + && player.data.has_host_privileges { game.bind_mut().change_team_option(team, key, value, false); } @@ -600,7 +606,7 @@ impl NetworkManager { let player = game.bind().find_player_by_addr(&conn.address).cloned(); if let Some(player) = player - && player.has_host_privileges + && player.data.has_host_privileges { godot_print!("Finishing game"); game.bind_mut().finish_game(); diff --git a/rust/src/ui/lobby.rs b/rust/src/ui/lobby.rs index 9a8b40f..8c3b6c0 100644 --- a/rust/src/ui/lobby.rs +++ b/rust/src/ui/lobby.rs @@ -130,6 +130,16 @@ impl IPanel for LobbyPanel { }); }); + game.signals() + .on_host_privileges_changed() + .connect_other(self, |s| { + s.run_deferred(|s| { + if let Some(game) = Game::singleton() { + s.set_options_disabled(!game.bind().has_host_privileges()); + } + }); + }); + let is_host = if let Some(game) = &Game::singleton() { game.bind().has_host_privileges() } else { @@ -262,6 +272,26 @@ impl LobbyPanel { NetworkManager::singleton().bind_mut().disconnect(); } + fn set_options_disabled(&mut self, disabled: bool) { + if let Some(game) = &Game::singleton() { + for (option, value) in &game.bind().opts.values { + if let Some(control) = self.option_nodes.get(option) { + set_control_disabled(control.clone(), value.clone(), disabled); + } + } + for (team_id, opts) in game.bind().opts.teams.iter().enumerate() { + if let Some(team_controls) = self.team_option_nodes.get(&(team_id as u8)) { + for (option, value) in &opts.values { + if let Some(control) = team_controls.get(option) { + set_control_disabled(control.clone(), value.clone(), disabled); + } + } + } + } + self.on_game_opts_update(&game.bind().opts, game.bind().has_host_privileges()); + } + } + fn use_alt_colors_changed(&mut self, value: bool) { if let Some(game) = &mut Game::singleton() { game.bind_mut().private_opts.use_alternate_team_colors = value; @@ -578,3 +608,18 @@ fn update_control(control: Gd, value: GameOptionValue) { } } } + +fn set_control_disabled(control: Gd, value: GameOptionValue, disabled: bool) { + match value { + GameOptionValue::Boolean(_) => { + if let Ok(mut checkbox) = control.try_cast::() { + checkbox.set_disabled(disabled); + } + } + GameOptionValue::Number(_) => { + if let Ok(mut spinbox) = control.try_cast::() { + spinbox.set_editable(!disabled); + } + } + } +}