mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
bevy_scene: Replace root list with struct (#6354)
# Objective Scenes are currently represented as a list of entities. This is all we need currently, but we may want to add more data to this format in the future (metadata, asset lists, etc.). It would be nice to update the format in preparation of possible future changes. Doing so now (i.e., before 0.9) could mean reduced[^1] breakage for things added in 0.10. [^1]: Obviously, adding features runs the risk of breaking things regardless. But if all features added are for whatever reason optional or well-contained, then users should at least have an easier time updating. ## Solution Made the scene root a struct rather than a list. ```rust ( entities: [ // Entity data here... ] ) ``` --- ## Changelog * The scene format now puts the entity list in a newly added `entities` field, rather than having it be the root object ## Migration Guide The scene file format now uses a struct as the root object rather than a list of entities. The list of entities is now found in the `entities` field of this struct. ```rust // OLD [ ( entity: 0, components: [ // Components... ] ), ] // NEW ( entities: [ ( entity: 0, components: [ // Components... ] ), ] ) ``` Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
This commit is contained in:
parent
f6b03aa27c
commit
beab0bdc63
2 changed files with 159 additions and 58 deletions
|
@ -1,44 +1,46 @@
|
||||||
[
|
(
|
||||||
(
|
entities: [
|
||||||
entity: 0,
|
(
|
||||||
components: [
|
entity: 0,
|
||||||
{
|
components: [
|
||||||
"bevy_transform::components::transform::Transform": (
|
{
|
||||||
translation: (
|
"bevy_transform::components::transform::Transform": (
|
||||||
x: 0.0,
|
translation: (
|
||||||
y: 0.0,
|
x: 0.0,
|
||||||
z: 0.0
|
y: 0.0,
|
||||||
|
z: 0.0
|
||||||
|
),
|
||||||
|
rotation: (0.0, 0.0, 0.0, 1.0),
|
||||||
|
scale: (
|
||||||
|
x: 1.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: 1.0
|
||||||
|
),
|
||||||
),
|
),
|
||||||
rotation: (0.0, 0.0, 0.0, 1.0),
|
},
|
||||||
scale: (
|
{
|
||||||
|
"scene::ComponentB": (
|
||||||
|
value: "hello",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"scene::ComponentA": (
|
||||||
x: 1.0,
|
x: 1.0,
|
||||||
y: 1.0,
|
y: 2.0,
|
||||||
z: 1.0
|
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
],
|
||||||
{
|
),
|
||||||
"scene::ComponentB": (
|
(
|
||||||
value: "hello",
|
entity: 1,
|
||||||
),
|
components: [
|
||||||
},
|
{
|
||||||
{
|
"scene::ComponentA": (
|
||||||
"scene::ComponentA": (
|
x: 3.0,
|
||||||
x: 1.0,
|
y: 4.0,
|
||||||
y: 2.0,
|
),
|
||||||
),
|
},
|
||||||
},
|
],
|
||||||
],
|
),
|
||||||
),
|
]
|
||||||
(
|
)
|
||||||
entity: 1,
|
|
||||||
components: [
|
|
||||||
{
|
|
||||||
"scene::ComponentA": (
|
|
||||||
x: 3.0,
|
|
||||||
y: 4.0,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
|
@ -7,8 +7,16 @@ use bevy_reflect::{
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
|
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
|
||||||
ser::{SerializeSeq, SerializeStruct},
|
ser::{SerializeSeq, SerializeStruct},
|
||||||
Deserialize, Serialize,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
|
||||||
|
pub const SCENE_STRUCT: &str = "Scene";
|
||||||
|
pub const SCENE_ENTITIES: &str = "entities";
|
||||||
|
|
||||||
|
pub const ENTITY_STRUCT: &str = "Entity";
|
||||||
|
pub const ENTITY_FIELD_ENTITY: &str = "entity";
|
||||||
|
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
||||||
|
|
||||||
pub struct SceneSerializer<'a> {
|
pub struct SceneSerializer<'a> {
|
||||||
pub scene: &'a DynamicScene,
|
pub scene: &'a DynamicScene,
|
||||||
|
@ -26,8 +34,30 @@ impl<'a> Serialize for SceneSerializer<'a> {
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut state = serializer.serialize_seq(Some(self.scene.entities.len()))?;
|
let mut state = serializer.serialize_struct(SCENE_STRUCT, 1)?;
|
||||||
for entity in &self.scene.entities {
|
state.serialize_field(
|
||||||
|
SCENE_ENTITIES,
|
||||||
|
&EntitiesSerializer {
|
||||||
|
entities: &self.scene.entities,
|
||||||
|
registry: self.registry,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EntitiesSerializer<'a> {
|
||||||
|
pub entities: &'a [DynamicEntity],
|
||||||
|
pub registry: &'a TypeRegistryArc,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for EntitiesSerializer<'a> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut state = serializer.serialize_seq(Some(self.entities.len()))?;
|
||||||
|
for entity in self.entities {
|
||||||
state.serialize_element(&EntitySerializer {
|
state.serialize_element(&EntitySerializer {
|
||||||
entity,
|
entity,
|
||||||
registry: self.registry,
|
registry: self.registry,
|
||||||
|
@ -81,6 +111,19 @@ impl<'a> Serialize for ComponentsSerializer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(field_identifier, rename_all = "lowercase")]
|
||||||
|
enum SceneField {
|
||||||
|
Entities,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(field_identifier, rename_all = "lowercase")]
|
||||||
|
enum EntityField {
|
||||||
|
Entity,
|
||||||
|
Components,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SceneDeserializer<'a> {
|
pub struct SceneDeserializer<'a> {
|
||||||
pub type_registry: &'a TypeRegistry,
|
pub type_registry: &'a TypeRegistry,
|
||||||
}
|
}
|
||||||
|
@ -92,10 +135,77 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> {
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
Ok(DynamicScene {
|
deserializer.deserialize_struct(
|
||||||
entities: deserializer.deserialize_seq(SceneEntitySeqVisitor {
|
SCENE_STRUCT,
|
||||||
|
&[SCENE_ENTITIES],
|
||||||
|
SceneVisitor {
|
||||||
type_registry: self.type_registry,
|
type_registry: self.type_registry,
|
||||||
})?,
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SceneVisitor<'a> {
|
||||||
|
pub type_registry: &'a TypeRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'de> Visitor<'de> for SceneVisitor<'a> {
|
||||||
|
type Value = DynamicScene;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("scene struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut entities = None;
|
||||||
|
while let Some(key) = map.next_key()? {
|
||||||
|
match key {
|
||||||
|
SceneField::Entities => {
|
||||||
|
if entities.is_some() {
|
||||||
|
return Err(Error::duplicate_field(SCENE_ENTITIES));
|
||||||
|
}
|
||||||
|
entities = Some(map.next_value_seed(SceneEntitySeqDeserializer {
|
||||||
|
type_registry: self.type_registry,
|
||||||
|
})?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let entities = entities.ok_or_else(|| Error::missing_field(SCENE_ENTITIES))?;
|
||||||
|
|
||||||
|
Ok(DynamicScene { entities })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
let entities = seq
|
||||||
|
.next_element_seed(SceneEntitySeqDeserializer {
|
||||||
|
type_registry: self.type_registry,
|
||||||
|
})?
|
||||||
|
.ok_or_else(|| Error::missing_field(SCENE_ENTITIES))?;
|
||||||
|
|
||||||
|
Ok(DynamicScene { entities })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SceneEntitySeqDeserializer<'a> {
|
||||||
|
pub type_registry: &'a TypeRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'de> DeserializeSeed<'de> for SceneEntitySeqDeserializer<'a> {
|
||||||
|
type Value = Vec<DynamicEntity>;
|
||||||
|
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_seq(SceneEntitySeqVisitor {
|
||||||
|
type_registry: self.type_registry,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,17 +257,6 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(field_identifier, rename_all = "lowercase")]
|
|
||||||
enum EntityField {
|
|
||||||
Entity,
|
|
||||||
Components,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ENTITY_STRUCT: &str = "Entity";
|
|
||||||
pub const ENTITY_FIELD_ENTITY: &str = "entity";
|
|
||||||
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
|
||||||
|
|
||||||
struct SceneEntityVisitor<'a> {
|
struct SceneEntityVisitor<'a> {
|
||||||
pub registry: &'a TypeRegistry,
|
pub registry: &'a TypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue