Skip to main content

forge/manifest_ledger/collect/
relations.rs

1// #t(file: rust_alloc_in_loop) relation rows intentionally own stable manifest coordinates.
2// #t(file: rust_clone_in_loop) independent relation rows retain their own scalar evidence.
3
4use wowlab_manifest_schema::{EventEffectDef, Manifest};
5
6use super::{base_row, effect_coordinate};
7use crate::manifest_ledger::types::{LedgerDisposition, LedgerRow, OperationCategory};
8
9pub(super) fn collect_manifest_relations(
10    rows: &mut Vec<LedgerRow>,
11    slug: &str,
12    path: &str,
13    manifest: &Manifest,
14) {
15    for (talent, auras) in &manifest.talent_companion_auras {
16        for (index, aura) in auras.iter().enumerate() {
17            rows.push(base_row(
18                slug,
19                path,
20                format!("talent_companion_auras.{talent}[{index}] ({aura})"),
21                OperationCategory::AuraApply,
22                LedgerDisposition::GenericGap,
23                "talent-selected companion aura activation",
24            ));
25        }
26    }
27
28    for (index, _) in manifest.spell_groups.iter().enumerate() {
29        rows.push(base_row(
30            slug,
31            path,
32            format!("spell_groups[{index}]"),
33            OperationCategory::Gate,
34            LedgerDisposition::ContentOrdering,
35            "authored mutually exclusive aura group",
36        ));
37    }
38
39    for (name, effect) in &manifest.effects {
40        rows.push(
41            base_row(
42                slug,
43                path,
44                format!("effects.{name}"),
45                OperationCategory::OrderedContent,
46                LedgerDisposition::Unresolved,
47                "hook reads a retained DBC scalar",
48            )
49            .effect(effect.spell_id, effect.effect),
50        );
51    }
52
53    for (name, declaration) in &manifest.content_effects {
54        rows.push(
55            base_row(
56                slug,
57                path,
58                format!("content_effects.{name}"),
59                OperationCategory::OrderedContent,
60                LedgerDisposition::Unresolved,
61                declaration.reason.clone(),
62            )
63            .effect(declaration.spell_id, declaration.effect),
64        );
65    }
66
67    for (name, spell_id) in &manifest.reported_spells {
68        rows.push(
69            base_row(
70                slug,
71                path,
72                format!("reported_spells.{name}"),
73                OperationCategory::TelemetryOnly,
74                LedgerDisposition::TelemetryBinding,
75                "damage attribution alias",
76            )
77            .owner(*spell_id),
78        );
79    }
80
81    for (index, proc) in manifest.impact_procs.iter().enumerate() {
82        let mut registration = base_row(
83            slug,
84            path,
85            format!("impact_procs[{index}]"),
86            OperationCategory::Proc,
87            LedgerDisposition::GenericGap,
88            "declarative impact subscription candidate",
89        );
90
91        if let Some(spell) = &proc.spell {
92            if let Some(definition) = manifest.spells.get(spell) {
93                registration = registration.owner(definition.id);
94            }
95        }
96
97        rows.push(registration);
98
99        for (effect_index, effect) in proc.effects.iter().enumerate() {
100            event_effect(
101                rows,
102                slug,
103                path,
104                &format!("impact_procs[{index}].effects[{effect_index}]"),
105                0,
106                effect,
107            );
108        }
109    }
110}
111
112pub(super) fn event_effect(
113    rows: &mut Vec<LedgerRow>,
114    owner: &str,
115    path: &str,
116    key: &str,
117    spell_id: u32,
118    effect: &EventEffectDef,
119) {
120    let (category, disposition, evidence) = match effect {
121        EventEffectDef::Energize { .. } => (
122            OperationCategory::Resource,
123            LedgerDisposition::GenericGap,
124            "typed energize child operation",
125        ),
126        EventEffectDef::ExtendAura { .. } => (
127            OperationCategory::AuraApply,
128            LedgerDisposition::GenericGap,
129            "typed aura-duration child operation",
130        ),
131        _ => (
132            OperationCategory::OrderedContent,
133            LedgerDisposition::Unresolved,
134            "unrecognized event operation",
135        ),
136    };
137    let mut row = base_row(owner, path, key, category, disposition, evidence);
138
139    if spell_id != 0 {
140        row = row.owner(spell_id);
141    }
142
143    if let EventEffectDef::Energize { amount, .. } = effect {
144        if let Some((effect_spell, effect_index)) = effect_coordinate(amount) {
145            row = row.effect(effect_spell, effect_index);
146        }
147    }
148
149    rows.push(row);
150}