From a073f8e5206bf77694d0cbbe11e284c69f908975 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Tue, 8 Apr 2025 17:58:14 +0200 Subject: [PATCH] Start query testing --- ecs/src/commands.rs | 38 +++++++--- ecs/src/lib.rs | 1 + ecs/src/resources.rs | 4 + ecs/src/update_testing.rs | 154 ++++++++++++++++++++++++++++++++++++++ ecs/src/updates.rs | 10 --- 5 files changed, 185 insertions(+), 22 deletions(-) create mode 100644 ecs/src/update_testing.rs diff --git a/ecs/src/commands.rs b/ecs/src/commands.rs index 854c63a..5c20f34 100644 --- a/ecs/src/commands.rs +++ b/ecs/src/commands.rs @@ -1,19 +1,21 @@ use anyhow::Result; use std::any::{Any, TypeId}; -use crate::{world::ComponentChange, *}; +use crate::{resources::Resource, world::ComponentChange, *}; -enum CommandsTypes { +enum CommandTypes { InsertEntity(EntityObject), RemoveEntity(Entity), UpdateEntity(Entity, ComponentChange), Event(TypeId, Box), + + InsertResource(TypeId, Box), } #[derive(Default)] pub struct Commands { - commands: Vec, + commands: Vec, } impl Commands { @@ -21,24 +23,24 @@ impl Commands { let entity = entity_object.as_entity(); self.commands - .push(CommandsTypes::InsertEntity(entity_object)); + .push(CommandTypes::InsertEntity(entity_object)); entity } pub fn remove_entity(&mut self, entity: Entity) { - self.commands.push(CommandsTypes::RemoveEntity(entity)); + self.commands.push(CommandTypes::RemoveEntity(entity)); } pub fn insert_component(&mut self, entity: Entity, component: T) { - self.commands.push(CommandsTypes::UpdateEntity( + self.commands.push(CommandTypes::UpdateEntity( entity, ComponentChange::Added(TypeId::of::(), Box::new(component)), )); } pub fn remove_component(&mut self, entity: Entity) { - self.commands.push(CommandsTypes::UpdateEntity( + self.commands.push(CommandTypes::UpdateEntity( entity, ComponentChange::Removed(TypeId::of::()), )); @@ -46,20 +48,32 @@ impl Commands { pub fn write_event(&mut self, payload: T) { self.commands - .push(CommandsTypes::Event(TypeId::of::(), Box::new(payload))); + .push(CommandTypes::Event(TypeId::of::(), Box::new(payload))); + } + + pub fn insert_resource(&mut self, resource: T) { + self.commands.push(CommandTypes::InsertResource( + TypeId::of::(), + Box::new(resource), + )); } pub(crate) fn apply_deferred(self, world: &mut World) -> Result<()> { for command in self.commands { match command { - CommandsTypes::InsertEntity(entity_object) => { + CommandTypes::InsertEntity(entity_object) => { world.add_entity(entity_object)?; } - CommandsTypes::RemoveEntity(entity) => world.remove_entity(entity), - CommandsTypes::UpdateEntity(entity, component_change) => { + CommandTypes::RemoveEntity(entity) => world.remove_entity(entity), + CommandTypes::UpdateEntity(entity, component_change) => { world.component_change(entity, component_change) } - CommandsTypes::Event(type_id, any) => world.events.write_payload(type_id, any), + CommandTypes::Event(type_id, payload) => { + world.events.write_payload(type_id, payload) + } + CommandTypes::InsertResource(type_id, resource) => { + world.resources.insert_resource(type_id, resource) + } } } diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index b2ec2b1..c873530 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -6,6 +6,7 @@ pub mod get_disjoint_mut; pub mod resources; mod type_map; mod unsafe_component_store; +mod update_testing; mod updates; mod world; diff --git a/ecs/src/resources.rs b/ecs/src/resources.rs index 4b1c62c..0a9eef6 100644 --- a/ecs/src/resources.rs +++ b/ecs/src/resources.rs @@ -38,6 +38,10 @@ impl Resources { .flatten() } + pub(crate) fn insert_resource(&mut self, type_id: TypeId, resource: Box) { + self.map.insert(type_id, resource); + } + pub fn insert_if_not_exists(&mut self) { if !self.contains::() { self.insert(T::default()); diff --git a/ecs/src/update_testing.rs b/ecs/src/update_testing.rs new file mode 100644 index 0000000..36ff4ad --- /dev/null +++ b/ecs/src/update_testing.rs @@ -0,0 +1,154 @@ +#![allow(unused)] + +use anyhow::Result; +use std::marker::PhantomData; +use std::{ops::Deref, ops::DerefMut}; + +use crate::*; + +#[derive(Copy, Clone)] +pub struct Query +where + F: StaticCheckFilter, +{ + entity: Entity, + c: C, + filter: PhantomData, +} + +impl Query { + pub fn entity(&self) -> Entity { + self.entity + } +} + +impl Deref for Query { + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.c + } +} + +impl DerefMut for Query { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.c + } +} + +trait CreateQueryArchetype { + fn create(f: Func) -> Self; +} + +pub trait StaticCheckFilter: Send + Sync + Default + Clone { + fn check(entity: &EntityObject) -> bool; + fn verify_dedup(); +} + +impl StaticCheckFilter for EmptyFilter { + fn check(_entity: &EntityObject) -> bool { + true + } + + fn verify_dedup() {} +} + +pub struct QueryArchetype { + check_entity: Box bool + Send + Sync>, + create_callback: Box< + dyn Fn( + &EntityObject, + ) + -> Result Result<()> + Send + Sync>> + + Send + + Sync, + >, + + entities: Vec Result<()> + Send + Sync>>, +} + +macro_rules! impl_query_singleton_update { + ( $($var:ident $(,)?)+ ) => { + impl CreateQueryArchetype<( $( $var, )+ ), (), Func, Filter> for QueryArchetype + where + Func: Fn(&mut Commands, Query<( $( &mut $var, )+ ), Filter>) -> Result<()> + Send + Sync + Clone + 'static, + Filter: StaticCheckFilter, + $( + $var: EntityComponent + ComponentDebug, + )+ + { + paste::item! { + fn create(f: Func) -> 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 e = entity.as_entity(); + let f = f.clone(); + + Ok(Box::new(move |commands, _world| { + let q = Query { + entity: e, + c: unsafe { ($([< $var:lower >].as_mut(),)+) }, + filter: PhantomData, + }; + + f(commands, q) + })) + }), + + entities: Vec::new(), + } + } + } + } + }; +} + +impl_query_singleton_update!(R); + +struct T {} + +impl EntityComponent for T { + fn name(&self) -> &str { + Self::debug_name() + } +} + +impl ComponentDebug for T { + fn debug_name() -> &'static str { + "T" + } +} + +fn system(_commands: &mut Commands, mut _query: Query<&mut T>) -> Result<()> { + Ok(()) +} + +fn test() { + // let q = QueryArchetype::create(system); +} diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs index 8385a13..e07bd79 100644 --- a/ecs/src/updates.rs +++ b/ecs/src/updates.rs @@ -3,7 +3,6 @@ use std::any::TypeId; use std::collections::HashMap; -use std::marker::PhantomData; #[cfg(feature = "timings")] use std::time::Instant; @@ -418,15 +417,6 @@ macro_rules! impl_update_filter { }; } -pub struct Query -where - F: CheckFilter, -{ - pub components: T, - - d: PhantomData, -} - pub trait AddUpdates { fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>; }