diff -r 58ce582ae87d -r 4cc9ec732392 rust/hedgewars-server/src/core/server.rs --- a/rust/hedgewars-server/src/core/server.rs Thu Oct 24 09:41:10 2019 -0400 +++ b/rust/hedgewars-server/src/core/server.rs Sat Oct 26 02:36:08 2019 +0300 @@ -28,6 +28,22 @@ Restricted, } +pub enum LeaveRoomResult { + RoomRemoved, + RoomRemains { + is_empty: bool, + was_master: bool, + was_in_game: bool, + new_master: Option, + removed_teams: Vec, + }, +} + +#[derive(Debug)] +pub enum LeaveRoomError { + NoRoom, +} + #[derive(Debug)] pub struct UninitializedError(); #[derive(Debug)] @@ -138,6 +154,20 @@ } #[inline] + pub fn client_and_room(&self, client_id: ClientId, room_id: RoomId) -> (&HwClient, &HwRoom) { + (&self.clients[client_id], &self.rooms[room_id]) + } + + #[inline] + pub fn client_and_room_mut( + &mut self, + client_id: ClientId, + room_id: RoomId, + ) -> (&mut HwClient, &mut HwRoom) { + (&mut self.clients[client_id], &mut self.rooms[room_id]) + } + + #[inline] pub fn is_admin(&self, client_id: ClientId) -> bool { self.clients .get(client_id) @@ -244,6 +274,81 @@ } } + pub fn leave_room(&mut self, client_id: ClientId) -> Result { + let client = &mut self.clients[client_id]; + if let Some(room_id) = client.room_id { + let room = &mut self.rooms[room_id]; + + room.players_number -= 1; + client.room_id = None; + + let is_empty = room.players_number == 0; + let is_fixed = room.is_fixed(); + let was_master = room.master_id == Some(client_id); + let was_in_game = client.is_in_game(); + let mut removed_teams = vec![]; + + if is_empty && !is_fixed { + if client.is_ready() && room.ready_players_number > 0 { + room.ready_players_number -= 1; + } + + removed_teams = room + .client_teams(client.id) + .map(|t| t.name.clone()) + .collect(); + + for team_name in &removed_teams { + room.remove_team(team_name); + } + + if client.is_master() && !is_fixed { + client.set_is_master(false); + room.master_id = None; + } + } + + client.set_is_ready(false); + client.set_is_in_game(false); + + if !is_fixed { + if room.players_number == 0 { + self.rooms.remove(room_id); + } else if room.master_id == None { + let new_master_id = self.room_clients(room_id).next(); + if let Some(new_master_id) = new_master_id { + let room = &mut self.rooms[room_id]; + room.master_id = Some(new_master_id); + let new_master = &mut self.clients[new_master_id]; + new_master.set_is_master(true); + + if room.protocol_number < 42 { + room.name = new_master.nick.clone(); + } + + room.set_join_restriction(false); + room.set_team_add_restriction(false); + room.set_unregistered_players_restriction(true); + } + } + } + + if is_empty && !is_fixed { + Ok(LeaveRoomResult::RoomRemoved) + } else { + Ok(LeaveRoomResult::RoomRemains { + is_empty, + was_master, + was_in_game, + new_master: self.rooms[room_id].master_id, + removed_teams, + }) + } + } else { + Err(LeaveRoomError::NoRoom) + } + } + #[inline] pub fn set_var(&mut self, client_id: ClientId, var: ServerVar) -> Result<(), AccessError> { if self.clients[client_id].is_admin() {