rust/hedgewars-server/src/handlers/inroom.rs
changeset 15482 4cc9ec732392
parent 15439 a158ff8f84ef
child 15487 91f0c5ec37b5
equal deleted inserted replaced
15481:58ce582ae87d 15482:4cc9ec732392
     1 use mio;
     1 use super::{common::rnd_reply, strings::*};
     2 
       
     3 use super::common::rnd_reply;
       
     4 use crate::utils::to_engine_msg;
       
     5 use crate::{
     2 use crate::{
     6     core::{
     3     core::{
     7         room::{HwRoom, RoomFlags, MAX_TEAMS_IN_ROOM},
     4         room::{HwRoom, RoomFlags, MAX_TEAMS_IN_ROOM},
     8         server::HwServer,
     5         server::{HwServer, LeaveRoomResult},
     9         types,
     6         types,
    10         types::{ClientId, GameCfg, RoomId, VoteType, Voting, MAX_HEDGEHOGS_PER_TEAM},
     7         types::{ClientId, GameCfg, RoomId, VoteType, Voting, MAX_HEDGEHOGS_PER_TEAM},
    11     },
     8     },
    12     protocol::messages::{
     9     protocol::messages::{
    13         add_flags, remove_flags, server_chat, HwProtocolMessage, HwServerMessage::*,
    10         add_flags, remove_flags, server_chat, HwProtocolMessage, HwServerMessage::*,
    14         ProtocolFlags as Flags,
    11         ProtocolFlags as Flags,
    15     },
    12     },
    16     utils::is_name_illegal,
    13     utils::{is_name_illegal, to_engine_msg},
    17 };
    14 };
    18 use base64::{decode, encode};
    15 use base64::{decode, encode};
    19 use log::*;
    16 use log::*;
    20 use std::{cmp::min, iter::once, mem::swap};
    17 use std::{cmp::min, iter::once, mem::swap};
    21 
    18 
    44 
    41 
    45 const VALID_MESSAGES: &[u8] =
    42 const VALID_MESSAGES: &[u8] =
    46     b"M#+LlRrUuDdZzAaSjJ,NpPwtgfhbc12345\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A";
    43     b"M#+LlRrUuDdZzAaSjJ,NpPwtgfhbc12345\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A";
    47 const NON_TIMED_MESSAGES: &[u8] = b"M#hb";
    44 const NON_TIMED_MESSAGES: &[u8] = b"M#hb";
    48 
    45 
    49 #[cfg(canhazslicepatterns)]
    46 /*#[cfg(canhazslicepatterns)]
    50 fn is_msg_valid(msg: &[u8], team_indices: &[u8]) -> bool {
    47 fn is_msg_valid(msg: &[u8], team_indices: &[u8]) -> bool {
    51     match msg {
    48     match msg {
    52         [size, typ, body..MAX] => {
    49         [size, typ, body..MAX] => {
    53             VALID_MESSAGES.contains(typ)
    50             VALID_MESSAGES.contains(typ)
    54                 && match body {
    51                 && match body {
    58                     _ => *typ != b'h',
    55                     _ => *typ != b'h',
    59                 }
    56                 }
    60         }
    57         }
    61         _ => false,
    58         _ => false,
    62     }
    59     }
    63 }
    60 }*/
    64 
    61 
    65 fn is_msg_valid(msg: &[u8], _team_indices: &[u8]) -> bool {
    62 fn is_msg_valid(msg: &[u8], _team_indices: &[u8]) -> bool {
    66     if let Some(typ) = msg.get(1) {
    63     if let Some(typ) = msg.get(1) {
    67         VALID_MESSAGES.contains(typ)
    64         VALID_MESSAGES.contains(typ)
    68     } else {
    65     } else {
   108     client_id: ClientId,
   105     client_id: ClientId,
   109     response: &mut super::Response,
   106     response: &mut super::Response,
   110     room_id: RoomId,
   107     room_id: RoomId,
   111     message: HwProtocolMessage,
   108     message: HwProtocolMessage,
   112 ) {
   109 ) {
   113     let client = &mut server.clients[client_id];
   110     let (client, room) = server.client_and_room_mut(client_id, room_id);
   114     let room = &mut server.rooms[room_id];
       
   115 
   111 
   116     use crate::protocol::messages::HwProtocolMessage::*;
   112     use crate::protocol::messages::HwProtocolMessage::*;
   117     match message {
   113     match message {
   118         Part(msg) => {
   114         Part(msg) => {
   119             let msg = match msg {
   115             let msg = match msg {
   120                 Some(s) => format!("part: {}", s),
   116                 Some(s) => format!("part: {}", s),
   121                 None => "part".to_string(),
   117                 None => "part".to_string(),
   122             };
   118             };
   123             super::common::exit_room(server, client_id, response, &msg);
   119 
       
   120             match server.leave_room(client_id) {
       
   121                 Ok(result) => {
       
   122                     let room = server.room(room_id);
       
   123                     super::common::get_room_leave_data(server, room, &msg, result, response)
       
   124                 }
       
   125                 Err(_) => (),
       
   126             }
   124         }
   127         }
   125         Chat(msg) => {
   128         Chat(msg) => {
   126             response.add(
   129             response.add(
   127                 ChatMsg {
   130                 ChatMsg {
   128                     nick: client.nick.clone(),
   131                     nick: client.nick.clone(),
   131                 .send_all()
   134                 .send_all()
   132                 .in_room(room_id),
   135                 .in_room(room_id),
   133             );
   136             );
   134         }
   137         }
   135         TeamChat(msg) => {
   138         TeamChat(msg) => {
   136             let room = &server.rooms[room_id];
       
   137             if let Some(ref info) = room.game_info {
   139             if let Some(ref info) = room.game_info {
   138                 if let Some(clan_color) = room.find_team_color(client_id) {
   140                 if let Some(clan_color) = room.find_team_color(client_id) {
   139                     let client = &server.clients[client_id];
       
   140                     let engine_msg =
   141                     let engine_msg =
   141                         to_engine_msg(format!("b{}]{}\x20\x20", client.nick, msg).bytes());
   142                         to_engine_msg(format!("b{}]{}\x20\x20", client.nick, msg).bytes());
   142                     let team = room.clan_team_owners(clan_color).collect();
   143                     let team = room.clan_team_owners(clan_color).collect();
   143                     response.add(ForwardEngineMessage(vec![engine_msg]).send_many(team))
   144                     response.add(ForwardEngineMessage(vec![engine_msg]).send_many(team))
   144                 }
   145                 }
   162                 room.greeting = text.unwrap_or(String::new());
   163                 room.greeting = text.unwrap_or(String::new());
   163             }
   164             }
   164         }
   165         }
   165         MaxTeams(count) => {
   166         MaxTeams(count) => {
   166             if !client.is_master() {
   167             if !client.is_master() {
   167                 response.add(Warning("You're not the room master!".to_string()).send_self());
   168                 response.warn(NOT_MASTER);
   168             } else if !(2..=MAX_TEAMS_IN_ROOM).contains(&count) {
   169             } else if !(2..=MAX_TEAMS_IN_ROOM).contains(&count) {
   169                 response
   170                 response.warn("/maxteams: specify number from 2 to 8");
   170                     .add(Warning("/maxteams: specify number from 2 to 8".to_string()).send_self());
   171             } else {
   171             } else {
   172                 room.max_teams = count;
   172                 server.rooms[room_id].max_teams = count;
       
   173             }
   173             }
   174         }
   174         }
   175         RoomName(new_name) => {
   175         RoomName(new_name) => {
   176             if is_name_illegal(&new_name) {
   176             if is_name_illegal(&new_name) {
   177                 response.add(Warning("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: $()*+?[]^{|}".to_string()).send_self());
   177                 response.warn("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: $()*+?[]^{|}");
   178             } else if server.has_room(&new_name) {
   178             } else if server.has_room(&new_name) {
   179                 response.add(
   179                 response.warn("A room with the same name already exists.");
   180                     Warning("A room with the same name already exists.".to_string()).send_self(),
   180             } else {
   181                 );
   181                 let (client, room) = server.client_and_room_mut(client_id, room_id);
   182             } else {
       
   183                 let room = &mut server.rooms[room_id];
       
   184                 if room.is_fixed() || room.master_id != Some(client_id) {
   182                 if room.is_fixed() || room.master_id != Some(client_id) {
   185                     response.add(Warning("Access denied.".to_string()).send_self());
   183                     response.warn(ACCESS_DENIED);
   186                 } else {
   184                 } else {
   187                     let mut old_name = new_name.clone();
   185                     let mut old_name = new_name.clone();
   188                     let client = &server.clients[client_id];
       
   189                     swap(&mut room.name, &mut old_name);
   186                     swap(&mut room.name, &mut old_name);
   190                     super::common::get_room_update(Some(old_name), room, Some(&client), response);
   187                     super::common::get_room_update(Some(old_name), room, Some(&client), response);
   191                 }
   188                 }
   192             }
   189             }
   193         }
   190         }
   212                 super::common::start_game(server, room_id, response);
   209                 super::common::start_game(server, room_id, response);
   213             }
   210             }
   214         }
   211         }
   215         AddTeam(mut info) => {
   212         AddTeam(mut info) => {
   216             if room.teams.len() >= room.max_teams as usize {
   213             if room.teams.len() >= room.max_teams as usize {
   217                 response.add(Warning("Too many teams!".to_string()).send_self());
   214                 response.warn("Too many teams!");
   218             } else if room.addable_hedgehogs() == 0 {
   215             } else if room.addable_hedgehogs() == 0 {
   219                 response.add(Warning("Too many hedgehogs!".to_string()).send_self());
   216                 response.warn("Too many hedgehogs!");
   220             } else if room.find_team(|t| t.name == info.name) != None {
   217             } else if room.find_team(|t| t.name == info.name) != None {
   221                 response.add(
   218                 response.warn("There's already a team with same name in the list.");
   222                     Warning("There's already a team with same name in the list.".to_string())
       
   223                         .send_self(),
       
   224                 );
       
   225             } else if room.game_info.is_some() {
   219             } else if room.game_info.is_some() {
   226                 response.add(
   220                 response.warn("Joining not possible: Round is in progress.");
   227                     Warning("Joining not possible: Round is in progress.".to_string()).send_self(),
       
   228                 );
       
   229             } else if room.is_team_add_restricted() {
   221             } else if room.is_team_add_restricted() {
   230                 response.add(
   222                 response.warn("This room currently does not allow adding new teams.");
   231                     Warning("This room currently does not allow adding new teams.".to_string())
       
   232                         .send_self(),
       
   233                 );
       
   234             } else {
   223             } else {
   235                 info.owner = client.nick.clone();
   224                 info.owner = client.nick.clone();
   236                 let team = room.add_team(client.id, *info, client.protocol_number < 42);
   225                 let team = room.add_team(client.id, *info, client.protocol_number < 42);
   237                 client.teams_in_game += 1;
   226                 client.teams_in_game += 1;
   238                 client.clan = Some(team.color);
   227                 client.clan = Some(team.color);
   252                     HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
   241                     HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
   253                         .send_all()
   242                         .send_all()
   254                         .in_room(room_id),
   243                         .in_room(room_id),
   255                 );
   244                 );
   256 
   245 
       
   246                 let room = server.room(room_id);
   257                 let room_master = if let Some(id) = room.master_id {
   247                 let room_master = if let Some(id) = room.master_id {
   258                     Some(&server.clients[id])
   248                     Some(server.client(id))
   259                 } else {
   249                 } else {
   260                     None
   250                     None
   261                 };
   251                 };
   262                 super::common::get_room_update(None, room, room_master, response);
   252                 super::common::get_room_update(None, room, room_master, response);
   263             }
   253             }
   264         }
   254         }
   265         RemoveTeam(name) => match room.find_team_owner(&name) {
   255         RemoveTeam(name) => match room.find_team_owner(&name) {
   266             None => response.add(
   256             None => response.warn("Error: The team you tried to remove does not exist."),
   267                 Warning("Error: The team you tried to remove does not exist.".to_string())
   257             Some((id, _)) if id != client_id => {
   268                     .send_self(),
   258                 response.warn("You can't remove a team you don't own.")
   269             ),
   259             }
   270             Some((id, _)) if id != client_id => response
       
   271                 .add(Warning("You can't remove a team you don't own.".to_string()).send_self()),
       
   272             Some((_, name)) => {
   260             Some((_, name)) => {
       
   261                 let name = name.to_string();
   273                 client.teams_in_game -= 1;
   262                 client.teams_in_game -= 1;
   274                 client.clan = room.find_team_color(client.id);
   263                 client.clan = room.find_team_color(client.id);
   275                 let names = vec![name.to_string()];
   264                 room.remove_team(&name);
   276                 super::common::remove_teams(room, names, client.is_in_game(), response);
   265                 let removed_teams = vec![name];
       
   266                 super::common::get_remove_teams_data(
       
   267                     room_id,
       
   268                     client.is_in_game(),
       
   269                     removed_teams,
       
   270                     response,
       
   271                 );
   277 
   272 
   278                 match room.game_info {
   273                 match room.game_info {
   279                     Some(ref info) if info.teams_in_game == 0 => {
   274                     Some(ref info) if info.teams_in_game == 0 => {
   280                         super::common::end_game(server, room_id, response)
   275                         super::common::end_game(server, room_id, response)
   281                     }
   276                     }
   289                 let max_hedgehogs = min(
   284                 let max_hedgehogs = min(
   290                     MAX_HEDGEHOGS_PER_TEAM,
   285                     MAX_HEDGEHOGS_PER_TEAM,
   291                     addable_hedgehogs + team.hedgehogs_number,
   286                     addable_hedgehogs + team.hedgehogs_number,
   292                 );
   287                 );
   293                 if !client.is_master() {
   288                 if !client.is_master() {
   294                     response.add(Error("You're not the room master!".to_string()).send_self());
   289                     response.error(NOT_MASTER);
   295                 } else if !(1..=max_hedgehogs).contains(&number) {
   290                 } else if !(1..=max_hedgehogs).contains(&number) {
   296                     response
   291                     response
   297                         .add(HedgehogsNumber(team.name.clone(), team.hedgehogs_number).send_self());
   292                         .add(HedgehogsNumber(team.name.clone(), team.hedgehogs_number).send_self());
   298                 } else {
   293                 } else {
   299                     team.hedgehogs_number = number;
   294                     team.hedgehogs_number = number;
   303                             .in_room(room_id)
   298                             .in_room(room_id)
   304                             .but_self(),
   299                             .but_self(),
   305                     );
   300                     );
   306                 }
   301                 }
   307             } else {
   302             } else {
   308                 response.add(Warning("No such team.".to_string()).send_self());
   303                 response.warn(NO_TEAM);
   309             }
   304             }
   310         }
   305         }
   311         SetTeamColor(team_name, color) => {
   306         SetTeamColor(team_name, color) => {
   312             if let Some((owner, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) {
   307             if let Some((owner, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) {
   313                 if !client.is_master() {
   308                 if !client.is_master() {
   314                     response.add(Error("You're not the room master!".to_string()).send_self());
   309                     response.error(NOT_MASTER);
   315                 } else {
   310                 } else {
   316                     team.color = color;
   311                     team.color = color;
   317                     response.add(
   312                     response.add(
   318                         TeamColor(team.name.clone(), color)
   313                         TeamColor(team.name.clone(), color)
   319                             .send_all()
   314                             .send_all()
   321                             .but_self(),
   316                             .but_self(),
   322                     );
   317                     );
   323                     server.clients[owner].clan = Some(color);
   318                     server.clients[owner].clan = Some(color);
   324                 }
   319                 }
   325             } else {
   320             } else {
   326                 response.add(Warning("No such team.".to_string()).send_self());
   321                 response.warn(NO_TEAM);
   327             }
   322             }
   328         }
   323         }
   329         Cfg(cfg) => {
   324         Cfg(cfg) => {
   330             if room.is_fixed() {
   325             if room.is_fixed() {
   331                 response.add(Warning("Access denied.".to_string()).send_self());
   326                 response.warn(ACCESS_DENIED);
   332             } else if !client.is_master() {
   327             } else if !client.is_master() {
   333                 response.add(Error("You're not the room master!".to_string()).send_self());
   328                 response.error(NOT_MASTER);
   334             } else {
   329             } else {
   335                 let cfg = match cfg {
   330                 let cfg = match cfg {
   336                     GameCfg::Scheme(name, mut values) => {
   331                     GameCfg::Scheme(name, mut values) => {
   337                         if client.protocol_number == 49 && values.len() >= 2 {
   332                         if client.protocol_number == 49 && values.len() >= 2 {
   338                             let mut s = "X".repeat(50);
   333                             let mut s = "X".repeat(50);
   365                         filename,
   360                         filename,
   366                         contents,
   361                         contents,
   367                     }),
   362                     }),
   368                     Err(e) => {
   363                     Err(e) => {
   369                         warn!("Error while serializing the room configs: {}", e);
   364                         warn!("Error while serializing the room configs: {}", e);
   370                         response.add(
   365                         response.warn("Unable to serialize the room configs.")
   371                             Warning("Unable to serialize the room configs.".to_string())
       
   372                                 .send_self(),
       
   373                         )
       
   374                     }
   366                     }
   375                 }
   367                 }
   376             }
   368             }
   377         }
   369         }
   378         #[cfg(feature = "official-server")]
   370         #[cfg(feature = "official-server")]
   587         }
   579         }
   588         Delegate(nick) => {
   580         Delegate(nick) => {
   589             let delegate_id = server.find_client(&nick).map(|c| (c.id, c.room_id));
   581             let delegate_id = server.find_client(&nick).map(|c| (c.id, c.room_id));
   590             let client = &server.clients[client_id];
   582             let client = &server.clients[client_id];
   591             if !(client.is_admin() || client.is_master()) {
   583             if !(client.is_admin() || client.is_master()) {
   592                 response.add(
   584                 response.warn("You're not the room master or a server admin!")
   593                     Warning("You're not the room master or a server admin!".to_string())
       
   594                         .send_self(),
       
   595                 )
       
   596             } else {
   585             } else {
   597                 match delegate_id {
   586                 match delegate_id {
   598                     None => response.add(Warning("Player is not online.".to_string()).send_self()),
   587                     None => response.warn("Player is not online."),
   599                     Some((id, _)) if id == client_id => response
   588                     Some((id, _)) if id == client_id => {
   600                         .add(Warning("You're already the room master.".to_string()).send_self()),
   589                         response.warn("You're already the room master.")
   601                     Some((_, id)) if id != Some(room_id) => response
   590                     }
   602                         .add(Warning("The player is not in your room.".to_string()).send_self()),
   591                     Some((_, id)) if id != Some(room_id) => {
       
   592                         response.warn("The player is not in your room.")
       
   593                     }
   603                     Some((id, _)) => {
   594                     Some((id, _)) => {
   604                         super::common::change_master(server, room_id, id, response);
   595                         super::common::change_master(server, room_id, id, response);
   605                     }
   596                     }
   606                 }
   597                 }
   607             }
   598             }