--- a/gameServer2/src/server/actions.rs Wed Jun 27 17:58:33 2018 +0300
+++ b/gameServer2/src/server/actions.rs Wed Jun 27 23:26:29 2018 +0300
@@ -222,14 +222,56 @@
c.is_ready = false;
c.is_master = false;
}
- let flags_msg = ClientFlags("+i".to_string(), vec![c.nick.clone()]);
let mut v = vec![
RoomJoined(vec![c.nick.clone()]).send_all().in_room(room_id).action(),
- flags_msg.send_all().action(),
+ ClientFlags("+i".to_string(), vec![c.nick.clone()]).send_all().action(),
SendRoomUpdate(None)];
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;
+
+ {
+ let teams = info.client_teams(c.id);
+ c.teams_in_game = teams.clone().count() as u8;
+ c.clan = teams.clone().next().map(|t| t.color);
+ team_names = teams.map(|t| t.name.clone()).collect();
+ }
+
+ if !team_names.is_empty() {
+ info.left_teams.retain(|name|
+ !team_names.contains(&name));
+ info.teams_in_game += team_names.len() as u8;
+ r.teams = info.teams_at_start.iter()
+ .filter(|(_, t)| !team_names.contains(&t.name))
+ .cloned().collect();
+ }
+ } else {
+ team_names = Vec::new();
+ }
+
v.push(SendRoomData{ to: client_id, teams: true, config: true, flags: true});
+
+ if let Some(ref info) = r.game_info {
+ v.push(RunGame.send_self().action());
+ v.push(ClientFlags("+g".to_string(), vec![c.nick.clone()])
+ .send_all().in_room(r.id).action());
+ v.push(ForwardEngineMessage(
+ to_engine_msg("e$spectate 1".bytes()) + &info.msg_log)
+ .send_self().action());
+
+ for name in team_names.iter() {
+ v.push(ForwardEngineMessage(
+ to_engine_msg(once(b'G').chain(name.bytes())))
+ .send_all().in_room(r.id).action());
+ }
+ if info.is_paused {
+ v.push(ForwardEngineMessage(to_engine_msg(once(b'I')))
+ .send_all().in_room(r.id).action())
+ }
+ }
}
v
};
@@ -247,9 +289,17 @@
}
}
if teams {
- for (owner_id, team) in r.teams.iter() {
+ let current_teams = match r.game_info {
+ Some(ref info) => &info.teams_at_start,
+ None => &r.teams
+ };
+ for (owner_id, team) in current_teams.iter() {
actions.push(TeamAdd(HWRoom::team_info(&server.clients[*owner_id], &team))
.send(to).action());
+ actions.push(TeamColor(team.name.clone(), team.color)
+ .send(to).action());
+ actions.push(HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
+ .send(to).action());
}
}
if flags {
@@ -368,7 +418,7 @@
} else if room.game_info.is_some() {
vec![Warn("The game is already in progress".to_string())]
} else {
- room.game_info = Some(GameInfo::new(room.teams.len() as u8));
+ room.start_round();
for id in room_clients {
let c = &mut server.clients[id];
c.is_in_game = true;
@@ -393,6 +443,13 @@
if info.teams_in_game == 0 {
actions.push(FinishRoomGame(r.id));
}
+ let remove_msg = to_engine_msg(once(b'F').chain(team_name.bytes()));
+ match &info.last_msg {
+ Some(m) => info.msg_log.push_str(&m),
+ None => info.msg_log.push_str(&remove_msg)
+ }
+ actions.push(ForwardEngineMessage(remove_msg)
+ .send_all().in_room(r.id).but_self().action());
}
}
server.react(client_id, actions);
--- a/gameServer2/src/server/handlers/inroom.rs Wed Jun 27 17:58:33 2018 +0300
+++ b/gameServer2/src/server/handlers/inroom.rs Wed Jun 27 23:26:29 2018 +0300
@@ -239,18 +239,25 @@
let decoding = decode(&em[..]).unwrap();
let messages = by_msg(&decoding);
let valid = messages.clone().filter(|m| is_msg_valid(m, &c.team_indices));
- let _non_empty = messages.filter(|m| !is_msg_empty(m));
- let _last_valid_timed_msg = valid.clone().scan(None, |res, msg| match msg {
+ let non_empty = messages.filter(|m| !is_msg_empty(m));
+ let last_msg = valid.clone().scan(None, |res, msg| match msg {
[_, b'+', ..] => Some(msg),
[_, typ, ..] if NON_TIMED_MESSAGES.contains(typ) => *res,
_ => None
- }).next();
+ }).next().map(|s| encode(s));
let em_response = encode(&valid.flat_map(|msg| msg).cloned().collect::<Vec<_>>());
if !em_response.is_empty() {
actions.push(ForwardEngineMessage(em_response)
.send_all().in_room(r.id).but_self().action());
}
+ let em_log = encode(&non_empty.flat_map(|msg| msg).cloned().collect::<Vec<_>>());
+ if let Some(ref mut info) = r.game_info {
+ info.msg_log.push_str(&em_log);
+ if last_msg.is_some() {
+ info.last_msg = last_msg;
+ }
+ }
}
}
server.react(client_id, actions)
--- a/gameServer2/src/server/handlers/lobby.rs Wed Jun 27 17:58:33 2018 +0300
+++ b/gameServer2/src/server/handlers/lobby.rs Wed Jun 27 23:26:29 2018 +0300
@@ -43,16 +43,16 @@
.map(|(_, c)| c.nick.clone())
.collect();
let c = &mut server.clients[client_id];
- actions = match room {
- None => vec![Warn("No such room.".to_string())],
- Some((_, r)) => {
- if c.protocol_number != r.protocol_number {
- vec![Warn("Room version incompatible to your Hedgewars version!".to_string())]
- } else {
- vec![MoveToRoom(r.id),
- RoomJoined(nicks).send_self().action()]
- }
+
+ 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 {
+ vec![MoveToRoom(r.id),
+ RoomJoined(nicks).send_self().action()]
}
+ } else {
+ vec![Warn("No such room.".to_string())]
};
}
server.react(client_id, actions);
--- a/gameServer2/src/server/room.rs Wed Jun 27 17:58:33 2018 +0300
+++ b/gameServer2/src/server/room.rs Wed Jun 27 23:26:29 2018 +0300
@@ -7,16 +7,19 @@
const MAX_HEDGEHOGS_IN_ROOM: u8 = 48;
pub type RoomId = usize;
+#[derive(Clone)]
struct Ammo {
name: String,
settings: Option<String>
}
+#[derive(Clone)]
struct Scheme {
name: String,
settings: Option<Vec<String>>
}
+#[derive(Clone)]
struct RoomConfig {
feature_size: u32,
map_type: String,
@@ -51,18 +54,57 @@
}
}
+fn client_teams_impl(teams: &Vec<(ClientId, TeamInfo)>, client_id: ClientId)
+ -> impl Iterator<Item = &TeamInfo> + Clone
+{
+ teams.iter().filter(move |(id, _)| *id == client_id).map(|(_, t)| t)
+}
+
+fn map_config_from(c: &RoomConfig) -> Vec<String> {
+ vec![c.feature_size.to_string(), c.map_type.to_string(),
+ c.map_generator.to_string(), c.maze_size.to_string(),
+ c.seed.to_string(), c.template.to_string()]
+}
+
+fn game_config_from(c: &RoomConfig) -> Vec<GameCfg> {
+ use server::coretypes::GameCfg::*;
+ let mut v = vec![
+ Ammo(c.ammo.name.to_string(), c.ammo.settings.clone()),
+ Scheme(c.scheme.name.to_string(), c.scheme.settings.clone()),
+ Script(c.script.to_string()),
+ Theme(c.theme.to_string())];
+ if let Some(ref m) = c.drawn_map {
+ v.push(DrawnMap(m.to_string()))
+ }
+ v
+}
+
pub struct GameInfo {
pub teams_in_game: u8,
- pub left_teams: Vec<String>
+ pub teams_at_start: Vec<(ClientId, TeamInfo)>,
+ pub left_teams: Vec<String>,
+ pub msg_log: String,
+ pub last_msg: Option<String>,
+ pub is_paused: bool,
+ config: RoomConfig
}
impl GameInfo {
- pub fn new(teams_number: u8) -> GameInfo {
+ fn new(teams: Vec<(ClientId, TeamInfo)>, config: RoomConfig) -> GameInfo {
GameInfo {
- teams_in_game: teams_number,
- left_teams: Vec::new()
+ left_teams: Vec::new(),
+ msg_log: String::new(),
+ last_msg: None,
+ is_paused: false,
+ teams_in_game: teams.len() as u8,
+ teams_at_start: teams,
+ config
}
}
+
+ pub fn client_teams(&self, client_id: ClientId) -> impl Iterator<Item = &TeamInfo> + Clone {
+ client_teams_impl(&self.teams_at_start, client_id)
+ }
}
pub struct HWRoom {
@@ -138,7 +180,7 @@
}
pub fn client_teams(&self, client_id: ClientId) -> impl Iterator<Item = &TeamInfo> {
- self.teams.iter().filter(move |(id, _)| *id == client_id).map(|(_, t)| t)
+ client_teams_impl(&self.teams, client_id)
}
pub fn client_team_indices(&self, client_id: ClientId) -> Vec<u8> {
@@ -179,6 +221,13 @@
};
}
+ pub fn start_round(&mut self) {
+ if self.game_info.is_none() {
+ self.game_info = Some(GameInfo::new(
+ self.teams.clone(), self.config.clone()));
+ }
+ }
+
pub fn info(&self, master: Option<&HWClient>) -> Vec<String> {
let flags = "-".to_string();
let c = &self.config;
@@ -196,24 +245,17 @@
}
pub fn map_config(&self) -> Vec<String> {
- let c = &self.config;
- vec![c.feature_size.to_string(), c.map_type.to_string(),
- c.map_generator.to_string(), c.maze_size.to_string(),
- c.seed.to_string(), c.template.to_string()]
+ match self.game_info {
+ Some(ref info) => map_config_from(&info.config),
+ None => map_config_from(&self.config)
+ }
}
pub fn game_config(&self) -> Vec<GameCfg> {
- use server::coretypes::GameCfg::*;
- let c = &self.config;
- let mut v = vec![
- Ammo(c.ammo.name.to_string(), c.ammo.settings.clone()),
- Scheme(c.scheme.name.to_string(), c.scheme.settings.clone()),
- Script(c.script.to_string()),
- Theme(c.theme.to_string())];
- if let Some(ref m) = c.drawn_map {
- v.push(DrawnMap(m.to_string()))
+ match self.game_info {
+ Some(ref info) => game_config_from(&info.config),
+ None => game_config_from(&self.config)
}
- v
}
pub fn team_info(owner: &HWClient, team: &TeamInfo) -> Vec<String> {