refactor(mc-state): 🏗️ Phase 3b — move GameState into mc-state behind a shim
p2-65 foundation milestone. `game_state.rs` (1356 lines: GameState +
PlayerState + MapUnit + TechState + PendingCaptureEvents + 8 action-request
structs + RallyCommand/BuildingRallyPoint/CityEcology + custom serde helpers)
relocated from mc-turn to mc-state. Decouples the canonical full-simulation
state shape from the turn-step mutation logic (Rail 1 cleanup).
- `git mv mc-turn/src/game_state.rs → mc-state/src/game_state.rs`; mc-turn's
`game_state.rs` is now `pub use mc_state::game_state::*;` so all ~30 consumer
sites (mc-ai, mc-player-api, mc-mod-host, api-gdext, mc-sim, mc-replay) +
mc-turn's lib.rs `pub use game_state::{GameState,…}` re-export resolve
unchanged for one cycle (Phase 4 sweeps them).
- Re-paths inside the moved file: `crate::combat_balance::CombatBalance` →
`mc_core::CombatBalance` (the only non-sibling code ref); the 5
sibling-module field types (ransom/capture/patrol/combat_event) resolve as
`crate::` since they're now co-located in mc-state. Broken `[crate::…]`
intra-doc links demoted to plain `mc_turn::…` backtick prose.
- `PendingCaptureEvents::drain_into` peeled off into the mc-turn-local
`DrainCaptureEvents` extension trait (`capture_drain.rs`): it embeds
`mc_replay::TurnEvent` + `mc_turn::combat_event::TurnResult`, neither movable
to the data crate without a cycle. Local-trait-for-foreign-type, orphan-rule
legal. 4 call sites (processor.rs + 3 tests) add the trait `use`.
SAVE-FORMAT GATE (the byte-identical proof): mc-turn serde_roundtrip 6/6 +
full_turn_golden 3/3 green — assembled GameState round-trips identically
post-move (serde shapes invariant; module paths were never on disk).
Parity (apricot): workspace --no-run exit 0; mc-state 12/12 (8 + the 4
game_state unit tests that moved with the file); mc-turn lib 234/234
(1 ignored, pre-existing — was 238 before the 4 moved out); mc-ai 268/268;
mc-player-api 126/126.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
45e9adea92
commit
0ed21945c1
8 changed files with 1404 additions and 1362 deletions
1294
src/simulator/crates/mc-state/src/game_state.rs
Normal file
1294
src/simulator/crates/mc-state/src/game_state.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,5 +17,6 @@
|
|||
|
||||
pub mod capture;
|
||||
pub mod combat_event;
|
||||
pub mod game_state;
|
||||
pub mod patrol;
|
||||
pub mod ransom;
|
||||
|
|
|
|||
89
src/simulator/crates/mc-turn/src/capture_drain.rs
Normal file
89
src/simulator/crates/mc-turn/src/capture_drain.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
//! Capture-event drain (p2-65 Phase 3b).
|
||||
//!
|
||||
//! `PendingCaptureEvents` is a data shape that lives in [`mc_state::game_state`],
|
||||
//! but draining it into a [`crate::combat_event::TurnResult`] is turn-step event
|
||||
//! translation: it builds `mc_replay::TurnEvent` variants and appends them to
|
||||
//! `result.events_emitted`. Both `TurnResult` and `mc_replay::TurnEvent` are
|
||||
//! `mc-turn` / replay shapes that cannot move into the data crate without a
|
||||
//! cycle, so this logic stays in `mc-turn` as an extension trait over the
|
||||
//! foreign `PendingCaptureEvents` type (local-trait-for-foreign-type — legal
|
||||
//! under the orphan rule because the trait is local).
|
||||
|
||||
use crate::combat_event::TurnResult;
|
||||
use mc_state::game_state::PendingCaptureEvents;
|
||||
|
||||
/// Drain staged capture/PvP events into the turn's `TurnResult`.
|
||||
pub trait DrainCaptureEvents {
|
||||
/// Move accumulated events into the supplied `TurnResult` and clear the
|
||||
/// scratch buffer. Called once per `process_pvp_combat`.
|
||||
///
|
||||
/// Also translates each p2-55 event into a `mc_replay::TurnEvent` variant
|
||||
/// and appends it to `result.events_emitted` so the chronicle pipeline
|
||||
/// picks them up without an extra pass.
|
||||
fn drain_into(&mut self, result: &mut TurnResult);
|
||||
}
|
||||
|
||||
impl DrainCaptureEvents for PendingCaptureEvents {
|
||||
fn drain_into(&mut self, result: &mut TurnResult) {
|
||||
// Emit replay variants before moving the vecs (we borrow from them).
|
||||
for ev in &self.units_captured {
|
||||
result.events_emitted.push(mc_replay::TurnEvent::UnitCaptured {
|
||||
turn: ev.turn,
|
||||
unit_id: ev.unit_id,
|
||||
captor: mc_replay::ClanId(ev.captor as u32),
|
||||
prior_owner: mc_replay::ClanId(ev.prior_owner as u32),
|
||||
hex: mc_replay::TileCoord::new(ev.col, ev.row),
|
||||
unit_kind: mc_replay::UnitKind(ev.unit_kind.clone()),
|
||||
});
|
||||
}
|
||||
for ev in &self.ransom_offers_created {
|
||||
result.events_emitted.push(mc_replay::TurnEvent::UnitRansomOffered {
|
||||
turn: ev.turn,
|
||||
offer_id: ev.offer_id,
|
||||
unit_id: ev.unit_id,
|
||||
captor: mc_replay::ClanId(ev.captor as u32),
|
||||
owner: mc_replay::ClanId(ev.owner as u32),
|
||||
price: ev.price,
|
||||
expires_turn: ev.expires_turn,
|
||||
});
|
||||
}
|
||||
for ev in &self.civilians_destroyed {
|
||||
result.events_emitted.push(mc_replay::TurnEvent::CivilianDestroyed {
|
||||
turn: ev.turn,
|
||||
unit_id: ev.unit_id,
|
||||
destroyer: mc_replay::ClanId(ev.destroyer as u32),
|
||||
owner: mc_replay::ClanId(ev.owner as u32),
|
||||
hex: mc_replay::TileCoord::new(ev.col, ev.row),
|
||||
unit_kind: mc_replay::UnitKind(ev.unit_kind.clone()),
|
||||
});
|
||||
}
|
||||
// p2-67 Bug 3: queued-PvP kill events were silent before this drain
|
||||
// existed — the inline `swap_remove` in `resolve_single_pvp_attack`
|
||||
// happened with no `TurnEvent::UnitKilled` push. Translate each
|
||||
// staged `UnitKilledEvent` to the chronicle variant now.
|
||||
for ev in &self.units_killed {
|
||||
result.events_emitted.push(mc_replay::TurnEvent::UnitKilled {
|
||||
turn: ev.turn,
|
||||
attacker: mc_replay::ClanId(ev.attacker as u32),
|
||||
defender: mc_replay::ClanId(ev.defender as u32),
|
||||
unit_id: ev.unit_id,
|
||||
unit_kind: mc_replay::UnitKind(ev.unit_kind.clone()),
|
||||
hex: mc_replay::TileCoord::new(ev.col, ev.row),
|
||||
});
|
||||
}
|
||||
// `units_killed` does not have a matching `TurnResult` Vec field —
|
||||
// the canonical surface is `events_emitted` above. Just clear.
|
||||
self.units_killed.clear();
|
||||
result.units_captured.append(&mut self.units_captured);
|
||||
result.ransom_offers_created.append(&mut self.ransom_offers_created);
|
||||
result.civilians_destroyed.append(&mut self.civilians_destroyed);
|
||||
// p2-55e: drain accepted/expired into TurnResult so chronicle reads
|
||||
// them directly without prior-turn cross-reference.
|
||||
result
|
||||
.ransom_offers_accepted
|
||||
.append(&mut self.ransom_offers_accepted);
|
||||
result
|
||||
.ransom_offers_expired
|
||||
.append(&mut self.ransom_offers_expired);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -21,6 +21,7 @@ pub mod abstract_projection;
|
|||
pub mod action;
|
||||
pub mod action_handlers;
|
||||
pub mod capture;
|
||||
pub mod capture_drain;
|
||||
pub mod combat_balance;
|
||||
pub mod ransom;
|
||||
pub mod building_action_handlers;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use crate::combat_event::{
|
|||
CivilianDestroyedEvent, FaunaCombatEvent, PvpCombatEvent, SiegeEvent, StrategicGateRejection,
|
||||
TurnResult, UnitCapturedEvent, UnitKilledEvent, UnitRansomOfferedEvent,
|
||||
};
|
||||
use crate::capture_drain::DrainCaptureEvents;
|
||||
use crate::game_state::{BuildingRallyPoint, GameState, MapUnit, RallyCommand};
|
||||
use crate::spatial_index::LairIndex;
|
||||
use mc_core::formation::{Formation, FormationShape};
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ use mc_ai::evaluator::ScoringWeights;
|
|||
use mc_city::CityState;
|
||||
use mc_replay::TurnEvent;
|
||||
use mc_turn::{
|
||||
capture_drain::DrainCaptureEvents,
|
||||
combat_event::{
|
||||
CivilianDestroyedEvent, TurnResult, UnitCapturedEvent,
|
||||
UnitRansomAcceptedEvent, UnitRansomExpiredEvent, UnitRansomOfferedEvent,
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ fn tick_drains_only_expired_leaves_others() {
|
|||
use mc_turn::combat_event::{
|
||||
UnitRansomAcceptedEvent, UnitRansomExpiredEvent,
|
||||
};
|
||||
use mc_turn::capture_drain::DrainCaptureEvents;
|
||||
use mc_turn::game_state::PendingCaptureEvents;
|
||||
use mc_turn::combat_event::TurnResult;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue