let mut pieces : Vec<_> = ig.gs.pieces.iter().collect();
- pieces.sort_by_key(|(_,pr)| pr.raised);
+ pieces.sort_by_key(|(_,pr)| pr.zlevel);
for (gpid, pr) in pieces {
let pri = PieceRenderInstructions {
client,
sameclient_cseq : form.cseq,
piece : pri_for_all.id,
+ zg : pc.zlevel.1,
op : update,
});
#[derive(Debug,Serialize,Deserialize)]
struct ApiPieceRaise {
+ z : ZCoord,
}
#[post("/_/api/raise", format="json", data="<form>")]
#[throws(OE)]
_: &dyn Lens)
-> (PieceUpdateOp<()>, Vec<LogEntry>) {
let pc = gs.pieces.byid_mut(piece).unwrap();
- pc.raised = gs.gen;
- let update = PieceUpdateOp::Raise();
+ pc.zlevel = (self.z, gs.gen);
+ let update = PieceUpdateOp::SetZLevel(pc.zlevel);
(update, vec![])
}
}
NoClient,
#[error("player not part of game (removed?)")]
NoPlayer,
+ #[error("invalid Z coordinate")]
+ InvalidZCoord,
}
pub use OnlineError::{NoClient,NoPlayer};
fn describe_html(&self, face : Option<FaceId>) -> String;
}
+#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
+#[derive(Serialize,Deserialize)]
+#[serde(into="f64")]
+#[serde(try_from="f64")]
+pub struct ZCoord(f64);
+impl TryFrom<f64> for ZCoord {
+ type Error = OnlineError;
+ #[throws(OnlineError)]
+ fn try_from(v: f64) -> ZCoord {
+ if !v.is_finite() { Err(OnlineError::InvalidZCoord)? }
+ ZCoord(v)
+ }
+}
+impl From<ZCoord> for f64 {
+ fn from(v: ZCoord) -> f64 { v.0 }
+}
+impl Ord for ZCoord {
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ self.0.partial_cmp(&other.0).unwrap()
+ }
+}
+impl Eq for ZCoord { }
+
#[derive(Debug)]
pub struct PieceRecord {
pub pos : Pos,
pub p : Box<dyn Piece>,
pub face : FaceId,
pub held : Option<PlayerId>,
- pub raised : Generation,
+ pub zlevel : (ZCoord,Generation),
pub gen : Generation,
pub lastclient : ClientId,
pub gen_before_lastclient : Generation,
face : 0.into(),
held : None,
lastclient : Default::default(),
- raised: Generation(0),
+ zlevel : (0f64 .try_into().unwrap(), Generation(0)),
gen,
gen_before_lastclient : Generation(0),
};
sameclient_cseq : ClientSequence,
piece : VisiblePieceId,
op : PieceUpdateOp<PreparedPieceState>,
+ zg : Generation,
},
Log (Arc<LogEntry>),
}
Insert(NS),
Modify(NS),
Move(Pos),
- Raise(),
+ SetZLevel((ZCoord, Generation)),
}
impl<NS> PieceUpdateOp<NS> {
pub fn new_state(&self) -> Option<&NS> {
Insert(ns) => Some(ns),
Modify(ns) => Some(ns),
Move(_) => None,
- Raise() => None,
+ SetZLevel(_) => None,
}
}
pub fn map_new_state<NS2,F: FnOnce(NS) -> NS2>(self, f:F)
Insert(ns) => Insert(f(ns)),
Modify(ns) => Modify(f(ns)),
Move(pos) => Move(pos),
- Raise() => Raise(),
+ SetZLevel(zl) => SetZLevel(zl),
}
}
}
let status = match self {
GameCorrupted => Status::InternalServerError,
NoClient | NoPlayer => Status::NotFound,
+ InvalidZCoord => Status::BadRequest,
};
let mut resp = Responder::respond_to(msg,req).unwrap();
resp.set_status(status);
pub use std::sync::{Arc,Mutex,RwLock,Condvar};
pub use std::collections::HashMap;
pub use std::borrow::Borrow;
-pub use std::convert::TryFrom;
+pub use std::convert::{TryFrom,TryInto};
pub use std::str;
pub use std::str::FromStr;
pub use std::iter;
pub use std::iter::repeat_with;
pub use std::collections::VecDeque;
pub use std::num::Wrapping;
-
+pub use std::cmp;
+
pub use thiserror::Error;
pub use anyhow::{Context,anyhow};
pub use fehler::{throws,throw};
Recorded {
piece : VisiblePieceId,
cseq : ClientSequence,
+ zg : Generation,
},
Piece {
piece : VisiblePieceId,
for u in &next.us {
let tu = match u {
&PreparedUpdateEntry::Piece
- { piece, client, sameclient_cseq : cseq, .. }
+ { piece, client, sameclient_cseq : cseq, zg, .. }
if client== self.client => {
- TransmitUpdate::Recorded { piece, cseq }
+ TransmitUpdate::Recorded { piece, cseq, zg }
},
&PreparedUpdateEntry::Piece { piece, ref op, .. } => {
TransmitUpdate::Piece { piece, op }