diff -r e42d1819b150 -r cd8392e52165 rust/hedgewars-server/src/core/server.rs --- a/rust/hedgewars-server/src/core/server.rs Sun Feb 11 20:33:15 2024 +0100 +++ b/rust/hedgewars-server/src/core/server.rs Mon Feb 12 01:19:32 2024 +0300 @@ -12,6 +12,7 @@ use bitflags::*; use log::*; +use rand::{self, seq::SliceRandom, thread_rng, Rng}; use slab::Slab; use std::{borrow::BorrowMut, cmp::min, collections::HashSet, iter, mem::replace}; @@ -109,9 +110,18 @@ } #[derive(Debug)] +pub enum VoteEffect { + Kicked(ClientId, LeaveRoomResult), + Map(String), + Pause, + NewSeed(GameCfg), + HedgehogsPerTeam(u8, Vec), +} + +#[derive(Debug)] pub enum VoteResult { Submitted, - Succeeded(VoteType), + Succeeded(VoteEffect), Failed, } @@ -609,8 +619,8 @@ HwRoomControl::new(self.server, client_id).filter(|c| c.room_id == room_id) } - pub fn leave_room(&mut self) -> LeaveRoomResult { - let (client, room) = self.get_mut(); + fn remove_from_room(&mut self, client_id: ClientId) -> LeaveRoomResult { + let Some((client, room)) = self.server.client_and_room_mut(client_id); room.players_number -= 1; client.room_id = None; @@ -689,6 +699,10 @@ } } + pub fn leave_room(&mut self) -> LeaveRoomResult { + self.remove_from_room(self.client_id) + } + pub fn change_master( &mut self, new_master_nick: String, @@ -743,6 +757,40 @@ } } + fn apply_vote(&mut self, kind: VoteType) -> Option { + match kind { + VoteType::Kick(nick) => { + if let Some(kicked_id) = self + .server + .find_client(&nick) + .filter(|c| c.room_id == Some(self.room_id)) + .map(|c| c.id) + { + let leave_result = self.remove_from_room(kicked_id); + Some(VoteEffect::Kicked(kicked_id, leave_result)) + } else { + None + } + } + VoteType::Map(None) => None, + VoteType::Map(Some(name)) => self + .load_config(&name) + .map(|s| VoteEffect::Map(s.to_string())), + VoteType::Pause => Some(VoteEffect::Pause).filter(|_| self.toggle_pause()), + VoteType::NewSeed => { + let seed = thread_rng().gen_range(0..1_000_000_000).to_string(); + let cfg = GameCfg::Seed(seed); + todo!("Protocol backwards compatibility"); + self.room_mut().set_config(cfg.clone()); + Some(VoteEffect::NewSeed(cfg)) + } + VoteType::HedgehogsPerTeam(number) => { + let nicks = self.set_hedgehogs_number(number); + Some(VoteEffect::HedgehogsPerTeam(number, nicks)) + } + } + } + pub fn vote(&mut self, vote: Vote) -> Result { use self::{VoteError::*, VoteResult::*}; let client_id = self.client_id; @@ -753,9 +801,14 @@ let pro = i.clone().filter(|(_, v)| *v).count(); let contra = i.filter(|(_, v)| !*v).count(); let success_quota = voting.voters.len() / 2 + 1; + if vote.is_forced && vote.is_pro || pro >= success_quota { let voting = self.room_mut().voting.take().unwrap(); - Ok(Succeeded(voting.kind)) + if let Some(effect) = self.apply_vote(voting.kind) { + Ok(Succeeded(effect)) + } else { + Ok(Failed) + } } else if vote.is_forced && !vote.is_pro || contra > voting.voters.len() - success_quota { @@ -941,7 +994,6 @@ } cfg => cfg, }; - room.set_config(cfg); Ok(()) }