use std::{any::TypeId, borrow::Cow};
use bevy::{
prelude::*,
reflect::{Reflect, TypeRegistry},
};
use bevy_hanabi::{
Attribute, ModifierContext, ReflectModifier, SetAttributeModifier, SetPositionCircleModifier,
SetPositionCone3dModifier, SetPositionSphereModifier, SetVelocityCircleModifier,
SetVelocitySphereModifier, SetVelocityTangentModifier, register_modifiers,
};
use crate::ModifierGroup;
#[derive(Clone, Copy)]
pub struct ModifierOverwrites {
pub overwrites: fn(&dyn Reflect) -> Vec<Attribute>,
}
pub struct ModifierKindView<'a> {
pub type_id: TypeId,
pub short_type_name: &'a str,
pub reflect_modifier: &'a ReflectModifier,
}
impl ModifierKindView<'_> {
pub fn display_name(&self) -> Cow<'static, str> {
crate::modifier_names::display_name_for_type(self.short_type_name)
}
pub fn context(&self) -> ModifierContext {
self.reflect_modifier.context
}
}
pub fn iter_modifier_kinds(registry: &TypeRegistry) -> impl Iterator<Item = ModifierKindView<'_>> {
let mut v: Vec<ModifierKindView<'_>> = registry
.iter()
.filter_map(|reg| {
let rm = reg.data::<ReflectModifier>()?;
Some(ModifierKindView {
type_id: reg.type_id(),
short_type_name: reg.type_info().type_path_table().short_path(),
reflect_modifier: rm,
})
})
.collect();
v.sort_by_key(|k| k.short_type_name);
v.into_iter()
}
pub fn iter_modifier_kinds_for(
registry: &TypeRegistry,
group: ModifierGroup,
) -> impl Iterator<Item = ModifierKindView<'_>> {
let flag: ModifierContext = group.into();
iter_modifier_kinds(registry).filter(move |k| k.context().contains(flag))
}
pub fn get_modifier_kind(registry: &TypeRegistry, type_id: TypeId) -> Option<ModifierKindView<'_>> {
let reg = registry.get(type_id)?;
let rm = reg.data::<ReflectModifier>()?;
Some(ModifierKindView {
type_id: reg.type_id(),
short_type_name: reg.type_info().type_path_table().short_path(),
reflect_modifier: rm,
})
}
pub struct ModifierRegistryPlugin;
impl Plugin for ModifierRegistryPlugin {
fn build(&self, app: &mut App) {
register_modifiers(app.world().resource::<AppTypeRegistry>());
register_builtin_overwrites(app);
}
}
fn register_builtin_overwrites(app: &mut App) {
let app_registry = app.world().resource::<AppTypeRegistry>();
let mut registry = app_registry.write();
let mut set = |type_id: TypeId, overwrites: fn(&dyn Reflect) -> Vec<Attribute>| {
if let Some(reg) = registry.get_mut(type_id) {
reg.insert(ModifierOverwrites { overwrites });
}
};
set(TypeId::of::<SetAttributeModifier>(), |m| {
m.downcast_ref::<SetAttributeModifier>()
.map(|s| vec![s.attribute])
.unwrap_or_default()
});
set(TypeId::of::<SetPositionSphereModifier>(), |_| {
vec![Attribute::POSITION]
});
set(TypeId::of::<SetPositionCircleModifier>(), |_| {
vec![Attribute::POSITION]
});
set(TypeId::of::<SetPositionCone3dModifier>(), |_| {
vec![Attribute::POSITION]
});
set(TypeId::of::<SetVelocitySphereModifier>(), |_| {
vec![Attribute::VELOCITY]
});
set(TypeId::of::<SetVelocityCircleModifier>(), |_| {
vec![Attribute::VELOCITY]
});
set(TypeId::of::<SetVelocityTangentModifier>(), |_| {
vec![Attribute::VELOCITY]
});
}