311 } else { |
331 } else { |
312 Err(DoesntExist) |
332 Err(DoesntExist) |
313 } |
333 } |
314 } |
334 } |
315 |
335 |
316 pub fn leave_room(&mut self, client_id: ClientId) -> Result<LeaveRoomResult, LeaveRoomError> { |
336 pub fn enable_super_power(&mut self, client_id: ClientId) -> bool { |
317 let client = &mut self.clients[client_id]; |
337 let client = &mut self.clients[client_id]; |
318 if let Some(room_id) = client.room_id { |
338 if client.is_admin() { |
319 let room = &mut self.rooms[room_id]; |
339 client.set_has_super_power(true); |
320 |
340 } |
321 room.players_number -= 1; |
341 client.is_admin() |
322 client.room_id = None; |
342 } |
323 |
343 |
324 let is_empty = room.players_number == 0; |
344 #[inline] |
325 let is_fixed = room.is_fixed(); |
345 pub fn set_var(&mut self, client_id: ClientId, var: ServerVar) -> Result<(), AccessError> { |
326 let was_master = room.master_id == Some(client_id); |
346 if self.clients[client_id].is_admin() { |
327 let was_in_game = client.is_in_game(); |
347 match var { |
328 let mut removed_teams = vec![]; |
348 ServerVar::MOTDNew(msg) => self.greetings.for_latest_protocol = msg, |
329 |
349 ServerVar::MOTDOld(msg) => self.greetings.for_old_protocols = msg, |
330 if is_empty && !is_fixed { |
350 ServerVar::LatestProto(n) => self.latest_protocol = n, |
331 if client.is_ready() && room.ready_players_number > 0 { |
351 } |
332 room.ready_players_number -= 1; |
352 Ok(()) |
|
353 } else { |
|
354 Err(AccessError()) |
|
355 } |
|
356 } |
|
357 |
|
358 #[inline] |
|
359 pub fn get_vars(&self, client_id: ClientId) -> Result<[ServerVar; 3], AccessError> { |
|
360 if self.clients[client_id].is_admin() { |
|
361 Ok([ |
|
362 ServerVar::MOTDNew(self.greetings.for_latest_protocol.clone()), |
|
363 ServerVar::MOTDOld(self.greetings.for_old_protocols.clone()), |
|
364 ServerVar::LatestProto(self.latest_protocol), |
|
365 ]) |
|
366 } else { |
|
367 Err(AccessError()) |
|
368 } |
|
369 } |
|
370 |
|
371 pub fn get_used_protocols(&self, client_id: ClientId) -> Result<Vec<u16>, AccessError> { |
|
372 if self.clients[client_id].is_admin() { |
|
373 let mut protocols: HashSet<_> = self |
|
374 .clients |
|
375 .iter() |
|
376 .map(|(_, c)| c.protocol_number) |
|
377 .chain(self.rooms.iter().map(|(_, r)| r.protocol_number)) |
|
378 .collect(); |
|
379 let mut protocols: Vec<_> = protocols.drain().collect(); |
|
380 protocols.sort(); |
|
381 Ok(protocols) |
|
382 } else { |
|
383 Err(AccessError()) |
|
384 } |
|
385 } |
|
386 |
|
387 #[inline] |
|
388 pub fn has_room(&self, name: &str) -> bool { |
|
389 self.find_room(name).is_some() |
|
390 } |
|
391 |
|
392 #[inline] |
|
393 pub fn find_room(&self, name: &str) -> Option<&HwRoom> { |
|
394 self.rooms |
|
395 .iter() |
|
396 .find_map(|(_, r)| Some(r).filter(|r| r.name == name)) |
|
397 } |
|
398 |
|
399 pub fn find_room_mut(&mut self, name: &str) -> Option<&mut HwRoom> { |
|
400 self.rooms |
|
401 .iter_mut() |
|
402 .find_map(|(_, r)| Some(r).filter(|r| r.name == name)) |
|
403 } |
|
404 |
|
405 pub fn find_client(&self, nick: &str) -> Option<&HwClient> { |
|
406 self.clients |
|
407 .iter() |
|
408 .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) |
|
409 } |
|
410 |
|
411 pub fn find_client_mut(&mut self, nick: &str) -> Option<&mut HwClient> { |
|
412 self.clients |
|
413 .iter_mut() |
|
414 .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) |
|
415 } |
|
416 |
|
417 pub fn all_clients(&self) -> impl Iterator<Item = ClientId> + '_ { |
|
418 self.clients.iter().map(|(id, _)| id) |
|
419 } |
|
420 |
|
421 pub fn filter_clients<'a, F>(&'a self, f: F) -> impl Iterator<Item = ClientId> + 'a |
|
422 where |
|
423 F: Fn(&(usize, &HwClient)) -> bool + 'a, |
|
424 { |
|
425 self.clients.iter().filter(f).map(|(_, c)| c.id) |
|
426 } |
|
427 |
|
428 pub fn filter_rooms<'a, F>(&'a self, f: F) -> impl Iterator<Item = RoomId> + 'a |
|
429 where |
|
430 F: Fn(&(usize, &HwRoom)) -> bool + 'a, |
|
431 { |
|
432 self.rooms.iter().filter(f).map(|(_, c)| c.id) |
|
433 } |
|
434 |
|
435 pub fn collect_clients<F>(&self, f: F) -> Vec<ClientId> |
|
436 where |
|
437 F: Fn(&(usize, &HwClient)) -> bool, |
|
438 { |
|
439 self.filter_clients(f).collect() |
|
440 } |
|
441 |
|
442 pub fn collect_nicks<F>(&self, f: F) -> Vec<String> |
|
443 where |
|
444 F: Fn(&(usize, &HwClient)) -> bool, |
|
445 { |
|
446 self.clients |
|
447 .iter() |
|
448 .filter(f) |
|
449 .map(|(_, c)| c.nick.clone()) |
|
450 .collect() |
|
451 } |
|
452 |
|
453 pub fn lobby_clients(&self) -> impl Iterator<Item = ClientId> + '_ { |
|
454 self.filter_clients(|(_, c)| c.room_id == None) |
|
455 } |
|
456 |
|
457 pub fn room_clients(&self, room_id: RoomId) -> impl Iterator<Item = ClientId> + '_ { |
|
458 self.filter_clients(move |(_, c)| c.room_id == Some(room_id)) |
|
459 } |
|
460 |
|
461 pub fn protocol_clients(&self, protocol: u16) -> impl Iterator<Item = ClientId> + '_ { |
|
462 self.filter_clients(move |(_, c)| c.protocol_number == protocol) |
|
463 } |
|
464 |
|
465 pub fn protocol_rooms(&self, protocol: u16) -> impl Iterator<Item = RoomId> + '_ { |
|
466 self.filter_rooms(move |(_, r)| r.protocol_number == protocol) |
|
467 } |
|
468 |
|
469 pub fn other_clients_in_room(&self, self_id: ClientId) -> Vec<ClientId> { |
|
470 let room_id = self.clients[self_id].room_id; |
|
471 self.collect_clients(|(id, c)| *id != self_id && c.room_id == room_id) |
|
472 } |
|
473 |
|
474 pub fn is_registered_only(&self) -> bool { |
|
475 self.flags.contains(ServerFlags::REGISTERED_ONLY) |
|
476 } |
|
477 |
|
478 pub fn set_is_registered_only(&mut self, value: bool) { |
|
479 self.flags.set(ServerFlags::REGISTERED_ONLY, value) |
|
480 } |
|
481 } |
|
482 |
|
483 pub struct HwRoomControl<'a> { |
|
484 server: &'a mut HwServer, |
|
485 client_id: ClientId, |
|
486 room_id: RoomId, |
|
487 } |
|
488 |
|
489 impl<'a> HwRoomControl<'a> { |
|
490 #[inline] |
|
491 pub fn new(server: &'a mut HwServer, client_id: ClientId) -> Option<Self> { |
|
492 if let Some(room_id) = server.clients[client_id].room_id { |
|
493 Some(Self { |
|
494 server, |
|
495 client_id, |
|
496 room_id, |
|
497 }) |
|
498 } else { |
|
499 None |
|
500 } |
|
501 } |
|
502 |
|
503 #[inline] |
|
504 pub fn server(&self) -> &HwServer { |
|
505 self.server |
|
506 } |
|
507 |
|
508 #[inline] |
|
509 pub fn client(&self) -> &HwClient { |
|
510 &self.server.clients[self.client_id] |
|
511 } |
|
512 |
|
513 #[inline] |
|
514 fn client_mut(&mut self) -> &mut HwClient { |
|
515 &mut self.server.clients[self.client_id] |
|
516 } |
|
517 |
|
518 #[inline] |
|
519 pub fn room(&self) -> &HwRoom { |
|
520 &self.server.rooms[self.room_id] |
|
521 } |
|
522 |
|
523 #[inline] |
|
524 fn room_mut(&mut self) -> &mut HwRoom { |
|
525 &mut self.server.rooms[self.room_id] |
|
526 } |
|
527 |
|
528 #[inline] |
|
529 pub fn get(&self) -> (&HwClient, &HwRoom) { |
|
530 (self.client(), self.room()) |
|
531 } |
|
532 |
|
533 #[inline] |
|
534 fn get_mut(&mut self) -> (&mut HwClient, &mut HwRoom) { |
|
535 ( |
|
536 &mut self.server.clients[self.client_id], |
|
537 &mut self.server.rooms[self.room_id], |
|
538 ) |
|
539 } |
|
540 |
|
541 pub fn leave_room(&mut self) -> LeaveRoomResult { |
|
542 let (client, room) = self.get_mut(); |
|
543 room.players_number -= 1; |
|
544 client.room_id = None; |
|
545 |
|
546 let is_empty = room.players_number == 0; |
|
547 let is_fixed = room.is_fixed(); |
|
548 let was_master = room.master_id == Some(client.id); |
|
549 let was_in_game = client.is_in_game(); |
|
550 let mut removed_teams = vec![]; |
|
551 |
|
552 if is_empty && !is_fixed { |
|
553 if client.is_ready() && room.ready_players_number > 0 { |
|
554 room.ready_players_number -= 1; |
|
555 } |
|
556 |
|
557 removed_teams = room |
|
558 .client_teams(client.id) |
|
559 .map(|t| t.name.clone()) |
|
560 .collect(); |
|
561 |
|
562 for team_name in &removed_teams { |
|
563 room.remove_team(team_name); |
|
564 } |
|
565 |
|
566 if client.is_master() && !is_fixed { |
|
567 client.set_is_master(false); |
|
568 room.master_id = None; |
|
569 } |
|
570 } |
|
571 |
|
572 client.set_is_ready(false); |
|
573 client.set_is_in_game(false); |
|
574 |
|
575 if !is_fixed { |
|
576 if room.players_number == 0 { |
|
577 self.server.rooms.remove(self.room_id); |
|
578 } else if room.master_id == None { |
|
579 let protocol_number = room.protocol_number; |
|
580 let new_master_id = self.server.room_clients(self.room_id).next(); |
|
581 |
|
582 if let Some(new_master_id) = new_master_id { |
|
583 let room = self.room_mut(); |
|
584 room.master_id = Some(new_master_id); |
|
585 let new_master = &mut self.server.clients[new_master_id]; |
|
586 new_master.set_is_master(true); |
|
587 |
|
588 if protocol_number < 42 { |
|
589 todo!(); |
|
590 let nick = new_master.nick.clone(); |
|
591 self.room_mut().name = nick; |
|
592 } |
|
593 |
|
594 let room = self.room_mut(); |
|
595 room.set_join_restriction(false); |
|
596 room.set_team_add_restriction(false); |
|
597 room.set_unregistered_players_restriction(true); |
333 } |
598 } |
334 |
599 } |
335 removed_teams = room |
600 } |
336 .client_teams(client.id) |
601 |
337 .map(|t| t.name.clone()) |
602 if is_empty && !is_fixed { |
338 .collect(); |
603 LeaveRoomResult::RoomRemoved |
339 |
604 } else { |
340 for team_name in &removed_teams { |
605 LeaveRoomResult::RoomRemains { |
341 room.remove_team(team_name); |
606 is_empty, |
342 } |
607 was_master, |
343 |
608 was_in_game, |
344 if client.is_master() && !is_fixed { |
609 new_master: self.room().master_id, |
345 client.set_is_master(false); |
610 removed_teams, |
346 room.master_id = None; |
611 } |
347 } |
|
348 } |
|
349 |
|
350 client.set_is_ready(false); |
|
351 client.set_is_in_game(false); |
|
352 |
|
353 if !is_fixed { |
|
354 if room.players_number == 0 { |
|
355 self.rooms.remove(room_id); |
|
356 } else if room.master_id == None { |
|
357 let new_master_id = self.room_clients(room_id).next(); |
|
358 if let Some(new_master_id) = new_master_id { |
|
359 let room = &mut self.rooms[room_id]; |
|
360 room.master_id = Some(new_master_id); |
|
361 let new_master = &mut self.clients[new_master_id]; |
|
362 new_master.set_is_master(true); |
|
363 |
|
364 if room.protocol_number < 42 { |
|
365 room.name = new_master.nick.clone(); |
|
366 } |
|
367 |
|
368 room.set_join_restriction(false); |
|
369 room.set_team_add_restriction(false); |
|
370 room.set_unregistered_players_restriction(true); |
|
371 } |
|
372 } |
|
373 } |
|
374 |
|
375 if is_empty && !is_fixed { |
|
376 Ok(LeaveRoomResult::RoomRemoved) |
|
377 } else { |
|
378 Ok(LeaveRoomResult::RoomRemains { |
|
379 is_empty, |
|
380 was_master, |
|
381 was_in_game, |
|
382 new_master: self.rooms[room_id].master_id, |
|
383 removed_teams, |
|
384 }) |
|
385 } |
|
386 } else { |
|
387 Err(LeaveRoomError::NoRoom) |
|
388 } |
612 } |
389 } |
613 } |
390 |
614 |
391 pub fn change_master( |
615 pub fn change_master( |
392 &mut self, |
616 &mut self, |
393 client_id: ClientId, |
|
394 room_id: RoomId, |
|
395 new_master_nick: String, |
617 new_master_nick: String, |
396 ) -> Result<ChangeMasterResult, ChangeMasterError> { |
618 ) -> Result<ChangeMasterResult, ChangeMasterError> { |
397 let client = &mut self.clients[client_id]; |
619 use ChangeMasterError::*; |
398 let room = &mut self.rooms[room_id]; |
620 let (client, room) = self.get_mut(); |
399 |
621 |
400 if client.is_admin() || room.master_id == Some(client_id) { |
622 if client.is_admin() || room.master_id == Some(client.id) { |
401 let new_master_id = self |
623 let new_master_id = self |
|
624 .server |
402 .clients |
625 .clients |
403 .iter() |
626 .iter() |
404 .find(|(_, c)| c.nick == new_master_nick) |
627 .find(|(_, c)| c.nick == new_master_nick) |
405 .map(|(id, _)| id); |
628 .map(|(id, _)| id); |
406 |
629 |
407 match new_master_id { |
630 match new_master_id { |
408 Some(new_master_id) if new_master_id == client_id => { |
631 Some(new_master_id) if new_master_id == self.client_id => Err(AlreadyMaster), |
409 Err(ChangeMasterError::AlreadyMaster) |
|
410 } |
|
411 Some(new_master_id) => { |
632 Some(new_master_id) => { |
412 let new_master = &mut self.clients[new_master_id]; |
633 let new_master = &mut self.server.clients[new_master_id]; |
413 if new_master.room_id == Some(room_id) { |
634 if new_master.room_id == Some(self.room_id) { |
414 self.clients[new_master_id].set_is_master(true); |
635 self.server.clients[new_master_id].set_is_master(true); |
415 let old_master_id = room.master_id; |
636 let room = self.room_mut(); |
|
637 let old_master_id = self.room().master_id; |
|
638 |
416 if let Some(master_id) = old_master_id { |
639 if let Some(master_id) = old_master_id { |
417 self.clients[master_id].set_is_master(false); |
640 self.server.clients[master_id].set_is_master(false); |
418 } |
641 } |
419 room.master_id = Some(new_master_id); |
642 self.room_mut().master_id = Some(new_master_id); |
420 Ok(ChangeMasterResult { |
643 Ok(ChangeMasterResult { |
421 old_master_id, |
644 old_master_id, |
422 new_master_id, |
645 new_master_id, |
423 }) |
646 }) |
424 } else { |
647 } else { |
425 Err(ChangeMasterError::ClientNotInRoom) |
648 Err(ClientNotInRoom) |
426 } |
649 } |
427 } |
650 } |
428 None => Err(ChangeMasterError::NoClient), |
651 None => Err(NoClient), |
429 } |
652 } |
430 } else { |
653 } else { |
431 Err(ChangeMasterError::NoAccess) |
654 Err(NoAccess) |
432 } |
655 } |
433 } |
656 } |
434 |
657 |
435 pub fn start_game(&mut self, room_id: RoomId) -> Result<Vec<String>, StartGameError> { |
658 pub fn vote(&mut self) { |
|
659 todo!("port from the room handler") |
|
660 } |
|
661 |
|
662 pub fn add_engine_message(&mut self) { |
|
663 todo!("port from the room handler") |
|
664 } |
|
665 |
|
666 pub fn toggle_flag(&mut self, flags: super::room::RoomFlags) -> bool { |
|
667 let (client, room) = self.get_mut(); |
|
668 if client.is_master() { |
|
669 room.flags.toggle(flags); |
|
670 } |
|
671 client.is_master() |
|
672 } |
|
673 |
|
674 pub fn fix_room(&mut self) -> Result<(), AccessError> { |
|
675 let (client, room) = self.get_mut(); |
|
676 if client.is_admin() { |
|
677 room.set_is_fixed(true); |
|
678 room.set_join_restriction(false); |
|
679 room.set_team_add_restriction(false); |
|
680 room.set_unregistered_players_restriction(true); |
|
681 Ok(()) |
|
682 } else { |
|
683 Err(AccessError()) |
|
684 } |
|
685 } |
|
686 |
|
687 pub fn unfix_room(&mut self) -> Result<(), AccessError> { |
|
688 let (client, room) = self.get_mut(); |
|
689 if client.is_admin() { |
|
690 room.set_is_fixed(false); |
|
691 Ok(()) |
|
692 } else { |
|
693 Err(AccessError()) |
|
694 } |
|
695 } |
|
696 |
|
697 pub fn set_room_name(&mut self, mut name: String) -> Result<String, ModifyRoomNameError> { |
|
698 use ModifyRoomNameError::*; |
|
699 let room_exists = self.server.has_room(&name); |
|
700 let (client, room) = self.get_mut(); |
|
701 if room.is_fixed() || room.master_id != Some(client.id) { |
|
702 Err(AccessDenied) |
|
703 } else if utils::is_name_illegal(&name) { |
|
704 Err(InvalidName) |
|
705 } else if room_exists { |
|
706 Err(DuplicateName) |
|
707 } else { |
|
708 std::mem::swap(&mut room.name, &mut name); |
|
709 Ok(name) |
|
710 } |
|
711 } |
|
712 |
|
713 pub fn set_room_greeting(&mut self, greeting: Option<String>) -> Result<(), AccessError> { |
|
714 let (client, room) = self.get_mut(); |
|
715 if client.is_admin() { |
|
716 room.greeting = greeting.unwrap_or(String::new()); |
|
717 Ok(()) |
|
718 } else { |
|
719 Err(AccessError()) |
|
720 } |
|
721 } |
|
722 |
|
723 pub fn set_room_max_teams(&mut self, count: u8) -> Result<(), SetTeamCountError> { |
|
724 use SetTeamCountError::*; |
|
725 let (client, room) = self.get_mut(); |
|
726 if !client.is_master() { |
|
727 Err(NotMaster) |
|
728 } else if !(2..=super::room::MAX_TEAMS_IN_ROOM).contains(&count) { |
|
729 Err(InvalidNumber) |
|
730 } else { |
|
731 room.max_teams = count; |
|
732 Ok(()) |
|
733 } |
|
734 } |
|
735 |
|
736 pub fn set_team_hedgehogs_number( |
|
737 &mut self, |
|
738 team_name: &str, |
|
739 number: u8, |
|
740 ) -> Result<(), SetHedgehogsError> { |
|
741 use SetHedgehogsError::*; |
|
742 let (client, room) = self.get_mut(); |
|
743 let addable_hedgehogs = room.addable_hedgehogs(); |
|
744 if let Some((_, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) { |
|
745 let max_hedgehogs = min( |
|
746 super::room::MAX_HEDGEHOGS_IN_ROOM, |
|
747 addable_hedgehogs + team.hedgehogs_number, |
|
748 ); |
|
749 if !client.is_master() { |
|
750 Err(NotMaster) |
|
751 } else if !(1..=max_hedgehogs).contains(&number) { |
|
752 Err(InvalidNumber(team.hedgehogs_number)) |
|
753 } else { |
|
754 team.hedgehogs_number = number; |
|
755 Ok(()) |
|
756 } |
|
757 } else { |
|
758 Err(NoTeam) |
|
759 } |
|
760 } |
|
761 |
|
762 pub fn add_team(&mut self, mut info: Box<TeamInfo>) -> Result<&TeamInfo, AddTeamError> { |
|
763 use AddTeamError::*; |
|
764 let (client, room) = self.get_mut(); |
|
765 if room.teams.len() >= room.max_teams as usize { |
|
766 Err(TooManyTeams) |
|
767 } else if room.addable_hedgehogs() == 0 { |
|
768 Err(TooManyHedgehogs) |
|
769 } else if room.find_team(|t| t.name == info.name) != None { |
|
770 Err(TeamAlreadyExists) |
|
771 } else if room.game_info.is_some() { |
|
772 Err(GameInProgress) |
|
773 } else if room.is_team_add_restricted() { |
|
774 Err(Restricted) |
|
775 } else { |
|
776 info.owner = client.nick.clone(); |
|
777 let team = room.add_team(client.id, *info, client.protocol_number < 42); |
|
778 client.teams_in_game += 1; |
|
779 client.clan = Some(team.color); |
|
780 Ok(team) |
|
781 } |
|
782 } |
|
783 |
|
784 pub fn remove_team(&mut self, team_name: &str) -> Result<(), RemoveTeamError> { |
|
785 use RemoveTeamError::*; |
|
786 let (client, room) = self.get_mut(); |
|
787 match room.find_team_owner(team_name) { |
|
788 None => Err(NoTeam), |
|
789 Some((id, _)) if id != client.id => Err(RemoveTeamError::TeamNotOwned), |
|
790 Some(_) => { |
|
791 client.teams_in_game -= 1; |
|
792 client.clan = room.find_team_color(client.id); |
|
793 room.remove_team(team_name); |
|
794 Ok(()) |
|
795 } |
|
796 } |
|
797 } |
|
798 |
|
799 pub fn set_team_color(&mut self, team_name: &str, color: u8) -> Result<(), ModifyTeamError> { |
|
800 use ModifyTeamError::*; |
|
801 let (client, room) = self.get_mut(); |
|
802 if let Some((owner, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) { |
|
803 if !client.is_master() { |
|
804 Err(NotMaster) |
|
805 } else { |
|
806 team.color = color; |
|
807 self.server.clients[owner].clan = Some(color); |
|
808 Ok(()) |
|
809 } |
|
810 } else { |
|
811 Err(NoTeam) |
|
812 } |
|
813 } |
|
814 |
|
815 pub fn set_config(&mut self, cfg: GameCfg) -> Result<(), SetConfigError> { |
|
816 use SetConfigError::*; |
|
817 let (client, room) = self.get_mut(); |
|
818 if room.is_fixed() { |
|
819 Err(RoomFixed) |
|
820 } else if !client.is_master() { |
|
821 Err(NotMaster) |
|
822 } else { |
|
823 let cfg = match cfg { |
|
824 GameCfg::Scheme(name, mut values) => { |
|
825 if client.protocol_number == 49 && values.len() >= 2 { |
|
826 let mut s = "X".repeat(50); |
|
827 s.push_str(&values.pop().unwrap()); |
|
828 values.push(s); |
|
829 } |
|
830 GameCfg::Scheme(name, values) |
|
831 } |
|
832 cfg => cfg, |
|
833 }; |
|
834 |
|
835 room.set_config(cfg); |
|
836 Ok(()) |
|
837 } |
|
838 } |
|
839 |
|
840 pub fn save_config(&mut self, name: String, location: String) { |
|
841 self.room_mut().save_config(name, location); |
|
842 } |
|
843 |
|
844 pub fn delete_config(&mut self, name: &str) -> bool { |
|
845 self.room_mut().delete_config(name) |
|
846 } |
|
847 |
|
848 pub fn toggle_ready(&mut self) -> bool { |
|
849 let (client, room) = self.get_mut(); |
|
850 client.set_is_ready(!client.is_ready()); |
|
851 if client.is_ready() { |
|
852 room.ready_players_number += 1; |
|
853 } else { |
|
854 room.ready_players_number -= 1; |
|
855 } |
|
856 client.is_ready() |
|
857 } |
|
858 |
|
859 pub fn start_game(&mut self) -> Result<Vec<String>, StartGameError> { |
|
860 use StartGameError::*; |
436 let (room_clients, room_nicks): (Vec<_>, Vec<_>) = self |
861 let (room_clients, room_nicks): (Vec<_>, Vec<_>) = self |
|
862 .server |
437 .clients |
863 .clients |
438 .iter() |
864 .iter() |
439 .map(|(id, c)| (id, c.nick.clone())) |
865 .map(|(id, c)| (id, c.nick.clone())) |
440 .unzip(); |
866 .unzip(); |
441 |
867 |
442 let room = &mut self.rooms[room_id]; |
868 let room = self.room_mut(); |
443 |
869 |
444 if !room.has_multiple_clans() { |
870 if !room.has_multiple_clans() { |
445 Err(StartGameError::NotEnoughClans) |
871 Err(NotEnoughClans) |
446 } else if room.protocol_number <= 43 && room.players_number != room.ready_players_number { |
872 } else if room.protocol_number <= 43 && room.players_number != room.ready_players_number { |
447 Err(StartGameError::NotReady) |
873 Err(NotReady) |
448 } else if room.game_info.is_some() { |
874 } else if room.game_info.is_some() { |
449 Err(StartGameError::AlreadyInGame) |
875 Err(AlreadyInGame) |
450 } else { |
876 } else { |
451 room.start_round(); |
877 room.start_round(); |
452 for id in room_clients { |
878 for id in room_clients { |
453 let c = &mut self.clients[id]; |
879 let team_indices = self.room().client_team_indices(id); |
|
880 let c = &mut self.server.clients[id]; |
454 c.set_is_in_game(true); |
881 c.set_is_in_game(true); |
455 c.team_indices = room.client_team_indices(c.id); |
882 c.team_indices = team_indices; |
456 } |
883 } |
457 Ok(room_nicks) |
884 Ok(room_nicks) |
458 } |
885 } |
459 } |
886 } |
460 |
887 |
461 pub fn leave_game(&mut self, client_id: ClientId) -> Option<Vec<String>> { |
888 pub fn leave_game(&mut self) -> Option<Vec<String>> { |
462 let client = &mut self.clients[client_id]; |
889 let (client, room) = self.get_mut(); |
463 let client_left = client.is_in_game(); |
890 let client_left = client.is_in_game(); |
464 if client_left { |
891 if client_left { |
465 client.set_is_in_game(false); |
892 client.set_is_in_game(false); |
466 let room = &mut self.rooms[client.room_id.expect("Client should've been in the game")]; |
|
467 |
893 |
468 let team_names: Vec<_> = room |
894 let team_names: Vec<_> = room |
469 .client_teams(client_id) |
895 .client_teams(client.id) |
470 .map(|t| t.name.clone()) |
896 .map(|t| t.name.clone()) |
471 .collect(); |
897 .collect(); |
472 |
898 |
473 if let Some(ref mut info) = room.game_info { |
899 if let Some(ref mut info) = room.game_info { |
474 info.teams_in_game -= team_names.len() as u8; |
900 info.teams_in_game -= team_names.len() as u8; |
521 None |
950 None |
522 } |
951 } |
523 }) |
952 }) |
524 .collect(); |
953 .collect(); |
525 |
954 |
526 EndGameResult { |
955 Some(EndGameResult { |
527 joined_mid_game_clients, |
956 joined_mid_game_clients, |
528 left_teams: info.left_teams.clone(), |
957 left_teams: info.left_teams.clone(), |
529 unreadied_nicks, |
958 unreadied_nicks, |
530 } |
959 }) |
531 } else { |
960 } else { |
532 unreachable!() |
961 None |
533 } |
962 } |
534 } |
|
535 |
|
536 pub fn enable_super_power(&mut self, client_id: ClientId) -> bool { |
|
537 let client = &mut self.clients[client_id]; |
|
538 if client.is_admin() { |
|
539 client.set_has_super_power(true); |
|
540 } |
|
541 client.is_admin() |
|
542 } |
|
543 |
|
544 pub fn set_room_name( |
|
545 &mut self, |
|
546 client_id: ClientId, |
|
547 room_id: RoomId, |
|
548 mut name: String, |
|
549 ) -> Result<String, ModifyRoomNameError> { |
|
550 let room_exists = self.has_room(&name); |
|
551 let room = &mut self.rooms[room_id]; |
|
552 if room.is_fixed() || room.master_id != Some(client_id) { |
|
553 Err(ModifyRoomNameError::AccessDenied) |
|
554 } else if utils::is_name_illegal(&name) { |
|
555 Err(ModifyRoomNameError::InvalidName) |
|
556 } else if room_exists { |
|
557 Err(ModifyRoomNameError::DuplicateName) |
|
558 } else { |
|
559 std::mem::swap(&mut room.name, &mut name); |
|
560 Ok(name) |
|
561 } |
|
562 } |
|
563 |
|
564 pub fn add_team( |
|
565 &mut self, |
|
566 client_id: ClientId, |
|
567 mut info: Box<TeamInfo>, |
|
568 ) -> Result<&TeamInfo, AddTeamError> { |
|
569 let client = &mut self.clients[client_id]; |
|
570 if let Some(room_id) = client.room_id { |
|
571 let room = &mut self.rooms[room_id]; |
|
572 if room.teams.len() >= room.max_teams as usize { |
|
573 Err(AddTeamError::TooManyTeams) |
|
574 } else if room.addable_hedgehogs() == 0 { |
|
575 Err(AddTeamError::TooManyHedgehogs) |
|
576 } else if room.find_team(|t| t.name == info.name) != None { |
|
577 Err(AddTeamError::TeamAlreadyExists) |
|
578 } else if room.game_info.is_some() { |
|
579 Err(AddTeamError::GameInProgress) |
|
580 } else if room.is_team_add_restricted() { |
|
581 Err(AddTeamError::Restricted) |
|
582 } else { |
|
583 info.owner = client.nick.clone(); |
|
584 let team = room.add_team(client.id, *info, client.protocol_number < 42); |
|
585 client.teams_in_game += 1; |
|
586 client.clan = Some(team.color); |
|
587 Ok(team) |
|
588 } |
|
589 } else { |
|
590 unreachable!() |
|
591 } |
|
592 } |
|
593 |
|
594 pub fn remove_team( |
|
595 &mut self, |
|
596 client_id: ClientId, |
|
597 team_name: &str, |
|
598 ) -> Result<(), RemoveTeamError> { |
|
599 let client = &mut self.clients[client_id]; |
|
600 if let Some(room_id) = client.room_id { |
|
601 let room = &mut self.rooms[room_id]; |
|
602 match room.find_team_owner(team_name) { |
|
603 None => Err(RemoveTeamError::NoTeam), |
|
604 Some((id, _)) if id != client_id => Err(RemoveTeamError::TeamNotOwned), |
|
605 Some(_) => { |
|
606 client.teams_in_game -= 1; |
|
607 client.clan = room.find_team_color(client.id); |
|
608 room.remove_team(team_name); |
|
609 Ok(()) |
|
610 } |
|
611 } |
|
612 } else { |
|
613 unreachable!(); |
|
614 } |
|
615 } |
|
616 |
|
617 pub fn set_team_color( |
|
618 &mut self, |
|
619 client_id: ClientId, |
|
620 room_id: RoomId, |
|
621 team_name: &str, |
|
622 color: u8, |
|
623 ) -> Result<(), ModifyTeamError> { |
|
624 let client = &self.clients[client_id]; |
|
625 let room = &mut self.rooms[room_id]; |
|
626 if let Some((owner, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) { |
|
627 if !client.is_master() { |
|
628 Err(ModifyTeamError::NotMaster) |
|
629 } else { |
|
630 team.color = color; |
|
631 self.clients[owner].clan = Some(color); |
|
632 Ok(()) |
|
633 } |
|
634 } else { |
|
635 Err(ModifyTeamError::NoTeam) |
|
636 } |
|
637 } |
|
638 |
|
639 pub fn toggle_ready(&mut self, client_id: ClientId) -> bool { |
|
640 let client = &mut self.clients[client_id]; |
|
641 if let Some(room_id) = client.room_id { |
|
642 let room = &mut self.rooms[room_id]; |
|
643 |
|
644 client.set_is_ready(!client.is_ready()); |
|
645 if client.is_ready() { |
|
646 room.ready_players_number += 1; |
|
647 } else { |
|
648 room.ready_players_number -= 1; |
|
649 } |
|
650 } |
|
651 client.is_ready() |
|
652 } |
|
653 |
|
654 #[inline] |
|
655 pub fn set_var(&mut self, client_id: ClientId, var: ServerVar) -> Result<(), AccessError> { |
|
656 if self.clients[client_id].is_admin() { |
|
657 match var { |
|
658 ServerVar::MOTDNew(msg) => self.greetings.for_latest_protocol = msg, |
|
659 ServerVar::MOTDOld(msg) => self.greetings.for_old_protocols = msg, |
|
660 ServerVar::LatestProto(n) => self.latest_protocol = n, |
|
661 } |
|
662 Ok(()) |
|
663 } else { |
|
664 Err(AccessError()) |
|
665 } |
|
666 } |
|
667 |
|
668 #[inline] |
|
669 pub fn get_vars(&self, client_id: ClientId) -> Result<[ServerVar; 3], AccessError> { |
|
670 if self.clients[client_id].is_admin() { |
|
671 Ok([ |
|
672 ServerVar::MOTDNew(self.greetings.for_latest_protocol.clone()), |
|
673 ServerVar::MOTDOld(self.greetings.for_old_protocols.clone()), |
|
674 ServerVar::LatestProto(self.latest_protocol), |
|
675 ]) |
|
676 } else { |
|
677 Err(AccessError()) |
|
678 } |
|
679 } |
|
680 |
|
681 pub fn get_used_protocols(&self, client_id: ClientId) -> Result<Vec<u16>, AccessError> { |
|
682 if self.clients[client_id].is_admin() { |
|
683 let mut protocols: HashSet<_> = self |
|
684 .clients |
|
685 .iter() |
|
686 .map(|(_, c)| c.protocol_number) |
|
687 .chain(self.rooms.iter().map(|(_, r)| r.protocol_number)) |
|
688 .collect(); |
|
689 let mut protocols: Vec<_> = protocols.drain().collect(); |
|
690 protocols.sort(); |
|
691 Ok(protocols) |
|
692 } else { |
|
693 Err(AccessError()) |
|
694 } |
|
695 } |
|
696 |
|
697 #[inline] |
|
698 pub fn has_room(&self, name: &str) -> bool { |
|
699 self.find_room(name).is_some() |
|
700 } |
|
701 |
|
702 #[inline] |
|
703 pub fn find_room(&self, name: &str) -> Option<&HwRoom> { |
|
704 self.rooms |
|
705 .iter() |
|
706 .find_map(|(_, r)| Some(r).filter(|r| r.name == name)) |
|
707 } |
|
708 |
|
709 pub fn find_room_mut(&mut self, name: &str) -> Option<&mut HwRoom> { |
|
710 self.rooms |
|
711 .iter_mut() |
|
712 .find_map(|(_, r)| Some(r).filter(|r| r.name == name)) |
|
713 } |
|
714 |
|
715 pub fn find_client(&self, nick: &str) -> Option<&HwClient> { |
|
716 self.clients |
|
717 .iter() |
|
718 .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) |
|
719 } |
|
720 |
|
721 pub fn find_client_mut(&mut self, nick: &str) -> Option<&mut HwClient> { |
|
722 self.clients |
|
723 .iter_mut() |
|
724 .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) |
|
725 } |
|
726 |
|
727 pub fn all_clients(&self) -> impl Iterator<Item = ClientId> + '_ { |
|
728 self.clients.iter().map(|(id, _)| id) |
|
729 } |
|
730 |
|
731 pub fn filter_clients<'a, F>(&'a self, f: F) -> impl Iterator<Item = ClientId> + 'a |
|
732 where |
|
733 F: Fn(&(usize, &HwClient)) -> bool + 'a, |
|
734 { |
|
735 self.clients.iter().filter(f).map(|(_, c)| c.id) |
|
736 } |
|
737 |
|
738 pub fn filter_rooms<'a, F>(&'a self, f: F) -> impl Iterator<Item = RoomId> + 'a |
|
739 where |
|
740 F: Fn(&(usize, &HwRoom)) -> bool + 'a, |
|
741 { |
|
742 self.rooms.iter().filter(f).map(|(_, c)| c.id) |
|
743 } |
|
744 |
|
745 pub fn collect_clients<F>(&self, f: F) -> Vec<ClientId> |
|
746 where |
|
747 F: Fn(&(usize, &HwClient)) -> bool, |
|
748 { |
|
749 self.filter_clients(f).collect() |
|
750 } |
|
751 |
|
752 pub fn collect_nicks<F>(&self, f: F) -> Vec<String> |
|
753 where |
|
754 F: Fn(&(usize, &HwClient)) -> bool, |
|
755 { |
|
756 self.clients |
|
757 .iter() |
|
758 .filter(f) |
|
759 .map(|(_, c)| c.nick.clone()) |
|
760 .collect() |
|
761 } |
|
762 |
|
763 pub fn lobby_clients(&self) -> impl Iterator<Item = ClientId> + '_ { |
|
764 self.filter_clients(|(_, c)| c.room_id == None) |
|
765 } |
|
766 |
|
767 pub fn room_clients(&self, room_id: RoomId) -> impl Iterator<Item = ClientId> + '_ { |
|
768 self.filter_clients(move |(_, c)| c.room_id == Some(room_id)) |
|
769 } |
|
770 |
|
771 pub fn protocol_clients(&self, protocol: u16) -> impl Iterator<Item = ClientId> + '_ { |
|
772 self.filter_clients(move |(_, c)| c.protocol_number == protocol) |
|
773 } |
|
774 |
|
775 pub fn protocol_rooms(&self, protocol: u16) -> impl Iterator<Item = RoomId> + '_ { |
|
776 self.filter_rooms(move |(_, r)| r.protocol_number == protocol) |
|
777 } |
|
778 |
|
779 pub fn other_clients_in_room(&self, self_id: ClientId) -> Vec<ClientId> { |
|
780 let room_id = self.clients[self_id].room_id; |
|
781 self.collect_clients(|(id, c)| *id != self_id && c.room_id == room_id) |
|
782 } |
|
783 |
|
784 pub fn is_registered_only(&self) -> bool { |
|
785 self.flags.contains(ServerFlags::REGISTERED_ONLY) |
|
786 } |
|
787 |
|
788 pub fn set_is_registered_only(&mut self, value: bool) { |
|
789 self.flags.set(ServerFlags::REGISTERED_ONLY, value) |
|
790 } |
963 } |
791 } |
964 } |
792 |
965 |
793 fn allocate_room(rooms: &mut Slab<HwRoom>) -> &mut HwRoom { |
966 fn allocate_room(rooms: &mut Slab<HwRoom>) -> &mut HwRoom { |
794 let entry = rooms.vacant_entry(); |
967 let entry = rooms.vacant_entry(); |