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, |
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 { |
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]; |
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())); |
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 { |