1 use super::{ |
1 use super::{ |
2 client::HwClient, |
2 client::HwClient, |
3 indexslab::IndexSlab, |
3 indexslab::IndexSlab, |
4 room::HwRoom, |
4 room::HwRoom, |
5 types::{ClientId, RoomId, ServerVar}, |
5 types::{ClientId, RoomId, ServerVar, TeamInfo}, |
6 }; |
6 }; |
7 use crate::{protocol::messages::HwProtocolMessage::Greeting, utils}; |
7 use crate::{protocol::messages::HwProtocolMessage::Greeting, utils}; |
8 |
8 |
|
9 use bitflags::_core::hint::unreachable_unchecked; |
9 use bitflags::*; |
10 use bitflags::*; |
10 use chrono::{offset, DateTime}; |
11 use chrono::{offset, DateTime}; |
11 use log::*; |
12 use log::*; |
12 use slab::Slab; |
13 use slab::Slab; |
13 use std::{borrow::BorrowMut, collections::HashSet, iter, mem::replace, num::NonZeroU16}; |
14 use std::{borrow::BorrowMut, collections::HashSet, iter, mem::replace, num::NonZeroU16}; |
227 fn client_mut(&mut self, client_id: ClientId) -> &mut HwClient { |
243 fn client_mut(&mut self, client_id: ClientId) -> &mut HwClient { |
228 &mut self.clients[client_id] |
244 &mut self.clients[client_id] |
229 } |
245 } |
230 |
246 |
231 #[inline] |
247 #[inline] |
|
248 pub fn has_client(&self, client_id: ClientId) -> bool { |
|
249 self.clients.contains(client_id) |
|
250 } |
|
251 |
|
252 #[inline] |
|
253 pub fn iter_clients(&self) -> impl Iterator<Item = &HwClient> { |
|
254 self.clients.iter().map(|(_, c)| c) |
|
255 } |
|
256 |
|
257 #[inline] |
232 pub fn room(&self, room_id: RoomId) -> &HwRoom { |
258 pub fn room(&self, room_id: RoomId) -> &HwRoom { |
233 &self.rooms[room_id] |
259 &self.rooms[room_id] |
234 } |
260 } |
235 |
261 |
236 #[inline] |
262 #[inline] |
246 #[inline] |
272 #[inline] |
247 pub fn client_and_room_mut( |
273 pub fn client_and_room_mut( |
248 &mut self, |
274 &mut self, |
249 client_id: ClientId, |
275 client_id: ClientId, |
250 room_id: RoomId, |
276 room_id: RoomId, |
251 ) -> (&mut HwClient, &mut HwRoom) { |
277 ) -> (&HwClient, &mut HwRoom) { |
252 (&mut self.clients[client_id], &mut self.rooms[room_id]) |
278 (&self.clients[client_id], &mut self.rooms[room_id]) |
253 } |
279 } |
254 |
280 |
255 #[inline] |
281 #[inline] |
256 pub fn is_admin(&self, client_id: ClientId) -> bool { |
282 pub fn is_admin(&self, client_id: ClientId) -> bool { |
257 self.clients |
283 self.clients |
502 } |
528 } |
503 Ok(room_nicks) |
529 Ok(room_nicks) |
504 } |
530 } |
505 } |
531 } |
506 |
532 |
|
533 pub fn leave_game(&mut self, client_id: ClientId) -> Option<Vec<String>> { |
|
534 let client = &mut self.clients[client_id]; |
|
535 let client_left = client.is_in_game(); |
|
536 if client_left { |
|
537 client.set_is_in_game(false); |
|
538 let room = &mut self.rooms[client.room_id.expect("Client should've been in the game")]; |
|
539 |
|
540 let team_names: Vec<_> = room |
|
541 .client_teams(client_id) |
|
542 .map(|t| t.name.clone()) |
|
543 .collect(); |
|
544 |
|
545 if let Some(ref mut info) = room.game_info { |
|
546 info.teams_in_game -= team_names.len() as u8; |
|
547 |
|
548 for team_name in &team_names { |
|
549 let remove_msg = |
|
550 utils::to_engine_msg(std::iter::once(b'F').chain(team_name.bytes())); |
|
551 if let Some(m) = &info.sync_msg { |
|
552 info.msg_log.push(m.clone()); |
|
553 } |
|
554 if info.sync_msg.is_some() { |
|
555 info.sync_msg = None |
|
556 } |
|
557 info.msg_log.push(remove_msg); |
|
558 } |
|
559 Some(team_names) |
|
560 } else { |
|
561 unreachable!(); |
|
562 } |
|
563 } else { |
|
564 None |
|
565 } |
|
566 } |
|
567 |
507 pub fn end_game(&mut self, room_id: RoomId) -> EndGameResult { |
568 pub fn end_game(&mut self, room_id: RoomId) -> EndGameResult { |
508 let room = &mut self.rooms[room_id]; |
569 let room = &mut self.rooms[room_id]; |
509 room.ready_players_number = 1; |
570 room.ready_players_number = room.master_id.is_some() as u8; |
510 |
571 |
511 if let Some(info) = replace(&mut room.game_info, None) { |
572 if let Some(info) = replace(&mut room.game_info, None) { |
512 let joined_mid_game_clients = self |
573 let joined_mid_game_clients = self |
513 .clients |
574 .clients |
514 .iter() |
575 .iter() |
570 std::mem::swap(&mut room.name, &mut name); |
631 std::mem::swap(&mut room.name, &mut name); |
571 Ok(name) |
632 Ok(name) |
572 } |
633 } |
573 } |
634 } |
574 |
635 |
575 pub fn add_team(&mut self, client_id: ClientId) {} |
636 pub fn add_team( |
|
637 &mut self, |
|
638 client_id: ClientId, |
|
639 mut info: Box<TeamInfo>, |
|
640 ) -> Result<&TeamInfo, AddTeamError> { |
|
641 let client = &mut self.clients[client_id]; |
|
642 if let Some(room_id) = client.room_id { |
|
643 let room = &mut self.rooms[room_id]; |
|
644 if room.teams.len() >= room.max_teams as usize { |
|
645 Err(AddTeamError::TooManyTeams) |
|
646 } else if room.addable_hedgehogs() == 0 { |
|
647 Err(AddTeamError::TooManyHedgehogs) |
|
648 } else if room.find_team(|t| t.name == info.name) != None { |
|
649 Err(AddTeamError::TeamAlreadyExists) |
|
650 } else if room.game_info.is_some() { |
|
651 Err(AddTeamError::GameInProgress) |
|
652 } else if room.is_team_add_restricted() { |
|
653 Err(AddTeamError::Restricted) |
|
654 } else { |
|
655 info.owner = client.nick.clone(); |
|
656 let team = room.add_team(client.id, *info, client.protocol_number < 42); |
|
657 client.teams_in_game += 1; |
|
658 client.clan = Some(team.color); |
|
659 Ok(team) |
|
660 } |
|
661 } else { |
|
662 unreachable!() |
|
663 } |
|
664 } |
|
665 |
|
666 pub fn remove_team( |
|
667 &mut self, |
|
668 client_id: ClientId, |
|
669 team_name: &str, |
|
670 ) -> Result<(), RemoveTeamError> { |
|
671 let client = &mut self.clients[client_id]; |
|
672 if let Some(room_id) = client.room_id { |
|
673 let room = &mut self.rooms[room_id]; |
|
674 match room.find_team_owner(team_name) { |
|
675 None => Err(RemoveTeamError::NoTeam), |
|
676 Some((id, _)) if id != client_id => Err(RemoveTeamError::TeamNotOwned), |
|
677 Some(_) => { |
|
678 client.teams_in_game -= 1; |
|
679 client.clan = room.find_team_color(client.id); |
|
680 room.remove_team(team_name); |
|
681 Ok(()) |
|
682 } |
|
683 } |
|
684 } else { |
|
685 unreachable!(); |
|
686 } |
|
687 } |
576 |
688 |
577 pub fn set_team_color( |
689 pub fn set_team_color( |
578 &mut self, |
690 &mut self, |
579 client_id: ClientId, |
691 client_id: ClientId, |
580 room_id: RoomId, |
692 room_id: RoomId, |