overlord_event_system/
lib.rs

1pub use behaviors::BehaviorRegistry;
2pub use event_system::event::LogicalTimestamp;
3pub use event_system::net;
4pub use event_system::net::EventTimestamped;
5pub use event_system::random::Seed;
6/// Re-exported so callers of `cases::try_finalize_item` can supply its RNG
7/// without depending on `event_system` directly.
8pub use event_system::script::random::GameRng;
9pub use event_system::script::types::ConditionalProgress;
10pub use event_system::system::{
11    EventHandleResult, EventHandler, EventHandlerContext, EventMeta, SystemConfig,
12};
13
14use event_system::event::EventPluginized;
15use rand::SeedableRng;
16
17pub mod attributes;
18pub mod behaviors;
19pub mod bundles;
20pub mod cases;
21pub mod entities;
22pub mod event;
23pub mod fight;
24pub mod gacha;
25pub mod game_config_helpers;
26pub mod logic;
27pub mod mechanics;
28pub mod party;
29pub mod quests;
30pub mod state;
31
32/// DB-free handler over the pure game logic. Routes every event to
33/// `OverlordLogic`; used by tests and simulations through the synchronous
34/// `System::run`.
35pub struct PureEventHandler {
36    logic: logic::handler::OverlordLogic,
37}
38
39impl PureEventHandler {
40    pub fn new(logic: logic::handler::OverlordLogic) -> Self {
41        Self { logic }
42    }
43
44    /// The logic this handler drives — so a caller can arm the fight seed of a
45    /// precalculated PvP fight before replaying it (see
46    /// `OverlordLogic::arm_fight_seed`).
47    pub fn logic_mut(&mut self) -> &mut logic::handler::OverlordLogic {
48        &mut self.logic
49    }
50}
51
52impl EventHandler<event::OverlordEvent, state::OverlordState> for PureEventHandler {
53    type Context = ();
54
55    async fn create_context_for_batch(
56        &self,
57        _state: &state::OverlordState,
58    ) -> anyhow::Result<Self::Context> {
59        Ok(())
60    }
61
62    async fn handle_event(
63        &mut self,
64        _ctx: &Self::Context,
65        event: &event::OverlordEvent,
66        meta: EventMeta,
67        prev_state: &state::OverlordState,
68        state: state::OverlordState,
69    ) -> anyhow::Result<EventHandleResult<event::OverlordEvent, state::OverlordState>> {
70        // Historical async RNG stream: `with_ts` of the pre-increment
71        // timestamp. Former-sync bodies use `with_ts(logical_ts)`; the
72        // asymmetry is historical and may be unified later as an isolated
73        // change with deliberate test-expectation updates.
74        let rand_gen =
75            rand::rngs::StdRng::seed_from_u64(meta.session_seed.with_ts(meta.logical_ts - 1));
76        let mut result = self
77            .logic
78            .handle_event(event, state, rand_gen, meta.current_tick);
79
80        if *result.state() != *prev_state {
81            let (new_state, result_events) = result.state_and_events_mut();
82            let mut events: Vec<EventPluginized<event::OverlordEvent, state::OverlordState>> = self
83                .logic
84                .compute_fields(new_state, prev_state)
85                .into_iter()
86                .map(EventPluginized::now)
87                .collect();
88            events.append(result_events);
89            *result_events = events;
90        }
91
92        Ok(result)
93    }
94
95    fn compute_fields(
96        &self,
97        state: &mut state::OverlordState,
98        prev_state: &state::OverlordState,
99    ) -> Vec<event::OverlordEvent> {
100        self.logic.compute_fields(state, prev_state)
101    }
102
103    fn collect_due_scheduled(&mut self, current_tick: u64) -> Vec<event::OverlordEvent> {
104        self.logic.collect_due_scheduled(current_tick)
105    }
106
107    async fn finalize_state(
108        &self,
109        _ctx: &Self::Context,
110        _state: &mut state::OverlordState,
111    ) -> anyhow::Result<()> {
112        Ok(())
113    }
114
115    async fn persist_in_memory_state(
116        &self,
117        _ctx: &Self::Context,
118        _state: &state::OverlordState,
119    ) -> anyhow::Result<()> {
120        Ok(())
121    }
122}
123
124pub type System<H> = event_system::system::System<
125    event::OverlordEvent,
126    state::OverlordState,
127    H,
128    event_system::plugin::delayed::RealDelayedPlugin<event::OverlordEvent>,
129    event_system::plugin::cron::RealCronPlugin<event::OverlordEvent, state::OverlordState>,
130>;
131
132pub const TICKER_UNIT_DURATION_MS: u128 = 1;
133
134pub fn new_system<H>(handler: H, session_seed: Seed, zero_tick: bool) -> System<H>
135where
136    H: EventHandler<event::OverlordEvent, state::OverlordState>,
137{
138    System::new(
139        SystemConfig {
140            ticker_unit_duration_ms: if zero_tick {
141                0
142            } else {
143                TICKER_UNIT_DURATION_MS
144            },
145            ..Default::default()
146        },
147        handler,
148        state::OverlordState::default(),
149        session_seed,
150    )
151}