From: Ian Jackson Date: Sun, 8 Nov 2020 14:50:28 +0000 (+0000) Subject: wip new game joining, remove players X-Git-Tag: otter-0.2.0~544 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=3566e665660f76ec501d5aa03f432ae736fd5c39;p=otter.git wip new game joining, remove players Signed-off-by: Ian Jackson --- diff --git a/src/accounts.rs b/src/accounts.rs index fe017f5d..0fdd50d0 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -338,7 +338,7 @@ impl AccountsGuard { else { throw!(AccountNotFound) } }; process_all_players_for_account(acctid, |ig,player| { - ig.player_remove(player)?; + ig.players_remove(&[player].iter().cloned().collect())?; Ok::<_,ME>(()) })?; accounts.names.remove(account); diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index a904232f..49605596 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -506,29 +506,32 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( &who)), } ]; - let eacl = EffectiveACL { - owner_account: &ig.account, - acl: &ig.acl, - }; - #[throws(InternalError)] fn remove_old_players(ag: &AccountsGuard, ig: &mut InstanceGuard, - who: &str, eacl: &EffectiveACL<'_, TP>, - log: &mut Vec) { - let mut remove = vec![]; - for (player, ipr) in ig.players { + who: &Who, log: &mut Vec) { + let owner_account = ig.name.account.to_string(); + let eacl = EffectiveACL { + owner_account: Some(&owner_account), + acl: &ig.acl, + }; + + let mut remove = HashSet::new(); + for (player, ipr) in &ig.iplayers { if_chain! { let acctid = ipr.ipl.acctid; - if let Some(record,_) = ag.lookup(acctid); - if let Ok(_) = eacl.check(&*record.name, &[TP::Play]); + if let Ok((record,_)) = ag.lookup(acctid); + let perm = &[TP::Play]; + if let Ok(_) = eacl.check(&record.account.to_string(), + perm.into()); then { /* ok */ } else { - remove.push(player); + remove.insert(player); } }; }; + for (gpl, _ipl) in ig.players_remove(&remove)? { let show = if let Some(gpl) = gpl { htmlescape::encode_minimal(&gpl.nick) @@ -541,7 +544,7 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( } } - remove_old_players(ag, ig, &who, &eacl, &mut log)?; + remove_old_players(&ag, ig, who, &mut log)?; (U{ pcs: vec![ ], log, diff --git a/src/commands.rs b/src/commands.rs index ad3ae0c4..7a7bd8cd 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -80,10 +80,10 @@ pub enum MgmtGameInstruction { JoinGame { details: MgmtPlayerDetails }, UpdatePlayer { player: PlayerId, details: MgmtPlayerDetails }, - RemovePlayer { player: PlayerId }, ClearLog, SetACL { acl: Acl }, + // RemovePlayer { player: PlayerId }, todo, does a special setacl } // xxx facilitator name? diff --git a/src/global.rs b/src/global.rs index 834f5856..2d2ea9b4 100644 --- a/src/global.rs +++ b/src/global.rs @@ -476,32 +476,34 @@ impl<'ig> InstanceGuard<'ig> { } pub fn remove_clients(&mut self, - player: PlayerId, + players: &HashSet, signal: ErrorSignaledViaUpdate) { let mut clients_to_remove = HashSet::new(); self.clients.retain(|k,v| { - let remove = v.player == player; + let remove = players.contains(&v.player); if remove { clients_to_remove.insert(k); } !remove }); let gen = self.c.g.gs.gen; - if let Some(iplayer) = self.iplayers.get_mut(player) { - iplayer.u.push(PreparedUpdate { - gen, - when: Instant::now(), - us : vec![ PreparedUpdateEntry::Error( - None, - signal, - )], - }); - }; + for &player in players { + if let Some(iplayer) = self.iplayers.get_mut(player) { + iplayer.u.push(PreparedUpdate { + gen, + when: Instant::now(), + us : vec![ PreparedUpdateEntry::Error( + None, + signal.clone(), + )], + }); + }; + } self.tokens_deregister_for_id(|id| clients_to_remove.contains(&id)); } // #[throws(InternalError)] // https://github.com/withoutboats/fehler/issues/62 - pub fn players_remove(&mut self, oldplayers: HashSet) + pub fn players_remove(&mut self, oldplayers: &HashSet) -> Result, Option) @@ -513,7 +515,9 @@ impl<'ig> InstanceGuard<'ig> { // 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_gpl = players.remove(oldplayers); + let old_gpls : Vec<_> = oldplayers.iter().cloned().map(|oldplayer| { + players.remove(oldplayer) + }).collect(); // New state let mut gs = GameState { @@ -527,19 +531,19 @@ impl<'ig> InstanceGuard<'ig> { pieces : Default::default(), }; + let held_by_old = |p: &PieceState| if_chain! { + if let Some(held) = p.held; + if oldplayers.contains(&held); + then { true } + else { false } + }; + let mut updated_pieces = vec![]; // drop order is reverse of creation order, so create undo // after all the things it will reference let mut undo : Vec> = vec![]; - let held_by_old = |p: PieceState| if_chain! { - if let Some(held) = p.held; - if oldplayers.contains(held); - then { true } - else { false } - }; - // Arrange gs.pieces for (piece,p) in &mut self.c.g.gs.pieces { if held_by_old(p) { @@ -573,7 +577,7 @@ impl<'ig> InstanceGuard<'ig> { // point of no return mem::drop(undo); - let old_ipl = (||{ + let old_ipls = (||{ for &piece in &updated_pieces { (||Some({ self.c.g.gs.pieces.get_mut(piece)?.gen = self.c.g.gs.gen; @@ -589,18 +593,24 @@ impl<'ig> InstanceGuard<'ig> { buf.finish(); self.remove_clients(oldplayers, ErrorSignaledViaUpdate::PlayerRemoved); - self.tokens_deregister_for_id(|id:PlayerId| oldplayers.contains(id)); - let iplayer = self.iplayers.remove(oldplayers); - let ipl = iplayer.map(|iplayer| iplayer.ipl); + self.tokens_deregister_for_id(|id:PlayerId| oldplayers.contains(&id)); + let old_ipls : Vec<_> = oldplayers.iter().cloned().map( + |oldplayer| self.iplayers.remove(oldplayer) + .map(|ipr| ipr.ipl) + ).collect(); self.save_access_now().unwrap_or_else( |e| warn!( "trouble garbage collecting accesses for deleted player: {:?}", &e) ); - ipl + old_ipls })(); // <- No ?, ensures that IEFE is infallible (barring panics) - Ok((old_gpl, old_ipl)) + let old = itertools::zip( + old_gpls, + old_ipls, + ).collect(); + Ok(old) } #[throws(InternalError)] @@ -619,7 +629,8 @@ impl<'ig> InstanceGuard<'ig> { })?; // ppoint of no return (||{ - self.remove_clients(player, ErrorSignaledViaUpdate::TokenRevoked); + self.remove_clients(&[player].iter().cloned().collect(), + ErrorSignaledViaUpdate::TokenRevoked); })(); // <- No ?, ensures that IEFE is infallible (barring panics) }