rust/hedgewars-server/src/server/actions.rs
changeset 14415 06672690d71b
parent 14374 e5db279308d7
child 14456 a077aac9df01
equal deleted inserted replaced
14414:6843c4551cde 14415:06672690d71b
       
     1 use std::{
       
     2     io, io::Write,
       
     3     iter::once,
       
     4     mem::replace
       
     5 };
       
     6 use super::{
       
     7     core::HWServer,
       
     8     room::{GameInfo, RoomFlags},
       
     9     client::HWClient,
       
    10     coretypes::{ClientId, RoomId, GameCfg, VoteType},
       
    11     room::HWRoom,
       
    12     handlers
       
    13 };
       
    14 use crate::{
       
    15     protocol::messages::{
       
    16         HWProtocolMessage,
       
    17         HWServerMessage,
       
    18         HWServerMessage::*,
       
    19         server_chat
       
    20     },
       
    21     utils::to_engine_msg
       
    22 };
       
    23 use rand::{thread_rng, Rng, distributions::Uniform};
       
    24 
       
    25 pub enum Destination {
       
    26     ToId(ClientId),
       
    27     ToSelf,
       
    28     ToAll {
       
    29         room_id: Option<RoomId>,
       
    30         protocol: Option<u16>,
       
    31         skip_self: bool
       
    32     }
       
    33 }
       
    34 
       
    35 pub struct PendingMessage {
       
    36     pub destination: Destination,
       
    37     pub message: HWServerMessage
       
    38 }
       
    39 
       
    40 impl PendingMessage {
       
    41     pub fn send(message: HWServerMessage, client_id: ClientId) -> PendingMessage {
       
    42         PendingMessage{ destination: Destination::ToId(client_id), message}
       
    43     }
       
    44 
       
    45     pub fn send_self(message: HWServerMessage) -> PendingMessage {
       
    46         PendingMessage{ destination: Destination::ToSelf, message }
       
    47     }
       
    48 
       
    49     pub fn send_all(message: HWServerMessage) -> PendingMessage {
       
    50         let destination = Destination::ToAll {
       
    51             room_id: None,
       
    52             protocol: None,
       
    53             skip_self: false,
       
    54         };
       
    55         PendingMessage{ destination, message }
       
    56     }
       
    57 
       
    58     pub fn in_room(mut self, clients_room_id: RoomId) -> PendingMessage {
       
    59         if let Destination::ToAll {ref mut room_id, ..} = self.destination {
       
    60             *room_id = Some(clients_room_id)
       
    61         }
       
    62         self
       
    63     }
       
    64 
       
    65     pub fn with_protocol(mut self, protocol_number: u16) -> PendingMessage {
       
    66         if let Destination::ToAll {ref mut protocol, ..} = self.destination {
       
    67             *protocol = Some(protocol_number)
       
    68         }
       
    69         self
       
    70     }
       
    71 
       
    72     pub fn but_self(mut self) -> PendingMessage {
       
    73         if let Destination::ToAll {ref mut skip_self, ..} = self.destination {
       
    74             *skip_self = true
       
    75         }
       
    76         self
       
    77     }
       
    78 
       
    79     pub fn action(self) -> Action { Send(self) }
       
    80 }
       
    81 
       
    82 impl Into<Action> for PendingMessage {
       
    83     fn into(self) -> Action { self.action() }
       
    84 }
       
    85 
       
    86 impl HWServerMessage {
       
    87     pub fn send(self, client_id: ClientId) -> PendingMessage { PendingMessage::send(self, client_id) }
       
    88     pub fn send_self(self) -> PendingMessage { PendingMessage::send_self(self) }
       
    89     pub fn send_all(self) -> PendingMessage { PendingMessage::send_all(self) }
       
    90 }
       
    91 
       
    92 pub enum Action {
       
    93     Send(PendingMessage),
       
    94     RemoveClient,
       
    95     ByeClient(String),
       
    96     ReactProtocolMessage(HWProtocolMessage),
       
    97     CheckRegistered,
       
    98     JoinLobby,
       
    99     AddRoom(String, Option<String>),
       
   100     RemoveRoom(RoomId),
       
   101     MoveToRoom(RoomId),
       
   102     MoveToLobby(String),
       
   103     ChangeMaster(RoomId, Option<ClientId>),
       
   104     RemoveTeam(String),
       
   105     RemoveClientTeams,
       
   106     SendRoomUpdate(Option<String>),
       
   107     StartRoomGame(RoomId),
       
   108     SendTeamRemovalMessage(String),
       
   109     FinishRoomGame(RoomId),
       
   110     SendRoomData{to: ClientId, teams: bool, config: bool, flags: bool},
       
   111     AddVote{vote: bool, is_forced: bool},
       
   112     ApplyVoting(VoteType, RoomId),
       
   113     Warn(String),
       
   114     ProtocolError(String)
       
   115 }
       
   116 
       
   117 use self::Action::*;
       
   118 
       
   119 pub fn run_action(server: &mut HWServer, client_id: usize, action: Action) {
       
   120     match action {
       
   121         Send(msg) => server.send(client_id, &msg.destination, msg.message),
       
   122         ByeClient(msg) => {
       
   123             let c = &server.clients[client_id];
       
   124             let nick = c.nick.clone();
       
   125 
       
   126             if let Some(id) = c.room_id{
       
   127                 if id != server.lobby_id {
       
   128                     server.react(client_id, vec![
       
   129                         MoveToLobby(format!("quit: {}", msg.clone()))]);
       
   130                 }
       
   131             }
       
   132 
       
   133             server.react(client_id, vec![
       
   134                 LobbyLeft(nick, msg.clone()).send_all().action(),
       
   135                 Bye(msg).send_self().action(),
       
   136                 RemoveClient]);
       
   137         },
       
   138         RemoveClient => {
       
   139             server.removed_clients.push(client_id);
       
   140             if server.clients.contains(client_id) {
       
   141                 server.clients.remove(client_id);
       
   142             }
       
   143         },
       
   144         ReactProtocolMessage(msg) =>
       
   145             handlers::handle(server, client_id, msg),
       
   146         CheckRegistered => {
       
   147             let client = &server.clients[client_id];
       
   148             if client.protocol_number > 0 && client.nick != "" {
       
   149                 let has_nick_clash = server.clients.iter().any(
       
   150                     |(id, c)| id != client_id && c.nick == client.nick);
       
   151 
       
   152                 let actions = if !client.is_checker() && has_nick_clash {
       
   153                     if client.protocol_number < 38 {
       
   154                         vec![ByeClient("Nickname is already in use".to_string())]
       
   155                     } else {
       
   156                         server.clients[client_id].nick.clear();
       
   157                         vec![Notice("NickAlreadyInUse".to_string()).send_self().action()]
       
   158                     }
       
   159                 } else {
       
   160                     vec![JoinLobby]
       
   161                 };
       
   162                 server.react(client_id, actions);
       
   163             }
       
   164         },
       
   165         JoinLobby => {
       
   166             server.clients[client_id].room_id = Some(server.lobby_id);
       
   167 
       
   168             let mut lobby_nicks = Vec::new();
       
   169             for (_, c) in server.clients.iter() {
       
   170                 if c.room_id.is_some() {
       
   171                     lobby_nicks.push(c.nick.clone());
       
   172                 }
       
   173             }
       
   174             let joined_msg = LobbyJoined(lobby_nicks);
       
   175 
       
   176             let everyone_msg = LobbyJoined(vec![server.clients[client_id].nick.clone()]);
       
   177             let flags_msg = ClientFlags(
       
   178                 "+i".to_string(),
       
   179                 server.clients.iter()
       
   180                     .filter(|(_, c)| c.room_id.is_some())
       
   181                     .map(|(_, c)| c.nick.clone())
       
   182                     .collect());
       
   183             let server_msg = ServerMessage("\u{1f994} is watching".to_string());
       
   184             let rooms_msg = Rooms(server.rooms.iter()
       
   185                 .filter(|(id, _)| *id != server.lobby_id)
       
   186                 .flat_map(|(_, r)|
       
   187                     r.info(r.master_id.map(|id| &server.clients[id])))
       
   188                 .collect());
       
   189             server.react(client_id, vec![
       
   190                 everyone_msg.send_all().but_self().action(),
       
   191                 joined_msg.send_self().action(),
       
   192                 flags_msg.send_self().action(),
       
   193                 server_msg.send_self().action(),
       
   194                 rooms_msg.send_self().action(),
       
   195                 ]);
       
   196         },
       
   197         AddRoom(name, password) => {
       
   198             let room_id = server.add_room();;
       
   199 
       
   200             let r = &mut server.rooms[room_id];
       
   201             let c = &mut server.clients[client_id];
       
   202             r.master_id = Some(c.id);
       
   203             r.name = name;
       
   204             r.password = password;
       
   205             r.protocol_number = c.protocol_number;
       
   206 
       
   207             let actions = vec![
       
   208                 RoomAdd(r.info(Some(&c))).send_all()
       
   209                     .with_protocol(r.protocol_number).action(),
       
   210                 MoveToRoom(room_id)];
       
   211 
       
   212             server.react(client_id, actions);
       
   213         },
       
   214         RemoveRoom(room_id) => {
       
   215             let r = &mut server.rooms[room_id];
       
   216             let actions = vec![RoomRemove(r.name.clone()).send_all()
       
   217                 .with_protocol(r.protocol_number).action()];
       
   218             server.rooms.remove(room_id);
       
   219             server.react(client_id, actions);
       
   220         }
       
   221         MoveToRoom(room_id) => {
       
   222             let r = &mut server.rooms[room_id];
       
   223             let c = &mut server.clients[client_id];
       
   224             r.players_number += 1;
       
   225             c.room_id = Some(room_id);
       
   226 
       
   227             let is_master = r.master_id == Some(c.id);
       
   228             c.set_is_master(is_master);
       
   229             c.set_is_ready(is_master);
       
   230             c.set_is_joined_mid_game(false);
       
   231 
       
   232             if is_master {
       
   233                 r.ready_players_number += 1;
       
   234             }
       
   235 
       
   236             let mut v = vec![
       
   237                 RoomJoined(vec![c.nick.clone()]).send_all().in_room(room_id).action(),
       
   238                 ClientFlags("+i".to_string(), vec![c.nick.clone()]).send_all().action(),
       
   239                 SendRoomUpdate(None)];
       
   240 
       
   241             if !r.greeting.is_empty() {
       
   242                 v.push(ChatMsg {nick: "[greeting]".to_string(), msg: r.greeting.clone()}
       
   243                     .send_self().action());
       
   244             }
       
   245 
       
   246             if !c.is_master() {
       
   247                 let team_names: Vec<_>;
       
   248                 if let Some(ref mut info) = r.game_info {
       
   249                     c.set_is_in_game(true);
       
   250                     c.set_is_joined_mid_game(true);
       
   251 
       
   252                     {
       
   253                         let teams = info.client_teams(c.id);
       
   254                         c.teams_in_game = teams.clone().count() as u8;
       
   255                         c.clan = teams.clone().next().map(|t| t.color);
       
   256                         team_names = teams.map(|t| t.name.clone()).collect();
       
   257                     }
       
   258 
       
   259                     if !team_names.is_empty() {
       
   260                         info.left_teams.retain(|name|
       
   261                             !team_names.contains(&name));
       
   262                         info.teams_in_game += team_names.len() as u8;
       
   263                         r.teams = info.teams_at_start.iter()
       
   264                             .filter(|(_, t)| !team_names.contains(&t.name))
       
   265                             .cloned().collect();
       
   266                     }
       
   267                 } else {
       
   268                     team_names = Vec::new();
       
   269                 }
       
   270 
       
   271                 v.push(SendRoomData{ to: client_id, teams: true, config: true, flags: true});
       
   272 
       
   273                 if let Some(ref info) = r.game_info {
       
   274                     v.push(RunGame.send_self().action());
       
   275                     v.push(ClientFlags("+g".to_string(), vec![c.nick.clone()])
       
   276                         .send_all().in_room(r.id).action());
       
   277                     v.push(ForwardEngineMessage(
       
   278                         vec![to_engine_msg("e$spectate 1".bytes())])
       
   279                         .send_self().action());
       
   280                     v.push(ForwardEngineMessage(info.msg_log.clone())
       
   281                         .send_self().action());
       
   282 
       
   283                     for name in &team_names {
       
   284                         v.push(ForwardEngineMessage(
       
   285                             vec![to_engine_msg(once(b'G').chain(name.bytes()))])
       
   286                             .send_all().in_room(r.id).action());
       
   287                     }
       
   288                     if info.is_paused {
       
   289                         v.push(ForwardEngineMessage(vec![to_engine_msg(once(b'I'))])
       
   290                             .send_all().in_room(r.id).action())
       
   291                     }
       
   292                 }
       
   293             }
       
   294             server.react(client_id, v);
       
   295         }
       
   296         SendRoomData {to, teams, config, flags} => {
       
   297             let mut actions = Vec::new();
       
   298             let room_id = server.clients[client_id].room_id;
       
   299             if let Some(r) = room_id.and_then(|id| server.rooms.get(id)) {
       
   300                 if config {
       
   301                     actions.push(ConfigEntry("FULLMAPCONFIG".to_string(), r.map_config())
       
   302                         .send(to).action());
       
   303                     for cfg in r.game_config() {
       
   304                         actions.push(cfg.to_server_msg().send(to).action());
       
   305                     }
       
   306                 }
       
   307                 if teams {
       
   308                     let current_teams = match r.game_info {
       
   309                         Some(ref info) => &info.teams_at_start,
       
   310                         None => &r.teams
       
   311                     };
       
   312                     for (owner_id, team) in current_teams.iter() {
       
   313                         actions.push(TeamAdd(HWRoom::team_info(&server.clients[*owner_id], &team))
       
   314                             .send(to).action());
       
   315                         actions.push(TeamColor(team.name.clone(), team.color)
       
   316                             .send(to).action());
       
   317                         actions.push(HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
       
   318                             .send(to).action());
       
   319                     }
       
   320                 }
       
   321                 if flags {
       
   322                     if let Some(id) = r.master_id {
       
   323                         actions.push(ClientFlags("+h".to_string(), vec![server.clients[id].nick.clone()])
       
   324                             .send(to).action());
       
   325                     }
       
   326                     let nicks: Vec<_> = server.clients.iter()
       
   327                         .filter(|(_, c)| c.room_id == Some(r.id) && c.is_ready())
       
   328                         .map(|(_, c)| c.nick.clone()).collect();
       
   329                     if !nicks.is_empty() {
       
   330                         actions.push(ClientFlags("+r".to_string(), nicks)
       
   331                             .send(to).action());
       
   332                     }
       
   333                 }
       
   334             }
       
   335             server.react(client_id, actions);
       
   336         }
       
   337         AddVote{vote, is_forced} => {
       
   338             let mut actions = Vec::new();
       
   339             if let Some(r) = server.room(client_id) {
       
   340                 let mut result = None;
       
   341                 if let Some(ref mut voting) = r.voting {
       
   342                     if is_forced || voting.votes.iter().all(|(id, _)| client_id != *id) {
       
   343                         actions.push(server_chat("Your vote has been counted.".to_string())
       
   344                             .send_self().action());
       
   345                         voting.votes.push((client_id, vote));
       
   346                         let i = voting.votes.iter();
       
   347                         let pro = i.clone().filter(|(_, v)| *v).count();
       
   348                         let contra = i.filter(|(_, v)| !*v).count();
       
   349                         let success_quota = voting.voters.len() / 2 + 1;
       
   350                         if is_forced && vote || pro >= success_quota {
       
   351                             result = Some(true);
       
   352                         } else if is_forced && !vote || contra > voting.voters.len() - success_quota {
       
   353                             result = Some(false);
       
   354                         }
       
   355                     } else {
       
   356                         actions.push(server_chat("You already have voted.".to_string())
       
   357                             .send_self().action());
       
   358                     }
       
   359                 } else {
       
   360                     actions.push(server_chat("There's no voting going on.".to_string())
       
   361                         .send_self().action());
       
   362                 }
       
   363 
       
   364                 if let Some(res) = result {
       
   365                     actions.push(server_chat("Voting closed.".to_string())
       
   366                         .send_all().in_room(r.id).action());
       
   367                     let voting = replace(&mut r.voting, None).unwrap();
       
   368                     if res {
       
   369                         actions.push(ApplyVoting(voting.kind, r.id));
       
   370                     }
       
   371                 }
       
   372             }
       
   373 
       
   374             server.react(client_id, actions);
       
   375         }
       
   376         ApplyVoting(kind, room_id) => {
       
   377             let mut actions = Vec::new();
       
   378             let mut id = client_id;
       
   379             match kind {
       
   380                 VoteType::Kick(nick) => {
       
   381                     if let Some(c) = server.find_client(&nick) {
       
   382                         if c.room_id == Some(room_id) {
       
   383                             id = c.id;
       
   384                             actions.push(Kicked.send_self().action());
       
   385                             actions.push(MoveToLobby("kicked".to_string()));
       
   386                         }
       
   387                     }
       
   388                 },
       
   389                 VoteType::Map(None) => (),
       
   390                 VoteType::Map(Some(name)) => {
       
   391                     if let Some(location) = server.rooms[room_id].load_config(&name) {
       
   392                         actions.push(server_chat(location.to_string())
       
   393                             .send_all().in_room(room_id).action());
       
   394                         actions.push(SendRoomUpdate(None));
       
   395                         for (_, c) in server.clients.iter() {
       
   396                             if c.room_id == Some(room_id) {
       
   397                                actions.push(SendRoomData{
       
   398                                    to: c.id, teams: false,
       
   399                                    config: true, flags: false})
       
   400                             }
       
   401                         }
       
   402                     }
       
   403                 },
       
   404                 VoteType::Pause => {
       
   405                     if let Some(ref mut info) = server.rooms[room_id].game_info {
       
   406                         info.is_paused = !info.is_paused;
       
   407                         actions.push(server_chat("Pause toggled.".to_string())
       
   408                             .send_all().in_room(room_id).action());
       
   409                         actions.push(ForwardEngineMessage(vec![to_engine_msg(once(b'I'))])
       
   410                             .send_all().in_room(room_id).action());
       
   411                     }
       
   412                 },
       
   413                 VoteType::NewSeed => {
       
   414                     let seed = thread_rng().gen_range(0, 1_000_000_000).to_string();
       
   415                     let cfg = GameCfg::Seed(seed);
       
   416                     actions.push(cfg.to_server_msg().send_all().in_room(room_id).action());
       
   417                     server.rooms[room_id].set_config(cfg);
       
   418                 },
       
   419                 VoteType::HedgehogsPerTeam(number) => {
       
   420                     let r = &mut server.rooms[room_id];
       
   421                     let nicks = r.set_hedgehogs_number(number);
       
   422                     actions.extend(nicks.into_iter().map(|n|
       
   423                         HedgehogsNumber(n, number).send_all().in_room(room_id).action()
       
   424                     ));
       
   425                 },
       
   426             }
       
   427             server.react(id, actions);
       
   428         }
       
   429         MoveToLobby(msg) => {
       
   430             let mut actions = Vec::new();
       
   431             let lobby_id = server.lobby_id;
       
   432             if let (c, Some(r)) = server.client_and_room(client_id) {
       
   433                 r.players_number -= 1;
       
   434                 if c.is_ready() && r.ready_players_number > 0 {
       
   435                     r.ready_players_number -= 1;
       
   436                 }
       
   437                 if c.is_master() && (r.players_number > 0 || r.is_fixed()) {
       
   438                     actions.push(ChangeMaster(r.id, None));
       
   439                 }
       
   440                 actions.push(ClientFlags("-i".to_string(), vec![c.nick.clone()])
       
   441                     .send_all().action());
       
   442             }
       
   443             server.react(client_id, actions);
       
   444             actions = Vec::new();
       
   445 
       
   446             if let (c, Some(r)) = server.client_and_room(client_id) {
       
   447                 c.room_id = Some(lobby_id);
       
   448                 if r.players_number == 0 && !r.is_fixed() {
       
   449                     actions.push(RemoveRoom(r.id));
       
   450                 } else {
       
   451                     actions.push(RemoveClientTeams);
       
   452                     actions.push(RoomLeft(c.nick.clone(), msg)
       
   453                         .send_all().in_room(r.id).but_self().action());
       
   454                     actions.push(SendRoomUpdate(Some(r.name.clone())));
       
   455                 }
       
   456             }
       
   457             server.react(client_id, actions)
       
   458         }
       
   459         ChangeMaster(room_id, new_id) => {
       
   460             let mut actions = Vec::new();
       
   461             let room_client_ids = server.room_clients(room_id);
       
   462             let new_id = if server.room(client_id).map(|r| r.is_fixed()).unwrap_or(false) {
       
   463                 new_id
       
   464             } else {
       
   465                 new_id.or_else(||
       
   466                     room_client_ids.iter().find(|id| **id != client_id).cloned())
       
   467             };
       
   468             let new_nick = new_id.map(|id| server.clients[id].nick.clone());
       
   469 
       
   470             if let (c, Some(r)) = server.client_and_room(client_id) {
       
   471                 match r.master_id {
       
   472                     Some(id) if id == c.id => {
       
   473                         c.set_is_master(false);
       
   474                         r.master_id = None;
       
   475                         actions.push(ClientFlags("-h".to_string(), vec![c.nick.clone()])
       
   476                             .send_all().in_room(r.id).action());
       
   477                     }
       
   478                     Some(_) => unreachable!(),
       
   479                     None => {}
       
   480                 }
       
   481                 r.master_id = new_id;
       
   482                 if !r.is_fixed() && c.protocol_number < 42 {
       
   483                     r.name.replace_range(.., new_nick.as_ref().map_or("[]", String::as_str));
       
   484                 }
       
   485                 r.set_join_restriction(false);
       
   486                 r.set_team_add_restriction(false);
       
   487                 let is_fixed = r.is_fixed();
       
   488                 r.set_unregistered_players_restriction(is_fixed);
       
   489                 if let Some(nick) = new_nick {
       
   490                     actions.push(ClientFlags("+h".to_string(), vec![nick])
       
   491                         .send_all().in_room(r.id).action());
       
   492                 }
       
   493             }
       
   494             if let Some(id) = new_id {
       
   495                 server.clients[id].set_is_master(true)
       
   496             }
       
   497             server.react(client_id, actions);
       
   498         }
       
   499         RemoveTeam(name) => {
       
   500             let mut actions = Vec::new();
       
   501             if let (c, Some(r)) = server.client_and_room(client_id) {
       
   502                 r.remove_team(&name);
       
   503                 if let Some(ref mut info) = r.game_info {
       
   504                     info.left_teams.push(name.clone());
       
   505                 }
       
   506                 actions.push(TeamRemove(name.clone()).send_all().in_room(r.id).action());
       
   507                 actions.push(SendRoomUpdate(None));
       
   508                 if r.game_info.is_some() && c.is_in_game() {
       
   509                     actions.push(SendTeamRemovalMessage(name));
       
   510                 }
       
   511             }
       
   512             server.react(client_id, actions);
       
   513         },
       
   514         RemoveClientTeams => {
       
   515             if let (c, Some(r)) = server.client_and_room(client_id) {
       
   516                 let actions = r.client_teams(c.id).map(|t| RemoveTeam(t.name.clone())).collect();
       
   517                 server.react(client_id, actions);
       
   518             }
       
   519         }
       
   520         SendRoomUpdate(old_name) => {
       
   521             if let (c, Some(r)) = server.client_and_room(client_id) {
       
   522                 let name = old_name.unwrap_or_else(|| r.name.clone());
       
   523                 let actions = vec![RoomUpdated(name, r.info(Some(&c)))
       
   524                     .send_all().with_protocol(r.protocol_number).action()];
       
   525                 server.react(client_id, actions);
       
   526             }
       
   527         },
       
   528         StartRoomGame(room_id) => {
       
   529             let actions = {
       
   530                 let (room_clients, room_nicks): (Vec<_>, Vec<_>) = server.clients.iter()
       
   531                     .map(|(id, c)| (id, c.nick.clone())).unzip();
       
   532                 let room = &mut server.rooms[room_id];
       
   533 
       
   534                 if !room.has_multiple_clans() {
       
   535                     vec![Warn("The game can't be started with less than two clans!".to_string())]
       
   536                 } else if room.protocol_number <= 43 && room.players_number != room.ready_players_number {
       
   537                     vec![Warn("Not all players are ready".to_string())]
       
   538                 } else if room.game_info.is_some() {
       
   539                     vec![Warn("The game is already in progress".to_string())]
       
   540                 } else {
       
   541                     room.start_round();
       
   542                     for id in room_clients {
       
   543                         let c = &mut server.clients[id];
       
   544                         c.set_is_in_game(false);
       
   545                         c.team_indices = room.client_team_indices(c.id);
       
   546                     }
       
   547                     vec![RunGame.send_all().in_room(room.id).action(),
       
   548                          SendRoomUpdate(None),
       
   549                          ClientFlags("+g".to_string(), room_nicks)
       
   550                              .send_all().in_room(room.id).action()]
       
   551                 }
       
   552             };
       
   553             server.react(client_id, actions);
       
   554         }
       
   555         SendTeamRemovalMessage(team_name) => {
       
   556             let mut actions = Vec::new();
       
   557             if let Some(r) = server.room(client_id) {
       
   558                 if let Some(ref mut info) = r.game_info {
       
   559                     let msg = once(b'F').chain(team_name.bytes());
       
   560                     actions.push(ForwardEngineMessage(vec![to_engine_msg(msg)]).
       
   561                         send_all().in_room(r.id).but_self().action());
       
   562                     info.teams_in_game -= 1;
       
   563                     if info.teams_in_game == 0 {
       
   564                         actions.push(FinishRoomGame(r.id));
       
   565                     }
       
   566                     let remove_msg = to_engine_msg(once(b'F').chain(team_name.bytes()));
       
   567                     if let Some(m) = &info.sync_msg {
       
   568                         info.msg_log.push(m.clone());
       
   569                     }
       
   570                     if info.sync_msg.is_some() {
       
   571                         info.sync_msg = None
       
   572                     }
       
   573                     info.msg_log.push(remove_msg.clone());
       
   574                     actions.push(ForwardEngineMessage(vec![remove_msg])
       
   575                         .send_all().in_room(r.id).but_self().action());
       
   576                 }
       
   577             }
       
   578             server.react(client_id, actions);
       
   579         }
       
   580         FinishRoomGame(room_id) => {
       
   581             let mut actions = Vec::new();
       
   582 
       
   583             let r = &mut server.rooms[room_id];
       
   584             r.ready_players_number = 1;
       
   585             actions.push(SendRoomUpdate(None));
       
   586             actions.push(RoundFinished.send_all().in_room(r.id).action());
       
   587 
       
   588             if let Some(info) = replace(&mut r.game_info, None) {
       
   589                 for (_, c) in server.clients.iter() {
       
   590                     if c.room_id == Some(room_id) && c.is_joined_mid_game() {
       
   591                         actions.push(SendRoomData{
       
   592                             to: c.id, teams: false,
       
   593                             config: true, flags: false});
       
   594                         for name in &info.left_teams {
       
   595                             actions.push(TeamRemove(name.clone())
       
   596                                 .send(c.id).action());
       
   597                         }
       
   598                     }
       
   599                 }
       
   600             }
       
   601 
       
   602             let nicks: Vec<_> = server.clients.iter_mut()
       
   603                 .filter(|(_, c)| c.room_id == Some(room_id))
       
   604                 .map(|(_, c)| {
       
   605                     c.set_is_ready(c.is_master());
       
   606                     c.set_is_joined_mid_game(false);
       
   607                     c
       
   608                 }).filter_map(|c| if !c.is_master() {
       
   609                     Some(c.nick.clone())
       
   610                 } else {
       
   611                     None
       
   612                 }).collect();
       
   613 
       
   614             if !nicks.is_empty() {
       
   615                 let msg = if r.protocol_number < 38 {
       
   616                     LegacyReady(false, nicks)
       
   617                 } else {
       
   618                     ClientFlags("-r".to_string(), nicks)
       
   619                 };
       
   620                 actions.push(msg.send_all().in_room(room_id).action());
       
   621             }
       
   622             server.react(client_id, actions);
       
   623         }
       
   624         Warn(msg) => {
       
   625             run_action(server, client_id, Warning(msg).send_self().action());
       
   626         }
       
   627         ProtocolError(msg) => {
       
   628             run_action(server, client_id, Error(msg).send_self().action())
       
   629         }
       
   630     }
       
   631 }