tz,
tokens_revealed: default(),
};
- let (player, logentry) = ig.player_new(gpl, ipl, logentry)?;
+ let (player, update, logentry) = ig.player_new(gpl, ipl, logentry)?;
let atr = ig.player_access_reset(ag, player, auth.therefore_ok())?;
(U{ pcs: vec![],
log: vec![ logentry ],
- raw: None },
+ raw: Some(vec![ update ] )},
Resp::JoinGame { nick, player, token: atr },
ig)
},
let got = ig.players_remove(&[player].iter().cloned().collect())?;
- let (gpl, ipl) = got.into_iter().next()
+ let (gpl, ipl, update) = got.into_iter().next()
.ok_or(PlayerNotFound)?;
let html = Html(
(U{ pcs: vec![],
log: vec![ LogEntry { html }],
- raw: None },
+ raw: Some(vec![ update ]) },
Fine, ig)
},
#[throws(InternalError)]
fn remove_old_players(ag: &AccountsGuard, ig: &mut InstanceGuard,
- who: &Html, log: &mut Vec<LogEntry>) {
+ who: &Html,
+ log: &mut Vec<LogEntry>)
+ -> Vec<PreparedUpdateEntry>
+ {
let owner_account = ig.name.account.to_string();
let eacl = EffectiveACL {
owner_account: Some(&owner_account),
};
};
- for (gpl, _ipl) in ig.players_remove(&remove)? {
+ let mut updates = Vec::new();
+ for (gpl, _ipl, update) in ig.players_remove(&remove)? {
let show = if let Some(gpl) = gpl {
htmlescape::encode_minimal(&gpl.nick)
} else {
log.push(LogEntry {
html: Html(format!("{} removed a player {}", &who.0, &show)),
});
+ updates.push(update);
}
+
+ updates
}
- remove_old_players(&ag, ig, who, &mut log)?;
+ let updates = remove_old_players(&ag, ig, who, &mut log)?;
(U{ pcs: vec![ ],
log,
- raw: None },
+ raw: Some(updates) },
Fine, ig)
},
};
use slotmap::dense as sm;
type ME = MgmtError;
+type ESU = ErrorSignaledViaUpdate;
// ---------- newtypes and type aliases ----------
#[throws(MgmtError)]
pub fn player_new(&mut self, gnew: GPlayerState, inew: IPlayerState,
logentry: LogEntry)
- -> (PlayerId, /* todo some game update,*/ LogEntry) {
+ -> (PlayerId, PreparedUpdateEntry, LogEntry) {
// saving is fallible, but we can't attempt to save unless
// we have a thing to serialise with the player in it
self.check_new_nick(&gnew.nick)?;
let player = self.c.g.gs.players.insert(gnew);
let u = PlayerUpdates::new_begin(&self.c.g.gs).new();
let record = PlayerRecord { u, ipl: inew };
+ let update = PreparedUpdateEntry::AddPlayer {
+ player,
+ data: DataLoadPlayer::from_player(self, player),
+ };
self.c.g.iplayers.insert(player, record);
(||{
(||{
})(); // <- No ?, ensures that IEFE is infallible (barring panics)
- (player, logentry)
+ (player, update, logentry)
}
#[throws(MgmtError)]
// #[throws(InternalError)]
// https://github.com/withoutboats/fehler/issues/62
- pub fn players_remove(&mut self, oldplayers: &HashSet<PlayerId>)
+ pub fn players_remove(&mut self, old_players_set: &HashSet<PlayerId>)
->
Result<Vec<
- (Option<GPlayerState>, Option<IPlayerState>)
+ (Option<GPlayerState>, Option<IPlayerState>, PreparedUpdateEntry)
>, InternalError>
{
// We have to filter this player out of everything
// We make a copy so if the save fails, we can put everything back
let mut players = self.c.g.gs.players.clone();
- let old_gpls : Vec<_> = oldplayers.iter().cloned().map(|oldplayer| {
+ let old_players : Vec<_> = old_players_set.iter().cloned().collect();
+ let old_gpls : Vec<_> = old_players.iter().cloned().map(|oldplayer| {
players.remove(oldplayer)
}).collect();
let held_by_old = |p: &PieceState| if_chain! {
if let Some(held) = p.held;
- if oldplayers.contains(&held);
+ if old_players_set.contains(&held);
then { true }
else { false }
};
}
buf.finish();
- self.remove_clients(oldplayers, ErrorSignaledViaUpdate::PlayerRemoved);
- self.tokens_deregister_for_id(|id:PlayerId| oldplayers.contains(&id));
- let old_ipls : Vec<_> = oldplayers.iter().cloned().map(
+ self.remove_clients(old_players_set, ESU::PlayerRemoved);
+ self.tokens_deregister_for_id(
+ |id:PlayerId| old_players_set.contains(&id)
+ );
+ let old_ipls : Vec<_> = old_players.iter().cloned().map(
|oldplayer| self.iplayers.remove(oldplayer)
.map(|ipr| ipr.ipl)
).collect();
old_ipls
})(); // <- No ?, ensures that IEFE is infallible (barring panics)
- let old = itertools::zip(
+ let updates = old_players.iter().cloned().map(
+ |player| PreparedUpdateEntry::RemovePlayer { player }
+ );
+
+ let old = izip!(
old_gpls,
old_ipls,
+ updates
).collect();
+
Ok(old)
}
// ppoint of no return
(||{
self.remove_clients(&[player].iter().cloned().collect(),
- ErrorSignaledViaUpdate::TokenRevoked);
+ ESU::TokenRevoked);
})(); // <- No ?, ensures that IEFE is infallible (barring panics)
}
pub use fs2::FileExt;
pub use if_chain::if_chain;
pub use index_vec::{define_index_type, index_vec, IndexVec, IndexSlice};
-pub use itertools::EitherOrBoth;
-pub use itertools::Itertools;
+pub use itertools::{izip, EitherOrBoth, Itertools};
pub use lazy_static::lazy_static;
pub use log::{log, log_enabled};
pub use log::{trace, debug, info, warn, error};
last_log_ts: String,
players : HashMap<PlayerId, DataLoadPlayer>,
}
-#[derive(Serialize,Debug)]
-struct DataLoadPlayer {
- dasharray : String,
-}
#[derive(Deserialize)]
struct SessionForm {
let mut load_players = HashMap::new();
for (player, _pl) in &ig.gs.players {
- let kd : slotmap::KeyData = player.into();
- let n = kd.get_idx_version().0;
- let n = if n != 0 { n.try_into().unwrap() }
- else { ig.gs.players.capacity() };
- assert!(n != 0);
- let mut dasharray = String::with_capacity(n*3 + 4);
- for dash in iter::once("3").chain(
- iter::repeat("1").take(n-1))
- {
- write!(&mut dasharray, "{} 1 ", &dash).unwrap();
- }
- let spc = dasharray.pop();
- assert_eq!(spc,Some(' '));
-
- load_players.insert(player, DataLoadPlayer {
- dasharray,
- });
+ let dataload = DataLoadPlayer::from_player(ig, player);
+ load_players.insert(player, dataload);
}
let gpl = ig.gs.players.byid_mut(player)?;
op : PieceUpdateOp<PreparedPieceState,ZLevel>,
},
SetTableSize(Pos),
+ AddPlayer { player: PlayerId, data: DataLoadPlayer },
+ RemovePlayer { player: PlayerId },
Log (Arc<CommittedLogEntry>),
Error (Option<ClientId> /* none: all */, ErrorSignaledViaUpdate),
}
pub uos: Vec<UoDescription>,
}
+#[derive(Serialize,Debug)]
+pub struct DataLoadPlayer {
+ dasharray : String,
+}
+
// ---------- piece updates ----------
#[derive(Debug,Serialize)]
ns: &'u PreparedPieceState,
},
SetTableSize(Pos),
+ AddPlayer { player: PlayerId, data: &'u DataLoadPlayer },
+ RemovePlayer { player: PlayerId },
#[serde(serialize_with="serialize_logentry")]
Log(TransmitUpdateLogEntry<'u>),
Error(&'u ErrorSignaledViaUpdate),
// ---------- prepared updates, queued in memory ----------
-
pub struct PlayerUpdatesBuildContext {
pub(self) u1: Arc<PreparedUpdate>,
}
Log(logent) => {
logent.logent.html.0.as_bytes().len() * 28
},
+ AddPlayer { player:_, data: DataLoadPlayer { dasharray } } => {
+ dasharray.as_bytes().len() + 100
+ },
SetTableSize(_) |
+ RemovePlayer { player:_ } |
Error(_,_) => {
100
},
}
}
+impl DataLoadPlayer {
+ pub fn from_player(ig: &Instance, player: PlayerId) -> Self {
+ let kd : slotmap::KeyData = player.into();
+ let n = kd.get_idx_version().0;
+ let n = if n != 0 { n.try_into().unwrap() }
+ else { ig.gs.players.capacity() };
+ assert!(n != 0);
+ let mut dasharray = String::with_capacity(n*3 + 4);
+ for dash in iter::once("3").chain(
+ iter::repeat("1").take(n-1))
+ {
+ write!(&mut dasharray, "{} 1 ", &dash).unwrap();
+ }
+ let spc = dasharray.pop();
+ assert_eq!(spc,Some(' '));
+ DataLoadPlayer {
+ dasharray,
+ }
+ }
+}
+
// ---------- PieceUpdatesOp ----------
impl<NS,ZC> PieceUpdateOp<NS,ZC> {
&PUE::SetTableSize(size) => {
TUE::SetTableSize(size)
},
+ &PUE::AddPlayer { player, ref data } => {
+ TUE::AddPlayer { player, data }
+ },
+ &PUE::RemovePlayer { player } => {
+ TUE::RemovePlayer { player }
+ },
PUE::Error(c, e) => {
if *c == None || *c == Some(dest) {
TUE::Error(e)