--- a/rust/hedgewars-server/src/core/server.rs Sat Dec 21 00:26:17 2019 +0300
+++ b/rust/hedgewars-server/src/core/server.rs Sat Dec 21 23:33:50 2019 +0300
@@ -2,10 +2,11 @@
client::HwClient,
indexslab::IndexSlab,
room::HwRoom,
- types::{ClientId, RoomId, ServerVar},
+ types::{ClientId, RoomId, ServerVar, TeamInfo},
};
use crate::{protocol::messages::HwProtocolMessage::Greeting, utils};
+use bitflags::_core::hint::unreachable_unchecked;
use bitflags::*;
use chrono::{offset, DateTime};
use log::*;
@@ -58,6 +59,21 @@
}
#[derive(Debug)]
+pub enum AddTeamError {
+ TooManyTeams,
+ TooManyHedgehogs,
+ TeamAlreadyExists,
+ GameInProgress,
+ Restricted,
+}
+
+#[derive(Debug)]
+pub enum RemoveTeamError {
+ NoTeam,
+ TeamNotOwned,
+}
+
+#[derive(Debug)]
pub enum ModifyTeamError {
NoTeam,
NotMaster,
@@ -229,6 +245,16 @@
}
#[inline]
+ pub fn has_client(&self, client_id: ClientId) -> bool {
+ self.clients.contains(client_id)
+ }
+
+ #[inline]
+ pub fn iter_clients(&self) -> impl Iterator<Item = &HwClient> {
+ self.clients.iter().map(|(_, c)| c)
+ }
+
+ #[inline]
pub fn room(&self, room_id: RoomId) -> &HwRoom {
&self.rooms[room_id]
}
@@ -248,8 +274,8 @@
&mut self,
client_id: ClientId,
room_id: RoomId,
- ) -> (&mut HwClient, &mut HwRoom) {
- (&mut self.clients[client_id], &mut self.rooms[room_id])
+ ) -> (&HwClient, &mut HwRoom) {
+ (&self.clients[client_id], &mut self.rooms[room_id])
}
#[inline]
@@ -504,9 +530,44 @@
}
}
+ pub fn leave_game(&mut self, client_id: ClientId) -> Option<Vec<String>> {
+ let client = &mut self.clients[client_id];
+ let client_left = client.is_in_game();
+ if client_left {
+ client.set_is_in_game(false);
+ let room = &mut self.rooms[client.room_id.expect("Client should've been in the game")];
+
+ let team_names: Vec<_> = room
+ .client_teams(client_id)
+ .map(|t| t.name.clone())
+ .collect();
+
+ if let Some(ref mut info) = room.game_info {
+ info.teams_in_game -= team_names.len() as u8;
+
+ for team_name in &team_names {
+ let remove_msg =
+ utils::to_engine_msg(std::iter::once(b'F').chain(team_name.bytes()));
+ if let Some(m) = &info.sync_msg {
+ info.msg_log.push(m.clone());
+ }
+ if info.sync_msg.is_some() {
+ info.sync_msg = None
+ }
+ info.msg_log.push(remove_msg);
+ }
+ Some(team_names)
+ } else {
+ unreachable!();
+ }
+ } else {
+ None
+ }
+ }
+
pub fn end_game(&mut self, room_id: RoomId) -> EndGameResult {
let room = &mut self.rooms[room_id];
- room.ready_players_number = 1;
+ room.ready_players_number = room.master_id.is_some() as u8;
if let Some(info) = replace(&mut room.game_info, None) {
let joined_mid_game_clients = self
@@ -572,7 +633,58 @@
}
}
- pub fn add_team(&mut self, client_id: ClientId) {}
+ pub fn add_team(
+ &mut self,
+ client_id: ClientId,
+ mut info: Box<TeamInfo>,
+ ) -> Result<&TeamInfo, AddTeamError> {
+ let client = &mut self.clients[client_id];
+ if let Some(room_id) = client.room_id {
+ let room = &mut self.rooms[room_id];
+ if room.teams.len() >= room.max_teams as usize {
+ Err(AddTeamError::TooManyTeams)
+ } else if room.addable_hedgehogs() == 0 {
+ Err(AddTeamError::TooManyHedgehogs)
+ } else if room.find_team(|t| t.name == info.name) != None {
+ Err(AddTeamError::TeamAlreadyExists)
+ } else if room.game_info.is_some() {
+ Err(AddTeamError::GameInProgress)
+ } else if room.is_team_add_restricted() {
+ Err(AddTeamError::Restricted)
+ } else {
+ info.owner = client.nick.clone();
+ let team = room.add_team(client.id, *info, client.protocol_number < 42);
+ client.teams_in_game += 1;
+ client.clan = Some(team.color);
+ Ok(team)
+ }
+ } else {
+ unreachable!()
+ }
+ }
+
+ pub fn remove_team(
+ &mut self,
+ client_id: ClientId,
+ team_name: &str,
+ ) -> Result<(), RemoveTeamError> {
+ let client = &mut self.clients[client_id];
+ if let Some(room_id) = client.room_id {
+ let room = &mut self.rooms[room_id];
+ match room.find_team_owner(team_name) {
+ None => Err(RemoveTeamError::NoTeam),
+ Some((id, _)) if id != client_id => Err(RemoveTeamError::TeamNotOwned),
+ Some(_) => {
+ client.teams_in_game -= 1;
+ client.clan = room.find_team_color(client.id);
+ room.remove_team(team_name);
+ Ok(())
+ }
+ }
+ } else {
+ unreachable!();
+ }
+ }
pub fn set_team_color(
&mut self,
--- a/rust/hedgewars-server/src/handlers.rs Sat Dec 21 00:26:17 2019 +0300
+++ b/rust/hedgewars-server/src/handlers.rs Sat Dec 21 23:33:50 2019 +0300
@@ -259,7 +259,7 @@
response.remove_client(client_id);
}
}
- } else if server.clients.contains(client_id) {
+ } else if server.has_client(client_id) {
match message {
HwProtocolMessage::Quit(Some(msg)) => {
common::remove_client(server, response, "User quit: ".to_string() + &msg);
--- a/rust/hedgewars-server/src/handlers/common.rs Sat Dec 21 00:26:17 2019 +0300
+++ b/rust/hedgewars-server/src/handlers/common.rs Sat Dec 21 23:33:50 2019 +0300
@@ -392,7 +392,7 @@
};
get_room_update(None, room, room_master, response);
- for (_, client) in server.clients.iter() {
+ for client in server.iter_clients() {
if client.room_id == Some(room_id) {
super::common::get_room_config(&server.rooms[room_id], client.id, response);
}
--- a/rust/hedgewars-server/src/handlers/inroom.rs Sat Dec 21 00:26:17 2019 +0300
+++ b/rust/hedgewars-server/src/handlers/inroom.rs Sat Dec 21 23:33:50 2019 +0300
@@ -1,4 +1,6 @@
use super::{common::rnd_reply, strings::*};
+use crate::core::room::GameInfo;
+use crate::core::server::AddTeamError;
use crate::{
core::{
room::{HwRoom, RoomFlags, MAX_TEAMS_IN_ROOM},
@@ -206,76 +208,69 @@
super::common::get_start_game_data(server, room_id, result, response);
}
}
- AddTeam(mut info) => {
- if room.teams.len() >= room.max_teams as usize {
- response.warn("Too many teams!");
- } else if room.addable_hedgehogs() == 0 {
- response.warn("Too many hedgehogs!");
- } else if room.find_team(|t| t.name == info.name) != None {
- response.warn("There's already a team with same name in the list.");
- } else if room.game_info.is_some() {
- response.warn("Joining not possible: Round is in progress.");
- } else if room.is_team_add_restricted() {
- response.warn("This room currently does not allow adding new teams.");
- } else {
- info.owner = client.nick.clone();
- let team = room.add_team(client.id, *info, client.protocol_number < 42);
- client.teams_in_game += 1;
- client.clan = Some(team.color);
- response.add(TeamAccepted(team.name.clone()).send_self());
- response.add(
- TeamAdd(team.to_protocol())
- .send_all()
- .in_room(room_id)
- .but_self(),
- );
- response.add(
- TeamColor(team.name.clone(), team.color)
- .send_all()
- .in_room(room_id),
- );
- response.add(
- HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
- .send_all()
- .in_room(room_id),
- );
+ AddTeam(info) => {
+ use crate::core::server::AddTeamError;
+ match server.add_team(client_id, info) {
+ Ok(team) => {
+ response.add(TeamAccepted(team.name.clone()).send_self());
+ response.add(
+ TeamAdd(team.to_protocol())
+ .send_all()
+ .in_room(room_id)
+ .but_self(),
+ );
+ response.add(
+ TeamColor(team.name.clone(), team.color)
+ .send_all()
+ .in_room(room_id),
+ );
+ response.add(
+ HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
+ .send_all()
+ .in_room(room_id),
+ );
- let room = server.room(room_id);
- let room_master = if let Some(id) = room.master_id {
- Some(server.client(id))
- } else {
- None
- };
- super::common::get_room_update(None, room, room_master, response);
+ let room = server.room(room_id);
+ let room_master = if let Some(id) = room.master_id {
+ Some(server.client(id))
+ } else {
+ None
+ };
+ super::common::get_room_update(None, room, room_master, response);
+ }
+ Err(AddTeamError::TooManyTeams) => response.warn(TOO_MANY_TEAMS),
+ Err(AddTeamError::TooManyHedgehogs) => response.warn(TOO_MANY_HEDGEHOGS),
+ Err(AddTeamError::TeamAlreadyExists) => response.warn(TEAM_EXISTS),
+ Err(AddTeamError::GameInProgress) => response.warn(ROUND_IN_PROGRESS),
+ Err(AddTeamError::Restricted) => response.warn(TEAM_ADD_RESTRICTED),
}
}
- RemoveTeam(name) => match room.find_team_owner(&name) {
- None => response.warn("Error: The team you tried to remove does not exist."),
- Some((id, _)) if id != client_id => {
- response.warn("You can't remove a team you don't own.")
+ RemoveTeam(name) => {
+ use crate::core::server::RemoveTeamError;
+ match server.remove_team(client_id, &name) {
+ Ok(()) => {
+ let (client, room) = server.client_and_room(client_id, room_id);
+
+ let removed_teams = vec![name];
+ super::common::get_remove_teams_data(
+ room_id,
+ client.is_in_game(),
+ removed_teams,
+ response,
+ );
+
+ match room.game_info {
+ Some(ref info) if info.teams_in_game == 0 => {
+ let result = server.end_game(room_id);
+ super::common::get_end_game_result(server, room_id, result, response);
+ }
+ _ => (),
+ }
+ }
+ Err(RemoveTeamError::NoTeam) => response.warn(NO_TEAM_TO_REMOVE),
+ Err(RemoveTeamError::TeamNotOwned) => response.warn(TEAM_NOT_OWNED),
}
- Some((_, name)) => {
- let name = name.to_string();
- client.teams_in_game -= 1;
- client.clan = room.find_team_color(client.id);
- room.remove_team(&name);
- let removed_teams = vec![name];
- super::common::get_remove_teams_data(
- room_id,
- client.is_in_game(),
- removed_teams,
- response,
- );
-
- match room.game_info {
- Some(ref info) if info.teams_in_game == 0 => {
- let result = server.end_game(room_id);
- super::common::get_end_game_result(server, room_id, result, response);
- }
- _ => (),
- }
- }
- },
+ }
SetHedgehogsNumber(team_name, number) => {
let addable_hedgehogs = room.addable_hedgehogs();
if let Some((_, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) {
@@ -510,54 +505,31 @@
}
}
RoundFinished => {
- let mut game_ended = false;
- if client.is_in_game() {
- client.set_is_in_game(false);
+ if let Some(team_names) = server.leave_game(client_id) {
+ let (client, room) = server.client_and_room(client_id, room_id);
response.add(
ClientFlags(remove_flags(&[Flags::InGame]), vec![client.nick.clone()])
.send_all()
.in_room(room.id),
);
- let team_names: Vec<_> = room
- .client_teams(client_id)
- .map(|t| t.name.clone())
- .collect();
-
- if let Some(ref mut info) = room.game_info {
- info.teams_in_game -= team_names.len() as u8;
- if info.teams_in_game == 0 {
- game_ended = true;
- }
-
- for team_name in team_names {
- let msg = once(b'F').chain(team_name.bytes());
- response.add(
- ForwardEngineMessage(vec![to_engine_msg(msg)])
- .send_all()
- .in_room(room_id)
- .but_self(),
- );
- let remove_msg = to_engine_msg(once(b'F').chain(team_name.bytes()));
- if let Some(m) = &info.sync_msg {
- info.msg_log.push(m.clone());
- }
- if info.sync_msg.is_some() {
- info.sync_msg = None
- }
- info.msg_log.push(remove_msg.clone());
- response.add(
- ForwardEngineMessage(vec![remove_msg])
- .send_all()
- .in_room(room_id)
- .but_self(),
- );
- }
+ for team_name in team_names {
+ let msg = once(b'F').chain(team_name.bytes());
+ response.add(
+ ForwardEngineMessage(vec![to_engine_msg(msg)])
+ .send_all()
+ .in_room(room_id)
+ .but_self(),
+ );
}
- }
- if game_ended {
- let result = server.end_game(room_id);
- super::common::get_end_game_result(server, room_id, result, response);
+
+ if let Some(GameInfo {
+ teams_in_game: 0, ..
+ }) = room.game_info
+ {
+ let result = server.end_game(room_id);
+ super::common::get_end_game_result(server, room_id, result, response);
+ }
}
}
Rnd(v) => {
--- a/rust/hedgewars-server/src/handlers/strings.rs Sat Dec 21 00:26:17 2019 +0300
+++ b/rust/hedgewars-server/src/handlers/strings.rs Sat Dec 21 23:33:50 2019 +0300
@@ -3,6 +3,7 @@
pub const ILLEGAL_ROOM_NAME: &str = "Illegal room name! A room name must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}";
pub const NO_ROOM: &str = "No such room.";
pub const NO_TEAM: &str = "No such team.";
+pub const NO_TEAM_TO_REMOVE: &str = "Error: The team you tried to remove does not exist.";
pub const NO_USER: &str = "No such user.";
pub const NOT_MASTER: &str = "You're not the room master!";
pub const REPLAY_LOAD_FAILED: &str = "Could't load the replay";
@@ -19,7 +20,13 @@
pub const ROOM_EXISTS: &str = "A room with the same name already exists.";
pub const ROOM_FULL: &str = "This room is already full.";
pub const ROOM_JOIN_RESTRICTED: &str = "Access denied. This room currently doesn't allow joining.";
+pub const ROUND_IN_PROGRESS: &str = "Joining not possible: Round is in progress.";
pub const SUPER_POWER: &str = "Super power activated.";
+pub const TEAM_EXISTS: &str = "There's already a team with same name in the list.";
+pub const TEAM_NOT_OWNED: &str = "You can't remove a team you don't own.";
+pub const TEAM_ADD_RESTRICTED: &str = "This room currently does not allow adding new teams.";
+pub const TOO_MANY_HEDGEHOGS: &str = "Too many hedgehogs!";
+pub const TOO_MANY_TEAMS: &str = "Too many teams!";
pub const USER_OFFLINE: &str = "Player is not online.";
pub const VARIABLE_UPDATED: &str = "Server variable has been updated.";
pub const WRONG_PROTOCOL: &str = "Room version incompatible to your Hedgewars version!";