--- 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<T> = slab::Slab<T>;
+pub enum CreateRoomError {
+ InvalidName,
+ AlreadyExists,
+}
+
+pub enum JoinRoomError {
+ DoesntExist,
+ WrongProtocol,
+ Full,
+ Restricted,
+}
+
+pub struct AccessError();
+
pub struct HwAnteClient {
pub nick: Option<String>,
pub protocol_number: Option<NonZeroU16>,
@@ -43,7 +58,7 @@
}
pub fn remove_client(&mut self, client_id: ClientId) -> Option<HwAnteClient> {
- 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<String>,
- ) -> 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<Item = &HwClient> + 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<Item = &HwClient> + 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<Vec<u16>, 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<HwRoom>,
+fn create_room<'a, 'b>(
+ client: &'a mut HwClient,
+ rooms: &'b mut Slab<HwRoom>,
name: String,
password: Option<String>,
-) -> 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) {