@@ -486,12 +486,22 @@ unsafe impl QueryData for EntityLocation {
486
486
/// SAFETY: access is read only
487
487
unsafe impl ReadOnlyQueryData for EntityLocation { }
488
488
489
+ /// The [`WorldQuery::Fetch`] type for WorldQueries that can fetch multiple components from an entity
490
+ /// ([`EntityRef`], [`EntityMut`], etc.)
491
+ #[ derive( Copy , Clone ) ]
492
+ #[ doc( hidden) ]
493
+ pub struct EntityFetch < ' w > {
494
+ world : UnsafeWorldCell < ' w > ,
495
+ last_run : Tick ,
496
+ this_run : Tick ,
497
+ }
498
+
489
499
/// SAFETY:
490
500
/// `fetch` accesses all components in a readonly way.
491
501
/// This is sound because `update_component_access` and `update_archetype_component_access` set read access for all components and panic when appropriate.
492
502
/// Filters are unchanged.
493
503
unsafe impl < ' a > WorldQuery for EntityRef < ' a > {
494
- type Fetch < ' w > = UnsafeWorldCell < ' w > ;
504
+ type Fetch < ' w > = EntityFetch < ' w > ;
495
505
type State = ( ) ;
496
506
497
507
fn shrink_fetch < ' wlong : ' wshort , ' wshort > ( fetch : Self :: Fetch < ' wlong > ) -> Self :: Fetch < ' wshort > {
@@ -501,10 +511,14 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> {
501
511
unsafe fn init_fetch < ' w > (
502
512
world : UnsafeWorldCell < ' w > ,
503
513
_state : & Self :: State ,
504
- _last_run : Tick ,
505
- _this_run : Tick ,
514
+ last_run : Tick ,
515
+ this_run : Tick ,
506
516
) -> Self :: Fetch < ' w > {
507
- world
517
+ EntityFetch {
518
+ world,
519
+ last_run,
520
+ this_run,
521
+ }
508
522
}
509
523
510
524
const IS_DENSE : bool = true ;
@@ -556,12 +570,17 @@ unsafe impl<'a> QueryData for EntityRef<'a> {
556
570
557
571
#[ inline( always) ]
558
572
unsafe fn fetch < ' w > (
559
- world : & mut Self :: Fetch < ' w > ,
573
+ fetch : & mut Self :: Fetch < ' w > ,
560
574
entity : Entity ,
561
575
_table_row : TableRow ,
562
576
) -> Self :: Item < ' w > {
563
577
// SAFETY: `fetch` must be called with an entity that exists in the world
564
- let cell = unsafe { world. get_entity ( entity) . debug_checked_unwrap ( ) } ;
578
+ let cell = unsafe {
579
+ fetch
580
+ . world
581
+ . get_entity_with_ticks ( entity, fetch. last_run , fetch. this_run )
582
+ . debug_checked_unwrap ( )
583
+ } ;
565
584
// SAFETY: Read-only access to every component has been registered.
566
585
unsafe { EntityRef :: new ( cell) }
567
586
}
@@ -572,7 +591,7 @@ unsafe impl ReadOnlyQueryData for EntityRef<'_> {}
572
591
573
592
/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
574
593
unsafe impl < ' a > WorldQuery for EntityMut < ' a > {
575
- type Fetch < ' w > = UnsafeWorldCell < ' w > ;
594
+ type Fetch < ' w > = EntityFetch < ' w > ;
576
595
type State = ( ) ;
577
596
578
597
fn shrink_fetch < ' wlong : ' wshort , ' wshort > ( fetch : Self :: Fetch < ' wlong > ) -> Self :: Fetch < ' wshort > {
@@ -582,10 +601,14 @@ unsafe impl<'a> WorldQuery for EntityMut<'a> {
582
601
unsafe fn init_fetch < ' w > (
583
602
world : UnsafeWorldCell < ' w > ,
584
603
_state : & Self :: State ,
585
- _last_run : Tick ,
586
- _this_run : Tick ,
604
+ last_run : Tick ,
605
+ this_run : Tick ,
587
606
) -> Self :: Fetch < ' w > {
588
- world
607
+ EntityFetch {
608
+ world,
609
+ last_run,
610
+ this_run,
611
+ }
589
612
}
590
613
591
614
const IS_DENSE : bool = true ;
@@ -637,20 +660,25 @@ unsafe impl<'a> QueryData for EntityMut<'a> {
637
660
638
661
#[ inline( always) ]
639
662
unsafe fn fetch < ' w > (
640
- world : & mut Self :: Fetch < ' w > ,
663
+ fetch : & mut Self :: Fetch < ' w > ,
641
664
entity : Entity ,
642
665
_table_row : TableRow ,
643
666
) -> Self :: Item < ' w > {
644
667
// SAFETY: `fetch` must be called with an entity that exists in the world
645
- let cell = unsafe { world. get_entity ( entity) . debug_checked_unwrap ( ) } ;
668
+ let cell = unsafe {
669
+ fetch
670
+ . world
671
+ . get_entity_with_ticks ( entity, fetch. last_run , fetch. this_run )
672
+ . debug_checked_unwrap ( )
673
+ } ;
646
674
// SAFETY: mutable access to every component has been registered.
647
675
unsafe { EntityMut :: new ( cell) }
648
676
}
649
677
}
650
678
651
679
/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
652
680
unsafe impl < ' a > WorldQuery for FilteredEntityRef < ' a > {
653
- type Fetch < ' w > = ( UnsafeWorldCell < ' w > , Access < ComponentId > ) ;
681
+ type Fetch < ' w > = ( EntityFetch < ' w > , Access < ComponentId > ) ;
654
682
type State = Access < ComponentId > ;
655
683
656
684
fn shrink_fetch < ' wlong : ' wshort , ' wshort > ( fetch : Self :: Fetch < ' wlong > ) -> Self :: Fetch < ' wshort > {
@@ -662,12 +690,19 @@ unsafe impl<'a> WorldQuery for FilteredEntityRef<'a> {
662
690
unsafe fn init_fetch < ' w > (
663
691
world : UnsafeWorldCell < ' w > ,
664
692
_state : & Self :: State ,
665
- _last_run : Tick ,
666
- _this_run : Tick ,
693
+ last_run : Tick ,
694
+ this_run : Tick ,
667
695
) -> Self :: Fetch < ' w > {
668
696
let mut access = Access :: default ( ) ;
669
697
access. read_all_components ( ) ;
670
- ( world, access)
698
+ (
699
+ EntityFetch {
700
+ world,
701
+ last_run,
702
+ this_run,
703
+ } ,
704
+ access,
705
+ )
671
706
}
672
707
673
708
#[ inline]
@@ -743,12 +778,17 @@ unsafe impl<'a> QueryData for FilteredEntityRef<'a> {
743
778
744
779
#[ inline( always) ]
745
780
unsafe fn fetch < ' w > (
746
- ( world , access) : & mut Self :: Fetch < ' w > ,
781
+ ( fetch , access) : & mut Self :: Fetch < ' w > ,
747
782
entity : Entity ,
748
783
_table_row : TableRow ,
749
784
) -> Self :: Item < ' w > {
750
785
// SAFETY: `fetch` must be called with an entity that exists in the world
751
- let cell = unsafe { world. get_entity ( entity) . debug_checked_unwrap ( ) } ;
786
+ let cell = unsafe {
787
+ fetch
788
+ . world
789
+ . get_entity_with_ticks ( entity, fetch. last_run , fetch. this_run )
790
+ . debug_checked_unwrap ( )
791
+ } ;
752
792
// SAFETY: mutable access to every component has been registered.
753
793
unsafe { FilteredEntityRef :: new ( cell, access. clone ( ) ) }
754
794
}
@@ -759,7 +799,7 @@ unsafe impl ReadOnlyQueryData for FilteredEntityRef<'_> {}
759
799
760
800
/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
761
801
unsafe impl < ' a > WorldQuery for FilteredEntityMut < ' a > {
762
- type Fetch < ' w > = ( UnsafeWorldCell < ' w > , Access < ComponentId > ) ;
802
+ type Fetch < ' w > = ( EntityFetch < ' w > , Access < ComponentId > ) ;
763
803
type State = Access < ComponentId > ;
764
804
765
805
fn shrink_fetch < ' wlong : ' wshort , ' wshort > ( fetch : Self :: Fetch < ' wlong > ) -> Self :: Fetch < ' wshort > {
@@ -771,12 +811,19 @@ unsafe impl<'a> WorldQuery for FilteredEntityMut<'a> {
771
811
unsafe fn init_fetch < ' w > (
772
812
world : UnsafeWorldCell < ' w > ,
773
813
_state : & Self :: State ,
774
- _last_run : Tick ,
775
- _this_run : Tick ,
814
+ last_run : Tick ,
815
+ this_run : Tick ,
776
816
) -> Self :: Fetch < ' w > {
777
817
let mut access = Access :: default ( ) ;
778
818
access. write_all_components ( ) ;
779
- ( world, access)
819
+ (
820
+ EntityFetch {
821
+ world,
822
+ last_run,
823
+ this_run,
824
+ } ,
825
+ access,
826
+ )
780
827
}
781
828
782
829
#[ inline]
@@ -850,12 +897,17 @@ unsafe impl<'a> QueryData for FilteredEntityMut<'a> {
850
897
851
898
#[ inline( always) ]
852
899
unsafe fn fetch < ' w > (
853
- ( world , access) : & mut Self :: Fetch < ' w > ,
900
+ ( fetch , access) : & mut Self :: Fetch < ' w > ,
854
901
entity : Entity ,
855
902
_table_row : TableRow ,
856
903
) -> Self :: Item < ' w > {
857
904
// SAFETY: `fetch` must be called with an entity that exists in the world
858
- let cell = unsafe { world. get_entity ( entity) . debug_checked_unwrap ( ) } ;
905
+ let cell = unsafe {
906
+ fetch
907
+ . world
908
+ . get_entity_with_ticks ( entity, fetch. last_run , fetch. this_run )
909
+ . debug_checked_unwrap ( )
910
+ } ;
859
911
// SAFETY: mutable access to every component has been registered.
860
912
unsafe { FilteredEntityMut :: new ( cell, access. clone ( ) ) }
861
913
}
@@ -868,7 +920,7 @@ unsafe impl<'a, B> WorldQuery for EntityRefExcept<'a, B>
868
920
where
869
921
B : Bundle ,
870
922
{
871
- type Fetch < ' w > = UnsafeWorldCell < ' w > ;
923
+ type Fetch < ' w > = EntityFetch < ' w > ;
872
924
type State = SmallVec < [ ComponentId ; 4 ] > ;
873
925
874
926
fn shrink_fetch < ' wlong : ' wshort , ' wshort > ( fetch : Self :: Fetch < ' wlong > ) -> Self :: Fetch < ' wshort > {
@@ -878,10 +930,14 @@ where
878
930
unsafe fn init_fetch < ' w > (
879
931
world : UnsafeWorldCell < ' w > ,
880
932
_: & Self :: State ,
881
- _ : Tick ,
882
- _ : Tick ,
933
+ last_run : Tick ,
934
+ this_run : Tick ,
883
935
) -> Self :: Fetch < ' w > {
884
- world
936
+ EntityFetch {
937
+ world,
938
+ last_run,
939
+ this_run,
940
+ }
885
941
}
886
942
887
943
const IS_DENSE : bool = true ;
@@ -948,11 +1004,14 @@ where
948
1004
}
949
1005
950
1006
unsafe fn fetch < ' w > (
951
- world : & mut Self :: Fetch < ' w > ,
1007
+ fetch : & mut Self :: Fetch < ' w > ,
952
1008
entity : Entity ,
953
1009
_: TableRow ,
954
1010
) -> Self :: Item < ' w > {
955
- let cell = world. get_entity ( entity) . unwrap ( ) ;
1011
+ let cell = fetch
1012
+ . world
1013
+ . get_entity_with_ticks ( entity, fetch. last_run , fetch. this_run )
1014
+ . unwrap ( ) ;
956
1015
EntityRefExcept :: new ( cell)
957
1016
}
958
1017
}
@@ -968,7 +1027,7 @@ unsafe impl<'a, B> WorldQuery for EntityMutExcept<'a, B>
968
1027
where
969
1028
B : Bundle ,
970
1029
{
971
- type Fetch < ' w > = UnsafeWorldCell < ' w > ;
1030
+ type Fetch < ' w > = EntityFetch < ' w > ;
972
1031
type State = SmallVec < [ ComponentId ; 4 ] > ;
973
1032
974
1033
fn shrink_fetch < ' wlong : ' wshort , ' wshort > ( fetch : Self :: Fetch < ' wlong > ) -> Self :: Fetch < ' wshort > {
@@ -978,10 +1037,14 @@ where
978
1037
unsafe fn init_fetch < ' w > (
979
1038
world : UnsafeWorldCell < ' w > ,
980
1039
_: & Self :: State ,
981
- _ : Tick ,
982
- _ : Tick ,
1040
+ last_run : Tick ,
1041
+ this_run : Tick ,
983
1042
) -> Self :: Fetch < ' w > {
984
- world
1043
+ EntityFetch {
1044
+ world,
1045
+ last_run,
1046
+ this_run,
1047
+ }
985
1048
}
986
1049
987
1050
const IS_DENSE : bool = true ;
@@ -1049,11 +1112,14 @@ where
1049
1112
}
1050
1113
1051
1114
unsafe fn fetch < ' w > (
1052
- world : & mut Self :: Fetch < ' w > ,
1115
+ fetch : & mut Self :: Fetch < ' w > ,
1053
1116
entity : Entity ,
1054
1117
_: TableRow ,
1055
1118
) -> Self :: Item < ' w > {
1056
- let cell = world. get_entity ( entity) . unwrap ( ) ;
1119
+ let cell = fetch
1120
+ . world
1121
+ . get_entity_with_ticks ( entity, fetch. last_run , fetch. this_run )
1122
+ . unwrap ( ) ;
1057
1123
EntityMutExcept :: new ( cell)
1058
1124
}
1059
1125
}
@@ -2544,10 +2610,11 @@ impl<C: Component, T: Copy, S: Copy> Copy for StorageSwitch<C, T, S> {}
2544
2610
2545
2611
#[ cfg( test) ]
2546
2612
mod tests {
2547
- use bevy_ecs_macros:: QueryData ;
2548
-
2549
2613
use super :: * ;
2614
+ use crate :: change_detection:: DetectChanges ;
2550
2615
use crate :: system:: { assert_is_system, Query } ;
2616
+ use bevy_ecs:: prelude:: Schedule ;
2617
+ use bevy_ecs_macros:: QueryData ;
2551
2618
2552
2619
#[ derive( Component ) ]
2553
2620
pub struct A ;
@@ -2641,4 +2708,34 @@ mod tests {
2641
2708
2642
2709
assert_is_system ( client_system) ;
2643
2710
}
2711
+
2712
+ // Test that EntityRef::get_ref::<T>() returns a Ref<T> value with the correct
2713
+ // ticks when the EntityRef was retrieved from a Query.
2714
+ // See: https://github.com/bevyengine/bevy/issues/13735
2715
+ #[ test]
2716
+ fn test_entity_ref_query_with_ticks ( ) {
2717
+ #[ derive( Component ) ]
2718
+ pub struct C ;
2719
+
2720
+ fn system ( query : Query < EntityRef > ) {
2721
+ for entity_ref in & query {
2722
+ if let Some ( c) = entity_ref. get_ref :: < C > ( ) {
2723
+ if !c. is_added ( ) {
2724
+ panic ! ( "Expected C to be added" ) ;
2725
+ }
2726
+ }
2727
+ }
2728
+ }
2729
+
2730
+ let mut world = World :: new ( ) ;
2731
+ let mut schedule = Schedule :: default ( ) ;
2732
+ schedule. add_systems ( system) ;
2733
+ world. spawn ( C ) ;
2734
+
2735
+ // reset the change ticks
2736
+ world. clear_trackers ( ) ;
2737
+
2738
+ // we want EntityRef to use the change ticks of the system
2739
+ schedule. run ( & mut world) ;
2740
+ }
2644
2741
}
0 commit comments