rust/hedgewars-server/src/core/server.rs
changeset 15074 c5a6e8566425
parent 14789 18240b308505
child 15075 e935b1ad23f3
equal deleted inserted replaced
15073:7732013ce64c 15074:c5a6e8566425
       
     1 use super::{
       
     2     client::HWClient,
       
     3     types::{ClientId, RoomId},
       
     4     indexslab::IndexSlab,
       
     5     room::HWRoom,
       
     6 };
       
     7 use crate::{
       
     8     utils,
       
     9     protocol::messages::HWProtocolMessage::Greeting
       
    10 };
       
    11 
       
    12 use bitflags::*;
       
    13 use log::*;
       
    14 use slab;
       
    15 use std::{borrow::BorrowMut, iter, num::NonZeroU16};
       
    16 
       
    17 type Slab<T> = slab::Slab<T>;
       
    18 
       
    19 pub struct HWAnteClient {
       
    20     pub nick: Option<String>,
       
    21     pub protocol_number: Option<NonZeroU16>,
       
    22     pub server_salt: String,
       
    23     pub is_checker: bool,
       
    24 }
       
    25 
       
    26 pub struct HWAnteroom {
       
    27     pub clients: IndexSlab<HWAnteClient>,
       
    28 }
       
    29 
       
    30 impl HWAnteroom {
       
    31     pub fn new(clients_limit: usize) -> Self {
       
    32         let clients = IndexSlab::with_capacity(clients_limit);
       
    33         HWAnteroom { clients }
       
    34     }
       
    35 
       
    36     pub fn add_client(&mut self, client_id: ClientId, salt: String) {
       
    37         let client = HWAnteClient {
       
    38             nick: None,
       
    39             protocol_number: None,
       
    40             server_salt: salt,
       
    41             is_checker: false,
       
    42         };
       
    43         self.clients.insert(client_id, client);
       
    44     }
       
    45 
       
    46     pub fn remove_client(&mut self, client_id: ClientId) -> Option<HWAnteClient> {
       
    47         let mut client = self.clients.remove(client_id);
       
    48         client
       
    49     }
       
    50 }
       
    51 
       
    52 pub struct ServerGreetings {
       
    53     pub for_latest_protocol: String,
       
    54     pub for_old_protocols: String,
       
    55 }
       
    56 
       
    57 impl ServerGreetings {
       
    58     fn new() -> Self {
       
    59         Self {
       
    60             for_latest_protocol: "\u{1f994} is watching".to_string(),
       
    61             for_old_protocols: "\u{1f994} is watching".to_string(),
       
    62         }
       
    63     }
       
    64 }
       
    65 
       
    66 bitflags! {
       
    67     pub struct ServerFlags: u8 {
       
    68         const REGISTERED_ONLY = 0b0000_1000;
       
    69     }
       
    70 }
       
    71 
       
    72 pub struct HWServer {
       
    73     pub clients: IndexSlab<HWClient>,
       
    74     pub rooms: Slab<HWRoom>,
       
    75     pub anteroom: HWAnteroom,
       
    76     pub latest_protocol: u16,
       
    77     pub flags: ServerFlags,
       
    78     pub greetings: ServerGreetings,
       
    79 }
       
    80 
       
    81 impl HWServer {
       
    82     pub fn new(clients_limit: usize, rooms_limit: usize) -> Self {
       
    83         let rooms = Slab::with_capacity(rooms_limit);
       
    84         let clients = IndexSlab::with_capacity(clients_limit);
       
    85         Self {
       
    86             clients,
       
    87             rooms,
       
    88             anteroom: HWAnteroom::new(clients_limit),
       
    89             greetings: ServerGreetings::new(),
       
    90             latest_protocol: 58,
       
    91             flags: ServerFlags::empty(),
       
    92         }
       
    93     }
       
    94 
       
    95     pub fn add_client(&mut self, client_id: ClientId, data: HWAnteClient) {
       
    96         if let (Some(protocol), Some(nick)) = (data.protocol_number, data.nick) {
       
    97             let mut client = HWClient::new(client_id, protocol.get(), nick);
       
    98             client.set_is_checker(data.is_checker);
       
    99             self.clients.insert(client_id, client);
       
   100         }
       
   101     }
       
   102 
       
   103     pub fn remove_client(&mut self, client_id: ClientId) {
       
   104         self.clients.remove(client_id);
       
   105     }
       
   106 
       
   107     pub fn get_greetings(&self, client_id: ClientId) -> &str {
       
   108         if self.clients[client_id].protocol_number < self.latest_protocol {
       
   109             &self.greetings.for_old_protocols
       
   110         } else {
       
   111             &self.greetings.for_latest_protocol
       
   112         }
       
   113     }
       
   114 
       
   115     #[inline]
       
   116     pub fn create_room(
       
   117         &mut self,
       
   118         creator_id: ClientId,
       
   119         name: String,
       
   120         password: Option<String>,
       
   121     ) -> RoomId {
       
   122         create_room(
       
   123             &mut self.clients[creator_id],
       
   124             &mut self.rooms,
       
   125             name,
       
   126             password,
       
   127         )
       
   128     }
       
   129 
       
   130     #[inline]
       
   131     pub fn move_to_room(&mut self, client_id: ClientId, room_id: RoomId) {
       
   132         move_to_room(&mut self.clients[client_id], &mut self.rooms[room_id])
       
   133     }
       
   134 
       
   135     pub fn has_room(&self, name: &str) -> bool {
       
   136         self.find_room(name).is_some()
       
   137     }
       
   138 
       
   139     pub fn find_room(&self, name: &str) -> Option<&HWRoom> {
       
   140         self.rooms
       
   141             .iter()
       
   142             .find_map(|(_, r)| Some(r).filter(|r| r.name == name))
       
   143     }
       
   144 
       
   145     pub fn find_room_mut(&mut self, name: &str) -> Option<&mut HWRoom> {
       
   146         self.rooms
       
   147             .iter_mut()
       
   148             .find_map(|(_, r)| Some(r).filter(|r| r.name == name))
       
   149     }
       
   150 
       
   151     pub fn find_client(&self, nick: &str) -> Option<&HWClient> {
       
   152         self.clients
       
   153             .iter()
       
   154             .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick))
       
   155     }
       
   156 
       
   157     pub fn find_client_mut(&mut self, nick: &str) -> Option<&mut HWClient> {
       
   158         self.clients
       
   159             .iter_mut()
       
   160             .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick))
       
   161     }
       
   162 
       
   163     pub fn all_clients(&self) -> impl Iterator<Item = ClientId> + '_ {
       
   164         self.clients.iter().map(|(id, _)| id)
       
   165     }
       
   166 
       
   167     pub fn filter_clients<'a, F>(&'a self, f: F) -> impl Iterator<Item = ClientId> + 'a
       
   168     where
       
   169         F: Fn(&(usize, &HWClient)) -> bool + 'a,
       
   170     {
       
   171         self.clients.iter().filter(f).map(|(_, c)| c.id)
       
   172     }
       
   173 
       
   174     pub fn filter_rooms<'a, F>(&'a self, f: F) -> impl Iterator<Item = RoomId> + 'a
       
   175     where
       
   176         F: Fn(&(usize, &HWRoom)) -> bool + 'a,
       
   177     {
       
   178         self.rooms.iter().filter(f).map(|(_, c)| c.id)
       
   179     }
       
   180 
       
   181     pub fn collect_clients<F>(&self, f: F) -> Vec<ClientId>
       
   182     where
       
   183         F: Fn(&(usize, &HWClient)) -> bool,
       
   184     {
       
   185         self.filter_clients(f).collect()
       
   186     }
       
   187 
       
   188     pub fn collect_nicks<F>(&self, f: F) -> Vec<String>
       
   189     where
       
   190         F: Fn(&(usize, &HWClient)) -> bool,
       
   191     {
       
   192         self.clients
       
   193             .iter()
       
   194             .filter(f)
       
   195             .map(|(_, c)| c.nick.clone())
       
   196             .collect()
       
   197     }
       
   198 
       
   199     pub fn lobby_clients(&self) -> impl Iterator<Item = ClientId> + '_ {
       
   200         self.filter_clients(|(_, c)| c.room_id == None)
       
   201     }
       
   202 
       
   203     pub fn room_clients(&self, room_id: RoomId) -> impl Iterator<Item = ClientId> + '_ {
       
   204         self.filter_clients(move |(_, c)| c.room_id == Some(room_id))
       
   205     }
       
   206 
       
   207     pub fn protocol_clients(&self, protocol: u16) -> impl Iterator<Item = ClientId> + '_ {
       
   208         self.filter_clients(move |(_, c)| c.protocol_number == protocol)
       
   209     }
       
   210 
       
   211     pub fn protocol_rooms(&self, protocol: u16) -> impl Iterator<Item = RoomId> + '_ {
       
   212         self.filter_rooms(move |(_, r)| r.protocol_number == protocol)
       
   213     }
       
   214 
       
   215     pub fn other_clients_in_room(&self, self_id: ClientId) -> Vec<ClientId> {
       
   216         let room_id = self.clients[self_id].room_id;
       
   217         self.collect_clients(|(id, c)| *id != self_id && c.room_id == room_id)
       
   218     }
       
   219 
       
   220     pub fn is_registered_only(&self) -> bool {
       
   221         self.flags.contains(ServerFlags::REGISTERED_ONLY)
       
   222     }
       
   223 
       
   224     pub fn set_is_registered_only(&mut self, value: bool) {
       
   225         self.flags.set(ServerFlags::REGISTERED_ONLY, value)
       
   226     }
       
   227 }
       
   228 
       
   229 fn allocate_room(rooms: &mut Slab<HWRoom>) -> &mut HWRoom {
       
   230     let entry = rooms.vacant_entry();
       
   231     let room = HWRoom::new(entry.key());
       
   232     entry.insert(room)
       
   233 }
       
   234 
       
   235 fn create_room(
       
   236     client: &mut HWClient,
       
   237     rooms: &mut Slab<HWRoom>,
       
   238     name: String,
       
   239     password: Option<String>,
       
   240 ) -> RoomId {
       
   241     let room = allocate_room(rooms);
       
   242 
       
   243     room.master_id = Some(client.id);
       
   244     room.name = name;
       
   245     room.password = password;
       
   246     room.protocol_number = client.protocol_number;
       
   247 
       
   248     room.players_number = 1;
       
   249     room.ready_players_number = 1;
       
   250 
       
   251     client.room_id = Some(room.id);
       
   252     client.set_is_master(true);
       
   253     client.set_is_ready(true);
       
   254     client.set_is_joined_mid_game(false);
       
   255 
       
   256     room.id
       
   257 }
       
   258 
       
   259 fn move_to_room(client: &mut HWClient, room: &mut HWRoom) {
       
   260     debug_assert!(client.room_id != Some(room.id));
       
   261 
       
   262     room.players_number += 1;
       
   263 
       
   264     client.room_id = Some(room.id);
       
   265     client.set_is_joined_mid_game(room.game_info.is_some());
       
   266     client.set_is_in_game(room.game_info.is_some());
       
   267 
       
   268     if let Some(ref mut info) = room.game_info {
       
   269         let teams = info.client_teams(client.id);
       
   270         client.teams_in_game = teams.clone().count() as u8;
       
   271         client.clan = teams.clone().next().map(|t| t.color);
       
   272         let team_names: Vec<_> = teams.map(|t| t.name.clone()).collect();
       
   273 
       
   274         if !team_names.is_empty() {
       
   275             info.left_teams.retain(|name| !team_names.contains(&name));
       
   276             info.teams_in_game += team_names.len() as u8;
       
   277             room.teams = info
       
   278                 .teams_at_start
       
   279                 .iter()
       
   280                 .filter(|(_, t)| !team_names.contains(&t.name))
       
   281                 .cloned()
       
   282                 .collect();
       
   283         }
       
   284     }
       
   285 }