Flexible ECS System Params (#798)

system params can be in any order, faster compiles, remove foreach
This commit is contained in:
Carter Anderson 2020-11-08 12:34:05 -08:00 committed by GitHub
parent f54788527b
commit ebcdc9fb8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 953 additions and 1156 deletions

View File

@ -4,7 +4,7 @@ use crate::{
plugin::Plugin,
stage, startup_stage, PluginGroup, PluginGroupBuilder,
};
use bevy_ecs::{FromResources, IntoQuerySystem, Resources, System, World};
use bevy_ecs::{FromResources, IntoSystem, Resources, System, World};
/// Configure [App]s using the builder pattern
pub struct AppBuilder {

View File

@ -2,7 +2,7 @@ use crate::{
update_asset_storage_system, Asset, AssetLoader, AssetServer, Handle, HandleId, RefChange,
};
use bevy_app::{prelude::Events, AppBuilder};
use bevy_ecs::{FromResources, IntoQuerySystem, ResMut};
use bevy_ecs::{FromResources, IntoSystem, ResMut};
use bevy_type_registry::RegisterType;
use bevy_utils::HashMap;
use crossbeam_channel::Sender;

View File

@ -31,7 +31,7 @@ pub mod prelude {
}
use bevy_app::{prelude::Plugin, AppBuilder};
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
use bevy_type_registry::RegisterType;
/// Adds support for Assets to an App. Assets are typed collections with change tracking, which are added as App Resources.

View File

@ -1,7 +1,7 @@
use crate::{Diagnostic, DiagnosticId, Diagnostics};
use bevy_app::prelude::*;
use bevy_core::Time;
use bevy_ecs::{IntoQuerySystem, Res, ResMut};
use bevy_ecs::{IntoSystem, Res, ResMut};
/// Adds "frame time" diagnostic to an App, specifically "frame time", "fps" and "frame count"
#[derive(Default)]

View File

@ -18,7 +18,7 @@ impl Plugin for DiagnosticsPlugin {
app.init_resource::<Diagnostics>();
#[cfg(feature = "profiler")]
{
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
app.add_resource::<Box<dyn bevy_ecs::Profiler>>(Box::new(
system_profiler::SystemProfiler::default(),
))

View File

@ -1,7 +1,7 @@
use super::{Diagnostic, DiagnosticId, Diagnostics};
use bevy_app::prelude::*;
use bevy_core::{Time, Timer};
use bevy_ecs::{IntoQuerySystem, Res, ResMut};
use bevy_ecs::{IntoSystem, Res, ResMut};
use std::time::Duration;
/// An App Plugin that prints diagnostics to the console

View File

@ -22,7 +22,10 @@ use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use proc_macro_crate::crate_name;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Error, Ident, Index, Lifetime, Path, Result};
use syn::{
parse::ParseStream, parse_macro_input, Data, DataStruct, DeriveInput, Error, Field, Fields,
Ident, Index, Lifetime, Path, Result,
};
/// Implement `Bundle` for a monomorphic struct
///
@ -332,3 +335,92 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
tokens
}
#[derive(Default)]
struct SystemParamFieldAttributes {
pub ignore: bool,
}
static SYSTEM_PARAM_ATTRIBUTE_NAME: &str = "system_param";
#[proc_macro_derive(SystemParam, attributes(system_param))]
pub fn derive_system_param(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("expected a struct with named fields"),
};
let path_str = if crate_name("bevy").is_ok() {
"bevy::ecs"
} else {
"bevy_ecs"
};
let path: Path = syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap();
let field_attributes = fields
.iter()
.map(|field| {
(
field,
field
.attrs
.iter()
.find(|a| *a.path.get_ident().as_ref().unwrap() == SYSTEM_PARAM_ATTRIBUTE_NAME)
.map_or_else(SystemParamFieldAttributes::default, |a| {
syn::custom_keyword!(ignore);
let mut attributes = SystemParamFieldAttributes::default();
a.parse_args_with(|input: ParseStream| {
if input.parse::<Option<ignore>>()?.is_some() {
attributes.ignore = true;
}
Ok(())
})
.expect("invalid 'render_resources' attribute format");
attributes
}),
)
})
.collect::<Vec<(&Field, SystemParamFieldAttributes)>>();
let mut fields = Vec::new();
let mut field_types = Vec::new();
let mut ignored_fields = Vec::new();
let mut ignored_field_types = Vec::new();
for (field, attrs) in field_attributes.iter() {
if attrs.ignore {
ignored_fields.push(field.ident.as_ref().unwrap());
ignored_field_types.push(&field.ty);
} else {
fields.push(field.ident.as_ref().unwrap());
field_types.push(&field.ty);
}
}
let generics = ast.generics;
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
let struct_name = &ast.ident;
TokenStream::from(quote! {
impl #impl_generics #path::SystemParam for #struct_name#ty_generics {
fn init(system_state: &mut #path::SystemState, world: &#path::World, resources: &mut #path::Resources) {
#(<#field_types>::init(system_state, world, resources);)*
}
unsafe fn get_param(
system_state: &mut #path::SystemState,
world: &#path::World,
resources: &#path::Resources,
) -> Option<Self> {
Some(#struct_name {
#(#fields: <#field_types>::get_param(system_state, world, resources)?,)*
#(#ignored_fields: <#ignored_field_types>::default(),)*
})
}
}
})
}

View File

@ -98,4 +98,4 @@ pub use lazy_static;
pub use query::Fetch;
#[cfg(feature = "macros")]
pub use bevy_hecs_macros::{impl_query_set, Bundle};
pub use bevy_hecs_macros::{impl_query_set, Bundle, SystemParam};

View File

@ -296,7 +296,7 @@ impl_or_query!(Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10);
/// .collect::<Vec<_>>();
/// assert_eq!(components, &[(false, 457)]);
/// ```
pub struct Or<T>(PhantomData<T>);
pub struct Or<T>(pub T);
//pub struct Or<Q1, Q2, Q3>(PhantomData<(Q1, Q2, Q3)>);
#[doc(hidden)]

View File

@ -249,6 +249,7 @@ impl World {
/// assert!(entities.contains(&(a, 123, true)));
/// assert!(entities.contains(&(b, 456, false)));
/// ```
#[inline]
pub fn query<Q: Query>(&self) -> QueryIter<'_, Q>
where
Q::Fetch: ReadOnlyFetch,
@ -281,6 +282,7 @@ impl World {
/// assert!(entities.contains(&(a, 123, true)));
/// assert!(entities.contains(&(b, 456, false)));
/// ```
#[inline]
pub fn query_mut<Q: Query>(&mut self) -> QueryIter<'_, Q> {
// SAFE: unique mutable access
unsafe { self.query_unchecked() }
@ -288,6 +290,7 @@ impl World {
/// Like `query`, but instead of returning a single iterator it returns a "batched iterator",
/// where each batch is `batch_size`. This is generally used for parallel iteration.
#[inline]
pub fn query_batched<Q: Query>(&self, batch_size: usize) -> BatchedIter<'_, Q>
where
Q::Fetch: ReadOnlyFetch,
@ -298,6 +301,7 @@ impl World {
/// Like `query`, but instead of returning a single iterator it returns a "batched iterator",
/// where each batch is `batch_size`. This is generally used for parallel iteration.
#[inline]
pub fn query_batched_mut<Q: Query>(&mut self, batch_size: usize) -> BatchedIter<'_, Q> {
// SAFE: unique mutable access
unsafe { self.query_batched_unchecked(batch_size) }
@ -316,6 +320,7 @@ impl World {
/// # Safety
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
#[inline]
pub unsafe fn query_unchecked<Q: Query>(&self) -> QueryIter<'_, Q> {
QueryIter::new(&self.archetypes)
}
@ -347,6 +352,7 @@ impl World {
/// let (number, flag) = world.query_one::<(&i32, &bool)>(a).unwrap();
/// assert_eq!(*number, 123);
/// ```
#[inline]
pub fn query_one<Q: Query>(
&self,
entity: Entity,
@ -372,6 +378,7 @@ impl World {
/// if *flag { *number *= 2; }
/// assert_eq!(*number, 246);
/// ```
#[inline]
pub fn query_one_mut<Q: Query>(
&mut self,
entity: Entity,
@ -387,6 +394,7 @@ impl World {
/// # Safety
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
#[inline]
pub unsafe fn query_one_unchecked<Q: Query>(
&self,
entity: Entity,
@ -399,6 +407,7 @@ impl World {
}
/// Borrow the `T` component of `entity`
#[inline]
pub fn get<T: Component>(&self, entity: Entity) -> Result<&'_ T, ComponentError> {
unsafe {
let loc = self.entities.get(entity)?;
@ -414,6 +423,7 @@ impl World {
}
/// Mutably borrow the `T` component of `entity`
#[inline]
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Result<Mut<'_, T>, ComponentError> {
// SAFE: uniquely borrows world
unsafe { self.get_mut_unchecked(entity) }
@ -434,6 +444,7 @@ impl World {
/// # Safety
/// This does not check for mutable access correctness. To be safe, make sure this is the only
/// thing accessing this entity's T component.
#[inline]
pub unsafe fn get_mut_unchecked<T: Component>(
&self,
entity: Entity,

View File

@ -11,10 +11,8 @@ pub use world::*;
pub mod prelude {
pub use crate::{
resource::{ChangedRes, FromResources, Local, OrRes, Res, ResMut, Resource, Resources},
system::{
Commands, IntoForEachSystem, IntoQuerySystem, IntoThreadLocalSystem, Query, System,
},
resource::{ChangedRes, FromResources, Local, Res, ResMut, Resource, Resources},
system::{Commands, IntoSystem, IntoThreadLocalSystem, Query, System},
world::WorldBuilderSource,
Added, Bundle, Changed, Component, Entity, Mut, Mutated, Or, QuerySet, Ref, RefMut, With,
Without, World,

View File

@ -1,11 +1,10 @@
use super::{FromResources, Resources};
use crate::{system::SystemId, Resource, ResourceIndex};
use bevy_hecs::{smaller_tuples_too, TypeAccess};
use super::FromResources;
use crate::{Resource, ResourceIndex, Resources, SystemId};
use core::{
ops::{Deref, DerefMut},
ptr::NonNull,
};
use std::{any::TypeId, marker::PhantomData};
use std::marker::PhantomData;
// TODO: align TypeAccess api with Query::Fetch
@ -28,15 +27,6 @@ impl<'a, T: Resource> ChangedRes<'a, T> {
}
}
impl<'a, T: Resource> UnsafeClone for ChangedRes<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self { value: self.value }
}
}
unsafe impl<T: Resource> Send for ChangedRes<'_, T> {}
unsafe impl<T: Resource> Sync for ChangedRes<'_, T> {}
impl<'a, T: Resource> Deref for ChangedRes<'a, T> {
type Target = T;
@ -63,21 +53,6 @@ impl<'a, T: Resource> Res<'a, T> {
}
}
/// A clone that is unsafe to perform. You probably shouldn't use this.
pub trait UnsafeClone {
#[allow(clippy::missing_safety_doc)]
unsafe fn unsafe_clone(&self) -> Self;
}
impl<'a, T: Resource> UnsafeClone for Res<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self { value: self.value }
}
}
unsafe impl<T: Resource> Send for Res<'_, T> {}
unsafe impl<T: Resource> Sync for Res<'_, T> {}
impl<'a, T: Resource> Deref for Res<'a, T> {
type Target = T;
@ -108,9 +83,6 @@ impl<'a, T: Resource> ResMut<'a, T> {
}
}
unsafe impl<T: Resource> Send for ResMut<'_, T> {}
unsafe impl<T: Resource> Sync for ResMut<'_, T> {}
impl<'a, T: Resource> Deref for ResMut<'a, T> {
type Target = T;
@ -128,16 +100,6 @@ impl<'a, T: Resource> DerefMut for ResMut<'a, T> {
}
}
impl<'a, T: Resource> UnsafeClone for ResMut<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
value: self.value,
mutated: self.mutated,
_marker: Default::default(),
}
}
}
/// Local<T> resources are unique per-system. Two instances of the same system will each have their own resource.
/// Local resources are automatically initialized using the FromResources trait.
#[derive(Debug)]
@ -146,10 +108,12 @@ pub struct Local<'a, T: Resource + FromResources> {
_marker: PhantomData<&'a T>,
}
impl<'a, T: Resource + FromResources> UnsafeClone for Local<'a, T> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
value: self.value,
impl<'a, T: Resource + FromResources> Local<'a, T> {
pub(crate) unsafe fn new(resources: &Resources, id: SystemId) -> Self {
Local {
value: resources
.get_unsafe_ref::<T>(ResourceIndex::System(id))
.as_ptr(),
_marker: Default::default(),
}
}
@ -169,337 +133,45 @@ impl<'a, T: Resource + FromResources> DerefMut for Local<'a, T> {
}
}
/// A collection of resource types fetch from a `Resources` collection
pub trait ResourceQuery {
type Fetch: for<'a> FetchResource<'a>;
// #[cfg(test)]
// mod tests {
// use super::*;
fn initialize(_resources: &mut Resources, _system_id: Option<SystemId>) {}
}
// #[test]
// fn changed_resource() {
// let mut resources = Resources::default();
// resources.insert(123);
// assert_eq!(
// resources.query::<ChangedRes<i32>>().as_deref(),
// Some(&(123 as i32))
// );
// resources.clear_trackers();
// assert_eq!(resources.query::<ChangedRes<i32>>().as_deref(), None);
// *resources.query::<ResMut<i32>>().unwrap() += 1;
// assert_eq!(
// resources.query::<ChangedRes<i32>>().as_deref(),
// Some(&(124 as i32))
// );
// }
/// Streaming iterators over contiguous homogeneous ranges of resources
pub trait FetchResource<'a>: Sized {
/// Type of value to be fetched
type Item: UnsafeClone;
fn access() -> TypeAccess<TypeId>;
fn borrow(resources: &Resources);
fn release(resources: &Resources);
#[allow(clippy::missing_safety_doc)]
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item;
#[allow(clippy::missing_safety_doc)]
unsafe fn is_some(_resources: &'a Resources, _system_id: Option<SystemId>) -> bool {
true
}
}
impl<'a, T: Resource> ResourceQuery for Res<'a, T> {
type Fetch = FetchResourceRead<T>;
}
/// Fetches a shared resource reference
#[derive(Debug)]
pub struct FetchResourceRead<T>(NonNull<T>);
impl<'a, T: Resource> FetchResource<'a> for FetchResourceRead<T> {
type Item = Res<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
Res::new(resources.get_unsafe_ref::<T>(ResourceIndex::Global))
}
fn borrow(resources: &Resources) {
resources.borrow::<T>();
}
fn release(resources: &Resources) {
resources.release::<T>();
}
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
access.add_read(TypeId::of::<T>());
access
}
}
impl<'a, T: Resource> ResourceQuery for ChangedRes<'a, T> {
type Fetch = FetchResourceChanged<T>;
}
/// Fetches a shared resource reference
#[derive(Debug)]
pub struct FetchResourceChanged<T>(NonNull<T>);
impl<'a, T: Resource> FetchResource<'a> for FetchResourceChanged<T> {
type Item = ChangedRes<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
ChangedRes::new(resources.get_unsafe_ref::<T>(ResourceIndex::Global))
}
unsafe fn is_some(resources: &'a Resources, _system_id: Option<SystemId>) -> bool {
let (added, mutated) = resources.get_unsafe_added_and_mutated::<T>(ResourceIndex::Global);
*added.as_ptr() || *mutated.as_ptr()
}
fn borrow(resources: &Resources) {
resources.borrow::<T>();
}
fn release(resources: &Resources) {
resources.release::<T>();
}
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
access.add_read(TypeId::of::<T>());
access
}
}
impl<'a, T: Resource> ResourceQuery for ResMut<'a, T> {
type Fetch = FetchResourceWrite<T>;
}
/// Fetches a unique resource reference
#[derive(Debug)]
pub struct FetchResourceWrite<T>(NonNull<T>);
impl<'a, T: Resource> FetchResource<'a> for FetchResourceWrite<T> {
type Item = ResMut<'a, T>;
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
let (value, type_state) =
resources.get_unsafe_ref_with_type_state::<T>(ResourceIndex::Global);
ResMut::new(value, type_state.mutated())
}
fn borrow(resources: &Resources) {
resources.borrow_mut::<T>();
}
fn release(resources: &Resources) {
resources.release_mut::<T>();
}
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
access.add_write(TypeId::of::<T>());
access
}
}
impl<'a, T: Resource + FromResources> ResourceQuery for Local<'a, T> {
type Fetch = FetchResourceLocalMut<T>;
fn initialize(resources: &mut Resources, id: Option<SystemId>) {
let id = id.expect("Local<T> resources can only be used by systems");
// Only add the local resource if it doesn't already exist for this system
if resources.get_local::<T>(id).is_none() {
let value = T::from_resources(resources);
resources.insert_local(id, value);
}
}
}
/// Fetches a `Local<T>` resource reference
#[derive(Debug)]
pub struct FetchResourceLocalMut<T>(NonNull<T>);
impl<'a, T: Resource + FromResources> FetchResource<'a> for FetchResourceLocalMut<T> {
type Item = Local<'a, T>;
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item {
let id = system_id.expect("Local<T> resources can only be used by systems");
Local {
value: resources
.get_unsafe_ref::<T>(ResourceIndex::System(id))
.as_ptr(),
_marker: Default::default(),
}
}
fn borrow(resources: &Resources) {
resources.borrow_mut::<T>();
}
fn release(resources: &Resources) {
resources.release_mut::<T>();
}
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
access.add_write(TypeId::of::<T>());
access
}
}
macro_rules! tuple_impl {
($($name: ident),*) => {
impl<'a, $($name: FetchResource<'a>),*> FetchResource<'a> for ($($name,)*) {
type Item = ($($name::Item,)*);
#[allow(unused_variables)]
fn borrow(resources: &Resources) {
$($name::borrow(resources);)*
}
#[allow(unused_variables)]
fn release(resources: &Resources) {
$($name::release(resources);)*
}
#[allow(unused_variables)]
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item {
($($name::get(resources, system_id),)*)
}
#[allow(unused_variables)]
unsafe fn is_some(resources: &'a Resources, system_id: Option<SystemId>) -> bool {
true $(&& $name::is_some(resources, system_id))*
}
#[allow(unused_mut)]
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
$(access.union(&$name::access());)*
access
}
}
impl<$($name: ResourceQuery),*> ResourceQuery for ($($name,)*) {
type Fetch = ($($name::Fetch,)*);
#[allow(unused_variables)]
fn initialize(resources: &mut Resources, system_id: Option<SystemId>) {
$($name::initialize(resources, system_id);)*
}
}
#[allow(unused_variables)]
#[allow(non_snake_case)]
impl<$($name: UnsafeClone),*> UnsafeClone for ($($name,)*) {
unsafe fn unsafe_clone(&self) -> Self {
let ($($name,)*) = self;
($($name.unsafe_clone(),)*)
}
}
};
}
smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
#[derive(Debug)]
pub struct OrRes<T>(T);
#[derive(Debug)]
pub struct FetchResourceOr<T>(NonNull<T>);
macro_rules! tuple_impl_or {
($($name: ident),*) => {
impl<'a, $($name: FetchResource<'a>),*> FetchResource<'a> for FetchResourceOr<($($name,)*)> {
type Item = OrRes<($($name::Item,)*)>;
#[allow(unused_variables)]
fn borrow(resources: &Resources) {
$($name::borrow(resources);)*
}
#[allow(unused_variables)]
fn release(resources: &Resources) {
$($name::release(resources);)*
}
#[allow(unused_variables)]
unsafe fn get(resources: &'a Resources, system_id: Option<SystemId>) -> Self::Item {
OrRes(($($name::get(resources, system_id),)*))
}
#[allow(unused_variables)]
unsafe fn is_some(resources: &'a Resources, system_id: Option<SystemId>) -> bool {
false $(|| $name::is_some(resources, system_id))*
}
#[allow(unused_mut)]
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
$(access.union(&$name::access());)*
access
}
}
impl<$($name: ResourceQuery),*> ResourceQuery for OrRes<($($name,)*)> {
type Fetch = FetchResourceOr<($($name::Fetch,)*)>;
#[allow(unused_variables)]
fn initialize(resources: &mut Resources, system_id: Option<SystemId>) {
$($name::initialize(resources, system_id);)*
}
}
#[allow(unused_variables)]
#[allow(non_snake_case)]
impl<$($name: UnsafeClone),*> UnsafeClone for OrRes<($($name,)*)> {
unsafe fn unsafe_clone(&self) -> Self {
let OrRes(($($name,)*)) = self;
OrRes(($($name.unsafe_clone(),)*))
}
}
impl<$($name,)*> Deref for OrRes<($($name,)*)> {
type Target = ($($name,)*);
fn deref(&self) -> &Self::Target {
&self.0
}
}
};
}
smaller_tuples_too!(tuple_impl_or, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn changed_resource() {
let mut resources = Resources::default();
resources.insert(123);
assert_eq!(
resources.query::<ChangedRes<i32>>().as_deref(),
Some(&(123 as i32))
);
resources.clear_trackers();
assert_eq!(resources.query::<ChangedRes<i32>>().as_deref(), None);
*resources.query::<ResMut<i32>>().unwrap() += 1;
assert_eq!(
resources.query::<ChangedRes<i32>>().as_deref(),
Some(&(124 as i32))
);
}
#[test]
fn or_changed_resource() {
let mut resources = Resources::default();
resources.insert(123);
resources.insert(0.2);
assert!(resources
.query::<OrRes<(ChangedRes<i32>, ChangedRes<f64>)>>()
.is_some(),);
resources.clear_trackers();
assert!(resources
.query::<OrRes<(ChangedRes<i32>, ChangedRes<f64>)>>()
.is_none(),);
*resources.query::<ResMut<i32>>().unwrap() += 1;
assert!(resources
.query::<OrRes<(ChangedRes<i32>, ChangedRes<f64>)>>()
.is_some(),);
assert!(resources
.query::<(ChangedRes<i32>, ChangedRes<f64>)>()
.is_none(),);
}
}
// #[test]
// fn or_changed_resource() {
// let mut resources = Resources::default();
// resources.insert(123);
// resources.insert(0.2);
// assert!(resources
// .query::<OrRes<(ChangedRes<i32>, ChangedRes<f64>)>>()
// .is_some(),);
// resources.clear_trackers();
// assert!(resources
// .query::<OrRes<(ChangedRes<i32>, ChangedRes<f64>)>>()
// .is_none(),);
// *resources.query::<ResMut<i32>>().unwrap() += 1;
// assert!(resources
// .query::<OrRes<(ChangedRes<i32>, ChangedRes<f64>)>>()
// .is_some(),);
// assert!(resources
// .query::<(ChangedRes<i32>, ChangedRes<f64>)>()
// .is_none(),);
// }
// }

View File

@ -1,4 +1,3 @@
use super::{FetchResource, ResourceQuery};
use crate::system::SystemId;
use bevy_hecs::{Archetype, AtomicBorrow, Entity, Ref, RefMut, TypeInfo, TypeState};
use bevy_utils::HashMap;
@ -264,29 +263,6 @@ impl Resources {
})
}
pub fn query<Q: ResourceQuery>(&self) -> Option<<Q::Fetch as FetchResource>::Item> {
unsafe {
if Q::Fetch::is_some(&self, None) {
Some(Q::Fetch::get(&self, None))
} else {
None
}
}
}
pub fn query_system<Q: ResourceQuery>(
&self,
id: SystemId,
) -> Option<<Q::Fetch as FetchResource>::Item> {
unsafe {
if Q::Fetch::is_some(&self, Some(id)) {
Some(Q::Fetch::get(&self, Some(id)))
} else {
None
}
}
}
#[inline]
#[allow(clippy::missing_safety_doc)]
pub unsafe fn get_unsafe_ref<T: Resource>(&self, resource_index: ResourceIndex) -> NonNull<T> {

View File

@ -532,7 +532,7 @@ mod tests {
use crate::{
resource::{Res, ResMut, Resources},
schedule::Schedule,
system::{IntoQuerySystem, IntoThreadLocalSystem, Query},
system::{IntoSystem, IntoThreadLocalSystem, Query},
Commands,
};
use bevy_hecs::{Entity, World};
@ -556,7 +556,7 @@ mod tests {
schedule.add_stage("PreArchetypeChange");
schedule.add_stage("PostArchetypeChange");
fn insert(mut commands: Commands) {
fn insert(commands: &mut Commands) {
commands.spawn((1u32,));
}
@ -603,6 +603,7 @@ mod tests {
schedule.add_system_to_stage("update", insert.thread_local_system());
schedule.add_system_to_stage("update", read.system());
schedule.initialize(&mut world, &mut resources);
let mut executor = ParallelExecutor::default();
executor.run(&mut schedule, &mut world, &mut resources);
@ -743,6 +744,7 @@ mod tests {
schedule.add_system_to_stage("C", read_isize_res.system());
schedule.add_system_to_stage("C", read_isize_write_f64_res.system());
schedule.add_system_to_stage("C", write_f64_res.system());
schedule.initialize(&mut world, &mut resources);
fn run_executor_and_validate(
executor: &mut ParallelExecutor,

View File

@ -198,4 +198,14 @@ impl Schedule {
pub fn generation(&self) -> usize {
self.generation
}
pub fn run_on_systems(&mut self, mut func: impl FnMut(&mut dyn System)) {
for stage_name in self.stage_order.iter() {
if let Some(stage_systems) = self.stages.get_mut(stage_name) {
for system in stage_systems.iter_mut() {
func(&mut **system);
}
}
}
}
}

View File

@ -1,8 +1,7 @@
use super::SystemId;
use crate::resource::{Resource, Resources};
use bevy_hecs::{Bundle, Component, DynamicBundle, Entity, EntityReserver, World};
use parking_lot::Mutex;
use std::{marker::PhantomData, sync::Arc};
use std::marker::PhantomData;
/// A [World] mutation
pub trait Command: Send + Sync {
@ -157,13 +156,13 @@ impl<T: Resource> Command for InsertLocalResource<T> {
}
#[derive(Default)]
pub struct CommandsInternal {
pub commands: Vec<Box<dyn Command>>,
pub current_entity: Option<Entity>,
pub entity_reserver: Option<EntityReserver>,
pub struct Commands {
commands: Vec<Box<dyn Command>>,
current_entity: Option<Entity>,
entity_reserver: Option<EntityReserver>,
}
impl CommandsInternal {
impl Commands {
pub fn spawn(&mut self, components: impl DynamicBundle + Send + Sync + 'static) -> &mut Self {
let entity = self
.entity_reserver
@ -175,6 +174,66 @@ impl CommandsInternal {
self
}
pub fn spawn_batch<I>(&mut self, components_iter: I) -> &mut Self
where
I: IntoIterator + Send + Sync + 'static,
I::Item: Bundle,
{
self.add_command(SpawnBatch { components_iter })
}
/// Despawns only the specified entity, ignoring any other consideration.
pub fn despawn(&mut self, entity: Entity) -> &mut Self {
self.add_command(Despawn { entity })
}
pub fn insert(
&mut self,
entity: Entity,
components: impl DynamicBundle + Send + Sync + 'static,
) -> &mut Self {
self.add_command(Insert { entity, components })
}
pub fn insert_one(&mut self, entity: Entity, component: impl Component) -> &mut Self {
self.add_command(InsertOne { entity, component })
}
pub fn insert_resource<T: Resource>(&mut self, resource: T) -> &mut Self {
self.add_command(InsertResource { resource })
}
pub fn insert_local_resource<T: Resource>(
&mut self,
system_id: SystemId,
resource: T,
) -> &mut Self {
self.add_command(InsertLocalResource {
system_id,
resource,
})
}
pub fn remove_one<T>(&mut self, entity: Entity) -> &mut Self
where
T: Component,
{
self.add_command(RemoveOne::<T> {
entity,
phantom: PhantomData,
})
}
pub fn remove<T>(&mut self, entity: Entity) -> &mut Self
where
T: Bundle + Send + Sync + 'static,
{
self.add_command(Remove::<T> {
entity,
phantom: PhantomData,
})
}
pub fn with_bundle(
&mut self,
components: impl DynamicBundle + Send + Sync + 'static,
@ -205,137 +264,35 @@ impl CommandsInternal {
self.commands.push(command);
self
}
}
/// A queue of [Command]s to run on the current [World] and [Resources]. Todo: remove arc here
#[derive(Default, Clone)]
pub struct Commands {
pub commands: Arc<Mutex<CommandsInternal>>,
}
impl Commands {
pub fn spawn(&mut self, components: impl DynamicBundle + Send + Sync + 'static) -> &mut Self {
{
let mut commands = self.commands.lock();
commands.spawn(components);
}
self
}
pub fn spawn_batch<I>(&mut self, components_iter: I) -> &mut Self
where
I: IntoIterator + Send + Sync + 'static,
I::Item: Bundle,
{
self.add_command(SpawnBatch { components_iter })
}
/// Despawns only the specified entity, ignoring any other consideration.
pub fn despawn(&mut self, entity: Entity) -> &mut Self {
self.add_command(Despawn { entity })
}
pub fn with(&mut self, component: impl Component) -> &mut Self {
{
let mut commands = self.commands.lock();
commands.with(component);
}
self
}
pub fn with_bundle(
&mut self,
components: impl DynamicBundle + Send + Sync + 'static,
) -> &mut Self {
{
let mut commands = self.commands.lock();
commands.with_bundle(components);
}
self
}
pub fn insert(
&mut self,
entity: Entity,
components: impl DynamicBundle + Send + Sync + 'static,
) -> &mut Self {
self.add_command(Insert { entity, components })
}
pub fn insert_one(&mut self, entity: Entity, component: impl Component) -> &mut Self {
self.add_command(InsertOne { entity, component })
}
pub fn insert_resource<T: Resource>(&mut self, resource: T) -> &mut Self {
self.add_command(InsertResource { resource })
}
pub fn insert_local_resource<T: Resource>(
&mut self,
system_id: SystemId,
resource: T,
) -> &mut Self {
self.add_command(InsertLocalResource {
system_id,
resource,
})
}
pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self {
self.commands.lock().add_command(command);
self
}
pub fn add_command_boxed(&mut self, command: Box<dyn Command>) -> &mut Self {
self.commands.lock().add_command_boxed(command);
self
}
pub fn apply(&self, world: &mut World, resources: &mut Resources) {
let mut commands = self.commands.lock();
for command in commands.commands.drain(..) {
pub fn apply(&mut self, world: &mut World, resources: &mut Resources) {
for command in self.commands.drain(..) {
command.write(world, resources);
}
}
pub fn current_entity(&self) -> Option<Entity> {
let commands = self.commands.lock();
commands.current_entity
self.current_entity
}
pub fn set_current_entity(&mut self, entity: Entity) {
self.current_entity = Some(entity);
}
pub fn clear_current_entity(&mut self) {
self.current_entity = None;
}
pub fn for_current_entity(&mut self, f: impl FnOnce(Entity)) -> &mut Self {
{
let commands = self.commands.lock();
let current_entity = commands
.current_entity
.expect("The 'current entity' is not set. You should spawn an entity first.");
f(current_entity);
}
let current_entity = self
.current_entity
.expect("The 'current entity' is not set. You should spawn an entity first.");
f(current_entity);
self
}
pub fn remove_one<T>(&mut self, entity: Entity) -> &mut Self
where
T: Component,
{
self.add_command(RemoveOne::<T> {
entity,
phantom: PhantomData,
})
}
pub fn remove<T>(&mut self, entity: Entity) -> &mut Self
where
T: Bundle + Send + Sync + 'static,
{
self.add_command(Remove::<T> {
entity,
phantom: PhantomData,
})
}
pub fn set_entity_reserver(&self, entity_reserver: EntityReserver) {
self.commands.lock().entity_reserver = Some(entity_reserver);
pub fn set_entity_reserver(&mut self, entity_reserver: EntityReserver) {
self.entity_reserver = Some(entity_reserver);
}
}

View File

@ -1,424 +1,214 @@
pub use super::Query;
use crate::{
resource::{FetchResource, ResourceQuery, Resources, UnsafeClone},
system::{Commands, System, SystemId, ThreadLocalExecution},
QueryAccess, QuerySet, QueryTuple, TypeAccess,
};
use bevy_hecs::{ArchetypeComponent, Fetch, Query as HecsQuery, World};
use std::{any::TypeId, borrow::Cow};
use crate::{Commands, Resources, System, SystemId, SystemParam, ThreadLocalExecution};
use bevy_hecs::{ArchetypeComponent, QueryAccess, TypeAccess, World};
use parking_lot::Mutex;
use std::{any::TypeId, borrow::Cow, sync::Arc};
#[derive(Debug)]
pub(crate) struct SystemFn<State, F, ThreadLocalF, Init, Update>
where
F: FnMut(&World, &Resources, &mut State) + Send + Sync,
ThreadLocalF: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
Init: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
Update: FnMut(&World, &mut TypeAccess<ArchetypeComponent>, &mut State) + Send + Sync,
State: Send + Sync,
{
pub state: State,
pub func: F,
pub thread_local_func: ThreadLocalF,
pub init_func: Init,
pub thread_local_execution: ThreadLocalExecution,
pub resource_access: TypeAccess<TypeId>,
pub name: Cow<'static, str>,
pub id: SystemId,
pub archetype_component_access: TypeAccess<ArchetypeComponent>,
pub update_func: Update,
pub struct SystemState {
pub(crate) id: SystemId,
pub(crate) name: Cow<'static, str>,
pub(crate) is_initialized: bool,
pub(crate) archetype_component_access: TypeAccess<ArchetypeComponent>,
pub(crate) resource_access: TypeAccess<TypeId>,
pub(crate) query_archetype_component_accesses: Vec<TypeAccess<ArchetypeComponent>>,
pub(crate) query_accesses: Vec<Vec<QueryAccess>>,
pub(crate) query_type_names: Vec<&'static str>,
pub(crate) commands: Commands,
pub(crate) arc_commands: Option<Arc<Mutex<Commands>>>,
pub(crate) current_query_index: usize,
}
impl<State, F, ThreadLocalF, Init, Update> System for SystemFn<State, F, ThreadLocalF, Init, Update>
impl SystemState {
pub fn reset_indices(&mut self) {
self.current_query_index = 0;
}
pub fn update(&mut self, world: &World) {
self.archetype_component_access.clear();
let mut conflict_index = None;
let mut conflict_name = None;
for (i, (query_accesses, component_access)) in self
.query_accesses
.iter()
.zip(self.query_archetype_component_accesses.iter_mut())
.enumerate()
{
component_access.clear();
for query_access in query_accesses.iter() {
query_access.get_world_archetype_access(world, Some(component_access));
}
if !component_access.is_compatible(&self.archetype_component_access) {
conflict_index = Some(i);
conflict_name = component_access
.get_conflict(&self.archetype_component_access)
.and_then(|archetype_component| {
query_accesses
.iter()
.filter_map(|query_access| {
query_access.get_type_name(archetype_component.component)
})
.next()
});
break;
}
self.archetype_component_access.union(component_access);
}
if let Some(conflict_index) = conflict_index {
let mut conflicts_with_index = None;
for prior_index in 0..conflict_index {
if !self.query_archetype_component_accesses[conflict_index]
.is_compatible(&self.query_archetype_component_accesses[prior_index])
{
conflicts_with_index = Some(prior_index);
}
}
panic!("System {} has conflicting queries. {} conflicts with the component access [{}] in this prior query: {}",
core::any::type_name::<Self>(),
self.query_type_names[conflict_index],
conflict_name.unwrap_or("Unknown"),
conflicts_with_index.map(|index| self.query_type_names[index]).unwrap_or("Unknown"));
}
}
}
pub struct FuncSystem<F, Init, ThreadLocalFunc>
where
F: FnMut(&World, &Resources, &mut State) + Send + Sync,
ThreadLocalF: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
Init: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
Update: FnMut(&World, &mut TypeAccess<ArchetypeComponent>, &mut State) + Send + Sync,
State: Send + Sync,
F: FnMut(&mut SystemState, &World, &Resources) + Send + Sync + 'static,
Init: FnMut(&mut SystemState, &World, &mut Resources) + Send + Sync + 'static,
ThreadLocalFunc: FnMut(&mut SystemState, &mut World, &mut Resources) + Send + Sync + 'static,
{
fn name(&self) -> Cow<'static, str> {
self.name.clone()
}
func: F,
thread_local_func: ThreadLocalFunc,
init_func: Init,
state: SystemState,
}
fn update(&mut self, world: &World) {
(self.update_func)(world, &mut self.archetype_component_access, &mut self.state);
}
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
&self.archetype_component_access
}
fn resource_access(&self) -> &TypeAccess<TypeId> {
&self.resource_access
}
fn thread_local_execution(&self) -> ThreadLocalExecution {
self.thread_local_execution
}
#[inline]
fn run(&mut self, world: &World, resources: &Resources) {
(self.func)(world, resources, &mut self.state);
}
fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources) {
(self.thread_local_func)(world, resources, &mut self.state);
}
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
(self.init_func)(world, resources, &mut self.state);
impl<F, Init, ThreadLocalFunc> System for FuncSystem<F, Init, ThreadLocalFunc>
where
F: FnMut(&mut SystemState, &World, &Resources) + Send + Sync + 'static,
Init: FnMut(&mut SystemState, &World, &mut Resources) + Send + Sync + 'static,
ThreadLocalFunc: FnMut(&mut SystemState, &mut World, &mut Resources) + Send + Sync + 'static,
{
fn name(&self) -> std::borrow::Cow<'static, str> {
self.state.name.clone()
}
fn id(&self) -> SystemId {
self.id
self.state.id
}
fn update(&mut self, world: &World) {
self.state.update(world);
}
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
&self.state.archetype_component_access
}
fn resource_access(&self) -> &TypeAccess<std::any::TypeId> {
&self.state.resource_access
}
fn thread_local_execution(&self) -> ThreadLocalExecution {
ThreadLocalExecution::NextFlush
}
fn run(&mut self, world: &World, resources: &Resources) {
(self.func)(&mut self.state, world, resources)
}
fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources) {
(self.thread_local_func)(&mut self.state, world, resources)
}
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
(self.init_func)(&mut self.state, world, resources);
self.state.is_initialized = true;
}
fn is_initialized(&self) -> bool {
self.state.is_initialized
}
}
/// Converts `Self` into a For-Each system
pub trait IntoForEachSystem<CommandBuffer, R, C> {
pub trait IntoSystem<Params> {
fn system(self) -> Box<dyn System>;
}
struct ForEachState {
commands: Commands,
query_access: QueryAccess,
}
macro_rules! impl_into_foreach_system {
(($($commands: ident)*), ($($resource: ident),*), ($($component: ident),*)) => {
impl<Func, $($resource,)* $($component,)*> IntoForEachSystem<($($commands,)*), ($($resource,)*), ($($component,)*)> for Func
where
Func:
FnMut($($commands,)* $($resource,)* $($component,)*) +
FnMut(
$($commands,)*
$(<<$resource as ResourceQuery>::Fetch as FetchResource>::Item,)*
$(<<$component as HecsQuery>::Fetch as Fetch>::Item,)*)+
Send + Sync + 'static,
$($component: HecsQuery,)*
$($resource: ResourceQuery,)*
macro_rules! impl_into_system {
($($param: ident),*) => {
impl<Func, $($param: SystemParam),*> IntoSystem<($($param,)*)> for Func
where Func: FnMut($($param),*) + Send + Sync + 'static,
{
#[allow(non_snake_case)]
#[allow(unused_variables)]
#[allow(unused_unsafe)]
#[allow(non_snake_case)]
fn system(mut self) -> Box<dyn System> {
let id = SystemId::new();
Box::new(SystemFn {
state: ForEachState {
Box::new(FuncSystem {
state: SystemState {
name: std::any::type_name::<Self>().into(),
archetype_component_access: TypeAccess::default(),
resource_access: TypeAccess::default(),
is_initialized: false,
id: SystemId::new(),
commands: Commands::default(),
query_access: <($($component,)*) as HecsQuery>::Fetch::access(),
arc_commands: Default::default(),
query_archetype_component_accesses: Vec::new(),
query_accesses: Vec::new(),
query_type_names: Vec::new(),
current_query_index: 0,
},
thread_local_execution: ThreadLocalExecution::NextFlush,
name: core::any::type_name::<Self>().into(),
id,
func: move |world, resources, state| {
{
let state_commands = &state.commands;
if let Some(($($resource,)*)) = resources.query_system::<($($resource,)*)>(id) {
// SAFE: the scheduler has ensured that there is no archetype clashing here
unsafe {
for ($($component,)*) in world.query_unchecked::<($($component,)*)>() {
fn_call!(self, ($($commands, state_commands)*), ($($resource),*), ($($component),*))
}
}
func: move |state, world, resources| {
state.reset_indices();
unsafe {
if let Some(($($param,)*)) = <($($param,)*)>::get_param(state, world, resources) {
self($($param),*);
}
}
},
thread_local_func: move |world, resources, state| {
thread_local_func: |state, world, resources| {
state.commands.apply(world, resources);
if let Some(ref commands) = state.arc_commands {
let mut commands = commands.lock();
commands.apply(world, resources);
}
},
init_func: move |world, resources, state| {
<($($resource,)*)>::initialize(resources, Some(id));
state.commands.set_entity_reserver(world.get_entity_reserver())
},
resource_access: <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::access(),
archetype_component_access: TypeAccess::default(),
update_func: |world, archetype_component_access, state| {
archetype_component_access.clear();
state.query_access.get_world_archetype_access(world, Some(archetype_component_access));
init_func: |state, world, resources| {
$($param::init(state, world, resources);)*
},
})
}
}
};
}
struct QuerySystemState {
query_accesses: Vec<Vec<QueryAccess>>,
query_type_names: Vec<&'static str>,
archetype_component_accesses: Vec<TypeAccess<ArchetypeComponent>>,
commands: Commands,
}
/// Converts `Self` into a Query System
pub trait IntoQuerySystem<Commands, R, Q, QS> {
fn system(self) -> Box<dyn System>;
}
macro_rules! impl_into_query_system {
(($($commands: ident)*), ($($resource: ident),*), ($($query: ident),*), ($($query_set: ident),*)) => {
impl<Func, $($resource,)* $($query,)* $($query_set,)*> IntoQuerySystem<($($commands,)*), ($($resource,)*), ($($query,)*), ($($query_set,)*)> for Func where
Func:
FnMut($($commands,)* $($resource,)* $(Query<$query>,)* $(QuerySet<$query_set>,)*) +
FnMut(
$($commands,)*
$(<<$resource as ResourceQuery>::Fetch as FetchResource>::Item,)*
$(Query<$query>,)*
$(QuerySet<$query_set>,)*
) +
Send + Sync +'static,
$($query: HecsQuery,)*
$($query_set: QueryTuple,)*
$($resource: ResourceQuery,)*
{
#[allow(non_snake_case)]
#[allow(unused_variables)]
#[allow(unused_unsafe)]
#[allow(unused_assignments)]
#[allow(unused_mut)]
fn system(mut self) -> Box<dyn System> {
let id = SystemId::new();
let query_accesses = vec![
$(vec![<$query::Fetch as Fetch>::access()],)*
$($query_set::get_accesses(),)*
];
let query_type_names = vec![
$(std::any::type_name::<$query>(),)*
$(std::any::type_name::<$query_set>(),)*
];
let archetype_component_accesses = vec![TypeAccess::default(); query_accesses.len()];
Box::new(SystemFn {
state: QuerySystemState {
query_accesses,
query_type_names,
archetype_component_accesses,
commands: Commands::default(),
},
thread_local_execution: ThreadLocalExecution::NextFlush,
id,
name: core::any::type_name::<Self>().into(),
func: move |world, resources, state| {
{
if let Some(($($resource,)*)) = resources.query_system::<($($resource,)*)>(id) {
let mut i = 0;
$(
let $query = Query::<$query>::new(
world,
&state.archetype_component_accesses[i]
);
i += 1;
)*
$(
let $query_set = QuerySet::<$query_set>::new(
world,
&state.archetype_component_accesses[i]
);
i += 1;
)*
let commands = &state.commands;
fn_call!(self, ($($commands, commands)*), ($($resource),*), ($($query),*), ($($query_set),*))
}
}
},
thread_local_func: move |world, resources, state| {
state.commands.apply(world, resources);
},
init_func: move |world, resources, state| {
<($($resource,)*)>::initialize(resources, Some(id));
state.commands.set_entity_reserver(world.get_entity_reserver())
},
resource_access: <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::access(),
archetype_component_access: TypeAccess::default(),
update_func: |world, archetype_component_access, state| {
archetype_component_access.clear();
let mut conflict_index = None;
let mut conflict_name = None;
for (i, (query_accesses, component_access)) in state.query_accesses.iter().zip(state.archetype_component_accesses.iter_mut()).enumerate() {
component_access.clear();
for query_access in query_accesses.iter() {
query_access.get_world_archetype_access(world, Some(component_access));
}
if !component_access.is_compatible(archetype_component_access) {
conflict_index = Some(i);
conflict_name = component_access.get_conflict(archetype_component_access).and_then(|archetype_component|
query_accesses
.iter()
.filter_map(|query_access| query_access.get_type_name(archetype_component.component))
.next());
break;
}
archetype_component_access.union(component_access);
}
if let Some(conflict_index) = conflict_index {
let mut conflicts_with_index = None;
for prior_index in 0..conflict_index {
if !state.archetype_component_accesses[conflict_index].is_compatible(&state.archetype_component_accesses[prior_index]) {
conflicts_with_index = Some(prior_index);
}
}
panic!("System {} has conflicting queries. {} conflicts with the component access [{}] in this prior query: {}",
core::any::type_name::<Self>(),
state.query_type_names[conflict_index],
conflict_name.unwrap_or("Unknown"),
conflicts_with_index.map(|index| state.query_type_names[index]).unwrap_or("Unknown"));
}
},
})
}
}
};
}
macro_rules! fn_call {
($self:ident, ($($commands: ident, $commands_var: ident)*), ($($resource: ident),*), ($($a: ident),*), ($($b: ident),*)) => {
unsafe { $self($($commands_var.clone(),)* $($resource.unsafe_clone(),)* $($a,)* $($b,)*) }
};
($self:ident, ($($commands: ident, $commands_var: ident)*), ($($resource: ident),*), ($($a: ident),*)) => {
unsafe { $self($($commands_var.clone(),)* $($resource.unsafe_clone(),)* $($a,)*) }
};
($self:ident, (), ($($resource: ident),*), ($($a: ident),*)) => {
unsafe { $self($($resource.unsafe_clone(),)* $($a,)*) }
};
}
macro_rules! impl_into_query_systems {
(($($resource: ident,)*), ($($query: ident),*)) => {
#[rustfmt::skip]
impl_into_query_system!((), ($($resource),*), ($($query),*), ());
#[rustfmt::skip]
impl_into_query_system!((), ($($resource),*), ($($query),*), (QS1));
#[rustfmt::skip]
impl_into_query_system!((), ($($resource),*), ($($query),*), (QS1, QS2));
#[rustfmt::skip]
impl_into_query_system!((Commands), ($($resource),*), ($($query),*), ());
#[rustfmt::skip]
impl_into_query_system!((Commands), ($($resource),*), ($($query),*), (QS1));
#[rustfmt::skip]
impl_into_query_system!((Commands), ($($resource),*), ($($query),*), (QS1, QS2));
}
}
macro_rules! impl_into_foreach_systems {
(($($resource: ident,)*), ($($component: ident),*)) => {
#[rustfmt::skip]
impl_into_foreach_system!((), ($($resource),*), ($($component),*));
#[rustfmt::skip]
impl_into_foreach_system!((Commands), ($($resource),*), ($($component),*));
}
}
macro_rules! impl_into_systems {
($($resource: ident),*) => {
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B,C));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B,C,D));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B,C,D,E));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B,C,D,E,F));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B,C,D,E,F,G));
#[rustfmt::skip]
impl_into_foreach_systems!(($($resource,)*), (A,B,C,D,E,F,G,H));
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), ());
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), (A));
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), (A,B));
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), (A,B,C));
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), (A,B,C,D));
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), (A,B,C,D,E));
#[rustfmt::skip]
impl_into_query_systems!(($($resource,)*), (A,B,C,D,E,F));
};
}
#[rustfmt::skip]
impl_into_systems!();
#[rustfmt::skip]
impl_into_systems!(Ra);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf,Rg);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf,Rg,Rh);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf,Rg,Rh,Ri);
#[rustfmt::skip]
impl_into_systems!(Ra,Rb,Rc,Rd,Re,Rf,Rg,Rh,Ri,Rj);
/// Converts `Self` into a thread local system
pub trait IntoThreadLocalSystem {
fn thread_local_system(self) -> Box<dyn System>;
}
impl<F> IntoThreadLocalSystem for F
where
F: ThreadLocalSystemFn,
{
fn thread_local_system(mut self) -> Box<dyn System> {
Box::new(SystemFn {
state: (),
thread_local_func: move |world, resources, _| {
self.run(world, resources);
},
func: |_, _, _| {},
init_func: |_, _, _| {},
update_func: |_, _, _| {},
thread_local_execution: ThreadLocalExecution::Immediate,
name: core::any::type_name::<F>().into(),
id: SystemId::new(),
resource_access: TypeAccess::default(),
archetype_component_access: TypeAccess::default(),
})
}
}
/// A thread local system function
pub trait ThreadLocalSystemFn: Send + Sync + 'static {
fn run(&mut self, world: &mut World, resource: &mut Resources);
}
impl<F> ThreadLocalSystemFn for F
where
F: FnMut(&mut World, &mut Resources) + Send + Sync + 'static,
{
fn run(&mut self, world: &mut World, resources: &mut Resources) {
self(world, resources);
}
}
impl_into_system!();
impl_into_system!(A);
impl_into_system!(A, B);
impl_into_system!(A, B, C);
impl_into_system!(A, B, C, D);
impl_into_system!(A, B, C, D, E);
impl_into_system!(A, B, C, D, E, F);
impl_into_system!(A, B, C, D, E, F, G);
impl_into_system!(A, B, C, D, E, F, G, H);
impl_into_system!(A, B, C, D, E, F, G, H, I);
impl_into_system!(A, B, C, D, E, F, G, H, I, J);
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K);
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_into_system!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
#[cfg(test)]
mod tests {
use super::{IntoForEachSystem, IntoQuerySystem, Query};
use super::IntoSystem;
use crate::{
resource::{ResMut, Resources},
schedule::Schedule,
ChangedRes, Mut, QuerySet,
ChangedRes, Query, QuerySet, System,
};
use bevy_hecs::{Entity, With, World};
use bevy_hecs::{Entity, Or, With, World};
#[derive(Debug, Eq, PartialEq)]
struct A;
@ -480,11 +270,7 @@ mod tests {
world.spawn((A, C));
world.spawn((A, D));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", query_system.system());
schedule.run(&mut world, &mut resources);
run_system(&mut world, &mut resources, query_system.system());
assert!(*resources.get::<bool>().unwrap(), "system ran");
}
@ -493,14 +279,12 @@ mod tests {
fn or_query_set_system() {
// Regression test for issue #762
use crate::{Added, Changed, Mutated, Or};
fn query_system(
mut ran: ResMut<bool>,
set: QuerySet<(
Query<Or<(Changed<A>, Changed<B>)>>,
Query<Or<(Added<A>, Added<B>)>>,
Query<Or<(Mutated<A>, Mutated<B>)>>,
)>,
) {
let query_system = move |mut ran: ResMut<bool>,
set: QuerySet<(
Query<Or<(Changed<A>, Changed<B>)>>,
Query<Or<(Added<A>, Added<B>)>>,
Query<Or<(Mutated<A>, Mutated<B>)>>,
)>| {
let changed = set.q0().iter().count();
let added = set.q1().iter().count();
let mutated = set.q2().iter().count();
@ -510,26 +294,24 @@ mod tests {
assert_eq!(mutated, 0);
*ran = true;
}
};
let mut world = World::default();
let mut resources = Resources::default();
resources.insert(false);
world.spawn((A, B));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", query_system.system());
schedule.run(&mut world, &mut resources);
run_system(&mut world, &mut resources, query_system.system());
assert!(*resources.get::<bool>().unwrap(), "system ran");
}
#[test]
fn changed_resource_system() {
fn incr_e_on_flip(_run_on_flip: ChangedRes<bool>, mut i: Mut<i32>) {
*i += 1;
fn incr_e_on_flip(_run_on_flip: ChangedRes<bool>, mut query: Query<&mut i32>) {
for mut i in query.iter_mut() {
*i += 1;
}
}
let mut world = World::default();
@ -540,6 +322,7 @@ mod tests {
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", incr_e_on_flip.system());
schedule.initialize(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
@ -552,6 +335,46 @@ mod tests {
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
}
#[test]
fn changed_resource_or_system() {
fn incr_e_on_flip(
_or: Or<(Option<ChangedRes<bool>>, Option<ChangedRes<i32>>)>,
mut query: Query<&mut i32>,
) {
for mut i in query.iter_mut() {
*i += 1;
}
}
let mut world = World::default();
let mut resources = Resources::default();
resources.insert(false);
resources.insert::<i32>(10);
let ent = world.spawn((0,));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", incr_e_on_flip.system());
schedule.initialize(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
schedule.run(&mut world, &mut resources);
assert_eq!(*(world.get::<i32>(ent).unwrap()), 1);
*resources.get_mut::<bool>().unwrap() = true;
schedule.run(&mut world, &mut resources);
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
schedule.run(&mut world, &mut resources);
assert_eq!(*(world.get::<i32>(ent).unwrap()), 2);
*resources.get_mut::<i32>().unwrap() = 20;
schedule.run(&mut world, &mut resources);
assert_eq!(*(world.get::<i32>(ent).unwrap()), 3);
}
#[test]
#[should_panic]
fn conflicting_query_mut_system() {
@ -561,11 +384,7 @@ mod tests {
let mut resources = Resources::default();
world.spawn((A,));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", sys.system());
schedule.run(&mut world, &mut resources);
run_system(&mut world, &mut resources, sys.system());
}
#[test]
@ -577,11 +396,7 @@ mod tests {
let mut resources = Resources::default();
world.spawn((A,));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", sys.system());
schedule.run(&mut world, &mut resources);
run_system(&mut world, &mut resources, sys.system());
}
#[test]
@ -592,11 +407,7 @@ mod tests {
let mut resources = Resources::default();
world.spawn((A,));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", sys.system());
schedule.run(&mut world, &mut resources);
run_system(&mut world, &mut resources, sys.system());
}
#[test]
@ -608,11 +419,7 @@ mod tests {
let mut resources = Resources::default();
world.spawn((A,));
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", sys.system());
schedule.run(&mut world, &mut resources);
run_system(&mut world, &mut resources, sys.system());
}
#[test]
@ -623,11 +430,15 @@ mod tests {
let mut world = World::default();
let mut resources = Resources::default();
world.spawn((A,));
run_system(&mut world, &mut resources, sys.system());
}
fn run_system(world: &mut World, resources: &mut Resources, system: Box<dyn System>) {
let mut schedule = Schedule::default();
schedule.add_stage("update");
schedule.add_system_to_stage("update", sys.system());
schedule.add_system_to_stage("update", system);
schedule.run(&mut world, &mut resources);
schedule.initialize(world, resources);
schedule.run(world, resources);
}
}

View File

@ -0,0 +1,79 @@
pub use super::Query;
use crate::{
resource::Resources,
system::{System, SystemId, ThreadLocalExecution},
TypeAccess,
};
use bevy_hecs::{ArchetypeComponent, World};
use std::{any::TypeId, borrow::Cow};
#[derive(Debug)]
pub(crate) struct ThreadLocalSystemFn<Func>
where
Func: FnMut(&mut World, &mut Resources) + Send + Sync,
{
pub func: Func,
pub resource_access: TypeAccess<TypeId>,
pub archetype_component_access: TypeAccess<ArchetypeComponent>,
pub name: Cow<'static, str>,
pub id: SystemId,
}
impl<Func> System for ThreadLocalSystemFn<Func>
where
Func: FnMut(&mut World, &mut Resources) + Send + Sync,
{
fn name(&self) -> Cow<'static, str> {
self.name.clone()
}
fn update(&mut self, _world: &World) {}
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
&self.archetype_component_access
}
fn resource_access(&self) -> &TypeAccess<TypeId> {
&self.resource_access
}
fn thread_local_execution(&self) -> ThreadLocalExecution {
ThreadLocalExecution::Immediate
}
fn run(&mut self, _world: &World, _resources: &Resources) {}
fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources) {
(self.func)(world, resources);
}
fn initialize(&mut self, _world: &mut World, _resources: &mut Resources) {}
fn id(&self) -> SystemId {
self.id
}
fn is_initialized(&self) -> bool {
true
}
}
/// Converts `Self` into a thread local system
pub trait IntoThreadLocalSystem {
fn thread_local_system(self) -> Box<dyn System>;
}
impl<F> IntoThreadLocalSystem for F
where
F: FnMut(&mut World, &mut Resources) + Send + Sync + 'static,
{
fn thread_local_system(mut self) -> Box<dyn System> {
Box::new(ThreadLocalSystemFn {
func: move |world, resources| (self)(world, resources),
name: core::any::type_name::<F>().into(),
id: SystemId::new(),
resource_access: TypeAccess::default(),
archetype_component_access: TypeAccess::default(),
})
}
}

View File

@ -1,14 +1,18 @@
mod commands;
mod into_system;
mod into_thread_local;
#[cfg(feature = "profiler")]
mod profiler;
mod query;
#[allow(clippy::module_inception)]
mod system;
mod system_param;
pub use commands::*;
pub use into_system::*;
pub use into_thread_local::*;
#[cfg(feature = "profiler")]
pub use profiler::*;
pub use query::*;
pub use system::*;
pub use system_param::*;

View File

@ -27,8 +27,14 @@ pub enum QueryError {
}
impl<'a, Q: HecsQuery> Query<'a, Q> {
/// # Safety
/// This will create a Query that could violate memory safety rules. Make sure that this is only called in
/// ways that ensure the Queries have unique mutable access.
#[inline]
pub fn new(world: &'a World, component_access: &'a TypeAccess<ArchetypeComponent>) -> Self {
pub unsafe fn new(
world: &'a World,
component_access: &'a TypeAccess<ArchetypeComponent>,
) -> Self {
Self {
world,
component_access,
@ -37,6 +43,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
}
/// Iterates over the query results. This can only be called for read-only queries
#[inline]
pub fn iter(&self) -> QueryIter<'_, Q>
where
Q::Fetch: ReadOnlyFetch,
@ -46,6 +53,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
}
/// Iterates over the query results
#[inline]
pub fn iter_mut(&mut self) -> QueryIter<'_, Q> {
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
unsafe { self.world.query_unchecked() }
@ -54,6 +62,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
/// Iterates over the query results
/// # Safety
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
#[inline]
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, Q> {
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
self.world.query_unchecked()
@ -75,6 +84,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
}
/// Gets the query result for the given `entity`
#[inline]
pub fn get(&self, entity: Entity) -> Result<<Q::Fetch as Fetch>::Item, QueryError>
where
Q::Fetch: ReadOnlyFetch,
@ -88,6 +98,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
}
/// Gets the query result for the given `entity`
#[inline]
pub fn get_mut(&mut self, entity: Entity) -> Result<<Q::Fetch as Fetch>::Item, QueryError> {
// SAFE: system runs without conflicts with other systems. same-system queries have runtime borrow checks when they conflict
unsafe {
@ -100,6 +111,7 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
/// Gets the query result for the given `entity`
/// # Safety
/// This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component
#[inline]
pub unsafe fn get_unsafe(
&self,
entity: Entity,

View File

@ -17,9 +17,12 @@ pub trait QueryTuple {
}
impl<T: QueryTuple> QuerySet<T> {
pub fn new(world: &World, component_access: &TypeAccess<ArchetypeComponent>) -> Self {
/// # Safety
/// This will create a set of Query types that could violate memory safety rules. Make sure that this is only called in
/// ways that ensure the Queries have unique mutable access.
pub unsafe fn new(world: &World, component_access: &TypeAccess<ArchetypeComponent>) -> Self {
QuerySet {
value: unsafe { T::new(world, component_access) },
value: T::new(world, component_access),
}
}
}

View File

@ -23,6 +23,7 @@ impl SystemId {
pub trait System: Send + Sync {
fn name(&self) -> Cow<'static, str>;
fn id(&self) -> SystemId;
fn is_initialized(&self) -> bool;
fn update(&mut self, world: &World);
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent>;
fn resource_access(&self) -> &TypeAccess<TypeId>;

View File

@ -0,0 +1,255 @@
pub use bevy_hecs::SystemParam;
use crate::{
ChangedRes, Commands, FromResources, Local, Query, QuerySet, QueryTuple, Res, ResMut, Resource,
ResourceIndex, Resources, SystemState,
};
use bevy_hecs::{ArchetypeComponent, Fetch, Or, Query as HecsQuery, TypeAccess, World};
use parking_lot::Mutex;
use std::{any::TypeId, sync::Arc};
pub trait SystemParam: Sized {
fn init(system_state: &mut SystemState, world: &World, resources: &mut Resources);
/// # Safety
/// This call might access any of the input parameters in an unsafe way. Make sure the data access is safe in
/// the context of the system scheduler
unsafe fn get_param(
system_state: &mut SystemState,
world: &World,
resources: &Resources,
) -> Option<Self>;
}
impl<'a, Q: HecsQuery> SystemParam for Query<'a, Q> {
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
world: &World,
_resources: &Resources,
) -> Option<Self> {
let query_index = system_state.current_query_index;
let world: &'a World = std::mem::transmute(world);
let archetype_component_access: &'a TypeAccess<ArchetypeComponent> =
std::mem::transmute(&system_state.query_archetype_component_accesses[query_index]);
system_state.current_query_index += 1;
Some(Query::new(world, archetype_component_access))
}
fn init(system_state: &mut SystemState, _world: &World, _resources: &mut Resources) {
system_state
.query_archetype_component_accesses
.push(TypeAccess::default());
system_state
.query_accesses
.push(vec![<Q::Fetch as Fetch>::access()]);
system_state
.query_type_names
.push(std::any::type_name::<Q>());
}
}
impl<T: QueryTuple> SystemParam for QuerySet<T> {
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
world: &World,
_resources: &Resources,
) -> Option<Self> {
let query_index = system_state.current_query_index;
system_state.current_query_index += 1;
Some(QuerySet::new(
world,
&system_state.query_archetype_component_accesses[query_index],
))
}
fn init(system_state: &mut SystemState, _world: &World, _resources: &mut Resources) {
system_state
.query_archetype_component_accesses
.push(TypeAccess::default());
system_state.query_accesses.push(T::get_accesses());
system_state
.query_type_names
.push(std::any::type_name::<T>());
}
}
impl<'a> SystemParam for &'a mut Commands {
fn init(system_state: &mut SystemState, world: &World, _resources: &mut Resources) {
system_state
.commands
.set_entity_reserver(world.get_entity_reserver())
}
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
_world: &World,
_resources: &Resources,
) -> Option<Self> {
let commands: &'a mut Commands = std::mem::transmute(&mut system_state.commands);
Some(commands)
}
}
impl SystemParam for Arc<Mutex<Commands>> {
fn init(system_state: &mut SystemState, world: &World, _resources: &mut Resources) {
system_state.arc_commands.get_or_insert_with(|| {
let mut commands = Commands::default();
commands.set_entity_reserver(world.get_entity_reserver());
Arc::new(Mutex::new(commands))
});
}
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
_world: &World,
_resources: &Resources,
) -> Option<Self> {
Some(system_state.arc_commands.as_ref().unwrap().clone())
}
}
impl<'a, T: Resource> SystemParam for Res<'a, T> {
fn init(system_state: &mut SystemState, _world: &World, _resources: &mut Resources) {
system_state.resource_access.add_read(TypeId::of::<T>());
}
#[inline]
unsafe fn get_param(
_system_state: &mut SystemState,
_world: &World,
resources: &Resources,
) -> Option<Self> {
Some(Res::new(
resources.get_unsafe_ref::<T>(ResourceIndex::Global),
))
}
}
impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
fn init(system_state: &mut SystemState, _world: &World, _resources: &mut Resources) {
system_state.resource_access.add_write(TypeId::of::<T>());
}
#[inline]
unsafe fn get_param(
_system_state: &mut SystemState,
_world: &World,
resources: &Resources,
) -> Option<Self> {
let (value, type_state) =
resources.get_unsafe_ref_with_type_state::<T>(ResourceIndex::Global);
Some(ResMut::new(value, type_state.mutated()))
}
}
impl<'a, T: Resource> SystemParam for ChangedRes<'a, T> {
fn init(system_state: &mut SystemState, _world: &World, _resources: &mut Resources) {
system_state.resource_access.add_read(TypeId::of::<T>());
}
#[inline]
unsafe fn get_param(
_system_state: &mut SystemState,
_world: &World,
resources: &Resources,
) -> Option<Self> {
let (added, mutated) = resources.get_unsafe_added_and_mutated::<T>(ResourceIndex::Global);
if *added.as_ptr() || *mutated.as_ptr() {
Some(ChangedRes::new(
resources.get_unsafe_ref::<T>(ResourceIndex::Global),
))
} else {
None
}
}
}
impl<'a, T: Resource + FromResources> SystemParam for Local<'a, T> {
fn init(system_state: &mut SystemState, _world: &World, resources: &mut Resources) {
system_state.resource_access.add_write(TypeId::of::<T>());
if resources.get_local::<T>(system_state.id).is_none() {
let value = T::from_resources(resources);
resources.insert_local(system_state.id, value);
}
}
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
_world: &World,
resources: &Resources,
) -> Option<Self> {
Some(Local::new(resources, system_state.id))
}
}
macro_rules! impl_system_param_tuple {
($($param: ident),*) => {
#[allow(unused_variables)]
impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
fn init(system_state: &mut SystemState, world: &World, resources: &mut Resources) {
$($param::init(system_state, world, resources);)*
}
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
world: &World,
resources: &Resources,
) -> Option<Self> {
Some(($($param::get_param(system_state, world, resources)?,)*))
}
}
#[allow(unused_variables)]
#[allow(unused_mut)]
#[allow(non_snake_case)]
impl<$($param: SystemParam),*> SystemParam for Or<($(Option<$param>,)*)> {
fn init(system_state: &mut SystemState, world: &World, resources: &mut Resources) {
$($param::init(system_state, world, resources);)*
}
#[inline]
unsafe fn get_param(
system_state: &mut SystemState,
world: &World,
resources: &Resources,
) -> Option<Self> {
let mut has_some = false;
$(
let $param = $param::get_param(system_state, world, resources);
if $param.is_some() {
has_some = true;
}
)*
if has_some {
Some(Or(($($param,)*)))
} else {
None
}
}
}
};
}
impl_system_param_tuple!();
impl_system_param_tuple!(A);
impl_system_param_tuple!(A, B);
impl_system_param_tuple!(A, B, C);
impl_system_param_tuple!(A, B, C, D);
impl_system_param_tuple!(A, B, C, D, E);
impl_system_param_tuple!(A, B, C, D, E, F);
impl_system_param_tuple!(A, B, C, D, E, F, G);
impl_system_param_tuple!(A, B, C, D, E, F, G, H);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J, K);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_system_param_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);

View File

@ -28,7 +28,7 @@ use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotio
use touch::{touch_screen_input_system, TouchInput, Touches};
use bevy_app::startup_stage::STARTUP;
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
use gamepad::{
gamepad_event_system, GamepadAxis, GamepadButton, GamepadEvent, GamepadEventRaw,
GamepadSettings,

View File

@ -14,7 +14,7 @@ pub mod prelude {
use bevy_app::prelude::*;
use bevy_asset::{AddAsset, Assets, Handle};
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
use bevy_render::{prelude::Color, render_graph::RenderGraph, shader};
use bevy_type_registry::RegisterType;
use light::Light;

View File

@ -3,7 +3,7 @@ use crate::{
render_graph::uniform,
};
use bevy_core::{AsBytes, Byteable};
use bevy_ecs::{Commands, IntoQuerySystem, Local, Query, Res, ResMut, Resources, System, World};
use bevy_ecs::{Commands, IntoSystem, Local, Query, Res, ResMut, Resources, System, World};
use bevy_render::{
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
renderer::{

View File

@ -10,12 +10,9 @@ use crate::{
shader::Shader,
};
use bevy_asset::{Assets, Handle};
use bevy_ecs::{
FetchResource, Query, Res, ResMut, ResourceIndex, ResourceQuery, Resources, SystemId,
TypeAccess, UnsafeClone,
};
use bevy_ecs::{Query, Res, ResMut, SystemParam};
use bevy_property::Properties;
use std::{any::TypeId, ops::Range, sync::Arc};
use std::{ops::Range, sync::Arc};
use thiserror::Error;
/// A queued command for the renderer
@ -125,100 +122,20 @@ pub enum DrawError {
BufferAllocationFailure,
}
//#[derive(Debug)]
#[derive(SystemParam)]
pub struct DrawContext<'a> {
pub pipelines: ResMut<'a, Assets<PipelineDescriptor>>,
pub shaders: ResMut<'a, Assets<Shader>>,
pub pipeline_compiler: ResMut<'a, PipelineCompiler>,
pub render_resource_context: Res<'a, Box<dyn RenderResourceContext>>,
pub shared_buffers: Res<'a, SharedBuffers>,
#[system_param(ignore)]
pub current_pipeline: Option<Handle<PipelineDescriptor>>,
}
impl<'a> UnsafeClone for DrawContext<'a> {
unsafe fn unsafe_clone(&self) -> Self {
Self {
pipelines: self.pipelines.unsafe_clone(),
shaders: self.shaders.unsafe_clone(),
pipeline_compiler: self.pipeline_compiler.unsafe_clone(),
render_resource_context: self.render_resource_context.unsafe_clone(),
shared_buffers: self.shared_buffers.unsafe_clone(),
current_pipeline: self.current_pipeline.clone(),
}
}
}
impl<'a> ResourceQuery for DrawContext<'a> {
type Fetch = FetchDrawContext;
}
#[derive(Debug)]
pub struct FetchDrawContext;
// TODO: derive this impl
impl<'a> FetchResource<'a> for FetchDrawContext {
type Item = DrawContext<'a>;
fn borrow(resources: &Resources) {
resources.borrow_mut::<Assets<PipelineDescriptor>>();
resources.borrow_mut::<Assets<Shader>>();
resources.borrow_mut::<PipelineCompiler>();
resources.borrow::<Box<dyn RenderResourceContext>>();
resources.borrow::<SharedBuffers>();
}
fn release(resources: &Resources) {
resources.release_mut::<Assets<PipelineDescriptor>>();
resources.release_mut::<Assets<Shader>>();
resources.release_mut::<PipelineCompiler>();
resources.release::<Box<dyn RenderResourceContext>>();
resources.release::<SharedBuffers>();
}
unsafe fn get(resources: &'a Resources, _system_id: Option<SystemId>) -> Self::Item {
let pipelines = {
let (value, type_state) = resources
.get_unsafe_ref_with_type_state::<Assets<PipelineDescriptor>>(
ResourceIndex::Global,
);
ResMut::new(value, type_state.mutated())
};
let shaders = {
let (value, type_state) =
resources.get_unsafe_ref_with_type_state::<Assets<Shader>>(ResourceIndex::Global);
ResMut::new(value, type_state.mutated())
};
let pipeline_compiler = {
let (value, type_state) =
resources.get_unsafe_ref_with_type_state::<PipelineCompiler>(ResourceIndex::Global);
ResMut::new(value, type_state.mutated())
};
DrawContext {
pipelines,
shaders,
pipeline_compiler,
render_resource_context: Res::new(
resources.get_unsafe_ref::<Box<dyn RenderResourceContext>>(ResourceIndex::Global),
),
shared_buffers: Res::new(
resources.get_unsafe_ref::<SharedBuffers>(ResourceIndex::Global),
),
current_pipeline: None,
}
}
fn access() -> TypeAccess<TypeId> {
let mut access = TypeAccess::default();
access.add_write(TypeId::of::<Assets<PipelineDescriptor>>());
access.add_write(TypeId::of::<Assets<Shader>>());
access.add_write(TypeId::of::<PipelineCompiler>());
access.add_read(TypeId::of::<Box<dyn RenderResourceContext>>());
access.add_read(TypeId::of::<SharedBuffers>());
access
}
}
impl<'a> DrawContext<'a> {
pub fn get_uniform_buffer<T: RenderResource>(
&self,

View File

@ -32,7 +32,7 @@ use crate::prelude::*;
use base::{MainPass, Msaa};
use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_ecs::{IntoQuerySystem, IntoThreadLocalSystem};
use bevy_ecs::{IntoSystem, IntoThreadLocalSystem};
use camera::{
ActiveCameras, Camera, OrthographicProjection, PerspectiveProjection, VisibleEntities,
};

View File

@ -8,7 +8,7 @@ use crate::{
};
use bevy_core::AsBytes;
use bevy_ecs::{Commands, IntoQuerySystem, Local, Query, Res, ResMut, Resources, System, World};
use bevy_ecs::{Commands, IntoSystem, Local, Query, Res, ResMut, Resources, System, World};
use bevy_transform::prelude::*;
use std::borrow::Cow;

View File

@ -10,9 +10,7 @@ use crate::{
};
use bevy_asset::{Asset, Assets, Handle, HandleId};
use bevy_ecs::{
Commands, Entity, IntoQuerySystem, Local, Query, Res, ResMut, Resources, System, World,
};
use bevy_ecs::{Commands, Entity, IntoSystem, Local, Query, Res, ResMut, Resources, System, World};
use bevy_utils::HashMap;
use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources};
use std::{hash::Hash, marker::PhantomData, ops::DerefMut};

View File

@ -3,13 +3,18 @@ use bevy_ecs::{Resources, World};
pub fn render_graph_schedule_executor_system(world: &mut World, resources: &mut Resources) {
// run render graph systems
let (mut system_schedule, commands) = {
let (mut system_schedule, mut commands) = {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
(render_graph.take_schedule(), render_graph.take_commands())
};
commands.apply(world, resources);
if let Some(schedule) = system_schedule.as_mut() {
schedule.run_on_systems(|system| {
if !system.is_initialized() {
system.initialize(world, resources);
}
});
schedule.run(world, resources);
}
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();

View File

@ -26,7 +26,7 @@ pub mod prelude {
use bevy_app::prelude::*;
use bevy_asset::{AddAsset, Assets, Handle};
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
use bevy_math::Vec2;
use bevy_render::{
mesh::{shape, Mesh},

View File

@ -1,7 +1,5 @@
use crate::prelude::{Children, Parent, PreviousParent};
use bevy_ecs::{
Command, Commands, CommandsInternal, Component, DynamicBundle, Entity, Resources, World,
};
use bevy_ecs::{Command, Commands, Component, DynamicBundle, Entity, Resources, World};
use smallvec::SmallVec;
#[derive(Debug)]
@ -42,7 +40,7 @@ pub struct PushChildren {
}
pub struct ChildBuilder<'a> {
commands: &'a mut CommandsInternal,
commands: &'a mut Commands,
push_children: PushChildren,
}
@ -75,12 +73,12 @@ impl<'a> ChildBuilder<'a> {
self.commands.spawn(components);
self.push_children
.children
.push(self.commands.current_entity.unwrap());
.push(self.commands.current_entity().unwrap());
self
}
pub fn current_entity(&self) -> Option<Entity> {
self.commands.current_entity
self.commands.current_entity()
}
pub fn with_bundle(
@ -99,7 +97,7 @@ impl<'a> ChildBuilder<'a> {
pub fn for_current_entity(&mut self, func: impl FnOnce(Entity)) -> &mut Self {
let current_entity = self
.commands
.current_entity
.current_entity()
.expect("The 'current entity' is not set. You should spawn an entity first.");
func(current_entity);
self
@ -114,56 +112,47 @@ pub trait BuildChildren {
impl BuildChildren for Commands {
fn with_children(&mut self, parent: impl FnOnce(&mut ChildBuilder)) -> &mut Self {
{
let mut commands = self.commands.lock();
let current_entity = commands.current_entity.expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first.");
commands.current_entity = None;
let push_children = {
let mut builder = ChildBuilder {
commands: &mut commands,
push_children: PushChildren {
children: SmallVec::default(),
parent: current_entity,
},
};
parent(&mut builder);
builder.push_children
let current_entity = self.current_entity().expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first.");
self.clear_current_entity();
let push_children = {
let mut builder = ChildBuilder {
commands: self,
push_children: PushChildren {
children: SmallVec::default(),
parent: current_entity,
},
};
parent(&mut builder);
builder.push_children
};
commands.current_entity = Some(current_entity);
commands.add_command(push_children);
}
self.set_current_entity(current_entity);
self.add_command(push_children);
self
}
fn push_children(&mut self, parent: Entity, children: &[Entity]) -> &mut Self {
{
let mut commands = self.commands.lock();
commands.add_command(PushChildren {
children: SmallVec::from(children),
parent,
});
}
self.add_command(PushChildren {
children: SmallVec::from(children),
parent,
});
self
}
fn insert_children(&mut self, parent: Entity, index: usize, children: &[Entity]) -> &mut Self {
{
let mut commands = self.commands.lock();
commands.add_command(InsertChildren {
children: SmallVec::from(children),
index,
parent,
});
}
self.add_command(InsertChildren {
children: SmallVec::from(children),
index,
parent,
});
self
}
}
impl<'a> BuildChildren for ChildBuilder<'a> {
fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self {
let current_entity = self.commands.current_entity.expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first.");
self.commands.current_entity = None;
let current_entity = self.commands.current_entity().expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first.");
self.commands.clear_current_entity();
let push_children = {
let mut builder = ChildBuilder {
commands: self.commands,
@ -177,7 +166,7 @@ impl<'a> BuildChildren for ChildBuilder<'a> {
builder.push_children
};
self.commands.current_entity = Some(current_entity);
self.commands.set_current_entity(current_entity);
self.commands.add_command(push_children);
self
}

View File

@ -1,10 +1,10 @@
use crate::components::*;
use bevy_ecs::{Commands, Entity, IntoQuerySystem, Query, System, Without};
use bevy_ecs::{Commands, Entity, IntoSystem, Query, System, Without};
use bevy_utils::HashMap;
use smallvec::SmallVec;
pub fn parent_update_system(
mut commands: Commands,
commands: &mut Commands,
removed_parent_query: Query<Without<Parent, (Entity, &PreviousParent)>>,
// TODO: ideally this only runs when the Parent component has changed
mut changed_parent_query: Query<(Entity, &Parent, Option<&mut PreviousParent>)>,
@ -122,6 +122,7 @@ mod test {
});
let parent = parent.unwrap();
commands.apply(&mut world, &mut resources);
schedule.initialize(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);
assert_eq!(

View File

@ -88,10 +88,10 @@ mod test {
),
])
.collect::<Vec<Entity>>();
// we need to run the schedule three times because components need to be filled in
// we need to run the schedule two times because components need to be filled in
// to resolve this problem in code, just add the correct components, or use Commands
// which adds all of the components needed with the correct state (see next test)
schedule.run(&mut world, &mut resources);
schedule.initialize(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);
@ -142,6 +142,7 @@ mod test {
.for_current_entity(|entity| children.push(entity));
});
commands.apply(&mut world, &mut resources);
schedule.initialize(&mut world, &mut resources);
schedule.run(&mut world, &mut resources);
assert_eq!(

View File

@ -3,7 +3,7 @@ use crate::{
transform_propagate_system::transform_propagate_system, transform_systems,
};
use bevy_ecs::{IntoQuerySystem, System};
use bevy_ecs::{IntoSystem, System};
use hierarchy_maintenance_system::hierarchy_maintenance_systems;
use transform_systems::transform_systems;

View File

@ -25,7 +25,7 @@ pub mod prelude {
}
use bevy_app::prelude::*;
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
use bevy_render::render_graph::RenderGraph;
use update::ui_z_system;

View File

@ -1,7 +1,7 @@
use crate::renderer::WgpuRenderResourceContext;
use bevy_app::prelude::*;
use bevy_diagnostic::{Diagnostic, DiagnosticId, Diagnostics};
use bevy_ecs::{IntoQuerySystem, Res, ResMut};
use bevy_ecs::{IntoSystem, Res, ResMut};
use bevy_render::renderer::RenderResourceContext;
#[derive(Default)]

View File

@ -11,7 +11,7 @@ pub use wgpu_renderer::*;
pub use wgpu_resources::*;
use bevy_app::prelude::*;
use bevy_ecs::{IntoQuerySystem, IntoThreadLocalSystem, Resources, World};
use bevy_ecs::{IntoSystem, IntoThreadLocalSystem, Resources, World};
use bevy_render::renderer::{free_shared_buffers_system, RenderResourceContext, SharedBuffers};
use renderer::WgpuRenderResourceContext;

View File

@ -13,7 +13,7 @@ pub mod prelude {
}
use bevy_app::prelude::*;
use bevy_ecs::IntoQuerySystem;
use bevy_ecs::IntoSystem;
pub struct WindowPlugin {
pub add_primary_window: bool,

View File

@ -46,7 +46,7 @@ const COL_SELECTED: Color = Color::rgb_linear(5.0, 5.0, 5.0);
const SHOWCASE_TIMER_SECS: f32 = 3.0;
fn setup(
mut cmd: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
@ -54,7 +54,8 @@ fn setup(
let texture_handle = asset_server.load("branding/icon.png");
cmd.spawn(Camera2dComponents::default())
commands
.spawn(Camera2dComponents::default())
.spawn(UiCameraComponents::default());
let mut sel = ContributorSelection {
@ -76,7 +77,8 @@ fn setup(
let mut transform = Transform::from_translation(Vec3::new(pos.0, pos.1, 0.0));
*transform.scale.x_mut() *= if flipped { -1.0 } else { 1.0 };
cmd.spawn((Contributor { color: col },))
commands
.spawn((Contributor { color: col },))
.with(Velocity {
translation: velocity,
rotation: -dir * 5.0,
@ -94,16 +96,17 @@ fn setup(
})
.with(transform);
let e = cmd.current_entity().unwrap();
let e = commands.current_entity().unwrap();
sel.order.push((name, e));
}
sel.order.shuffle(&mut rnd);
cmd.spawn((SelectTimer, Timer::from_seconds(SHOWCASE_TIMER_SECS, true)));
commands.spawn((SelectTimer, Timer::from_seconds(SHOWCASE_TIMER_SECS, true)));
cmd.spawn((ContributorDisplay,))
commands
.spawn((ContributorDisplay,))
.with_bundle(TextComponents {
style: Style {
align_self: AlignSelf::FlexEnd,
@ -120,7 +123,7 @@ fn setup(
..Default::default()
});
cmd.insert_resource(sel);
commands.insert_resource(sel);
}
/// Finds the next contributor to display and selects the entity

View File

@ -8,7 +8,7 @@ fn main() {
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {

View File

@ -21,7 +21,7 @@ fn animate_sprite_system(
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
) {

View File

@ -21,7 +21,7 @@ fn setup(mut rpg_sprite_handles: ResMut<RpgSpriteHandles>, asset_server: Res<Ass
}
fn load_atlas(
mut commands: Commands,
commands: &mut Commands,
mut rpg_sprite_handles: ResMut<RpgSpriteHandles>,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,

View File

@ -10,7 +10,7 @@ fn main() {
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {

View File

@ -8,7 +8,7 @@ fn main() {
.run();
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
commands
.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf"))
.spawn(LightComponents {

View File

@ -13,7 +13,7 @@ fn main() {
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {

View File

@ -23,7 +23,7 @@ fn rotator_system(time: Res<Time>, mut query: Query<(&Rotator, &mut Transform)>)
/// set up a simple scene with a "parent" cube and a "child" cube
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {

View File

@ -32,7 +32,7 @@ fn move_cubes(
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {

View File

@ -10,7 +10,7 @@ fn main() {
/// sets up a scene with textured entities
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,

View File

@ -42,7 +42,7 @@ fn camera_order_color_system(
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {

View File

@ -10,7 +10,7 @@ fn main() {
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
meshes: Res<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,

View File

@ -10,7 +10,7 @@ fn main() {
.run();
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
// Load our mesh:
let scene_handle = asset_server.load("models/monkey/Monkey.gltf");

View File

@ -141,7 +141,7 @@ fn game_over_system(
// the initial "state" of our game. The only thing that distinguishes a "startup" system from a "normal" system is how it is registered:
// Startup: app.add_startup_system(startup_system)
// Normal: app.add_system(normal_system)
fn startup_system(mut commands: Commands, mut game_state: ResMut<GameState>) {
fn startup_system(commands: &mut Commands, mut game_state: ResMut<GameState>) {
// Create our game rules resource
commands.insert_resource(GameRules {
max_rounds: 10,
@ -175,7 +175,7 @@ fn startup_system(mut commands: Commands, mut game_state: ResMut<GameState>) {
// Command buffers give us the ability to queue up changes to our World without directly accessing it
// NOTE: Command buffers must always come before resources and queries in system functions
fn new_player_system(
mut commands: Commands,
commands: &mut Commands,
game_rules: Res<GameRules>,
mut game_state: ResMut<GameState>,
) {

View File

@ -9,7 +9,7 @@ fn main() {
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
@ -89,7 +89,7 @@ fn setup(
// A simple system to rotate the root entity, and rotate all its children separately
fn rotate(
mut commands: Commands,
commands: &mut Commands,
time: Res<Time>,
mut parents_query: Query<(Entity, &mut Children, &Sprite)>,
mut transform_query: Query<With<Sprite, &mut Transform>>,

View File

@ -4,7 +4,7 @@ use rand::random;
struct Velocity(Vec2);
fn spawn_system(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {

View File

@ -37,7 +37,7 @@ enum Collider {
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>,
) {
@ -195,7 +195,7 @@ fn scoreboard_system(scoreboard: Res<Scoreboard>, mut query: Query<&mut Text>) {
}
fn ball_collision_system(
mut commands: Commands,
commands: &mut Commands,
mut scoreboard: ResMut<Scoreboard>,
mut ball_query: Query<(&mut Ball, &Transform, &Sprite)>,
collider_query: Query<(Entity, &Collider, &Transform, &Sprite)>,

View File

@ -1,6 +1,6 @@
use bevy::{
prelude::{
shape, App, Assets, Camera3dComponents, Color, Commands, DefaultPlugins, IntoQuerySystem,
shape, App, Assets, Camera3dComponents, Color, Commands, DefaultPlugins, IntoSystem,
LightComponents, Mesh, Msaa, PbrComponents, ResMut, StandardMaterial, Transform, Vec3,
WindowDescriptor,
},
@ -23,7 +23,7 @@ extern "C" fn main_rs() {
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {

View File

@ -101,7 +101,7 @@ fn save_scene_system(_world: &mut World, resources: &mut Resources) {
}
// This is only necessary for the info message in the UI. See examples/ui/text.rs for a standalone text example.
fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
fn infotext_system(commands: &mut Commands, asset_server: Res<AssetServer>) {
commands
.spawn(UiCameraComponents::default())
.spawn(TextComponents {

View File

@ -52,7 +52,7 @@ void main() {
"#;
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
mut shaders: ResMut<Assets<Shader>>,
mut meshes: ResMut<Assets<Mesh>>,

View File

@ -51,7 +51,7 @@ void main() {
"#;
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
mut shaders: ResMut<Assets<Shader>>,
mut meshes: ResMut<Assets<Mesh>>,

View File

@ -63,7 +63,7 @@ void main() {
"#;
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
mut shaders: ResMut<Assets<Shader>>,
mut meshes: ResMut<Assets<Mesh>>,

View File

@ -57,7 +57,7 @@ fn button_system(
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
button_materials: Res<ButtonMaterials>,
) {

View File

@ -28,7 +28,7 @@ impl Default for State {
}
fn atlas_render_system(
mut commands: Commands,
commands: &mut Commands,
mut state: ResMut<State>,
mut materials: ResMut<Assets<ColorMaterial>>,
font_atlas_sets: Res<Assets<FontAtlasSet>>,
@ -72,7 +72,7 @@ fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Quer
}
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResMut<State>) {
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>, mut state: ResMut<State>) {
let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf");
state.handle = font_handle.clone();
commands

View File

@ -26,7 +26,7 @@ fn text_update_system(diagnostics: Res<Diagnostics>, mut query: Query<(&mut Text
}
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn setup(commands: &mut Commands, asset_server: Res<AssetServer>) {
commands
// 2d camera
.spawn(UiCameraComponents::default())

View File

@ -9,7 +9,7 @@ fn main() {
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {

View File

@ -32,7 +32,7 @@ struct State {
printed: bool,
}
fn load_asset(mut commands: Commands, asset_server: Res<AssetServer>) {
fn load_asset(commands: &mut Commands, asset_server: Res<AssetServer>) {
commands.insert_resource(State {
handle: asset_server.load("assets_wasm.rs"),
printed: false,

View File

@ -22,7 +22,7 @@ fn main() {
}
fn setup(
mut commands: Commands,
commands: &mut Commands,
mut create_window_events: ResMut<Events<CreateWindow>>,
mut active_cameras: ResMut<ActiveCameras>,
mut render_graph: ResMut<RenderGraph>,