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