Skip to content

Commit

Permalink
Serialize Entity in DynamicScene
Browse files Browse the repository at this point in the history
This PR also changes `Entity` serialization to `u64`, so `DynamicScene`
will contain just a plain number as before.
  • Loading branch information
Shatur committed Apr 30, 2023
1 parent ee697f8 commit 21bf741
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 34 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_ecs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ thread_local = "1.1.4"
fixedbitset = "0.4.2"
rustc-hash = "1.1"
downcast-rs = "1.2"
serde = { version = "1", features = ["derive"] }
serde = "1"
thiserror = "1.0"

[dev-dependencies]
Expand Down
21 changes: 20 additions & 1 deletion crates/bevy_ecs/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ type IdCursor = isize;
/// [`EntityCommands`]: crate::system::EntityCommands
/// [`Query::get`]: crate::system::Query::get
/// [`World`]: crate::world::World
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Entity {
generation: u32,
index: u32,
Expand Down Expand Up @@ -233,6 +233,25 @@ impl fmt::Debug for Entity {
}
}

impl Serialize for Entity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_u64(self.to_bits())
}
}

impl<'de> Deserialize<'de> for Entity {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let id: u64 = serde::de::Deserialize::deserialize(deserializer)?;
Ok(Entity::from_bits(id))
}
}

impl SparseSetIndex for Entity {
#[inline]
fn sparse_set_index(&self) -> usize {
Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_scene/src/dynamic_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ pub struct DynamicScene {

/// A reflection-powered serializable representation of an entity and its components.
pub struct DynamicEntity {
/// The transiently unique identifier of a corresponding [`Entity`](bevy_ecs::entity::Entity).
pub entity: u32,
/// The identifier of the entity, unique within a scene (and the world it may have been generated from).
///
/// Components that reference this entity must consistently use this identifier.
pub entity: Entity,
/// A vector of boxed components that belong to the given entity and
/// implement the [`Reflect`] trait.
pub components: Vec<Box<dyn Reflect>>,
Expand Down Expand Up @@ -101,7 +103,7 @@ impl DynamicScene {
// or spawn a new entity with a transiently unique id if there is
// no corresponding entry.
let entity = *entity_map
.entry(bevy_ecs::entity::Entity::from_raw(scene_entity.entity))
.entry(scene_entity.entity)
.or_insert_with(|| world.spawn_empty().id());
let entity_mut = &mut world.entity_mut(entity);

Expand Down
28 changes: 13 additions & 15 deletions crates/bevy_scene/src/dynamic_scene_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use std::collections::BTreeMap;
/// ```
pub struct DynamicSceneBuilder<'w> {
extracted_resources: BTreeMap<ComponentId, Box<dyn Reflect>>,
extracted_scene: BTreeMap<u32, DynamicEntity>,
extracted_scene: BTreeMap<Entity, DynamicEntity>,
type_registry: AppTypeRegistry,
original_world: &'w World,
}
Expand Down Expand Up @@ -123,14 +123,12 @@ impl<'w> DynamicSceneBuilder<'w> {
let type_registry = self.type_registry.read();

for entity in entities {
let index = entity.index();

if self.extracted_scene.contains_key(&index) {
if self.extracted_scene.contains_key(&entity) {
continue;
}

let mut entry = DynamicEntity {
entity: index,
entity,
components: Vec::new(),
};

Expand All @@ -151,7 +149,7 @@ impl<'w> DynamicSceneBuilder<'w> {
};
extract_and_push();
}
self.extracted_scene.insert(index, entry);
self.extracted_scene.insert(entity.id(), entry);
}

drop(type_registry);
Expand Down Expand Up @@ -243,7 +241,7 @@ mod tests {
let scene = builder.build();

assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity.index());
assert_eq!(scene.entities[0].entity, entity);
assert_eq!(scene.entities[0].components.len(), 1);
assert!(scene.entities[0].components[0].represents::<ComponentA>());
}
Expand All @@ -264,7 +262,7 @@ mod tests {
let scene = builder.build();

assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity.index());
assert_eq!(scene.entities[0].entity, entity);
assert_eq!(scene.entities[0].components.len(), 1);
assert!(scene.entities[0].components[0].represents::<ComponentA>());
}
Expand All @@ -288,7 +286,7 @@ mod tests {
let scene = builder.build();

assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity.index());
assert_eq!(scene.entities[0].entity, entity);
assert_eq!(scene.entities[0].components.len(), 2);
assert!(scene.entities[0].components[0].represents::<ComponentA>());
assert!(scene.entities[0].components[1].represents::<ComponentB>());
Expand All @@ -315,10 +313,10 @@ mod tests {
let mut entities = builder.build().entities.into_iter();

// Assert entities are ordered
assert_eq!(entity_a.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_b.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_c.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_d.index(), entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_a, entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_b, entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_c, entities.next().map(|e| e.entity).unwrap());
assert_eq!(entity_d, entities.next().map(|e| e.entity).unwrap());
}

#[test]
Expand All @@ -345,7 +343,7 @@ mod tests {
assert_eq!(scene.entities.len(), 2);
let mut scene_entities = vec![scene.entities[0].entity, scene.entities[1].entity];
scene_entities.sort();
assert_eq!(scene_entities, [entity_a_b.index(), entity_a.index()]);
assert_eq!(scene_entities, [entity_a_b, entity_a]);
}

#[test]
Expand All @@ -365,7 +363,7 @@ mod tests {
let scene = builder.build();

assert_eq!(scene.entities.len(), 1);
assert_eq!(scene.entities[0].entity, entity_a.index());
assert_eq!(scene.entities[0].entity, entity_a);
}

#[test]
Expand Down
29 changes: 15 additions & 14 deletions crates/bevy_scene/src/serde.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{DynamicEntity, DynamicScene};
use anyhow::Result;
use bevy_ecs::prelude::Entity;
use bevy_reflect::serde::{TypedReflectDeserializer, TypedReflectSerializer};
use bevy_reflect::{
serde::{TypeRegistrationDeserializer, UntypedReflectDeserializer},
Expand Down Expand Up @@ -260,9 +261,9 @@ impl<'a, 'de> Visitor<'de> for SceneEntitiesVisitor<'a> {
A: MapAccess<'de>,
{
let mut entities = Vec::new();
while let Some(id) = map.next_key::<u32>()? {
while let Some(entity) = map.next_key::<Entity>()? {
let entity = map.next_value_seed(SceneEntityDeserializer {
id,
entity,
type_registry: self.type_registry,
})?;
entities.push(entity);
Expand All @@ -273,7 +274,7 @@ impl<'a, 'de> Visitor<'de> for SceneEntitiesVisitor<'a> {
}

pub struct SceneEntityDeserializer<'a> {
pub id: u32,
pub entity: Entity,
pub type_registry: &'a TypeRegistry,
}

Expand All @@ -288,15 +289,15 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
ENTITY_STRUCT,
&[ENTITY_FIELD_COMPONENTS],
SceneEntityVisitor {
id: self.id,
entity: self.entity,
registry: self.type_registry,
},
)
}
}

struct SceneEntityVisitor<'a> {
pub id: u32,
pub entity: Entity,
pub registry: &'a TypeRegistry,
}

Expand All @@ -318,7 +319,7 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisitor<'a> {
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?;

Ok(DynamicEntity {
entity: self.id,
entity: self.entity,
components,
})
}
Expand Down Expand Up @@ -346,7 +347,7 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisitor<'a> {
.take()
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?;
Ok(DynamicEntity {
entity: self.id,
entity: self.entity,
components,
})
}
Expand Down Expand Up @@ -696,12 +697,12 @@ mod tests {

assert_eq!(
vec![
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
37, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 115, 99, 101, 110, 101, 58, 58,
115, 101, 114, 100, 101, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77, 121, 67, 111,
109, 112, 111, 110, 101, 110, 116, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0, 102, 102, 166, 63, 205, 204, 108, 64, 1, 0, 0, 0, 12, 0, 0,
0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 115, 99, 101, 110, 101,
58, 58, 115, 101, 114, 100, 101, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77, 121,
67, 111, 109, 112, 111, 110, 101, 110, 116, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 102, 102, 166, 63, 205, 204, 108, 64, 1, 0, 0, 0,
12, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33
],
serialized_scene
);
Expand Down Expand Up @@ -732,7 +733,7 @@ mod tests {
.entities
.iter()
.find(|dynamic_entity| dynamic_entity.entity == expected.entity)
.unwrap_or_else(|| panic!("missing entity (expected: `{}`)", expected.entity));
.unwrap_or_else(|| panic!("missing entity (expected: `{:?}`)", expected.entity));

assert_eq!(expected.entity, received.entity, "entities did not match",);

Expand Down

0 comments on commit 21bf741

Please sign in to comment.