1- //! Provides an [`Index`] system parameter, allowing a user to lookup an [`Entity`]
2- //! based on the value of one of its [`Components`][`Component`].
1+ use std:: { hash:: Hash , marker:: PhantomData } ;
2+
3+ use bevy_app:: { App , Plugin , Update } ;
34
4- use crate as bevy_ecs;
55use bevy_ecs:: {
66 component:: { Component , Tick } ,
77 prelude:: { Changed , Entity , Query , Ref , RemovedComponents , ResMut } ,
88 query:: ReadOnlyWorldQuery ,
9- system:: { SystemChangeTick , SystemParam } ,
9+ system:: { Resource , SystemChangeTick , SystemParam } ,
1010} ;
1111
12- use bevy_ecs_macros:: Resource ;
13-
1412use bevy_utils:: { default, EntityHashMap , EntityHashSet , HashMap } ;
1513
16- use std:: { hash:: Hash , marker:: PhantomData } ;
17-
18- /// Describes how to transform a [`Component`] `Input` into an `Index` suitable for an [`Index`].
14+ /// Describes how to transform an `Input` into an `Index` suitable for an [`Index`].
1915pub trait Indexer {
20- /// The input [`Component`] to index against.
21- type Input : Component ;
16+ /// The input to index against.
17+ type Input ;
2218
23- /// A type suitable for indexing the [`Component`] `Input`
24- type Index : Hash + Eq + Clone + Sync + Send + ' static ;
19+ /// A type suitable for indexing the `Input`
20+ type Index ;
2521
2622 /// Generate an `Index` from the provided `Input`
2723 fn index ( input : & Self :: Input ) -> Self :: Index ;
2824}
2925
30- /// A basic [`Indexer`] which directly uses the [`Component`] `T`'s value.
26+ /// A basic [`Indexer`] which directly uses `T`'s value.
3127pub struct SimpleIndexer < T > ( PhantomData < T > ) ;
3228
3329impl < T > Indexer for SimpleIndexer < T >
3430where
35- T : Component + Hash + Eq + Clone ,
31+ T : Clone ,
3632{
3733 type Input = T ;
3834
4541
4642/// Stored data required for an [`Index`].
4743#[ derive( Resource ) ]
48- pub struct IndexBacking < T , F = ( ) , I = SimpleIndexer < T > >
44+ struct IndexBacking < T , F = ( ) , I = SimpleIndexer < T > >
4945where
5046 I : Indexer ,
5147{
@@ -75,10 +71,16 @@ where
7571impl < T , F , I > IndexBacking < T , F , I >
7672where
7773 I : Indexer < Input = T > ,
74+ I :: Index : Hash + Clone + Eq ,
7875{
7976 fn update ( & mut self , entity : Entity , value : Option < & T > ) -> Option < I :: Index > {
8077 let value = value. map ( |value| I :: index ( value) ) ;
8178
79+ if self . reverse . get ( & entity) == value. as_ref ( ) {
80+ // Return early since the value is already up-to-date
81+ return None ;
82+ }
83+
8284 let old = if let Some ( ref value) = value {
8385 self . reverse . insert ( entity, value. clone ( ) )
8486 } else {
@@ -102,13 +104,33 @@ where
102104 old
103105 }
104106
107+ fn insert ( & mut self , entity : Entity , value : & T ) -> Option < I :: Index > {
108+ self . update ( entity, Some ( value) )
109+ }
110+
111+ fn remove_by_entity ( & mut self , entity : Entity ) -> Option < I :: Index > {
112+ self . update ( entity, None )
113+ }
114+
105115 fn get ( & self , value : & T ) -> impl Iterator < Item = Entity > + ' _ {
116+ self . get_by_index ( & I :: index ( value) )
117+ }
118+
119+ fn get_by_index ( & self , index : & I :: Index ) -> impl Iterator < Item = Entity > + ' _ {
106120 self . forward
107- . get ( & I :: index ( value ) )
121+ . get ( index)
108122 . unwrap_or ( & self . empty )
109123 . iter ( )
110124 . copied ( )
111125 }
126+
127+ fn iter (
128+ & mut self ,
129+ ) -> impl Iterator < Item = ( & I :: Index , impl Iterator < Item = Entity > + ' _ ) > + ' _ {
130+ self . forward
131+ . iter ( )
132+ . map ( |( index, entities) | ( index, entities. iter ( ) . copied ( ) ) )
133+ }
112134}
113135
114136/// Allows for lookup of an [`Entity`] based on the [`Component`] `T`'s value.
@@ -121,64 +143,92 @@ where
121143 T : Component ,
122144 I : Indexer + ' static ,
123145 F : ReadOnlyWorldQuery + ' static ,
146+ I :: Index : Send + Sync + ' static ,
124147{
125148 changed : Query < ' w , ' s , ( Entity , Ref < ' static , T > ) , ( Changed < T > , F ) > ,
126149 removed : RemovedComponents < ' w , ' s , T > ,
127150 index : ResMut < ' w , IndexBacking < T , F , I > > ,
128- this_run : SystemChangeTick ,
151+ change_tick : SystemChangeTick ,
129152}
130153
131154impl < ' w , ' s , T , F , I > Index < ' w , ' s , T , F , I >
132155where
133156 T : Component ,
134157 I : Indexer < Input = T > + ' static ,
135158 F : ReadOnlyWorldQuery + ' static ,
159+ I :: Index : Hash + Clone + Eq + Send + Sync + ' static ,
136160{
137161 fn update_index_internal ( & mut self ) {
138- let this_run = self . this_run . this_run ( ) ;
162+ let this_run = self . change_tick . this_run ( ) ;
139163
140164 // Remove old entires
141165 for entity in self . removed . read ( ) {
142- self . index . update ( entity, None ) ;
166+ self . index . remove_by_entity ( entity) ;
143167 }
144168
145169 // Update new and existing entries
146170 for ( entity, component) in self . changed . iter ( ) {
147- self . index . update ( entity, Some ( component. as_ref ( ) ) ) ;
171+ self . index . insert ( entity, component. as_ref ( ) ) ;
148172 }
149173
150174 self . index . last_this_run = Some ( this_run) ;
151175 }
152176
153177 /// System to keep [`Index`] coarsely updated every frame
154- pub fn update_index ( mut index : Index < T , F , I > ) {
178+ fn update_index ( mut index : Index < T , F , I > ) {
155179 index. update_index_internal ( ) ;
156180 }
157181
158182 fn ensure_updated ( & mut self ) {
159- let this_run = self . this_run . this_run ( ) ;
183+ let this_run = self . change_tick . this_run ( ) ;
160184
161185 if self . index . last_this_run != Some ( this_run) {
162186 self . update_index_internal ( ) ;
163187 }
164188 }
165189
166- /// Get
190+ /// Get all [entities](`Entity`) with a [`Component`] of `value`.
167191 pub fn get ( & mut self , value : & T ) -> impl Iterator < Item = Entity > + ' _ {
168192 self . ensure_updated ( ) ;
169193
170194 self . index . get ( value)
171195 }
172196
197+ /// Get all [entities](`Entity`) with an `index`.
198+ pub fn get_by_index ( & mut self , index : & I :: Index ) -> impl Iterator < Item = Entity > + ' _ {
199+ self . ensure_updated ( ) ;
200+
201+ self . index . get_by_index ( index)
202+ }
203+
173204 /// Iterate over [entities](`Entity`) grouped by their [Index](`Indexer::Index`)
174205 pub fn iter (
175206 & mut self ,
176207 ) -> impl Iterator < Item = ( & I :: Index , impl Iterator < Item = Entity > + ' _ ) > + ' _ {
177208 self . ensure_updated ( ) ;
178209
179- self . index
180- . forward
181- . iter ( )
182- . map ( |( index, entities) | ( index, entities. iter ( ) . copied ( ) ) )
210+ self . index . iter ( )
211+ }
212+ }
213+
214+ /// Starts indexing the [`Component`] `T`. This provides access to the [`Index`] system parameter.
215+ pub struct IndexPlugin < T , F = ( ) , I = SimpleIndexer < T > > ( PhantomData < fn ( T , F , I ) > ) ;
216+
217+ impl < T , F , I > Default for IndexPlugin < T , F , I > {
218+ fn default ( ) -> Self {
219+ Self ( PhantomData )
220+ }
221+ }
222+
223+ impl < T , I , F > Plugin for IndexPlugin < T , F , I >
224+ where
225+ T : Component ,
226+ I : Indexer < Input = T > + ' static ,
227+ F : ReadOnlyWorldQuery + ' static ,
228+ I :: Index : Hash + Clone + Eq + Send + Sync + ' static ,
229+ {
230+ fn build ( & self , app : & mut App ) {
231+ app. init_resource :: < IndexBacking < T , F , I > > ( )
232+ . add_systems ( Update , Index :: < T , F , I > :: update_index) ;
183233 }
184234}
0 commit comments