Support skipping Relationship on_replace hooks (#18378)
# Objective Fixes #18357 ## Solution Generalize `RelationshipInsertHookMode` to `RelationshipHookMode`, wire it up to on_replace execution, and use it in the `Relationship::on_replace` hook.
This commit is contained in:
parent
ac53e4c482
commit
6d6054116a
@ -18,7 +18,7 @@ use crate::{
|
||||
observer::Observers,
|
||||
prelude::World,
|
||||
query::DebugCheckedUnwrap,
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, EntityWorldMut, ON_ADD, ON_INSERT, ON_REPLACE},
|
||||
};
|
||||
@ -1104,7 +1104,7 @@ impl<'w> BundleInserter<'w> {
|
||||
bundle: T,
|
||||
insert_mode: InsertMode,
|
||||
caller: MaybeLocation,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) -> (EntityLocation, T::Effect) {
|
||||
let bundle_info = self.bundle_info.as_ref();
|
||||
let archetype_after_insert = self.archetype_after_insert.as_ref();
|
||||
@ -1130,6 +1130,7 @@ impl<'w> BundleInserter<'w> {
|
||||
entity,
|
||||
archetype_after_insert.iter_existing(),
|
||||
caller,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1317,7 +1318,7 @@ impl<'w> BundleInserter<'w> {
|
||||
entity,
|
||||
archetype_after_insert.iter_inserted(),
|
||||
caller,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
if new_archetype.has_insert_observer() {
|
||||
deferred_world.trigger_observers(
|
||||
@ -1336,7 +1337,7 @@ impl<'w> BundleInserter<'w> {
|
||||
entity,
|
||||
archetype_after_insert.iter_added(),
|
||||
caller,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
if new_archetype.has_insert_observer() {
|
||||
deferred_world.trigger_observers(
|
||||
@ -1484,7 +1485,7 @@ impl<'w> BundleSpawner<'w> {
|
||||
entity,
|
||||
bundle_info.iter_contributed_components(),
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
);
|
||||
if archetype.has_insert_observer() {
|
||||
deferred_world.trigger_observers(
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
change_detection::{MaybeLocation, MAX_CHANGE_AGE},
|
||||
entity::{ComponentCloneCtx, Entity, SourceComponent},
|
||||
query::DebugCheckedUnwrap,
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
resource::Resource,
|
||||
storage::{SparseSetIndex, SparseSets, Table, TableRow},
|
||||
system::{Commands, Local, SystemParam},
|
||||
@ -584,7 +584,7 @@ pub struct HookContext {
|
||||
/// The caller location is `Some` if the `track_caller` feature is enabled.
|
||||
pub caller: MaybeLocation,
|
||||
/// Configures how relationship hooks will run
|
||||
pub relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
pub relationship_hook_mode: RelationshipHookMode,
|
||||
}
|
||||
|
||||
/// [`World`]-mutating functions that run as part of lifecycle events of a [`Component`].
|
||||
|
@ -10,7 +10,7 @@ use alloc::boxed::Box;
|
||||
use crate::component::{ComponentCloneBehavior, ComponentCloneFn};
|
||||
use crate::entity::hash_map::EntityHashMap;
|
||||
use crate::entity::{Entities, EntityMapper};
|
||||
use crate::relationship::RelationshipInsertHookMode;
|
||||
use crate::relationship::RelationshipHookMode;
|
||||
use crate::system::Commands;
|
||||
use crate::{
|
||||
bundle::Bundle,
|
||||
@ -415,7 +415,7 @@ impl<'a> BundleScratch<'a> {
|
||||
self,
|
||||
world: &mut World,
|
||||
entity: Entity,
|
||||
relationship_hook_insert_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_insert_mode: RelationshipHookMode,
|
||||
) {
|
||||
// SAFETY:
|
||||
// - All `component_ids` are from the same world as `target` entity
|
||||
@ -453,7 +453,7 @@ impl EntityCloner {
|
||||
world: &mut World,
|
||||
source: Entity,
|
||||
mapper: &mut dyn EntityMapper,
|
||||
relationship_hook_insert_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_insert_mode: RelationshipHookMode,
|
||||
) -> Entity {
|
||||
let target = mapper.get_mapped(source);
|
||||
// PERF: reusing allocated space across clones would be more efficient. Consider an allocation model similar to `Commands`.
|
||||
@ -581,16 +581,15 @@ impl EntityCloner {
|
||||
mapper: &mut dyn EntityMapper,
|
||||
) -> Entity {
|
||||
// All relationships on the root should have their hooks run
|
||||
let target =
|
||||
self.clone_entity_internal(world, source, mapper, RelationshipInsertHookMode::Run);
|
||||
let target = self.clone_entity_internal(world, source, mapper, RelationshipHookMode::Run);
|
||||
let child_hook_insert_mode = if self.linked_cloning {
|
||||
// When spawning "linked relationships", we want to ignore hooks for relationships we are spawning, while
|
||||
// still registering with original relationship targets that are "not linked" to the current recursive spawn.
|
||||
RelationshipInsertHookMode::RunIfNotLinked
|
||||
RelationshipHookMode::RunIfNotLinked
|
||||
} else {
|
||||
// If we are not cloning "linked relationships" recursively, then we want any cloned relationship components to
|
||||
// register themselves with their original relationship target.
|
||||
RelationshipInsertHookMode::Run
|
||||
RelationshipHookMode::Run
|
||||
};
|
||||
loop {
|
||||
let queued = self.clone_queue.pop_front();
|
||||
|
@ -331,7 +331,7 @@ mod tests {
|
||||
use crate::{
|
||||
entity::Entity,
|
||||
hierarchy::{ChildOf, Children},
|
||||
relationship::RelationshipTarget,
|
||||
relationship::{RelationshipHookMode, RelationshipTarget},
|
||||
spawn::{Spawn, SpawnRelated},
|
||||
world::World,
|
||||
};
|
||||
@ -492,4 +492,21 @@ mod tests {
|
||||
let id = world.spawn(Children::spawn((Spawn(()), Spawn(())))).id();
|
||||
assert_eq!(world.entity(id).get::<Children>().unwrap().len(), 2,);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn child_replace_hook_skip() {
|
||||
let mut world = World::new();
|
||||
let parent = world.spawn_empty().id();
|
||||
let other = world.spawn_empty().id();
|
||||
let child = world.spawn(ChildOf { parent }).id();
|
||||
world.entity_mut(child).insert_with_relationship_hook_mode(
|
||||
ChildOf { parent: other },
|
||||
RelationshipHookMode::Skip,
|
||||
);
|
||||
assert_eq!(
|
||||
&**world.entity(parent).get::<Children>().unwrap(),
|
||||
&[child],
|
||||
"Children should still have the old value, as on_insert/on_replace didn't run"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
bundle::BundleFromComponents,
|
||||
entity::EntityMapper,
|
||||
prelude::Bundle,
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
world::{EntityMut, EntityWorldMut},
|
||||
};
|
||||
use bevy_reflect::{
|
||||
@ -42,7 +42,7 @@ pub struct ReflectBundleFns {
|
||||
&dyn PartialReflect,
|
||||
&TypeRegistry,
|
||||
&mut dyn EntityMapper,
|
||||
RelationshipInsertHookMode,
|
||||
RelationshipHookMode,
|
||||
),
|
||||
/// Function pointer implementing [`ReflectBundle::remove`].
|
||||
pub remove: fn(&mut EntityWorldMut),
|
||||
@ -93,15 +93,9 @@ impl ReflectBundle {
|
||||
bundle: &dyn PartialReflect,
|
||||
registry: &TypeRegistry,
|
||||
mapper: &mut dyn EntityMapper,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) {
|
||||
(self.0.apply_or_insert_mapped)(
|
||||
entity,
|
||||
bundle,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
(self.0.apply_or_insert_mapped)(entity, bundle, registry, mapper, relationship_hook_mode);
|
||||
}
|
||||
|
||||
/// Removes this [`Bundle`] type from the entity. Does nothing if it doesn't exist.
|
||||
@ -183,46 +177,49 @@ impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for Refl
|
||||
}
|
||||
}
|
||||
},
|
||||
apply_or_insert_mapped:
|
||||
|entity, reflected_bundle, registry, mapper, relationship_insert_hook_mode| {
|
||||
if let Some(reflect_component) =
|
||||
registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
|
||||
{
|
||||
reflect_component.apply_or_insert_mapped(
|
||||
entity,
|
||||
reflected_bundle,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
} else {
|
||||
match reflected_bundle.reflect_ref() {
|
||||
ReflectRef::Struct(bundle) => bundle.iter_fields().for_each(|field| {
|
||||
apply_or_insert_field_mapped(
|
||||
entity,
|
||||
field,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
}),
|
||||
ReflectRef::Tuple(bundle) => bundle.iter_fields().for_each(|field| {
|
||||
apply_or_insert_field_mapped(
|
||||
entity,
|
||||
field,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
}),
|
||||
_ => panic!(
|
||||
"expected bundle `{}` to be a named struct or tuple",
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
core::any::type_name::<B>(),
|
||||
),
|
||||
}
|
||||
apply_or_insert_mapped: |entity,
|
||||
reflected_bundle,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_hook_mode| {
|
||||
if let Some(reflect_component) =
|
||||
registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
|
||||
{
|
||||
reflect_component.apply_or_insert_mapped(
|
||||
entity,
|
||||
reflected_bundle,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
} else {
|
||||
match reflected_bundle.reflect_ref() {
|
||||
ReflectRef::Struct(bundle) => bundle.iter_fields().for_each(|field| {
|
||||
apply_or_insert_field_mapped(
|
||||
entity,
|
||||
field,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
}),
|
||||
ReflectRef::Tuple(bundle) => bundle.iter_fields().for_each(|field| {
|
||||
apply_or_insert_field_mapped(
|
||||
entity,
|
||||
field,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
}),
|
||||
_ => panic!(
|
||||
"expected bundle `{}` to be a named struct or tuple",
|
||||
// FIXME: once we have unique reflect, use `TypePath`.
|
||||
core::any::type_name::<B>(),
|
||||
),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
remove: |entity| {
|
||||
entity.remove::<B>();
|
||||
},
|
||||
@ -259,7 +256,7 @@ fn apply_or_insert_field_mapped(
|
||||
field: &dyn PartialReflect,
|
||||
registry: &TypeRegistry,
|
||||
mapper: &mut dyn EntityMapper,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) {
|
||||
let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
|
||||
panic!(
|
||||
@ -274,7 +271,7 @@ fn apply_or_insert_field_mapped(
|
||||
field,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
} else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
|
||||
reflect_bundle.apply_or_insert_mapped(
|
||||
@ -282,7 +279,7 @@ fn apply_or_insert_field_mapped(
|
||||
field,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
);
|
||||
} else {
|
||||
let is_component = entity.world().components().get_id(type_id).is_some();
|
||||
|
@ -63,7 +63,7 @@ use crate::{
|
||||
component::{ComponentId, ComponentMutability},
|
||||
entity::{Entity, EntityMapper},
|
||||
prelude::Component,
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
world::{
|
||||
unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut,
|
||||
FilteredEntityRef, World,
|
||||
@ -111,7 +111,7 @@ pub struct ReflectComponentFns {
|
||||
&dyn PartialReflect,
|
||||
&TypeRegistry,
|
||||
&mut dyn EntityMapper,
|
||||
RelationshipInsertHookMode,
|
||||
RelationshipHookMode,
|
||||
),
|
||||
/// Function pointer implementing [`ReflectComponent::remove()`].
|
||||
pub remove: fn(&mut EntityWorldMut),
|
||||
@ -180,15 +180,9 @@ impl ReflectComponent {
|
||||
component: &dyn PartialReflect,
|
||||
registry: &TypeRegistry,
|
||||
map: &mut dyn EntityMapper,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) {
|
||||
(self.0.apply_or_insert_mapped)(
|
||||
entity,
|
||||
component,
|
||||
registry,
|
||||
map,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
(self.0.apply_or_insert_mapped)(entity, component, registry, map, relationship_hook_mode);
|
||||
}
|
||||
|
||||
/// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist.
|
||||
@ -333,40 +327,33 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
|
||||
let mut component = unsafe { entity.get_mut_assume_mutable::<C>() }.unwrap();
|
||||
component.apply(reflected_component);
|
||||
},
|
||||
apply_or_insert_mapped:
|
||||
|entity, reflected_component, registry, mapper, relationship_insert_hook_mode| {
|
||||
let map_fn = map_function(mapper);
|
||||
if C::Mutability::MUTABLE {
|
||||
// SAFETY: guard ensures `C` is a mutable component
|
||||
if let Some(mut component) = unsafe { entity.get_mut_assume_mutable::<C>() }
|
||||
{
|
||||
component.apply(reflected_component.as_partial_reflect());
|
||||
C::visit_entities_mut(&mut component, map_fn);
|
||||
} else {
|
||||
let mut component = entity.world_scope(|world| {
|
||||
from_reflect_with_fallback::<C>(
|
||||
reflected_component,
|
||||
world,
|
||||
registry,
|
||||
)
|
||||
});
|
||||
C::visit_entities_mut(&mut component, map_fn);
|
||||
entity.insert_with_relationship_insert_hook_mode(
|
||||
component,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
}
|
||||
apply_or_insert_mapped: |entity,
|
||||
reflected_component,
|
||||
registry,
|
||||
mapper,
|
||||
relationship_hook_mode| {
|
||||
let map_fn = map_function(mapper);
|
||||
if C::Mutability::MUTABLE {
|
||||
// SAFETY: guard ensures `C` is a mutable component
|
||||
if let Some(mut component) = unsafe { entity.get_mut_assume_mutable::<C>() } {
|
||||
component.apply(reflected_component.as_partial_reflect());
|
||||
C::visit_entities_mut(&mut component, map_fn);
|
||||
} else {
|
||||
let mut component = entity.world_scope(|world| {
|
||||
from_reflect_with_fallback::<C>(reflected_component, world, registry)
|
||||
});
|
||||
C::visit_entities_mut(&mut component, map_fn);
|
||||
entity.insert_with_relationship_insert_hook_mode(
|
||||
component,
|
||||
relationship_insert_hook_mode,
|
||||
);
|
||||
entity
|
||||
.insert_with_relationship_hook_mode(component, relationship_hook_mode);
|
||||
}
|
||||
},
|
||||
} else {
|
||||
let mut component = entity.world_scope(|world| {
|
||||
from_reflect_with_fallback::<C>(reflected_component, world, registry)
|
||||
});
|
||||
C::visit_entities_mut(&mut component, map_fn);
|
||||
entity.insert_with_relationship_hook_mode(component, relationship_hook_mode);
|
||||
}
|
||||
},
|
||||
remove: |entity| {
|
||||
entity.remove::<C>();
|
||||
},
|
||||
|
@ -90,14 +90,14 @@ pub trait Relationship: Component + Sized {
|
||||
HookContext {
|
||||
entity,
|
||||
caller,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
..
|
||||
}: HookContext,
|
||||
) {
|
||||
match relationship_insert_hook_mode {
|
||||
RelationshipInsertHookMode::Run => {}
|
||||
RelationshipInsertHookMode::Skip => return,
|
||||
RelationshipInsertHookMode::RunIfNotLinked => {
|
||||
match relationship_hook_mode {
|
||||
RelationshipHookMode::Run => {}
|
||||
RelationshipHookMode::Skip => return,
|
||||
RelationshipHookMode::RunIfNotLinked => {
|
||||
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
|
||||
return;
|
||||
}
|
||||
@ -137,7 +137,23 @@ pub trait Relationship: Component + Sized {
|
||||
|
||||
/// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
|
||||
// note: think of this as "on_drop"
|
||||
fn on_replace(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
||||
fn on_replace(
|
||||
mut world: DeferredWorld,
|
||||
HookContext {
|
||||
entity,
|
||||
relationship_hook_mode,
|
||||
..
|
||||
}: HookContext,
|
||||
) {
|
||||
match relationship_hook_mode {
|
||||
RelationshipHookMode::Run => {}
|
||||
RelationshipHookMode::Skip => return,
|
||||
RelationshipHookMode::RunIfNotLinked => {
|
||||
if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let target_entity = world.entity(entity).get::<Self>().unwrap().get();
|
||||
if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
|
||||
if let Some(mut relationship_target) =
|
||||
@ -305,14 +321,14 @@ pub fn clone_relationship_target<T: RelationshipTarget>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Configures the conditions under which the Relationship insert hook will be run.
|
||||
/// Configures the conditions under which the Relationship insert/replace hooks will be run.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum RelationshipInsertHookMode {
|
||||
/// Relationship insert hooks will always run
|
||||
pub enum RelationshipHookMode {
|
||||
/// Relationship insert/replace hooks will always run
|
||||
Run,
|
||||
/// Relationship insert hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
|
||||
/// Relationship insert/replace hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
|
||||
RunIfNotLinked,
|
||||
/// Relationship insert hooks will always be skipped
|
||||
/// Relationship insert/replace hooks will always be skipped
|
||||
Skip,
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
entity::{Entity, EntityClonerBuilder},
|
||||
error::Result,
|
||||
event::Event,
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
system::{command::HandleError, Command, IntoObserverSystem},
|
||||
world::{error::EntityMutableFetchError, EntityWorldMut, FromWorld, World},
|
||||
};
|
||||
@ -157,7 +157,7 @@ where
|
||||
pub fn insert(bundle: impl Bundle, mode: InsertMode) -> impl EntityCommand {
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.insert_with_caller(bundle, mode, caller, RelationshipInsertHookMode::Run);
|
||||
entity.insert_with_caller(bundle, mode, caller, RelationshipHookMode::Run);
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ pub unsafe fn insert_by_id<T: Send + 'static>(
|
||||
ptr,
|
||||
mode,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -197,7 +197,7 @@ pub fn insert_from_world<T: Component + FromWorld>(mode: InsertMode) -> impl Ent
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
let value = entity.world_scope(|world| T::from_world(world));
|
||||
entity.insert_with_caller(value, mode, caller, RelationshipInsertHookMode::Run);
|
||||
entity.insert_with_caller(value, mode, caller, RelationshipHookMode::Run);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
observer::{Observers, TriggerTargets},
|
||||
prelude::{Component, QueryState},
|
||||
query::{QueryData, QueryFilter},
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
resource::Resource,
|
||||
system::{Commands, Query},
|
||||
traversal::Traversal,
|
||||
@ -121,6 +121,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
[component_id].into_iter(),
|
||||
MaybeLocation::caller(),
|
||||
RelationshipHookMode::Run,
|
||||
);
|
||||
if archetype.has_replace_observer() {
|
||||
self.trigger_observers(
|
||||
@ -160,7 +161,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
[component_id].into_iter(),
|
||||
MaybeLocation::caller(),
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
);
|
||||
if archetype.has_insert_observer() {
|
||||
self.trigger_observers(
|
||||
@ -564,7 +565,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
component_id,
|
||||
caller,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode::Run,
|
||||
relationship_hook_mode: RelationshipHookMode::Run,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -583,7 +584,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
caller: MaybeLocation,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) {
|
||||
if archetype.has_insert_hook() {
|
||||
for component_id in targets {
|
||||
@ -596,7 +597,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
component_id,
|
||||
caller,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -615,6 +616,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
caller: MaybeLocation,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) {
|
||||
if archetype.has_replace_hook() {
|
||||
for component_id in targets {
|
||||
@ -627,7 +629,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
component_id,
|
||||
caller,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode::Run,
|
||||
relationship_hook_mode,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -658,7 +660,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
component_id,
|
||||
caller,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode::Run,
|
||||
relationship_hook_mode: RelationshipHookMode::Run,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -689,7 +691,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
entity,
|
||||
component_id,
|
||||
caller,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode::Run,
|
||||
relationship_hook_mode: RelationshipHookMode::Run,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||
event::Event,
|
||||
observer::Observer,
|
||||
query::{Access, ReadOnlyQueryData},
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
removal_detection::RemovedComponentEvents,
|
||||
resource::Resource,
|
||||
storage::Storages,
|
||||
@ -1534,13 +1534,13 @@ impl<'w> EntityWorldMut<'w> {
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
MaybeLocation::caller(),
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
}
|
||||
|
||||
/// Adds a [`Bundle`] of components to the entity.
|
||||
/// [`Relationship`](crate::relationship::Relationship) components in the bundle will follow the configuration
|
||||
/// in `relationship_insert_hook_mode`.
|
||||
/// in `relationship_hook_mode`.
|
||||
///
|
||||
/// This will overwrite any previous value(s) of the same component type.
|
||||
///
|
||||
@ -1553,16 +1553,16 @@ impl<'w> EntityWorldMut<'w> {
|
||||
///
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn insert_with_relationship_insert_hook_mode<T: Bundle>(
|
||||
pub fn insert_with_relationship_hook_mode<T: Bundle>(
|
||||
&mut self,
|
||||
bundle: T,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) -> &mut Self {
|
||||
self.insert_with_caller(
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
MaybeLocation::caller(),
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1580,7 +1580,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
bundle,
|
||||
InsertMode::Keep,
|
||||
MaybeLocation::caller(),
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1592,7 +1592,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
bundle: T,
|
||||
mode: InsertMode,
|
||||
caller: MaybeLocation,
|
||||
relationship_insert_hook_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_mode: RelationshipHookMode,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let change_tick = self.world.change_tick();
|
||||
@ -1606,7 +1606,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
bundle,
|
||||
mode,
|
||||
caller,
|
||||
relationship_insert_hook_mode,
|
||||
relationship_hook_mode,
|
||||
)
|
||||
};
|
||||
self.location = location;
|
||||
@ -1641,7 +1641,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
component,
|
||||
InsertMode::Replace,
|
||||
MaybeLocation::caller(),
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1656,7 +1656,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
component: OwningPtr<'_>,
|
||||
mode: InsertMode,
|
||||
caller: MaybeLocation,
|
||||
relationship_hook_insert_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_insert_mode: RelationshipHookMode,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let change_tick = self.world.change_tick();
|
||||
@ -1711,11 +1711,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
component_ids: &[ComponentId],
|
||||
iter_components: I,
|
||||
) -> &mut Self {
|
||||
self.insert_by_ids_internal(
|
||||
component_ids,
|
||||
iter_components,
|
||||
RelationshipInsertHookMode::Run,
|
||||
)
|
||||
self.insert_by_ids_internal(component_ids, iter_components, RelationshipHookMode::Run)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
@ -1723,7 +1719,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
&mut self,
|
||||
component_ids: &[ComponentId],
|
||||
iter_components: I,
|
||||
relationship_hook_insert_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_insert_mode: RelationshipHookMode,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let change_tick = self.world.change_tick();
|
||||
@ -2310,6 +2306,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
caller,
|
||||
RelationshipHookMode::Run,
|
||||
);
|
||||
if archetype.has_remove_observer() {
|
||||
deferred_world.trigger_observers(
|
||||
@ -2762,7 +2759,13 @@ unsafe fn trigger_on_replace_and_on_remove_hooks_and_observers(
|
||||
caller,
|
||||
);
|
||||
}
|
||||
deferred_world.trigger_on_replace(archetype, entity, bundle_components_in_archetype(), caller);
|
||||
deferred_world.trigger_on_replace(
|
||||
archetype,
|
||||
entity,
|
||||
bundle_components_in_archetype(),
|
||||
caller,
|
||||
RelationshipHookMode::Run,
|
||||
);
|
||||
if archetype.has_remove_observer() {
|
||||
deferred_world.trigger_observers(
|
||||
ON_REMOVE,
|
||||
@ -4251,7 +4254,7 @@ unsafe fn insert_dynamic_bundle<
|
||||
storage_types: S,
|
||||
mode: InsertMode,
|
||||
caller: MaybeLocation,
|
||||
relationship_hook_insert_mode: RelationshipInsertHookMode,
|
||||
relationship_hook_insert_mode: RelationshipHookMode,
|
||||
) -> EntityLocation {
|
||||
struct DynamicInsertBundle<'a, I: Iterator<Item = (StorageType, OwningPtr<'a>)>> {
|
||||
components: I,
|
||||
|
@ -53,7 +53,7 @@ use crate::{
|
||||
event::{Event, EventId, Events, SendBatchIds},
|
||||
observer::Observers,
|
||||
query::{DebugCheckedUnwrap, QueryData, QueryFilter, QueryState},
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
removal_detection::RemovedComponentEvents,
|
||||
resource::Resource,
|
||||
schedule::{Schedule, ScheduleLabel, Schedules},
|
||||
@ -2305,7 +2305,7 @@ impl World {
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
};
|
||||
}
|
||||
@ -2327,7 +2327,7 @@ impl World {
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
};
|
||||
spawn_or_insert =
|
||||
@ -2465,7 +2465,7 @@ impl World {
|
||||
first_bundle,
|
||||
insert_mode,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
};
|
||||
|
||||
@ -2493,7 +2493,7 @@ impl World {
|
||||
bundle,
|
||||
insert_mode,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
};
|
||||
} else {
|
||||
@ -2615,7 +2615,7 @@ impl World {
|
||||
first_bundle,
|
||||
insert_mode,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
};
|
||||
break Some(cache);
|
||||
@ -2652,7 +2652,7 @@ impl World {
|
||||
bundle,
|
||||
insert_mode,
|
||||
caller,
|
||||
RelationshipInsertHookMode::Run,
|
||||
RelationshipHookMode::Run,
|
||||
)
|
||||
};
|
||||
} else {
|
||||
|
@ -12,7 +12,7 @@ use crate::reflect_utils::clone_reflect_value;
|
||||
#[cfg(feature = "serialize")]
|
||||
use crate::serde::SceneSerializer;
|
||||
use bevy_ecs::component::ComponentCloneBehavior;
|
||||
use bevy_ecs::relationship::RelationshipInsertHookMode;
|
||||
use bevy_ecs::relationship::RelationshipHookMode;
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::Serialize;
|
||||
|
||||
@ -122,7 +122,7 @@ impl DynamicScene {
|
||||
component.as_partial_reflect(),
|
||||
&type_registry,
|
||||
mapper,
|
||||
RelationshipInsertHookMode::Skip,
|
||||
RelationshipHookMode::Skip,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use bevy_ecs::{
|
||||
entity::{hash_map::EntityHashMap, Entity, SceneEntityMapper},
|
||||
entity_disabling::DefaultQueryFilters,
|
||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
|
||||
relationship::RelationshipInsertHookMode,
|
||||
relationship::RelationshipHookMode,
|
||||
world::World,
|
||||
};
|
||||
use bevy_reflect::TypePath;
|
||||
@ -159,7 +159,7 @@ impl Scene {
|
||||
component.as_partial_reflect(),
|
||||
&type_registry,
|
||||
mapper,
|
||||
RelationshipInsertHookMode::Skip,
|
||||
RelationshipHookMode::Skip,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user