diff -r e7c059ac6e54 -r a158ff8f84ef rust/hedgewars-server/src/core/server.rs --- a/rust/hedgewars-server/src/core/server.rs Mon Sep 30 16:02:39 2019 +0200 +++ b/rust/hedgewars-server/src/core/server.rs Tue Oct 01 23:48:32 2019 +0300 @@ -2,17 +2,32 @@ client::HwClient, indexslab::IndexSlab, room::HwRoom, - types::{ClientId, RoomId}, + types::{ClientId, RoomId, ServerVar}, }; use crate::{protocol::messages::HwProtocolMessage::Greeting, utils}; +use crate::core::server::JoinRoomError::WrongProtocol; use bitflags::*; use log::*; use slab; -use std::{borrow::BorrowMut, iter, num::NonZeroU16}; +use std::{borrow::BorrowMut, collections::HashSet, iter, num::NonZeroU16}; type Slab = slab::Slab; +pub enum CreateRoomError { + InvalidName, + AlreadyExists, +} + +pub enum JoinRoomError { + DoesntExist, + WrongProtocol, + Full, + Restricted, +} + +pub struct AccessError(); + pub struct HwAnteClient { pub nick: Option, pub protocol_number: Option, @@ -43,7 +58,7 @@ } pub fn remove_client(&mut self, client_id: ClientId) -> Option { - let mut client = self.clients.remove(client_id); + let client = self.clients.remove(client_id); client } } @@ -115,29 +130,123 @@ } #[inline] + pub fn get_client_nick(&self, client_id: ClientId) -> &str { + &self.clients[client_id].nick + } + + #[inline] pub fn create_room( &mut self, creator_id: ClientId, name: String, password: Option, - ) -> RoomId { - create_room( - &mut self.clients[creator_id], - &mut self.rooms, - name, - password, - ) + ) -> Result<(&HwClient, &HwRoom), CreateRoomError> { + use CreateRoomError::*; + if utils::is_name_illegal(&name) { + Err(InvalidName) + } else if self.has_room(&name) { + Err(AlreadyExists) + } else { + Ok(create_room( + &mut self.clients[creator_id], + &mut self.rooms, + name, + password, + )) + } + } + + pub fn join_room( + &mut self, + client_id: ClientId, + room_id: RoomId, + ) -> Result<(&HwClient, &HwRoom, impl Iterator + Clone), JoinRoomError> { + use JoinRoomError::*; + let room = &mut self.rooms[room_id]; + let client = &mut self.clients[client_id]; + + if client.protocol_number != room.protocol_number { + Err(WrongProtocol) + } else if room.is_join_restricted() { + Err(Restricted) + } else if room.players_number == u8::max_value() { + Err(Full) + } else { + move_to_room(client, room); + let room_id = room.id; + Ok(( + &self.clients[client_id], + &self.rooms[room_id], + self.clients.iter().map(|(_, c)| c), + )) + } } #[inline] - pub fn move_to_room(&mut self, client_id: ClientId, room_id: RoomId) { - move_to_room(&mut self.clients[client_id], &mut self.rooms[room_id]) + pub fn join_room_by_name( + &mut self, + client_id: ClientId, + room_name: &str, + ) -> Result<(&HwClient, &HwRoom, impl Iterator + Clone), JoinRoomError> { + use JoinRoomError::*; + let room = self.rooms.iter().find(|(_, r)| r.name == room_name); + if let Some((_, room)) = room { + let room_id = room.id; + self.join_room(client_id, room_id) + } else { + Err(DoesntExist) + } + } + + #[inline] + pub fn set_var(&mut self, client_id: ClientId, var: ServerVar) -> Result<(), AccessError> { + if self.clients[client_id].is_admin() { + match var { + ServerVar::MOTDNew(msg) => self.greetings.for_latest_protocol = msg, + ServerVar::MOTDOld(msg) => self.greetings.for_old_protocols = msg, + ServerVar::LatestProto(n) => self.latest_protocol = n, + } + Ok(()) + } else { + Err(AccessError()) + } } + #[inline] + pub fn get_vars(&self, client_id: ClientId) -> Result<[ServerVar; 3], AccessError> { + if self.clients[client_id].is_admin() { + Ok([ + ServerVar::MOTDNew(self.greetings.for_latest_protocol.clone()), + ServerVar::MOTDOld(self.greetings.for_old_protocols.clone()), + ServerVar::LatestProto(self.latest_protocol), + ]) + } else { + Err(AccessError()) + } + } + + pub fn get_used_protocols(&self, client_id: ClientId) -> Result, AccessError> { + if self.clients[client_id].is_admin() { + let mut protocols: HashSet<_> = self + .clients + .iter() + .map(|(_, c)| c.protocol_number) + .chain(self.rooms.iter().map(|(_, r)| r.protocol_number)) + .collect(); + let mut protocols: Vec<_> = protocols.drain().collect(); + protocols.sort(); + Ok(protocols) + } else { + Err(AccessError()) + } + } + + #[inline] pub fn has_room(&self, name: &str) -> bool { self.find_room(name).is_some() } + #[inline] pub fn find_room(&self, name: &str) -> Option<&HwRoom> { self.rooms .iter() @@ -234,12 +343,12 @@ entry.insert(room) } -fn create_room( - client: &mut HwClient, - rooms: &mut Slab, +fn create_room<'a, 'b>( + client: &'a mut HwClient, + rooms: &'b mut Slab, name: String, password: Option, -) -> RoomId { +) -> (&'a HwClient, &'b HwRoom) { let room = allocate_room(rooms); room.master_id = Some(client.id); @@ -255,7 +364,7 @@ client.set_is_ready(true); client.set_is_joined_mid_game(false); - room.id + (client, room) } fn move_to_room(client: &mut HwClient, room: &mut HwRoom) {