Skip to content

Commit beab0bd

Browse files
committed
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 <[email protected]>
1 parent f6b03aa commit beab0bd

File tree

2 files changed

+159
-58
lines changed

2 files changed

+159
-58
lines changed
Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,46 @@
1-
[
2-
(
3-
entity: 0,
4-
components: [
5-
{
6-
"bevy_transform::components::transform::Transform": (
7-
translation: (
8-
x: 0.0,
9-
y: 0.0,
10-
z: 0.0
1+
(
2+
entities: [
3+
(
4+
entity: 0,
5+
components: [
6+
{
7+
"bevy_transform::components::transform::Transform": (
8+
translation: (
9+
x: 0.0,
10+
y: 0.0,
11+
z: 0.0
12+
),
13+
rotation: (0.0, 0.0, 0.0, 1.0),
14+
scale: (
15+
x: 1.0,
16+
y: 1.0,
17+
z: 1.0
18+
),
1119
),
12-
rotation: (0.0, 0.0, 0.0, 1.0),
13-
scale: (
20+
},
21+
{
22+
"scene::ComponentB": (
23+
value: "hello",
24+
),
25+
},
26+
{
27+
"scene::ComponentA": (
1428
x: 1.0,
15-
y: 1.0,
16-
z: 1.0
29+
y: 2.0,
30+
),
31+
},
32+
],
33+
),
34+
(
35+
entity: 1,
36+
components: [
37+
{
38+
"scene::ComponentA": (
39+
x: 3.0,
40+
y: 4.0,
1741
),
18-
),
19-
},
20-
{
21-
"scene::ComponentB": (
22-
value: "hello",
23-
),
24-
},
25-
{
26-
"scene::ComponentA": (
27-
x: 1.0,
28-
y: 2.0,
29-
),
30-
},
31-
],
32-
),
33-
(
34-
entity: 1,
35-
components: [
36-
{
37-
"scene::ComponentA": (
38-
x: 3.0,
39-
y: 4.0,
40-
),
41-
},
42-
],
43-
),
44-
]
42+
},
43+
],
44+
),
45+
]
46+
)

crates/bevy_scene/src/serde.rs

Lines changed: 116 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@ use bevy_reflect::{
77
use serde::{
88
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
99
ser::{SerializeSeq, SerializeStruct},
10-
Deserialize, Serialize,
10+
Deserialize, Deserializer, Serialize, Serializer,
1111
};
12+
use std::fmt::Formatter;
13+
14+
pub const SCENE_STRUCT: &str = "Scene";
15+
pub const SCENE_ENTITIES: &str = "entities";
16+
17+
pub const ENTITY_STRUCT: &str = "Entity";
18+
pub const ENTITY_FIELD_ENTITY: &str = "entity";
19+
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
1220

1321
pub struct SceneSerializer<'a> {
1422
pub scene: &'a DynamicScene,
@@ -26,8 +34,30 @@ impl<'a> Serialize for SceneSerializer<'a> {
2634
where
2735
S: serde::Serializer,
2836
{
29-
let mut state = serializer.serialize_seq(Some(self.scene.entities.len()))?;
30-
for entity in &self.scene.entities {
37+
let mut state = serializer.serialize_struct(SCENE_STRUCT, 1)?;
38+
state.serialize_field(
39+
SCENE_ENTITIES,
40+
&EntitiesSerializer {
41+
entities: &self.scene.entities,
42+
registry: self.registry,
43+
},
44+
)?;
45+
state.end()
46+
}
47+
}
48+
49+
pub struct EntitiesSerializer<'a> {
50+
pub entities: &'a [DynamicEntity],
51+
pub registry: &'a TypeRegistryArc,
52+
}
53+
54+
impl<'a> Serialize for EntitiesSerializer<'a> {
55+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56+
where
57+
S: Serializer,
58+
{
59+
let mut state = serializer.serialize_seq(Some(self.entities.len()))?;
60+
for entity in self.entities {
3161
state.serialize_element(&EntitySerializer {
3262
entity,
3363
registry: self.registry,
@@ -81,6 +111,19 @@ impl<'a> Serialize for ComponentsSerializer<'a> {
81111
}
82112
}
83113

114+
#[derive(Deserialize)]
115+
#[serde(field_identifier, rename_all = "lowercase")]
116+
enum SceneField {
117+
Entities,
118+
}
119+
120+
#[derive(Deserialize)]
121+
#[serde(field_identifier, rename_all = "lowercase")]
122+
enum EntityField {
123+
Entity,
124+
Components,
125+
}
126+
84127
pub struct SceneDeserializer<'a> {
85128
pub type_registry: &'a TypeRegistry,
86129
}
@@ -92,10 +135,77 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> {
92135
where
93136
D: serde::Deserializer<'de>,
94137
{
95-
Ok(DynamicScene {
96-
entities: deserializer.deserialize_seq(SceneEntitySeqVisitor {
138+
deserializer.deserialize_struct(
139+
SCENE_STRUCT,
140+
&[SCENE_ENTITIES],
141+
SceneVisitor {
142+
type_registry: self.type_registry,
143+
},
144+
)
145+
}
146+
}
147+
148+
struct SceneVisitor<'a> {
149+
pub type_registry: &'a TypeRegistry,
150+
}
151+
152+
impl<'a, 'de> Visitor<'de> for SceneVisitor<'a> {
153+
type Value = DynamicScene;
154+
155+
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
156+
formatter.write_str("scene struct")
157+
}
158+
159+
fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
160+
where
161+
A: MapAccess<'de>,
162+
{
163+
let mut entities = None;
164+
while let Some(key) = map.next_key()? {
165+
match key {
166+
SceneField::Entities => {
167+
if entities.is_some() {
168+
return Err(Error::duplicate_field(SCENE_ENTITIES));
169+
}
170+
entities = Some(map.next_value_seed(SceneEntitySeqDeserializer {
171+
type_registry: self.type_registry,
172+
})?);
173+
}
174+
}
175+
}
176+
177+
let entities = entities.ok_or_else(|| Error::missing_field(SCENE_ENTITIES))?;
178+
179+
Ok(DynamicScene { entities })
180+
}
181+
182+
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
183+
where
184+
A: SeqAccess<'de>,
185+
{
186+
let entities = seq
187+
.next_element_seed(SceneEntitySeqDeserializer {
97188
type_registry: self.type_registry,
98-
})?,
189+
})?
190+
.ok_or_else(|| Error::missing_field(SCENE_ENTITIES))?;
191+
192+
Ok(DynamicScene { entities })
193+
}
194+
}
195+
196+
pub struct SceneEntitySeqDeserializer<'a> {
197+
pub type_registry: &'a TypeRegistry,
198+
}
199+
200+
impl<'a, 'de> DeserializeSeed<'de> for SceneEntitySeqDeserializer<'a> {
201+
type Value = Vec<DynamicEntity>;
202+
203+
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
204+
where
205+
D: Deserializer<'de>,
206+
{
207+
deserializer.deserialize_seq(SceneEntitySeqVisitor {
208+
type_registry: self.type_registry,
99209
})
100210
}
101211
}
@@ -147,17 +257,6 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
147257
}
148258
}
149259

150-
#[derive(Deserialize)]
151-
#[serde(field_identifier, rename_all = "lowercase")]
152-
enum EntityField {
153-
Entity,
154-
Components,
155-
}
156-
157-
pub const ENTITY_STRUCT: &str = "Entity";
158-
pub const ENTITY_FIELD_ENTITY: &str = "entity";
159-
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
160-
161260
struct SceneEntityVisitor<'a> {
162261
pub registry: &'a TypeRegistry,
163262
}

0 commit comments

Comments
 (0)