Skip to content

Commit 523f599

Browse files
committed
init
1 parent 1b84446 commit 523f599

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed

crates/bevy_ecs/src/system/query.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,3 +1667,32 @@ impl<'w, D: QueryData, F: QueryFilter> QuerySingle<'w, D, F> {
16671667
self.item
16681668
}
16691669
}
1670+
1671+
/// [System parameter] that works very much like [`Query`] except it always contains at least one matching entity.
1672+
///
1673+
/// This [`SystemParam`](crate::system::SystemParam) fails validation if no matching entities exist.
1674+
/// This will cause systems that use this parameter to be skipped.
1675+
///
1676+
/// See [`Query`] for more details.
1677+
pub struct QueryNonEmpty<'w, 's, D: QueryData, F: QueryFilter = ()>(pub(crate) Query<'w, 's, D, F>);
1678+
1679+
impl<'w, 's, D: QueryData, F: QueryFilter> Deref for QueryNonEmpty<'w, 's, D, F> {
1680+
type Target = Query<'w, 's, D, F>;
1681+
1682+
fn deref(&self) -> &Self::Target {
1683+
&self.0
1684+
}
1685+
}
1686+
1687+
impl<D: QueryData, F: QueryFilter> DerefMut for QueryNonEmpty<'_, '_, D, F> {
1688+
fn deref_mut(&mut self) -> &mut Self::Target {
1689+
&mut self.0
1690+
}
1691+
}
1692+
1693+
impl<'w, 's, D: QueryData, F: QueryFilter> QueryNonEmpty<'w, 's, D, F> {
1694+
/// Returns the inner item with ownership.
1695+
pub fn into_inner(self) -> Query<'w, 's, D, F> {
1696+
self.0
1697+
}
1698+
}

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use core::{
2626
ops::{Deref, DerefMut},
2727
};
2828

29+
use super::QueryNonEmpty;
30+
2931
/// A parameter that can be used in a [`System`](super::System).
3032
///
3133
/// # Derive
@@ -489,6 +491,63 @@ unsafe impl<'a, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOn
489491
{
490492
}
491493

494+
// SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
495+
// this Query conflicts with any prior access, a panic will occur.
496+
unsafe impl<'world, 'state, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
497+
for QueryNonEmpty<'world, 'state, D, F>
498+
{
499+
type State = QueryState<D, F>;
500+
type Item<'w, 's> = QueryNonEmpty<'w, 's, D, F>;
501+
502+
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
503+
Query::<'world, 'state, D, F>::init_state(world, system_meta)
504+
}
505+
506+
unsafe fn new_archetype(
507+
state: &mut Self::State,
508+
archetype: &Archetype,
509+
system_meta: &mut SystemMeta,
510+
) {
511+
// SAFETY: Delegate to existing `SystemParam` implementations.
512+
unsafe { Query::<'world, 'state, D, F>::new_archetype(state, archetype, system_meta) };
513+
}
514+
515+
#[inline]
516+
unsafe fn get_param<'w, 's>(
517+
state: &'s mut Self::State,
518+
system_meta: &SystemMeta,
519+
world: UnsafeWorldCell<'w>,
520+
change_tick: Tick,
521+
) -> Self::Item<'w, 's> {
522+
// SAFETY: Delegate to existing `SystemParam` implementations.
523+
let query = unsafe {
524+
Query::<'world, 'state, D, F>::get_param(state, system_meta, world, change_tick)
525+
};
526+
QueryNonEmpty(query)
527+
}
528+
529+
#[inline]
530+
unsafe fn validate_param(
531+
state: &Self::State,
532+
system_meta: &SystemMeta,
533+
world: UnsafeWorldCell,
534+
) -> bool {
535+
state.validate_world(world.id());
536+
// SAFETY:
537+
// - We have read-only access to the components accessed by query.
538+
// - The world has been validated.
539+
!unsafe {
540+
state.is_empty_unsafe_world_cell(world, system_meta.last_run, world.change_tick())
541+
}
542+
}
543+
}
544+
545+
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
546+
unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
547+
for QueryNonEmpty<'w, 's, D, F>
548+
{
549+
}
550+
492551
/// A collection of potentially conflicting [`SystemParam`]s allowed by disjoint access.
493552
///
494553
/// Allows systems to safely access and interact with up to 8 mutually exclusive [`SystemParam`]s, such as

examples/ecs/fallible_params.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
//! - [`Res<R>`], [`ResMut<R>`] - If resource doesn't exist.
66
//! - [`QuerySingle<D, F>`] - If there is no or more than one entities matching.
77
//! - [`Option<QuerySingle<D, F>>`] - If there are more than one entities matching.
8+
//! - [`QueryNonEmpty<D, F>`] - If there are no matching entities matching.
89
9-
use bevy::prelude::*;
10+
use bevy::{ecs::system::QueryNonEmpty, prelude::*};
1011
use rand::Rng;
1112

1213
fn main() {
@@ -105,9 +106,9 @@ fn user_input(
105106
}
106107

107108
// System that moves the enemies in a circle.
108-
// TODO: Use [`NonEmptyQuery`] when it exists.
109-
fn move_targets(mut enemies: Query<(&mut Transform, &mut Enemy)>, time: Res<Time>) {
110-
for (mut transform, mut target) in &mut enemies {
109+
// Only runs if there are enemies.
110+
fn move_targets(mut enemies: QueryNonEmpty<(&mut Transform, &mut Enemy)>, time: Res<Time>) {
111+
for (mut transform, mut target) in &mut *enemies {
111112
target.rotation += target.rotation_speed * time.delta_seconds();
112113
transform.rotation = Quat::from_rotation_z(target.rotation);
113114
let offset = transform.right() * target.radius;

0 commit comments

Comments
 (0)