Skip to content

Commit 64b27aa

Browse files
committed
init
1 parent c148665 commit 64b27aa

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
@@ -499,6 +501,63 @@ unsafe impl<'a, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOn
499501
{
500502
}
501503

504+
// SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
505+
// this Query conflicts with any prior access, a panic will occur.
506+
unsafe impl<'world, 'state, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
507+
for QueryNonEmpty<'world, 'state, D, F>
508+
{
509+
type State = QueryState<D, F>;
510+
type Item<'w, 's> = QueryNonEmpty<'w, 's, D, F>;
511+
512+
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
513+
Query::<'world, 'state, D, F>::init_state(world, system_meta)
514+
}
515+
516+
unsafe fn new_archetype(
517+
state: &mut Self::State,
518+
archetype: &Archetype,
519+
system_meta: &mut SystemMeta,
520+
) {
521+
// SAFETY: Delegate to existing `SystemParam` implementations.
522+
unsafe { Query::<'world, 'state, D, F>::new_archetype(state, archetype, system_meta) };
523+
}
524+
525+
#[inline]
526+
unsafe fn get_param<'w, 's>(
527+
state: &'s mut Self::State,
528+
system_meta: &SystemMeta,
529+
world: UnsafeWorldCell<'w>,
530+
change_tick: Tick,
531+
) -> Self::Item<'w, 's> {
532+
// SAFETY: Delegate to existing `SystemParam` implementations.
533+
let query = unsafe {
534+
Query::<'world, 'state, D, F>::get_param(state, system_meta, world, change_tick)
535+
};
536+
QueryNonEmpty(query)
537+
}
538+
539+
#[inline]
540+
unsafe fn validate_param(
541+
state: &Self::State,
542+
system_meta: &SystemMeta,
543+
world: UnsafeWorldCell,
544+
) -> bool {
545+
state.validate_world(world.id());
546+
// SAFETY:
547+
// - We have read-only access to the components accessed by query.
548+
// - The world has been validated.
549+
!unsafe {
550+
state.is_empty_unsafe_world_cell(world, system_meta.last_run, world.change_tick())
551+
}
552+
}
553+
}
554+
555+
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
556+
unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
557+
for QueryNonEmpty<'w, 's, D, F>
558+
{
559+
}
560+
502561
/// A collection of potentially conflicting [`SystemParam`]s allowed by disjoint access.
503562
///
504563
/// 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)