@@ -7,10 +7,10 @@ use crate::{
7
7
entity:: Entities ,
8
8
query:: {
9
9
Access , AccessConflicts , FilteredAccess , FilteredAccessSet , QueryData , QueryFilter ,
10
- QueryState , ReadOnlyQueryData ,
10
+ QuerySingleError , QueryState , ReadOnlyQueryData ,
11
11
} ,
12
12
storage:: { ResourceData , SparseSetIndex } ,
13
- system:: { Query , SystemMeta } ,
13
+ system:: { Query , QuerySingle , SystemMeta } ,
14
14
world:: { unsafe_world_cell:: UnsafeWorldCell , DeferredWorld , FromWorld , World } ,
15
15
} ;
16
16
use bevy_ecs_macros:: impl_param_set;
@@ -227,12 +227,21 @@ pub unsafe trait SystemParam: Sized {
227
227
/// The [`world`](UnsafeWorldCell) can only be used to read param's data
228
228
/// and world metadata. No data can be written.
229
229
///
230
+ /// When using system parameters that require `change_tick` you can use
231
+ /// [`UnsafeWorldCell::change_tick()`]. Even if this isn't the exact
232
+ /// same tick used for [`SystemParam::get_param`], the world access
233
+ /// ensures that the queried data will be the same in both calls.
234
+ ///
235
+ /// This method has to be called directly before [`SystemParam::get_param`] with no other (relevant)
236
+ /// world mutations inbetween. Otherwise, while it won't lead to any undefined behavior,
237
+ /// the validity of the param may change.
238
+ ///
230
239
/// # Safety
231
240
///
232
241
/// - The passed [`UnsafeWorldCell`] must have read-only access to world data
233
242
/// registered in [`init_state`](SystemParam::init_state).
234
243
/// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).
235
- /// - all `world`'s archetypes have been processed by [`new_archetype`](SystemParam::new_archetype).
244
+ /// - All `world`'s archetypes have been processed by [`new_archetype`](SystemParam::new_archetype).
236
245
unsafe fn validate_param (
237
246
_state : & Self :: State ,
238
247
_system_meta : & SystemMeta ,
@@ -356,6 +365,140 @@ fn assert_component_access_compatibility(
356
365
panic ! ( "error[B0001]: Query<{query_type}, {filter_type}> in system {system_name} accesses component(s){accesses} in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevyengine.org/learn/errors/b0001" ) ;
357
366
}
358
367
368
+ // SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
369
+ // this Query conflicts with any prior access, a panic will occur.
370
+ unsafe impl < ' a , D : QueryData + ' static , F : QueryFilter + ' static > SystemParam
371
+ for QuerySingle < ' a , D , F >
372
+ {
373
+ type State = QueryState < D , F > ;
374
+ type Item < ' w , ' s > = QuerySingle < ' w , D , F > ;
375
+
376
+ fn init_state ( world : & mut World , system_meta : & mut SystemMeta ) -> Self :: State {
377
+ Query :: init_state ( world, system_meta)
378
+ }
379
+
380
+ unsafe fn new_archetype (
381
+ state : & mut Self :: State ,
382
+ archetype : & Archetype ,
383
+ system_meta : & mut SystemMeta ,
384
+ ) {
385
+ // SAFETY: Delegate to existing `SystemParam` implementations.
386
+ unsafe { Query :: new_archetype ( state, archetype, system_meta) } ;
387
+ }
388
+
389
+ #[ inline]
390
+ unsafe fn get_param < ' w , ' s > (
391
+ state : & ' s mut Self :: State ,
392
+ system_meta : & SystemMeta ,
393
+ world : UnsafeWorldCell < ' w > ,
394
+ change_tick : Tick ,
395
+ ) -> Self :: Item < ' w , ' s > {
396
+ state. validate_world ( world. id ( ) ) ;
397
+ // SAFETY: State ensures that the components it accesses are not accessible somewhere elsewhere.
398
+ let result =
399
+ unsafe { state. get_single_unchecked_manual ( world, system_meta. last_run , change_tick) } ;
400
+ let single =
401
+ result. expect ( "The query was expected to contain exactly one matching entity." ) ;
402
+ QuerySingle {
403
+ item : single,
404
+ _filter : PhantomData ,
405
+ }
406
+ }
407
+
408
+ #[ inline]
409
+ unsafe fn validate_param (
410
+ state : & Self :: State ,
411
+ system_meta : & SystemMeta ,
412
+ world : UnsafeWorldCell ,
413
+ ) -> bool {
414
+ state. validate_world ( world. id ( ) ) ;
415
+ // SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
416
+ // and the query is read only.
417
+ let result = unsafe {
418
+ state. as_readonly ( ) . get_single_unchecked_manual (
419
+ world,
420
+ system_meta. last_run ,
421
+ world. change_tick ( ) ,
422
+ )
423
+ } ;
424
+ result. is_ok ( )
425
+ }
426
+ }
427
+
428
+ // SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
429
+ // this Query conflicts with any prior access, a panic will occur.
430
+ unsafe impl < ' a , D : QueryData + ' static , F : QueryFilter + ' static > SystemParam
431
+ for Option < QuerySingle < ' a , D , F > >
432
+ {
433
+ type State = QueryState < D , F > ;
434
+ type Item < ' w , ' s > = Option < QuerySingle < ' w , D , F > > ;
435
+
436
+ fn init_state ( world : & mut World , system_meta : & mut SystemMeta ) -> Self :: State {
437
+ QuerySingle :: init_state ( world, system_meta)
438
+ }
439
+
440
+ unsafe fn new_archetype (
441
+ state : & mut Self :: State ,
442
+ archetype : & Archetype ,
443
+ system_meta : & mut SystemMeta ,
444
+ ) {
445
+ // SAFETY: Delegate to existing `SystemParam` implementations.
446
+ unsafe { QuerySingle :: new_archetype ( state, archetype, system_meta) } ;
447
+ }
448
+
449
+ #[ inline]
450
+ unsafe fn get_param < ' w , ' s > (
451
+ state : & ' s mut Self :: State ,
452
+ system_meta : & SystemMeta ,
453
+ world : UnsafeWorldCell < ' w > ,
454
+ change_tick : Tick ,
455
+ ) -> Self :: Item < ' w , ' s > {
456
+ state. validate_world ( world. id ( ) ) ;
457
+ // SAFETY: State ensures that the components it accesses are not accessible elsewhere.
458
+ let result =
459
+ unsafe { state. get_single_unchecked_manual ( world, system_meta. last_run , change_tick) } ;
460
+ match result {
461
+ Ok ( single) => Some ( QuerySingle {
462
+ item : single,
463
+ _filter : PhantomData ,
464
+ } ) ,
465
+ Err ( QuerySingleError :: NoEntities ( _) ) => None ,
466
+ Err ( QuerySingleError :: MultipleEntities ( e) ) => panic ! ( "{}" , e) ,
467
+ }
468
+ }
469
+
470
+ #[ inline]
471
+ unsafe fn validate_param (
472
+ state : & Self :: State ,
473
+ system_meta : & SystemMeta ,
474
+ world : UnsafeWorldCell ,
475
+ ) -> bool {
476
+ state. validate_world ( world. id ( ) ) ;
477
+ // SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
478
+ // and the query is read only.
479
+ let result = unsafe {
480
+ state. as_readonly ( ) . get_single_unchecked_manual (
481
+ world,
482
+ system_meta. last_run ,
483
+ world. change_tick ( ) ,
484
+ )
485
+ } ;
486
+ !matches ! ( result, Err ( QuerySingleError :: MultipleEntities ( _) ) )
487
+ }
488
+ }
489
+
490
+ // SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
491
+ unsafe impl < ' a , D : ReadOnlyQueryData + ' static , F : QueryFilter + ' static > ReadOnlySystemParam
492
+ for QuerySingle < ' a , D , F >
493
+ {
494
+ }
495
+
496
+ // SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
497
+ unsafe impl < ' a , D : ReadOnlyQueryData + ' static , F : QueryFilter + ' static > ReadOnlySystemParam
498
+ for Option < QuerySingle < ' a , D , F > >
499
+ {
500
+ }
501
+
359
502
/// A collection of potentially conflicting [`SystemParam`]s allowed by disjoint access.
360
503
///
361
504
/// Allows systems to safely access and interact with up to 8 mutually exclusive [`SystemParam`]s, such as
@@ -1172,11 +1315,10 @@ unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
1172
1315
/// the scheduler to instead run the system on the main thread so that it doesn't send the resource
1173
1316
/// over to another thread.
1174
1317
///
1175
- /// # Panics
1176
- ///
1177
- /// Panics when used as a `SystemParameter` if the resource does not exist.
1318
+ /// This [`SystemParam`] fails validation if non-send resource doesn't exist.
1319
+ /// This will cause systems that use this parameter to be skipped.
1178
1320
///
1179
- /// Use `Option<NonSend<T>>` instead if the resource might not always exist.
1321
+ /// Use [ `Option<NonSend<T>>`] instead if the resource might not always exist.
1180
1322
pub struct NonSend < ' w , T : ' static > {
1181
1323
pub ( crate ) value : & ' w T ,
1182
1324
ticks : ComponentTicks ,
0 commit comments