legion: remove foreach system functions
this is a bit sad, but upstream legion's new lifetimes appear to be incompatible with our foreach approach
This commit is contained in:
		
							parent
							
								
									981687ae41
								
							
						
					
					
						commit
						1f12964026
					
				@ -1,6 +1,6 @@
 | 
			
		||||
use crate::time::Time;
 | 
			
		||||
use bevy_property::Properties;
 | 
			
		||||
use legion::prelude::{ComMut, Res};
 | 
			
		||||
use legion::prelude::{Query, Res, SubWorld, Write};
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Default, Properties)]
 | 
			
		||||
@ -37,6 +37,8 @@ impl Timer {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn timer_system(time: Res<Time>, mut timer: ComMut<Timer>) {
 | 
			
		||||
pub fn timer_system(time: Res<Time>, world: &mut SubWorld, query: &mut Query<Write<Timer>>) {
 | 
			
		||||
    for mut timer in query.iter_mut(world) {
 | 
			
		||||
        timer.tick(time.delta_seconds);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,13 +17,11 @@ pub mod world;
 | 
			
		||||
#[cfg(feature = "serialize")]
 | 
			
		||||
pub mod serialize;
 | 
			
		||||
 | 
			
		||||
mod system_fn_types;
 | 
			
		||||
mod tuple;
 | 
			
		||||
mod zip;
 | 
			
		||||
 | 
			
		||||
pub mod prelude {
 | 
			
		||||
    pub use crate::{
 | 
			
		||||
        borrow::{Ref as Com, RefMut as ComMut},
 | 
			
		||||
        command::CommandBuffer,
 | 
			
		||||
        entity::Entity,
 | 
			
		||||
        event::Event,
 | 
			
		||||
 | 
			
		||||
@ -1,113 +0,0 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    borrow::{Ref, RefIter, RefIterMut, RefMut},
 | 
			
		||||
    filter::{ComponentFilter, EntityFilterTuple, Passthrough},
 | 
			
		||||
    index::{ChunkIndex, SetIndex},
 | 
			
		||||
    query::{DefaultFilter, View, ViewElement},
 | 
			
		||||
    storage::{ArchetypeData, Component, ComponentStorage, ComponentTypeId},
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    any::TypeId,
 | 
			
		||||
    slice::{Iter, IterMut},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Component> DefaultFilter for RefMut<'static, T> {
 | 
			
		||||
    type Filter = EntityFilterTuple<ComponentFilter<T>, Passthrough, Passthrough>;
 | 
			
		||||
 | 
			
		||||
    fn filter() -> Self::Filter { super::filter::filter_fns::component() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Component> View<'a> for RefMut<'static, T> {
 | 
			
		||||
    type Iter = RefIterMut<'a, T, IterMut<'a, T>>;
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn fetch(
 | 
			
		||||
        _: &'a ArchetypeData,
 | 
			
		||||
        chunk: &'a ComponentStorage,
 | 
			
		||||
        _: ChunkIndex,
 | 
			
		||||
        _: SetIndex,
 | 
			
		||||
    ) -> Self::Iter {
 | 
			
		||||
        let (slice_borrow, slice) = unsafe {
 | 
			
		||||
            chunk
 | 
			
		||||
                .components(ComponentTypeId::of::<T>())
 | 
			
		||||
                .unwrap_or_else(|| {
 | 
			
		||||
                    panic!(
 | 
			
		||||
                        "Component of type {:?} not found in chunk when fetching Write view",
 | 
			
		||||
                        std::any::type_name::<T>()
 | 
			
		||||
                    )
 | 
			
		||||
                })
 | 
			
		||||
                .data_slice_mut::<T>()
 | 
			
		||||
                .deconstruct()
 | 
			
		||||
        };
 | 
			
		||||
        RefIterMut::new(slice_borrow, slice.iter_mut())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn validate() -> bool { true }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn reads<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn writes<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn read_types() -> Vec<ComponentTypeId> { vec![ComponentTypeId::of::<T>()] }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn write_types() -> Vec<ComponentTypeId> { vec![ComponentTypeId::of::<T>()] }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Component> ViewElement for RefMut<'static, T> {
 | 
			
		||||
    type Component = T;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Component> DefaultFilter for Ref<'static, T> {
 | 
			
		||||
    type Filter = EntityFilterTuple<ComponentFilter<T>, Passthrough, Passthrough>;
 | 
			
		||||
 | 
			
		||||
    fn filter() -> Self::Filter { super::filter::filter_fns::component() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Component> View<'a> for Ref<'static, T> {
 | 
			
		||||
    type Iter = RefIter<'a, T, Iter<'a, T>>;
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn fetch(
 | 
			
		||||
        _: &'a ArchetypeData,
 | 
			
		||||
        chunk: &'a ComponentStorage,
 | 
			
		||||
        _: ChunkIndex,
 | 
			
		||||
        _: SetIndex,
 | 
			
		||||
    ) -> Self::Iter {
 | 
			
		||||
        let (slice_borrow, slice) = unsafe {
 | 
			
		||||
            chunk
 | 
			
		||||
                .components(ComponentTypeId::of::<T>())
 | 
			
		||||
                .unwrap_or_else(|| {
 | 
			
		||||
                    panic!(
 | 
			
		||||
                        "Component of type {:?} not found in chunk when fetching Write view",
 | 
			
		||||
                        std::any::type_name::<T>()
 | 
			
		||||
                    )
 | 
			
		||||
                })
 | 
			
		||||
                .data_slice::<T>()
 | 
			
		||||
                .deconstruct()
 | 
			
		||||
        };
 | 
			
		||||
        RefIter::new(slice_borrow, slice.iter())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn validate() -> bool { true }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn reads<D: Component>() -> bool { TypeId::of::<T>() == TypeId::of::<D>() }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn writes<D: Component>() -> bool { false }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn read_types() -> Vec<ComponentTypeId> { vec![ComponentTypeId::of::<T>()] }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn write_types() -> Vec<ComponentTypeId> { Vec::new() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Component> ViewElement for Ref<'static, T> {
 | 
			
		||||
    type Component = T;
 | 
			
		||||
}
 | 
			
		||||
@ -21,164 +21,6 @@ fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec<Ident> {
 | 
			
		||||
        .collect::<Vec<Ident>>()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[proc_macro]
 | 
			
		||||
pub fn impl_fn_systems(_input: TokenStream) -> TokenStream {
 | 
			
		||||
    let max_resources = 8;
 | 
			
		||||
    let max_views = 8;
 | 
			
		||||
    let resources = get_idents(|i| format!("R{}", i), max_resources);
 | 
			
		||||
    let resource_vars = get_idents(|i| format!("r{}", i), max_resources);
 | 
			
		||||
    let views = get_idents(|i| format!("V{}", i), max_views);
 | 
			
		||||
    let view_vars = get_idents(|i| format!("v{}", i), max_views);
 | 
			
		||||
 | 
			
		||||
    let mut tokens = TokenStream::new();
 | 
			
		||||
 | 
			
		||||
    let command_buffer = vec![Ident::new("CommandBuffer", Span::call_site())];
 | 
			
		||||
    let command_buffer_var = vec![Ident::new("_command_buffer", Span::call_site())];
 | 
			
		||||
    for resource_count in 0..=max_resources {
 | 
			
		||||
        let resource = &resources[0..resource_count];
 | 
			
		||||
        let resource_var = &resource_vars[0..resource_count];
 | 
			
		||||
 | 
			
		||||
        let resource_tuple = tuple(resource);
 | 
			
		||||
        let resource_var_tuple = tuple(resource_var);
 | 
			
		||||
 | 
			
		||||
        let resource_access = if resource_count == 0 {
 | 
			
		||||
            quote! { Access::default() }
 | 
			
		||||
        } else {
 | 
			
		||||
            quote! {{
 | 
			
		||||
                let mut resource_access: Access<ResourceTypeId> = Access::default();
 | 
			
		||||
                resource_access
 | 
			
		||||
                    .reads
 | 
			
		||||
                    .extend(<#resource_tuple as ResourceSet>::read_types().iter());
 | 
			
		||||
                resource_access
 | 
			
		||||
                    .writes
 | 
			
		||||
                    .extend(<#resource_tuple as ResourceSet>::write_types().iter());
 | 
			
		||||
                resource_access
 | 
			
		||||
            }}
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        for view_count in 0..=max_views {
 | 
			
		||||
            let view = &views[0..view_count];
 | 
			
		||||
            let view_var = &view_vars[0..view_count];
 | 
			
		||||
 | 
			
		||||
            let view_tuple = tuple(view);
 | 
			
		||||
 | 
			
		||||
            let component_access = if view_count == 0 {
 | 
			
		||||
                quote! { Access::default() }
 | 
			
		||||
            } else {
 | 
			
		||||
                quote! {{
 | 
			
		||||
                    let mut component_access: Access<ComponentTypeId> = Access::default();
 | 
			
		||||
                    component_access
 | 
			
		||||
                        .reads
 | 
			
		||||
                        .extend(<#view_tuple as View>::read_types().iter());
 | 
			
		||||
                    component_access
 | 
			
		||||
                        .writes
 | 
			
		||||
                        .extend(<#view_tuple as View>::write_types().iter());
 | 
			
		||||
                    component_access
 | 
			
		||||
                }}
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let system_query = if view_count == 0 {
 | 
			
		||||
                quote! { () }
 | 
			
		||||
            } else if view_count == 1 {
 | 
			
		||||
                quote! { SystemQuery<
 | 
			
		||||
                    #(#view),*,
 | 
			
		||||
                    #(<#view as DefaultFilter>::Filter),*,
 | 
			
		||||
                > }
 | 
			
		||||
            } else {
 | 
			
		||||
                quote! { SystemQuery<
 | 
			
		||||
                    (#(#view),*),
 | 
			
		||||
                    EntityFilterTuple<
 | 
			
		||||
                        And<(
 | 
			
		||||
                            #(<<#view as DefaultFilter>::Filter as EntityFilter>::ArchetypeFilter),*
 | 
			
		||||
                        )>,
 | 
			
		||||
                        And<(
 | 
			
		||||
                            #(<<#view as DefaultFilter>::Filter as EntityFilter>::ChunksetFilter),*
 | 
			
		||||
                        )>,
 | 
			
		||||
                        And<(
 | 
			
		||||
                            #(<<#view as DefaultFilter>::Filter as EntityFilter>::ChunkFilter),*
 | 
			
		||||
                        )>,
 | 
			
		||||
                    >
 | 
			
		||||
                >   }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let query = if view_count == 0 {
 | 
			
		||||
                quote! {()}
 | 
			
		||||
            } else {
 | 
			
		||||
                quote! {<#view_tuple>::query()}
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            for command_buffer_index in 0..2 {
 | 
			
		||||
                let command_buffer = &command_buffer[0..command_buffer_index];
 | 
			
		||||
                let command_buffer_var = &command_buffer_var[0..command_buffer_index];
 | 
			
		||||
 | 
			
		||||
                let run_fn = if view_count == 0 {
 | 
			
		||||
                    quote! { self(#(#resource_var,)* #(#command_buffer_var,)*) }
 | 
			
		||||
                } else {
 | 
			
		||||
                    quote! {
 | 
			
		||||
                        for (#(#view_var),*) in _query.iter_mut(_world) {
 | 
			
		||||
                            self(#(#resource_var.clone(),)* #(#command_buffer_var,)* #(#view_var),*);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                tokens.extend(TokenStream::from(quote! {
 | 
			
		||||
                    impl<'a,
 | 
			
		||||
                        Func,
 | 
			
		||||
                        #(#resource: ResourceSet<PreparedResources = #resource> + 'static + Clone,)*
 | 
			
		||||
                        #(#view: for<'b> View<'b> + DefaultFilter + ViewElement,)*
 | 
			
		||||
                    > IntoSystem<(#(#command_buffer)*), (#(#resource,)*), (#(#view,)*), ()> for Func
 | 
			
		||||
                    where
 | 
			
		||||
                        Func: FnMut(#(#resource,)* #(&mut #command_buffer,)* #(#view),*) + Send + Sync + 'static,
 | 
			
		||||
                        #(<#view as View<'a>>::Iter: Iterator<Item = #view>,
 | 
			
		||||
                        <#view as DefaultFilter>::Filter: Sync),*
 | 
			
		||||
                    {
 | 
			
		||||
                        fn system_id(mut self, id: SystemId) -> Box<dyn Schedulable> {
 | 
			
		||||
                            let resource_access: Access<ResourceTypeId> = #resource_access;
 | 
			
		||||
                            let component_access: Access<ComponentTypeId> = #component_access;
 | 
			
		||||
 | 
			
		||||
                            let run_fn = FuncSystemFnWrapper(
 | 
			
		||||
                                move |_command_buffer,
 | 
			
		||||
                                    _world,
 | 
			
		||||
                                    _resources: #resource_tuple,
 | 
			
		||||
                                    _query: &mut #system_query
 | 
			
		||||
                                | {
 | 
			
		||||
                                    let #resource_var_tuple = _resources;
 | 
			
		||||
                                    #run_fn
 | 
			
		||||
                                },
 | 
			
		||||
                                PhantomData,
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            Box::new(FuncSystem {
 | 
			
		||||
                                name: id,
 | 
			
		||||
                                queries: AtomicRefCell::new(#query),
 | 
			
		||||
                                access: SystemAccess {
 | 
			
		||||
                                    resources: resource_access,
 | 
			
		||||
                                    components: component_access,
 | 
			
		||||
                                    tags: Access::default(),
 | 
			
		||||
                                },
 | 
			
		||||
                                archetypes: ArchetypeAccess::Some(BitSet::default()),
 | 
			
		||||
                                _resources: PhantomData::<#resource_tuple>,
 | 
			
		||||
                                command_buffer: FxHashMap::default(),
 | 
			
		||||
                                run_fn: AtomicRefCell::new(run_fn),
 | 
			
		||||
                            })
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        fn system_named(self, name: &'static str) -> Box<dyn Schedulable> {
 | 
			
		||||
                            self.system_id(name.into())
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        fn system(self) -> Box<dyn Schedulable> {
 | 
			
		||||
                            self.system_id(std::any::type_name::<Self>().to_string().into())
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tokens
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[proc_macro]
 | 
			
		||||
pub fn impl_fn_query_systems(_input: TokenStream) -> TokenStream {
 | 
			
		||||
    let max_resources = 8;
 | 
			
		||||
@ -193,6 +35,8 @@ pub fn impl_fn_query_systems(_input: TokenStream) -> TokenStream {
 | 
			
		||||
 | 
			
		||||
    let command_buffer = vec![Ident::new("CommandBuffer", Span::call_site())];
 | 
			
		||||
    let command_buffer_var = vec![Ident::new("_command_buffer", Span::call_site())];
 | 
			
		||||
    let subworld = vec![Ident::new("SubWorld", Span::call_site())];
 | 
			
		||||
    let subworld_var = vec![Ident::new("_world", Span::call_site())];
 | 
			
		||||
    for resource_count in 0..=max_resources {
 | 
			
		||||
        let resource = &resources[0..resource_count];
 | 
			
		||||
        let resource_var = &resource_vars[0..resource_count];
 | 
			
		||||
@ -215,12 +59,14 @@ pub fn impl_fn_query_systems(_input: TokenStream) -> TokenStream {
 | 
			
		||||
            }}
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        for query_count in 1..=max_queries {
 | 
			
		||||
        for query_count in 0..=max_queries {
 | 
			
		||||
            let view = &views[0..query_count];
 | 
			
		||||
            let query_var = &query_vars[0..query_count];
 | 
			
		||||
 | 
			
		||||
            let view_tuple = tuple(view);
 | 
			
		||||
            let query_var_tuple = tuple(query_var);
 | 
			
		||||
            let subworld = &subworld[0..query_count.min(1)];
 | 
			
		||||
            let subworld_var = &subworld_var[0..query_count.min(1)];
 | 
			
		||||
 | 
			
		||||
            let component_access = if query_count == 0 {
 | 
			
		||||
                quote! { Access::default() }
 | 
			
		||||
@ -241,19 +87,13 @@ pub fn impl_fn_query_systems(_input: TokenStream) -> TokenStream {
 | 
			
		||||
                let command_buffer = &command_buffer[0..command_buffer_index];
 | 
			
		||||
                let command_buffer_var = &command_buffer_var[0..command_buffer_index];
 | 
			
		||||
 | 
			
		||||
                let view_tuple_avoid_type_collision = if query_count == 1 {
 | 
			
		||||
                    quote! {(#(#view)*,)}
 | 
			
		||||
                } else {
 | 
			
		||||
                    quote! {(#(#view,)*)}
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                tokens.extend(TokenStream::from(quote! {
 | 
			
		||||
                    impl<Func,
 | 
			
		||||
                        #(#resource: ResourceSet<PreparedResources = #resource> + 'static + Clone,)*
 | 
			
		||||
                        #(#view: for<'b> View<'b> + DefaultFilter + ViewElement),*
 | 
			
		||||
                    > IntoSystem<(#(#command_buffer)*), (#(#resource,)*), (), #view_tuple_avoid_type_collision> for Func
 | 
			
		||||
                    > IntoSystem<(#(#command_buffer)*), (#(#resource,)*), (#(#view,)*)> for Func
 | 
			
		||||
                    where
 | 
			
		||||
                        Func: FnMut(#(#resource,)*#(&mut #command_buffer,)* &mut SubWorld, #(&mut SystemQuery<#view, <#view as DefaultFilter>::Filter>),*) + Send + Sync + 'static,
 | 
			
		||||
                        Func: FnMut(#(#resource,)*#(&mut #command_buffer,)* #(&mut #subworld,)* #(&mut SystemQuery<#view, <#view as DefaultFilter>::Filter>),*) + Send + Sync + 'static,
 | 
			
		||||
                        #(<#view as DefaultFilter>::Filter: Sync),*
 | 
			
		||||
                    {
 | 
			
		||||
                        fn system_id(mut self, id: SystemId) -> Box<dyn Schedulable> {
 | 
			
		||||
@ -268,7 +108,7 @@ pub fn impl_fn_query_systems(_input: TokenStream) -> TokenStream {
 | 
			
		||||
                                | {
 | 
			
		||||
                                    let #resource_var_tuple = _resources;
 | 
			
		||||
                                    let #query_var_tuple = _queries;
 | 
			
		||||
                                    self(#(#resource_var,)*#(#command_buffer_var,)*_world,#(#query_var),*)
 | 
			
		||||
                                    self(#(#resource_var,)*#(#command_buffer_var,)*#(#subworld_var,)*#(#query_var),*)
 | 
			
		||||
                                },
 | 
			
		||||
                                PhantomData,
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
@ -9,20 +9,18 @@ use fxhash::FxHashMap;
 | 
			
		||||
use legion_core::{
 | 
			
		||||
    borrow::AtomicRefCell,
 | 
			
		||||
    command::CommandBuffer,
 | 
			
		||||
    filter::{And, EntityFilter, EntityFilterTuple},
 | 
			
		||||
    query::{DefaultFilter, IntoQuery, View, ViewElement},
 | 
			
		||||
    storage::ComponentTypeId,
 | 
			
		||||
};
 | 
			
		||||
use legion_fn_system_macro::{impl_fn_query_systems, impl_fn_systems};
 | 
			
		||||
use legion_fn_system_macro::impl_fn_query_systems;
 | 
			
		||||
use std::marker::PhantomData;
 | 
			
		||||
 | 
			
		||||
pub trait IntoSystem<CommandBuffer, Resources, Views, Queries> {
 | 
			
		||||
pub trait IntoSystem<CommandBuffer, Resources, Queries> {
 | 
			
		||||
    fn system_id(self, id: SystemId) -> Box<dyn Schedulable>;
 | 
			
		||||
    fn system_named(self, name: &'static str) -> Box<dyn Schedulable>;
 | 
			
		||||
    fn system(self) -> Box<dyn Schedulable>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_fn_systems!();
 | 
			
		||||
impl_fn_query_systems!();
 | 
			
		||||
 | 
			
		||||
#[allow(type_alias_bounds)]
 | 
			
		||||
@ -33,14 +31,8 @@ where
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::{
 | 
			
		||||
        resource::Resources,
 | 
			
		||||
        system_fn_types::{Res, ResMut},
 | 
			
		||||
        IntoSystem, Query, SubWorld,
 | 
			
		||||
    };
 | 
			
		||||
    use crate::{resource::Resources, system_fn_types::Res, IntoSystem, Query, SubWorld};
 | 
			
		||||
    use legion_core::{
 | 
			
		||||
        borrow::{Ref, RefMut},
 | 
			
		||||
        command::CommandBuffer,
 | 
			
		||||
        query::{Read, Write},
 | 
			
		||||
        world::World,
 | 
			
		||||
    };
 | 
			
		||||
@ -68,10 +60,12 @@ mod tests {
 | 
			
		||||
                println!("{:?}", x);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        let mut system = query_system.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn query_system2(
 | 
			
		||||
            world: &mut SubWorld,
 | 
			
		||||
            a: Res<A>,
 | 
			
		||||
            world: &mut SubWorld,
 | 
			
		||||
            query: &mut Query<(Read<X>, Write<Y>)>,
 | 
			
		||||
            query2: &mut Query<Read<X>>,
 | 
			
		||||
        ) {
 | 
			
		||||
@ -86,98 +80,14 @@ mod tests {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut system = query_system.system();
 | 
			
		||||
        let mut system2 = query_system2.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
        system2.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn query_system3(a: Res<A>) {
 | 
			
		||||
            println!("{:?}", *a);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_into_system() {
 | 
			
		||||
        let mut world = World::new();
 | 
			
		||||
        let mut resources = Resources::default();
 | 
			
		||||
        resources.insert(A(0));
 | 
			
		||||
        world.insert((), vec![(X(1), Y(1)), (X(2), Y(2))]);
 | 
			
		||||
 | 
			
		||||
        fn single_read_system(x: Ref<X>) {
 | 
			
		||||
            println!("{}", x.0);
 | 
			
		||||
        }
 | 
			
		||||
        let mut system = single_read_system.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn read_write_system(x: Ref<X>, y: Ref<Y>, mut z: RefMut<A>) {
 | 
			
		||||
            z.0 += 1;
 | 
			
		||||
            println!("{} {} {}", x.0, y.0, z.0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ({
 | 
			
		||||
            |x: Res<A>, y: Ref<Y>, mut z: RefMut<A>| {
 | 
			
		||||
                z.0 += 1;
 | 
			
		||||
                println!("{} {} {}", x.0, y.0, z.0);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        .system();
 | 
			
		||||
 | 
			
		||||
        let mut system = read_write_system.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn resource_system(a: Res<A>, x: Ref<X>, y: Ref<Y>) {
 | 
			
		||||
            println!("{} {} {}", a.0, x.0, y.0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut system = resource_system.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn empty_system_mut() {
 | 
			
		||||
            println!("hello world");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut system = empty_system_mut.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn resource_system_mut(mut a: ResMut<A>, x: Ref<X>, y: Ref<Y>) {
 | 
			
		||||
            a.0 += 1;
 | 
			
		||||
            println!("{} {} {}", a.0, x.0, y.0);
 | 
			
		||||
        }
 | 
			
		||||
        let mut system = resource_system_mut.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
 | 
			
		||||
        fn command_buffer_system(command_buffer: &mut CommandBuffer, mut a: ResMut<A>) {
 | 
			
		||||
            a.0 += 1;
 | 
			
		||||
            command_buffer.insert((), vec![(X(1), Y(1)), (X(2), Y(2))]);
 | 
			
		||||
            println!("{}", a.0);
 | 
			
		||||
        }
 | 
			
		||||
        let mut system = command_buffer_system.system();
 | 
			
		||||
        system.run(&mut world, &mut resources);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_resource_system_fn() {
 | 
			
		||||
        fn my_system(mut a: ResMut<A>, x: Ref<X>, mut y: RefMut<Y>) {
 | 
			
		||||
            if a.0 == 0 {
 | 
			
		||||
                assert_eq!(*a, A(0));
 | 
			
		||||
                assert_eq!(*x, X(2));
 | 
			
		||||
                assert_eq!(*y, Y(3));
 | 
			
		||||
            } else if a.0 == 1 {
 | 
			
		||||
                assert_eq!(*a, A(1));
 | 
			
		||||
                assert_eq!(*x, X(4));
 | 
			
		||||
                assert_eq!(*y, Y(5));
 | 
			
		||||
                y.0 += 1;
 | 
			
		||||
                assert_eq!(*y, Y(6));
 | 
			
		||||
            } else {
 | 
			
		||||
                panic!("unexpected value");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            a.0 += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut world = World::new();
 | 
			
		||||
        let mut resources = Resources::default();
 | 
			
		||||
 | 
			
		||||
        resources.insert(A(0));
 | 
			
		||||
        resources.insert(B(1));
 | 
			
		||||
        world.insert((), vec![(X(2), Y(3)), (X(4), Y(5))]);
 | 
			
		||||
        let mut my_system = my_system.system();
 | 
			
		||||
        my_system.run(&mut world, &mut resources);
 | 
			
		||||
        let mut system3 = query_system3.system();
 | 
			
		||||
        system3.run(&mut world, &mut resources);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -13,8 +13,8 @@ use crate::{
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use bevy_property::Properties;
 | 
			
		||||
use legion::{
 | 
			
		||||
    prelude::{ComMut, Res, ResourceSet},
 | 
			
		||||
    systems::{resource::ResourceTypeId, ResMut},
 | 
			
		||||
    prelude::{Res, ResourceSet, Write},
 | 
			
		||||
    systems::{resource::ResourceTypeId, ResMut, SubWorld, Query},
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    ops::{Deref, DerefMut, Range},
 | 
			
		||||
@ -340,6 +340,8 @@ pub trait Drawable {
 | 
			
		||||
    fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn clear_draw_system(mut draw: ComMut<Draw>) {
 | 
			
		||||
pub fn clear_draw_system(world: &mut SubWorld, query: &mut Query<Write<Draw>>) {
 | 
			
		||||
    for mut draw in query.iter_mut(world) {
 | 
			
		||||
        draw.clear_render_commands();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,10 @@ use crate::{
 | 
			
		||||
};
 | 
			
		||||
use bevy_asset::Handle;
 | 
			
		||||
use bevy_property::Properties;
 | 
			
		||||
use legion::{prelude::ComMut, systems::ResMut};
 | 
			
		||||
use legion::{
 | 
			
		||||
    prelude::Write,
 | 
			
		||||
    systems::{Query, ResMut, SubWorld},
 | 
			
		||||
};
 | 
			
		||||
#[derive(Properties, Default, Clone)]
 | 
			
		||||
pub struct RenderPipeline {
 | 
			
		||||
    pub pipeline: Handle<PipelineDescriptor>,
 | 
			
		||||
@ -104,12 +107,14 @@ impl<'a> Drawable for DrawableRenderPipelines<'a> {
 | 
			
		||||
pub fn draw_render_pipelines_system(
 | 
			
		||||
    mut draw_context: DrawContext,
 | 
			
		||||
    mut render_resource_bindings: ResMut<RenderResourceBindings>,
 | 
			
		||||
    mut draw: ComMut<Draw>,
 | 
			
		||||
    mut render_pipelines: ComMut<RenderPipelines>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Write<Draw>, Write<RenderPipelines>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (mut draw, mut render_pipelines) in query.iter_mut(world) {
 | 
			
		||||
        let mut drawable = DrawableRenderPipelines {
 | 
			
		||||
            render_pipelines: &mut render_pipelines,
 | 
			
		||||
            render_resource_bindings: &mut render_resource_bindings,
 | 
			
		||||
        };
 | 
			
		||||
        drawable.draw(&mut draw, &mut draw_context).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,9 @@
 | 
			
		||||
use crate::{texture::Texture, RenderPipelines};
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use legion::prelude::{Com, ComMut, Res};
 | 
			
		||||
use legion::{
 | 
			
		||||
    prelude::{Read, Res, Write},
 | 
			
		||||
    systems::{Query, SubWorld},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub use bevy_derive::ShaderDefs;
 | 
			
		||||
 | 
			
		||||
@ -55,10 +58,11 @@ impl ShaderDef for Option<Handle<Texture>> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn shader_defs_system<T>(shader_defs: Com<T>, mut render_pipelines: ComMut<RenderPipelines>)
 | 
			
		||||
pub fn shader_defs_system<T>(world: &mut SubWorld, query: Query<(Read<T>, Write<RenderPipelines>)>)
 | 
			
		||||
where
 | 
			
		||||
    T: ShaderDefs + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
    for (shader_defs, mut render_pipelines) in query.iter_mut(world) {
 | 
			
		||||
        for shader_def in shader_defs.iter_shader_defs() {
 | 
			
		||||
            for render_pipeline in render_pipelines.pipelines.iter_mut() {
 | 
			
		||||
                render_pipeline
 | 
			
		||||
@ -68,9 +72,11 @@ where
 | 
			
		||||
                    .insert(shader_def.to_string());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn clear_shader_defs_system(mut render_pipelines: ComMut<RenderPipelines>) {
 | 
			
		||||
pub fn clear_shader_defs_system(world: &mut SubWorld, query: &mut Query<Write<RenderPipelines>>) {
 | 
			
		||||
    for mut render_pipelines in query.iter_mut(world) {
 | 
			
		||||
        for render_pipeline in render_pipelines.pipelines.iter_mut() {
 | 
			
		||||
            render_pipeline
 | 
			
		||||
                .specialization
 | 
			
		||||
@ -78,15 +84,17 @@ pub fn clear_shader_defs_system(mut render_pipelines: ComMut<RenderPipelines>) {
 | 
			
		||||
                .shader_defs
 | 
			
		||||
                .clear();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn asset_shader_defs_system<T>(
 | 
			
		||||
    assets: Res<Assets<T>>,
 | 
			
		||||
    asset_handle: Com<Handle<T>>,
 | 
			
		||||
    mut render_pipelines: ComMut<RenderPipelines>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Read<Handle<T>>, Write<RenderPipelines>)>,
 | 
			
		||||
) where
 | 
			
		||||
    T: ShaderDefs + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
    for (asset_handle, mut render_pipelines) in query.iter_mut(world) {
 | 
			
		||||
        let shader_defs = assets.get(&asset_handle).unwrap();
 | 
			
		||||
        for shader_def in shader_defs.iter_shader_defs() {
 | 
			
		||||
            for render_pipeline in render_pipelines.pipelines.iter_mut() {
 | 
			
		||||
@ -97,4 +105,5 @@ pub fn asset_shader_defs_system<T>(
 | 
			
		||||
                    .insert(shader_def.to_string());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,10 +6,10 @@ use bevy_render::{
 | 
			
		||||
    texture::Texture,
 | 
			
		||||
    Color,
 | 
			
		||||
};
 | 
			
		||||
use bevy_sprite::{ComMut, TextureAtlas};
 | 
			
		||||
use bevy_sprite::TextureAtlas;
 | 
			
		||||
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
 | 
			
		||||
use bevy_transform::prelude::Transform;
 | 
			
		||||
use legion::prelude::{Com, Res, ResMut};
 | 
			
		||||
use legion::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub struct Label {
 | 
			
		||||
    pub text: String,
 | 
			
		||||
@ -37,8 +37,10 @@ impl Label {
 | 
			
		||||
        fonts: Res<Assets<Font>>,
 | 
			
		||||
        mut font_atlas_sets: ResMut<Assets<FontAtlasSet>>,
 | 
			
		||||
        mut texture_atlases: ResMut<Assets<TextureAtlas>>,
 | 
			
		||||
        label: Com<Label>,
 | 
			
		||||
        world: &mut SubWorld,
 | 
			
		||||
        query: &mut Query<Read<Label>>,
 | 
			
		||||
    ) {
 | 
			
		||||
        for label in query.iter(world) {
 | 
			
		||||
            let font_atlases = font_atlas_sets
 | 
			
		||||
                .get_or_insert_with(Handle::from_id(label.font.id), || {
 | 
			
		||||
                    FontAtlasSet::new(label.font)
 | 
			
		||||
@ -57,6 +59,7 @@ impl Label {
 | 
			
		||||
                &label.text,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn draw_label_system(
 | 
			
		||||
        mut draw_context: DrawContext,
 | 
			
		||||
@ -65,11 +68,10 @@ impl Label {
 | 
			
		||||
        texture_atlases: Res<Assets<TextureAtlas>>,
 | 
			
		||||
        mut render_resource_bindings: ResMut<RenderResourceBindings>,
 | 
			
		||||
        mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
 | 
			
		||||
        mut draw: ComMut<Draw>,
 | 
			
		||||
        label: Com<Label>,
 | 
			
		||||
        node: Com<Node>,
 | 
			
		||||
        transform: Com<Transform>,
 | 
			
		||||
        world: &mut SubWorld,
 | 
			
		||||
        query: &mut Query<(Write<Draw>, Read<Label>, Read<Node>, Read<Transform>)>,
 | 
			
		||||
    ) {
 | 
			
		||||
        for (mut draw, label, node, transform) in query.iter_mut(world) {
 | 
			
		||||
            // let position = transform.0 - quad.size / 2.0;
 | 
			
		||||
            let position = transform.value.w_axis().truncate() - (node.size / 2.0).extend(0.0);
 | 
			
		||||
 | 
			
		||||
@ -87,4 +89,5 @@ impl Label {
 | 
			
		||||
            );
 | 
			
		||||
            drawable_text.draw(&mut draw, &mut draw_context).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,15 +10,20 @@ fn main() {
 | 
			
		||||
 | 
			
		||||
fn animate_sprite_system(
 | 
			
		||||
    texture_atlases: Res<Assets<TextureAtlas>>,
 | 
			
		||||
    mut timer: ComMut<Timer>,
 | 
			
		||||
    mut sprite: ComMut<TextureAtlasSprite>,
 | 
			
		||||
    texture_atlas_handle: Com<Handle<TextureAtlas>>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(
 | 
			
		||||
        Write<Timer>,
 | 
			
		||||
        Write<TextureAtlasSprite>,
 | 
			
		||||
        Read<Handle<TextureAtlas>>,
 | 
			
		||||
    )>,
 | 
			
		||||
) {
 | 
			
		||||
    for (mut timer, mut sprite, texture_atlas_handle) in query.iter_mut(world) {
 | 
			
		||||
        if timer.finished {
 | 
			
		||||
            let texture_atlas = texture_atlases.get(&texture_atlas_handle).unwrap();
 | 
			
		||||
            sprite.index = ((sprite.index as usize + 1) % texture_atlas.textures.len()) as u32;
 | 
			
		||||
            timer.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(
 | 
			
		||||
 | 
			
		||||
@ -11,8 +11,14 @@ fn main() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// rotates the parent, which will result in the child also rotating
 | 
			
		||||
fn rotator_system(time: Res<Time>, _rotator: ComMut<Rotator>, mut rotation: ComMut<Rotation>) {
 | 
			
		||||
fn rotator_system(
 | 
			
		||||
    time: Res<Time>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Read<Rotator>, Write<Rotation>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (_rotator, mut rotation) in query.iter_mut(world) {
 | 
			
		||||
        rotation.0 = rotation.0 * Quat::from_rotation_x(3.0 * time.delta_seconds);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// set up a simple scene with a "parent" cube and a "child" cube
 | 
			
		||||
 | 
			
		||||
@ -17,12 +17,14 @@ fn main() {
 | 
			
		||||
fn move_cubes(
 | 
			
		||||
    time: Res<Time>,
 | 
			
		||||
    mut materials: ResMut<Assets<StandardMaterial>>,
 | 
			
		||||
    mut translation: ComMut<Translation>,
 | 
			
		||||
    material_handle: Com<Handle<StandardMaterial>>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Write<Translation>, Read<Handle<StandardMaterial>>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (mut translation, material_handle) in query.iter_mut(world) {
 | 
			
		||||
        let material = materials.get_mut(&material_handle).unwrap();
 | 
			
		||||
        translation.0 += math::vec3(1.0, 0.0, 0.0) * time.delta_seconds;
 | 
			
		||||
        material.albedo += Color::rgb(-time.delta_seconds, -time.delta_seconds, time.delta_seconds);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(
 | 
			
		||||
 | 
			
		||||
@ -12,8 +12,14 @@ fn main() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// rotates the parent, which will result in the child also rotating
 | 
			
		||||
fn rotator_system(time: Res<Time>, _rotator: ComMut<Rotator>, mut rotation: ComMut<Rotation>) {
 | 
			
		||||
fn rotator_system(
 | 
			
		||||
    time: Res<Time>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Read<Rotator>, Write<Rotation>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (_rotator, mut rotation) in query.iter_mut(world) {
 | 
			
		||||
        rotation.0 = rotation.0 * Quat::from_rotation_x(3.0 * time.delta_seconds);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn camera_order_color_system(
 | 
			
		||||
 | 
			
		||||
@ -80,9 +80,9 @@ fn new_round_system(game_rules: Res<GameRules>, mut game_state: ResMut<GameState
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This system runs once for each entity with both the "Player" and "Score" component.
 | 
			
		||||
// NOTE: Com<Player> is a read-only component reference, whereas ComMut<Score> can modify the component
 | 
			
		||||
fn score_system(player: Com<Player>, mut score: ComMut<Score>) {
 | 
			
		||||
// This system updates the score for each entity with the "Player" and "Score" component.
 | 
			
		||||
fn score_system(world: &mut SubWorld, query: &mut Query<(Read<Player>, Write<Score>)>) {
 | 
			
		||||
    for (player, mut score) in query.iter_mut(world) {
 | 
			
		||||
        let scored_a_point = random::<bool>();
 | 
			
		||||
        if scored_a_point {
 | 
			
		||||
            score.value += 1;
 | 
			
		||||
@ -96,32 +96,18 @@ fn score_system(player: Com<Player>, mut score: ComMut<Score>) {
 | 
			
		||||
                player.name, score.value
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // this game isn't very fun is it :)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This system runs on all entities with the "Player" and "Score" components, but it also
 | 
			
		||||
// accesses the "GameRules" resource to determine if a player has won.
 | 
			
		||||
// NOTE: resources must always come before components in system functions
 | 
			
		||||
// NOTE: resources must always come before worlds/queries in system functions
 | 
			
		||||
fn score_check_system(
 | 
			
		||||
    game_rules: Res<GameRules>,
 | 
			
		||||
    mut game_state: ResMut<GameState>,
 | 
			
		||||
    player: Com<Player>,
 | 
			
		||||
    score: Com<Score>,
 | 
			
		||||
) {
 | 
			
		||||
    if score.value == game_rules.winning_score {
 | 
			
		||||
        game_state.winning_player = Some(player.name.clone());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If you need more control over iteration or direct access to SubWorld, you can also use "query systems"
 | 
			
		||||
// This is how you would represent the system above with a "query system"
 | 
			
		||||
// NOTE: You can add as many queries as you want, but they must come after all resources (Res/ResMut).
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
fn query_score_check_system(
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    game_rules: Res<GameRules>,
 | 
			
		||||
    mut game_state: ResMut<GameState>,
 | 
			
		||||
    query: &mut Query<(Read<Player>, Read<Score>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (player, score) in query.iter(world) {
 | 
			
		||||
@ -191,7 +177,7 @@ fn startup_system(world: &mut World, resources: &mut Resources) {
 | 
			
		||||
// Normal systems cannot safely access the World instance directly because they run in parallel.
 | 
			
		||||
// Our World contains all of our components, so accessing it in parallel is not thread safe.
 | 
			
		||||
// 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 components in system functions
 | 
			
		||||
// NOTE: Command buffers must always come after resources and before queries in system functions
 | 
			
		||||
fn new_player_system(
 | 
			
		||||
    game_rules: Res<GameRules>,
 | 
			
		||||
    mut game_state: ResMut<GameState>,
 | 
			
		||||
@ -252,9 +238,11 @@ fn thread_local_system(world: &mut World, resources: &mut Resources) {
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
fn closure_system() -> Box<dyn Schedulable> {
 | 
			
		||||
    let mut counter = 0;
 | 
			
		||||
    (move |player: Com<Player>, score: Com<Score>| {
 | 
			
		||||
    (move |world: &mut SubWorld, query: &mut Query<(Read<Player>, Read<Score>)>| {
 | 
			
		||||
        for (player, score) in query.iter(world) {
 | 
			
		||||
            println!("processed: {} {}", player.name, score.value);
 | 
			
		||||
        println!("this ran {} times", counter);
 | 
			
		||||
        }
 | 
			
		||||
        println!("this system ran {} times", counter);
 | 
			
		||||
        counter += 1;
 | 
			
		||||
    })
 | 
			
		||||
    .system()
 | 
			
		||||
@ -270,9 +258,15 @@ struct State {
 | 
			
		||||
 | 
			
		||||
// NOTE: this doesn't do anything relevant to our game, it is just here for illustrative purposes
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
fn stateful_system(mut state: ComMut<State>, player: Com<Player>, score: ComMut<Score>) {
 | 
			
		||||
fn stateful_system(
 | 
			
		||||
    mut state: ResMut<State>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Read<Player>, Read<Score>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (player, score) in query.iter(world) {
 | 
			
		||||
        println!("processed: {} {}", player.name, score.value);
 | 
			
		||||
    println!("this ran {} times", state.counter);
 | 
			
		||||
    }
 | 
			
		||||
    println!("this system ran {} times", state.counter);
 | 
			
		||||
    state.counter += 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -50,12 +50,19 @@ fn atlas_render_system(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut label: ComMut<Label>) {
 | 
			
		||||
fn text_update_system(
 | 
			
		||||
    mut state: ResMut<State>,
 | 
			
		||||
    time: Res<Time>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<Write<Label>>,
 | 
			
		||||
) {
 | 
			
		||||
    for mut label in query.iter_mut(world) {
 | 
			
		||||
        state.timer.tick(time.delta_seconds);
 | 
			
		||||
        if state.timer.finished {
 | 
			
		||||
            label.text = format!("{}", rand::random::<u8>() as char);
 | 
			
		||||
            state.timer.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(
 | 
			
		||||
@ -71,10 +78,7 @@ fn setup(
 | 
			
		||||
        .entity_with(OrthographicCameraComponents::default())
 | 
			
		||||
        // texture
 | 
			
		||||
        .entity_with(LabelComponents {
 | 
			
		||||
            node: Node::new(
 | 
			
		||||
                Anchors::TOP_LEFT,
 | 
			
		||||
                Margins::new(0.0, 250.0, 0.0, 60.0),
 | 
			
		||||
            ),
 | 
			
		||||
            node: Node::new(Anchors::TOP_LEFT, Margins::new(0.0, 250.0, 0.0, 60.0)),
 | 
			
		||||
            label: Label {
 | 
			
		||||
                text: "a".to_string(),
 | 
			
		||||
                font: font_handle,
 | 
			
		||||
 | 
			
		||||
@ -12,12 +12,18 @@ fn main() {
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn text_update_system(diagnostics: Res<Diagnostics>, mut label: ComMut<Label>) {
 | 
			
		||||
fn text_update_system(
 | 
			
		||||
    diagnostics: Res<Diagnostics>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<Write<Label>>,
 | 
			
		||||
) {
 | 
			
		||||
    for mut label in query.iter_mut(world) {
 | 
			
		||||
        if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) {
 | 
			
		||||
            if let Some(average) = fps.average() {
 | 
			
		||||
                label.text = format!("FPS: {:.2}", average);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(asset_server: Res<AssetServer>, command_buffer: &mut CommandBuffer) {
 | 
			
		||||
@ -28,10 +34,7 @@ fn setup(asset_server: Res<AssetServer>, command_buffer: &mut CommandBuffer) {
 | 
			
		||||
        .entity_with(OrthographicCameraComponents::default())
 | 
			
		||||
        // texture
 | 
			
		||||
        .entity_with(LabelComponents {
 | 
			
		||||
            node: Node::new(
 | 
			
		||||
                Anchors::TOP_LEFT,
 | 
			
		||||
                Margins::new(0.0, 250.0, 0.0, 60.0),
 | 
			
		||||
            ),
 | 
			
		||||
            node: Node::new(Anchors::TOP_LEFT, Margins::new(0.0, 250.0, 0.0, 60.0)),
 | 
			
		||||
            label: Label {
 | 
			
		||||
                text: "FPS:".to_string(),
 | 
			
		||||
                font: font_handle,
 | 
			
		||||
 | 
			
		||||
@ -12,13 +12,15 @@ fn main() {
 | 
			
		||||
fn placement_system(
 | 
			
		||||
    time: Res<Time>,
 | 
			
		||||
    materials: Res<Assets<ColorMaterial>>,
 | 
			
		||||
    mut node: ComMut<Node>,
 | 
			
		||||
    material_handle: Com<Handle<ColorMaterial>>,
 | 
			
		||||
    world: &mut SubWorld,
 | 
			
		||||
    query: &mut Query<(Write<Node>, Read<Handle<ColorMaterial>>)>,
 | 
			
		||||
) {
 | 
			
		||||
    for (mut node, material_handle) in query.iter_mut(world) {
 | 
			
		||||
        let material = materials.get(&material_handle).unwrap();
 | 
			
		||||
        if material.color.r > 0.2 {
 | 
			
		||||
            node.position += Vec2::new(0.1 * time.delta_seconds, 0.0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(mut materials: ResMut<Assets<ColorMaterial>>, command_buffer: &mut CommandBuffer) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user