Compare commits
1 commit
d33dfca274
...
3e2b549717
Author | SHA1 | Date | |
---|---|---|---|
3e2b549717 |
8 changed files with 647 additions and 665 deletions
|
@ -12,6 +12,5 @@ ron = "0.10.0"
|
||||||
syn = { version = "2.0.67", features = ["extra-traits", "full"] }
|
syn = { version = "2.0.67", features = ["extra-traits", "full"] }
|
||||||
quote = "1.0.35"
|
quote = "1.0.35"
|
||||||
proc-macro2 = "1.0.86"
|
proc-macro2 = "1.0.86"
|
||||||
itertools = "0.14.0"
|
|
||||||
|
|
||||||
utilities = { git = "https://gavania.de/hodasemi/utilities.git" }
|
utilities = { git = "https://gavania.de/hodasemi/utilities.git" }
|
||||||
|
|
|
@ -11,6 +11,8 @@ serde.workspace = true
|
||||||
paste.workspace = true
|
paste.workspace = true
|
||||||
ron.workspace = true
|
ron.workspace = true
|
||||||
utilities.workspace = true
|
utilities.workspace = true
|
||||||
itertools.workspace = true
|
|
||||||
|
|
||||||
update_macros = { path = "../update_macros" }
|
update_macros = { path = "../update_macros" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
timings = []
|
||||||
|
|
|
@ -4,20 +4,18 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{resources::Resource, world::ComponentChange, *};
|
use crate::{world::ComponentChange, *};
|
||||||
|
|
||||||
enum CommandTypes {
|
enum CommandsTypes {
|
||||||
InsertEntity(EntityObject),
|
InsertEntity(EntityObject),
|
||||||
RemoveEntity(Entity),
|
RemoveEntity(Entity),
|
||||||
UpdateEntity(Entity, ComponentChange),
|
UpdateEntity(Entity, ComponentChange),
|
||||||
|
|
||||||
Event(TypeId, Box<dyn Any + Send + Sync>),
|
Event(TypeId, Box<dyn Any + Send + Sync>),
|
||||||
|
|
||||||
InsertResource(TypeId, Box<dyn Resource>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Commands {
|
pub struct Commands {
|
||||||
commands: Vec<CommandTypes>,
|
commands: Vec<CommandsTypes>,
|
||||||
now: Duration,
|
now: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,24 +35,24 @@ impl Commands {
|
||||||
let entity = entity_object.as_entity();
|
let entity = entity_object.as_entity();
|
||||||
|
|
||||||
self.commands
|
self.commands
|
||||||
.push(CommandTypes::InsertEntity(entity_object));
|
.push(CommandsTypes::InsertEntity(entity_object));
|
||||||
|
|
||||||
entity
|
entity
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_entity(&mut self, entity: Entity) {
|
pub fn remove_entity(&mut self, entity: Entity) {
|
||||||
self.commands.push(CommandTypes::RemoveEntity(entity));
|
self.commands.push(CommandsTypes::RemoveEntity(entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_component<T: EntityComponent>(&mut self, entity: Entity, component: T) {
|
pub fn insert_component<T: EntityComponent>(&mut self, entity: Entity, component: T) {
|
||||||
self.commands.push(CommandTypes::UpdateEntity(
|
self.commands.push(CommandsTypes::UpdateEntity(
|
||||||
entity,
|
entity,
|
||||||
ComponentChange::Added(TypeId::of::<T>(), Box::new(component)),
|
ComponentChange::Added(TypeId::of::<T>(), Box::new(component)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_component<T: EntityComponent>(&mut self, entity: Entity) {
|
pub fn remove_component<T: EntityComponent>(&mut self, entity: Entity) {
|
||||||
self.commands.push(CommandTypes::UpdateEntity(
|
self.commands.push(CommandsTypes::UpdateEntity(
|
||||||
entity,
|
entity,
|
||||||
ComponentChange::Removed(TypeId::of::<T>()),
|
ComponentChange::Removed(TypeId::of::<T>()),
|
||||||
));
|
));
|
||||||
|
@ -62,32 +60,20 @@ impl Commands {
|
||||||
|
|
||||||
pub fn write_event<T: Any + Send + Sync>(&mut self, payload: T) {
|
pub fn write_event<T: Any + Send + Sync>(&mut self, payload: T) {
|
||||||
self.commands
|
self.commands
|
||||||
.push(CommandTypes::Event(TypeId::of::<T>(), Box::new(payload)));
|
.push(CommandsTypes::Event(TypeId::of::<T>(), Box::new(payload)));
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_resource<T: Resource>(&mut self, resource: T) {
|
|
||||||
self.commands.push(CommandTypes::InsertResource(
|
|
||||||
TypeId::of::<T>(),
|
|
||||||
Box::new(resource),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn apply_deferred(self, world: &mut World) -> Result<()> {
|
pub(crate) fn apply_deferred(self, world: &mut World) -> Result<()> {
|
||||||
for command in self.commands {
|
for command in self.commands {
|
||||||
match command {
|
match command {
|
||||||
CommandTypes::InsertEntity(entity_object) => {
|
CommandsTypes::InsertEntity(entity_object) => {
|
||||||
world.add_entity(entity_object)?;
|
world.add_entity(entity_object)?;
|
||||||
}
|
}
|
||||||
CommandTypes::RemoveEntity(entity) => world.remove_entity(entity),
|
CommandsTypes::RemoveEntity(entity) => world.remove_entity(entity),
|
||||||
CommandTypes::UpdateEntity(entity, component_change) => {
|
CommandsTypes::UpdateEntity(entity, component_change) => {
|
||||||
world.component_change(entity, component_change)
|
world.component_change(entity, component_change)
|
||||||
}
|
}
|
||||||
CommandTypes::Event(type_id, payload) => {
|
CommandsTypes::Event(type_id, any) => world.events.write_payload(type_id, any),
|
||||||
world.events.write_payload(type_id, payload)
|
|
||||||
}
|
|
||||||
CommandTypes::InsertResource(type_id, resource) => {
|
|
||||||
world.resources.insert_resource(type_id, resource)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,6 @@ impl Resources {
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert_resource(&mut self, type_id: TypeId, resource: Box<dyn Resource>) {
|
|
||||||
self.map.insert(type_id, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_if_not_exists<T: Resource + Default>(&mut self) {
|
pub fn insert_if_not_exists<T: Resource + Default>(&mut self) {
|
||||||
if !self.contains::<T>() {
|
if !self.contains::<T>() {
|
||||||
self.insert(T::default());
|
self.insert(T::default());
|
||||||
|
|
|
@ -1,15 +1,370 @@
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::any::TypeId;
|
||||||
use std::{any::TypeId, marker::PhantomData};
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use itertools::Itertools;
|
|
||||||
use update_macros::implement_updates;
|
#[cfg(feature = "timings")]
|
||||||
|
use super::super::timings::Timings;
|
||||||
|
|
||||||
use crate::resources::Resource as ResourceTrait;
|
use crate::resources::Resource as ResourceTrait;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use update_macros::{implement_pair_update, implement_single_update};
|
||||||
|
|
||||||
|
macro_rules! impl_singleton_update {
|
||||||
|
// without resources
|
||||||
|
( $($var:ident $(,)?)+ ) => {
|
||||||
|
impl<Func, Filter, $( $var, )+> CreateArchetype<( $( $var, )+ ), (), Func, Filter> for Archetype
|
||||||
|
where
|
||||||
|
Func: Fn(&mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
Filter: CheckFilter + 'static,
|
||||||
|
$(
|
||||||
|
$var: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
{
|
||||||
|
paste::item! {
|
||||||
|
fn create(f: Func, filter: Filter) -> Self {
|
||||||
|
$(
|
||||||
|
filter.verify_dedup::<$var>();
|
||||||
|
)+
|
||||||
|
|
||||||
|
Self {
|
||||||
|
check_entity: Box::new({
|
||||||
|
move |entity| {
|
||||||
|
$(
|
||||||
|
if !entity.components.contains::<$var>() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
|
||||||
|
if !filter.check(entity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
create_callback: Box::new(move |entity| {
|
||||||
|
$(
|
||||||
|
let [< $var:lower >] = UnsafeComponentStore::from(
|
||||||
|
entity.get_component::<$var>()?
|
||||||
|
);
|
||||||
|
)+
|
||||||
|
|
||||||
|
let f = f.clone();
|
||||||
|
|
||||||
|
Ok(Box::new(move |e, commands, _world| {
|
||||||
|
unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+) }
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
|
||||||
|
entities: IndexMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, Filter, $( $var, )+> AddUpdates<( $( $var, )+ ), (), Func, Filter> for Updates
|
||||||
|
where
|
||||||
|
$(
|
||||||
|
$var: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
Func: Fn(& mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
Filter: CheckFilter + 'static
|
||||||
|
{
|
||||||
|
fn add_update(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
priority: u32,
|
||||||
|
func: Func,
|
||||||
|
filter: Filter
|
||||||
|
) -> Result<()> {
|
||||||
|
paste::item! {
|
||||||
|
self.add(name, priority, Update::Single(Archetype::create(func, filter)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, Filter, $( $var, )+> AddUpdates<( $( $var, )+ ), (), Func, Filter> for WorldBuilder
|
||||||
|
where
|
||||||
|
$(
|
||||||
|
$var: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
Func: Fn(& mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
Filter: CheckFilter + 'static
|
||||||
|
{
|
||||||
|
fn add_update(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
priority: u32,
|
||||||
|
func: Func,
|
||||||
|
filter: Filter,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.updates.add_update(name, priority, func, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// with resources
|
||||||
|
( $($var:ident $(,)?)+ [$($res:ident $(,)?)+] ) => {
|
||||||
|
impl<Func, Filter, $( $var, )+ $( $res, )+> CreateArchetype<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for Archetype
|
||||||
|
where
|
||||||
|
Func: Fn(&mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
Filter: CheckFilter + 'static,
|
||||||
|
$(
|
||||||
|
$var: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
$(
|
||||||
|
$res: ResourceTrait,
|
||||||
|
)+
|
||||||
|
{
|
||||||
|
paste::item! {
|
||||||
|
fn create(f: Func, filter: Filter) -> Self {
|
||||||
|
$(
|
||||||
|
filter.verify_dedup::<$var>();
|
||||||
|
)+
|
||||||
|
|
||||||
|
Self {
|
||||||
|
check_entity: Box::new({
|
||||||
|
move |entity| {
|
||||||
|
$(
|
||||||
|
if !entity.components.contains::<$var>() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
|
||||||
|
if !filter.check(entity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
create_callback: Box::new(move |entity| {
|
||||||
|
$(
|
||||||
|
let [< $var:lower >] = UnsafeComponentStore::from(
|
||||||
|
entity.get_component::<$var>()?
|
||||||
|
);
|
||||||
|
)+
|
||||||
|
|
||||||
|
let f = f.clone();
|
||||||
|
|
||||||
|
Ok(Box::new(move |e, commands, world| {
|
||||||
|
|
||||||
|
let (
|
||||||
|
$(
|
||||||
|
[< $res:lower _var >],
|
||||||
|
)+
|
||||||
|
): (
|
||||||
|
$(
|
||||||
|
&mut $res,
|
||||||
|
)+
|
||||||
|
) = world.resources.get_mut()?;
|
||||||
|
|
||||||
|
unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+ $([< $res:lower _var >],)+) }
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
|
||||||
|
entities: IndexMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, Filter, $( $var, )+ $( $res, )+> AddUpdates<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for Updates
|
||||||
|
where
|
||||||
|
$(
|
||||||
|
$var: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
$(
|
||||||
|
$res: ResourceTrait,
|
||||||
|
)+
|
||||||
|
Func: Fn(& mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
Filter: CheckFilter + 'static
|
||||||
|
{
|
||||||
|
fn add_update(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
priority: u32,
|
||||||
|
func: Func,
|
||||||
|
filter: Filter
|
||||||
|
) -> Result<()> {
|
||||||
|
paste::item! {
|
||||||
|
self.add(name, priority, Update::Single(Archetype::create(func, filter)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, Filter, $( $var, )+ $( $res, )+> AddUpdates<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for WorldBuilder
|
||||||
|
where
|
||||||
|
$(
|
||||||
|
$var: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
$(
|
||||||
|
$res: ResourceTrait,
|
||||||
|
)+
|
||||||
|
Func: Fn(& mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
Filter: CheckFilter + 'static
|
||||||
|
{
|
||||||
|
fn add_update(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
priority: u32,
|
||||||
|
func: Func,
|
||||||
|
filter: Filter,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.updates.add_update(name, priority, func, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_pair_update {
|
||||||
|
(
|
||||||
|
$lhs_id: expr,
|
||||||
|
( $([$lhs_little: ident: $lhs_big: ident]$(,)?)+ ),
|
||||||
|
$rhs_id: expr,
|
||||||
|
( $([$rhs_little: ident: $rhs_big: ident]$(,)?)+ )
|
||||||
|
) => {
|
||||||
|
impl ArchetypePair {
|
||||||
|
paste::item! {
|
||||||
|
pub fn [<create_lhs_ $lhs_id _rhs_ $rhs_id>] <F, LeftFilter, RightFilter, $($lhs_big,)+ $($rhs_big,)+>
|
||||||
|
(f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self
|
||||||
|
where
|
||||||
|
F: Fn(&mut Commands, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
LeftFilter: CheckFilter + 'static,
|
||||||
|
RightFilter: CheckFilter + 'static,
|
||||||
|
$(
|
||||||
|
$rhs_big: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
$(
|
||||||
|
$lhs_big: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
{
|
||||||
|
$(
|
||||||
|
left_filter.verify_dedup::<$lhs_big>();
|
||||||
|
)+
|
||||||
|
|
||||||
|
$(
|
||||||
|
right_filter.verify_dedup::<$rhs_big>();
|
||||||
|
)+
|
||||||
|
|
||||||
|
Self {
|
||||||
|
check_left_entity: Box::new({
|
||||||
|
move |entity| {
|
||||||
|
$(
|
||||||
|
if !entity.components.contains::<$lhs_big>() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
|
||||||
|
if !left_filter.check(entity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
check_right_entity: Box::new({
|
||||||
|
move |entity| {
|
||||||
|
$(
|
||||||
|
if !entity.components.contains::<$rhs_big>() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
|
||||||
|
if !right_filter.check(entity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
create_callback: Box::new(move |lhs_entity, rhs_entity| {
|
||||||
|
$(
|
||||||
|
let $lhs_little = UnsafeComponentStore::from(
|
||||||
|
lhs_entity.get_component::<$lhs_big>()?
|
||||||
|
);
|
||||||
|
)+
|
||||||
|
|
||||||
|
$(
|
||||||
|
let $rhs_little = UnsafeComponentStore::from(
|
||||||
|
rhs_entity.get_component::<$rhs_big>()?
|
||||||
|
);
|
||||||
|
)+
|
||||||
|
|
||||||
|
let f = f.clone();
|
||||||
|
|
||||||
|
Ok(Box::new(move |lhs_e, rhs_e, commands| {
|
||||||
|
unsafe { f(commands, (lhs_e, $($lhs_little.as_mut(),)+), (rhs_e, $($rhs_little.as_mut(),)+) ) }
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
|
||||||
|
entities: IndexMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, LhsFilter, RhsFilter, $( $lhs_big, )+ $($rhs_big,)+> AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), (), Func, (LhsFilter, RhsFilter)> for Updates
|
||||||
|
where
|
||||||
|
$(
|
||||||
|
$rhs_big: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
$(
|
||||||
|
$lhs_big: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
Func: Fn(&mut Commands, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
LhsFilter: CheckFilter + 'static,
|
||||||
|
RhsFilter: CheckFilter + 'static
|
||||||
|
{
|
||||||
|
fn add_update(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
priority: u32,
|
||||||
|
func: Func,
|
||||||
|
filter: (LhsFilter, RhsFilter)
|
||||||
|
) -> Result<()> {
|
||||||
|
paste::item! {
|
||||||
|
self.add(name, priority, Update::Pair(ArchetypePair::[<create_lhs_ $lhs_id _rhs_ $rhs_id>](func, filter.0, filter.1)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, LhsFilter, RhsFilter, $( $lhs_big, )+ $($rhs_big,)+> AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), (), Func, (LhsFilter, RhsFilter)> for WorldBuilder
|
||||||
|
where
|
||||||
|
$(
|
||||||
|
$rhs_big: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
$(
|
||||||
|
$lhs_big: EntityComponent + ComponentDebug,
|
||||||
|
)+
|
||||||
|
Func: Fn(& mut Commands, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
|
LhsFilter: CheckFilter + 'static,
|
||||||
|
RhsFilter: CheckFilter + 'static
|
||||||
|
{
|
||||||
|
fn add_update(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
priority: u32,
|
||||||
|
func: Func,
|
||||||
|
filter: (LhsFilter, RhsFilter),
|
||||||
|
) -> Result<()> {
|
||||||
|
self.updates.add_update(name, priority, func, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_update_filter {
|
macro_rules! impl_update_filter {
|
||||||
( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => {
|
( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => {
|
||||||
|
@ -31,7 +386,7 @@ macro_rules! impl_update_filter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> {
|
impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> {
|
||||||
fn check(entity: &EntityObject) -> bool {
|
fn check(&self, entity: &EntityObject) -> bool {
|
||||||
$(
|
$(
|
||||||
if entity.contains_component::<$big>() {
|
if entity.contains_component::<$big>() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,7 +396,7 @@ macro_rules! impl_update_filter {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_dedup<O: EntityComponent>() {
|
fn verify_dedup<O: EntityComponent>(&self) {
|
||||||
$(
|
$(
|
||||||
if TypeId::of::<O>() == TypeId::of::<$big>() {
|
if TypeId::of::<O>() == TypeId::of::<$big>() {
|
||||||
panic!("Type is used as input and filter at the same time");
|
panic!("Type is used as input and filter at the same time");
|
||||||
|
@ -63,58 +418,37 @@ macro_rules! impl_update_filter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
pub struct Query<T, F = EmptyFilter>
|
||||||
pub struct Query<C, F = EmptyFilter>
|
|
||||||
where
|
where
|
||||||
F: CheckFilter,
|
F: CheckFilter,
|
||||||
{
|
{
|
||||||
entity: Entity,
|
pub components: T,
|
||||||
c: C,
|
|
||||||
filter: PhantomData<F>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, F: CheckFilter> Query<C, F> {
|
d: PhantomData<F>,
|
||||||
pub fn entity(&self) -> Entity {
|
|
||||||
self.entity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, F: CheckFilter> Deref for Query<C, F> {
|
|
||||||
type Target = C;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, F: CheckFilter> DerefMut for Query<C, F> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.c
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AddUpdates<T, R, Func, Filter> {
|
pub trait AddUpdates<T, R, Func, Filter> {
|
||||||
fn add_update(&mut self, priority: u32, func: Func) -> Result<()>;
|
fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CreateArchetype<T, R, Func, Filter> {
|
trait CreateArchetype<T, R, Func, Filter> {
|
||||||
fn create(f: Func) -> Self;
|
fn create(f: Func, filter: Filter) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CheckFilter: Send + Sync + Default + Clone {
|
pub trait CheckFilter: Send + Sync + Default + Clone {
|
||||||
fn check(entity: &EntityObject) -> bool;
|
fn check(&self, entity: &EntityObject) -> bool;
|
||||||
fn verify_dedup<O: EntityComponent>();
|
fn verify_dedup<O: EntityComponent>(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct EmptyFilter;
|
pub struct EmptyFilter;
|
||||||
|
|
||||||
impl CheckFilter for EmptyFilter {
|
impl CheckFilter for EmptyFilter {
|
||||||
fn check(_entity: &EntityObject) -> bool {
|
fn check(&self, _entity: &EntityObject) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_dedup<O>() {}
|
fn verify_dedup<O>(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
|
@ -137,76 +471,42 @@ impl ArchetypeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Archetype {
|
pub struct Archetype {
|
||||||
queries: usize,
|
check_entity: Box<dyn Fn(&EntityObject) -> bool + Send + Sync>,
|
||||||
check_entity: Box<dyn Fn(&EntityObject) -> Option<Vec<usize>> + Send + Sync>,
|
|
||||||
create_callback: Box<
|
create_callback: Box<
|
||||||
dyn Fn(
|
dyn Fn(
|
||||||
&[&EntityObject],
|
&EntityObject,
|
||||||
)
|
)
|
||||||
-> Result<Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>>
|
-> Result<Box<dyn Fn(Entity, &mut Commands, &mut World) -> Result<()> + Send + Sync>>
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync,
|
+ Sync,
|
||||||
>,
|
>,
|
||||||
|
|
||||||
entities:
|
entities: IndexMap<
|
||||||
IndexMap<Vec<Entity>, Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>>,
|
Entity,
|
||||||
|
Box<dyn Fn(Entity, &mut Commands, &mut World) -> Result<()> + Send + Sync>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Archetype {
|
impl Archetype {
|
||||||
pub fn add_entities(
|
pub fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> {
|
||||||
&mut self,
|
if (self.check_entity)(entity_object) {
|
||||||
new_entity: &EntityObject,
|
let cb = (self.create_callback)(entity_object)?;
|
||||||
entity_objects: &IndexMap<Entity, EntityObject>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut complying_entities: Vec<Vec<&EntityObject>> = vec![Vec::new(); self.queries];
|
|
||||||
|
|
||||||
match (self.check_entity)(new_entity) {
|
self.entities.insert(entity_object.as_entity(), cb);
|
||||||
Some(complying_queries) => complying_queries
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|q| complying_entities[q].push(new_entity)),
|
|
||||||
None => return Ok(()),
|
|
||||||
}
|
|
||||||
|
|
||||||
for old_entity in entity_objects.values() {
|
|
||||||
if let Some(complying_queries) = (self.check_entity)(old_entity) {
|
|
||||||
complying_queries
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|q| complying_entities[q].push(old_entity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if one of the queries could not be fullfilled
|
|
||||||
for queryable_entities in complying_entities.iter() {
|
|
||||||
if queryable_entities.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for combinations in complying_entities.into_iter().multi_cartesian_product() {
|
|
||||||
let cb = (self.create_callback)(&combinations)?;
|
|
||||||
|
|
||||||
self.entities
|
|
||||||
.insert(combinations.iter().map(|e| e.as_entity()).collect(), cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_entity(&mut self, entity: Entity) {
|
pub fn remove_entity(&mut self, entity: Entity) {
|
||||||
while let Some(index) = self
|
self.entities.swap_remove(&entity);
|
||||||
.entities
|
|
||||||
.keys()
|
|
||||||
.position(|entities| entities.contains(&entity))
|
|
||||||
{
|
|
||||||
self.entities.swap_remove_index(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&self, world: &mut World) -> Result<()> {
|
pub fn execute(&self, world: &mut World) -> Result<()> {
|
||||||
let mut commands = Commands::new(world.now());
|
let mut commands = Commands::new(world.now());
|
||||||
|
|
||||||
for callback in self.entities.values() {
|
for (entity, callback) in self.entities.iter() {
|
||||||
callback(&mut commands, world)?;
|
callback(*entity, &mut commands, world)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.apply_deferred(world)?;
|
commands.apply_deferred(world)?;
|
||||||
|
@ -216,23 +516,120 @@ impl Archetype {
|
||||||
|
|
||||||
pub fn entities(
|
pub fn entities(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<
|
) -> &IndexMap<Entity, Box<dyn Fn(Entity, &mut Commands, &mut World) -> Result<()> + Send + Sync>>
|
||||||
Item = (
|
{
|
||||||
&Vec<Entity>,
|
&self.entities
|
||||||
&Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>,
|
}
|
||||||
),
|
}
|
||||||
> {
|
|
||||||
self.entities.iter()
|
pub struct ArchetypePair {
|
||||||
|
check_left_entity: Box<dyn Fn(&EntityObject) -> bool + Send + Sync>,
|
||||||
|
check_right_entity: Box<dyn Fn(&EntityObject) -> bool + Send + Sync>,
|
||||||
|
|
||||||
|
create_callback: Box<
|
||||||
|
dyn Fn(
|
||||||
|
&EntityObject,
|
||||||
|
&EntityObject,
|
||||||
|
)
|
||||||
|
-> Result<Box<dyn Fn(Entity, Entity, &mut Commands) -> Result<()> + Send + Sync>>
|
||||||
|
+ Send
|
||||||
|
+ Sync,
|
||||||
|
>,
|
||||||
|
|
||||||
|
entities: IndexMap<
|
||||||
|
(Entity, Entity),
|
||||||
|
Box<dyn Fn(Entity, Entity, &mut Commands) -> Result<()> + Send + Sync>,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArchetypePair {
|
||||||
|
pub(crate) fn add_entity(
|
||||||
|
&mut self,
|
||||||
|
entity_object: &EntityObject,
|
||||||
|
entities: &IndexMap<Entity, EntityObject>,
|
||||||
|
) -> Result<()> {
|
||||||
|
for (other_entity, other_entity_object) in entities.iter() {
|
||||||
|
if entity_object.as_entity() == *other_entity {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the entities can be on both sides
|
||||||
|
if (self.check_left_entity)(entity_object)
|
||||||
|
&& (self.check_right_entity)(other_entity_object)
|
||||||
|
{
|
||||||
|
let cb = (self.create_callback)(entity_object, other_entity_object)?;
|
||||||
|
|
||||||
|
self.entities
|
||||||
|
.insert((entity_object.as_entity(), *other_entity), cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.check_left_entity)(other_entity_object)
|
||||||
|
&& (self.check_right_entity)(entity_object)
|
||||||
|
{
|
||||||
|
let cb = (self.create_callback)(other_entity_object, entity_object)?;
|
||||||
|
|
||||||
|
self.entities
|
||||||
|
.insert((*other_entity, entity_object.as_entity()), cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove_entity(&mut self, entity: Entity) {
|
||||||
|
while let Some((left_entity, right_entity)) = self
|
||||||
|
.entities
|
||||||
|
.keys()
|
||||||
|
.find(|(left_entity, right_entity)| *left_entity == entity || *right_entity == entity)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
self.entities.swap_remove(&(left_entity, right_entity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn execute(&self, world: &mut World) -> Result<()> {
|
||||||
|
let mut commands = Commands::new(world.now());
|
||||||
|
|
||||||
|
for ((left_entity, right_entity), callback) in self.entities.iter() {
|
||||||
|
callback(*left_entity, *right_entity, &mut commands)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.apply_deferred(world)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Update {
|
||||||
|
Single(Archetype),
|
||||||
|
Pair(ArchetypePair),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Archetype> for Update {
|
||||||
|
fn from(archetype: Archetype) -> Self {
|
||||||
|
Self::Single(archetype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ArchetypePair> for Update {
|
||||||
|
fn from(pair: ArchetypePair) -> Self {
|
||||||
|
Self::Pair(pair)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Updates {
|
pub struct Updates {
|
||||||
updates: Vec<(u32, Archetype)>,
|
#[cfg(feature = "timings")]
|
||||||
|
timings: Timings,
|
||||||
|
|
||||||
|
updates: Vec<(String, u32, Update)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Updates {
|
impl Default for Updates {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
timings: Timings::default,
|
||||||
|
|
||||||
updates: Vec::new(),
|
updates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,9 +637,38 @@ impl Default for Updates {
|
||||||
|
|
||||||
impl Updates {
|
impl Updates {
|
||||||
pub(crate) fn update(&mut self, world: &mut World) -> Result<()> {
|
pub(crate) fn update(&mut self, world: &mut World) -> Result<()> {
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
if let Some(timings) = self.timings.check_timing(world.now(), None) {
|
||||||
|
if !timings.is_empty() {
|
||||||
|
println!("timings: {:#?}", timings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
let timings = &mut self.timings;
|
||||||
|
|
||||||
self.updates
|
self.updates
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|(_, archetype)| archetype.execute(world))
|
.try_for_each(|(_name, _, update)| -> Result<()> {
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
let before = Instant::now();
|
||||||
|
|
||||||
|
match update {
|
||||||
|
Update::Single(archetype) => {
|
||||||
|
archetype.execute(world)?;
|
||||||
|
}
|
||||||
|
Update::Pair(archetype_pair) => {
|
||||||
|
archetype_pair.execute(world)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
timings.add(_name, Instant::now().duration_since(before));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_entity(
|
pub(crate) fn add_entity(
|
||||||
|
@ -250,27 +676,88 @@ impl Updates {
|
||||||
entity_object: &EntityObject,
|
entity_object: &EntityObject,
|
||||||
entities: &IndexMap<Entity, EntityObject>,
|
entities: &IndexMap<Entity, EntityObject>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for (_, archetype) in self.updates.iter_mut() {
|
for (_, _, update) in self.updates.iter_mut() {
|
||||||
archetype.add_entities(entity_object, entities)?;
|
match update {
|
||||||
|
Update::Single(archetype) => {
|
||||||
|
archetype.add_entity(entity_object)?;
|
||||||
|
}
|
||||||
|
Update::Pair(archetype_pair) => {
|
||||||
|
archetype_pair.add_entity(entity_object, entities)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_entity(&mut self, entity: Entity) {
|
pub(crate) fn remove_entity(&mut self, entity: Entity) {
|
||||||
for (_, archetype) in self.updates.iter_mut() {
|
for (_, _, update) in self.updates.iter_mut() {
|
||||||
archetype.remove_entity(entity);
|
match update {
|
||||||
|
Update::Single(archetype) => {
|
||||||
|
archetype.remove_entity(entity);
|
||||||
|
}
|
||||||
|
Update::Pair(archetype_pair) => {
|
||||||
|
archetype_pair.remove_entity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, priority: u32, archetype: Archetype) -> Result<()> {
|
// pub(crate) fn clear(&mut self) {
|
||||||
self.updates.push((priority, archetype));
|
// self.updates.clear();
|
||||||
self.updates.sort_by_key(|(prio, _)| *prio);
|
|
||||||
|
// #[cfg(feature = "timings")]
|
||||||
|
// self.timings.clear();
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub(crate) fn add(&mut self, name: &str, priority: u32, update: Update) -> Result<()> {
|
||||||
|
#[cfg(feature = "timings")]
|
||||||
|
self.timings.add_timing_afterwards(name);
|
||||||
|
|
||||||
|
self.updates.push((name.to_string(), priority, update));
|
||||||
|
self.updates
|
||||||
|
.sort_by(|(_, lhs_prio, _), (_, rhs_prio, _)| lhs_prio.cmp(rhs_prio));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Archetypes {
|
||||||
|
archetypes: HashMap<String, Archetype>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Archetypes {
|
||||||
|
pub(crate) fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> {
|
||||||
|
for archetype in self.archetypes.values_mut() {
|
||||||
|
archetype.add_entity(entity_object)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove_entity(&mut self, entity: Entity) {
|
||||||
|
for archetype in self.archetypes.values_mut() {
|
||||||
|
archetype.remove_entity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn insert(&mut self, name: String, archetype: Archetype) {
|
||||||
|
assert!(self.archetypes.insert(name, archetype).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get(&self, name: &String) -> Option<&Archetype> {
|
||||||
|
self.archetypes.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn execute(&self, name: &String, world: &mut World) -> Result<()> {
|
||||||
|
self.archetypes[name].execute(world)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implement_pair_update!(impl_pair_update, 1, 10);
|
||||||
|
implement_single_update!(impl_singleton_update, 1, 10);
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
impl_update_filter!(Monuple, [R, r]);
|
impl_update_filter!(Monuple, [R, r]);
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
@ -291,5 +778,3 @@ impl_update_filter!(Octuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w],
|
||||||
impl_update_filter!(Nonuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z]);
|
impl_update_filter!(Nonuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z]);
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
impl_update_filter!(Decuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z], [A, a]);
|
impl_update_filter!(Decuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z], [A, a]);
|
||||||
|
|
||||||
implement_updates!(5, 5);
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Error, Result, bail};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use utilities::prelude::{remove_life_time, remove_life_time_mut};
|
use utilities::prelude::{remove_life_time, remove_life_time_mut};
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ pub struct WorldBuilder {
|
||||||
pub(crate) updates: Updates,
|
pub(crate) updates: Updates,
|
||||||
pub events: Events,
|
pub events: Events,
|
||||||
pub resources: Resources,
|
pub resources: Resources,
|
||||||
|
archetypes: Archetypes,
|
||||||
systems: Vec<(
|
systems: Vec<(
|
||||||
u32,
|
u32,
|
||||||
Box<dyn Fn(&mut World) -> Result<bool> + Send + Sync + 'static>,
|
Box<dyn Fn(&mut World) -> Result<bool> + Send + Sync + 'static>,
|
||||||
|
@ -28,6 +29,10 @@ impl WorldBuilder {
|
||||||
self.systems.push((priority, Box::new(f)));
|
self.systems.push((priority, Box::new(f)));
|
||||||
self.systems.sort_by_key(|(priority, _)| *priority);
|
self.systems.sort_by_key(|(priority, _)| *priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_archetype(&mut self, name: impl ToString, archetype: Archetype) {
|
||||||
|
self.archetypes.insert(name.to_string(), archetype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorldBuilder {
|
impl WorldBuilder {
|
||||||
|
@ -37,6 +42,7 @@ impl WorldBuilder {
|
||||||
events: self.events,
|
events: self.events,
|
||||||
resources: self.resources,
|
resources: self.resources,
|
||||||
entities: Default::default(),
|
entities: Default::default(),
|
||||||
|
archetypes: self.archetypes,
|
||||||
|
|
||||||
entities_to_remove: Default::default(),
|
entities_to_remove: Default::default(),
|
||||||
entities_to_add: Default::default(),
|
entities_to_add: Default::default(),
|
||||||
|
@ -62,6 +68,7 @@ pub struct World {
|
||||||
pub events: Events,
|
pub events: Events,
|
||||||
pub resources: Resources,
|
pub resources: Resources,
|
||||||
pub(crate) entities: IndexMap<Entity, EntityObject>,
|
pub(crate) entities: IndexMap<Entity, EntityObject>,
|
||||||
|
archetypes: Archetypes,
|
||||||
|
|
||||||
entities_to_remove: Vec<Entity>,
|
entities_to_remove: Vec<Entity>,
|
||||||
entities_to_add: Vec<EntityObject>,
|
entities_to_add: Vec<EntityObject>,
|
||||||
|
@ -82,6 +89,7 @@ impl World {
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
resources: Default::default(),
|
resources: Default::default(),
|
||||||
systems: Default::default(),
|
systems: Default::default(),
|
||||||
|
archetypes: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +263,33 @@ impl World {
|
||||||
pub fn remove_entity(&mut self, entity: Entity) {
|
pub fn remove_entity(&mut self, entity: Entity) {
|
||||||
self.entities_to_remove.push(entity);
|
self.entities_to_remove.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn execute_archetype(&mut self, name: impl ToString) -> Result<()> {
|
||||||
|
let archetypes = unsafe { remove_life_time_mut(&mut self.archetypes) };
|
||||||
|
archetypes.execute(&name.to_string(), self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn archetype_info(&self, name: impl ToString) -> Result<ArchetypeInfo> {
|
||||||
|
let name = name.to_string();
|
||||||
|
let archetype = self
|
||||||
|
.archetypes
|
||||||
|
.get(&name)
|
||||||
|
.ok_or_else(|| Error::msg(format!("requested archetype ({}) not found", name)))?;
|
||||||
|
|
||||||
|
let mut entities = Vec::new();
|
||||||
|
|
||||||
|
for entity in archetype.entities().keys() {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let debug_name = self.entity(*entity)?.debug_name.clone();
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
let debug_name = None;
|
||||||
|
|
||||||
|
entities.push((*entity, debug_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ArchetypeInfo::new(entities))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// async application of changes
|
// async application of changes
|
||||||
|
@ -270,6 +305,7 @@ impl World {
|
||||||
let e = entity.as_entity();
|
let e = entity.as_entity();
|
||||||
|
|
||||||
self.updates.add_entity(&mut entity, &self.entities)?;
|
self.updates.add_entity(&mut entity, &self.entities)?;
|
||||||
|
self.archetypes.add_entity(&entity)?;
|
||||||
assert!(self.entities.insert(e, entity).is_none());
|
assert!(self.entities.insert(e, entity).is_none());
|
||||||
|
|
||||||
Ok(e)
|
Ok(e)
|
||||||
|
@ -283,6 +319,7 @@ impl World {
|
||||||
|
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
self.updates.remove_entity(entity);
|
self.updates.remove_entity(entity);
|
||||||
|
self.archetypes.remove_entity(entity);
|
||||||
|
|
||||||
return Ok(Some(entity_object));
|
return Ok(Some(entity_object));
|
||||||
}
|
}
|
||||||
|
@ -302,6 +339,7 @@ impl World {
|
||||||
.ok_or_else(|| EntityNotFoundError::new(entity))?;
|
.ok_or_else(|| EntityNotFoundError::new(entity))?;
|
||||||
|
|
||||||
self.updates.remove_entity(entity);
|
self.updates.remove_entity(entity);
|
||||||
|
self.archetypes.remove_entity(entity);
|
||||||
|
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
|
|
||||||
|
@ -313,6 +351,7 @@ impl World {
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
|
|
||||||
self.updates.add_entity(entity_object, &self.entities)?;
|
self.updates.add_entity(entity_object, &self.entities)?;
|
||||||
|
self.archetypes.add_entity(entity_object)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -328,6 +367,7 @@ impl World {
|
||||||
.ok_or_else(|| EntityNotFoundError::new(entity))?;
|
.ok_or_else(|| EntityNotFoundError::new(entity))?;
|
||||||
|
|
||||||
self.updates.remove_entity(entity);
|
self.updates.remove_entity(entity);
|
||||||
|
self.archetypes.remove_entity(entity);
|
||||||
|
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
|
|
||||||
|
@ -338,6 +378,7 @@ impl World {
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
|
|
||||||
self.updates.add_entity(entity_object, &self.entities)?;
|
self.updates.add_entity(entity_object, &self.entities)?;
|
||||||
|
self.archetypes.add_entity(entity_object)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -375,6 +416,7 @@ impl World {
|
||||||
|
|
||||||
for (entity, changes) in core::mem::take(&mut self.entities_updates) {
|
for (entity, changes) in core::mem::take(&mut self.entities_updates) {
|
||||||
self.updates.remove_entity(entity);
|
self.updates.remove_entity(entity);
|
||||||
|
self.archetypes.remove_entity(entity);
|
||||||
|
|
||||||
if let Ok(entity_object) = unsafe { self.entity_mut_unchecked(entity) } {
|
if let Ok(entity_object) = unsafe { self.entity_mut_unchecked(entity) } {
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
|
@ -405,6 +447,7 @@ impl World {
|
||||||
entity_object.activation_state.apply_change();
|
entity_object.activation_state.apply_change();
|
||||||
|
|
||||||
self.updates.add_entity(entity_object, &self.entities)?;
|
self.updates.add_entity(entity_object, &self.entities)?;
|
||||||
|
self.archetypes.add_entity(entity_object)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
mod pair_update;
|
mod pair_update;
|
||||||
mod single_update;
|
mod single_update;
|
||||||
mod update;
|
|
||||||
|
|
||||||
use pair_update::pair_update;
|
use pair_update::pair_update;
|
||||||
use single_update::single_update;
|
use single_update::single_update;
|
||||||
use update::update;
|
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
@ -15,31 +13,6 @@ use syn::{
|
||||||
token::Comma,
|
token::Comma,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateInfo {
|
|
||||||
max_components: usize,
|
|
||||||
max_resources: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for UpdateInfo {
|
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
|
||||||
let max_components = input.parse::<LitInt>()?.base10_parse()?;
|
|
||||||
input.parse::<Comma>()?;
|
|
||||||
let max_resources = input.parse::<LitInt>()?.base10_parse()?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
max_components,
|
|
||||||
max_resources,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn implement_updates(input: TokenStream) -> TokenStream {
|
|
||||||
let input = parse_macro_input!(input as UpdateInfo);
|
|
||||||
|
|
||||||
update(input.max_components, input.max_resources)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InputInfo {
|
struct InputInfo {
|
||||||
macro_ident: Ident,
|
macro_ident: Ident,
|
||||||
start: usize,
|
start: usize,
|
||||||
|
|
|
@ -1,502 +0,0 @@
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
|
||||||
use quote::{ToTokens, format_ident, quote};
|
|
||||||
use syn::Ident;
|
|
||||||
|
|
||||||
struct Query {
|
|
||||||
components: Vec<Ident>,
|
|
||||||
filter: Ident,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Query {
|
|
||||||
pub fn new(components: impl Iterator<Item = Ident>, filter_id: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
components: components.collect(),
|
|
||||||
filter: format_ident!("Filter{filter_id}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn types(&self) -> TokenStream2 {
|
|
||||||
let component_list = self
|
|
||||||
.components
|
|
||||||
.iter()
|
|
||||||
.map(|c| quote! { #c })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let components = if component_list.len() == 1 {
|
|
||||||
let component = &component_list[0];
|
|
||||||
quote! { #component }
|
|
||||||
} else {
|
|
||||||
quote! { ( #( #component_list, )* ) }
|
|
||||||
};
|
|
||||||
|
|
||||||
components
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dedup_checks(&self) -> TokenStream2 {
|
|
||||||
let components = &self.components;
|
|
||||||
let filter = &self.filter;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #filter::verify_dedup::<#components>(); )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_entity(&self, index: usize) -> TokenStream2 {
|
|
||||||
let components = &self.components;
|
|
||||||
let filter = &self.filter;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
{
|
|
||||||
let mut complies = true;
|
|
||||||
|
|
||||||
#(
|
|
||||||
if !entity.components.contains::<#components>() {
|
|
||||||
complies = false;
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
|
|
||||||
if !#filter::check(entity) {
|
|
||||||
complies = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if complies {
|
|
||||||
comply_queries.push(#index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn component_store_and_query(&self, index: usize) -> (TokenStream2, TokenStream2, Ident) {
|
|
||||||
let components = &self.components;
|
|
||||||
let entity_name = format_ident!("entity_{index}");
|
|
||||||
let component_names = self
|
|
||||||
.components
|
|
||||||
.iter()
|
|
||||||
.map(|component| format_ident!("q_{index}_{component}"))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let query_ident = format_ident!("query_{index}");
|
|
||||||
let entity_ident = format_ident!("e_{index}");
|
|
||||||
|
|
||||||
(
|
|
||||||
quote! {
|
|
||||||
let #entity_name = &entities[#index];
|
|
||||||
let #entity_ident = #entity_name.as_entity();
|
|
||||||
|
|
||||||
#(
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let #component_names = UnsafeComponentStore::from(
|
|
||||||
#entity_name.get_component::<#components>()?
|
|
||||||
);
|
|
||||||
)*
|
|
||||||
},
|
|
||||||
if component_names.len() == 1 {
|
|
||||||
let component_name = &component_names[0];
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
let #query_ident = Query {
|
|
||||||
entity: #entity_ident,
|
|
||||||
c: unsafe { #component_name.as_mut() },
|
|
||||||
filter: PhantomData,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
let #query_ident = Query {
|
|
||||||
entity: #entity_ident,
|
|
||||||
c: unsafe { ( #( #component_names.as_mut(), )* ) },
|
|
||||||
filter: PhantomData,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
query_ident,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn components(&self) -> &Vec<Ident> {
|
|
||||||
&self.components
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter(&self) -> &Ident {
|
|
||||||
&self.filter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for Query {
|
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
|
||||||
let component_list = self
|
|
||||||
.components
|
|
||||||
.iter()
|
|
||||||
.map(|c| quote! { &mut #c })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let components = if component_list.len() == 1 {
|
|
||||||
let component = &component_list[0];
|
|
||||||
quote! { #component }
|
|
||||||
} else {
|
|
||||||
quote! { ( #( #component_list, )* ) }
|
|
||||||
};
|
|
||||||
|
|
||||||
let filter = self.filter.clone();
|
|
||||||
|
|
||||||
TokenStream2::from(quote! {
|
|
||||||
Query<#components, #filter>
|
|
||||||
})
|
|
||||||
.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Update {
|
|
||||||
queries: Vec<Query>,
|
|
||||||
resources: Vec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Update {
|
|
||||||
const MIN_RESOURCE: usize = 0;
|
|
||||||
const MIN_COMPONENTS: usize = 1;
|
|
||||||
|
|
||||||
pub fn new(queries: impl Iterator<Item = usize>, resources: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
queries: queries
|
|
||||||
.enumerate()
|
|
||||||
.map(|(query, component_count)| {
|
|
||||||
Query::new(
|
|
||||||
(0..component_count).map(|component| format_ident!("C{component}Q{query}")),
|
|
||||||
query,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
resources: (0..resources)
|
|
||||||
.map(|resource| format_ident!("Res{resource}"))
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter_types(&self) -> TokenStream2 {
|
|
||||||
let filter_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.filter())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if filter_types.len() == 1 {
|
|
||||||
let filter = &filter_types[0];
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#filter
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
( #( #filter_types, )* )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter_type_impls(&self) -> TokenStream2 {
|
|
||||||
let filter_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.filter())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #filter_types, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter_requirements(&self) -> TokenStream2 {
|
|
||||||
let filter_requirements = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.filter())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #filter_requirements: CheckFilter + 'static, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_types(&self) -> TokenStream2 {
|
|
||||||
let query_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.types())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
( #( #query_types, )* )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_type_impls(&self) -> TokenStream2 {
|
|
||||||
let query_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.components())
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #query_types, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn component_requirements(&self) -> TokenStream2 {
|
|
||||||
let component_requirements = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| {
|
|
||||||
query.components.iter().map(|component| {
|
|
||||||
quote! {
|
|
||||||
#component: EntityComponent + ComponentDebug,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #component_requirements )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resource_store(&self) -> (TokenStream2, Vec<Ident>) {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
let resource_idents = self
|
|
||||||
.resources
|
|
||||||
.iter()
|
|
||||||
.map(|resource| format_ident!("res_{resource}"))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if self.resources.is_empty() {
|
|
||||||
(quote! {}, Vec::new())
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
quote! {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let (
|
|
||||||
#( #resource_idents, )*
|
|
||||||
): (
|
|
||||||
#( &mut #resource_types, )*
|
|
||||||
) = world.resources.get_mut()?;
|
|
||||||
},
|
|
||||||
resource_idents,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resource_types(&self) -> TokenStream2 {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
( #( #resource_types, )* )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resource_type_impls(&self) -> TokenStream2 {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #resource_types, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reource_requirement(&self) -> TokenStream2 {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #resource_types: ResourceTrait, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for Update {
|
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
|
||||||
// generics to specify trait implementations
|
|
||||||
let filter_types = self.filter_types();
|
|
||||||
let filter_type_impls = self.filter_type_impls();
|
|
||||||
let query_types = self.query_types();
|
|
||||||
let query_type_impls = self.query_type_impls();
|
|
||||||
let resource_types = self.resource_types();
|
|
||||||
let resource_type_impls = self.resource_type_impls();
|
|
||||||
|
|
||||||
// panic!("{resource_type_impls}");
|
|
||||||
|
|
||||||
// function parameter
|
|
||||||
let queries = &self.queries;
|
|
||||||
let resources = if self.resources.is_empty() {
|
|
||||||
quote! {}
|
|
||||||
} else {
|
|
||||||
let resources = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( &mut #resources, )*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// trait requirements
|
|
||||||
let filter_requirements = self.filter_requirements();
|
|
||||||
let component_requirements = self.component_requirements();
|
|
||||||
let reource_requirement = self.reource_requirement();
|
|
||||||
|
|
||||||
let query_count = self.queries.len();
|
|
||||||
|
|
||||||
let verify_dedup = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.dedup_checks())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let check_entities = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index, query)| query.check_entity(index))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let component_stores_and_queries = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index, query)| query.component_store_and_query(index))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let mut component_stores = Vec::new();
|
|
||||||
let mut query_structs = Vec::new();
|
|
||||||
let mut query_idents = Vec::new();
|
|
||||||
|
|
||||||
for (component_store, query_struct, query_ident) in component_stores_and_queries {
|
|
||||||
component_stores.push(component_store);
|
|
||||||
query_structs.push(query_struct);
|
|
||||||
query_idents.push(query_ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (resource_store, resource_idents) = self.resource_store();
|
|
||||||
|
|
||||||
TokenStream2::from(quote! {
|
|
||||||
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> CreateArchetype<#query_types, #resource_types, Func, #filter_types> for Archetype
|
|
||||||
where
|
|
||||||
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
|
||||||
#filter_requirements
|
|
||||||
#component_requirements
|
|
||||||
#reource_requirement
|
|
||||||
{
|
|
||||||
fn create(f: Func) -> Self {
|
|
||||||
#( #verify_dedup )*
|
|
||||||
|
|
||||||
Self {
|
|
||||||
queries: #query_count,
|
|
||||||
|
|
||||||
check_entity: Box::new(move |entity| {
|
|
||||||
let mut comply_queries = Vec::new();
|
|
||||||
|
|
||||||
#( #check_entities )*
|
|
||||||
|
|
||||||
if comply_queries.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(comply_queries)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
create_callback: Box::new(move |entities| {
|
|
||||||
#( #component_stores )*
|
|
||||||
|
|
||||||
let f = f.clone();
|
|
||||||
|
|
||||||
Ok(Box::new(move |commands, world| {
|
|
||||||
#( #query_structs )*
|
|
||||||
#resource_store
|
|
||||||
|
|
||||||
f(commands, #( #query_idents, )* #( #resource_idents, )* )
|
|
||||||
}))
|
|
||||||
}),
|
|
||||||
|
|
||||||
entities: IndexMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> AddUpdates<#query_types, #resource_types, Func, #filter_types> for Updates
|
|
||||||
where
|
|
||||||
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
|
||||||
#filter_requirements
|
|
||||||
#component_requirements
|
|
||||||
#reource_requirement
|
|
||||||
{
|
|
||||||
fn add_update(
|
|
||||||
&mut self,
|
|
||||||
priority: u32,
|
|
||||||
func: Func,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.add(priority, Archetype::create(func))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> AddUpdates<#query_types, #resource_types, Func, #filter_types> for WorldBuilder
|
|
||||||
where
|
|
||||||
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
|
||||||
#filter_requirements
|
|
||||||
#component_requirements
|
|
||||||
#reource_requirement
|
|
||||||
{
|
|
||||||
fn add_update(
|
|
||||||
&mut self,
|
|
||||||
priority: u32,
|
|
||||||
func: Func,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.updates.add_update(priority, func)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(max_components: usize, max_resources: usize) -> TokenStream {
|
|
||||||
let mut queries: Vec<Vec<usize>> = Vec::new();
|
|
||||||
|
|
||||||
for c in Update::MIN_COMPONENTS..=max_components {
|
|
||||||
queries.push(vec![c]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in Update::MIN_COMPONENTS..=max_components {
|
|
||||||
for y in Update::MIN_COMPONENTS..=max_components {
|
|
||||||
queries.push(vec![x, y]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in Update::MIN_COMPONENTS..=max_components {
|
|
||||||
for y in Update::MIN_COMPONENTS..=max_components {
|
|
||||||
for z in Update::MIN_COMPONENTS..=max_components {
|
|
||||||
queries.push(vec![x, y, z]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut resources = Vec::new();
|
|
||||||
|
|
||||||
for resource in Update::MIN_RESOURCE..=max_resources {
|
|
||||||
resources.push(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut updates = Vec::new();
|
|
||||||
|
|
||||||
for query in queries.iter() {
|
|
||||||
for resource_count in resources.iter() {
|
|
||||||
updates.push(Update::new(query.iter().cloned(), *resource_count));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updates.push(Update::new(vec![1].into_iter(), 0));
|
|
||||||
|
|
||||||
// let q = quote! {
|
|
||||||
// #( #updates )*
|
|
||||||
// };
|
|
||||||
|
|
||||||
// panic!("{q}");
|
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
|
||||||
#( #updates )*
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in a new issue