Flexible ECS System Params (#798)
system params can be in any order, faster compiles, remove foreach
This commit is contained in:
parent
f54788527b
commit
ebcdc9fb8c
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)]
|
||||
|
@ -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(),
|
||||
))
|
||||
|
@ -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
|
||||
|
@ -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(),)*
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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(),);
|
||||
// }
|
||||
// }
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
79
crates/bevy_ecs/src/system/into_thread_local.rs
Normal file
79
crates/bevy_ecs/src/system/into_thread_local.rs
Normal 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(),
|
||||
})
|
||||
}
|
||||
}
|
@ -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::*;
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
|
255
crates/bevy_ecs/src/system/system_param.rs
Normal file
255
crates/bevy_ecs/src/system/system_param.rs
Normal 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);
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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::{
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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();
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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!(
|
||||
|
@ -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!(
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -8,7 +8,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
commands: &mut Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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 {
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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>,
|
||||
) {
|
||||
|
@ -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>>,
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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)>,
|
||||
|
@ -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>>,
|
||||
) {
|
||||
|
@ -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 {
|
||||
|
@ -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>>,
|
||||
|
@ -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>>,
|
||||
|
@ -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>>,
|
||||
|
@ -57,7 +57,7 @@ fn button_system(
|
||||
}
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
commands: &mut Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
button_materials: Res<ButtonMaterials>,
|
||||
) {
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -9,7 +9,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
commands: &mut Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
|
@ -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,
|
||||
|
@ -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>,
|
||||
|
Loading…
Reference in New Issue
Block a user