feat(replay): ✨ Add Godot engine replay extensions and enhance event handling for replay processing
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
39aa1f25e2
commit
e55e8c5ec6
2 changed files with 199 additions and 0 deletions
|
|
@ -302,6 +302,66 @@ fn event_to_dict(evt: &TurnEvent) -> Dictionary {
|
|||
d.set("party_a", parties[0].0 as i64);
|
||||
d.set("party_b", parties[1].0 as i64);
|
||||
}
|
||||
TurnEvent::EnvelopeDispatched {
|
||||
turn,
|
||||
envelope_id,
|
||||
sender,
|
||||
recipient,
|
||||
payload_kind,
|
||||
eta_turn,
|
||||
} => {
|
||||
d.set("kind", GString::from("EnvelopeDispatched"));
|
||||
d.set("turn", *turn as i64);
|
||||
d.set("envelope_id", *envelope_id as i64);
|
||||
d.set("sender", sender.0 as i64);
|
||||
d.set("recipient", recipient.0 as i64);
|
||||
d.set("payload_kind", GString::from(payload_kind.as_str()));
|
||||
d.set("eta_turn", *eta_turn as i64);
|
||||
}
|
||||
TurnEvent::EnvelopeDelivered {
|
||||
turn,
|
||||
envelope_id,
|
||||
sender,
|
||||
recipient,
|
||||
payload_kind,
|
||||
} => {
|
||||
d.set("kind", GString::from("EnvelopeDelivered"));
|
||||
d.set("turn", *turn as i64);
|
||||
d.set("envelope_id", *envelope_id as i64);
|
||||
d.set("sender", sender.0 as i64);
|
||||
d.set("recipient", recipient.0 as i64);
|
||||
d.set("payload_kind", GString::from(payload_kind.as_str()));
|
||||
}
|
||||
TurnEvent::EnvelopeIntercepted {
|
||||
turn,
|
||||
envelope_id,
|
||||
sender,
|
||||
recipient,
|
||||
payload_kind,
|
||||
reason,
|
||||
} => {
|
||||
d.set("kind", GString::from("EnvelopeIntercepted"));
|
||||
d.set("turn", *turn as i64);
|
||||
d.set("envelope_id", *envelope_id as i64);
|
||||
d.set("sender", sender.0 as i64);
|
||||
d.set("recipient", recipient.0 as i64);
|
||||
d.set("payload_kind", GString::from(payload_kind.as_str()));
|
||||
d.set("reason", GString::from(reason.as_str()));
|
||||
}
|
||||
TurnEvent::LinkSevered { turn, player_a, player_b, tile } => {
|
||||
d.set("kind", GString::from("LinkSevered"));
|
||||
d.set("turn", *turn as i64);
|
||||
d.set("player_a", player_a.0 as i64);
|
||||
d.set("player_b", player_b.0 as i64);
|
||||
d.set("col", tile.q as i64);
|
||||
d.set("row", tile.r as i64);
|
||||
}
|
||||
TurnEvent::LinkRestored { turn, player_a, player_b } => {
|
||||
d.set("kind", GString::from("LinkRestored"));
|
||||
d.set("turn", *turn as i64);
|
||||
d.set("player_a", player_a.0 as i64);
|
||||
d.set("player_b", player_b.0 as i64);
|
||||
}
|
||||
}
|
||||
d
|
||||
}
|
||||
|
|
|
|||
|
|
@ -380,6 +380,80 @@ pub enum TurnEvent {
|
|||
/// The two parties to the share, in canonical (min, max) order.
|
||||
parties: [ClanId; 2],
|
||||
},
|
||||
/// Communications Phase 6 — envelope-flow: a new envelope was
|
||||
/// dispatched. Fires from `mc_player_api::comms_dispatch::
|
||||
/// dispatch_envelope` at the moment of allocation.
|
||||
EnvelopeDispatched {
|
||||
/// Turn the event fired on.
|
||||
turn: u32,
|
||||
/// Stable envelope id.
|
||||
envelope_id: u32,
|
||||
/// Sender player slot.
|
||||
sender: ClanId,
|
||||
/// Recipient player slot.
|
||||
recipient: ClanId,
|
||||
/// Stable payload kind string.
|
||||
payload_kind: String,
|
||||
/// Turn the envelope is expected to arrive.
|
||||
eta_turn: u32,
|
||||
},
|
||||
/// Communications Phase 6 — envelope-flow: an envelope arrived
|
||||
/// intact at its recipient and the payload's delivery effect
|
||||
/// applied. Fires from `step_comms`.
|
||||
EnvelopeDelivered {
|
||||
/// Turn the event fired on.
|
||||
turn: u32,
|
||||
/// Stable envelope id.
|
||||
envelope_id: u32,
|
||||
/// Sender player slot.
|
||||
sender: ClanId,
|
||||
/// Recipient player slot.
|
||||
recipient: ClanId,
|
||||
/// Stable payload kind string.
|
||||
payload_kind: String,
|
||||
},
|
||||
/// Communications Phase 6 — envelope-flow: an envelope failed to
|
||||
/// arrive (route severed, capital lost, courier killed). Distinct
|
||||
/// from `EnvelopeTapped`, which is read-but-still-delivered.
|
||||
EnvelopeIntercepted {
|
||||
/// Turn the event fired on.
|
||||
turn: u32,
|
||||
/// Stable envelope id.
|
||||
envelope_id: u32,
|
||||
/// Sender player slot.
|
||||
sender: ClanId,
|
||||
/// Recipient player slot.
|
||||
recipient: ClanId,
|
||||
/// Stable payload kind string.
|
||||
payload_kind: String,
|
||||
/// Stable discard-reason string: `"path_severed"`,
|
||||
/// `"capital_lost"`, `"courier_killed"`.
|
||||
reason: String,
|
||||
},
|
||||
/// Communications Phase 6 — link-flow: a courier link between
|
||||
/// `player_a` and `player_b` was severed (pillage of a wire,
|
||||
/// blackout, courier killed) at `tile`.
|
||||
LinkSevered {
|
||||
/// Turn the event fired on.
|
||||
turn: u32,
|
||||
/// First party (canonical min slot).
|
||||
player_a: ClanId,
|
||||
/// Second party (canonical max slot).
|
||||
player_b: ClanId,
|
||||
/// Hex where the severance occurred.
|
||||
tile: TileCoord,
|
||||
},
|
||||
/// Communications Phase 6 — link-flow: a previously-severed link
|
||||
/// between `player_a` and `player_b` was restored (wire rebuilt,
|
||||
/// new route established, blackout ended).
|
||||
LinkRestored {
|
||||
/// Turn the event fired on.
|
||||
turn: u32,
|
||||
/// First party (canonical min slot).
|
||||
player_a: ClanId,
|
||||
/// Second party (canonical max slot).
|
||||
player_b: ClanId,
|
||||
},
|
||||
/// p2-48: the game has ended. Emitted at most once per game, at the tail
|
||||
/// of `TurnProcessor::step` when `end_conditions::evaluate_conditions`
|
||||
/// returns `Some`.
|
||||
|
|
@ -445,6 +519,11 @@ impl TurnEvent {
|
|||
| Self::HeartbeatMissed { turn, .. }
|
||||
| Self::VisionShareCollapsed { turn, .. }
|
||||
| Self::VisionShareRestored { turn, .. }
|
||||
| Self::EnvelopeDispatched { turn, .. }
|
||||
| Self::EnvelopeDelivered { turn, .. }
|
||||
| Self::EnvelopeIntercepted { turn, .. }
|
||||
| Self::LinkSevered { turn, .. }
|
||||
| Self::LinkRestored { turn, .. }
|
||||
| Self::GameOver { turn, .. } => turn,
|
||||
}
|
||||
}
|
||||
|
|
@ -694,4 +773,64 @@ mod tests {
|
|||
bincode::serde::decode_from_slice(&bytes, cfg).expect("decode");
|
||||
assert_eq!(decoded, events);
|
||||
}
|
||||
|
||||
/// Communications Phase 6: verify the five envelope-flow + link-flow
|
||||
/// event variants round-trip through serde (JSON + bincode) and
|
||||
/// `turn()` returns the correct value for each.
|
||||
#[test]
|
||||
fn link_severed_restored_round_trip() {
|
||||
let dispatched = TurnEvent::EnvelopeDispatched {
|
||||
turn: 5,
|
||||
envelope_id: 11,
|
||||
sender: ClanId(0),
|
||||
recipient: ClanId(1),
|
||||
payload_kind: "war_declaration".into(),
|
||||
eta_turn: 12,
|
||||
};
|
||||
let delivered = TurnEvent::EnvelopeDelivered {
|
||||
turn: 12,
|
||||
envelope_id: 11,
|
||||
sender: ClanId(0),
|
||||
recipient: ClanId(1),
|
||||
payload_kind: "war_declaration".into(),
|
||||
};
|
||||
let intercepted = TurnEvent::EnvelopeIntercepted {
|
||||
turn: 7,
|
||||
envelope_id: 12,
|
||||
sender: ClanId(0),
|
||||
recipient: ClanId(2),
|
||||
payload_kind: "treaty_offer".into(),
|
||||
reason: "path_severed".into(),
|
||||
};
|
||||
let severed = TurnEvent::LinkSevered {
|
||||
turn: 7,
|
||||
player_a: ClanId(0),
|
||||
player_b: ClanId(1),
|
||||
tile: TileCoord::new(3, 4),
|
||||
};
|
||||
let restored = TurnEvent::LinkRestored {
|
||||
turn: 14,
|
||||
player_a: ClanId(0),
|
||||
player_b: ClanId(1),
|
||||
};
|
||||
|
||||
assert_eq!(dispatched.turn(), 5);
|
||||
assert_eq!(delivered.turn(), 12);
|
||||
assert_eq!(intercepted.turn(), 7);
|
||||
assert_eq!(severed.turn(), 7);
|
||||
assert_eq!(restored.turn(), 14);
|
||||
|
||||
let events = vec![dispatched, delivered, intercepted, severed, restored];
|
||||
for ev in &events {
|
||||
let json = serde_json::to_string(ev).expect("serialize");
|
||||
let back: TurnEvent = serde_json::from_str(&json).expect("deserialize");
|
||||
assert_eq!(&back, ev);
|
||||
}
|
||||
|
||||
let cfg = bincode::config::standard();
|
||||
let bytes = bincode::serde::encode_to_vec(&events, cfg).expect("encode");
|
||||
let (decoded, _): (Vec<TurnEvent>, usize) =
|
||||
bincode::serde::decode_from_slice(&bytes, cfg).expect("decode");
|
||||
assert_eq!(decoded, events);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue