pub nick: String,
pub layout: PresentationLayout,
pub idmap: PerPlayerIdMap,
- #[serde(default)] pub moveheld: SparseSecondaryMap<PieceId, GMoveHistLast>,
- #[serde(default)] pub movehist: VecDeque<MoveHistEnt>,
+ #[serde(default)] pub moveheld: GMoveHeld,
+ #[serde(default)] pub movehist: GMoveHist,
}
#[derive(Debug,Serialize,Deserialize)]
pub moveable: PieceMoveable,
}
-#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
-pub struct MoveHistPosx { // usual variable: posx
- pub pos: Pos,
- pub angle: CompassAngle,
- pub facehint: Option<FaceId>,
-}
-
-#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
-pub struct GMoveHistLast {
- pub held: PlayerId,
- pub posx: MoveHistPosx,
-}
-
-#[derive(Debug,Clone,Serialize,Deserialize)]
-pub struct MoveHistEnt {
- pub held: PlayerId,
- pub posx: OldNew<MoveHistPosx>,
-}
-
pub type PieceXDataState = Option<Box<dyn PieceXData>>;
#[derive(Debug,Serialize,Deserialize)]
--- /dev/null
+// Copyright 2020-2021 Ian Jackson and contributors to Otter
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use super::*; // we are otter::updates::movehist
+
+#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
+pub struct MoveHistPosx { // usual variable: posx
+ pub pos: Pos,
+ pub angle: CompassAngle,
+ pub facehint: Option<FaceId>,
+}
+
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub struct MoveHistEnt {
+ pub held: PlayerId,
+ pub posx: OldNew<MoveHistPosx>,
+}
+
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub struct GMoveHist {
+ pub hist: VecDeque<MoveHistEnt>,
+}
+
+// ---------- non-public structs ----------
+
+#[derive(Debug,Clone,Serialize,Deserialize,Default)]
+pub struct GMoveHeld {
+ held: SparseSecondaryMap<VisiblePieceId, GMoveHistLast>,
+}
+
+#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
+struct GMoveHistLast {
+ held: PlayerId,
+ posx: MoveHistPosx,
+}
+
+impl Default for GMoveHist {
+ fn default() -> GMoveHist { GMoveHist {
+ hist: VecDeque::with_capacity(MOVEHIST_LEN_MAX),
+ } }
+}
+
+// We're track this on behalf of the client, based on the updates
+// we are sending. That means we don't ahve to worry about
+// occultation, etc. etc.
+pub fn peek_prep_update(gs: &mut GameState, peek: &PreparedUpdateEntry)
+ -> Option<PreparedUpdateEntry> {
+ if_let!{ PUE::Piece(PUE_P { ops,.. }) = peek; else return None; }
+
+ let mut pu = SecondarySlotMap::new();
+ for (player, &PreparedPieceUpdate { ref op, piece,.. }) in ops { if_chain! {
+ if let Some(ns) = op.new_state();
+ if let Some(gpl) = wants!( gs.players.get_mut(player), ?player);
+ if let Some(mut ent) = wants!( gpl.moveheld.held.entry(piece), ?piece);
+ let &PreparedPieceState { pos, angle, facehint, .. } = ns;
+ let new_posx = MoveHistPosx { pos, angle, facehint };
+
+ then {
+ if let slotmap::sparse_secondary::Entry::Occupied(ref mut oe) = ent {
+ let last = oe.get();
+ if ns.held == Some(last.held) { continue }
+
+ // Generate an update
+ let histent = MoveHistEnt {
+ held: last.held,
+ posx: OldNew::from([last.posx, new_posx]),
+ };
+ if gpl.movehist.hist.len() == MOVEHIST_LEN_MAX {
+ gpl.movehist.hist.pop_front();
+ }
+ gpl.movehist.hist.push_back(histent.clone());
+ pu.insert(player, histent);
+ }
+
+ if let Some(held) = ns.held {
+ ent.insert(GMoveHistLast { held: held, posx: new_posx });
+ } else {
+ ent.remove();
+ }
+ }
+ } }
+
+ if pu.is_empty() { return None }
+
+ Some(PUE::MoveHistEnt(pu))
+}
pub use crate::toml_de;
pub use crate::tz::*;
pub use crate::updates::*;
+pub use crate::updates::movehist::{self, GMoveHeld, GMoveHist, MoveHistEnt};
pub use crate::utils::*;
pub use crate::ui::*;
use crate::prelude::*;
+#[path="movehist.rs"] pub mod movehist;
+
#[allow(non_camel_case_types)] type TUE_P<'u> = TransmitUpdateEntry_Piece<'u>;
#[allow(non_camel_case_types)] type PUE_I = PreparedUpdateEntry_Image;
#[allow(non_camel_case_types)] type TUE_I<'u> = TransmitUpdateEntry_Image<'u>;
PreparedUpdateEntry::Error(ErrorSignaledViaUpdate::InternalError)
});
- // We're track this on behalf of the client, based on the updates
- // we are sending. That means we don't ahve to worry about
- // occultation, etc. etc.
- let movehist_update = if let PUE::Piece(PUE_P { ops,.. }) = &update {
- let mut pu = SecondarySlotMap::new();
- for (player, PreparedPieceUpdate { op,.. }) in ops { if_chain! {
- if let Some(ns) = op.new_state();
- if let Some(gpl) = wants!( self.g.gs.players.get_mut(player), ?player);
- if let Some(mut ent) = wants!( gpl.moveheld.entry(piece), ?piece);
- let &PreparedPieceState { pos, angle, facehint, .. } = ns;
- let new_posx = MoveHistPosx { pos, angle, facehint };
-
- then {
- if let slotmap::sparse_secondary::Entry::Occupied(ref mut oe) = ent {
- let last = oe.get();
- if ns.held == Some(last.held) { continue }
-
- // Generate an update
- let histent = MoveHistEnt {
- held: last.held,
- posx: OldNew::from([last.posx, new_posx]),
- };
- gpl.movehist.reserve(MOVEHIST_LEN_MAX);
- if gpl.movehist.len() == MOVEHIST_LEN_MAX {
- gpl.movehist.pop_front();
- }
- gpl.movehist.push_back(histent.clone());
- pu.insert(player, histent);
- }
-
- if let Some(held) = ns.held {
- ent.insert(GMoveHistLast { held: held, posx: new_posx });
- } else {
- ent.remove();
- }
- }
- } }
+ let movehist_update = movehist::peek_prep_update(&mut self.g.gs, &update);
- if pu.is_empty() {
- None
- } else {
- Some(PUE::MoveHistEnt(pu))
- }
- } else {
- None
- };
self.us.push(update);
self.us.extend(movehist_update);
}