1 use super::{common::rnd_reply, strings::*}; |
1 use super::{common::rnd_reply, strings::*}; |
2 use crate::core::room::GameInfo; |
2 use crate::core::room::GameInfo; |
3 use crate::core::server::AddTeamError; |
3 use crate::core::server::{AddTeamError, SetTeamCountError}; |
4 use crate::{ |
4 use crate::{ |
5 core::{ |
5 core::{ |
6 room::{HwRoom, RoomFlags, MAX_TEAMS_IN_ROOM}, |
6 room::{HwRoom, RoomFlags, MAX_TEAMS_IN_ROOM}, |
7 server::{ |
7 server::{ |
8 ChangeMasterError, ChangeMasterResult, HwServer, LeaveRoomResult, ModifyTeamError, |
8 ChangeMasterError, ChangeMasterResult, HwRoomControl, LeaveRoomResult, ModifyTeamError, |
9 StartGameError, |
9 StartGameError, |
10 }, |
10 }, |
11 types, |
11 types, |
12 types::{ClientId, GameCfg, RoomId, VoteType, Voting, MAX_HEDGEHOGS_PER_TEAM}, |
12 types::{ClientId, GameCfg, RoomId, VoteType, Voting, MAX_HEDGEHOGS_PER_TEAM}, |
13 }, |
13 }, |
104 _ => RoomFlags::empty(), |
104 _ => RoomFlags::empty(), |
105 } |
105 } |
106 } |
106 } |
107 |
107 |
108 pub fn handle( |
108 pub fn handle( |
109 server: &mut HwServer, |
109 mut room_control: HwRoomControl, |
110 client_id: ClientId, |
|
111 response: &mut super::Response, |
110 response: &mut super::Response, |
112 room_id: RoomId, |
|
113 message: HwProtocolMessage, |
111 message: HwProtocolMessage, |
114 ) { |
112 ) { |
115 let (client, room) = server.client_and_room_mut(client_id, room_id); |
113 let (client, room) = room_control.get(); |
|
114 let (client_id, room_id) = (client.id, room.id); |
116 |
115 |
117 use crate::protocol::messages::HwProtocolMessage::*; |
116 use crate::protocol::messages::HwProtocolMessage::*; |
118 match message { |
117 match message { |
119 Part(msg) => { |
118 Part(msg) => { |
120 let msg = match msg { |
119 let msg = match msg { |
121 Some(s) => format!("part: {}", s), |
120 Some(s) => format!("part: {}", s), |
122 None => "part".to_string(), |
121 None => "part".to_string(), |
123 }; |
122 }; |
124 |
123 |
125 let result = server.leave_room(client_id); |
124 let result = room_control.leave_room(); |
126 super::common::get_room_leave_data(server, room_id, &msg, result, response); |
125 super::common::get_room_leave_result( |
|
126 room_control.server(), |
|
127 room_control.room(), |
|
128 &msg, |
|
129 result, |
|
130 response, |
|
131 ); |
127 } |
132 } |
128 Chat(msg) => { |
133 Chat(msg) => { |
129 response.add( |
134 response.add( |
130 ChatMsg { |
135 ChatMsg { |
131 nick: client.nick.clone(), |
136 nick: client.nick.clone(), |
144 response.add(ForwardEngineMessage(vec![engine_msg]).send_many(team)) |
149 response.add(ForwardEngineMessage(vec![engine_msg]).send_many(team)) |
145 } |
150 } |
146 } |
151 } |
147 } |
152 } |
148 Fix => { |
153 Fix => { |
149 if client.is_admin() { |
154 if let Err(_) = room_control.fix_room() { |
150 room.set_is_fixed(true); |
|
151 room.set_join_restriction(false); |
|
152 room.set_team_add_restriction(false); |
|
153 room.set_unregistered_players_restriction(true); |
|
154 } else { |
|
155 response.warn(ACCESS_DENIED) |
155 response.warn(ACCESS_DENIED) |
156 } |
156 } |
157 } |
157 } |
158 Unfix => { |
158 Unfix => { |
159 if client.is_admin() { |
159 if let Err(_) = room_control.unfix_room() { |
160 room.set_is_fixed(false); |
|
161 } else { |
|
162 response.warn(ACCESS_DENIED) |
160 response.warn(ACCESS_DENIED) |
163 } |
161 } |
164 } |
162 } |
165 Greeting(text) => { |
163 Greeting(text) => { |
166 if client.is_admin() || client.is_master() && !room.is_fixed() { |
164 if let Err(_) = room_control.set_room_greeting(text) { |
167 room.greeting = text.unwrap_or(String::new()); |
165 response.warn(ACCESS_DENIED) |
168 } |
166 } |
169 } |
167 } |
170 MaxTeams(count) => { |
168 MaxTeams(count) => { |
171 if !client.is_master() { |
169 use crate::core::server::SetTeamCountError; |
172 response.warn(NOT_MASTER); |
170 match room_control.set_room_max_teams(count) { |
173 } else if !(2..=MAX_TEAMS_IN_ROOM).contains(&count) { |
171 Ok(()) => {} |
174 response.warn("/maxteams: specify number from 2 to 8"); |
172 Err(SetTeamCountError::NotMaster) => response.warn(NOT_MASTER), |
175 } else { |
173 Err(SetTeamCountError::InvalidNumber) => { |
176 room.max_teams = count; |
174 response.warn("/maxteams: specify number from 2 to 8") |
177 } |
175 } |
|
176 }; |
178 } |
177 } |
179 RoomName(new_name) => { |
178 RoomName(new_name) => { |
180 use crate::core::server::ModifyRoomNameError; |
179 use crate::core::server::ModifyRoomNameError; |
181 match server.set_room_name(client_id, room_id, new_name) { |
180 match room_control.set_room_name(new_name) { |
182 Ok(old_name) => { |
181 Ok(old_name) => { |
183 let (client, room) = server.client_and_room(client_id, room_id); |
182 let (client, room) = room_control.get(); |
184 super::common::get_room_update(Some(old_name), room, Some(client), response) |
183 super::common::get_room_update(Some(old_name), room, Some(client), response) |
185 } |
184 } |
186 Err(ModifyRoomNameError::AccessDenied) => response.warn(ACCESS_DENIED), |
185 Err(ModifyRoomNameError::AccessDenied) => response.warn(ACCESS_DENIED), |
187 Err(ModifyRoomNameError::InvalidName) => response.warn(ILLEGAL_ROOM_NAME), |
186 Err(ModifyRoomNameError::InvalidName) => response.warn(ILLEGAL_ROOM_NAME), |
188 Err(ModifyRoomNameError::DuplicateName) => response.warn(ROOM_EXISTS), |
187 Err(ModifyRoomNameError::DuplicateName) => response.warn(ROOM_EXISTS), |
189 } |
188 } |
190 } |
189 } |
191 ToggleReady => { |
190 ToggleReady => { |
192 let flags = if server.toggle_ready(client_id) { |
191 let flags = if room_control.toggle_ready() { |
193 add_flags(&[Flags::Ready]) |
192 add_flags(&[Flags::Ready]) |
194 } else { |
193 } else { |
195 remove_flags(&[Flags::Ready]) |
194 remove_flags(&[Flags::Ready]) |
196 }; |
195 }; |
197 let (client, room) = server.client_and_room(client_id, room_id); |
196 let (client, room) = room_control.get(); |
198 |
197 |
199 let msg = if client.protocol_number < 38 { |
198 let msg = if client.protocol_number < 38 { |
200 LegacyReady(client.is_ready(), vec![client.nick.clone()]) |
199 LegacyReady(client.is_ready(), vec![client.nick.clone()]) |
201 } else { |
200 } else { |
202 ClientFlags(flags, vec![client.nick.clone()]) |
201 ClientFlags(flags, vec![client.nick.clone()]) |
203 }; |
202 }; |
204 response.add(msg.send_all().in_room(room_id)); |
203 response.add(msg.send_all().in_room(room_id)); |
205 |
204 |
206 if room.is_fixed() && room.ready_players_number == room.players_number { |
205 if room.is_fixed() && room.ready_players_number == room.players_number { |
207 let result = server.start_game(room_id); |
206 let result = room_control.start_game(); |
208 super::common::get_start_game_data(server, room_id, result, response); |
207 super::common::get_start_game_data( |
|
208 room_control.server(), |
|
209 room_id, |
|
210 result, |
|
211 response, |
|
212 ); |
209 } |
213 } |
210 } |
214 } |
211 AddTeam(info) => { |
215 AddTeam(info) => { |
212 use crate::core::server::AddTeamError; |
216 use crate::core::server::AddTeamError; |
213 match server.add_team(client_id, info) { |
217 match room_control.add_team(info) { |
214 Ok(team) => { |
218 Ok(team) => { |
215 response.add(TeamAccepted(team.name.clone()).send_self()); |
219 response.add(TeamAccepted(team.name.clone()).send_self()); |
216 response.add( |
220 response.add( |
217 TeamAdd(team.to_protocol()) |
221 TeamAdd(team.to_protocol()) |
218 .send_all() |
222 .send_all() |
259 response, |
263 response, |
260 ); |
264 ); |
261 |
265 |
262 match room.game_info { |
266 match room.game_info { |
263 Some(ref info) if info.teams_in_game == 0 => { |
267 Some(ref info) if info.teams_in_game == 0 => { |
264 let result = server.end_game(room_id); |
268 if let Some(result) = room_control.end_game() { |
265 super::common::get_end_game_result(server, room_id, result, response); |
269 super::common::get_end_game_result( |
|
270 room_control.server(), |
|
271 room_id, |
|
272 result, |
|
273 response, |
|
274 ); |
|
275 } |
266 } |
276 } |
267 _ => (), |
277 _ => (), |
268 } |
278 } |
269 } |
279 } |
270 Err(RemoveTeamError::NoTeam) => response.warn(NO_TEAM_TO_REMOVE), |
280 Err(RemoveTeamError::NoTeam) => response.warn(NO_TEAM_TO_REMOVE), |
271 Err(RemoveTeamError::TeamNotOwned) => response.warn(TEAM_NOT_OWNED), |
281 Err(RemoveTeamError::TeamNotOwned) => response.warn(TEAM_NOT_OWNED), |
272 } |
282 } |
273 } |
283 } |
274 SetHedgehogsNumber(team_name, number) => { |
284 SetHedgehogsNumber(team_name, number) => { |
275 let addable_hedgehogs = room.addable_hedgehogs(); |
285 use crate::core::server::SetHedgehogsError; |
276 if let Some((_, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) { |
286 match room_control.set_team_hedgehogs_number(&team_name, number) { |
277 let max_hedgehogs = min( |
287 Ok(()) => { |
278 MAX_HEDGEHOGS_PER_TEAM, |
288 response.add( |
279 addable_hedgehogs + team.hedgehogs_number, |
289 HedgehogsNumber(team_name.clone(), number) |
280 ); |
|
281 if !client.is_master() { |
|
282 response.error(NOT_MASTER); |
|
283 } else if !(1..=max_hedgehogs).contains(&number) { |
|
284 response |
|
285 .add(HedgehogsNumber(team.name.clone(), team.hedgehogs_number).send_self()); |
|
286 } else { |
|
287 team.hedgehogs_number = number; |
|
288 response.add( |
|
289 HedgehogsNumber(team.name.clone(), number) |
|
290 .send_all() |
290 .send_all() |
291 .in_room(room_id) |
291 .in_room(room_id) |
292 .but_self(), |
292 .but_self(), |
293 ); |
293 ); |
294 } |
294 } |
295 } else { |
295 Err(SetHedgehogsError::NotMaster) => response.error(NOT_MASTER), |
296 response.warn(NO_TEAM); |
296 Err(SetHedgehogsError::NoTeam) => response.warn(NO_TEAM), |
297 } |
297 Err(SetHedgehogsError::InvalidNumber(previous_number)) => { |
298 } |
298 response.add(HedgehogsNumber(team_name.clone(), previous_number).send_self()) |
299 SetTeamColor(team_name, color) => { |
299 } |
300 match server.set_team_color(client_id, room_id, &team_name, color) { |
300 } |
301 Ok(()) => response.add( |
301 } |
302 TeamColor(team_name, color) |
302 SetTeamColor(team_name, color) => match room_control.set_team_color(&team_name, color) { |
303 .send_all() |
303 Ok(()) => response.add( |
304 .in_room(room_id) |
304 TeamColor(team_name, color) |
305 .but_self(), |
305 .send_all() |
306 ), |
306 .in_room(room_id) |
307 Err(ModifyTeamError::NoTeam) => response.warn(NO_TEAM), |
307 .but_self(), |
308 Err(ModifyTeamError::NotMaster) => response.error(NOT_MASTER), |
308 ), |
309 } |
309 Err(ModifyTeamError::NoTeam) => response.warn(NO_TEAM), |
310 } |
310 Err(ModifyTeamError::NotMaster) => response.error(NOT_MASTER), |
|
311 }, |
311 Cfg(cfg) => { |
312 Cfg(cfg) => { |
312 if room.is_fixed() { |
313 use crate::core::server::SetConfigError; |
313 response.warn(ACCESS_DENIED); |
314 let msg = cfg.to_server_msg(); |
314 } else if !client.is_master() { |
315 match room_control.set_config(cfg) { |
315 response.error(NOT_MASTER); |
316 Ok(()) => { |
316 } else { |
317 response.add(msg.send_all().in_room(room_control.room().id).but_self()); |
317 let cfg = match cfg { |
318 } |
318 GameCfg::Scheme(name, mut values) => { |
319 Err(SetConfigError::NotMaster) => response.error(NOT_MASTER), |
319 if client.protocol_number == 49 && values.len() >= 2 { |
320 Err(SetConfigError::RoomFixed) => response.warn(ACCESS_DENIED), |
320 let mut s = "X".repeat(50); |
|
321 s.push_str(&values.pop().unwrap()); |
|
322 values.push(s); |
|
323 } |
|
324 GameCfg::Scheme(name, values) |
|
325 } |
|
326 cfg => cfg, |
|
327 }; |
|
328 |
|
329 response.add(cfg.to_server_msg().send_all().in_room(room.id).but_self()); |
|
330 room.set_config(cfg); |
|
331 } |
321 } |
332 } |
322 } |
333 Save(name, location) => { |
323 Save(name, location) => { |
334 response.add( |
324 response.add( |
335 server_chat(format!("Room config saved as {}", name)) |
325 server_chat(format!("Room config saved as {}", name)) |
336 .send_all() |
326 .send_all() |
337 .in_room(room_id), |
327 .in_room(room_id), |
338 ); |
328 ); |
339 room.save_config(name, location); |
329 room_control.save_config(name, location); |
340 } |
330 } |
341 #[cfg(feature = "official-server")] |
331 #[cfg(feature = "official-server")] |
342 SaveRoom(filename) => { |
332 SaveRoom(filename) => { |
343 if client.is_admin() { |
333 if client.is_admin() { |
344 match room.get_saves() { |
334 match room.get_saves() { |
373 } |
363 } |
374 CallVote(None) => { |
364 CallVote(None) => { |
375 response.add(server_chat("Available callvote commands: kick <nickname>, map <name>, pause, newseed, hedgehogs <number>".to_string()) |
365 response.add(server_chat("Available callvote commands: kick <nickname>, map <name>, pause, newseed, hedgehogs <number>".to_string()) |
376 .send_self()); |
366 .send_self()); |
377 } |
367 } |
378 CallVote(Some(kind)) => { |
368 /*CallVote(Some(kind)) => { |
379 let is_in_game = room.game_info.is_some(); |
369 let is_in_game = room.game_info.is_some(); |
380 let error = match &kind { |
370 let error = match &kind { |
381 VoteType::Kick(nick) => { |
371 VoteType::Kick(nick) => { |
382 if server |
372 if room_control.server() |
383 .find_client(&nick) |
373 .find_client(&nick) |
384 .filter(|c| c.room_id == Some(room_id)) |
374 .filter(|c| c.room_id == Some(room_id)) |
385 .is_some() |
375 .is_some() |
386 { |
376 { |
387 None |
377 None |
388 } else { |
378 } else { |
389 Some("/callvote kick: No such user!".to_string()) |
379 Some("/callvote kick: No such user!".to_string()) |
390 } |
380 } |
391 } |
381 } |
392 VoteType::Map(None) => { |
382 VoteType::Map(None) => { |
393 let names: Vec<_> = server.room(room_id).saves.keys().cloned().collect(); |
383 let names: Vec<_> = room.saves.keys().cloned().collect(); |
394 if names.is_empty() { |
384 if names.is_empty() { |
395 Some("/callvote map: No maps saved in this room!".to_string()) |
385 Some("/callvote map: No maps saved in this room!".to_string()) |
396 } else { |
386 } else { |
397 Some(format!("Available maps: {}", names.join(", "))) |
387 Some(format!("Available maps: {}", names.join(", "))) |
398 } |
388 } |
436 } |
426 } |
437 Some(msg) => { |
427 Some(msg) => { |
438 response.add(server_chat(msg).send_self()); |
428 response.add(server_chat(msg).send_self()); |
439 } |
429 } |
440 } |
430 } |
441 } |
431 }*/ |
442 Vote(vote) => { |
432 /*Vote(vote) => { |
443 super::common::submit_vote( |
433 super::common::submit_vote( |
444 server, |
434 room_control.server(), |
445 types::Vote { |
435 types::Vote { |
446 is_pro: vote, |
436 is_pro: vote, |
447 is_forced: false, |
437 is_forced: false, |
448 }, |
438 }, |
449 response, |
439 response, |
450 ); |
440 ); |
451 } |
441 }*/ |
452 ForceVote(vote) => { |
442 /*ForceVote(vote) => { |
453 let is_forced = client.is_admin(); |
443 let is_forced = client.is_admin(); |
454 super::common::submit_vote( |
444 super::common::submit_vote( |
455 server, |
445 room_control.server(), |
456 types::Vote { |
446 types::Vote { |
457 is_pro: vote, |
447 is_pro: vote, |
458 is_forced, |
448 is_forced, |
459 }, |
449 }, |
460 response, |
450 response, |
461 ); |
451 ); |
462 } |
452 }*/ |
463 ToggleRestrictJoin | ToggleRestrictTeams | ToggleRegisteredOnly => { |
453 ToggleRestrictJoin | ToggleRestrictTeams | ToggleRegisteredOnly => { |
464 if client.is_master() { |
454 if room_control.toggle_flag(room_message_flag(&message)) { |
465 room.flags.toggle(room_message_flag(&message)); |
455 let (client, room) = room_control.get(); |
466 super::common::get_room_update(None, room, Some(&client), response); |
456 super::common::get_room_update(None, room, Some(&client), response); |
467 } |
457 } |
468 } |
458 } |
469 StartGame => { |
459 StartGame => { |
470 let result = server.start_game(room_id); |
460 let result = room_control.start_game(); |
471 super::common::get_start_game_data(server, room_id, result, response); |
461 super::common::get_start_game_data(room_control.server(), room_id, result, response); |
472 } |
462 } |
473 EngineMessage(em) => { |
463 /*EngineMessage(em) => { |
474 if client.teams_in_game > 0 { |
464 if client.teams_in_game > 0 { |
475 let decoding = decode(&em[..]).unwrap(); |
465 let decoding = decode(&em[..]).unwrap(); |
476 let messages = by_msg(&decoding); |
466 let messages = by_msg(&decoding); |
477 let valid = messages.filter(|m| is_msg_valid(m, &client.team_indices)); |
467 let valid = messages.filter(|m| is_msg_valid(m, &client.team_indices)); |
478 let non_empty = valid.clone().filter(|m| !is_msg_empty(m)); |
468 let non_empty = valid.clone().filter(|m| !is_msg_empty(m)); |
525 |
515 |
526 if let Some(GameInfo { |
516 if let Some(GameInfo { |
527 teams_in_game: 0, .. |
517 teams_in_game: 0, .. |
528 }) = room.game_info |
518 }) = room.game_info |
529 { |
519 { |
530 let result = server.end_game(room_id); |
520 if let Some(result) = room_control.end_game() { |
531 super::common::get_end_game_result(server, room_id, result, response); |
521 super::common::get_end_game_result( |
|
522 room_control.server(), |
|
523 room_id, |
|
524 result, |
|
525 response, |
|
526 ); |
|
527 } |
532 } |
528 } |
533 } |
529 } |
534 } |
530 } |
535 Rnd(v) => { |
531 Rnd(v) => { |
536 let result = rnd_reply(&v); |
532 let result = rnd_reply(&v); |
537 let mut echo = vec!["/rnd".to_string()]; |
533 let mut echo = vec!["/rnd".to_string()]; |
538 echo.extend(v.into_iter()); |
534 echo.extend(v.into_iter()); |
539 let chat_msg = ChatMsg { |
535 let chat_msg = ChatMsg { |
540 nick: server.client(client_id).nick.clone(), |
536 nick: client.nick.clone(), |
541 msg: echo.join(" "), |
537 msg: echo.join(" "), |
542 }; |
538 }; |
543 response.add(chat_msg.send_all().in_room(room_id)); |
539 response.add(chat_msg.send_all().in_room(room_id)); |
544 response.add(result.send_all().in_room(room_id)); |
540 response.add(result.send_all().in_room(room_id)); |
545 } |
541 } |
546 Delegate(nick) => match server.change_master(client_id, room_id, nick) { |
542 Delegate(nick) => match room_control.change_master(nick) { |
547 Ok(ChangeMasterResult { |
543 Ok(ChangeMasterResult { |
548 old_master_id, |
544 old_master_id, |
549 new_master_id, |
545 new_master_id, |
550 }) => { |
546 }) => { |
551 if let Some(master_id) = old_master_id { |
547 if let Some(master_id) = old_master_id { |
552 response.add( |
548 response.add( |
553 ClientFlags( |
549 ClientFlags( |
554 remove_flags(&[Flags::RoomMaster]), |
550 remove_flags(&[Flags::RoomMaster]), |
555 vec![server.client(master_id).nick.clone()], |
551 vec![room_control.server().client(master_id).nick.clone()], |
556 ) |
552 ) |
557 .send_all() |
553 .send_all() |
558 .in_room(room_id), |
554 .in_room(room_id), |
559 ); |
555 ); |
560 } |
556 } |
561 response.add( |
557 response.add( |
562 ClientFlags( |
558 ClientFlags( |
563 add_flags(&[Flags::RoomMaster]), |
559 add_flags(&[Flags::RoomMaster]), |
564 vec![server.client(new_master_id).nick.clone()], |
560 vec![room_control.server().client(new_master_id).nick.clone()], |
565 ) |
561 ) |
566 .send_all() |
562 .send_all() |
567 .in_room(room_id), |
563 .in_room(room_id), |
568 ); |
564 ); |
569 } |
565 } |