use std::collections::HashMap;
use bevy::reflect::TypeRegistry;
use bevy_hanabi::{Attribute, EffectAsset};
use crate::{ModifierGroup, modifier_registry::ModifierOverwrites};
pub fn shadowed_modifiers(
asset: &EffectAsset,
registry: &TypeRegistry,
) -> HashMap<(ModifierGroup, usize), Vec<(Attribute, usize)>> {
let mut out = HashMap::new();
analyze_group(asset, ModifierGroup::Init, registry, &mut out);
analyze_group(asset, ModifierGroup::Update, registry, &mut out);
out
}
fn analyze_group(
asset: &EffectAsset,
group: ModifierGroup,
registry: &TypeRegistry,
out: &mut HashMap<(ModifierGroup, usize), Vec<(Attribute, usize)>>,
) {
let overwrites: Vec<Vec<Attribute>> = match group {
ModifierGroup::Init => asset
.init_modifiers()
.map(|m| overwrites_for(m.as_reflect(), registry))
.collect(),
ModifierGroup::Update => asset
.update_modifiers()
.map(|m| overwrites_for(m.as_reflect(), registry))
.collect(),
ModifierGroup::Render => return,
};
for (i, w_i) in overwrites.iter().enumerate() {
if w_i.is_empty() {
continue;
}
let mut hits: Vec<(Attribute, usize)> = Vec::with_capacity(w_i.len());
for &attr in w_i {
let earliest = overwrites
.iter()
.enumerate()
.skip(i + 1)
.find(|(_, w_j)| w_j.contains(&attr))
.map(|(j, _)| j);
match earliest {
Some(j) => hits.push((attr, j)),
None => {
hits.clear();
break;
}
}
}
if !hits.is_empty() {
out.insert((group, i), hits);
}
}
}
fn overwrites_for(m: &dyn bevy::reflect::Reflect, registry: &TypeRegistry) -> Vec<Attribute> {
let Some(reg) = registry.get(std::any::Any::type_id(m)) else {
return Vec::new();
};
let Some(rm) = reg.data::<ModifierOverwrites>() else {
return Vec::new();
};
(rm.overwrites)(m)
}