@@ -4,7 +4,7 @@ use crate::{
4
4
change_detection:: Ticks ,
5
5
component:: { Component , ComponentId , ComponentTicks , Components , StorageType } ,
6
6
entity:: { Entities , Entity , EntityLocation } ,
7
- ptr:: { OwningPtr , Ptr } ,
7
+ ptr:: { OwningPtr , Ptr , UnsafeCellDeref } ,
8
8
storage:: { SparseSet , Storages } ,
9
9
world:: { Mut , World } ,
10
10
} ;
@@ -72,6 +72,17 @@ impl<'w> EntityRef<'w> {
72
72
}
73
73
}
74
74
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
+
75
86
/// Gets a mutable reference to the component of type `T` associated with
76
87
/// this entity without ensuring there are no other borrows active and without
77
88
/// ensuring that the returned reference will stay valid.
@@ -169,6 +180,17 @@ impl<'w> EntityMut<'w> {
169
180
unsafe { self . get_unchecked_mut :: < T > ( ) }
170
181
}
171
182
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
+
172
194
/// Gets a mutable reference to the component of type `T` associated with
173
195
/// this entity without ensuring there are no other borrows active and without
174
196
/// ensuring that the returned reference will stay valid.
@@ -531,6 +553,31 @@ unsafe fn get_component_and_ticks(
531
553
}
532
554
}
533
555
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
+
534
581
// TODO: move to Storages?
535
582
/// Moves component data out of storage.
536
583
///
@@ -601,6 +648,18 @@ pub(crate) unsafe fn get_component_and_ticks_with_type(
601
648
get_component_and_ticks ( world, component_id, entity, location)
602
649
}
603
650
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
+
604
663
fn contains_component_with_type ( world : & World , type_id : TypeId , location : EntityLocation ) -> bool {
605
664
if let Some ( component_id) = world. components . get_id ( type_id) {
606
665
contains_component_with_id ( world, component_id, location)
0 commit comments