Skip to main content

wowlab_engine_combat/state/program/
telemetry.rs

1//! Immutable target metadata and encounter telemetry scope.
2
3use wowlab_engine_domain::encounter::EnemyActorDefinition;
4use wowlab_engine_telemetry::{AuraTelemetryScope, TargetMetadata, TelemetryScope};
5use wowlab_types::sim::{ActorId, AuraKey, EnemyIdx};
6
7use super::CombatProgram;
8use crate::state::CombatInstance;
9
10pub(crate) fn finalize_target_metadata(enemies: &[EnemyActorDefinition]) -> Vec<TargetMetadata> {
11    enemies
12        .iter()
13        .map(|enemy| TargetMetadata {
14            id: enemy.id().to_target_idx(),
15            npc_id: enemy.npc_id(),
16            display_name: enemy.display_name().to_string(),
17            group: enemy.group_id(),
18            enemy_tags: enemy.enemy_tags().to_vec(),
19            group_tags: enemy.group_tags().to_vec(),
20        })
21        .collect()
22}
23
24impl CombatProgram {
25    /// Immutable target dictionary finalized in encounter identity order.
26    #[must_use]
27    pub fn telemetry_targets(&self) -> &[TargetMetadata] {
28        &self.telemetry_targets
29    }
30
31    /// Exact source/target ownership scope for telemetry emitted against `target`.
32    #[must_use]
33    pub fn telemetry_scope(&self, source: ActorId, target: EnemyIdx) -> Option<TelemetryScope> {
34        let definition = self.config.encounter.definition();
35        let enemy = definition.enemies.get(target.as_usize())?;
36        let group = definition.groups.get(enemy.group_id.as_usize())?;
37        let wave = definition.waves.get(group.wave_id.as_usize())?;
38
39        Some(TelemetryScope {
40            source,
41            target,
42            pull: wave.pull_id,
43            group: group.id,
44        })
45    }
46
47    /// Pull/group ownership for an exact aura instance.
48    #[must_use]
49    pub fn aura_telemetry_scope(
50        &self,
51        instance: &CombatInstance,
52        key: AuraKey,
53    ) -> AuraTelemetryScope {
54        let (pull, group) = match key.affected() {
55            ActorId::Enemy(target) => self
56                .telemetry_scope(key.source(), target)
57                .map_or((instance.runtime.encounter.active_pull(), None), |scope| {
58                    (scope.pull, Some(scope.group))
59                }),
60            ActorId::Player | ActorId::External | ActorId::Pet(_) => {
61                (instance.runtime.encounter.active_pull(), None)
62            }
63        };
64
65        AuraTelemetryScope {
66            source: key.source(),
67            affected: key.affected(),
68            pull,
69            group,
70        }
71    }
72}