--- a/gameServer2/Cargo.toml Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/Cargo.toml Sat Jul 21 02:06:13 2018 +0200
@@ -13,3 +13,7 @@
log = "0.4"
proptest = "0.8"
base64 = "0.9"
+bitflags = "1.0"
+serde = "1.0"
+serde_yaml = "0.7"
+serde_derive = "1.0"
--- a/gameServer2/src/main.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/main.rs Sat Jul 21 02:06:13 2018 +0200
@@ -12,6 +12,10 @@
extern crate log;
extern crate env_logger;
#[macro_use] extern crate proptest;
+#[macro_use] extern crate bitflags;
+extern crate serde;
+extern crate serde_yaml;
+#[macro_use] extern crate serde_derive;
//use std::io::*;
//use rand::Rng;
--- a/gameServer2/src/protocol/messages.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/protocol/messages.rs Sat Jul 21 02:06:13 2018 +0200
@@ -18,7 +18,7 @@
Info(String),
// not entered state
Nick(String),
- Proto(u32),
+ Proto(u16),
Password(String, String),
Checker(u32, String, String),
// lobby
@@ -41,7 +41,7 @@
// in room
Part(Option<String>),
Cfg(GameCfg),
- AddTeam(TeamInfo),
+ AddTeam(Box<TeamInfo>),
RemoveTeam(String),
SetHedgehogsNumber(String, u8),
SetTeamColor(String, u8),
@@ -76,7 +76,7 @@
Pong,
Bye(String),
Nick(String),
- Proto(u32),
+ Proto(u16),
LobbyLeft(String, String),
LobbyJoined(Vec<String>),
ChatMsg {nick: String, msg: String},
@@ -105,8 +105,8 @@
Unreachable,
}
-pub fn server_chat(msg: &str) -> HWServerMessage {
- HWServerMessage::ChatMsg{ nick: "[server]".to_string(), msg: msg.to_string() }
+pub fn server_chat(msg: String) -> HWServerMessage {
+ HWServerMessage::ChatMsg{ nick: "[server]".to_string(), msg }
}
impl GameCfg {
@@ -234,10 +234,10 @@
//CallVote(Option<(String, Option<String>)>) =>, ??
Vote(msg) => msg!["CMD", format!("VOTE {}", if *msg {"YES"} else {"NO"})],
ForceVote(msg) => msg!["CMD", format!("FORCE {}", if *msg {"YES"} else {"NO"})],
- //Save(String, String), ??
- Delete(room) => msg!["CMD", format!("DELETE {}", room)],
- SaveRoom(room) => msg!["CMD", format!("SAVEROOM {}", room)],
- LoadRoom(room) => msg!["CMD", format!("LOADROOM {}", room)],
+ Save(name, location) => msg!["CMD", format!("SAVE {} {}", name, location)],
+ Delete(name) => msg!["CMD", format!("DELETE {}", name)],
+ SaveRoom(name) => msg!["CMD", format!("SAVEROOM {}", name)],
+ LoadRoom(name) => msg!["CMD", format!("LOADROOM {}", name)],
Malformed => msg!["A", "QUICK", "BROWN", "HOG", "JUMPS", "OVER", "THE", "LAZY", "DOG"],
Empty => msg![""],
_ => panic!("Protocol message not yet implemented")
@@ -245,7 +245,7 @@
}
}
-fn construct_message(header: &[&str], msg: &Vec<String>) -> String {
+fn construct_message(header: &[&str], msg: &[String]) -> String {
let mut v: Vec<_> = header.iter().map(|s| *s).collect();
v.extend(msg.iter().map(|s| &s[..]));
v.push("\n");
--- a/gameServer2/src/protocol/parser.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/protocol/parser.rs Sat Jul 21 02:06:13 2018 +0200
@@ -24,7 +24,10 @@
named!(end_of_message, tag!("\n\n"));
named!(str_line<&[u8], &str>, map_res!(not_line_ending, str::from_utf8));
named!( a_line<&[u8], String>, map!(str_line, String::from));
+named!(cmd_arg<&[u8], String>,
+ map!(map_res!(take_until_either!(" \n"), str::from_utf8), String::from));
named!( u8_line<&[u8], u8>, map_res!(str_line, FromStr::from_str));
+named!(u16_line<&[u8], u16>, map_res!(str_line, FromStr::from_str));
named!(u32_line<&[u8], u32>, map_res!(str_line, FromStr::from_str));
named!(yes_no_line<&[u8], bool>, alt!(
do_parse!(tag_no_case!("YES") >> (true))
@@ -87,7 +90,7 @@
| do_parse!(tag!("ROOM_NAME") >> eol >> n: a_line >> (RoomName(n)))
| do_parse!(tag!("REMOVE_TEAM") >> eol >> n: a_line >> (RemoveTeam(n)))
- | do_parse!(tag!("PROTO") >> eol >> d: u32_line >> (Proto(d)))
+ | do_parse!(tag!("PROTO") >> eol >> d: u16_line >> (Proto(d)))
| do_parse!(tag!("QUIT") >> msg: opt_param >> (Quit(msg)))
));
@@ -103,9 +106,10 @@
| do_parse!(tag_no_case!("PART") >> m: opt_space_param >> (Part(m)))
| do_parse!(tag_no_case!("QUIT") >> m: opt_space_param >> (Quit(m)))
| do_parse!(tag_no_case!("DELEGATE") >> spaces >> n: a_line >> (Delegate(n)))
+ | do_parse!(tag_no_case!("SAVE") >> spaces >> n: cmd_arg >> spaces >> l: cmd_arg >> (Save(n, l)))
+ | do_parse!(tag_no_case!("DELETE") >> spaces >> n: a_line >> (Delete(n)))
| do_parse!(tag_no_case!("SAVEROOM") >> spaces >> r: a_line >> (SaveRoom(r)))
| do_parse!(tag_no_case!("LOADROOM") >> spaces >> r: a_line >> (LoadRoom(r)))
- | do_parse!(tag_no_case!("DELETE") >> spaces >> r: a_line >> (Delete(r)))
| do_parse!(tag_no_case!("GLOBAL") >> spaces >> m: a_line >> (Global(m)))
| do_parse!(tag_no_case!("WATCH") >> spaces >> i: a_line >> (Watch(i)))
| do_parse!(tag_no_case!("GREETING") >> spaces >> m: a_line >> (Greeting(m)))
@@ -148,11 +152,11 @@
flag: a_line >> eol >>
difficulty: u8_line >> eol >>
hedgehogs: _8_hogs >>
- (AddTeam(TeamInfo{
+ (AddTeam(Box::new(TeamInfo{
name, color, grave, fort,
voice_pack, flag, difficulty,
hedgehogs, hedgehogs_number: 0
- })))
+ }))))
| do_parse!(tag!("HH_NUM") >> eol >>
n: a_line >> eol >>
c: u8_line >>
--- a/gameServer2/src/protocol/test.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/protocol/test.rs Sat Jul 21 02:06:13 2018 +0200
@@ -118,7 +118,7 @@
7 => SuperPower(),
8 => Info(Ascii),
9 => Nick(Ascii),
- 10 => Proto(u32),
+ 10 => Proto(u16),
11 => Password(Ascii, Ascii),
12 => Checker(u32, Ascii, Ascii),
13 => List(),
@@ -139,7 +139,7 @@
28 => Stats(),
29 => Part(Option<Ascii>),
30 => Cfg(GameCfg),
- 31 => AddTeam(TeamInfo),
+ 31 => AddTeam(Box<TeamInfo>),
32 => RemoveTeam(Ascii),
33 => SetHedgehogsNumber(Ascii, u8),
34 => SetTeamColor(Ascii, u8),
@@ -160,7 +160,7 @@
//49 => CallVote(Option<(String, Option<String>)>),
50 => Vote(bool),
51 => ForceVote(bool),
- //52 => Save(String, String),
+ 52 => Save(Ascii, Ascii),
53 => Delete(Ascii),
54 => SaveRoom(Ascii),
55 => LoadRoom(Ascii),
--- a/gameServer2/src/server/actions.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/actions.rs Sat Jul 21 02:06:13 2018 +0200
@@ -5,7 +5,7 @@
};
use super::{
server::HWServer,
- room::{GameInfo},
+ room::{GameInfo, RoomFlags},
client::HWClient,
coretypes::{ClientId, RoomId, GameCfg, VoteType},
room::HWRoom,
@@ -25,7 +25,7 @@
ToSelf,
ToAll {
room_id: Option<RoomId>,
- protocol: Option<u32>,
+ protocol: Option<u16>,
skip_self: bool
}
}
@@ -60,7 +60,7 @@
self
}
- pub fn with_protocol(mut self, protocol_number: u32) -> PendingMessage {
+ pub fn with_protocol(mut self, protocol_number: u16) -> PendingMessage {
if let Destination::ToAll {ref mut protocol, ..} = self.destination {
*protocol = Some(protocol_number)
}
@@ -116,7 +116,7 @@
pub fn run_action(server: &mut HWServer, client_id: usize, action: Action) {
match action {
- Send(msg) => server.send(client_id, msg.destination, msg.message),
+ Send(msg) => server.send(client_id, &msg.destination, msg.message),
ByeClient(msg) => {
let room_id;
let nick;
@@ -126,12 +126,12 @@
nick = c.nick.clone();
}
- room_id.map (|id| {
+ if let Some(id) = room_id{
if id != server.lobby_id {
server.react(client_id, vec![
MoveToLobby(format!("quit: {}", msg.clone()))]);
}
- });
+ }
server.react(client_id, vec![
LobbyLeft(nick, msg.clone()).send_all().action(),
@@ -218,14 +218,14 @@
let c = &mut server.clients[client_id];
r.players_number += 1;
c.room_id = Some(room_id);
- c.is_joined_mid_game = false;
- if r.master_id == Some(c.id) {
+
+ let is_master = r.master_id == Some(c.id);
+ c.set_is_master(is_master);
+ c.set_is_ready(is_master);
+ c.set_is_joined_mid_game(false);
+
+ if is_master {
r.ready_players_number += 1;
- c.is_master = true;
- c.is_ready = true;
- } else {
- c.is_ready = false;
- c.is_master = false;
}
let mut v = vec![
@@ -236,11 +236,11 @@
v.push(ChatMsg {nick: "[greeting]".to_string(), msg: r.greeting.clone()}
.send_self().action());
}
- if !c.is_master {
+ if !c.is_master() {
let team_names: Vec<_>;
if let Some(ref mut info) = r.game_info {
- c.is_in_game = true;
- c.is_joined_mid_game = true;
+ c.set_is_in_game(true);
+ c.set_is_joined_mid_game(true);
{
let teams = info.client_teams(c.id);
@@ -273,7 +273,7 @@
v.push(ForwardEngineMessage(info.msg_log.clone())
.send_self().action());
- for name in team_names.iter() {
+ for name in &team_names {
v.push(ForwardEngineMessage(
vec![to_engine_msg(once(b'G').chain(name.bytes()))])
.send_all().in_room(r.id).action());
@@ -295,7 +295,7 @@
if config {
actions.push(ConfigEntry("FULLMAPCONFIG".to_string(), r.map_config())
.send(to).action());
- for cfg in r.game_config().into_iter() {
+ for cfg in r.game_config() {
actions.push(cfg.to_server_msg().send(to).action());
}
}
@@ -319,7 +319,7 @@
.send(to).action());
}
let nicks: Vec<_> = server.clients.iter()
- .filter(|(_, c)| c.room_id == Some(r.id) && c.is_ready)
+ .filter(|(_, c)| c.room_id == Some(r.id) && c.is_ready())
.map(|(_, c)| c.nick.clone()).collect();
if !nicks.is_empty() {
actions.push(ClientFlags("+r".to_string(), nicks)
@@ -331,11 +331,12 @@
}
AddVote{vote, is_forced} => {
let mut actions = Vec::new();
- if let (c, Some(r)) = server.client_and_room(client_id) {
+ if let Some(r) = server.room(client_id) {
let mut result = None;
if let Some(ref mut voting) = r.voting {
if is_forced || voting.votes.iter().find(|(id, _)| client_id == *id).is_none() {
- actions.push(server_chat("Your vote has been counted.").send_self().action());
+ actions.push(server_chat("Your vote has been counted.".to_string())
+ .send_self().action());
voting.votes.push((client_id, vote));
let i = voting.votes.iter();
let pro = i.clone().filter(|(_, v)| *v).count();
@@ -347,14 +348,16 @@
result = Some(false);
}
} else {
- actions.push(server_chat("You already have voted.").send_self().action());
+ actions.push(server_chat("You already have voted.".to_string())
+ .send_self().action());
}
} else {
- actions.push(server_chat("There's no voting going on.").send_self().action());
+ actions.push(server_chat("There's no voting going on.".to_string())
+ .send_self().action());
}
if let Some(res) = result {
- actions.push(server_chat("Voting closed.")
+ actions.push(server_chat("Voting closed.".to_string())
.send_all().in_room(r.id).action());
let voting = replace(&mut r.voting, None).unwrap();
if res {
@@ -378,13 +381,25 @@
}
}
},
- VoteType::Map(_) => {
- unimplemented!();
+ VoteType::Map(None) => (),
+ VoteType::Map(Some(name)) => {
+ if let Some(location) = server.rooms[room_id].load_config(&name) {
+ actions.push(server_chat(location.to_string())
+ .send_all().in_room(room_id).action());
+ actions.push(SendRoomUpdate(None));
+ for (_, c) in server.clients.iter() {
+ if c.room_id == Some(room_id) {
+ actions.push(SendRoomData{
+ to: c.id, teams: false,
+ config: true, flags: false})
+ }
+ }
+ }
},
VoteType::Pause => {
if let Some(ref mut info) = server.rooms[room_id].game_info {
info.is_paused = !info.is_paused;
- actions.push(server_chat("Pause toggled.")
+ actions.push(server_chat("Pause toggled.".to_string())
.send_all().in_room(room_id).action());
actions.push(ForwardEngineMessage(vec![to_engine_msg(once(b'I'))])
.send_all().in_room(room_id).action());
@@ -411,10 +426,10 @@
let lobby_id = server.lobby_id;
if let (c, Some(r)) = server.client_and_room(client_id) {
r.players_number -= 1;
- if c.is_ready && r.ready_players_number > 0 {
+ if c.is_ready() && r.ready_players_number > 0 {
r.ready_players_number -= 1;
}
- if c.is_master && (r.players_number > 0 || r.is_fixed) {
+ if c.is_master() && (r.players_number > 0 || r.is_fixed()) {
actions.push(ChangeMaster(r.id, None));
}
actions.push(ClientFlags("-i".to_string(), vec![c.nick.clone()])
@@ -425,7 +440,7 @@
if let (c, Some(r)) = server.client_and_room(client_id) {
c.room_id = Some(lobby_id);
- if r.players_number == 0 && !r.is_fixed {
+ if r.players_number == 0 && !r.is_fixed() {
actions.push(RemoveRoom(r.id));
} else {
actions.push(RemoveClientTeams);
@@ -439,18 +454,18 @@
ChangeMaster(room_id, new_id) => {
let mut actions = Vec::new();
let room_client_ids = server.room_clients(room_id);
- let new_id = if server.room(client_id).map(|r| r.is_fixed).unwrap_or(false) {
+ let new_id = if server.room(client_id).map(|r| r.is_fixed()).unwrap_or(false) {
new_id
} else {
new_id.or_else(||
- room_client_ids.iter().find(|id| **id != client_id).map(|id| *id))
+ room_client_ids.iter().find(|id| **id != client_id).cloned())
};
let new_nick = new_id.map(|id| server.clients[id].nick.clone());
if let (c, Some(r)) = server.client_and_room(client_id) {
match r.master_id {
Some(id) if id == c.id => {
- c.is_master = false;
+ c.set_is_master(false);
r.master_id = None;
actions.push(ClientFlags("-h".to_string(), vec![c.nick.clone()])
.send_all().in_room(r.id).action());
@@ -459,12 +474,16 @@
None => {}
}
r.master_id = new_id;
+ r.set_join_restriction(false);
+ r.set_team_add_restriction(false);
+ let is_fixed = r.is_fixed();
+ r.set_unregistered_players_restriction(is_fixed);
if let Some(nick) = new_nick {
actions.push(ClientFlags("+h".to_string(), vec![nick])
.send_all().in_room(r.id).action());
}
}
- new_id.map(|id| server.clients[id].is_master = true);
+ if let Some(id) = new_id { server.clients[id].set_is_master(true) }
server.react(client_id, actions);
}
RemoveTeam(name) => {
@@ -476,7 +495,7 @@
}
actions.push(TeamRemove(name.clone()).send_all().in_room(r.id).action());
actions.push(SendRoomUpdate(None));
- if r.game_info.is_some() && c.is_in_game {
+ if r.game_info.is_some() && c.is_in_game() {
actions.push(SendTeamRemovalMessage(name));
}
}
@@ -514,7 +533,7 @@
room.start_round();
for id in room_clients {
let c = &mut server.clients[id];
- c.is_in_game = true;
+ c.set_is_in_game(false);
c.team_indices = room.client_team_indices(c.id);
}
vec![RunGame.send_all().in_room(room.id).action(),
@@ -527,7 +546,7 @@
}
SendTeamRemovalMessage(team_name) => {
let mut actions = Vec::new();
- if let (c, Some(r)) = server.client_and_room(client_id) {
+ if let Some(r) = server.room(client_id) {
if let Some(ref mut info) = r.game_info {
let msg = once(b'F').chain(team_name.bytes());
actions.push(ForwardEngineMessage(vec![to_engine_msg(msg)]).
@@ -564,11 +583,11 @@
if let Some(info) = old_info {
for (_, c) in server.clients.iter() {
- if c.room_id == Some(room_id) && c.is_joined_mid_game {
+ if c.room_id == Some(room_id) && c.is_joined_mid_game() {
actions.push(SendRoomData{
to: c.id, teams: false,
config: true, flags: false});
- for name in info.left_teams.iter() {
+ for name in &info.left_teams {
actions.push(TeamRemove(name.clone())
.send(c.id).action());
}
@@ -579,10 +598,11 @@
let nicks: Vec<_> = server.clients.iter_mut()
.filter(|(_, c)| c.room_id == Some(room_id))
.map(|(_, c)| {
- c.is_ready = c.is_master;
- c.is_joined_mid_game = false;
+ let is_master = c.is_master();
+ c.set_is_ready(is_master);
+ c.set_is_joined_mid_game(false);
c
- }).filter_map(|c| if !c.is_master {
+ }).filter_map(|c| if !c.is_master() {
Some(c.nick.clone())
} else {
None
--- a/gameServer2/src/server/client.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/client.rs Sat Jul 21 02:06:13 2018 +0200
@@ -1,18 +1,27 @@
use super::coretypes::ClientId;
+bitflags!{
+ pub struct ClientFlags: u8 {
+ const IS_ADMIN = 0b0000_0001;
+ const IS_MASTER = 0b0000_0010;
+ const IS_READY = 0b0000_0100;
+ const IS_IN_GAME = 0b0000_1000;
+ const IS_JOINED_MID_GAME = 0b0001_0000;
+
+ const NONE = 0b0000_0000;
+ const DEFAULT = Self::NONE.bits;
+ }
+}
+
pub struct HWClient {
pub id: ClientId,
pub room_id: Option<usize>,
pub nick: String,
- pub protocol_number: u32,
- pub is_admin: bool,
- pub is_master: bool,
- pub is_ready: bool,
- pub is_in_game: bool,
+ pub protocol_number: u16,
+ pub flags: ClientFlags,
pub teams_in_game: u8,
pub team_indices: Vec<u8>,
- pub clan: Option<u8>,
- pub is_joined_mid_game: bool,
+ pub clan: Option<u8>
}
impl HWClient {
@@ -22,14 +31,30 @@
room_id: None,
nick: String::new(),
protocol_number: 0,
- is_admin: false,
- is_master: false,
- is_ready: false,
- is_in_game: false,
+ flags: ClientFlags::DEFAULT,
teams_in_game: 0,
team_indices: Vec::new(),
clan: None,
- is_joined_mid_game: false,
}
}
+
+ fn contains(& self, mask: ClientFlags) -> bool {
+ self.flags.contains(mask)
+ }
+
+ fn set(&mut self, mask: ClientFlags, value: bool) {
+ self.flags.set(mask, value);
+ }
+
+ pub fn is_admin(&self)-> bool { self.contains(ClientFlags::IS_ADMIN) }
+ pub fn is_master(&self)-> bool { self.contains(ClientFlags::IS_MASTER) }
+ pub fn is_ready(&self)-> bool { self.contains(ClientFlags::IS_READY) }
+ pub fn is_in_game(&self)-> bool { self.contains(ClientFlags::IS_IN_GAME) }
+ pub fn is_joined_mid_game(&self)-> bool { self.contains(ClientFlags::IS_JOINED_MID_GAME) }
+
+ pub fn set_is_admin(&mut self, value: bool) { self.set(ClientFlags::IS_ADMIN, value) }
+ pub fn set_is_master(&mut self, value: bool) { self.set(ClientFlags::IS_MASTER, value) }
+ pub fn set_is_ready(&mut self, value: bool) { self.set(ClientFlags::IS_READY, value) }
+ pub fn set_is_in_game(&mut self, value: bool) { self.set(ClientFlags::IS_IN_GAME, value) }
+ pub fn set_is_joined_mid_game(&mut self, value: bool) { self.set(ClientFlags::IS_JOINED_MID_GAME, value) }
}
\ No newline at end of file
--- a/gameServer2/src/server/handlers/common.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/handlers/common.rs Sat Jul 21 02:06:13 2018 +0200
@@ -1,30 +1,21 @@
use protocol::messages::{
HWProtocolMessage::{self, Rnd}, HWServerMessage::{self, ChatMsg},
};
-use rand::{self, Rng};
-use server::{actions::Action, room::HWRoom, server::HWServer};
+use rand::{self, Rng, thread_rng};
+use server::{actions::Action, server::HWServer};
-pub fn rnd_action(options: Vec<String>, room: Option<&mut HWRoom>) -> Vec<Action> {
- if let Some(room) = room {
- let msg = rnd_reply(options);
- vec![msg.send_all().in_room(room.id).action()]
+pub fn rnd_reply(options: &[String]) -> HWServerMessage {
+ let mut rng = thread_rng();
+ let reply = if options.is_empty() {
+ (*rng.choose(&["heads", "tails"]).unwrap()).to_owned()
} else {
- Vec::new()
- }
-}
+ rng.choose(&options).unwrap().clone()
+ };
-fn rnd_reply(options: Vec<String>) -> HWServerMessage {
- let options = if options.is_empty() {
- vec!["heads".to_owned(), "tails".to_owned()]
- } else {
- options
- };
- let reply = rand::thread_rng().choose(&options).unwrap();
- let msg = ChatMsg {
+ ChatMsg {
nick: "[random]".to_owned(),
msg: reply.clone(),
- };
- msg
+ }
}
#[cfg(test)]
@@ -45,7 +36,7 @@
fn run_handle_test(opts: Vec<String>) {
let opts2 = opts.clone();
for opt in opts {
- while reply2string(rnd_reply(opts2.clone())) != opt {}
+ while reply2string(rnd_reply(&opts2)) != opt {}
}
}
@@ -72,7 +63,7 @@
while tries < 1000 || ((ones as f64 / tries as f64) - lim).abs() >= eps {
tries += 1;
- if reply2string(rnd_reply(opts.clone())) == 1.to_string() {
+ if reply2string(rnd_reply(&opts)) == 1.to_string() {
ones += 1;
}
}
--- a/gameServer2/src/server/handlers/inroom.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/handlers/inroom.rs Sat Jul 21 02:06:13 2018 +0200
@@ -6,15 +6,18 @@
server_chat
};
use server::{
- coretypes::{ClientId, Voting, VoteType},
+ coretypes::{ClientId, RoomId, Voting, VoteType},
server::HWServer,
- room::HWRoom,
+ room::{HWRoom, RoomFlags},
actions::{Action, Action::*}
};
use utils::is_name_illegal;
-use std::mem::swap;
+use std::{
+ mem::swap, fs::{File, OpenOptions},
+ io::{Read, Write, Result, Error, ErrorKind}
+};
use base64::{encode, decode};
-use super::common::rnd_action;
+use super::common::rnd_reply;
#[derive(Clone)]
struct ByMsg<'a> {
@@ -35,8 +38,8 @@
}
}
-fn by_msg(source: &Vec<u8>) -> ByMsg {
- ByMsg {messages: &source[..]}
+fn by_msg(source: &[u8]) -> ByMsg {
+ ByMsg {messages: source}
}
const VALID_MESSAGES: &[u8] =
@@ -81,7 +84,29 @@
})
}
-pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) {
+fn room_message_flag(msg: &HWProtocolMessage) -> RoomFlags {
+ use protocol::messages::HWProtocolMessage::*;
+ match msg {
+ ToggleRestrictJoin => RoomFlags::RESTRICTED_JOIN,
+ ToggleRestrictTeams => RoomFlags::RESTRICTED_TEAM_ADD,
+ ToggleRegisteredOnly => RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS,
+ _ => RoomFlags::empty()
+ }
+}
+
+fn read_file(filename: &str) -> Result<String> {
+ let mut reader = File::open(filename)?;
+ let mut result = String::new();
+ reader.read_to_string(&mut result)?;
+ Ok(result)
+}
+
+fn write_file(filename: &str, content: &str) -> Result<()> {
+ let mut writer = OpenOptions::new().create(true).write(true).open(filename)?;
+ writer.write_all(content.as_bytes())
+}
+
+pub fn handle(server: &mut HWServer, client_id: ClientId, room_id: RoomId, message: HWProtocolMessage) {
use protocol::messages::HWProtocolMessage::*;
match message {
Part(None) => server.react(client_id, vec![
@@ -91,28 +116,24 @@
Chat(msg) => {
let actions = {
let c = &mut server.clients[client_id];
- let chat_msg = ChatMsg {nick: c.nick.clone(), msg: msg};
- if let Some(room_id) = c.room_id {
- vec![chat_msg.send_all().in_room(room_id).but_self().action()]
- } else {
- Vec::new()
- }
+ let chat_msg = ChatMsg {nick: c.nick.clone(), msg};
+ vec![chat_msg.send_all().in_room(room_id).but_self().action()]
};
server.react(client_id, actions);
},
Fix => {
if let (c, Some(r)) = server.client_and_room(client_id) {
- if c.is_admin { r.is_fixed = true }
+ if c.is_admin() { r.set_is_fixed(true) }
}
}
Unfix => {
if let (c, Some(r)) = server.client_and_room(client_id) {
- if c.is_admin { r.is_fixed = false }
+ if c.is_admin() { r.set_is_fixed(false) }
}
}
Greeting(text) => {
if let (c, Some(r)) = server.client_and_room(client_id) {
- if c.is_admin || c.is_master && !r.is_fixed {
+ if c.is_admin() || c.is_master() && !r.is_fixed() {
r.greeting = text
}
}
@@ -121,35 +142,32 @@
let actions =
if is_name_illegal(&new_name) {
vec![Warn("Illegal room name! A room name must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string())]
- } else if server.room(client_id).map(|r| r.is_fixed).unwrap_or(false) {
+ } else if server.rooms[room_id].is_fixed() {
vec![Warn("Access denied.".to_string())]
} else if server.has_room(&new_name) {
vec![Warn("A room with the same name already exists.".to_string())]
} else {
let mut old_name = new_name.clone();
- if let (_, Some(r)) = server.client_and_room(client_id) {
- swap(&mut r.name, &mut old_name);
- vec![SendRoomUpdate(Some(old_name))]
- } else {
- Vec::new()
- }
+ swap(&mut server.rooms[room_id].name, &mut old_name);
+ vec![SendRoomUpdate(Some(old_name))]
};
server.react(client_id, actions);
},
ToggleReady => {
let actions = if let (c, Some(r)) = server.client_and_room(client_id) {
- let flags = if c.is_ready {
+ let flags = if c.is_ready() {
r.ready_players_number -= 1;
"-r"
} else {
r.ready_players_number += 1;
"+r"
};
- c.is_ready = !c.is_ready;
+ let is_ready = !c.is_ready();
+ c.set_is_ready(is_ready);
let mut v =
vec![ClientFlags(flags.to_string(), vec![c.nick.clone()])
.send_all().in_room(r.id).action()];
- if r.is_fixed && r.ready_players_number as u32 == r.players_number {
+ if r.is_fixed() && r.ready_players_number == r.players_number {
v.push(StartRoomGame(r.id))
}
v
@@ -161,7 +179,6 @@
AddTeam(info) => {
let mut actions = Vec::new();
if let (c, Some(r)) = server.client_and_room(client_id) {
- let room_id = r.id;
if r.teams.len() >= r.team_limit as usize {
actions.push(Warn("Too many teams!".to_string()))
} else if r.addable_hedgehogs() == 0 {
@@ -170,8 +187,10 @@
actions.push(Warn("There's already a team with same name in the list.".to_string()))
} else if r.game_info.is_some() {
actions.push(Warn("Joining not possible: Round is in progress.".to_string()))
+ } else if r.is_team_add_restricted() {
+ actions.push(Warn("This room currently does not allow adding new teams.".to_string()));
} else {
- let team = r.add_team(c.id, info);
+ let team = r.add_team(c.id, *info);
c.teams_in_game += 1;
c.clan = Some(team.color);
actions.push(TeamAccepted(team.name.clone())
@@ -206,10 +225,9 @@
},
SetHedgehogsNumber(team_name, number) => {
let actions = if let (c, Some(r)) = server.client_and_room(client_id) {
- let room_id = r.id;
let addable_hedgehogs = r.addable_hedgehogs();
if let Some((_, mut team)) = r.find_team_and_owner_mut(|t| t.name == team_name) {
- if !c.is_master {
+ if !c.is_master() {
vec![ProtocolError("You're not the room master!".to_string())]
} else if number < 1 || number > 8
|| number > addable_hedgehogs + team.hedgehogs_number {
@@ -231,9 +249,8 @@
SetTeamColor(team_name, color) => {
let mut owner_id = None;
let actions = if let (c, Some(r)) = server.client_and_room(client_id) {
- let room_id = r.id;
if let Some((owner, mut team)) = r.find_team_and_owner_mut(|t| t.name == team_name) {
- if !c.is_master {
+ if !c.is_master() {
vec![ProtocolError("You're not the room master!".to_string())]
} else if false {
Vec::new()
@@ -258,9 +275,9 @@
},
Cfg(cfg) => {
let actions = if let (c, Some(r)) = server.client_and_room(client_id) {
- if r.is_fixed {
+ if r.is_fixed() {
vec![Warn("Access denied.".to_string())]
- } else if !c.is_master {
+ } else if !c.is_master() {
vec![ProtocolError("You're not the room master!".to_string())]
} else {
let v = vec![cfg.to_server_msg()
@@ -273,33 +290,98 @@
};
server.react(client_id, actions);
}
+ Save(name, location) => {
+ let actions = vec![server_chat(format!("Room config saved as {}", name))
+ .send_all().in_room(room_id).action()];
+ server.rooms[room_id].save_config(name, location);
+ server.react(client_id, actions);
+ }
+ SaveRoom(filename) => {
+ let actions = if server.clients[client_id].is_admin() {
+ match server.rooms[room_id].get_saves() {
+ Ok(text) => match write_file(&filename, &text) {
+ Ok(_) => vec![server_chat("Room configs saved successfully.".to_string())
+ .send_self().action()],
+ Err(e) => {
+ warn!("Error while writing the config file \"{}\": {}", filename, e);
+ vec![Warn("Unable to save the room configs.".to_string())]
+ }
+ }
+ Err(e) => {
+ warn!("Error while serializing the room configs: {}", e);
+ vec![Warn("Unable to serialize the room configs.".to_string())]
+ }
+ }
+ } else {
+ Vec::new()
+ };
+ server.react(client_id, actions);
+ }
+ LoadRoom(filename) => {
+ let actions = if server.clients[client_id].is_admin() {
+ match read_file(&filename) {
+ Ok(text) => match server.rooms[room_id].set_saves(&text) {
+ Ok(_) => vec![server_chat("Room configs loaded successfully.".to_string())
+ .send_self().action()],
+ Err(e) => {
+ warn!("Error while deserializing the room configs: {}", e);
+ vec![Warn("Unable to deserialize the room configs.".to_string())]
+ }
+ }
+ Err(e) => {
+ warn!("Error while reading the config file \"{}\": {}", filename, e);
+ vec![Warn("Unable to load the room configs.".to_string())]
+ }
+ }
+ } else {
+ Vec::new()
+ };
+ server.react(client_id, actions);
+ }
+ Delete(name) => {
+ let actions = if !server.rooms[room_id].delete_config(&name) {
+ vec![Warn(format!("Save doesn't exist: {}", name))]
+ } else {
+ vec![server_chat(format!("Room config {} has been deleted", name))
+ .send_all().in_room(room_id).action()]
+ };
+ server.react(client_id, actions);
+ }
CallVote(None) => {
server.react(client_id, vec![
- server_chat("Available callvote commands: kick <nickname>, map <name>, pause, newseed, hedgehogs <number>")
+ server_chat("Available callvote commands: kick <nickname>, map <name>, pause, newseed, hedgehogs <number>".to_string())
.send_self().action()])
}
CallVote(Some(kind)) => {
- let (room_id, is_in_game) = server.room(client_id)
- .map(|r| (r.id, r.game_info.is_some())).unwrap();
+ let is_in_game = server.rooms[room_id].game_info.is_some();
let error = match &kind {
VoteType::Kick(nick) => {
if server.find_client(&nick).filter(|c| c.room_id == Some(room_id)).is_some() {
None
} else {
- Some("/callvote kick: No such user!")
+ Some("/callvote kick: No such user!".to_string())
}
},
VoteType::Map(None) => {
- Some("/callvote map: Not implemented")
+ let names: Vec<_> = server.rooms[room_id].saves.keys().cloned().collect();
+ if names.is_empty() {
+ Some("/callvote map: No maps saved in this room!".to_string())
+ } else {
+ Some(format!("Available maps: {}", names.join(", ")))
+ }
},
VoteType::Map(Some(name)) => {
- Some("/callvote map: Not implemented")
+ if server.rooms[room_id].saves.get(&name[..]).is_some() {
+ None
+ } else {
+ Some("/callvote map: No such map!".to_string())
+ }
},
VoteType::Pause => {
if is_in_game {
None
} else {
- Some("/callvote pause: No game in progress!")
+ Some("/callvote pause: No game in progress!".to_string())
}
},
VoteType::NewSeed => {
@@ -308,7 +390,7 @@
VoteType::HedgehogsPerTeam(number) => {
match number {
1...8 => None,
- _ => Some("/callvote hedgehogs: Specify number from 1 to 8.")
+ _ => Some("/callvote hedgehogs: Specify number from 1 to 8.".to_string())
}
},
};
@@ -316,9 +398,9 @@
None => {
let msg = voting_description(&kind);
let voting = Voting::new(kind, server.room_clients(client_id));
- server.room(client_id).unwrap().voting = Some(voting);
+ server.rooms[room_id].voting = Some(voting);
server.react(client_id, vec![
- server_chat(&msg).send_all().in_room(room_id).action(),
+ server_chat(msg).send_all().in_room(room_id).action(),
AddVote{ vote: true, is_forced: false}]);
}
Some(msg) => {
@@ -328,28 +410,20 @@
}
}
Vote(vote) => {
- let actions = if let (c, Some(r)) = server.client_and_room(client_id) {
- vec![AddVote{ vote, is_forced: false }]
- } else {
- Vec::new()
- };
- server.react(client_id, actions);
+ server.react(client_id, vec![AddVote{ vote, is_forced: false }]);
}
ForceVote(vote) => {
- let actions = if let (c, Some(r)) = server.client_and_room(client_id) {
- vec![AddVote{ vote, is_forced: c.is_admin} ]
- } else {
- Vec::new()
- };
- server.react(client_id, actions);
+ let is_forced = server.clients[client_id].is_admin();
+ server.react(client_id, vec![AddVote{ vote, is_forced }]);
+ }
+ ToggleRestrictJoin | ToggleRestrictTeams | ToggleRegisteredOnly => {
+ if server.clients[client_id].is_master() {
+ server.rooms[room_id].flags.toggle(room_message_flag(&message));
+ }
+ server.react(client_id, vec![SendRoomUpdate(None)]);
}
StartGame => {
- let actions = if let (_, Some(r)) = server.client_and_room(client_id) {
- vec![StartRoomGame(r.id)]
- } else {
- Vec::new()
- };
- server.react(client_id, actions);
+ server.react(client_id, vec![StartRoomGame(room_id)]);
}
EngineMessage(em) => {
let mut actions = Vec::new();
@@ -383,8 +457,8 @@
RoundFinished => {
let mut actions = Vec::new();
if let (c, Some(r)) = server.client_and_room(client_id) {
- if c.is_in_game {
- c.is_in_game = false;
+ if c.is_in_game() {
+ c.set_is_in_game(false);
actions.push(ClientFlags("-g".to_string(), vec![c.nick.clone()]).
send_all().in_room(r.id).action());
if r.game_info.is_some() {
@@ -397,8 +471,16 @@
server.react(client_id, actions)
},
Rnd(v) => {
- let actions = rnd_action(v, server.room(client_id));
- server.react(client_id, actions)
+ let result = rnd_reply(&v);
+ let mut echo = vec!["/rnd".to_string()];
+ echo.extend(v.into_iter());
+ let chat_msg = ChatMsg {
+ nick: server.clients[client_id].nick.clone(),
+ msg: echo.join(" ")
+ };
+ server.react(client_id, vec![
+ chat_msg.send_all().in_room(room_id).action(),
+ result.send_all().in_room(room_id).action()])
},
_ => warn!("Unimplemented!")
}
--- a/gameServer2/src/server/handlers/lobby.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/handlers/lobby.rs Sat Jul 21 02:06:13 2018 +0200
@@ -10,7 +10,7 @@
HWServerMessage::*
};
use utils::is_name_illegal;
-use super::common::rnd_action;
+use super::common::rnd_reply;
pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) {
use protocol::messages::HWProtocolMessage::*;
@@ -31,8 +31,9 @@
server.react(client_id, actions);
},
Chat(msg) => {
- let chat_msg = ChatMsg {nick: server.clients[client_id].nick.clone(), msg: msg};
- server.react(client_id, vec![chat_msg.send_all().but_self().action()]);
+ let actions = vec![ChatMsg {nick: server.clients[client_id].nick.clone(), msg}
+ .send_all().in_room(server.lobby_id).but_self().action()];
+ server.react(client_id, actions);
},
JoinRoom(name, password) => {
let actions;
@@ -48,6 +49,10 @@
actions = if let Some((_, r)) = room {
if c.protocol_number != r.protocol_number {
vec![Warn("Room version incompatible to your Hedgewars version!".to_string())]
+ } else if r.is_join_restricted() {
+ vec![Warn("Access denied. This room currently doesn't allow joining.".to_string())]
+ } else if r.players_number == u8::max_value() {
+ vec![Warn("This room is already full".to_string())]
} else {
vec![MoveToRoom(r.id),
RoomJoined(nicks).send_self().action()]
@@ -59,8 +64,7 @@
server.react(client_id, actions);
},
Rnd(v) => {
- let actions = rnd_action(v, server.room(client_id));
- server.react(client_id, actions)
+ server.react(client_id, vec![rnd_reply(&v).send_self().action()]);
},
List => warn!("Deprecated LIST message received"),
_ => warn!("Incorrect command in lobby state"),
--- a/gameServer2/src/server/handlers/mod.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/handlers/mod.rs Sat Jul 21 02:06:13 2018 +0200
@@ -1,36 +1,38 @@
use mio;
-use std::io::Write;
-use std::io;
+use std::{io, io::Write};
-use super::server::HWServer;
-use super::actions::Action;
-use super::actions::Action::*;
-use protocol::messages::HWProtocolMessage;
-use protocol::messages::HWServerMessage::*;
-
+use super::{
+ server::HWServer,
+ actions::{Action, Action::*},
+ coretypes::ClientId
+};
+use protocol::messages::{
+ HWProtocolMessage,
+ HWServerMessage::*
+};
mod common;
mod loggingin;
mod lobby;
mod inroom;
-pub fn handle(server: &mut HWServer, token: usize, message: HWProtocolMessage) {
+pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) {
match message {
HWProtocolMessage::Ping =>
- server.react(token, vec![Pong.send_self().action()]),
+ server.react(client_id, vec![Pong.send_self().action()]),
HWProtocolMessage::Quit(Some(msg)) =>
- server.react(token, vec![ByeClient("User quit: ".to_string() + &msg)]),
+ server.react(client_id, vec![ByeClient("User quit: ".to_string() + &msg)]),
HWProtocolMessage::Quit(None) =>
- server.react(token, vec![ByeClient("User quit".to_string())]),
+ server.react(client_id, vec![ByeClient("User quit".to_string())]),
HWProtocolMessage::Malformed => warn!("Malformed/unknown message"),
HWProtocolMessage::Empty => warn!("Empty message"),
_ => {
- match server.clients[token].room_id {
+ match server.clients[client_id].room_id {
None =>
- loggingin::handle(server, token, message),
+ loggingin::handle(server, client_id, message),
Some(id) if id == server.lobby_id =>
- lobby::handle(server, token, message),
- _ =>
- inroom::handle(server, token, message)
+ lobby::handle(server, client_id, message),
+ Some(id) =>
+ inroom::handle(server, client_id, id, message)
}
},
}
--- a/gameServer2/src/server/network.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/network.rs Sat Jul 21 02:06:13 2018 +0200
@@ -105,14 +105,14 @@
}
pub fn send_raw_msg(&mut self, msg: &[u8]) {
- self.buf_out.write(msg).unwrap();
+ self.buf_out.write_all(msg).unwrap();
}
- pub fn send_string(&mut self, msg: &String) {
+ pub fn send_string(&mut self, msg: &str) {
self.send_raw_msg(&msg.as_bytes());
}
- pub fn send_msg(&mut self, msg: HWServerMessage) {
+ pub fn send_msg(&mut self, msg: &HWServerMessage) {
self.send_string(&msg.to_raw_protocol());
}
}
@@ -143,7 +143,7 @@
let mut client_exists = false;
if let Some(ref client) = self.clients.get(id) {
poll.deregister(&client.socket)
- .ok().expect("could not deregister socket");
+ .expect("could not deregister socket");
info!("client {} ({}) removed", client.id, client.peer_addr);
client_exists = true;
}
@@ -156,7 +156,7 @@
poll.register(&client_socket, Token(id),
Ready::readable() | Ready::writable(),
PollOpt::edge())
- .ok().expect("could not register socket with event loop");
+ .expect("could not register socket with event loop");
let entry = self.clients.vacant_entry();
let client = NetworkClient::new(id, client_socket, addr);
@@ -189,7 +189,7 @@
Ok(())
}
- fn operation_failed(&mut self, poll: &Poll, client_id: ClientId, error: Error, msg: &str) -> io::Result<()> {
+ fn operation_failed(&mut self, poll: &Poll, client_id: ClientId, error: &Error, msg: &str) -> io::Result<()> {
let addr = if let Some(ref mut client) = self.clients.get_mut(client_id) {
client.peer_addr
} else {
@@ -224,7 +224,7 @@
};
}
Err(e) => self.operation_failed(
- poll, client_id, e,
+ poll, client_id, &e,
"Error while reading from client socket")?
}
@@ -256,7 +256,7 @@
},
Ok(_) => {}
Err(e) => self.operation_failed(
- poll, client_id, e,
+ poll, client_id, &e,
"Error while writing to client socket")?
}
--- a/gameServer2/src/server/room.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/room.rs Sat Jul 21 02:06:13 2018 +0200
@@ -1,24 +1,29 @@
-use std::{iter};
+use std::{
+ iter, collections::HashMap
+};
use server::{
coretypes::{ClientId, RoomId, TeamInfo, GameCfg, GameCfg::*, Voting},
client::{HWClient}
};
+use serde::{Serialize, Deserialize};
+use serde_yaml;
-const MAX_HEDGEHOGS_IN_ROOM: u8 = 48;
+const MAX_HEDGEHOGS_IN_ROOM: u8 = 64;
+const MAX_TEAMS_IN_ROOM: u8 = 8;
-#[derive(Clone)]
+#[derive(Clone, Serialize, Deserialize)]
struct Ammo {
name: String,
settings: Option<String>
}
-#[derive(Clone)]
+#[derive(Clone, Serialize, Deserialize)]
struct Scheme {
name: String,
settings: Option<Vec<String>>
}
-#[derive(Clone)]
+#[derive(Clone, Serialize, Deserialize)]
struct RoomConfig {
feature_size: u32,
map_type: String,
@@ -53,7 +58,7 @@
}
}
-fn client_teams_impl(teams: &Vec<(ClientId, TeamInfo)>, client_id: ClientId)
+fn client_teams_impl(teams: &[(ClientId, TeamInfo)], client_id: ClientId)
-> impl Iterator<Item = &TeamInfo> + Clone
{
teams.iter().filter(move |(id, _)| *id == client_id).map(|(_, t)| t)
@@ -106,22 +111,38 @@
}
}
+#[derive(Serialize, Deserialize)]
+pub struct RoomSave {
+ pub location: String,
+ config: RoomConfig
+}
+
+bitflags!{
+ pub struct RoomFlags: u8 {
+ const FIXED = 0b0000_0001;
+ const RESTRICTED_JOIN = 0b0000_0010;
+ const RESTRICTED_TEAM_ADD = 0b0000_0100;
+ const RESTRICTED_UNREGISTERED_PLAYERS = 0b0000_1000;
+ }
+}
+
pub struct HWRoom {
pub id: RoomId,
pub master_id: Option<ClientId>,
pub name: String,
pub password: Option<String>,
- pub protocol_number: u32,
pub greeting: String,
- pub is_fixed: bool,
+ pub protocol_number: u16,
+ pub flags: RoomFlags,
- pub players_number: u32,
+ pub players_number: u8,
pub default_hedgehog_number: u8,
pub team_limit: u8,
pub ready_players_number: u8,
pub teams: Vec<(ClientId, TeamInfo)>,
config: RoomConfig,
pub voting: Option<Voting>,
+ pub saves: HashMap<String, RoomSave>,
pub game_info: Option<GameInfo>
}
@@ -133,15 +154,16 @@
name: String::new(),
password: None,
greeting: "".to_string(),
- is_fixed: false,
+ flags: RoomFlags::empty(),
protocol_number: 0,
players_number: 0,
default_hedgehog_number: 4,
- team_limit: 8,
+ team_limit: MAX_TEAMS_IN_ROOM,
ready_players_number: 0,
teams: Vec::new(),
config: RoomConfig::new(),
voting: None,
+ saves: HashMap::new(),
game_info: None
}
}
@@ -250,11 +272,47 @@
}
}
+ pub fn is_fixed(&self) -> bool {
+ self.flags.contains(RoomFlags::FIXED)
+ }
+ pub fn is_join_restricted(&self) -> bool {
+ self.flags.contains(RoomFlags::RESTRICTED_JOIN)
+ }
+ pub fn is_team_add_restricted(&self) -> bool {
+ self.flags.contains(RoomFlags::RESTRICTED_TEAM_ADD)
+ }
+ pub fn are_unregistered_players_restricted(&self) -> bool {
+ self.flags.contains(RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS)
+ }
+
+ pub fn set_is_fixed(&mut self, value: bool) {
+ self.flags.set(RoomFlags::FIXED, value)
+ }
+ pub fn set_join_restriction(&mut self, value: bool) {
+ self.flags.set(RoomFlags::RESTRICTED_JOIN, value)
+ }
+ pub fn set_team_add_restriction(&mut self, value: bool) {
+ self.flags.set(RoomFlags::RESTRICTED_TEAM_ADD, value)
+ }
+ pub fn set_unregistered_players_restriction(&mut self, value: bool) {
+ self.flags.set(RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS, value)
+ }
+
+ fn flags_string(&self) -> String {
+ let mut result = "-".to_string();
+ if self.game_info.is_some() { result += "g" }
+ if self.password.is_some() { result += "p" }
+ if self.is_join_restricted() { result += "j" }
+ if self.are_unregistered_players_restricted() {
+ result += "r"
+ }
+ result
+ }
+
pub fn info(&self, master: Option<&HWClient>) -> Vec<String> {
- let flags = "-".to_string();
let c = &self.config;
vec![
- flags,
+ self.flags_string(),
self.name.clone(),
self.players_number.to_string(),
self.teams.len().to_string(),
@@ -280,6 +338,34 @@
}
}
+ pub fn save_config(&mut self, name: String, location: String) {
+ self.saves.insert(name, RoomSave { location, config: self.config.clone() });
+ }
+
+ pub fn load_config(&mut self, name: &str) -> Option<&str> {
+ if let Some(save) = self.saves.get(name) {
+ self.config = save.config.clone();
+ Some(&save.location[..])
+ } else {
+ None
+ }
+ }
+
+ pub fn delete_config(&mut self, name: &str) -> bool {
+ self.saves.remove(name).is_some()
+ }
+
+ pub fn get_saves(&self) -> Result<String, serde_yaml::Error> {
+ serde_yaml::to_string(&(&self.greeting, &self.saves))
+ }
+
+ pub fn set_saves(&mut self, text: &str) -> Result<(), serde_yaml::Error> {
+ serde_yaml::from_str::<(String, HashMap<String, RoomSave>)>(text).map(|(greeting, saves)| {
+ self.greeting = greeting;
+ self.saves = saves;
+ })
+ }
+
pub fn team_info(owner: &HWClient, team: &TeamInfo) -> Vec<String> {
let mut info = vec![
team.name.clone(),
--- a/gameServer2/src/server/server.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/server/server.rs Sat Jul 21 02:06:13 2018 +0200
@@ -40,7 +40,7 @@
let client = HWClient::new(entry.key());
entry.insert(client);
}
- self.send(key, Destination::ToSelf, HWServerMessage::Connected(utils::PROTOCOL_VERSION));
+ self.send(key, &Destination::ToSelf, HWServerMessage::Connected(utils::PROTOCOL_VERSION));
key
}
@@ -64,8 +64,8 @@
}
}
- fn get_recipients(&self, client_id: ClientId, destination: Destination) -> Vec<ClientId> {
- let mut ids = match destination {
+ fn get_recipients(&self, client_id: ClientId, destination: &Destination) -> Vec<ClientId> {
+ let mut ids = match *destination {
Destination::ToSelf => vec![client_id],
Destination::ToId(id) => vec![id],
Destination::ToAll {room_id: Some(id), ..} =>
@@ -83,8 +83,8 @@
ids
}
- pub fn send(&mut self, client_id: ClientId, destination: Destination, message: HWServerMessage) {
- let ids = self.get_recipients(client_id, destination);
+ pub fn send(&mut self, client_id: ClientId, destination: &Destination, message: HWServerMessage) {
+ let ids = self.get_recipients(client_id, &destination);
self.output.push((ids, message));
}
@@ -94,6 +94,8 @@
}
}
+ pub fn lobby(&self) -> &HWRoom { &self.rooms[self.lobby_id] }
+
pub fn has_room(&self, name: &str) -> bool {
self.rooms.iter().any(|(_, r)| r.name == name)
}
@@ -124,7 +126,7 @@
self.select_clients(|(_, c)| c.room_id == Some(room_id))
}
- pub fn protocol_clients(&self, protocol: u32) -> Vec<ClientId> {
+ pub fn protocol_clients(&self, protocol: u16) -> Vec<ClientId> {
self.select_clients(|(_, c)| c.protocol_number == protocol)
}
--- a/gameServer2/src/utils.rs Sat Jul 21 00:34:32 2018 +0200
+++ b/gameServer2/src/utils.rs Sat Jul 21 02:06:13 2018 +0200
@@ -3,7 +3,7 @@
use base64::{encode};
pub const PROTOCOL_VERSION : u32 = 3;
-pub const SERVER: mio::Token = mio::Token(1000000000 + 0);
+pub const SERVER: mio::Token = mio::Token(1_000_000_000);
pub fn is_name_illegal(name: &str ) -> bool{
name.len() > 40 ||