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