# HG changeset patch # User alfadur # Date 1530131189 -10800 # Node ID 6f6a866c86a239a4388e4af7e82691251907842e # Parent f091f69d59e494ab914435149165f4d2db281bdd Send more data on room joining diff -r f091f69d59e4 -r 6f6a866c86a2 gameServer2/src/server/actions.rs --- 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); diff -r f091f69d59e4 -r 6f6a866c86a2 gameServer2/src/server/handlers/inroom.rs --- 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::>()); 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::>()); + 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) diff -r f091f69d59e4 -r 6f6a866c86a2 gameServer2/src/server/handlers/lobby.rs --- 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); diff -r f091f69d59e4 -r 6f6a866c86a2 gameServer2/src/server/room.rs --- 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 } +#[derive(Clone)] struct Scheme { name: String, settings: Option> } +#[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 + Clone +{ + teams.iter().filter(move |(id, _)| *id == client_id).map(|(_, t)| t) +} + +fn map_config_from(c: &RoomConfig) -> Vec { + 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 { + 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 + pub teams_at_start: Vec<(ClientId, TeamInfo)>, + pub left_teams: Vec, + pub msg_log: String, + pub last_msg: Option, + 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 + 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 { - 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 { @@ -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 { let flags = "-".to_string(); let c = &self.config; @@ -196,24 +245,17 @@ } pub fn map_config(&self) -> Vec { - 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 { - 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 {