entity cloning and mapping
This commit is contained in:
parent
8556b190f3
commit
f4e06add26
@ -8,12 +8,14 @@ use crate::{
|
|||||||
archetype::Archetype,
|
archetype::Archetype,
|
||||||
bundle::Bundle,
|
bundle::Bundle,
|
||||||
component::{Component, ComponentCloneBehavior, ComponentCloneFn, ComponentId, ComponentInfo},
|
component::{Component, ComponentCloneBehavior, ComponentCloneFn, ComponentId, ComponentInfo},
|
||||||
entity::{hash_map::EntityHashMap, Entities, Entity, EntityMapper},
|
entity::{hash_map::EntityHashMap, Entity, EntityMapper},
|
||||||
query::DebugCheckedUnwrap,
|
query::DebugCheckedUnwrap,
|
||||||
relationship::RelationshipHookMode,
|
relationship::RelationshipHookMode,
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::EntitiesAllocator;
|
||||||
|
|
||||||
/// Provides read access to the source component (the component being cloned) in a [`ComponentCloneFn`].
|
/// Provides read access to the source component (the component being cloned) in a [`ComponentCloneFn`].
|
||||||
pub struct SourceComponent<'a> {
|
pub struct SourceComponent<'a> {
|
||||||
ptr: Ptr<'a>,
|
ptr: Ptr<'a>,
|
||||||
@ -76,7 +78,7 @@ pub struct ComponentCloneCtx<'a, 'b> {
|
|||||||
target_component_written: bool,
|
target_component_written: bool,
|
||||||
bundle_scratch: &'a mut BundleScratch<'b>,
|
bundle_scratch: &'a mut BundleScratch<'b>,
|
||||||
bundle_scratch_allocator: &'b Bump,
|
bundle_scratch_allocator: &'b Bump,
|
||||||
entities: &'a Entities,
|
allocator: &'a EntitiesAllocator,
|
||||||
source: Entity,
|
source: Entity,
|
||||||
target: Entity,
|
target: Entity,
|
||||||
component_info: &'a ComponentInfo,
|
component_info: &'a ComponentInfo,
|
||||||
@ -102,7 +104,7 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
|||||||
target: Entity,
|
target: Entity,
|
||||||
bundle_scratch_allocator: &'b Bump,
|
bundle_scratch_allocator: &'b Bump,
|
||||||
bundle_scratch: &'a mut BundleScratch<'b>,
|
bundle_scratch: &'a mut BundleScratch<'b>,
|
||||||
entities: &'a Entities,
|
allocator: &'a EntitiesAllocator,
|
||||||
component_info: &'a ComponentInfo,
|
component_info: &'a ComponentInfo,
|
||||||
entity_cloner: &'a mut EntityCloner,
|
entity_cloner: &'a mut EntityCloner,
|
||||||
mapper: &'a mut dyn EntityMapper,
|
mapper: &'a mut dyn EntityMapper,
|
||||||
@ -116,7 +118,7 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
|||||||
bundle_scratch,
|
bundle_scratch,
|
||||||
target_component_written: false,
|
target_component_written: false,
|
||||||
bundle_scratch_allocator,
|
bundle_scratch_allocator,
|
||||||
entities,
|
allocator,
|
||||||
mapper,
|
mapper,
|
||||||
component_info,
|
component_info,
|
||||||
entity_cloner,
|
entity_cloner,
|
||||||
@ -268,7 +270,7 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
|||||||
|
|
||||||
/// Queues the `entity` to be cloned by the current [`EntityCloner`]
|
/// Queues the `entity` to be cloned by the current [`EntityCloner`]
|
||||||
pub fn queue_entity_clone(&mut self, entity: Entity) {
|
pub fn queue_entity_clone(&mut self, entity: Entity) {
|
||||||
let target = self.entities.reserve_entity();
|
let target = self.allocator.alloc();
|
||||||
self.mapper.set_mapped(entity, target);
|
self.mapper.set_mapped(entity, target);
|
||||||
self.entity_cloner.clone_queue.push_back(entity);
|
self.entity_cloner.clone_queue.push_back(entity);
|
||||||
}
|
}
|
||||||
@ -521,7 +523,7 @@ impl EntityCloner {
|
|||||||
target,
|
target,
|
||||||
&bundle_scratch_allocator,
|
&bundle_scratch_allocator,
|
||||||
&mut bundle_scratch,
|
&mut bundle_scratch,
|
||||||
world.entities(),
|
world.entities_allocator(),
|
||||||
info,
|
info,
|
||||||
self,
|
self,
|
||||||
mapper,
|
mapper,
|
||||||
@ -539,10 +541,6 @@ impl EntityCloner {
|
|||||||
(deferred)(world, mapper);
|
(deferred)(world, mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !world.entities.contains(target) {
|
|
||||||
panic!("Target entity does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.move_components {
|
if self.move_components {
|
||||||
world
|
world
|
||||||
.entity_mut(source)
|
.entity_mut(source)
|
||||||
|
|||||||
@ -53,7 +53,7 @@ use super::EntityIndexSet;
|
|||||||
pub trait MapEntities {
|
pub trait MapEntities {
|
||||||
/// Updates all [`Entity`] references stored inside using `entity_mapper`.
|
/// Updates all [`Entity`] references stored inside using `entity_mapper`.
|
||||||
///
|
///
|
||||||
/// Implementors should look up any and all [`Entity`] values stored within `self` and
|
/// Implementers should look up any and all [`Entity`] values stored within `self` and
|
||||||
/// update them to the mapped values via `entity_mapper`.
|
/// update them to the mapped values via `entity_mapper`.
|
||||||
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E);
|
fn map_entities<E: EntityMapper>(&mut self, entity_mapper: &mut E);
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ impl<T: MapEntities, A: smallvec::Array<Item = T>> MapEntities for SmallVec<A> {
|
|||||||
///
|
///
|
||||||
/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
|
/// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World).
|
||||||
///
|
///
|
||||||
/// This is used by [`MapEntities`] implementors.
|
/// This is used by [`MapEntities`] implementers.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
@ -286,14 +286,10 @@ impl<'m> SceneEntityMapper<'m> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
|
/// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`]
|
||||||
pub fn new(map: &'m mut EntityHashMap<Entity>, world: &mut World) -> Self {
|
pub fn new(map: &'m mut EntityHashMap<Entity>, world: &World) -> Self {
|
||||||
// We're going to be calling methods on `Entities` that require advance
|
|
||||||
// flushing, such as `alloc` and `free`.
|
|
||||||
world.flush_entities();
|
|
||||||
Self {
|
Self {
|
||||||
map,
|
map,
|
||||||
// SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope`
|
dead_start: world.allocator.alloc(),
|
||||||
dead_start: unsafe { world.entities_mut().alloc() },
|
|
||||||
generations: 0,
|
generations: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,10 +298,10 @@ impl<'m> SceneEntityMapper<'m> {
|
|||||||
/// [`Entity`] while reserving extra generations. Because this makes the [`SceneEntityMapper`] unable to
|
/// [`Entity`] while reserving extra generations. Because this makes the [`SceneEntityMapper`] unable to
|
||||||
/// safely allocate any more references, this method takes ownership of `self` in order to render it unusable.
|
/// safely allocate any more references, this method takes ownership of `self` in order to render it unusable.
|
||||||
pub fn finish(self, world: &mut World) {
|
pub fn finish(self, world: &mut World) {
|
||||||
// SAFETY: Entities data is kept in a valid state via `EntityMap::world_scope`
|
// SAFETY: We never constructed the entity and never released it for something else to construct.
|
||||||
let entities = unsafe { world.entities_mut() };
|
unsafe {
|
||||||
assert!(entities.free(self.dead_start).is_some());
|
world.release_generations_unchecked(self.dead_start.row(), self.generations);
|
||||||
assert!(entities.reserve_generations(self.dead_start.index(), self.generations));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
|
/// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap<Entity>`], then calls the
|
||||||
@ -375,21 +371,4 @@ mod tests {
|
|||||||
assert_eq!(entity.index(), dead_ref.index());
|
assert_eq!(entity.index(), dead_ref.index());
|
||||||
assert!(entity.generation() > dead_ref.generation());
|
assert!(entity.generation() > dead_ref.generation());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn entity_mapper_no_panic() {
|
|
||||||
let mut world = World::new();
|
|
||||||
// "Dirty" the `Entities`, requiring a flush afterward.
|
|
||||||
world.entities.reserve_entity();
|
|
||||||
assert!(world.entities.needs_flush());
|
|
||||||
|
|
||||||
// Create and exercise a SceneEntityMapper - should not panic because it flushes
|
|
||||||
// `Entities` first.
|
|
||||||
SceneEntityMapper::world_scope(&mut Default::default(), &mut world, |_, m| {
|
|
||||||
m.get_mapped(Entity::PLACEHOLDER);
|
|
||||||
});
|
|
||||||
|
|
||||||
// The SceneEntityMapper should leave `Entities` in a flushed state.
|
|
||||||
assert!(!world.entities.needs_flush());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2784,7 +2784,7 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
self.assert_not_despawned();
|
self.assert_not_despawned();
|
||||||
self.world.flush();
|
self.world.flush();
|
||||||
|
|
||||||
let entity_clone = self.world.allocator.alloc();
|
let entity_clone = self.world.spawn_empty().id();
|
||||||
|
|
||||||
let mut builder = EntityCloner::build(self.world);
|
let mut builder = EntityCloner::build(self.world);
|
||||||
config(&mut builder);
|
config(&mut builder);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user