2020-07-28 23:17:21 +00:00
|
|
|
pub use super::Query;
|
2020-07-10 04:18:35 +00:00
|
|
|
use crate::{
|
2020-07-17 02:20:51 +00:00
|
|
|
resource::{FetchResource, ResourceQuery, Resources, UnsafeClone},
|
2020-10-30 06:39:55 +00:00
|
|
|
system::{Commands, System, SystemId, ThreadLocalExecution},
|
|
|
|
QueryAccess, QuerySet, QueryTuple, TypeAccess,
|
2020-07-10 04:18:35 +00:00
|
|
|
};
|
2020-10-30 06:39:55 +00:00
|
|
|
use bevy_hecs::{ArchetypeComponent, Fetch, Query as HecsQuery, World};
|
|
|
|
use std::{any::TypeId, borrow::Cow};
|
2020-07-10 04:18:35 +00:00
|
|
|
|
2020-10-08 18:43:01 +00:00
|
|
|
#[derive(Debug)]
|
2020-10-30 06:39:55 +00:00
|
|
|
pub(crate) struct SystemFn<State, F, ThreadLocalF, Init, Update>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
2020-10-30 06:39:55 +00:00
|
|
|
F: FnMut(&World, &Resources, &mut State) + Send + Sync,
|
2020-07-15 02:05:39 +00:00
|
|
|
ThreadLocalF: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
|
2020-09-18 00:16:38 +00:00
|
|
|
Init: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
|
2020-10-30 06:39:55 +00:00
|
|
|
Update: FnMut(&World, &mut TypeAccess<ArchetypeComponent>, &mut State) + Send + Sync,
|
2020-07-15 02:05:39 +00:00
|
|
|
State: Send + Sync,
|
2020-07-10 04:18:35 +00:00
|
|
|
{
|
2020-07-15 02:05:39 +00:00
|
|
|
pub state: State,
|
2020-07-10 04:18:35 +00:00
|
|
|
pub func: F,
|
2020-07-14 21:19:17 +00:00
|
|
|
pub thread_local_func: ThreadLocalF,
|
2020-07-10 04:18:35 +00:00
|
|
|
pub init_func: Init,
|
|
|
|
pub thread_local_execution: ThreadLocalExecution,
|
2020-10-30 06:39:55 +00:00
|
|
|
pub resource_access: TypeAccess<TypeId>,
|
2020-07-10 04:18:35 +00:00
|
|
|
pub name: Cow<'static, str>,
|
|
|
|
pub id: SystemId,
|
2020-10-30 06:39:55 +00:00
|
|
|
pub archetype_component_access: TypeAccess<ArchetypeComponent>,
|
|
|
|
pub update_func: Update,
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
impl<State, F, ThreadLocalF, Init, Update> System for SystemFn<State, F, ThreadLocalF, Init, Update>
|
2020-07-10 04:18:35 +00:00
|
|
|
where
|
2020-10-30 06:39:55 +00:00
|
|
|
F: FnMut(&World, &Resources, &mut State) + Send + Sync,
|
2020-07-15 02:05:39 +00:00
|
|
|
ThreadLocalF: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
|
2020-09-18 00:16:38 +00:00
|
|
|
Init: FnMut(&mut World, &mut Resources, &mut State) + Send + Sync,
|
2020-10-30 06:39:55 +00:00
|
|
|
Update: FnMut(&World, &mut TypeAccess<ArchetypeComponent>, &mut State) + Send + Sync,
|
2020-07-15 02:05:39 +00:00
|
|
|
State: Send + Sync,
|
2020-07-10 04:18:35 +00:00
|
|
|
{
|
|
|
|
fn name(&self) -> Cow<'static, str> {
|
|
|
|
self.name.clone()
|
|
|
|
}
|
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
fn update(&mut self, world: &World) {
|
|
|
|
(self.update_func)(world, &mut self.archetype_component_access, &mut self.state);
|
2020-07-14 02:29:34 +00:00
|
|
|
}
|
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
fn archetype_component_access(&self) -> &TypeAccess<ArchetypeComponent> {
|
|
|
|
&self.archetype_component_access
|
2020-07-14 02:29:34 +00:00
|
|
|
}
|
2020-07-17 00:23:50 +00:00
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
fn resource_access(&self) -> &TypeAccess<TypeId> {
|
2020-07-16 00:20:36 +00:00
|
|
|
&self.resource_access
|
|
|
|
}
|
2020-07-14 02:29:34 +00:00
|
|
|
|
2020-07-10 04:18:35 +00:00
|
|
|
fn thread_local_execution(&self) -> ThreadLocalExecution {
|
|
|
|
self.thread_local_execution
|
|
|
|
}
|
|
|
|
|
2020-07-15 06:56:49 +00:00
|
|
|
#[inline]
|
2020-07-10 04:18:35 +00:00
|
|
|
fn run(&mut self, world: &World, resources: &Resources) {
|
2020-10-30 06:39:55 +00:00
|
|
|
(self.func)(world, resources, &mut self.state);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_thread_local(&mut self, world: &mut World, resources: &mut Resources) {
|
2020-07-15 02:05:39 +00:00
|
|
|
(self.thread_local_func)(world, resources, &mut self.state);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-09-18 00:16:38 +00:00
|
|
|
fn initialize(&mut self, world: &mut World, resources: &mut Resources) {
|
|
|
|
(self.init_func)(world, resources, &mut self.state);
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
2020-07-28 21:24:03 +00:00
|
|
|
|
2020-07-10 04:18:35 +00:00
|
|
|
fn id(&self) -> SystemId {
|
|
|
|
self.id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// Converts `Self` into a For-Each system
|
2020-07-10 04:18:35 +00:00
|
|
|
pub trait IntoForEachSystem<CommandBuffer, R, C> {
|
|
|
|
fn system(self) -> Box<dyn System>;
|
|
|
|
}
|
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
struct ForEachState {
|
|
|
|
commands: Commands,
|
|
|
|
query_access: QueryAccess,
|
|
|
|
}
|
|
|
|
|
2020-07-10 04:18:35 +00:00
|
|
|
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,)*
|
|
|
|
{
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
#[allow(unused_variables)]
|
2020-07-12 19:06:43 +00:00
|
|
|
#[allow(unused_unsafe)]
|
2020-07-10 04:18:35 +00:00
|
|
|
fn system(mut self) -> Box<dyn System> {
|
|
|
|
let id = SystemId::new();
|
|
|
|
Box::new(SystemFn {
|
2020-10-30 06:39:55 +00:00
|
|
|
state: ForEachState {
|
|
|
|
commands: Commands::default(),
|
|
|
|
query_access: <($($component,)*) as HecsQuery>::Fetch::access(),
|
|
|
|
},
|
2020-07-10 04:18:35 +00:00
|
|
|
thread_local_execution: ThreadLocalExecution::NextFlush,
|
|
|
|
name: core::any::type_name::<Self>().into(),
|
|
|
|
id,
|
2020-10-30 06:39:55 +00:00
|
|
|
func: move |world, resources, state| {
|
2020-07-12 19:27:11 +00:00
|
|
|
{
|
2020-10-30 06:39:55 +00:00
|
|
|
let state_commands = &state.commands;
|
2020-09-10 20:15:02 +00:00
|
|
|
if let Some(($($resource,)*)) = resources.query_system::<($($resource,)*)>(id) {
|
2020-09-18 00:16:38 +00:00
|
|
|
// SAFE: the scheduler has ensured that there is no archetype clashing here
|
|
|
|
unsafe {
|
2020-10-30 06:39:55 +00:00
|
|
|
for ($($component,)*) in world.query_unchecked::<($($component,)*)>() {
|
|
|
|
fn_call!(self, ($($commands, state_commands)*), ($($resource),*), ($($component),*))
|
2020-09-18 00:16:38 +00:00
|
|
|
}
|
2020-09-10 20:15:02 +00:00
|
|
|
}
|
2020-07-12 19:27:11 +00:00
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
},
|
2020-07-15 02:05:39 +00:00
|
|
|
thread_local_func: move |world, resources, state| {
|
2020-10-30 06:39:55 +00:00
|
|
|
state.commands.apply(world, resources);
|
2020-07-14 21:19:17 +00:00
|
|
|
},
|
2020-09-18 00:16:38 +00:00
|
|
|
init_func: move |world, resources, state| {
|
2020-07-10 04:18:35 +00:00
|
|
|
<($($resource,)*)>::initialize(resources, Some(id));
|
2020-10-30 06:39:55 +00:00
|
|
|
state.commands.set_entity_reserver(world.get_entity_reserver())
|
2020-07-10 04:18:35 +00:00
|
|
|
},
|
2020-07-16 00:20:36 +00:00
|
|
|
resource_access: <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::access(),
|
2020-10-30 06:39:55 +00:00
|
|
|
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));
|
2020-07-14 02:29:34 +00:00
|
|
|
},
|
2020-07-10 04:18:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-07-15 02:05:39 +00:00
|
|
|
struct QuerySystemState {
|
2020-10-30 06:39:55 +00:00
|
|
|
query_accesses: Vec<Vec<QueryAccess>>,
|
|
|
|
query_type_names: Vec<&'static str>,
|
|
|
|
archetype_component_accesses: Vec<TypeAccess<ArchetypeComponent>>,
|
2020-07-15 02:05:39 +00:00
|
|
|
commands: Commands,
|
|
|
|
}
|
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// Converts `Self` into a Query System
|
2020-10-30 06:39:55 +00:00
|
|
|
pub trait IntoQuerySystem<Commands, R, Q, QS> {
|
2020-07-10 04:18:35 +00:00
|
|
|
fn system(self) -> Box<dyn System>;
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_into_query_system {
|
2020-10-30 06:39:55 +00:00
|
|
|
(($($commands: ident)*), ($($resource: ident),*), ($($query: ident),*), ($($query_set: ident),*)) => {
|
|
|
|
impl<Func, $($resource,)* $($query,)* $($query_set,)*> IntoQuerySystem<($($commands,)*), ($($resource,)*), ($($query,)*), ($($query_set,)*)> for Func where
|
2020-07-10 04:18:35 +00:00
|
|
|
Func:
|
2020-10-30 06:39:55 +00:00
|
|
|
FnMut($($commands,)* $($resource,)* $(Query<$query>,)* $(QuerySet<$query_set>,)*) +
|
2020-07-10 04:18:35 +00:00
|
|
|
FnMut(
|
|
|
|
$($commands,)*
|
|
|
|
$(<<$resource as ResourceQuery>::Fetch as FetchResource>::Item,)*
|
2020-10-30 06:39:55 +00:00
|
|
|
$(Query<$query>,)*
|
|
|
|
$(QuerySet<$query_set>,)*
|
|
|
|
) +
|
2020-07-10 04:18:35 +00:00
|
|
|
Send + Sync +'static,
|
|
|
|
$($query: HecsQuery,)*
|
2020-10-30 06:39:55 +00:00
|
|
|
$($query_set: QueryTuple,)*
|
2020-07-10 04:18:35 +00:00
|
|
|
$($resource: ResourceQuery,)*
|
|
|
|
{
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
#[allow(unused_variables)]
|
2020-07-12 19:06:43 +00:00
|
|
|
#[allow(unused_unsafe)]
|
2020-07-15 02:05:39 +00:00
|
|
|
#[allow(unused_assignments)]
|
|
|
|
#[allow(unused_mut)]
|
2020-07-10 04:18:35 +00:00
|
|
|
fn system(mut self) -> Box<dyn System> {
|
|
|
|
let id = SystemId::new();
|
2020-10-30 06:39:55 +00:00
|
|
|
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()];
|
2020-07-10 04:18:35 +00:00
|
|
|
Box::new(SystemFn {
|
2020-07-15 02:05:39 +00:00
|
|
|
state: QuerySystemState {
|
2020-10-30 06:39:55 +00:00
|
|
|
query_accesses,
|
|
|
|
query_type_names,
|
|
|
|
archetype_component_accesses,
|
2020-07-15 02:05:39 +00:00
|
|
|
commands: Commands::default(),
|
|
|
|
},
|
2020-07-10 04:18:35 +00:00
|
|
|
thread_local_execution: ThreadLocalExecution::NextFlush,
|
|
|
|
id,
|
|
|
|
name: core::any::type_name::<Self>().into(),
|
2020-10-30 06:39:55 +00:00
|
|
|
func: move |world, resources, state| {
|
2020-07-12 19:27:11 +00:00
|
|
|
{
|
2020-09-10 20:15:02 +00:00
|
|
|
if let Some(($($resource,)*)) = resources.query_system::<($($resource,)*)>(id) {
|
|
|
|
let mut i = 0;
|
|
|
|
$(
|
2020-10-30 06:39:55 +00:00
|
|
|
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]
|
|
|
|
);
|
2020-09-10 20:15:02 +00:00
|
|
|
i += 1;
|
|
|
|
)*
|
|
|
|
|
|
|
|
let commands = &state.commands;
|
2020-10-30 06:39:55 +00:00
|
|
|
fn_call!(self, ($($commands, commands)*), ($($resource),*), ($($query),*), ($($query_set),*))
|
2020-09-10 20:15:02 +00:00
|
|
|
}
|
2020-07-12 19:27:11 +00:00
|
|
|
}
|
2020-07-10 04:18:35 +00:00
|
|
|
},
|
2020-07-15 02:05:39 +00:00
|
|
|
thread_local_func: move |world, resources, state| {
|
|
|
|
state.commands.apply(world, resources);
|
2020-07-14 21:19:17 +00:00
|
|
|
},
|
2020-09-18 00:16:38 +00:00
|
|
|
init_func: move |world, resources, state| {
|
2020-07-10 04:18:35 +00:00
|
|
|
<($($resource,)*)>::initialize(resources, Some(id));
|
2020-09-18 00:16:38 +00:00
|
|
|
state.commands.set_entity_reserver(world.get_entity_reserver())
|
|
|
|
|
2020-07-10 04:18:35 +00:00
|
|
|
},
|
2020-07-16 00:20:36 +00:00
|
|
|
resource_access: <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::access(),
|
2020-10-30 06:39:55 +00:00
|
|
|
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"));
|
|
|
|
}
|
2020-07-14 02:29:34 +00:00
|
|
|
},
|
2020-07-10 04:18:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! fn_call {
|
2020-10-30 06:39:55 +00:00
|
|
|
($self:ident, ($($commands: ident, $commands_var: ident)*), ($($resource: ident),*), ($($a: ident),*), ($($b: ident),*)) => {
|
|
|
|
unsafe { $self($($commands_var.clone(),)* $($resource.unsafe_clone(),)* $($a,)* $($b,)*) }
|
|
|
|
};
|
2020-07-10 04:18:35 +00:00
|
|
|
($self:ident, ($($commands: ident, $commands_var: ident)*), ($($resource: ident),*), ($($a: ident),*)) => {
|
2020-07-12 19:06:43 +00:00
|
|
|
unsafe { $self($($commands_var.clone(),)* $($resource.unsafe_clone(),)* $($a,)*) }
|
2020-07-10 04:18:35 +00:00
|
|
|
};
|
|
|
|
($self:ident, (), ($($resource: ident),*), ($($a: ident),*)) => {
|
2020-07-12 19:06:43 +00:00
|
|
|
unsafe { $self($($resource.unsafe_clone(),)* $($a,)*) }
|
2020-07-10 04:18:35 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_into_query_systems {
|
|
|
|
(($($resource: ident,)*), ($($query: ident),*)) => {
|
|
|
|
#[rustfmt::skip]
|
2020-10-30 06:39:55 +00:00
|
|
|
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),*), ());
|
2020-07-10 04:18:35 +00:00
|
|
|
#[rustfmt::skip]
|
2020-10-30 06:39:55 +00:00
|
|
|
impl_into_query_system!((Commands), ($($resource),*), ($($query),*), (QS1));
|
|
|
|
#[rustfmt::skip]
|
|
|
|
impl_into_query_system!((Commands), ($($resource),*), ($($query),*), (QS1, QS2));
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// Converts `Self` into a thread local system
|
2020-07-14 21:19:17 +00:00
|
|
|
pub trait IntoThreadLocalSystem {
|
|
|
|
fn thread_local_system(self) -> Box<dyn System>;
|
2020-07-10 04:18:35 +00:00
|
|
|
}
|
2020-07-14 21:19:17 +00:00
|
|
|
|
2020-07-14 23:23:25 +00:00
|
|
|
impl<F> IntoThreadLocalSystem for F
|
|
|
|
where
|
|
|
|
F: ThreadLocalSystemFn,
|
|
|
|
{
|
2020-07-14 21:19:17 +00:00
|
|
|
fn thread_local_system(mut self) -> Box<dyn System> {
|
|
|
|
Box::new(SystemFn {
|
2020-07-15 02:05:39 +00:00
|
|
|
state: (),
|
|
|
|
thread_local_func: move |world, resources, _| {
|
2020-07-14 21:19:17 +00:00
|
|
|
self.run(world, resources);
|
|
|
|
},
|
2020-10-30 06:39:55 +00:00
|
|
|
func: |_, _, _| {},
|
2020-09-18 00:16:38 +00:00
|
|
|
init_func: |_, _, _| {},
|
2020-10-30 06:39:55 +00:00
|
|
|
update_func: |_, _, _| {},
|
2020-07-14 21:19:17 +00:00
|
|
|
thread_local_execution: ThreadLocalExecution::Immediate,
|
2020-07-10 04:18:35 +00:00
|
|
|
name: core::any::type_name::<F>().into(),
|
2020-07-10 08:37:06 +00:00
|
|
|
id: SystemId::new(),
|
2020-07-16 00:20:36 +00:00
|
|
|
resource_access: TypeAccess::default(),
|
2020-10-30 06:39:55 +00:00
|
|
|
archetype_component_access: TypeAccess::default(),
|
2020-07-10 04:18:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2020-07-14 21:19:17 +00:00
|
|
|
|
2020-08-09 23:13:04 +00:00
|
|
|
/// A thread local system function
|
2020-07-10 04:18:35 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-07-14 23:23:25 +00:00
|
|
|
}
|
2020-07-15 02:05:39 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-09-10 20:15:02 +00:00
|
|
|
use super::{IntoForEachSystem, IntoQuerySystem, Query};
|
2020-07-17 02:20:51 +00:00
|
|
|
use crate::{
|
|
|
|
resource::{ResMut, Resources},
|
|
|
|
schedule::Schedule,
|
2020-10-30 06:39:55 +00:00
|
|
|
ChangedRes, Mut, QuerySet,
|
2020-07-17 02:20:51 +00:00
|
|
|
};
|
2020-08-10 00:58:56 +00:00
|
|
|
use bevy_hecs::{Entity, With, World};
|
2020-07-15 02:05:39 +00:00
|
|
|
|
2020-10-30 06:39:55 +00:00
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
2020-07-15 02:05:39 +00:00
|
|
|
struct A;
|
|
|
|
struct B;
|
|
|
|
struct C;
|
|
|
|
struct D;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn query_system_gets() {
|
|
|
|
fn query_system(
|
|
|
|
mut ran: ResMut<bool>,
|
2020-10-30 06:39:55 +00:00
|
|
|
entity_query: Query<With<A, Entity>>,
|
2020-07-15 02:05:39 +00:00
|
|
|
b_query: Query<&B>,
|
|
|
|
a_c_query: Query<(&A, &C)>,
|
|
|
|
d_query: Query<&D>,
|
|
|
|
) {
|
2020-10-30 06:39:55 +00:00
|
|
|
let entities = entity_query.iter().collect::<Vec<Entity>>();
|
2020-07-15 02:05:39 +00:00
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<B>(entities[0]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 0 should not have B"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<B>(entities[1]).is_ok(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 1 should have B"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<A>(entities[1]).is_err(),
|
2020-10-30 06:39:55 +00:00
|
|
|
"entity 1 should have A, but b_query shouldn't have access to it"
|
|
|
|
);
|
2020-07-15 02:05:39 +00:00
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<D>(entities[3]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 3 should have D, but it shouldn't be accessible from b_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
b_query.get_component::<C>(entities[2]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 2 has C, but it shouldn't be accessible from b_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
a_c_query.get_component::<C>(entities[2]).is_ok(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 2 has C, and it should be accessible from a_c_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
a_c_query.get_component::<D>(entities[3]).is_err(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 3 should have D, but it shouldn't be accessible from b_query"
|
|
|
|
);
|
|
|
|
assert!(
|
2020-10-31 01:04:33 +00:00
|
|
|
d_query.get_component::<D>(entities[3]).is_ok(),
|
2020-07-15 02:05:39 +00:00
|
|
|
"entity 3 should have D"
|
|
|
|
);
|
|
|
|
|
|
|
|
*ran = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
resources.insert(false);
|
|
|
|
world.spawn((A,));
|
|
|
|
world.spawn((A, B));
|
|
|
|
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);
|
|
|
|
|
|
|
|
assert!(*resources.get::<bool>().unwrap(), "system ran");
|
|
|
|
}
|
2020-09-10 20:15:02 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn changed_resource_system() {
|
|
|
|
fn incr_e_on_flip(_run_on_flip: ChangedRes<bool>, mut i: Mut<i32>) {
|
|
|
|
*i += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
let mut resources = Resources::default();
|
|
|
|
resources.insert(false);
|
|
|
|
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.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);
|
|
|
|
}
|
2020-10-30 06:39:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_mut_system() {
|
|
|
|
fn sys(_q1: Query<&mut A>, _q2: Query<&mut A>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_immut_system() {
|
|
|
|
fn sys(_q1: Query<&A>, _q2: Query<&mut A>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn query_set_system() {
|
|
|
|
fn sys(_set: QuerySet<(Query<&mut A>, Query<&B>)>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_with_query_set_system() {
|
|
|
|
fn sys(_query: Query<&mut A>, _set: QuerySet<(Query<&mut A>, Query<&B>)>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn conflicting_query_sets_system() {
|
|
|
|
fn sys(_set_1: QuerySet<(Query<&mut A>,)>, _set_2: QuerySet<(Query<&mut A>, Query<&B>)>) {}
|
|
|
|
|
|
|
|
let mut world = World::default();
|
|
|
|
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);
|
|
|
|
}
|
2020-07-15 02:05:39 +00:00
|
|
|
}
|