From 9344e42622229315e077592912d082e227fcd974 Mon Sep 17 00:00:00 2001 From: radiish Date: Mon, 26 Feb 2024 16:13:04 +0000 Subject: [PATCH] reflect: treat proxy types correctly when serializing (#12024) # Objective - Fixes #12001. - Note this PR doesn't change any feature flags, however flaky the issue revealed they are. ## Solution - Use `FromReflect` to convert proxy types to concrete ones in `ReflectSerialize::get_serializable`. - Use `get_represented_type_info() -> type_id()` to get the correct type id to interact with the registry in `bevy_reflect::serde::ser::get_serializable`. --- ## Changelog - Registering `ReflectSerialize` now imposes additional `FromReflect` and `TypePath` bounds. ## Migration Guide - If `ReflectSerialize` is registered on a type, but `TypePath` or `FromReflect` implementations are omitted (perhaps by `#[reflect(type_path = false)` or `#[reflect(from_reflect = false)]`), the traits must now be implemented. --------- Co-authored-by: Alice Cecile Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com> --- crates/bevy_reflect/src/serde/ser.rs | 11 +++++++++-- crates/bevy_reflect/src/type_registry.rs | 18 ++++++++++++------ examples/scene/scene.rs | 1 + 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index 35c5107cf50827..2823f2f811617a 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -32,12 +32,19 @@ fn get_serializable<'a, E: Error>( reflect_value: &'a dyn Reflect, type_registry: &TypeRegistry, ) -> Result, E> { + let info = reflect_value.get_represented_type_info().ok_or_else(|| { + Error::custom(format_args!( + "Type '{}' does not represent any type", + reflect_value.reflect_type_path(), + )) + })?; + let reflect_serialize = type_registry - .get_type_data::(reflect_value.type_id()) + .get_type_data::(info.type_id()) .ok_or_else(|| { Error::custom(format_args!( "Type '{}' did not register ReflectSerialize", - reflect_value.reflect_type_path() + info.type_path(), )) })?; Ok(reflect_serialize.get_serializable(reflect_value)) diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index a67678e836bb9d..8fc39297f3d5a2 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -1,4 +1,4 @@ -use crate::{serde::Serializable, Reflect, TypeInfo, TypePath, Typed}; +use crate::{serde::Serializable, FromReflect, Reflect, TypeInfo, TypePath, Typed}; use bevy_ptr::{Ptr, PtrMut}; use bevy_utils::{HashMap, HashSet, TypeIdMap}; use downcast_rs::{impl_downcast, Downcast}; @@ -461,14 +461,20 @@ pub struct ReflectSerialize { get_serializable: for<'a> fn(value: &'a dyn Reflect) -> Serializable, } -impl FromType for ReflectSerialize { +impl FromType for ReflectSerialize { fn from_type() -> Self { ReflectSerialize { get_serializable: |value| { - let value = value.downcast_ref::().unwrap_or_else(|| { - panic!("ReflectSerialize::get_serialize called with type `{}`, even though it was created for `{}`", value.reflect_type_path(), std::any::type_name::()) - }); - Serializable::Borrowed(value) + value + .downcast_ref::() + .map(|value| Serializable::Borrowed(value)) + .or_else(|| T::from_reflect(value).map(|value| Serializable::Owned(Box::new(value)))) + .unwrap_or_else(|| { + panic!( + "FromReflect::from_reflect failed when called on type `{}` with this value: {value:?}", + T::type_path(), + ); + }) }, } } diff --git a/examples/scene/scene.rs b/examples/scene/scene.rs index dac36e96d7fd41..6b42451d885ef8 100644 --- a/examples/scene/scene.rs +++ b/examples/scene/scene.rs @@ -114,6 +114,7 @@ fn save_scene_system(world: &mut World) { component_b, ComponentA { x: 1.0, y: 2.0 }, Transform::IDENTITY, + Name::new("joe"), )); scene_world.spawn(ComponentA { x: 3.0, y: 4.0 }); scene_world.insert_resource(ResourceA { score: 1 });