use std::any::TypeId;
use bevy::{
ecs::reflect::AppTypeRegistry,
log::warn,
reflect::{
serde::{ReflectDeserializer, TypedReflectSerializer},
PartialReflect, Reflect, TypeRegistry,
},
};
use serde::{
de::DeserializeSeed,
ser::{Error as _, SerializeMap as _},
Serializer,
};
use crate::{BoxedModifier, Modifier, ModifierContext, Module};
pub type ModifierFactory = fn(&mut Module) -> BoxedModifier;
#[derive(Clone, Copy)]
pub struct ReflectModifier {
pub factory: ModifierFactory,
pub context: ModifierContext,
}
impl ReflectModifier {}
pub fn register_reflect_modifier<T: Modifier>(
type_registry: &AppTypeRegistry,
factory: ModifierFactory,
) {
let context = {
let mut module = Module::default();
let modifier = factory(&mut module);
let context = modifier.context();
let any = modifier.into_any();
assert_eq!(
any.type_id(),
TypeId::of::<T>(),
"Factory for modifier type '{}' returned a different object of type.",
std::any::type_name::<T>()
);
context
};
let reflect_modifier = ReflectModifier { factory, context };
match type_registry.write().get_mut(TypeId::of::<T>()) {
Some(type_registration) => type_registration.insert(reflect_modifier),
None => warn!(
"insert_reflect_modifier: type {} not found in TypeRegistry",
std::any::type_name::<T>()
),
}
}
impl bevy::reflect::serde::SerializeWithRegistry for BoxedModifier {
fn serialize<S>(&self, serializer: S, registry: &TypeRegistry) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let reflect: &dyn Reflect = Reflect::as_reflect(&**self);
let type_path = reflect
.get_represented_type_info()
.ok_or_else(|| {
S::Error::custom("cannot serialize dynamic value without represented type")
})?
.type_path();
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry(type_path, &TypedReflectSerializer::new(reflect, registry))?;
map.end()
}
}
impl<'de> bevy::reflect::serde::DeserializeWithRegistry<'de> for BoxedModifier {
fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let reflect_seed = ReflectDeserializer::new(registry);
let boxed_partial: Box<dyn PartialReflect> = reflect_seed
.deserialize(deserializer)
.map_err(serde::de::Error::custom)?;
let type_info = boxed_partial.get_represented_type_info().ok_or_else(|| {
serde::de::Error::custom("reflected value has no represented type info")
})?;
let type_id = type_info.type_id();
let reflect_modifier = registry
.get_type_data::<ReflectModifier>(type_id)
.ok_or_else(|| {
serde::de::Error::custom(format!(
"no ReflectModifier type data for '{}'",
type_info.type_path()
))
})?;
let mut module = Module::default();
let mut modifier: BoxedModifier = (reflect_modifier.factory)(&mut module);
let reflect_mut: &mut dyn Reflect = Reflect::as_reflect_mut(&mut *modifier);
reflect_mut.apply(boxed_partial.as_partial_reflect());
Ok(modifier)
}
}
use std::fmt::Formatter;
use std::ops::{Deref, DerefMut};
use bevy::reflect::serde::{ReflectDeserializeWithRegistry, ReflectSerializeWithRegistry};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
#[derive(Default, Clone, Reflect)]
#[reflect(SerializeWithRegistry, DeserializeWithRegistry, from_reflect = false)]
pub struct Modifiers(#[reflect(ignore)] pub Vec<BoxedModifier>);
impl Deref for Modifiers {
type Target = Vec<BoxedModifier>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Modifiers {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl bevy::reflect::serde::SerializeWithRegistry for Modifiers {
fn serialize<S>(&self, serializer: S, registry: &TypeRegistry) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
struct Elem<'a> {
boxed: &'a BoxedModifier,
registry: &'a TypeRegistry,
}
impl<'a> serde::Serialize for Elem<'a> {
fn serialize<S2>(&self, serializer: S2) -> Result<S2::Ok, S2::Error>
where
S2: serde::Serializer,
{
use bevy::reflect::serde::SerializeWithRegistry;
self.boxed.serialize(serializer, self.registry)
}
}
let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
for m in &self.0 {
seq.serialize_element(&Elem { boxed: m, registry })?;
}
seq.end()
}
}
impl<'de> bevy::reflect::serde::DeserializeWithRegistry<'de> for Modifiers {
fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct ModifiersVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for ModifiersVisitor<'a> {
type Value = Modifiers;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
write!(formatter, "a list of modifiers")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
struct ElemSeed<'a> {
registry: &'a TypeRegistry,
}
impl<'de2, 'a> serde::de::DeserializeSeed<'de2> for ElemSeed<'a> {
type Value = BoxedModifier;
fn deserialize<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
where
D2: serde::de::Deserializer<'de2>,
{
use bevy::reflect::serde::DeserializeWithRegistry;
BoxedModifier::deserialize(deserializer, self.registry)
}
}
let mut vec = Vec::new();
while let Some(modifier) = seq.next_element_seed(ElemSeed {
registry: self.registry,
})? {
vec.push(modifier);
}
Ok(Modifiers(vec))
}
}
let modifiers: Self = deserializer.deserialize_seq(ModifiersVisitor { registry })?;
Ok(modifiers)
}
}
#[cfg(test)]
mod tests {
use bevy::math::Vec3;
use ron::ser::PrettyConfig;
use serde::de::DeserializeSeed;
use super::*;
use crate::{
register_modifiers, AccelModifier, EffectAsset, EffectAssetDeserializer,
EffectAssetSerializer, RenderModifier, SpawnerSettings,
};
#[test]
fn serde_modifiers() {
use bevy::reflect::{
serde::{TypedReflectDeserializer, TypedReflectSerializer},
Reflect,
};
use crate::{Attribute, SetAttributeModifier, SetPositionSphereModifier, ShapeDimension};
let mut module = Module::default();
let mut modifiers = vec![];
let m1 = SetAttributeModifier::new(Attribute::SIZE, module.lit(2.));
let bm1: BoxedModifier = Box::new(m1);
modifiers.push(bm1);
let m2 = SetPositionSphereModifier {
center: module.lit(Vec3::ZERO),
radius: module.lit(1.),
dimension: ShapeDimension::Surface,
};
let bm2: BoxedModifier = Box::new(m2);
modifiers.push(bm2);
let modifiers = Modifiers(modifiers);
let type_registry = AppTypeRegistry::new_with_derived_types();
register_modifiers(&type_registry);
let registry = type_registry.read();
let s = ron::ser::to_string_pretty(
&TypedReflectSerializer::new(modifiers.as_reflect(), ®istry),
PrettyConfig::default(),
)
.unwrap();
println!("{s}");
assert!(s.contains(std::any::type_name::<SetAttributeModifier>()));
assert!(s.contains(std::any::type_name::<SetPositionSphereModifier>()));
assert!(!s.contains(std::any::type_name::<Modifiers>()));
let mut de = ron::de::Deserializer::from_str(&s).unwrap();
let type_registration = registry.get(std::any::TypeId::of::<Modifiers>()).unwrap();
let deserializer = TypedReflectDeserializer::new(type_registration, ®istry);
let mods = deserializer.deserialize(&mut de).unwrap();
assert!(mods.represents::<Modifiers>());
let mods = mods.try_downcast::<Modifiers>().unwrap();
assert_eq!(mods.0.len(), modifiers.0.len());
for (mi, smi) in mods.0.iter().zip(modifiers.0.iter()) {
use std::any::Any;
assert_eq!(
mi.get_represented_type_info().type_id(),
smi.get_represented_type_info().type_id()
);
}
let serde_m1 = mods.0[0]
.as_reflect()
.downcast_ref::<SetAttributeModifier>()
.unwrap();
let serde_m2 = mods.0[1]
.as_reflect()
.downcast_ref::<SetPositionSphereModifier>()
.unwrap();
assert_eq!(m1, *serde_m1);
assert_eq!(m2, *serde_m2);
}
fn cmp_modifiers<'a>(
a: impl Iterator<Item = &'a dyn Modifier>,
b: impl Iterator<Item = &'a dyn Modifier>,
) {
let a = a.collect::<Vec<_>>();
let b = b.collect::<Vec<_>>();
assert_eq!(a.len(), b.len());
for (a, b) in a.iter().zip(b.iter()) {
assert_eq!(a.context(), b.context());
}
}
fn cmp_render_modifiers<'a>(
a: impl Iterator<Item = &'a dyn RenderModifier>,
b: impl Iterator<Item = &'a dyn RenderModifier>,
) {
let a = a.collect::<Vec<_>>();
let b = b.collect::<Vec<_>>();
assert_eq!(a.len(), b.len());
for (a, b) in a.iter().zip(b.iter()) {
assert_eq!(a.context(), b.context());
}
}
#[test]
fn serde_asset() {
let mut module = Module::default();
let accel_mod = AccelModifier::new(module.lit(Vec3::X));
let asset =
EffectAsset::new(24, SpawnerSettings::once(3.0.into()), module).update(accel_mod);
let type_registry = AppTypeRegistry::new_with_derived_types();
register_modifiers(&type_registry);
let registry = type_registry.read();
let serializer = EffectAssetSerializer::new(&asset, ®istry);
let json = ron::ser::to_string_pretty(&serializer, PrettyConfig::default()).unwrap();
println!("{json}");
let mut deserializer = ron::de::Deserializer::from_str(&json).unwrap();
let deserialize = EffectAssetDeserializer::new(®istry);
let serde_asset = deserialize.deserialize(&mut deserializer).unwrap();
assert_eq!(asset.name, serde_asset.name);
assert_eq!(asset.capacity(), serde_asset.capacity());
assert_eq!(asset.spawner, serde_asset.spawner);
assert_eq!(asset.z_layer_2d, serde_asset.z_layer_2d);
assert_eq!(asset.simulation_space, serde_asset.simulation_space);
assert_eq!(asset.simulation_condition, serde_asset.simulation_condition);
assert_eq!(asset.prng_seed, serde_asset.prng_seed);
assert_eq!(asset.motion_integration, serde_asset.motion_integration);
assert_eq!(asset.alpha_mode, serde_asset.alpha_mode);
cmp_modifiers(asset.init_modifiers(), serde_asset.init_modifiers());
cmp_modifiers(asset.update_modifiers(), serde_asset.update_modifiers());
cmp_render_modifiers(asset.render_modifiers(), serde_asset.render_modifiers());
}
}