feat(mc-player-api): ✨ Introduce message types and dispatch logic for player API communication
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
7d4f3ba480
commit
69133d5a4e
3 changed files with 61 additions and 6 deletions
|
|
@ -81,6 +81,15 @@ pub struct CommsState {
|
|||
/// map each turn.
|
||||
#[serde(default)]
|
||||
pub vision_shares: BTreeMap<u64, crate::heartbeat::VisionShareLink>,
|
||||
/// Phase 6 — side-channel buffer for chronicle events emitted from
|
||||
/// non-end-of-turn paths (e.g. `PlayerAction::NameSeatOfPower`).
|
||||
/// Drained by `mc-player-api`'s end-of-turn pass into the replay
|
||||
/// archive. Skipped by serde — never persists across saves; if a
|
||||
/// save is taken mid-turn the events will be re-emitted on resume.
|
||||
/// Carries serde-encoded `mc_replay::TurnEvent` strings to avoid a
|
||||
/// reverse mc-comms → mc-replay dep.
|
||||
#[serde(skip)]
|
||||
pub pending_chronicle_json: Vec<String>,
|
||||
}
|
||||
|
||||
impl CommsState {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,22 @@ const DEFAULT_COURIER_ERA_TIER: u8 = 2;
|
|||
pub fn dispatch_war_declaration(state: &mut GameState, sender: PlayerId, target: PlayerId) {
|
||||
let mut sink: Vec<TurnEvent> = Vec::new();
|
||||
dispatch_war_declaration_with_events(state, sender, target, &mut sink);
|
||||
// Phase 6 — flush dispatched-event into the side-channel so
|
||||
// production action handlers (PlayerAction::DeclareWar via
|
||||
// `apply_declare_war`) surface the event without threading a vec
|
||||
// through `apply_action`'s wire-event return type.
|
||||
flush_to_pending_chronicle(&mut state.comms, sink);
|
||||
}
|
||||
|
||||
/// Phase 6 — serialise a batch of `TurnEvent`s into
|
||||
/// `CommsState.pending_chronicle_json`. Drained by
|
||||
/// `run_end_of_turn_comms_passes` at the next end-of-turn pass.
|
||||
fn flush_to_pending_chronicle(comms: &mut mc_comms::CommsState, events: Vec<TurnEvent>) {
|
||||
for ev in events {
|
||||
if let Ok(json) = serde_json::to_string(&ev) {
|
||||
comms.pending_chronicle_json.push(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like [`dispatch_war_declaration`] but appends an
|
||||
|
|
@ -87,6 +103,7 @@ pub fn dispatch_war_declaration_with_events(
|
|||
pub fn dispatch_peace_proposal(state: &mut GameState, sender: PlayerId, target: PlayerId) {
|
||||
let mut sink: Vec<TurnEvent> = Vec::new();
|
||||
dispatch_peace_proposal_with_events(state, sender, target, &mut sink);
|
||||
flush_to_pending_chronicle(&mut state.comms, sink);
|
||||
}
|
||||
|
||||
/// Event-emitting variant of [`dispatch_peace_proposal`].
|
||||
|
|
@ -120,14 +137,17 @@ pub fn dispatch_treaty_offer(
|
|||
if (sender as usize) >= state.players.len() || (target as usize) >= state.players.len() {
|
||||
return;
|
||||
}
|
||||
dispatch_envelope(
|
||||
let mut sink: Vec<TurnEvent> = Vec::new();
|
||||
dispatch_envelope_with_events(
|
||||
state,
|
||||
sender,
|
||||
target,
|
||||
Payload::TreatyOffer {
|
||||
agreement_kind: agreement_kind.to_string(),
|
||||
},
|
||||
&mut sink,
|
||||
);
|
||||
flush_to_pending_chronicle(&mut state.comms, sink);
|
||||
}
|
||||
|
||||
/// Dispatch a treaty-accept envelope. The `agreement_kind` carries the
|
||||
|
|
@ -145,14 +165,17 @@ pub fn dispatch_treaty_accept(
|
|||
if (sender as usize) >= state.players.len() || (target as usize) >= state.players.len() {
|
||||
return;
|
||||
}
|
||||
dispatch_envelope(
|
||||
let mut sink: Vec<TurnEvent> = Vec::new();
|
||||
dispatch_envelope_with_events(
|
||||
state,
|
||||
sender,
|
||||
target,
|
||||
Payload::TreatyAccept {
|
||||
agreement_kind: agreement_kind.to_string(),
|
||||
},
|
||||
&mut sink,
|
||||
);
|
||||
flush_to_pending_chronicle(&mut state.comms, sink);
|
||||
}
|
||||
|
||||
/// Dispatch a treaty-decline envelope.
|
||||
|
|
@ -168,14 +191,17 @@ pub fn dispatch_treaty_decline(
|
|||
if (sender as usize) >= state.players.len() || (target as usize) >= state.players.len() {
|
||||
return;
|
||||
}
|
||||
dispatch_envelope(
|
||||
let mut sink: Vec<TurnEvent> = Vec::new();
|
||||
dispatch_envelope_with_events(
|
||||
state,
|
||||
sender,
|
||||
target,
|
||||
Payload::TreatyDecline {
|
||||
agreement_kind: agreement_kind.to_string(),
|
||||
},
|
||||
&mut sink,
|
||||
);
|
||||
flush_to_pending_chronicle(&mut state.comms, sink);
|
||||
}
|
||||
|
||||
/// Allocate + populate + stash a generic envelope. Shared by every
|
||||
|
|
|
|||
|
|
@ -314,9 +314,20 @@ fn apply_name_seat_of_power(
|
|||
let pos = player_state.city_positions[idx];
|
||||
player_state.capital_position = Some(pos);
|
||||
let _ = mc_comms::blackout::end_blackout(&mut state.comms, player);
|
||||
// No wire-event counterpart for `CapitalBlackoutEnded` yet, but the
|
||||
// replay archive consumer reads it via the side-channel like the
|
||||
// other Phase 3 events.
|
||||
// Phase 6 — emit `CapitalBlackoutEnded` into the side-channel
|
||||
// `pending_chronicle_json` buffer on `CommsState`. The next
|
||||
// `run_end_of_turn_comms_passes` drains it into the replay
|
||||
// archive. Stored as a JSON string so this crate (mc-player-api)
|
||||
// doesn't need to thread a TurnEvent vector across the `apply_action`
|
||||
// return type (which returns wire `Event`s, not chronicle ones).
|
||||
let ended_event = mc_replay::TurnEvent::CapitalBlackoutEnded {
|
||||
turn: state.turn,
|
||||
player: mc_replay::ClanId(player as u32),
|
||||
new_capital_city_id: mc_replay::CityName(city_id.to_string()),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&ended_event) {
|
||||
state.comms.pending_chronicle_json.push(json);
|
||||
}
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
|
|
@ -441,6 +452,15 @@ pub(crate) fn run_end_of_turn_comms_passes(
|
|||
let mut events: Vec<mc_replay::TurnEvent> = Vec::new();
|
||||
let turn_now = state.turn;
|
||||
|
||||
// 0. Drain the side-channel chronicle buffer (events emitted from
|
||||
// non-end-of-turn paths such as `PlayerAction::NameSeatOfPower`).
|
||||
let pending: Vec<String> = std::mem::take(&mut state.comms.pending_chronicle_json);
|
||||
for json in pending {
|
||||
if let Ok(ev) = serde_json::from_str::<mc_replay::TurnEvent>(&json) {
|
||||
events.push(ev);
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Drive envelopes through delivery / interception.
|
||||
let _ = crate::comms_dispatch::step_comms_with_events(state, &mut events);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue