Compare commits
1 commit
main
...
renovate/r
Author | SHA1 | Date | |
---|---|---|---|
d33dfca274 |
13 changed files with 659 additions and 704 deletions
|
@ -1,14 +1,14 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
members = ["ecs", "update_macros", "update_macro_base"]
|
members = ["ecs", "update_macros"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = { version = "1.0.86", features = ["backtrace"] }
|
anyhow = { version = "1.0.86", features = ["backtrace"] }
|
||||||
indexmap = { version = "2.9.0", features = ["rayon"] }
|
indexmap = { version = "2.9.0", features = ["rayon"] }
|
||||||
serde = { version = "1.0.203", features = ["derive"] }
|
serde = { version = "1.0.203", features = ["derive"] }
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
ron = "0.9.0"
|
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"
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub struct Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Commands {
|
impl Commands {
|
||||||
pub fn new(now: Duration) -> Self {
|
pub(crate) fn new(now: Duration) -> Self {
|
||||||
Self {
|
Self {
|
||||||
commands: Vec::new(),
|
commands: Vec::new(),
|
||||||
now,
|
now,
|
||||||
|
@ -72,7 +72,7 @@ impl Commands {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub 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) => {
|
CommandTypes::InsertEntity(entity_object) => {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
|
||||||
pub struct Events {
|
pub struct Events {
|
||||||
pub(crate) events: HashMap<
|
events: HashMap<
|
||||||
TypeId, // TypeId of Payload
|
TypeId, // TypeId of Payload
|
||||||
(
|
(
|
||||||
Vec<Box<dyn Any + Send + Sync>>, // Payload
|
Vec<Box<dyn Any + Send + Sync>>, // Payload
|
||||||
|
@ -51,6 +51,20 @@ impl Events {
|
||||||
.insert(TypeId::of::<T>(), (Vec::new(), Vec::new()));
|
.insert(TypeId::of::<T>(), (Vec::new(), Vec::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_reader<T: Any + Send + Sync, F>(&mut self, f: F)
|
||||||
|
where
|
||||||
|
F: Fn(&mut World, &T) -> anyhow::Result<()> + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
match self.events.get_mut(&TypeId::of::<T>()) {
|
||||||
|
Some((_, listener)) => listener.push(Arc::new(move |world, payload| {
|
||||||
|
let typed_payload: &T = payload.downcast_ref().unwrap();
|
||||||
|
|
||||||
|
f(world, typed_payload)
|
||||||
|
})),
|
||||||
|
None => panic!("register event type first!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_event<T: Any + Send + Sync>(&mut self, payload: T) {
|
pub fn write_event<T: Any + Send + Sync>(&mut self, payload: T) {
|
||||||
match self.events.get_mut(&TypeId::of::<T>()) {
|
match self.events.get_mut(&TypeId::of::<T>()) {
|
||||||
Some((payloads, _)) => payloads.push(Box::new(payload)),
|
Some((payloads, _)) => payloads.push(Box::new(payload)),
|
||||||
|
@ -79,10 +93,3 @@ impl Events {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventReader<P, T, R, Func, Filter>
|
|
||||||
where
|
|
||||||
P: Any + Send + Sync,
|
|
||||||
{
|
|
||||||
fn add_reader(&mut self, func: Func);
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,14 +10,14 @@ mod updates;
|
||||||
mod world;
|
mod world;
|
||||||
|
|
||||||
pub use crate::entity::{Entity, EntityComponentDisjointMut, EntityNotFoundError, EntityObject};
|
pub use crate::entity::{Entity, EntityComponentDisjointMut, EntityNotFoundError, EntityObject};
|
||||||
pub use crate::events::{EventReader, Events};
|
pub use crate::events::Events;
|
||||||
pub use crate::resources::Resources;
|
pub use crate::resources::Resources;
|
||||||
pub use crate::type_map::{
|
pub use crate::type_map::{
|
||||||
ComponentCreateInfo, ComponentDebug, ComponentNotFoundError, EntityComponent, TypeMap,
|
ComponentCreateInfo, ComponentDebug, ComponentNotFoundError, EntityComponent, TypeMap,
|
||||||
};
|
};
|
||||||
pub use crate::unsafe_component_store::UnsafeComponentStore;
|
pub use crate::unsafe_component_store::UnsafeComponentStore;
|
||||||
pub use crate::updates::*;
|
pub use crate::updates::*;
|
||||||
pub use crate::world::{AddSystem, World, WorldBuilder};
|
pub use crate::world::{World, WorldBuilder};
|
||||||
pub use commands::Commands;
|
pub use commands::Commands;
|
||||||
pub use get_disjoint_mut::GetDisjointMut;
|
pub use get_disjoint_mut::GetDisjointMut;
|
||||||
pub use update_macros::Resource;
|
pub use update_macros::Resource;
|
||||||
|
|
|
@ -74,14 +74,6 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, F: CheckFilter> Query<C, F> {
|
impl<C, F: CheckFilter> Query<C, F> {
|
||||||
pub fn new(entity: Entity, c: C) -> Self {
|
|
||||||
Self {
|
|
||||||
entity,
|
|
||||||
c,
|
|
||||||
filter: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn entity(&self) -> Entity {
|
pub fn entity(&self) -> Entity {
|
||||||
self.entity
|
self.entity
|
||||||
}
|
}
|
||||||
|
@ -300,4 +292,4 @@ impl_update_filter!(Nonuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w],
|
||||||
#[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, 10);
|
implement_updates!(5, 5);
|
||||||
|
|
|
@ -10,38 +10,28 @@ use utilities::prelude::{remove_life_time, remove_life_time_mut};
|
||||||
|
|
||||||
use crate::{entity_object_manager::EntityObjectManager, *};
|
use crate::{entity_object_manager::EntityObjectManager, *};
|
||||||
|
|
||||||
pub trait AddSystem<R, Func, W> {
|
|
||||||
fn add_system(&mut self, priority: u32, f: Func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WorldBuilder {
|
pub struct WorldBuilder {
|
||||||
pub(crate) updates: Updates,
|
pub(crate) updates: Updates,
|
||||||
pub events: Events,
|
pub events: Events,
|
||||||
pub resources: Resources,
|
pub resources: Resources,
|
||||||
pub(crate) systems: Vec<(
|
systems: Vec<(
|
||||||
u32,
|
u32,
|
||||||
Box<dyn Fn(&mut World, &mut Commands) -> Result<bool> + Send + Sync + 'static>,
|
Box<dyn Fn(&mut World) -> Result<bool> + Send + Sync + 'static>,
|
||||||
)>,
|
)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Func> AddSystem<(), Func, &mut World> for WorldBuilder
|
impl WorldBuilder {
|
||||||
|
pub fn add_system<F>(&mut self, priority: u32, f: F)
|
||||||
where
|
where
|
||||||
Func: Fn(&mut World) -> Result<bool> + Send + Sync + 'static,
|
F: Fn(&mut World) -> Result<bool> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn add_system(&mut self, priority: u32, func: Func) {
|
self.systems.push((priority, Box::new(f)));
|
||||||
self.systems.push((
|
|
||||||
priority,
|
|
||||||
Box::new(move |world: &mut World, _commands: &mut Commands| func(world)),
|
|
||||||
));
|
|
||||||
self.systems.sort_by_key(|(priority, _)| *priority);
|
self.systems.sort_by_key(|(priority, _)| *priority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorldBuilder {
|
impl WorldBuilder {
|
||||||
pub fn build(mut self) -> World {
|
pub fn build(self) -> World {
|
||||||
self.add_system(1000, World::process_events);
|
|
||||||
self.add_system(2000, World::process_updates);
|
|
||||||
|
|
||||||
World {
|
World {
|
||||||
updates: self.updates,
|
updates: self.updates,
|
||||||
events: self.events,
|
events: self.events,
|
||||||
|
@ -82,7 +72,7 @@ pub struct World {
|
||||||
|
|
||||||
start_time: Instant,
|
start_time: Instant,
|
||||||
|
|
||||||
systems: Vec<Box<dyn Fn(&mut World, &mut Commands) -> Result<bool> + Send + Sync + 'static>>,
|
systems: Vec<Box<dyn Fn(&mut World) -> Result<bool> + Send + Sync + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
|
@ -428,40 +418,29 @@ impl World {
|
||||||
let systems = std::mem::take(&mut self.systems);
|
let systems = std::mem::take(&mut self.systems);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let now = self.now();
|
// we need to take all events because of borrowing rules
|
||||||
|
let mut events = self.events.take_events();
|
||||||
|
events.fire_events(self)?;
|
||||||
|
|
||||||
for system in systems.iter() {
|
{
|
||||||
let mut commands = Commands::new(now);
|
// actually safe:
|
||||||
|
// - updates can't be altered on a running world
|
||||||
|
// - entity changes are processed afterwards
|
||||||
|
let w = unsafe { remove_life_time_mut(self) };
|
||||||
|
|
||||||
if !system(self, &mut commands)? {
|
self.updates.update(w)?;
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.apply_deferred(self)?;
|
self.commit_entity_changes()?;
|
||||||
|
|
||||||
|
for system in systems.iter() {
|
||||||
|
if !system(self)? {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset flag
|
// reset flag
|
||||||
self.had_entity_changes = false;
|
self.had_entity_changes = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_events(world: &mut World) -> Result<bool> {
|
|
||||||
// we need to take all events because of borrowing rules
|
|
||||||
let mut events = world.events.take_events();
|
|
||||||
events.fire_events(world)?;
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_updates(world: &mut World) -> Result<bool> {
|
|
||||||
// actually safe:
|
|
||||||
// - updates can't be altered on a running world
|
|
||||||
// - entity changes are processed afterwards
|
|
||||||
let w = unsafe { remove_life_time_mut(world) };
|
|
||||||
|
|
||||||
world.updates.update(w)?;
|
|
||||||
world.commit_entity_changes()?;
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "update_macro_base"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
syn = { workspace = true }
|
|
||||||
quote = { workspace = true }
|
|
||||||
proc-macro2 = { workspace = true }
|
|
|
@ -1,422 +0,0 @@
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
|
||||||
use quote::{ToTokens, format_ident, quote};
|
|
||||||
use syn::Ident;
|
|
||||||
|
|
||||||
pub struct Query {
|
|
||||||
components: Vec<Ident>,
|
|
||||||
filter: Ident,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Query {
|
|
||||||
fn new(components: impl Iterator<Item = Ident>, filter_id: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
components: components.collect(),
|
|
||||||
filter: format_ident!("Filter{filter_id}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dedup_checks(&self) -> TokenStream2 {
|
|
||||||
let components = &self.components;
|
|
||||||
let filter = &self.filter;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #filter::verify_dedup::<#components>(); )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::new(
|
|
||||||
#entity_ident,
|
|
||||||
unsafe { #component_name.as_mut() },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
let #query_ident = Query::new(
|
|
||||||
#entity_ident,
|
|
||||||
unsafe { ( #( #component_names.as_mut(), )* ) },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
query_ident,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn components(&self) -> &Vec<Ident> {
|
|
||||||
&self.components
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Update {
|
|
||||||
queries: Vec<Query>,
|
|
||||||
resources: Vec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Update {
|
|
||||||
pub const MIN_RESOURCE: usize = 0;
|
|
||||||
pub 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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, )* )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn filter_type_impls(&self) -> TokenStream2 {
|
|
||||||
let filter_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.filter())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #filter_types, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn filter_requirements(&self) -> TokenStream2 {
|
|
||||||
let filter_requirements = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.filter())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #filter_requirements: CheckFilter + 'static, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_types(&self) -> TokenStream2 {
|
|
||||||
let query_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.types())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
( #( #query_types, )* )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_type_impls(&self) -> TokenStream2 {
|
|
||||||
let query_types = self
|
|
||||||
.queries
|
|
||||||
.iter()
|
|
||||||
.map(|query| query.components())
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #query_types, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resource_types(&self) -> TokenStream2 {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
( #( #resource_types, )* )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resource_type_impls(&self) -> TokenStream2 {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #resource_types, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reource_requirement(&self) -> TokenStream2 {
|
|
||||||
let resource_types = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( #resource_types: ResourceTrait, )*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ResourceTokens {
|
|
||||||
pub resource_types: TokenStream2,
|
|
||||||
pub resource_type_impls: TokenStream2,
|
|
||||||
pub resources: TokenStream2,
|
|
||||||
pub resource_requirement: TokenStream2,
|
|
||||||
pub resource_store: TokenStream2,
|
|
||||||
pub resource_idents: Vec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryTokens<'a> {
|
|
||||||
pub filter_types: TokenStream2,
|
|
||||||
pub filter_type_impls: TokenStream2,
|
|
||||||
pub query_types: TokenStream2,
|
|
||||||
pub query_type_impls: TokenStream2,
|
|
||||||
pub queries: &'a [Query],
|
|
||||||
pub filter_requirements: TokenStream2,
|
|
||||||
pub component_requirements: TokenStream2,
|
|
||||||
pub query_count: usize,
|
|
||||||
pub verify_dedup: Vec<TokenStream2>,
|
|
||||||
pub check_entities: Vec<TokenStream2>,
|
|
||||||
pub component_stores: Vec<TokenStream2>,
|
|
||||||
pub query_structs: Vec<TokenStream2>,
|
|
||||||
pub query_idents: Vec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Update {
|
|
||||||
pub fn resourece_tokens(&self) -> ResourceTokens {
|
|
||||||
let resource_types = self.resource_types();
|
|
||||||
let resource_type_impls = self.resource_type_impls();
|
|
||||||
|
|
||||||
let resources = if self.resources.is_empty() {
|
|
||||||
quote! {}
|
|
||||||
} else {
|
|
||||||
let resources = &self.resources;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#( &mut #resources, )*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let resource_requirement = self.reource_requirement();
|
|
||||||
let (resource_store, resource_idents) = self.resource_store();
|
|
||||||
|
|
||||||
ResourceTokens {
|
|
||||||
resource_types,
|
|
||||||
resource_type_impls,
|
|
||||||
resources,
|
|
||||||
resource_requirement,
|
|
||||||
resource_store,
|
|
||||||
resource_idents,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_tokens(&self) -> QueryTokens<'_> {
|
|
||||||
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 queries = &self.queries;
|
|
||||||
|
|
||||||
let filter_requirements = self.filter_requirements();
|
|
||||||
let component_requirements = self.component_requirements();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryTokens {
|
|
||||||
filter_types,
|
|
||||||
filter_type_impls,
|
|
||||||
query_types,
|
|
||||||
query_type_impls,
|
|
||||||
queries,
|
|
||||||
filter_requirements,
|
|
||||||
component_requirements,
|
|
||||||
query_count,
|
|
||||||
verify_dedup,
|
|
||||||
check_entities,
|
|
||||||
component_stores,
|
|
||||||
query_structs,
|
|
||||||
query_idents,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,5 +11,3 @@ proc-macro = true
|
||||||
syn = { workspace = true }
|
syn = { workspace = true }
|
||||||
quote = { workspace = true }
|
quote = { workspace = true }
|
||||||
proc-macro2 = { workspace = true }
|
proc-macro2 = { workspace = true }
|
||||||
|
|
||||||
update_macro_base = { path = "../update_macro_base" }
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
|
mod pair_update;
|
||||||
|
mod single_update;
|
||||||
mod update;
|
mod update;
|
||||||
|
|
||||||
|
use pair_update::pair_update;
|
||||||
|
use single_update::single_update;
|
||||||
use update::update;
|
use update::update;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{
|
use syn::{
|
||||||
DeriveInput, LitInt, Result,
|
DeriveInput, Ident, LitInt, Result,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_macro_input,
|
parse_macro_input,
|
||||||
token::Comma,
|
token::Comma,
|
||||||
|
@ -36,6 +40,42 @@ pub fn implement_updates(input: TokenStream) -> TokenStream {
|
||||||
update(input.max_components, input.max_resources)
|
update(input.max_components, input.max_resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InputInfo {
|
||||||
|
macro_ident: Ident,
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for InputInfo {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let macro_ident = input.parse::<Ident>()?;
|
||||||
|
input.parse::<Comma>()?;
|
||||||
|
let start = input.parse::<LitInt>()?.base10_parse()?;
|
||||||
|
input.parse::<Comma>()?;
|
||||||
|
let end = input.parse::<LitInt>()?.base10_parse()?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
macro_ident,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn implement_pair_update(input: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(input as InputInfo);
|
||||||
|
|
||||||
|
pair_update(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn implement_single_update(input: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(input as InputInfo);
|
||||||
|
|
||||||
|
single_update(input)
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Resource)]
|
#[proc_macro_derive(Resource)]
|
||||||
pub fn derive_resource(input: TokenStream) -> TokenStream {
|
pub fn derive_resource(input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
89
update_macros/src/pair_update.rs
Normal file
89
update_macros/src/pair_update.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use syn::{Ident, LitInt};
|
||||||
|
|
||||||
|
use crate::InputInfo;
|
||||||
|
|
||||||
|
struct TupleType {
|
||||||
|
little: Ident,
|
||||||
|
big: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pair_update(input: InputInfo) -> TokenStream {
|
||||||
|
let mut generic_count = Vec::new();
|
||||||
|
|
||||||
|
for lhs in input.start..=input.end {
|
||||||
|
for rhs in input.start..=input.end {
|
||||||
|
generic_count.push((lhs, rhs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let generic_tuples: Vec<(Vec<TupleType>, Vec<TupleType>)> = generic_count
|
||||||
|
.iter()
|
||||||
|
.map(|(lhs_count, rhs_count)| {
|
||||||
|
let lhs = (input.start..(input.start + lhs_count))
|
||||||
|
.map(|i| TupleType {
|
||||||
|
little: format_ident!("l{}", i),
|
||||||
|
big: format_ident!("L{}", i),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let rhs = (input.start..(input.start + rhs_count))
|
||||||
|
.map(|i| TupleType {
|
||||||
|
little: format_ident!("r{}", i),
|
||||||
|
big: format_ident!("R{}", i),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(lhs, rhs)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let invocations: Vec<TokenStream2> = generic_tuples
|
||||||
|
.iter()
|
||||||
|
.map(|(lhs, rhs)| {
|
||||||
|
let lhs_expr = LitInt::new(&format!("{}", lhs.len()), Span::call_site());
|
||||||
|
let rhs_expr = LitInt::new(&format!("{}", rhs.len()), Span::call_site());
|
||||||
|
|
||||||
|
let lhs_args: Vec<TokenStream2> = lhs
|
||||||
|
.iter()
|
||||||
|
.map(|tuple| {
|
||||||
|
let little = &tuple.little;
|
||||||
|
let big = &tuple.big;
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
[#little: #big],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let rhs_args: Vec<TokenStream2> = rhs
|
||||||
|
.iter()
|
||||||
|
.map(|tuple| {
|
||||||
|
let little = &tuple.little;
|
||||||
|
let big = &tuple.big;
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
[#little: #big],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let macro_ident = &input.macro_ident;
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#macro_ident!(
|
||||||
|
#lhs_expr, (#(#lhs_args)*),
|
||||||
|
#rhs_expr, (#(#rhs_args)*)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
#(
|
||||||
|
#invocations
|
||||||
|
)*
|
||||||
|
})
|
||||||
|
}
|
70
update_macros/src/single_update.rs
Normal file
70
update_macros/src/single_update.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use syn::Ident;
|
||||||
|
|
||||||
|
use crate::InputInfo;
|
||||||
|
|
||||||
|
const MIN_RESOURCE: usize = 1;
|
||||||
|
|
||||||
|
pub fn single_update(input: InputInfo) -> TokenStream {
|
||||||
|
let mut generic_counts = Vec::new();
|
||||||
|
|
||||||
|
for components in input.start..=input.end {
|
||||||
|
for resources in MIN_RESOURCE..=input.end {
|
||||||
|
generic_counts.push((components, resources));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let generics: Vec<(Vec<Ident>, Vec<Ident>)> = generic_counts
|
||||||
|
.into_iter()
|
||||||
|
.map(|(component_count, resource_count)| {
|
||||||
|
let components = (input.start..(input.start + component_count))
|
||||||
|
.map(|i| format_ident!("t{}", i))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let resources = (MIN_RESOURCE..(MIN_RESOURCE + resource_count))
|
||||||
|
.map(|i| format_ident!("r{}", i))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(components, resources)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let resource_invocations: Vec<TokenStream2> = generics
|
||||||
|
.iter()
|
||||||
|
.map(|(components, resources)| {
|
||||||
|
let macro_ident = &input.macro_ident;
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#macro_ident!(#(#components,)* [#(#resources,)*]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let generate_inputs: Vec<Vec<Ident>> = (input.start..=input.end)
|
||||||
|
.map(|count| {
|
||||||
|
(input.start..(input.start + count))
|
||||||
|
.map(|i| format_ident!("t{}", i))
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let empty_resource_invocations: Vec<TokenStream2> = generate_inputs
|
||||||
|
.iter()
|
||||||
|
.map(|t| {
|
||||||
|
let macro_ident = &input.macro_ident;
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#macro_ident!(#(#t,)*);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
#(
|
||||||
|
#empty_resource_invocations
|
||||||
|
#resource_invocations
|
||||||
|
)*
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,108 +1,385 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::{ToTokens, format_ident, quote};
|
||||||
|
use syn::Ident;
|
||||||
|
|
||||||
use update_macro_base::*;
|
struct Query {
|
||||||
|
components: Vec<Ident>,
|
||||||
|
filter: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resource_only_events_and_systems(update: &Update) -> TokenStream2 {
|
impl Query {
|
||||||
let resource_tokens = update.resourece_tokens();
|
pub fn new(components: impl Iterator<Item = Ident>, filter_id: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
components: components.collect(),
|
||||||
|
filter: format_ident!("Filter{filter_id}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let resource_types = &resource_tokens.resource_types;
|
pub fn types(&self) -> TokenStream2 {
|
||||||
let resource_type_impls = &resource_tokens.resource_type_impls;
|
let component_list = self
|
||||||
let resources = &resource_tokens.resources;
|
.components
|
||||||
let resource_requirement = &resource_tokens.resource_requirement;
|
.iter()
|
||||||
let resource_store = &resource_tokens.resource_store;
|
.map(|c| quote! { #c })
|
||||||
let resource_idents = &resource_tokens.resource_idents;
|
.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! {
|
quote! {
|
||||||
impl<P, Func, #resource_type_impls> EventReader<P, (), #resource_types, Func, ()> for Events
|
#( #filter::verify_dedup::<#components>(); )*
|
||||||
where
|
|
||||||
Func: Fn(&P, &mut Commands, #resources ) -> Result<()> + Send + Sync + 'static,
|
|
||||||
#resource_requirement
|
|
||||||
P: std::any::Any + Send + Sync,
|
|
||||||
{
|
|
||||||
fn add_reader(&mut self, func: Func) {
|
|
||||||
match self.events.get_mut(&TypeId::of::<P>()) {
|
|
||||||
Some((_, listener)) => listener.push(std::sync::Arc::new(move |world, payload| {
|
|
||||||
let typed_payload: &P = payload.downcast_ref().unwrap();
|
|
||||||
let mut commands = Commands::new(world.now());
|
|
||||||
|
|
||||||
#resource_store
|
|
||||||
func(typed_payload, &mut commands, #( #resource_idents, )*)?;
|
|
||||||
|
|
||||||
commands.apply_deferred(world)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})),
|
|
||||||
None => panic!("register event type first!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Func, #resource_type_impls> AddSystem<#resource_types, Func, ()> for WorldBuilder
|
|
||||||
where
|
|
||||||
Func: Fn(&mut Commands, #resources ) -> Result<bool> + Send + Sync + 'static,
|
|
||||||
#resource_requirement
|
|
||||||
{
|
|
||||||
fn add_system(&mut self, priority: u32, func: Func) {
|
|
||||||
self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| {
|
|
||||||
#resource_store
|
|
||||||
func(commands, #( #resource_idents, )*)
|
|
||||||
})));
|
|
||||||
self.systems.sort_by_key(|(priority, _)| *priority);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Func, #resource_type_impls> AddSystem<#resource_types, Func, World> for WorldBuilder
|
pub fn check_entity(&self, index: usize) -> TokenStream2 {
|
||||||
where
|
let components = &self.components;
|
||||||
Func: Fn(&World, &mut Commands, #resources ) -> Result<bool> + Send + Sync + 'static,
|
let filter = &self.filter;
|
||||||
#resource_requirement
|
|
||||||
{
|
|
||||||
fn add_system(&mut self, priority: u32, func: Func) {
|
|
||||||
self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| {
|
|
||||||
let w = unsafe { utilities::unsafe_life_time::remove_life_time(world) };
|
|
||||||
#resource_store
|
|
||||||
func(w, commands, #( #resource_idents, )*)
|
|
||||||
})));
|
|
||||||
self.systems.sort_by_key(|(priority, _)| *priority);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn events_and_systems(update: &Update) -> TokenStream2 {
|
|
||||||
let query_tokens = update.query_tokens();
|
|
||||||
|
|
||||||
let filter_types = &query_tokens.filter_types;
|
|
||||||
let filter_type_impls = &query_tokens.filter_type_impls;
|
|
||||||
let query_types = &query_tokens.query_types;
|
|
||||||
let query_type_impls = &query_tokens.query_type_impls;
|
|
||||||
let queries = query_tokens.queries;
|
|
||||||
let filter_requirements = &query_tokens.filter_requirements;
|
|
||||||
let component_requirements = &query_tokens.component_requirements;
|
|
||||||
let query_count = query_tokens.query_count;
|
|
||||||
let verify_dedup = &query_tokens.verify_dedup;
|
|
||||||
let check_entities = &query_tokens.check_entities;
|
|
||||||
let component_stores = &query_tokens.component_stores;
|
|
||||||
let query_structs = &query_tokens.query_structs;
|
|
||||||
let query_idents = &query_tokens.query_idents;
|
|
||||||
|
|
||||||
let resource_tokens = update.resourece_tokens();
|
|
||||||
|
|
||||||
let resource_types = &resource_tokens.resource_types;
|
|
||||||
let resource_type_impls = &resource_tokens.resource_type_impls;
|
|
||||||
let resources = &resource_tokens.resources;
|
|
||||||
let resource_requirement = &resource_tokens.resource_requirement;
|
|
||||||
let resource_store = &resource_tokens.resource_store;
|
|
||||||
let resource_idents = &resource_tokens.resource_idents;
|
|
||||||
|
|
||||||
quote! {
|
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
|
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> CreateArchetype<#query_types, #resource_types, Func, #filter_types> for Archetype
|
||||||
where
|
where
|
||||||
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
#filter_requirements
|
#filter_requirements
|
||||||
#component_requirements
|
#component_requirements
|
||||||
#resource_requirement
|
#reource_requirement
|
||||||
{
|
{
|
||||||
fn create(f: Func) -> Self {
|
fn create(f: Func) -> Self {
|
||||||
#( #verify_dedup )*
|
#( #verify_dedup )*
|
||||||
|
@ -145,7 +422,7 @@ fn events_and_systems(update: &Update) -> TokenStream2 {
|
||||||
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
#filter_requirements
|
#filter_requirements
|
||||||
#component_requirements
|
#component_requirements
|
||||||
#resource_requirement
|
#reource_requirement
|
||||||
{
|
{
|
||||||
fn add_update(
|
fn add_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -161,7 +438,7 @@ fn events_and_systems(update: &Update) -> TokenStream2 {
|
||||||
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
|
||||||
#filter_requirements
|
#filter_requirements
|
||||||
#component_requirements
|
#component_requirements
|
||||||
#resource_requirement
|
#reource_requirement
|
||||||
{
|
{
|
||||||
fn add_update(
|
fn add_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -171,61 +448,8 @@ fn events_and_systems(update: &Update) -> TokenStream2 {
|
||||||
self.updates.add_update(priority, func)
|
self.updates.add_update(priority, func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
impl<P, Func, #filter_type_impls #query_type_impls #resource_type_impls> EventReader<P, #query_types, #resource_types, Func, #filter_types> for Events
|
.to_tokens(tokens);
|
||||||
where
|
|
||||||
Func: Fn(&P, &mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + 'static,
|
|
||||||
#filter_requirements
|
|
||||||
#component_requirements
|
|
||||||
#resource_requirement
|
|
||||||
P: std::any::Any + Send + Sync,
|
|
||||||
{
|
|
||||||
fn add_reader(&mut self, func: Func) {
|
|
||||||
#( #verify_dedup )*
|
|
||||||
|
|
||||||
match self.events.get_mut(&TypeId::of::<P>()) {
|
|
||||||
Some((_, listener)) => listener.push(std::sync::Arc::new(move |world, payload| {
|
|
||||||
let typed_payload: &P = payload.downcast_ref().unwrap();
|
|
||||||
let mut commands = Commands::new(world.now());
|
|
||||||
|
|
||||||
#resource_store
|
|
||||||
|
|
||||||
let mut complying_entities: Vec<Vec<&EntityObject>> = vec![Vec::new(); #query_count];
|
|
||||||
|
|
||||||
for entity in world.entities.values() {
|
|
||||||
let mut comply_queries = Vec::new();
|
|
||||||
|
|
||||||
#( #check_entities )*
|
|
||||||
|
|
||||||
if !comply_queries.is_empty() {
|
|
||||||
comply_queries
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|q| complying_entities[q].push(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 entities in complying_entities.into_iter().multi_cartesian_product() {
|
|
||||||
#( #component_stores )*
|
|
||||||
#( #query_structs )*
|
|
||||||
|
|
||||||
func(typed_payload, &mut commands, #( #query_idents, )* #( #resource_idents, )*)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.apply_deferred(world)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})),
|
|
||||||
None => panic!("register event type first!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,22 +484,10 @@ pub fn update(max_components: usize, max_resources: usize) -> TokenStream {
|
||||||
|
|
||||||
for query in queries.iter() {
|
for query in queries.iter() {
|
||||||
for resource_count in resources.iter() {
|
for resource_count in resources.iter() {
|
||||||
updates.push(events_and_systems(&Update::new(
|
updates.push(Update::new(query.iter().cloned(), *resource_count));
|
||||||
query.iter().cloned(),
|
|
||||||
*resource_count,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut events = Vec::new();
|
|
||||||
|
|
||||||
for resource_count in resources.iter() {
|
|
||||||
let q =
|
|
||||||
resource_only_events_and_systems(&Update::new(vec![1].into_iter(), *resource_count));
|
|
||||||
|
|
||||||
events.push(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
// updates.push(Update::new(vec![1].into_iter(), 0));
|
// updates.push(Update::new(vec![1].into_iter(), 0));
|
||||||
|
|
||||||
// let q = quote! {
|
// let q = quote! {
|
||||||
|
@ -286,6 +498,5 @@ pub fn update(max_components: usize, max_resources: usize) -> TokenStream {
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
#( #updates )*
|
#( #updates )*
|
||||||
#( #events )*
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue