Fix TypeRegistry use in dynamic scene (#12715)
Adopted from and closes https://github.com/bevyengine/bevy/pull/9914 by @djeedai # Objective Fix the use of `TypeRegistry` instead of `TypeRegistryArc` in dynamic scene and its serializer. Rename `DynamicScene::serialize_ron()` into `serialize()` to highlight the fact this is not about serializing to RON specifically, but rather about serializing to the official Bevy scene format (`.scn` / `.scn.ron`) which the `SceneLoader` can deserialize (and which happens to be based in RON, but that not the object here). Also make the link with the documentation of `SceneLoader` so users understand the full serializing cycle of a Bevy dynamic scene. Document `SceneSerializer` with an example showing how to serialize to a custom format (here: RON), which is easily transposed to serializing into any other format. Fixes #9520 ## Changelog ### Changed * `SceneSerializer` and all related serializing helper types now take a `&TypeRegistry` instead of a `&TypeRegistryArc`. ([SceneSerializer needlessly uses specifically &TypeRegistryArc #9520](https://github.com/bevyengine/bevy/issues/9520)) * `DynamicScene::serialize_ron()` was renamed to `serialize()`. ## Migration Guide * `SceneSerializer` and all related serializing helper types now take a `&TypeRegistry` instead of a `&TypeRegistryArc`. You can upgrade by getting the former from the latter with `TypeRegistryArc::read()`, _e.g._ ```diff let registry_arc: TypeRegistryArc = [...]; - let serializer = SceneSerializer(&scene, ®istry_arc); + let registry = registry_arc.read(); + let serializer = SceneSerializer(&scene, ®istry); ``` * Rename `DynamicScene::serialize_ron()` to `serialize()`. --------- Co-authored-by: Jerome Humbert <djeedai@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com> Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com> Co-authored-by: James Liu <contact@jamessliu.com>
This commit is contained in:
parent
6840f95d62
commit
760c645de1
@ -5,7 +5,7 @@ use bevy_ecs::{
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
||||
use bevy_reflect::{Reflect, TypePath, TypeRegistry};
|
||||
use bevy_utils::TypeIdMap;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
@ -171,9 +171,15 @@ impl DynamicScene {
|
||||
}
|
||||
|
||||
// TODO: move to AssetSaver when it is implemented
|
||||
/// Serialize this dynamic scene into rust object notation (ron).
|
||||
/// Serialize this dynamic scene into the official Bevy scene format (`.scn` / `.scn.ron`).
|
||||
///
|
||||
/// The Bevy scene format is based on [Rusty Object Notation (RON)]. It describes the scene
|
||||
/// in a human-friendly format. To deserialize the scene, use the [`SceneLoader`].
|
||||
///
|
||||
/// [`SceneLoader`]: crate::SceneLoader
|
||||
/// [Rusty Object Notation (RON)]: https://crates.io/crates/ron
|
||||
#[cfg(feature = "serialize")]
|
||||
pub fn serialize_ron(&self, registry: &TypeRegistryArc) -> Result<String, ron::Error> {
|
||||
pub fn serialize(&self, registry: &TypeRegistry) -> Result<String, ron::Error> {
|
||||
serialize_ron(SceneSerializer::new(self, registry))
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,9 @@ use bevy_reflect::TypeRegistryArc;
|
||||
use serde::de::DeserializeSeed;
|
||||
use thiserror::Error;
|
||||
|
||||
/// [`AssetLoader`] for loading serialized Bevy scene files as [`DynamicScene`].
|
||||
/// Asset loader for a Bevy dynamic scene (`.scn` / `.scn.ron`).
|
||||
///
|
||||
/// The loader handles assets serialized with [`DynamicScene::serialize`].
|
||||
#[derive(Debug)]
|
||||
pub struct SceneLoader {
|
||||
type_registry: TypeRegistryArc,
|
||||
|
@ -5,7 +5,7 @@ use bevy_ecs::entity::Entity;
|
||||
use bevy_reflect::serde::{TypedReflectDeserializer, TypedReflectSerializer};
|
||||
use bevy_reflect::{
|
||||
serde::{ReflectDeserializer, TypeRegistrationDeserializer},
|
||||
Reflect, TypeRegistry, TypeRegistryArc,
|
||||
Reflect, TypeRegistry,
|
||||
};
|
||||
use bevy_utils::HashSet;
|
||||
use serde::ser::SerializeMap;
|
||||
@ -28,59 +28,46 @@ pub const ENTITY_STRUCT: &str = "Entity";
|
||||
/// Name of the serialized component field in an entity struct.
|
||||
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
||||
|
||||
/// Handles serialization of a scene as a struct containing its entities and resources.
|
||||
/// Serializer for a [`DynamicScene`].
|
||||
///
|
||||
/// # Examples
|
||||
/// Helper object defining Bevy's serialize format for a [`DynamicScene`] and implementing
|
||||
/// the [`Serialize`] trait for use with Serde.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_scene::{serde::SceneSerializer, DynamicScene};
|
||||
/// # use bevy_ecs::{
|
||||
/// # prelude::{Component, World},
|
||||
/// # reflect::{AppTypeRegistry, ReflectComponent},
|
||||
/// # };
|
||||
/// # use bevy_reflect::Reflect;
|
||||
/// // Define an example component type.
|
||||
/// #[derive(Component, Reflect, Default)]
|
||||
/// #[reflect(Component)]
|
||||
/// struct MyComponent {
|
||||
/// foo: [usize; 3],
|
||||
/// bar: (f32, f32),
|
||||
/// baz: String,
|
||||
/// }
|
||||
///
|
||||
/// // Create our world, provide it with a type registry.
|
||||
/// // Normally, [`App`] handles providing the type registry.
|
||||
/// let mut world = World::new();
|
||||
/// let registry = AppTypeRegistry::default();
|
||||
/// {
|
||||
/// let mut registry = registry.write();
|
||||
/// // Register our component. Primitives and String are registered by default.
|
||||
/// // Sequence types are automatically handled.
|
||||
/// registry.register::<MyComponent>();
|
||||
/// }
|
||||
/// world.insert_resource(registry);
|
||||
/// world.spawn(MyComponent {
|
||||
/// foo: [1, 2, 3],
|
||||
/// bar: (1.3, 3.7),
|
||||
/// baz: String::from("test"),
|
||||
/// });
|
||||
///
|
||||
/// // Print out our serialized scene in the RON format.
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_scene::{DynamicScene, serde::SceneSerializer};
|
||||
/// # let mut world = World::default();
|
||||
/// # world.insert_resource(AppTypeRegistry::default());
|
||||
/// // Get the type registry
|
||||
/// let registry = world.resource::<AppTypeRegistry>();
|
||||
/// let registry = registry.read();
|
||||
///
|
||||
/// // Get a DynamicScene to serialize, for example from the World itself
|
||||
/// let scene = DynamicScene::from_world(&world);
|
||||
/// let scene_serializer = SceneSerializer::new(&scene, ®istry.0);
|
||||
/// println!("{}", bevy_scene::serialize_ron(scene_serializer).unwrap());
|
||||
///
|
||||
/// // Create a serializer for that DynamicScene, using the associated TypeRegistry
|
||||
/// let scene_serializer = SceneSerializer::new(&scene, ®istry);
|
||||
///
|
||||
/// // Serialize through any serde-compatible Serializer
|
||||
/// let ron_string = bevy_scene::ron::ser::to_string(&scene_serializer);
|
||||
/// ```
|
||||
pub struct SceneSerializer<'a> {
|
||||
/// The scene to serialize.
|
||||
pub scene: &'a DynamicScene,
|
||||
/// Type registry in which the components and resources types used in the scene are registered.
|
||||
pub registry: &'a TypeRegistryArc,
|
||||
/// The type registry containing the types present in the scene.
|
||||
pub registry: &'a TypeRegistry,
|
||||
}
|
||||
|
||||
impl<'a> SceneSerializer<'a> {
|
||||
/// Creates a scene serializer.
|
||||
pub fn new(scene: &'a DynamicScene, registry: &'a TypeRegistryArc) -> Self {
|
||||
/// Create a new serializer from a [`DynamicScene`] and an associated [`TypeRegistry`].
|
||||
///
|
||||
/// The type registry must contain all types present in the scene. This is generally the case
|
||||
/// if you obtain both the scene and the registry from the same [`World`].
|
||||
///
|
||||
/// [`World`]: bevy_ecs::world::World
|
||||
pub fn new(scene: &'a DynamicScene, registry: &'a TypeRegistry) -> Self {
|
||||
SceneSerializer { scene, registry }
|
||||
}
|
||||
}
|
||||
@ -114,7 +101,7 @@ pub struct EntitiesSerializer<'a> {
|
||||
/// The entities to serialize.
|
||||
pub entities: &'a [DynamicEntity],
|
||||
/// Type registry in which the component types used by the entities are registered.
|
||||
pub registry: &'a TypeRegistryArc,
|
||||
pub registry: &'a TypeRegistry,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for EntitiesSerializer<'a> {
|
||||
@ -141,7 +128,7 @@ pub struct EntitySerializer<'a> {
|
||||
/// The entity to serialize.
|
||||
pub entity: &'a DynamicEntity,
|
||||
/// Type registry in which the component types used by the entity are registered.
|
||||
pub registry: &'a TypeRegistryArc,
|
||||
pub registry: &'a TypeRegistry,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for EntitySerializer<'a> {
|
||||
@ -170,7 +157,7 @@ pub struct SceneMapSerializer<'a> {
|
||||
/// List of boxed values of unique type to serialize.
|
||||
pub entries: &'a [Box<dyn Reflect>],
|
||||
/// Type registry in which the types used in `entries` are registered.
|
||||
pub registry: &'a TypeRegistryArc,
|
||||
pub registry: &'a TypeRegistry,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for SceneMapSerializer<'a> {
|
||||
@ -182,7 +169,7 @@ impl<'a> Serialize for SceneMapSerializer<'a> {
|
||||
for reflect in self.entries {
|
||||
state.serialize_entry(
|
||||
reflect.get_represented_type_info().unwrap().type_path(),
|
||||
&TypedReflectSerializer::new(&**reflect, &self.registry.read()),
|
||||
&TypedReflectSerializer::new(&**reflect, self.registry),
|
||||
)?;
|
||||
}
|
||||
state.end()
|
||||
@ -624,7 +611,7 @@ mod tests {
|
||||
},
|
||||
)"#;
|
||||
let output = scene
|
||||
.serialize_ron(&world.resource::<AppTypeRegistry>().0)
|
||||
.serialize(&world.resource::<AppTypeRegistry>().read())
|
||||
.unwrap();
|
||||
assert_eq!(expected, output);
|
||||
}
|
||||
@ -707,7 +694,7 @@ mod tests {
|
||||
let scene = DynamicScene::from_world(&world);
|
||||
|
||||
let serialized = scene
|
||||
.serialize_ron(&world.resource::<AppTypeRegistry>().0)
|
||||
.serialize(&world.resource::<AppTypeRegistry>().read())
|
||||
.unwrap();
|
||||
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
|
||||
let scene_deserializer = SceneDeserializer {
|
||||
@ -753,10 +740,11 @@ mod tests {
|
||||
});
|
||||
|
||||
let registry = world.resource::<AppTypeRegistry>();
|
||||
let registry = ®istry.read();
|
||||
|
||||
let scene = DynamicScene::from_world(&world);
|
||||
|
||||
let scene_serializer = SceneSerializer::new(&scene, ®istry.0);
|
||||
let scene_serializer = SceneSerializer::new(&scene, registry);
|
||||
let serialized_scene = postcard::to_allocvec(&scene_serializer).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@ -770,7 +758,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let scene_deserializer = SceneDeserializer {
|
||||
type_registry: ®istry.0.read(),
|
||||
type_registry: registry,
|
||||
};
|
||||
let deserialized_scene = scene_deserializer
|
||||
.deserialize(&mut postcard::Deserializer::from_bytes(&serialized_scene))
|
||||
@ -791,10 +779,11 @@ mod tests {
|
||||
});
|
||||
|
||||
let registry = world.resource::<AppTypeRegistry>();
|
||||
let registry = ®istry.read();
|
||||
|
||||
let scene = DynamicScene::from_world(&world);
|
||||
|
||||
let scene_serializer = SceneSerializer::new(&scene, ®istry.0);
|
||||
let scene_serializer = SceneSerializer::new(&scene, registry);
|
||||
let mut buf = Vec::new();
|
||||
let mut ser = rmp_serde::Serializer::new(&mut buf);
|
||||
scene_serializer.serialize(&mut ser).unwrap();
|
||||
@ -811,7 +800,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let scene_deserializer = SceneDeserializer {
|
||||
type_registry: ®istry.0.read(),
|
||||
type_registry: registry,
|
||||
};
|
||||
let mut reader = BufReader::new(buf.as_slice());
|
||||
|
||||
@ -834,10 +823,11 @@ mod tests {
|
||||
});
|
||||
|
||||
let registry = world.resource::<AppTypeRegistry>();
|
||||
let registry = ®istry.read();
|
||||
|
||||
let scene = DynamicScene::from_world(&world);
|
||||
|
||||
let scene_serializer = SceneSerializer::new(&scene, ®istry.0);
|
||||
let scene_serializer = SceneSerializer::new(&scene, registry);
|
||||
let serialized_scene = bincode::serialize(&scene_serializer).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@ -853,7 +843,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let scene_deserializer = SceneDeserializer {
|
||||
type_registry: ®istry.0.read(),
|
||||
type_registry: registry,
|
||||
};
|
||||
|
||||
let deserialized_scene = bincode::DefaultOptions::new()
|
||||
|
@ -125,7 +125,8 @@ fn save_scene_system(world: &mut World) {
|
||||
|
||||
// Scenes can be serialized like this:
|
||||
let type_registry = world.resource::<AppTypeRegistry>();
|
||||
let serialized_scene = scene.serialize_ron(type_registry).unwrap();
|
||||
let type_registry = type_registry.read();
|
||||
let serialized_scene = scene.serialize(&type_registry).unwrap();
|
||||
|
||||
// Showing the scene in the console
|
||||
info!("{}", serialized_scene);
|
||||
|
Loading…
Reference in New Issue
Block a user