Skip to content

Commit c8c806d

Browse files
TheRawMeatballItsDoot
authored andcommitted
Add get_change_ticks method to EntityRef and EntityMut (bevyengine#2539)
Direct access to the change ticks is useful for integrating the reliable change detection with external stuff.
1 parent d3f5d30 commit c8c806d

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

crates/bevy_ecs/src/world/entity_ref.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
change_detection::Ticks,
55
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
66
entity::{Entities, Entity, EntityLocation},
7-
ptr::{OwningPtr, Ptr},
7+
ptr::{OwningPtr, Ptr, UnsafeCellDeref},
88
storage::{SparseSet, Storages},
99
world::{Mut, World},
1010
};
@@ -72,6 +72,17 @@ impl<'w> EntityRef<'w> {
7272
}
7373
}
7474

75+
/// Retrieves the change ticks for the given component. This can be useful for implementing change
76+
/// detection in custom runtimes.
77+
#[inline]
78+
pub fn get_change_ticks<T: Component>(&self) -> Option<&'w ComponentTicks> {
79+
// SAFE: entity location is valid
80+
unsafe {
81+
get_ticks_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
82+
.map(|ticks| ticks.deref())
83+
}
84+
}
85+
7586
/// Gets a mutable reference to the component of type `T` associated with
7687
/// this entity without ensuring there are no other borrows active and without
7788
/// ensuring that the returned reference will stay valid.
@@ -169,6 +180,17 @@ impl<'w> EntityMut<'w> {
169180
unsafe { self.get_unchecked_mut::<T>() }
170181
}
171182

183+
/// Retrieves the change ticks for the given component. This can be useful for implementing change
184+
/// detection in custom runtimes.
185+
#[inline]
186+
pub fn get_change_ticks<T: Component>(&self) -> Option<&ComponentTicks> {
187+
// SAFE: entity location is valid
188+
unsafe {
189+
get_ticks_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
190+
.map(|ticks| ticks.deref())
191+
}
192+
}
193+
172194
/// Gets a mutable reference to the component of type `T` associated with
173195
/// this entity without ensuring there are no other borrows active and without
174196
/// ensuring that the returned reference will stay valid.
@@ -531,6 +553,31 @@ unsafe fn get_component_and_ticks(
531553
}
532554
}
533555

556+
#[inline]
557+
unsafe fn get_ticks(
558+
world: &World,
559+
component_id: ComponentId,
560+
entity: Entity,
561+
location: EntityLocation,
562+
) -> Option<&UnsafeCell<ComponentTicks>> {
563+
let archetype = &world.archetypes[location.archetype_id];
564+
let component_info = world.components.get_info_unchecked(component_id);
565+
match component_info.storage_type() {
566+
StorageType::Table => {
567+
let table = &world.storages.tables[archetype.table_id()];
568+
let components = table.get_column(component_id)?;
569+
let table_row = archetype.entity_table_row(location.index);
570+
// SAFE: archetypes only store valid table_rows and the stored component type is T
571+
Some(components.get_ticks_unchecked(table_row))
572+
}
573+
StorageType::SparseSet => world
574+
.storages
575+
.sparse_sets
576+
.get(component_id)
577+
.and_then(|sparse_set| sparse_set.get_ticks(entity)),
578+
}
579+
}
580+
534581
// TODO: move to Storages?
535582
/// Moves component data out of storage.
536583
///
@@ -601,6 +648,18 @@ pub(crate) unsafe fn get_component_and_ticks_with_type(
601648
get_component_and_ticks(world, component_id, entity, location)
602649
}
603650

651+
/// # Safety
652+
/// `entity_location` must be within bounds of an archetype that exists.
653+
pub(crate) unsafe fn get_ticks_with_type(
654+
world: &World,
655+
type_id: TypeId,
656+
entity: Entity,
657+
location: EntityLocation,
658+
) -> Option<&UnsafeCell<ComponentTicks>> {
659+
let component_id = world.components.get_id(type_id)?;
660+
get_ticks(world, component_id, entity, location)
661+
}
662+
604663
fn contains_component_with_type(world: &World, type_id: TypeId, location: EntityLocation) -> bool {
605664
if let Some(component_id) = world.components.get_id(type_id) {
606665
contains_component_with_id(world, component_id, location)

0 commit comments

Comments
 (0)