ParamSet
for conflicting SystemParam
:s (#2765)
# Objective Add a system parameter `ParamSet` to be used as container for conflicting parameters. ## Solution Added two methods to the SystemParamState trait, which gives the access used by the parameter. Did the implementation. Added some convenience methods to FilteredAccessSet. Changed `get_conflicts` to return every conflicting component instead of breaking on the first conflicting `FilteredAccess`. Co-authored-by: bilsen <40690317+bilsen@users.noreply.github.com>
This commit is contained in:
parent
7ff3d876fa
commit
63fee2572b
2
.github/contributing/example_style_guide.md
vendored
2
.github/contributing/example_style_guide.md
vendored
@ -36,7 +36,7 @@ For more advice on writing examples, see the [relevant section](../../CONTRIBUTI
|
|||||||
2. Prefer `for` loops over `.for_each`. The latter is faster (for now), but it is less clear for beginners, less idiomatic, and less flexible.
|
2. Prefer `for` loops over `.for_each`. The latter is faster (for now), but it is less clear for beginners, less idiomatic, and less flexible.
|
||||||
3. Use `.single` and `.single_mut` where appropriate.
|
3. Use `.single` and `.single_mut` where appropriate.
|
||||||
4. In Queries, prefer `With<T>` filters over actually fetching unused data with `&T`.
|
4. In Queries, prefer `With<T>` filters over actually fetching unused data with `&T`.
|
||||||
5. Prefer disjoint queries using `With` and `Without` over query sets when you need more than one query in a single system.
|
5. Prefer disjoint queries using `With` and `Without` over param sets when you need more than one query in a single system.
|
||||||
6. Prefer structs with named fields over tuple structs except in the case of single-field wrapper types.
|
6. Prefer structs with named fields over tuple structs except in the case of single-field wrapper types.
|
||||||
7. Use enum-labels over string-labels for system / stage / etc. labels.
|
7. Use enum-labels over string-labels for system / stage / etc. labels.
|
||||||
|
|
||||||
|
@ -178,88 +178,83 @@ fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec<Ident> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn impl_query_set(_input: TokenStream) -> TokenStream {
|
pub fn impl_param_set(_input: TokenStream) -> TokenStream {
|
||||||
let mut tokens = TokenStream::new();
|
let mut tokens = TokenStream::new();
|
||||||
let max_queries = 4;
|
let max_params = 8;
|
||||||
let queries = get_idents(|i| format!("Q{}", i), max_queries);
|
let params = get_idents(|i| format!("P{}", i), max_params);
|
||||||
let filters = get_idents(|i| format!("F{}", i), max_queries);
|
let params_fetch = get_idents(|i| format!("PF{}", i), max_params);
|
||||||
let mut query_fn_muts = Vec::new();
|
let metas = get_idents(|i| format!("m{}", i), max_params);
|
||||||
for i in 0..max_queries {
|
let mut param_fn_muts = Vec::new();
|
||||||
let query = &queries[i];
|
for (i, param) in params.iter().enumerate() {
|
||||||
let filter = &filters[i];
|
let fn_name = Ident::new(&format!("p{}", i), Span::call_site());
|
||||||
let fn_name = Ident::new(&format!("q{}", i), Span::call_site());
|
|
||||||
let index = Index::from(i);
|
let index = Index::from(i);
|
||||||
query_fn_muts.push(quote! {
|
param_fn_muts.push(quote! {
|
||||||
pub fn #fn_name(&mut self) -> Query<'_, '_, #query, #filter> {
|
pub fn #fn_name<'a>(&'a mut self) -> <#param::Fetch as SystemParamFetch<'a, 'a>>::Item {
|
||||||
// SAFE: systems run without conflicts with other systems.
|
// SAFE: systems run without conflicts with other systems.
|
||||||
// Conflicting queries in QuerySet are not accessible at the same time
|
// Conflicting params in ParamSet are not accessible at the same time
|
||||||
// QuerySets are guaranteed to not conflict with other SystemParams
|
// ParamSets are guaranteed to not conflict with other SystemParams
|
||||||
unsafe {
|
unsafe {
|
||||||
Query::new(self.world, &self.query_states.#index, self.last_change_tick, self.change_tick)
|
<#param::Fetch as SystemParamFetch<'a, 'a>>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for query_count in 1..=max_queries {
|
for param_count in 1..=max_params {
|
||||||
let query = &queries[0..query_count];
|
let param = ¶ms[0..param_count];
|
||||||
let filter = &filters[0..query_count];
|
let param_fetch = ¶ms_fetch[0..param_count];
|
||||||
let query_fn_mut = &query_fn_muts[0..query_count];
|
let meta = &metas[0..param_count];
|
||||||
|
let param_fn_mut = ¶m_fn_muts[0..param_count];
|
||||||
tokens.extend(TokenStream::from(quote! {
|
tokens.extend(TokenStream::from(quote! {
|
||||||
impl<'w, 's, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParam for QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)>
|
impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)>
|
||||||
where #(#filter::Fetch: FilterFetch,)*
|
|
||||||
{
|
{
|
||||||
type Fetch = QuerySetState<(#(QueryState<#query, #filter>,)*)>;
|
type Fetch = ParamSetState<(#(#param::Fetch,)*)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFE: All Queries are constrained to ReadOnlyFetch, so World is only read
|
// SAFE: All parameters are constrained to ReadOnlyFetch, so World is only read
|
||||||
unsafe impl<#(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> ReadOnlySystemParamFetch for QuerySetState<(#(QueryState<#query, #filter>,)*)>
|
|
||||||
where #(#query::Fetch: ReadOnlyFetch,)* #(#filter::Fetch: FilterFetch,)*
|
unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> ReadOnlySystemParamFetch for ParamSetState<(#(#param_fetch,)*)>
|
||||||
|
where #(#param_fetch: ReadOnlySystemParamFetch,)*
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// SAFE: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any QueryState conflicts
|
// SAFE: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts
|
||||||
// with any prior access, a panic will occur.
|
// with any prior access, a panic will occur.
|
||||||
unsafe impl<#(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamState for QuerySetState<(#(QueryState<#query, #filter>,)*)>
|
|
||||||
where #(#filter::Fetch: FilterFetch,)*
|
unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamState for ParamSetState<(#(#param_fetch,)*)>
|
||||||
{
|
{
|
||||||
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
|
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
|
||||||
#(
|
#(
|
||||||
let mut #query = QueryState::<#query, #filter>::new(world);
|
// Pretend to add each param to the system alone, see if it conflicts
|
||||||
assert_component_access_compatibility(
|
let mut #meta = system_meta.clone();
|
||||||
&system_meta.name,
|
#meta.component_access_set.clear();
|
||||||
std::any::type_name::<#query>(),
|
#meta.archetype_component_access.clear();
|
||||||
std::any::type_name::<#filter>(),
|
#param_fetch::init(world, &mut #meta);
|
||||||
&system_meta.component_access_set,
|
let #param = #param_fetch::init(world, &mut system_meta.clone());
|
||||||
&#query.component_access,
|
|
||||||
world,
|
|
||||||
);
|
|
||||||
)*
|
)*
|
||||||
#(
|
#(
|
||||||
system_meta
|
system_meta
|
||||||
.component_access_set
|
.component_access_set
|
||||||
.add(#query.component_access.clone());
|
.extend(#meta.component_access_set);
|
||||||
system_meta
|
system_meta
|
||||||
.archetype_component_access
|
.archetype_component_access
|
||||||
.extend(&#query.archetype_component_access);
|
.extend(&#meta.archetype_component_access);
|
||||||
)*
|
)*
|
||||||
QuerySetState((#(#query,)*))
|
ParamSetState((#(#param,)*))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
|
fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) {
|
||||||
let (#(#query,)*) = &mut self.0;
|
let (#(#param,)*) = &mut self.0;
|
||||||
#(
|
#(
|
||||||
#query.new_archetype(archetype);
|
#param.new_archetype(archetype, system_meta);
|
||||||
system_meta
|
|
||||||
.archetype_component_access
|
|
||||||
.extend(&#query.archetype_component_access);
|
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamFetch<'w, 's> for QuerySetState<(#(QueryState<#query, #filter>,)*)>
|
|
||||||
where #(#filter::Fetch: FilterFetch,)*
|
|
||||||
|
impl<'w, 's, #(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamFetch<'w, 's> for ParamSetState<(#(#param_fetch,)*)>
|
||||||
{
|
{
|
||||||
type Item = QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)>;
|
type Item = ParamSet<'w, 's, (#(<#param_fetch as SystemParamFetch<'w, 's>>::Item,)*)>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn get_param(
|
unsafe fn get_param(
|
||||||
@ -268,19 +263,19 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
|
|||||||
world: &'w World,
|
world: &'w World,
|
||||||
change_tick: u32,
|
change_tick: u32,
|
||||||
) -> Self::Item {
|
) -> Self::Item {
|
||||||
QuerySet {
|
ParamSet {
|
||||||
query_states: &state.0,
|
param_states: &mut state.0,
|
||||||
|
system_meta: system_meta.clone(),
|
||||||
world,
|
world,
|
||||||
last_change_tick: system_meta.last_change_tick,
|
|
||||||
change_tick,
|
change_tick,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, #(#query: WorldQuery,)* #(#filter: WorldQuery,)*> QuerySet<'w, 's, (#(QueryState<#query, #filter>,)*)>
|
impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)>
|
||||||
where #(#filter::Fetch: FilterFetch,)*
|
|
||||||
{
|
{
|
||||||
#(#query_fn_mut)*
|
|
||||||
|
#(#param_fn_mut)*
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ pub mod prelude {
|
|||||||
},
|
},
|
||||||
system::{
|
system::{
|
||||||
Commands, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend,
|
Commands, In, IntoChainSystem, IntoExclusiveSystem, IntoSystem, Local, NonSend,
|
||||||
NonSendMut, Query, QuerySet, RemovedComponents, Res, ResMut, System,
|
NonSendMut, ParamSet, Query, RemovedComponents, Res, ResMut, System,
|
||||||
SystemParamFunction,
|
SystemParamFunction,
|
||||||
},
|
},
|
||||||
world::{FromWorld, Mut, World},
|
world::{FromWorld, Mut, World},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::storage::SparseSetIndex;
|
use crate::storage::SparseSetIndex;
|
||||||
|
use bevy_utils::HashSet;
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ impl<T: SparseSetIndex> Access<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
pub struct FilteredAccess<T: SparseSetIndex> {
|
pub struct FilteredAccess<T: SparseSetIndex> {
|
||||||
access: Access<T>,
|
access: Access<T>,
|
||||||
with: FixedBitSet,
|
with: FixedBitSet,
|
||||||
@ -146,6 +147,14 @@ impl<T: SparseSetIndex> Default for FilteredAccess<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: SparseSetIndex> From<FilteredAccess<T>> for FilteredAccessSet<T> {
|
||||||
|
fn from(filtered_access: FilteredAccess<T>) -> Self {
|
||||||
|
let mut base = FilteredAccessSet::<T>::default();
|
||||||
|
base.add(filtered_access);
|
||||||
|
base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: SparseSetIndex> FilteredAccess<T> {
|
impl<T: SparseSetIndex> FilteredAccess<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn access(&self) -> &Access<T> {
|
pub fn access(&self) -> &Access<T> {
|
||||||
@ -191,7 +200,7 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
|
|||||||
self.access.read_all();
|
self.access.read_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct FilteredAccessSet<T: SparseSetIndex> {
|
pub struct FilteredAccessSet<T: SparseSetIndex> {
|
||||||
combined_access: Access<T>,
|
combined_access: Access<T>,
|
||||||
filtered_accesses: Vec<FilteredAccess<T>>,
|
filtered_accesses: Vec<FilteredAccess<T>>,
|
||||||
@ -211,22 +220,42 @@ impl<T: SparseSetIndex> FilteredAccessSet<T> {
|
|||||||
pub fn get_conflicts(&self, filtered_access: &FilteredAccess<T>) -> Vec<T> {
|
pub fn get_conflicts(&self, filtered_access: &FilteredAccess<T>) -> Vec<T> {
|
||||||
// if combined unfiltered access is incompatible, check each filtered access for
|
// if combined unfiltered access is incompatible, check each filtered access for
|
||||||
// compatibility
|
// compatibility
|
||||||
|
let mut conflicts = HashSet::<usize>::default();
|
||||||
if !filtered_access.access.is_compatible(&self.combined_access) {
|
if !filtered_access.access.is_compatible(&self.combined_access) {
|
||||||
for current_filtered_access in &self.filtered_accesses {
|
for current_filtered_access in &self.filtered_accesses {
|
||||||
if !current_filtered_access.is_compatible(filtered_access) {
|
if !current_filtered_access.is_compatible(filtered_access) {
|
||||||
return current_filtered_access
|
conflicts.extend(
|
||||||
|
current_filtered_access
|
||||||
.access
|
.access
|
||||||
.get_conflicts(&filtered_access.access);
|
.get_conflicts(&filtered_access.access)
|
||||||
|
.iter()
|
||||||
|
.map(|ind| ind.sparse_set_index()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vec::new()
|
conflicts
|
||||||
|
.iter()
|
||||||
|
.map(|ind| T::get_sparse_set_index(*ind))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, filtered_access: FilteredAccess<T>) {
|
pub fn add(&mut self, filtered_access: FilteredAccess<T>) {
|
||||||
self.combined_access.extend(&filtered_access.access);
|
self.combined_access.extend(&filtered_access.access);
|
||||||
self.filtered_accesses.push(filtered_access);
|
self.filtered_accesses.push(filtered_access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, filtered_access_set: FilteredAccessSet<T>) {
|
||||||
|
self.combined_access
|
||||||
|
.extend(&filtered_access_set.combined_access);
|
||||||
|
self.filtered_accesses
|
||||||
|
.extend(filtered_access_set.filtered_accesses);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.combined_access.clear();
|
||||||
|
self.filtered_accesses.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SparseSetIndex> Default for FilteredAccessSet<T> {
|
impl<T: SparseSetIndex> Default for FilteredAccessSet<T> {
|
||||||
|
@ -13,6 +13,7 @@ use bevy_ecs_macros::all_tuples;
|
|||||||
use std::{borrow::Cow, fmt::Debug, hash::Hash, marker::PhantomData};
|
use std::{borrow::Cow, fmt::Debug, hash::Hash, marker::PhantomData};
|
||||||
|
|
||||||
/// The metadata of a [`System`].
|
/// The metadata of a [`System`].
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SystemMeta {
|
pub struct SystemMeta {
|
||||||
pub(crate) name: Cow<'static, str>,
|
pub(crate) name: Cow<'static, str>,
|
||||||
pub(crate) component_access_set: FilteredAccessSet<ComponentId>,
|
pub(crate) component_access_set: FilteredAccessSet<ComponentId>,
|
||||||
|
@ -100,10 +100,10 @@ mod tests {
|
|||||||
bundle::Bundles,
|
bundle::Bundles,
|
||||||
component::{Component, Components},
|
component::{Component, Components},
|
||||||
entity::{Entities, Entity},
|
entity::{Entities, Entity},
|
||||||
query::{Added, Changed, Or, QueryState, With, Without},
|
query::{Added, Changed, Or, With, Without},
|
||||||
schedule::{Schedule, Stage, SystemStage},
|
schedule::{Schedule, Stage, SystemStage},
|
||||||
system::{
|
system::{
|
||||||
IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, Query, QuerySet,
|
IntoExclusiveSystem, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query,
|
||||||
RemovedComponents, Res, ResMut, System, SystemState,
|
RemovedComponents, Res, ResMut, System, SystemState,
|
||||||
},
|
},
|
||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
@ -211,17 +211,17 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn or_query_set_system() {
|
fn or_param_set_system() {
|
||||||
// Regression test for issue #762
|
// Regression test for issue #762
|
||||||
fn query_system(
|
fn query_system(
|
||||||
mut ran: ResMut<bool>,
|
mut ran: ResMut<bool>,
|
||||||
mut set: QuerySet<(
|
mut set: ParamSet<(
|
||||||
QueryState<(), Or<(Changed<A>, Changed<B>)>>,
|
Query<(), Or<(Changed<A>, Changed<B>)>>,
|
||||||
QueryState<(), Or<(Added<A>, Added<B>)>>,
|
Query<(), Or<(Added<A>, Added<B>)>>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
let changed = set.q0().iter().count();
|
let changed = set.p0().iter().count();
|
||||||
let added = set.q1().iter().count();
|
let added = set.p1().iter().count();
|
||||||
|
|
||||||
assert_eq!(changed, 1);
|
assert_eq!(changed, 1);
|
||||||
assert_eq!(added, 1);
|
assert_eq!(added, 1);
|
||||||
@ -320,7 +320,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn query_set_system() {
|
fn query_set_system() {
|
||||||
fn sys(mut _set: QuerySet<(QueryState<&mut A>, QueryState<&A>)>) {}
|
fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {}
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
run_system(&mut world, sys);
|
run_system(&mut world, sys);
|
||||||
}
|
}
|
||||||
@ -328,7 +328,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn conflicting_query_with_query_set_system() {
|
fn conflicting_query_with_query_set_system() {
|
||||||
fn sys(_query: Query<&mut A>, _set: QuerySet<(QueryState<&mut A>, QueryState<&B>)>) {}
|
fn sys(_query: Query<&mut A>, _set: ParamSet<(Query<&mut A>, Query<&B>)>) {}
|
||||||
|
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
run_system(&mut world, sys);
|
run_system(&mut world, sys);
|
||||||
@ -337,11 +337,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn conflicting_query_sets_system() {
|
fn conflicting_query_sets_system() {
|
||||||
fn sys(
|
fn sys(_set_1: ParamSet<(Query<&mut A>,)>, _set_2: ParamSet<(Query<&mut A>, Query<&B>)>) {}
|
||||||
_set_1: QuerySet<(QueryState<&mut A>,)>,
|
|
||||||
_set_2: QuerySet<(QueryState<&mut A>, QueryState<&B>)>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
run_system(&mut world, sys);
|
run_system(&mut world, sys);
|
||||||
@ -674,11 +670,8 @@ mod tests {
|
|||||||
world.insert_resource(A(42));
|
world.insert_resource(A(42));
|
||||||
world.spawn().insert(B(7));
|
world.spawn().insert(B(7));
|
||||||
|
|
||||||
let mut system_state: SystemState<(
|
let mut system_state: SystemState<(Res<A>, Query<&B>, ParamSet<(Query<&C>, Query<&D>)>)> =
|
||||||
Res<A>,
|
SystemState::new(&mut world);
|
||||||
Query<&B>,
|
|
||||||
QuerySet<(QueryState<&C>, QueryState<&D>)>,
|
|
||||||
)> = SystemState::new(&mut world);
|
|
||||||
let (a, query, _) = system_state.get(&world);
|
let (a, query, _) = system_state.get(&world);
|
||||||
assert_eq!(*a, A(42), "returned resource matches initial value");
|
assert_eq!(*a, A(42), "returned resource matches initial value");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -83,7 +83,7 @@ use thiserror::Error;
|
|||||||
///
|
///
|
||||||
/// Similarly, a system cannot contain two queries that would break Rust's mutability Rules.
|
/// Similarly, a system cannot contain two queries that would break Rust's mutability Rules.
|
||||||
/// If you need such Queries, you can use Filters to make the Queries disjoint or use a
|
/// If you need such Queries, you can use Filters to make the Queries disjoint or use a
|
||||||
/// [`QuerySet`](super::QuerySet).
|
/// [`ParamSet`](super::ParamSet).
|
||||||
///
|
///
|
||||||
/// ## Entity ID access
|
/// ## Entity ID access
|
||||||
///
|
///
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
pub use bevy_ecs_macros::SystemParam;
|
pub use bevy_ecs_macros::SystemParam;
|
||||||
use bevy_ecs_macros::{all_tuples, impl_query_set};
|
use bevy_ecs_macros::{all_tuples, impl_param_set};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@ -74,7 +74,7 @@ pub unsafe trait SystemParamState: Send + Sync + 'static {
|
|||||||
pub unsafe trait ReadOnlySystemParamFetch {}
|
pub unsafe trait ReadOnlySystemParamFetch {}
|
||||||
|
|
||||||
pub trait SystemParamFetch<'world, 'state>: SystemParamState {
|
pub trait SystemParamFetch<'world, 'state>: SystemParamState {
|
||||||
type Item;
|
type Item: SystemParam<Fetch = Self>;
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This call might access any of the input parameters in an unsafe way. Make sure the data
|
/// This call might access any of the input parameters in an unsafe way. Make sure the data
|
||||||
@ -170,21 +170,20 @@ fn assert_component_access_compatibility(
|
|||||||
.map(|component_id| world.components.get_info(component_id).unwrap().name())
|
.map(|component_id| world.components.get_info(component_id).unwrap().name())
|
||||||
.collect::<Vec<&str>>();
|
.collect::<Vec<&str>>();
|
||||||
let accesses = conflicting_components.join(", ");
|
let accesses = conflicting_components.join(", ");
|
||||||
panic!("error[B0001]: Query<{}, {}> in system {} accesses component(s) {} in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `QuerySet`.",
|
panic!("error[B0001]: Query<{}, {}> in system {} accesses component(s) {} 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`.",
|
||||||
query_type, filter_type, system_name, accesses);
|
query_type, filter_type, system_name, accesses);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QuerySet<'w, 's, T> {
|
pub struct ParamSet<'w, 's, T: SystemParam> {
|
||||||
query_states: &'s T,
|
param_states: &'s mut T::Fetch,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
last_change_tick: u32,
|
system_meta: SystemMeta,
|
||||||
change_tick: u32,
|
change_tick: u32,
|
||||||
}
|
}
|
||||||
|
/// The [`SystemParamState`] of [`ParamSet<T::Item>`].
|
||||||
|
pub struct ParamSetState<T: for<'w, 's> SystemParamFetch<'w, 's>>(T);
|
||||||
|
|
||||||
#[doc(hidden)]
|
impl_param_set!();
|
||||||
pub struct QuerySetState<T>(T);
|
|
||||||
|
|
||||||
impl_query_set!();
|
|
||||||
|
|
||||||
pub trait Resource: Send + Sync + 'static {}
|
pub trait Resource: Send + Sync + 'static {}
|
||||||
|
|
||||||
|
@ -3,22 +3,22 @@ use bevy_ecs::prelude::*;
|
|||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct A(usize);
|
struct A(usize);
|
||||||
|
|
||||||
fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>, e: Res<Entity>) {
|
fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res<Entity>) {
|
||||||
let mut q2 = queries.q0();
|
let mut q2 = queries.p0();
|
||||||
let mut b = q2.get_mut(*e).unwrap();
|
let mut b = q2.get_mut(*e).unwrap();
|
||||||
|
|
||||||
let q1 = queries.q1();
|
let q1 = queries.p1();
|
||||||
let a = q1.get(*e).unwrap();
|
let a = q1.get(*e).unwrap();
|
||||||
|
|
||||||
// this should fail to compile
|
// this should fail to compile
|
||||||
b.0 = a.0
|
b.0 = a.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_set_flip(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>, e: Res<Entity>) {
|
fn query_set_flip(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>, e: Res<Entity>) {
|
||||||
let q1 = queries.q1();
|
let q1 = queries.p1();
|
||||||
let a = q1.get(*e).unwrap();
|
let a = q1.get(*e).unwrap();
|
||||||
|
|
||||||
let mut q2 = queries.q0();
|
let mut q2 = queries.p0();
|
||||||
let mut b = q2.get_mut(*e).unwrap();
|
let mut b = q2.get_mut(*e).unwrap();
|
||||||
|
|
||||||
// this should fail to compile
|
// this should fail to compile
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
||||||
--> tests/ui/system_query_set_get_lifetime_safety.rs:10:14
|
--> tests/ui/system_query_set_get_lifetime_safety.rs:10:14
|
||||||
|
|
|
|
||||||
7 | let mut q2 = queries.q0();
|
7 | let mut q2 = queries.p0();
|
||||||
| ------------ first mutable borrow occurs here
|
| ------------ first mutable borrow occurs here
|
||||||
...
|
...
|
||||||
10 | let q1 = queries.q1();
|
10 | let q1 = queries.p1();
|
||||||
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
||||||
...
|
...
|
||||||
14 | b.0 = a.0
|
14 | b.0 = a.0
|
||||||
@ -13,10 +13,10 @@ error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
|||||||
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
||||||
--> tests/ui/system_query_set_get_lifetime_safety.rs:21:18
|
--> tests/ui/system_query_set_get_lifetime_safety.rs:21:18
|
||||||
|
|
|
|
||||||
18 | let q1 = queries.q1();
|
18 | let q1 = queries.p1();
|
||||||
| ------------ first mutable borrow occurs here
|
| ------------ first mutable borrow occurs here
|
||||||
...
|
...
|
||||||
21 | let mut q2 = queries.q0();
|
21 | let mut q2 = queries.p0();
|
||||||
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
||||||
...
|
...
|
||||||
25 | b.0 = a.0
|
25 | b.0 = a.0
|
||||||
|
@ -3,12 +3,12 @@ use bevy_ecs::prelude::*;
|
|||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct A(usize);
|
struct A(usize);
|
||||||
|
|
||||||
fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>) {
|
fn query_set(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>) {
|
||||||
let mut q2 = queries.q0();
|
let mut q2 = queries.p0();
|
||||||
let mut iter2 = q2.iter_mut();
|
let mut iter2 = q2.iter_mut();
|
||||||
let mut b = iter2.next().unwrap();
|
let mut b = iter2.next().unwrap();
|
||||||
|
|
||||||
let q1 = queries.q1();
|
let q1 = queries.p1();
|
||||||
let mut iter = q1.iter();
|
let mut iter = q1.iter();
|
||||||
let a = &*iter.next().unwrap();
|
let a = &*iter.next().unwrap();
|
||||||
|
|
||||||
@ -16,12 +16,12 @@ fn query_set(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>) {
|
|||||||
b.0 = a.0
|
b.0 = a.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_set_flip(mut queries: QuerySet<(QueryState<&mut A>, QueryState<&A>)>) {
|
fn query_set_flip(mut queries: ParamSet<(Query<&mut A>, Query<&A>)>) {
|
||||||
let q1 = queries.q1();
|
let q1 = queries.p1();
|
||||||
let mut iter = q1.iter();
|
let mut iter = q1.iter();
|
||||||
let a = &*iter.next().unwrap();
|
let a = &*iter.next().unwrap();
|
||||||
|
|
||||||
let mut q2 = queries.q0();
|
let mut q2 = queries.p0();
|
||||||
let mut iter2 = q2.iter_mut();
|
let mut iter2 = q2.iter_mut();
|
||||||
let mut b = iter2.next().unwrap();
|
let mut b = iter2.next().unwrap();
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
||||||
--> tests/ui/system_query_set_iter_lifetime_safety.rs:11:14
|
--> tests/ui/system_query_set_iter_lifetime_safety.rs:11:14
|
||||||
|
|
|
|
||||||
7 | let mut q2 = queries.q0();
|
7 | let mut q2 = queries.p0();
|
||||||
| ------------ first mutable borrow occurs here
|
| ------------ first mutable borrow occurs here
|
||||||
...
|
...
|
||||||
11 | let q1 = queries.q1();
|
11 | let q1 = queries.p1();
|
||||||
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
||||||
...
|
...
|
||||||
16 | b.0 = a.0
|
16 | b.0 = a.0
|
||||||
@ -13,10 +13,10 @@ error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
|||||||
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
error[E0499]: cannot borrow `queries` as mutable more than once at a time
|
||||||
--> tests/ui/system_query_set_iter_lifetime_safety.rs:24:18
|
--> tests/ui/system_query_set_iter_lifetime_safety.rs:24:18
|
||||||
|
|
|
|
||||||
20 | let q1 = queries.q1();
|
20 | let q1 = queries.p1();
|
||||||
| ------------ first mutable borrow occurs here
|
| ------------ first mutable borrow occurs here
|
||||||
...
|
...
|
||||||
24 | let mut q2 = queries.q0();
|
24 | let mut q2 = queries.p0();
|
||||||
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
| ^^^^^^^^^^^^ second mutable borrow occurs here
|
||||||
...
|
...
|
||||||
29 | b.0 = a.0;
|
29 | b.0 = a.0;
|
||||||
|
@ -110,9 +110,9 @@ fn queue_wireframes(
|
|||||||
mut pipelines: ResMut<SpecializedMeshPipelines<WireframePipeline>>,
|
mut pipelines: ResMut<SpecializedMeshPipelines<WireframePipeline>>,
|
||||||
mut pipeline_cache: ResMut<PipelineCache>,
|
mut pipeline_cache: ResMut<PipelineCache>,
|
||||||
msaa: Res<Msaa>,
|
msaa: Res<Msaa>,
|
||||||
mut material_meshes: QuerySet<(
|
mut material_meshes: ParamSet<(
|
||||||
QueryState<(Entity, &Handle<Mesh>, &MeshUniform)>,
|
Query<(Entity, &Handle<Mesh>, &MeshUniform)>,
|
||||||
QueryState<(Entity, &Handle<Mesh>, &MeshUniform), With<Wireframe>>,
|
Query<(Entity, &Handle<Mesh>, &MeshUniform), With<Wireframe>>,
|
||||||
)>,
|
)>,
|
||||||
mut views: Query<(&ExtractedView, &mut RenderPhase<Opaque3d>)>,
|
mut views: Query<(&ExtractedView, &mut RenderPhase<Opaque3d>)>,
|
||||||
) {
|
) {
|
||||||
@ -153,9 +153,9 @@ fn queue_wireframes(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if wireframe_config.global {
|
if wireframe_config.global {
|
||||||
material_meshes.q0().iter().for_each(add_render_phase);
|
material_meshes.p0().iter().for_each(add_render_phase);
|
||||||
} else {
|
} else {
|
||||||
material_meshes.q1().iter().for_each(add_render_phase);
|
material_meshes.p1().iter().for_each(add_render_phase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,14 @@ use crate::{
|
|||||||
use bevy_app::{App, CoreStage, Plugin, StartupStage};
|
use bevy_app::{App, CoreStage, Plugin, StartupStage};
|
||||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
change_detection::DetectChanges,
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::EventReader,
|
event::EventReader,
|
||||||
prelude::{DetectChanges, QueryState, With},
|
prelude::With,
|
||||||
query::Added,
|
query::Added,
|
||||||
reflect::ReflectComponent,
|
reflect::ReflectComponent,
|
||||||
system::{Commands, Query, QuerySet, Res, ResMut},
|
system::{Commands, ParamSet, Query, Res, ResMut},
|
||||||
};
|
};
|
||||||
use bevy_math::{Mat4, UVec2, Vec2, Vec3};
|
use bevy_math::{Mat4, UVec2, Vec2, Vec3};
|
||||||
use bevy_reflect::{Reflect, ReflectDeserialize};
|
use bevy_reflect::{Reflect, ReflectDeserialize};
|
||||||
@ -153,9 +154,9 @@ pub fn camera_system<T: CameraProjection + Component>(
|
|||||||
mut image_asset_events: EventReader<AssetEvent<Image>>,
|
mut image_asset_events: EventReader<AssetEvent<Image>>,
|
||||||
windows: Res<Windows>,
|
windows: Res<Windows>,
|
||||||
images: Res<Assets<Image>>,
|
images: Res<Assets<Image>>,
|
||||||
mut queries: QuerySet<(
|
mut queries: ParamSet<(
|
||||||
QueryState<(Entity, &mut Camera, &mut T)>,
|
Query<(Entity, &mut Camera, &mut T)>,
|
||||||
QueryState<Entity, Added<Camera>>,
|
Query<Entity, Added<Camera>>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
let mut changed_window_ids = Vec::new();
|
let mut changed_window_ids = Vec::new();
|
||||||
@ -191,10 +192,10 @@ pub fn camera_system<T: CameraProjection + Component>(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut added_cameras = vec![];
|
let mut added_cameras = vec![];
|
||||||
for entity in &mut queries.q1().iter() {
|
for entity in &mut queries.p1().iter() {
|
||||||
added_cameras.push(entity);
|
added_cameras.push(entity);
|
||||||
}
|
}
|
||||||
for (entity, mut camera, mut camera_projection) in queries.q0().iter_mut() {
|
for (entity, mut camera, mut camera_projection) in queries.p0().iter_mut() {
|
||||||
if camera
|
if camera
|
||||||
.target
|
.target
|
||||||
.is_changed(&changed_window_ids, &changed_image_handles)
|
.is_changed(&changed_window_ids, &changed_image_handles)
|
||||||
|
@ -140,9 +140,9 @@ pub fn update_frusta<T: Component + CameraProjection + Send + Sync + 'static>(
|
|||||||
|
|
||||||
pub fn check_visibility(
|
pub fn check_visibility(
|
||||||
mut view_query: Query<(&mut VisibleEntities, &Frustum, Option<&RenderLayers>), With<Camera>>,
|
mut view_query: Query<(&mut VisibleEntities, &Frustum, Option<&RenderLayers>), With<Camera>>,
|
||||||
mut visible_entity_query: QuerySet<(
|
mut visible_entity_query: ParamSet<(
|
||||||
QueryState<&mut ComputedVisibility>,
|
Query<&mut ComputedVisibility>,
|
||||||
QueryState<(
|
Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&Visibility,
|
&Visibility,
|
||||||
&mut ComputedVisibility,
|
&mut ComputedVisibility,
|
||||||
@ -154,7 +154,7 @@ pub fn check_visibility(
|
|||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
// Reset the computed visibility to false
|
// Reset the computed visibility to false
|
||||||
for mut computed_visibility in visible_entity_query.q0().iter_mut() {
|
for mut computed_visibility in visible_entity_query.p0().iter_mut() {
|
||||||
computed_visibility.is_visible = false;
|
computed_visibility.is_visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ pub fn check_visibility(
|
|||||||
maybe_aabb,
|
maybe_aabb,
|
||||||
maybe_no_frustum_culling,
|
maybe_no_frustum_culling,
|
||||||
maybe_transform,
|
maybe_transform,
|
||||||
) in visible_entity_query.q1().iter_mut()
|
) in visible_entity_query.p1().iter_mut()
|
||||||
{
|
{
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
continue;
|
continue;
|
||||||
|
@ -3,9 +3,9 @@ use bevy_ecs::{
|
|||||||
bundle::Bundle,
|
bundle::Bundle,
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Changed, QueryState, With},
|
query::{Changed, With},
|
||||||
reflect::ReflectComponent,
|
reflect::ReflectComponent,
|
||||||
system::{Local, Query, QuerySet, Res, ResMut},
|
system::{Local, ParamSet, Query, Res, ResMut},
|
||||||
};
|
};
|
||||||
use bevy_math::{Size, Vec3};
|
use bevy_math::{Size, Vec3};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
@ -138,13 +138,13 @@ pub fn text2d_system(
|
|||||||
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
||||||
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
||||||
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
||||||
mut text_queries: QuerySet<(
|
mut text_queries: ParamSet<(
|
||||||
QueryState<Entity, (With<Text2dSize>, Changed<Text>)>,
|
Query<Entity, (With<Text2dSize>, Changed<Text>)>,
|
||||||
QueryState<(&Text, Option<&Text2dBounds>, &mut Text2dSize), With<Text2dSize>>,
|
Query<(&Text, Option<&Text2dBounds>, &mut Text2dSize), With<Text2dSize>>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
// Adds all entities where the text or the style has changed to the local queue
|
// Adds all entities where the text or the style has changed to the local queue
|
||||||
for entity in text_queries.q0().iter_mut() {
|
for entity in text_queries.p0().iter_mut() {
|
||||||
queued_text.entities.push(entity);
|
queued_text.entities.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ pub fn text2d_system(
|
|||||||
|
|
||||||
// Computes all text in the local queue
|
// Computes all text in the local queue
|
||||||
let mut new_queue = Vec::new();
|
let mut new_queue = Vec::new();
|
||||||
let mut query = text_queries.q1();
|
let mut query = text_queries.p1();
|
||||||
for entity in queued_text.entities.drain(..) {
|
for entity in queued_text.entities.drain(..) {
|
||||||
if let Ok((text, bounds, mut calculated_size)) = query.get_mut(entity) {
|
if let Ok((text, bounds, mut calculated_size)) = query.get_mut(entity) {
|
||||||
let text_bounds = match bounds {
|
let text_bounds = match bounds {
|
||||||
|
@ -2,9 +2,8 @@ use crate::{CalculatedSize, Style, Val};
|
|||||||
use bevy_asset::Assets;
|
use bevy_asset::Assets;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
prelude::QueryState,
|
|
||||||
query::{Changed, Or, With},
|
query::{Changed, Or, With},
|
||||||
system::{Local, QuerySet, Res, ResMut},
|
system::{Local, ParamSet, Query, Res, ResMut},
|
||||||
};
|
};
|
||||||
use bevy_math::Size;
|
use bevy_math::Size;
|
||||||
use bevy_render::texture::Image;
|
use bevy_render::texture::Image;
|
||||||
@ -46,10 +45,10 @@ pub fn text_system(
|
|||||||
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
||||||
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
||||||
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
||||||
mut text_queries: QuerySet<(
|
mut text_queries: ParamSet<(
|
||||||
QueryState<Entity, Or<(Changed<Text>, Changed<Style>)>>,
|
Query<Entity, Or<(Changed<Text>, Changed<Style>)>>,
|
||||||
QueryState<Entity, (With<Text>, With<Style>)>,
|
Query<Entity, (With<Text>, With<Style>)>,
|
||||||
QueryState<(&Text, &Style, &mut CalculatedSize)>,
|
Query<(&Text, &Style, &mut CalculatedSize)>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
let scale_factor = windows.scale_factor(WindowId::primary());
|
let scale_factor = windows.scale_factor(WindowId::primary());
|
||||||
@ -59,12 +58,12 @@ pub fn text_system(
|
|||||||
#[allow(clippy::float_cmp)]
|
#[allow(clippy::float_cmp)]
|
||||||
if *last_scale_factor == scale_factor {
|
if *last_scale_factor == scale_factor {
|
||||||
// Adds all entities where the text or the style has changed to the local queue
|
// Adds all entities where the text or the style has changed to the local queue
|
||||||
for entity in text_queries.q0().iter() {
|
for entity in text_queries.p0().iter() {
|
||||||
queued_text.entities.push(entity);
|
queued_text.entities.push(entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the scale factor has changed, queue all text
|
// If the scale factor has changed, queue all text
|
||||||
for entity in text_queries.q1().iter() {
|
for entity in text_queries.p1().iter() {
|
||||||
queued_text.entities.push(entity);
|
queued_text.entities.push(entity);
|
||||||
}
|
}
|
||||||
*last_scale_factor = scale_factor;
|
*last_scale_factor = scale_factor;
|
||||||
@ -76,7 +75,7 @@ pub fn text_system(
|
|||||||
|
|
||||||
// Computes all text in the local queue
|
// Computes all text in the local queue
|
||||||
let mut new_queue = Vec::new();
|
let mut new_queue = Vec::new();
|
||||||
let mut query = text_queries.q2();
|
let mut query = text_queries.p2();
|
||||||
for entity in queued_text.entities.drain(..) {
|
for entity in queued_text.entities.drain(..) {
|
||||||
if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) {
|
if let Ok((text, style, mut calculated_size)) = query.get_mut(entity) {
|
||||||
let node_size = Size::new(
|
let node_size = Size::new(
|
||||||
|
@ -60,9 +60,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Solution #2: use a [`QuerySet`](https://docs.rs/bevy/*/bevy/ecs/system/struct.QuerySet.html)
|
Solution #2: use a `ParamSet`
|
||||||
|
|
||||||
A [`QuerySet`](https://docs.rs/bevy/*/bevy/ecs/system/struct.QuerySet.html) will let you have conflicting queries as a parameter, but you will still be responsible of not using them at the same time in your system.
|
A `ParamSet` will let you have conflicting queries as a parameter, but you will still be responsible of not using them at the same time in your system.
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@ -74,9 +74,9 @@ struct Player;
|
|||||||
struct Enemy;
|
struct Enemy;
|
||||||
|
|
||||||
fn move_enemies_to_player(
|
fn move_enemies_to_player(
|
||||||
mut transforms: QuerySet<(
|
mut transforms: ParamSet<(
|
||||||
QueryState<&mut Transform, With<Enemy>>,
|
Query<&mut Transform, With<Enemy>>,
|
||||||
QueryState<&Transform, With<Player>>,
|
Query<&Transform, With<Player>>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
// ...
|
// ...
|
||||||
|
@ -144,28 +144,28 @@ fn toggle_light(
|
|||||||
fn toggle_shadows(
|
fn toggle_shadows(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
input: Res<Input<KeyCode>>,
|
input: Res<Input<KeyCode>>,
|
||||||
mut queries: QuerySet<(
|
mut queries: ParamSet<(
|
||||||
QueryState<Entity, (With<Handle<Mesh>>, With<NotShadowCaster>)>,
|
Query<Entity, (With<Handle<Mesh>>, With<NotShadowCaster>)>,
|
||||||
QueryState<Entity, (With<Handle<Mesh>>, With<NotShadowReceiver>)>,
|
Query<Entity, (With<Handle<Mesh>>, With<NotShadowReceiver>)>,
|
||||||
QueryState<Entity, (With<Handle<Mesh>>, Without<NotShadowCaster>)>,
|
Query<Entity, (With<Handle<Mesh>>, Without<NotShadowCaster>)>,
|
||||||
QueryState<Entity, (With<Handle<Mesh>>, Without<NotShadowReceiver>)>,
|
Query<Entity, (With<Handle<Mesh>>, Without<NotShadowReceiver>)>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
if input.just_pressed(KeyCode::C) {
|
if input.just_pressed(KeyCode::C) {
|
||||||
println!("Toggling casters");
|
println!("Toggling casters");
|
||||||
for entity in queries.q0().iter() {
|
for entity in queries.p0().iter() {
|
||||||
commands.entity(entity).remove::<NotShadowCaster>();
|
commands.entity(entity).remove::<NotShadowCaster>();
|
||||||
}
|
}
|
||||||
for entity in queries.q2().iter() {
|
for entity in queries.p2().iter() {
|
||||||
commands.entity(entity).insert(NotShadowCaster);
|
commands.entity(entity).insert(NotShadowCaster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if input.just_pressed(KeyCode::R) {
|
if input.just_pressed(KeyCode::R) {
|
||||||
println!("Toggling receivers");
|
println!("Toggling receivers");
|
||||||
for entity in queries.q1().iter() {
|
for entity in queries.p1().iter() {
|
||||||
commands.entity(entity).remove::<NotShadowReceiver>();
|
commands.entity(entity).remove::<NotShadowReceiver>();
|
||||||
}
|
}
|
||||||
for entity in queries.q3().iter() {
|
for entity in queries.p3().iter() {
|
||||||
commands.entity(entity).insert(NotShadowReceiver);
|
commands.entity(entity).insert(NotShadowReceiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,15 +254,12 @@ fn move_player(
|
|||||||
fn focus_camera(
|
fn focus_camera(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut game: ResMut<Game>,
|
mut game: ResMut<Game>,
|
||||||
mut transforms: QuerySet<(
|
mut transforms: ParamSet<(Query<&mut Transform, With<Camera3d>>, Query<&Transform>)>,
|
||||||
QueryState<&mut Transform, With<Camera3d>>,
|
|
||||||
QueryState<&Transform>,
|
|
||||||
)>,
|
|
||||||
) {
|
) {
|
||||||
const SPEED: f32 = 2.0;
|
const SPEED: f32 = 2.0;
|
||||||
// if there is both a player and a bonus, target the mid-point of them
|
// if there is both a player and a bonus, target the mid-point of them
|
||||||
if let (Some(player_entity), Some(bonus_entity)) = (game.player.entity, game.bonus.entity) {
|
if let (Some(player_entity), Some(bonus_entity)) = (game.player.entity, game.bonus.entity) {
|
||||||
let transform_query = transforms.q1();
|
let transform_query = transforms.p1();
|
||||||
if let (Ok(player_transform), Ok(bonus_transform)) = (
|
if let (Ok(player_transform), Ok(bonus_transform)) = (
|
||||||
transform_query.get(player_entity),
|
transform_query.get(player_entity),
|
||||||
transform_query.get(bonus_entity),
|
transform_query.get(bonus_entity),
|
||||||
@ -273,7 +270,7 @@ fn focus_camera(
|
|||||||
}
|
}
|
||||||
// otherwise, if there is only a player, target the player
|
// otherwise, if there is only a player, target the player
|
||||||
} else if let Some(player_entity) = game.player.entity {
|
} else if let Some(player_entity) = game.player.entity {
|
||||||
if let Ok(player_transform) = transforms.q1().get(player_entity) {
|
if let Ok(player_transform) = transforms.p1().get(player_entity) {
|
||||||
game.camera_should_focus = player_transform.translation;
|
game.camera_should_focus = player_transform.translation;
|
||||||
}
|
}
|
||||||
// otherwise, target the middle
|
// otherwise, target the middle
|
||||||
@ -290,7 +287,7 @@ fn focus_camera(
|
|||||||
game.camera_is_focus += camera_motion;
|
game.camera_is_focus += camera_motion;
|
||||||
}
|
}
|
||||||
// look at that new camera's actual focus
|
// look at that new camera's actual focus
|
||||||
for mut transform in transforms.q0().iter_mut() {
|
for mut transform in transforms.p0().iter_mut() {
|
||||||
*transform = transform.looking_at(game.camera_is_focus, Vec3::Y);
|
*transform = transform.looking_at(game.camera_is_focus, Vec3::Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user