if let Some(gpc) = g.gs.pieces.get_mut(piece);
if gpc.held != was_held;
if let Some(ipc) = &g.ipieces.get(piece);
- if let Ok(unprepared) = ipc.direct_trait_access().held_change_hook(
+ let thunk = ipc.direct_trait_access().held_change_hook(
&iad.gref,
&mut g.gs.pieces,
piece,
was_held,
- ).map_err(|e| error!("internal error on change hook: {:?}", e));
+ );
+ let unprepared = match thunk {
+ Err(e) => Err(e),
+ Ok(OpHookThunk::Immediate(uu)) => Ok(uu),
+ Ok(OpHookThunk::Reborrow(f)) => f(&mut ig, player),
+ };
+ if let Ok(unprepared) = unprepared.map_err(
+ |e| error!("internal error on change hook: {:?}", e));
then {
PrepareUpdatesBuffer::only_unprepared(&mut ig, unprepared);
}
gpieces: &mut GPieces,
piece: PieceId,
was_held: Option<PlayerId>)
- -> UnpreparedUpdates {
+ -> OpHookThunk {
let gpc = gpieces.get_mut(piece);
let gpc = if let Some(gpc) = gpc { gpc } else { return default() };
let now_held = gpc.held;
state.do_start_or_stop(piece, was_current, was_running,
now_held, &self.spec, ig)?;
- unprepared_update(piece)
+ unprepared_update(piece).into()
}
#[throws(IE)]
gpieces: &mut GPieces,
piece: PieceId,
_was_held: Option<PlayerId>)
- -> UnpreparedUpdates {
+ -> OpHookThunk {
self.cooldown_cleanup_hook(gpieces, piece)?;
default()
}
_gpieces: &mut GPieces,
_piece: PieceId,
_was_held: Option<PlayerId>)
- -> Result<UnpreparedUpdates,IE> { Ok(default()) }
+ -> Result<OpHookThunk,IE> { Ok(default()) }
fn loaded_hook(&self, _piece: PieceId,
_gs: &mut GameState, _ig: &InstanceRef) -> Result<(),IE> {
-> Result<UpdateFromOpComplex, ApiPieceOpError>>),
}
+#[derive(From,Educe)]
+#[educe(Default)]
+pub enum OpHookThunk {
+ #[educe(Default)]
+ Immediate(UnpreparedUpdates),
+ /// Allows a UI operation full mutable access to the whole Instance.
+ ///
+ /// Use with care! Eg, you might have to call save_game_and_aux_late.r
+ ///
+ /// Adding and removing pieces during play (rather than management)
+ /// is complicated, because we want to avoid having to rewrite the aux.
+ /// file during routine game saves. `fastsplit.rs` has machinery that
+ /// can achieve this.
+ Reborrow(Box<dyn FnOnce(&mut InstanceGuard, PlayerId)
+ -> Result<UnpreparedUpdates, InternalError>>),
+}
+
pub type UpdateFromOpComplex = (
PieceUpdate,
UnpreparedUpdates,