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:
Carter Anderson 2025-03-17 18:24:07 -07:00 committed by GitHub
parent ac53e4c482
commit 6d6054116a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 180 additions and 158 deletions

View File

@ -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(

View File

@ -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`].

View File

@ -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();

View File

@ -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"
);
}
}

View File

@ -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();

View File

@ -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>();
},

View File

@ -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,
}

View File

@ -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);
}
}

View File

@ -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,
},
);
}

View File

@ -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,

View File

@ -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 {

View File

@ -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,
);
});
}

View File

@ -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,
);
});
}