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},
|
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
use bevy_reflect::{Reflect, TypePath, TypeRegistry};
|
||||||
use bevy_utils::TypeIdMap;
|
use bevy_utils::TypeIdMap;
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
@ -171,9 +171,15 @@ impl DynamicScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to AssetSaver when it is implemented
|
// 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")]
|
#[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))
|
serialize_ron(SceneSerializer::new(self, registry))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@ use bevy_reflect::TypeRegistryArc;
|
|||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
use thiserror::Error;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct SceneLoader {
|
pub struct SceneLoader {
|
||||||
type_registry: TypeRegistryArc,
|
type_registry: TypeRegistryArc,
|
||||||
|
@ -5,7 +5,7 @@ use bevy_ecs::entity::Entity;
|
|||||||
use bevy_reflect::serde::{TypedReflectDeserializer, TypedReflectSerializer};
|
use bevy_reflect::serde::{TypedReflectDeserializer, TypedReflectSerializer};
|
||||||
use bevy_reflect::{
|
use bevy_reflect::{
|
||||||
serde::{ReflectDeserializer, TypeRegistrationDeserializer},
|
serde::{ReflectDeserializer, TypeRegistrationDeserializer},
|
||||||
Reflect, TypeRegistry, TypeRegistryArc,
|
Reflect, TypeRegistry,
|
||||||
};
|
};
|
||||||
use bevy_utils::HashSet;
|
use bevy_utils::HashSet;
|
||||||
use serde::ser::SerializeMap;
|
use serde::ser::SerializeMap;
|
||||||
@ -28,59 +28,46 @@ pub const ENTITY_STRUCT: &str = "Entity";
|
|||||||
/// Name of the serialized component field in an entity struct.
|
/// Name of the serialized component field in an entity struct.
|
||||||
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
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::*;
|
||||||
/// # use bevy_ecs::{
|
/// # use bevy_scene::{DynamicScene, serde::SceneSerializer};
|
||||||
/// # prelude::{Component, World},
|
/// # let mut world = World::default();
|
||||||
/// # reflect::{AppTypeRegistry, ReflectComponent},
|
/// # world.insert_resource(AppTypeRegistry::default());
|
||||||
/// # };
|
/// // Get the type registry
|
||||||
/// # 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.
|
|
||||||
/// let registry = world.resource::<AppTypeRegistry>();
|
/// 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 = 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> {
|
pub struct SceneSerializer<'a> {
|
||||||
/// The scene to serialize.
|
/// The scene to serialize.
|
||||||
pub scene: &'a DynamicScene,
|
pub scene: &'a DynamicScene,
|
||||||
/// Type registry in which the components and resources types used in the scene are registered.
|
/// The type registry containing the types present in the scene.
|
||||||
pub registry: &'a TypeRegistryArc,
|
pub registry: &'a TypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SceneSerializer<'a> {
|
impl<'a> SceneSerializer<'a> {
|
||||||
/// Creates a scene serializer.
|
/// Create a new serializer from a [`DynamicScene`] and an associated [`TypeRegistry`].
|
||||||
pub fn new(scene: &'a DynamicScene, registry: &'a TypeRegistryArc) -> Self {
|
///
|
||||||
|
/// 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 }
|
SceneSerializer { scene, registry }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +101,7 @@ pub struct EntitiesSerializer<'a> {
|
|||||||
/// The entities to serialize.
|
/// The entities to serialize.
|
||||||
pub entities: &'a [DynamicEntity],
|
pub entities: &'a [DynamicEntity],
|
||||||
/// Type registry in which the component types used by the entities are registered.
|
/// 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> {
|
impl<'a> Serialize for EntitiesSerializer<'a> {
|
||||||
@ -141,7 +128,7 @@ pub struct EntitySerializer<'a> {
|
|||||||
/// The entity to serialize.
|
/// The entity to serialize.
|
||||||
pub entity: &'a DynamicEntity,
|
pub entity: &'a DynamicEntity,
|
||||||
/// Type registry in which the component types used by the entity are registered.
|
/// 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> {
|
impl<'a> Serialize for EntitySerializer<'a> {
|
||||||
@ -170,7 +157,7 @@ pub struct SceneMapSerializer<'a> {
|
|||||||
/// List of boxed values of unique type to serialize.
|
/// List of boxed values of unique type to serialize.
|
||||||
pub entries: &'a [Box<dyn Reflect>],
|
pub entries: &'a [Box<dyn Reflect>],
|
||||||
/// Type registry in which the types used in `entries` are registered.
|
/// 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> {
|
impl<'a> Serialize for SceneMapSerializer<'a> {
|
||||||
@ -182,7 +169,7 @@ impl<'a> Serialize for SceneMapSerializer<'a> {
|
|||||||
for reflect in self.entries {
|
for reflect in self.entries {
|
||||||
state.serialize_entry(
|
state.serialize_entry(
|
||||||
reflect.get_represented_type_info().unwrap().type_path(),
|
reflect.get_represented_type_info().unwrap().type_path(),
|
||||||
&TypedReflectSerializer::new(&**reflect, &self.registry.read()),
|
&TypedReflectSerializer::new(&**reflect, self.registry),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
state.end()
|
state.end()
|
||||||
@ -624,7 +611,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
)"#;
|
)"#;
|
||||||
let output = scene
|
let output = scene
|
||||||
.serialize_ron(&world.resource::<AppTypeRegistry>().0)
|
.serialize(&world.resource::<AppTypeRegistry>().read())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(expected, output);
|
assert_eq!(expected, output);
|
||||||
}
|
}
|
||||||
@ -707,7 +694,7 @@ mod tests {
|
|||||||
let scene = DynamicScene::from_world(&world);
|
let scene = DynamicScene::from_world(&world);
|
||||||
|
|
||||||
let serialized = scene
|
let serialized = scene
|
||||||
.serialize_ron(&world.resource::<AppTypeRegistry>().0)
|
.serialize(&world.resource::<AppTypeRegistry>().read())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
|
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
|
||||||
let scene_deserializer = SceneDeserializer {
|
let scene_deserializer = SceneDeserializer {
|
||||||
@ -753,10 +740,11 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let registry = world.resource::<AppTypeRegistry>();
|
let registry = world.resource::<AppTypeRegistry>();
|
||||||
|
let registry = ®istry.read();
|
||||||
|
|
||||||
let scene = DynamicScene::from_world(&world);
|
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();
|
let serialized_scene = postcard::to_allocvec(&scene_serializer).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -770,7 +758,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let scene_deserializer = SceneDeserializer {
|
let scene_deserializer = SceneDeserializer {
|
||||||
type_registry: ®istry.0.read(),
|
type_registry: registry,
|
||||||
};
|
};
|
||||||
let deserialized_scene = scene_deserializer
|
let deserialized_scene = scene_deserializer
|
||||||
.deserialize(&mut postcard::Deserializer::from_bytes(&serialized_scene))
|
.deserialize(&mut postcard::Deserializer::from_bytes(&serialized_scene))
|
||||||
@ -791,10 +779,11 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let registry = world.resource::<AppTypeRegistry>();
|
let registry = world.resource::<AppTypeRegistry>();
|
||||||
|
let registry = ®istry.read();
|
||||||
|
|
||||||
let scene = DynamicScene::from_world(&world);
|
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 buf = Vec::new();
|
||||||
let mut ser = rmp_serde::Serializer::new(&mut buf);
|
let mut ser = rmp_serde::Serializer::new(&mut buf);
|
||||||
scene_serializer.serialize(&mut ser).unwrap();
|
scene_serializer.serialize(&mut ser).unwrap();
|
||||||
@ -811,7 +800,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let scene_deserializer = SceneDeserializer {
|
let scene_deserializer = SceneDeserializer {
|
||||||
type_registry: ®istry.0.read(),
|
type_registry: registry,
|
||||||
};
|
};
|
||||||
let mut reader = BufReader::new(buf.as_slice());
|
let mut reader = BufReader::new(buf.as_slice());
|
||||||
|
|
||||||
@ -834,10 +823,11 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let registry = world.resource::<AppTypeRegistry>();
|
let registry = world.resource::<AppTypeRegistry>();
|
||||||
|
let registry = ®istry.read();
|
||||||
|
|
||||||
let scene = DynamicScene::from_world(&world);
|
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();
|
let serialized_scene = bincode::serialize(&scene_serializer).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -853,7 +843,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let scene_deserializer = SceneDeserializer {
|
let scene_deserializer = SceneDeserializer {
|
||||||
type_registry: ®istry.0.read(),
|
type_registry: registry,
|
||||||
};
|
};
|
||||||
|
|
||||||
let deserialized_scene = bincode::DefaultOptions::new()
|
let deserialized_scene = bincode::DefaultOptions::new()
|
||||||
|
@ -125,7 +125,8 @@ fn save_scene_system(world: &mut World) {
|
|||||||
|
|
||||||
// Scenes can be serialized like this:
|
// Scenes can be serialized like this:
|
||||||
let type_registry = world.resource::<AppTypeRegistry>();
|
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
|
// Showing the scene in the console
|
||||||
info!("{}", serialized_scene);
|
info!("{}", serialized_scene);
|
||||||
|
Loading…
Reference in New Issue
Block a user