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