# HG changeset patch # User alfadur # Date 1707689972 -10800 # Node ID cd8392e52165e498d5405de6397f6eed1857b9a9 # Parent e42d1819b1504b562cb3f0a303ec6a0f093ad28d fix voting rights diff -r e42d1819b150 -r cd8392e52165 rust/hedgewars-server/Cargo.toml --- a/rust/hedgewars-server/Cargo.toml Sun Feb 11 20:33:15 2024 +0100 +++ b/rust/hedgewars-server/Cargo.toml Mon Feb 12 01:19:32 2024 +0300 @@ -25,7 +25,7 @@ serde_derive = "1.0" sha1 = { version = "0.10.0", optional = true } slab = "0.4" -tokio = { version = "1.16", features = ["full"]} +tokio = { version = "1.36", features = ["full"]} tokio-native-tls = { version = "0.3", optional = true } hedgewars-network-protocol = { path = "../hedgewars-network-protocol" } 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(()) } diff -r e42d1819b150 -r cd8392e52165 rust/hedgewars-server/src/handlers/common.rs --- a/rust/hedgewars-server/src/handlers/common.rs Sun Feb 11 20:33:15 2024 +0100 +++ b/rust/hedgewars-server/src/handlers/common.rs Mon Feb 12 01:19:32 2024 +0300 @@ -9,7 +9,7 @@ room::HwRoom, server::{ EndGameResult, HwRoomControl, HwServer, JoinRoomError, LeaveRoomResult, StartGameError, - VoteError, VoteResult, + VoteEffect, VoteError, VoteResult, }, types::{ClientId, RoomId}, }, @@ -510,76 +510,58 @@ } pub fn handle_vote( - mut room_control: HwRoomControl, + room_control: HwRoomControl, result: Result, response: &mut super::Response, ) { - todo!("voting result needs to be processed with raised privileges"); let room_id = room_control.room().id; - super::common::get_vote_data(room_control.room().id, &result, response); + get_vote_data(room_control.room().id, &result, response); - if let Ok(VoteResult::Succeeded(kind)) = result { - match kind { - VoteType::Kick(nick) => { - if let Some(kicked_client) = room_control.server().find_client(&nick) { - let kicked_id = kicked_client.id; - if let Some(mut room_control) = room_control.change_client(kicked_id) { - response.add(Kicked.send(kicked_id)); - let result = room_control.leave_room(); - super::common::get_room_leave_result( - room_control.server(), - room_control.room(), - "kicked", - result, - response, - ); - } - } + if let Ok(VoteResult::Succeeded(effect)) = result { + match effect { + VoteEffect::Kicked(kicked_id, leave_result) => { + response.add(Kicked.send(kicked_id)); + get_room_leave_result( + room_control.server(), + room_control.room(), + "kicked", + leave_result, + response, + ); } - VoteType::Map(None) => (), - VoteType::Map(Some(name)) => { - if let Some(location) = room_control.load_config(&name) { - let msg = server_chat(location.to_string()); - let room = room_control.room(); - response.add(msg.send_all().in_room(room.id)); + VoteEffect::Map(location) => { + let msg = server_chat(location.to_string()); + let room = room_control.room(); + response.add(msg.send_all().in_room(room.id)); - let room_master = room.master_id.map(|id| room_control.server().client(id)); + let room_master = room.master_id.map(|id| room_control.server().client(id)); - super::common::get_room_update(None, room, room_master, response); + get_room_update(None, room, room_master, response); - let room_destination = Destination::ToAll { - group: DestinationGroup::Room(room.id), - skip_self: false, - }; - super::common::get_active_room_config(room, room_destination, response); - } + let room_destination = Destination::ToAll { + group: DestinationGroup::Room(room.id), + skip_self: false, + }; + get_active_room_config(room, room_destination, response); } - VoteType::Pause => { - if room_control.toggle_pause() { - response.add( - server_chat("Pause toggled.".to_string()) - .send_all() - .in_room(room_id), - ); - response.add( - ForwardEngineMessage(vec![to_engine_msg(once(b'I'))]) - .send_all() - .in_room(room_id), - ); - } + VoteEffect::Pause => { + response.add( + server_chat("Pause toggled.".to_string()) + .send_all() + .in_room(room_id), + ); + response.add( + ForwardEngineMessage(vec![to_engine_msg(once(b'I'))]) + .send_all() + .in_room(room_id), + ); } - VoteType::NewSeed => { - let seed = thread_rng().gen_range(0..1_000_000_000).to_string(); - let cfg = GameCfg::Seed(seed); + VoteEffect::NewSeed(cfg) => { response.add(cfg.to_server_msg().send_all().in_room(room_id)); - room_control - .set_config(cfg) - .expect("Apparently, you cannot just set room config"); } - VoteType::HedgehogsPerTeam(number) => { - let nicks = room_control.set_hedgehogs_number(number); + VoteEffect::HedgehogsPerTeam(number, team_names) => { response.extend( - nicks + team_names .into_iter() .map(|n| HedgehogsNumber(n, number).send_all().in_room(room_id)), );