chiark / gitweb /
wip update protocol
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 28 Jun 2020 19:04:07 +0000 (20:04 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 28 Jun 2020 19:04:07 +0000 (20:04 +0100)
junk/gamestate.rs
src/bin/server.rs
src/gamestate.rs
src/updates.rs [new file with mode: 0644]
templates/script.js

index 7c23ad3cba18bd8f9276a849b88f20ecab75f79f..ef9b21930f31444b7f24e5639297da5ea4f05c88 100644 (file)
@@ -9,13 +9,6 @@ impl Deref for GameRef {
   fn deref(&self) -> &GameState { self.0.read() }
 }
 
-enum GameUpdate {
-  NoUpdate,
-  PieceInsert(usize, PieceRecord),
-  PieceDelete(usize, PieceRecord),
-  PieceUpdate(usize, PieceRecord, PieceRecord),
-}
-
 struct LogMessage (HtmlString);
 
 impl PieceRecord {
index 4fcd6c845e7e48229aba91e61bab54dfe49010d6..9e6af503323c68e27f47c93a2a30c98ddc7877a1 100644 (file)
@@ -115,6 +115,7 @@ fn session(form : Json<SessionForm>) -> Result<Template,RE> {
 #[derive(Error,Debug)]
 #[error("operation error {:?}",self)]
 enum OpError {
+  Conflict,
   PieceGone,
   PieceHeld,
 }
@@ -122,18 +123,50 @@ enum OpError {
 #[derive(Debug,Serialize,Deserialize)]
 struct ApiGrab {
   t : String,
+  c : ClientId,
   p : VisiblePieceId,
+  g : Counter,
+  s : ClientSequence,
 }
 #[post("/_/api/grab", format="json", data="<form>")]
 #[throws(RE)]
 fn api_grab(form : Json<ApiGrab>) -> impl response::Responder<'static> {
   let iad = lookup_token(&form.t).ok_or_else(||anyhow!("unknown token"))?;
   let mut g = iad.i.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
+  let client = form.c;
   let r : Result<(),OpError> = (||{
     let p = decode_visible_pieceid(form.p);
-    let p = g.gs.pieces.get_mut(p).ok_or(OpError::PieceGone)?;
+    let gs = &mut g.gs;
+    let p = gs.pieces.get_mut(p).ok_or(OpError::PieceGone)?;
+    let q_gen = form.g;
+    let u_gen =
+      if client == p.lastclient { p.gen_lastclient }
+      else { p.gen_before_lastclient };
+    if p.gen > u_gen { Err(OpError::Conflict)? }
     if p.held != None { Err(OpError::PieceHeld)? };
     p.held = Some(iad.player);
+    gs.gen += 1;
+    let gen = gs.gen;
+    if client != p.lastclient {
+      p.gen_before_lastclient = p.gen_lastclient;
+      p.lastclient = client;
+    }
+    p.gen_lastclient = gen;
+    for (tplayer, tpl) in g.gs.players {
+      for (tclient, cl) in ig.clients.get(tplayer) {
+        if tclient == cl {
+          cl.transmit_update(client, Update {
+            gen,
+            u : GameUpdate::ClientSequence(form.s)
+          });
+        } else {
+          cl.transmit_update(client, Update {
+            gen,
+            u : GameUpdate::PieceUpdate(p, p.update()),
+          });
+        }          
+      }
+    }
     Ok(())
   })();
   eprintln!("API {:?} => {:?}", &form, &r);
index 7eca3e8e5c23f83b30ad9977ac7ed70e2cf95527..3d07b1c6a27ef8ca80d5b5f78b0ba027a05dba18 100644 (file)
@@ -48,6 +48,9 @@ pub struct PieceRecord {
   pub p : Box<dyn Piece>,
   pub face : FaceId,
   pub held : Option<PlayerId>,
+  pub lastclient : ClientId,
+  pub gen_lastclient : Counter,
+  pub gen_before_lastclient : Counter,
 }
 
 #[derive(Debug)]
@@ -69,6 +72,7 @@ pub fn xxx_gamestate_init() -> GameState {
       pos, p,
       face : 0.into(),
       held : None,
+      gen : 0,
     };
     pieces.insert(pr);
   }
diff --git a/src/updates.rs b/src/updates.rs
new file mode 100644 (file)
index 0000000..674ad79
--- /dev/null
@@ -0,0 +1,13 @@
+
+struct Update {
+  gen : Counter,
+  u : UpdatePayload,
+}
+
+enum UpdatePayload {
+  NoUpdate,
+  ClientSequence(ClientCounter),
+  PieceDelete(PieceId),
+  PieceInsert(PieceId, PieceUpdate),
+  PieceUpdate(PieceId, PieceUpdate),
+}
index 42e45568770f367f957d790ce3e0903968ad490a..6734939a624cad275259f86d2b894cbf19452a59 100644 (file)
@@ -8,6 +8,7 @@ var our_dnd_type = "text/puvnex-game-server-dummy";
 api_queue = [];
 api_posting = false;
 var us;
+var gen = 0;
 
 function xhr_post_then(url,data,good) {
   var xhr = new XMLHttpRequest();
@@ -95,6 +96,7 @@ function drag_mousedown(e) {
     set_grab(delt, us);
     api('grab', {
       t : token,
+      g : gen,
       p : delt.dataset.p,
     })
   }