chiark / gitweb /
multigrab: Set the z coordinate
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 30 Apr 2022 11:42:01 +0000 (12:42 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 30 Apr 2022 12:30:04 +0000 (13:30 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
daemon/api.rs
src/gamestate.rs
templates/script.ts

index 4a6f0eb343a97d4d9607245d21e3783728c6ed59..24c4f94f9607f4d839413c720b9bed0754d5d046 100644 (file)
@@ -569,6 +569,7 @@ api_route!{
 api_route!{
   api_multigrab, "/_/api/multigrab",
   struct ApiPieceMultigrab {
+    z: ZCoord,
     n: MultigrabQty,
   }
 
@@ -581,7 +582,15 @@ api_route!{
       let y = pri.fully_visible().ok_or(Ia::Occultation)?;
       let gpc = a.gs.pieces.byid_mut(a.piece)?;
       if gpc.held != None { throw!(Ia::PieceHeld) }
-      a.ipc.show(y).op_multigrab(a, pri, self.n)?
+      if ! (self.z > gpc.zlevel.z) { throw!(Ia::BadPieceStateForOperation); }
+      op_do_set_z(gpc, a.gs.gen, &self.z)?;
+      a.ipc.show(y).op_multigrab(a, pri, self.n, &self.z).map_err(|e| match e {
+        // TODO: The error handling is wrong, here.  If op_multigrab
+        // returns a deferred thunk, the APOE::PartiallyProcessed will
+        // not be applked.
+        APOE::Inapplicable(ia) => APOE::PartiallyProcessed(ia, vec![]),
+        other => other,
+      })?
     }
   }
 }
index 0e6f8751f65cea9ad3a3344521cf663f99ee11f8..4caeddeca62b8c5c937b613ede1ef9c4eb0a34cf 100644 (file)
@@ -245,8 +245,31 @@ pub trait PieceTrait: PieceBaseTrait + Send + Debug + 'static {
     default()
   }
 
+  // This is going to have to set the Z coordinate.  This is because
+  // when we split a banknote, the note the user grabbed must end up
+  // above the "change", the "new" note which remains.  So we need to
+  // select Z coordinates.
+  //
+  // We *could* solve this by simply giving the two pieces different Z
+  // generations, but the same ZCoord, but this is quite undesirable
+  // because it can lead to the client having to do piece restacking.
+  //
+  // We can't readily find a suitable Z ZCoord for the change (ie, the
+  // lower coordinate), because that's piece lowering which is very
+  // complicated, because it may have to restack due to clashing
+  // ZCoords.  (We have that in JS in the client.)
+  //
+  // So we want to set the ZCoord of the piece the client has just
+  // grasped.  We don't want to disrupt the client's drag operation,
+  // so we don't want to change anything server-side that's subject to
+  // the update concurrency protocool.  Or to put it another way,
+  // the ZCoord must be predictable (and predicted) by the client.
+  // And the client can easily select a suitable ZCoord: the top
+  // one will do.
+  //
+  // So the multigrab operation specifies a ZCoord.
   fn op_multigrab(&self, _a: ApiPieceOpArgs, _pri: PieceRenderInstructions,
-                  _qty: MultigrabQty)
+                  _qty: MultigrabQty, _new_z: &ZCoord)
                   -> Result<OpOutcomeThunk,ApiPieceOpError>  {
     Err(Ia::BadPieceStateForOperation)?
   }
index 771443ccc1ae32052ec04a34db70879542742637..1edca6e40283f027bf154c6ec80dfd00a28ab052 100644 (file)
@@ -994,8 +994,10 @@ function grab_clicked(clicked: PieceId[], loose: boolean,
       api_piece_x(api_immediate, loose,
                  wresting ? 'wrest' : 'grab', piece,p, { });
     } else {
-      api_piece_x(api_immediate, loose, 'multigrab',
-                 piece,p, { n: multigrab });
+      piece_raise(piece,p, 'Raised', function(piece,p,z) {
+       api_piece_x(api_immediate, loose, 'multigrab',
+                   piece,p, { n: multigrab, z: z });
+      })
     }
   }
 }