wowlab_engine_combat/builder/
compile.rs1use wowlab_engine_domain::rotation::{
4 CatalogHints, DenseBuffer, RotationEngine, RuntimeBackend, SpecCatalog,
5};
6use wowlab_types::sim::{FastMap, Rotation};
7
8pub(crate) struct SpellGate {
10 pub(crate) spell_id: u32,
11 pub(crate) aura_id: u32,
12 pub(crate) min_stacks: u8,
13}
14
15pub(crate) struct CostBypass {
17 pub(crate) spell_id: u32,
18 pub(crate) aura_id: u32,
19}
20
21pub(crate) struct CooldownBypass {
23 pub(crate) spell_id: u32,
24 pub(crate) aura_id: u32,
25}
26
27pub(crate) struct SpellOverride {
28 pub(crate) spell_id: u32,
29 pub(crate) replacement_spell_id: u32,
30 pub(crate) aura_id: u32,
31 pub(crate) shares_base_cooldown: bool,
32}
33
34pub(crate) struct RotationCompileInput<'a> {
35 pub(crate) rotation: &'a Rotation,
36 pub(crate) spell_ids: &'a FastMap<String, u32>,
37 pub(crate) aura_ids: &'a FastMap<String, u32>,
38 pub(crate) secondary_resource_name: Option<&'a str>,
39 pub(crate) hints: &'a CatalogHints,
40 pub(crate) gating: &'a [SpellGate],
41 pub(crate) cost_bypass: &'a [CostBypass],
42 pub(crate) cooldown_bypass: &'a [CooldownBypass],
43 pub(crate) overrides: &'a [SpellOverride],
44}
45
46pub(crate) fn compile_rotation(
47 input: &RotationCompileInput<'_>,
48) -> Result<(RotationEngine, DenseBuffer), wowlab_engine_domain::rotation::Error> {
49 let mut catalog = SpecCatalog::new(input.spell_ids, input.aura_ids, input.hints);
50
51 if let Some(sec_name) = input.secondary_resource_name {
52 catalog.register_secondary_resource(sec_name);
53 }
54
55 let mut resolver = catalog.to_resolver("auto");
56
57 for gate in input.gating {
58 resolver = resolver.spell_gating(
59 wowlab_types::sim::SpellIdx(gate.spell_id),
60 wowlab_types::sim::AuraIdx(gate.aura_id),
61 wowlab_types::sim::AuraOn::Player,
62 gate.min_stacks,
63 );
64 }
65
66 for bypass in input.cost_bypass {
67 resolver = resolver.spell_cost_bypass(
68 wowlab_types::sim::SpellIdx(bypass.spell_id),
69 wowlab_types::sim::AuraIdx(bypass.aura_id),
70 wowlab_types::sim::AuraOn::Player,
71 );
72 }
73
74 for bypass in input.cooldown_bypass {
75 resolver = resolver.spell_cooldown_bypass(
76 wowlab_types::sim::SpellIdx(bypass.spell_id),
77 wowlab_types::sim::AuraIdx(bypass.aura_id),
78 wowlab_types::sim::AuraOn::Player,
79 );
80 }
81
82 for replacement in input.overrides {
83 resolver = resolver.spell_override(
84 wowlab_types::sim::SpellIdx(replacement.spell_id),
85 wowlab_types::sim::SpellIdx(replacement.replacement_spell_id),
86 wowlab_types::sim::AuraIdx(replacement.aura_id),
87 wowlab_types::sim::AuraOn::Player,
88 replacement.shares_base_cooldown,
89 );
90 }
91
92 let engine = RotationEngine::compile(input.rotation, &resolver)?;
93
94 let schema = engine.schema();
95 let offsets = schema.buffer_offsets.clone();
96 let size = schema.size;
97
98 let buffer = DenseBuffer::new(offsets, size);
99
100 Ok((engine, buffer))
101}