Skip to main content

wowlab_engine_application/simulate_intent/
handler.rs

1use wowlab_engine_ports::{
2    ContentCatalog, DynDataResolver, EngineError, HandlerParams, SpecHandler,
3};
4use wowlab_types::constants::DEFAULT_DURATION_S;
5
6use super::setup::{ResolvedSetup, resolve_setup};
7use crate::{
8    error::{ApplicationError, ApplicationStage, EngineResultExt as _},
9    intent_builder::IntentOverrides,
10    resolved_handler::ResolvedHandler,
11};
12
13pub(super) struct BootstrapResult {
14    pub handler: ResolvedHandler,
15    pub duration_s: f64,
16}
17
18/// Build a fresh handler from previously resolved setup inputs.
19pub fn build_handler_from_setup(
20    setup: &ResolvedSetup,
21) -> Result<ResolvedHandler, ApplicationError> {
22    let handler = (setup.descriptor.handler_factory)(
23        HandlerParams {
24            game_data: setup.game_data.clone(),
25            rotation: &setup.rotation,
26            stats: &setup.stats,
27            talent_selections: &setup.talent_selections,
28            encounter: &setup.encounter,
29            fight_duration_secs: setup.encounter.fight_duration_secs(),
30            equipped_items: &setup.equipped_items,
31            set_bonus_auras: &setup.set_bonus_auras,
32            bloodlust: setup.consumables.bloodlust,
33            pre_pot_tempered: setup.consumables.pre_pot_tempered,
34            flask: setup.consumables.flask,
35            augment_rune: setup.consumables.augment_rune,
36            race: setup.race,
37            weapon_enchant_procs: &setup.weapon_enchant_procs,
38            bugs: setup.bugs.clone(),
39            cast_latency: setup.cast_latency,
40            raid_events: &setup.raid_events,
41            external_buffs: &setup.external_buffs,
42        }
43        .validate()
44        .in_application_stage(ApplicationStage::HandlerConstruction)?,
45    )
46    .in_application_stage(ApplicationStage::HandlerConstruction)?;
47
48    Ok(ResolvedHandler::from_boxed(handler))
49}
50
51pub(super) async fn bootstrap(
52    catalog: &ContentCatalog,
53    sim_config: &str,
54    resolver: &DynDataResolver<'_>,
55    overrides: &IntentOverrides,
56) -> Result<BootstrapResult, ApplicationError> {
57    let setup = resolve_setup(catalog, sim_config, resolver, overrides).await?;
58    let duration_s = setup.duration_s;
59    let handler = build_handler_from_setup(&setup)?;
60
61    Ok(BootstrapResult {
62        handler,
63        duration_s,
64    })
65}
66
67pub(crate) fn run_on_sim_start(handler: &mut dyn SpecHandler) {
68    let sim_state = wowlab_engine_ports::SimState::new(
69        0,
70        wowlab_types::sim::SimTime::from_secs(wowlab_types::numeric::f64_to_u32_saturating_round(
71            DEFAULT_DURATION_S,
72        )),
73        0,
74    );
75    let mut sink = wowlab_engine_telemetry::TelemetrySink::new();
76    let mut ctx = wowlab_engine_ports::SimContext {
77        state: &sim_state,
78        telemetry: &mut sink,
79    };
80
81    handler.on_sim_start(&mut ctx);
82}
83
84/// Build a handler from a sim config without running iterations; runs `on_sim_start`.
85pub async fn build_handler(
86    catalog: &ContentCatalog,
87    sim_config: &str,
88    resolver: &DynDataResolver<'_>,
89) -> Result<ResolvedHandler, ApplicationError> {
90    let mut handler = bootstrap(
91        catalog,
92        sim_config,
93        resolver,
94        &IntentOverrides {
95            skip_rotation: true,
96            ..Default::default()
97        },
98    )
99    .await?
100    .handler;
101
102    run_on_sim_start(handler.handler_mut());
103
104    Ok(handler)
105}
106
107pub(super) fn handler_factory(
108    handler: ResolvedHandler,
109) -> impl Fn() -> Result<ResolvedHandler, ApplicationError> {
110    let cell = std::cell::Cell::new(Some(handler));
111
112    move || {
113        cell.take().ok_or_else(|| {
114            ApplicationError::from_engine(
115                ApplicationStage::HandlerConstruction,
116                EngineError::spec_construction("handler factory called more than once"),
117            )
118        })
119    }
120}