rust/hedgewars-server/src/core/server.rs
changeset 15439 a158ff8f84ef
parent 15176 f6115638aa92
child 15441 61a0bd0bb021
--- 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) {