--- 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" }
--- 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<String>),
+}
+
+#[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<VoteEffect> {
+ 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<VoteResult, VoteError> {
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(())
}
--- 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<VoteResult, VoteError>,
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)),
);