diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index cfcea53b3644c..c19073b2c97ae 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -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] diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index 0dcbe44581beb..adbebf42f37da 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -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, @@ -233,6 +233,25 @@ impl fmt::Debug for Entity { } } +impl Serialize for Entity { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_u64(self.to_bits()) + } +} + +impl<'de> Deserialize<'de> for Entity { + fn deserialize(deserializer: D) -> Result + 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 { diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index 0a45e0e82b9d8..c621c5acd65a7 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -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>, @@ -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); diff --git a/crates/bevy_scene/src/dynamic_scene_builder.rs b/crates/bevy_scene/src/dynamic_scene_builder.rs index 0f25b1e484ba3..fabd0baa461ec 100644 --- a/crates/bevy_scene/src/dynamic_scene_builder.rs +++ b/crates/bevy_scene/src/dynamic_scene_builder.rs @@ -38,7 +38,7 @@ use std::collections::BTreeMap; /// ``` pub struct DynamicSceneBuilder<'w> { extracted_resources: BTreeMap>, - extracted_scene: BTreeMap, + extracted_scene: BTreeMap, type_registry: AppTypeRegistry, original_world: &'w World, } @@ -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(), }; @@ -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); @@ -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::()); } @@ -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::()); } @@ -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::()); assert!(scene.entities[0].components[1].represents::()); @@ -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] @@ -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] @@ -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] diff --git a/crates/bevy_scene/src/serde.rs b/crates/bevy_scene/src/serde.rs index debe7c54515f3..dc5a46683af6a 100644 --- a/crates/bevy_scene/src/serde.rs +++ b/crates/bevy_scene/src/serde.rs @@ -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}, @@ -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::()? { + while let Some(entity) = map.next_key::()? { let entity = map.next_value_seed(SceneEntityDeserializer { - id, + entity, type_registry: self.type_registry, })?; entities.push(entity); @@ -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, } @@ -288,7 +289,7 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> { ENTITY_STRUCT, &[ENTITY_FIELD_COMPONENTS], SceneEntityVisitor { - id: self.id, + entity: self.entity, registry: self.type_registry, }, ) @@ -296,7 +297,7 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> { } struct SceneEntityVisitor<'a> { - pub id: u32, + pub entity: Entity, pub registry: &'a TypeRegistry, } @@ -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, }) } @@ -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, }) } @@ -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 ); @@ -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",);