From 991fa7ac1ab72ecc5d1726c26e7e93366c369442 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 27 Sep 2020 02:04:12 +0100 Subject: [PATCH] prevent modifying which pieces exist without a modperm Signed-off-by: Ian Jackson --- src/cmdlistener.rs | 4 +-- src/gamestate.rs | 3 ++- src/global.rs | 62 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index 6267bcf9..3eb53d16 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -227,7 +227,7 @@ fn execute_game_insn(cs: &CommandStream, let p = ig.pieces.as_mut(modperm) .remove(piece).ok_or(ME::PieceNotFound)?; let gs = &mut ig.gs; - let pc = gs.pieces.remove(piece); + let pc = gs.pieces.as_mut(modperm).remove(piece); let desc_html = p.describe_html(Some(Default::default())); if let Some(pc) = pc { p.delete_hook(&pc, gs); } (U{ pcs: vec![(piece, PieceUpdateOp::Delete())], @@ -264,7 +264,7 @@ fn execute_game_insn(cs: &CommandStream, if let (_, true) = pc.pos.clamped(gs.table_size) { throw!(SpecError::PosOffTable); } - let piece = gs.pieces.insert(pc); + let piece = gs.pieces.as_mut(modperm).insert(pc); ig.pieces.as_mut(modperm).insert(piece, p); updates.push((piece, PieceUpdateOp::Insert(()))); pos[0] += posd[0]; diff --git a/src/gamestate.rs b/src/gamestate.rs index 9cabc5aa..54231352 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -44,7 +44,7 @@ pub struct ZLevel { #[derive(Debug,Serialize,Deserialize)] pub struct GameState { pub table_size : Pos, - pub pieces : DenseSlotMap, + pub pieces : Pieces, pub players : PlayerMap, pub gen : Generation, pub log : Vec<(Generation,Arc)>, @@ -196,6 +196,7 @@ impl Debug for Html { // ---------- game state - rendering etc. ---------- + impl PieceState { #[throws(IE)] pub fn prep_piecestate(&self, p: &dyn Piece, pri : &PieceRenderInstructions) diff --git a/src/global.rs b/src/global.rs index f6986e08..341008d6 100644 --- a/src/global.rs +++ b/src/global.rs @@ -7,6 +7,7 @@ use crate::imports::*; use std::sync::PoisonError; +use slotmap::dense as sm; // ---------- newtypes and type aliases ---------- @@ -49,6 +50,11 @@ pub type ActualPiecesLoaded = SecondarySlotMap>; #[derive(Copy,Clone,Debug)] pub struct ModifyingPieces(()); +#[derive(Debug,Serialize,Deserialize,Default)] +#[serde(transparent)] +pub struct Pieces (pub(in crate::global) ActualPieces); +type ActualPieces = DenseSlotMap; + #[derive(Debug,Clone,Deserialize,Serialize)] #[derive(Eq,PartialEq,Ord,PartialOrd,Hash)] pub enum ManagementScope { @@ -408,7 +414,9 @@ impl InstanceGuard<'_> { } } undo.push(Box::new(|ig| for &piece in &updated_pieces { - ig.c.g.gs.pieces[piece].held = Some(oldplayer) + (||Some({ + ig.c.g.gs.pieces.get_mut(piece)?.held = Some(oldplayer); + }))(); })); // Handle gs.log: @@ -433,7 +441,9 @@ impl InstanceGuard<'_> { (||{ for &piece in &updated_pieces { - self.c.g.gs.pieces[piece].gen = self.c.g.gs.gen; + (||Some({ + self.c.g.gs.pieces.get_mut(piece)?.gen = self.c.g.gs.gen; + }))(); } let lens = TransparentLens { }; @@ -730,8 +740,8 @@ impl InstanceGuard<'_> { for mut p in gs.pieces.values_mut() { p.lastclient = Default::default(); } - gs.pieces.retain(|k,_v| pieces.contains_key(k)); - pieces.retain(|k,_v| gs.pieces.contains_key(k)); + gs.pieces.0.retain(|k,_v| pieces.contains_key(k)); + pieces.retain(|k,_v| gs.pieces.0.contains_key(k)); gs }; @@ -908,6 +918,50 @@ impl PiecesLoaded { } } +// ---------- gamestate pieces table ---------- + +impl Deref for Pieces { + type Target = ActualPieces; + fn deref(&self) -> &ActualPieces { &self.0 } +} + +impl Pieces { + pub fn get_mut(&mut self, piece: PieceId) -> Option<&mut PieceState> { + self.0.get_mut(piece) + } + pub fn values_mut(&mut self) -> sm::ValuesMut { + self.0.values_mut() + } + pub fn as_mut(&mut self, _: ModifyingPieces) -> &mut ActualPieces { + &mut self.0 + } +} + +impl ById for Pieces { + type Id = PieceId; + type Entry = PieceState; + type Error = OnlineError; + #[throws(OE)] + fn byid(&self, piece: PieceId) -> &PieceState { + self.get(piece).ok_or(OE::PieceGone)? + } + #[throws(OE)] + fn byid_mut(&mut self, piece: PieceId) -> &mut PieceState { + self.get_mut(piece).ok_or(OE::PieceGone)? + } +} + +/*impl<'p> IntoIterator for &'p Pieces { + type Item = (PieceId, &'p PieceState); + type IntoIter = sm::Iter<'p, PieceId, PieceState>; + fn into_iter(self) -> Self::IntoIter { (&self.0).into_iter() } +}*/ +impl<'p> IntoIterator for &'p mut Pieces { + type Item = (PieceId, &'p mut PieceState); + type IntoIter = sm::IterMut<'p, PieceId, PieceState>; + fn into_iter(self) -> Self::IntoIter { (&mut self.0).into_iter() } +} + // ========== background maintenance ========== // ---------- delayed game save ---------- -- 2.30.2