From f646c11d214342e167479b541cf90389e9abac8b Mon Sep 17 00:00:00 2001 From: hodasemi Date: Tue, 4 Mar 2025 18:34:44 +0100 Subject: [PATCH] Move ecs into new repo --- Cargo.toml | 3 +- context/Cargo.toml | 2 +- ecs/Cargo.toml | 19 - ecs/src/entity.rs | 313 ---------- ecs/src/entity_object_manager.rs | 19 - ecs/src/events.rs | 88 --- ecs/src/lib.rs | 18 - ecs/src/resources.rs | 178 ------ ecs/src/type_map.rs | 332 ---------- ecs/src/unsafe_component_store.rs | 67 -- ecs/src/updates.rs | 675 --------------------- ecs/src/world.rs | 362 ----------- engine/Cargo.toml | 2 +- engine/src/engine/engine.rs | 2 +- engine/src/engine/engine_event_handling.rs | 14 +- examples/simple_window/Cargo.toml | 2 +- presentation/Cargo.toml | 2 +- scene_update_macros/Cargo.toml | 13 - scene_update_macros/src/lib.rs | 117 ---- skybox/Cargo.toml | 2 +- 20 files changed, 14 insertions(+), 2216 deletions(-) delete mode 100644 ecs/Cargo.toml delete mode 100644 ecs/src/entity.rs delete mode 100644 ecs/src/entity_object_manager.rs delete mode 100644 ecs/src/events.rs delete mode 100644 ecs/src/lib.rs delete mode 100644 ecs/src/resources.rs delete mode 100644 ecs/src/type_map.rs delete mode 100644 ecs/src/unsafe_component_store.rs delete mode 100644 ecs/src/updates.rs delete mode 100644 ecs/src/world.rs delete mode 100644 scene_update_macros/Cargo.toml delete mode 100644 scene_update_macros/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 57c14de..81aedc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ members = [ "asset", "context", "controllable_thread", - "ecs", "engine", "entity_manager", "examples/simple_window", @@ -18,7 +17,6 @@ members = [ "presentation", "promise", "ring_buffer", - "scene_update_macros", "skybox", "transaction_derive", ] @@ -65,6 +63,7 @@ assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } audio = { git = "https://gavania.de/hodasemi/audio.git" } library_loader = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } ui = { git = "https://gavania.de/hodasemi/ui.git" } +ecs = { git = "https://gavania.de/hodasemi/ecs.git" } [profile.release-lto] inherits = "release" diff --git a/context/Cargo.toml b/context/Cargo.toml index 435be07..57e190d 100644 --- a/context/Cargo.toml +++ b/context/Cargo.toml @@ -7,9 +7,9 @@ edition = "2024" [dependencies] audio = { workspace = true, optional = true } anyhow = { workspace = true } +ecs = { workspace = true } presentation = { path = "../presentation" } -ecs = { path = "../ecs" } [target.'cfg(target_os = "linux")'.dependencies] shared_library = { workspace = true } diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml deleted file mode 100644 index 78870a1..0000000 --- a/ecs/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "ecs" -version = "0.1.0" -authors = ["hodasemi "] -edition = "2024" - -[dependencies] -anyhow.workspace = true -destructure_traitobject.workspace = true -indexmap.workspace = true -serde = { workspace = true, features = ["derive"] } -paste.workspace = true -ron.workspace = true -utilities.workspace = true - -scene_update_macros = { path = "../scene_update_macros" } - -[features] -timings = [] diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs deleted file mode 100644 index fdfdc35..0000000 --- a/ecs/src/entity.rs +++ /dev/null @@ -1,313 +0,0 @@ -use core::fmt; -use std::any::TypeId; -use std::collections::HashSet; -use std::{num::ParseIntError, str::FromStr}; - -use anyhow::Result; -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; - -use crate::{ComponentDebug, ComponentNotFoundError, EntityComponent, MultiMut, TypeMap}; - -#[derive(Debug)] -pub struct EntityNotFoundError { - entity: Entity, -} - -impl EntityNotFoundError { - pub(crate) fn new(entity: Entity) -> Self { - Self { entity } - } -} - -impl std::fmt::Display for EntityNotFoundError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Entity (ID: {}) not found!", self.entity) - } -} - -impl std::error::Error for EntityNotFoundError {} - -#[derive(Default)] -pub struct ActivationState { - activated: bool, -} - -impl ActivationState { - pub fn is_active(&self) -> bool { - self.activated - } - - pub(crate) fn apply_change(&mut self) { - self.activated = !self.activated; - } -} - -pub struct EntityObject { - #[cfg(debug_assertions)] - pub debug_name: Option, - - // gltf file name - pub gltf_file: Option, - - // activation state of Entity - pub(crate) activation_state: ActivationState, - - // program local ID - pub entity_id: u32, - - // component map - pub components: TypeMap, - - #[cfg(debug_assertions)] - component_names: Vec, -} - -unsafe impl Send for EntityObject {} -unsafe impl Sync for EntityObject {} - -impl EntityObject { - pub(crate) fn new(id: u32) -> Self { - Self { - #[cfg(debug_assertions)] - debug_name: None, - - gltf_file: None, - - activation_state: ActivationState::default(), - - entity_id: id, - - components: TypeMap::default(), - - #[cfg(debug_assertions)] - component_names: Vec::new(), - } - } - - pub fn gltf_file(&self) -> Option<&String> { - self.gltf_file.as_ref() - } - - pub fn multi_mut(&mut self) -> MultiMut<'_> { - self.components.multi_mut() - } - - pub fn insert_component( - &mut self, - component: T, - ) -> Option { - assert!( - !self.activation_state.is_active(), - "inserting components while the entity is activated is not allowed" - ); - - #[cfg(debug_assertions)] - { - let name = component.name().to_string(); - - if !self.component_names.contains(&name) { - self.component_names.push(name); - } - } - - self.components.insert(component) - } - - pub(crate) fn insert_component_by_id( - &mut self, - type_id: TypeId, - component: Box, - ) -> Option> { - assert!( - !self.activation_state.is_active(), - "inserting components while the entity is activated is not allowed" - ); - - #[cfg(debug_assertions)] - { - let name = component.name().to_string(); - - if !self.component_names.contains(&name) { - self.component_names.push(name); - } - } - - self.components.insert_type(type_id, component) - } - - pub fn remove_component(&mut self) -> Option { - assert!( - !self.activation_state.is_active(), - "removing components while the entity is activated is not allowed" - ); - - let t: Option = self.components.remove(); - - #[cfg(debug_assertions)] - if let Some(t) = &t { - if let Some(index) = self - .component_names - .iter() - .position(|name| name == t.name()) - { - self.component_names.remove(index); - } - } - - t - } - - pub(crate) fn remove_component_by_id( - &mut self, - type_id: TypeId, - ) -> Option> { - assert!( - !self.activation_state.is_active(), - "removing components while the entity is activated is not allowed" - ); - - let t = self.components.remove_by_type_id(&type_id); - - #[cfg(debug_assertions)] - if let Some(t) = &t { - if let Some(index) = self - .component_names - .iter() - .position(|name| name == t.name()) - { - self.component_names.remove(index); - } - } - - t - } - - #[cfg(debug_assertions)] - pub fn component_names(&self) -> &[String] { - &self.component_names - } - - pub fn get_component( - &self, - ) -> std::result::Result<&T, ComponentNotFoundError> { - self.components.get() - } - - pub fn get_component_mut( - &mut self, - ) -> std::result::Result<&mut T, ComponentNotFoundError> { - self.components.get_mut() - } - - pub fn contains_component(&self) -> bool { - self.components.contains::() - } - - pub fn is_activated(&self) -> bool { - self.activation_state.is_active() - } - - pub fn as_entity(&self) -> Entity { - Entity { id: self.entity_id } - } - - pub(crate) fn clone_without_components(&self, id: u32) -> EntityObject { - EntityObject { - #[cfg(debug_assertions)] - debug_name: self.debug_name.clone(), - - // gltf file name - gltf_file: self.gltf_file.clone(), - - activation_state: Default::default(), - - entity_id: id, - - // component map - components: TypeMap::default(), - - #[cfg(debug_assertions)] - component_names: Vec::new(), - } - } - - pub fn clone_component_from( - &mut self, - other: &Self, - ) -> Result<()> { - let component = other.get_component::()?; - self.insert_component(component.clone()); - - Ok(()) - } -} - -#[allow(clippy::derive_hash_xor_eq)] -#[derive(Debug, Clone, Copy, Hash, Eq, Serialize, Deserialize)] -pub struct Entity { - pub(crate) id: u32, -} - -impl PartialEq for Entity { - fn eq(&self, entity: &EntityObject) -> bool { - self.id == entity.entity_id - } -} - -impl PartialEq for Entity { - fn eq(&self, entity: &Entity) -> bool { - self.id == entity.id - } -} - -impl fmt::Display for Entity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.id) - } -} - -impl FromStr for Entity { - type Err = ParseIntError; - - fn from_str(s: &str) -> std::result::Result { - Ok(Self { id: s.parse()? }) - } -} - -pub struct EntityMultiMut<'a> { - entities: &'a mut IndexMap, - buffer: HashSet, -} - -impl<'a> EntityMultiMut<'a> { - pub(crate) fn new(entities: &'a mut IndexMap) -> Self { - Self { - entities, - buffer: HashSet::new(), - } - } - - pub fn get( - &mut self, - entity: Entity, - ) -> std::result::Result<&'a mut EntityObject, EntityNotFoundError> { - match self.entities.get_mut(&entity) { - Some(v) => { - let ptr = v as *mut EntityObject; - - assert!( - self.buffer.get(&entity).is_none(), - "Entity ({}) already borrowed", - entity.id - ); - self.buffer.insert(entity); - - let e: Option<&'a mut EntityObject> = Some(unsafe { &mut *ptr }); - - e.ok_or_else(|| EntityNotFoundError::new(entity)) - } - None => Err(EntityNotFoundError::new(entity)), - } - } -} diff --git a/ecs/src/entity_object_manager.rs b/ecs/src/entity_object_manager.rs deleted file mode 100644 index e16afcd..0000000 --- a/ecs/src/entity_object_manager.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::EntityObject; - -#[derive(Default)] -pub struct EntityObjectManager { - current_entity_id: u32, -} - -impl EntityObjectManager { - pub(crate) fn fetch_add_entity_id(&mut self) -> u32 { - let id = self.current_entity_id; - self.current_entity_id += 1; - - id - } - - pub(crate) fn create_entity(&mut self) -> EntityObject { - EntityObject::new(self.fetch_add_entity_id()) - } -} diff --git a/ecs/src/events.rs b/ecs/src/events.rs deleted file mode 100644 index 71abc73..0000000 --- a/ecs/src/events.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::{ - any::{Any, TypeId}, - collections::HashMap, - ops::DerefMut, - sync::Arc, -}; - -use crate::World; - -pub struct Events { - events: HashMap< - TypeId, // TypeId of Payload - ( - Vec>, // Payload - Vec anyhow::Result<()> + Send + Sync>>, // Listener on Payload - ), - >, -} - -impl Default for Events { - fn default() -> Self { - Self { - events: HashMap::new(), - } - } -} - -impl Events { - pub(crate) fn take_events(&mut self) -> Self { - Self { - events: self - .events - .iter_mut() - .filter_map(|(type_id, (payload, listener))| { - (!payload.is_empty()) - .then(|| (*type_id, (std::mem::take(payload), listener.clone()))) - }) - .collect(), - } - } - - pub fn clear(&mut self) { - for (payloads, listener) in self.events.values_mut() { - payloads.clear(); - listener.clear(); - } - } - - pub fn register_event(&mut self) { - self.events - .insert(TypeId::of::(), (Vec::new(), Vec::new())); - } - - pub fn add_reader(&mut self, f: F) - where - F: Fn(&mut World, &T) -> anyhow::Result<()> + Send + Sync + 'static, - { - match self.events.get_mut(&TypeId::of::()) { - 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(&mut self, payload: T) { - match self.events.get_mut(&TypeId::of::()) { - Some((payloads, _)) => payloads.push(Box::new(payload)), - None => panic!("register event type first!"), - } - } - - pub(crate) fn fire_events(&mut self, world: &mut World) -> anyhow::Result<()> { - for (payloads, listeners) in self.events.values_mut() { - for payload in payloads.iter_mut() { - for listener in listeners.iter_mut() { - (listener)(world, payload.deref_mut())?; - } - } - - payloads.clear(); - } - - Ok(()) - } -} diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs deleted file mode 100644 index b74be15..0000000 --- a/ecs/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -mod entity; -mod entity_object_manager; -mod events; -mod resources; -mod type_map; -mod unsafe_component_store; -mod updates; -mod world; - -pub use crate::entity::{Entity, EntityMultiMut, EntityNotFoundError, EntityObject}; -pub use crate::events::Events; -pub use crate::resources::{ResourceMultiMut, Resources}; -pub use crate::type_map::{ - ComponentCreateInfo, ComponentDebug, ComponentNotFoundError, EntityComponent, MultiMut, TypeMap, -}; -pub use crate::unsafe_component_store::UnsafeComponentStore; -pub use crate::updates::*; -pub use crate::world::{World, WorldBuilder}; diff --git a/ecs/src/resources.rs b/ecs/src/resources.rs deleted file mode 100644 index 44fbd15..0000000 --- a/ecs/src/resources.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::{ - any::{Any, TypeId}, - collections::HashMap, - mem::transmute, -}; - -use utilities::prelude::{remove_life_time, remove_life_time_mut}; - -type Untyped = dyn Any + Send + Sync; - -#[derive(Default)] -pub struct Resources { - map: HashMap>, -} - -impl Resources { - pub fn insert(&mut self, value: T) -> Option { - self.map - .insert(TypeId::of::(), Box::new(value)) - .map(|any| *Self::downcast_unchecked(any)) - } - - pub fn insert_if_not_exists(&mut self) { - if !self.contains::() { - self.insert(T::default()); - } - } - - pub fn remove(&mut self) -> Option { - self.map - .remove(&TypeId::of::()) - .map(|any| *Self::downcast_unchecked(any)) - } - - pub fn get(&self) -> &T { - self.get_opt::().unwrap() - } - - pub fn get_by_type_id(&self, type_id: TypeId) -> &T { - self.get_opt_by_type_id(type_id).unwrap() - } - - pub fn get_unchecked<'a, T: Any + Send + Sync>(&self) -> &'a T { - unsafe { remove_life_time(self.get::()) } - } - - pub fn get_opt(&self) -> Option<&T> { - self.get_opt_by_type_id(TypeId::of::()) - } - - pub fn get_opt_by_type_id(&self, type_id: TypeId) -> Option<&T> { - debug_assert_eq!(type_id, TypeId::of::()); - - self.map - .get(&type_id) - .map(|any| Self::downcast_ref_unchecked(any)) - } - - pub fn get_mut(&mut self) -> &mut T { - self.get_mut_opt::().unwrap() - } - - pub fn get_mut_by_type_id(&mut self, type_id: TypeId) -> &mut T { - self.get_mut_opt_by_type_id(type_id).unwrap() - } - - pub fn get_mut_by_type_id_untyped(&mut self, type_id: TypeId) -> &mut Untyped { - self.get_mut_opt_by_type_id_untyped(type_id).unwrap() - } - - pub fn get_mut_unchecked<'a, T: Any + Send + Sync>(&mut self) -> &'a mut T { - unsafe { remove_life_time_mut(self.get_mut::()) } - } - - pub fn get_mut_opt(&mut self) -> Option<&mut T> { - self.get_mut_opt_by_type_id(TypeId::of::()) - } - - pub fn get_mut_opt_by_type_id( - &mut self, - type_id: TypeId, - ) -> Option<&mut T> { - debug_assert_eq!(type_id, TypeId::of::()); - - self.map - .get_mut(&type_id) - .map(|any| Self::downcast_mut_unchecked(any)) - } - - pub fn get_mut_opt_by_type_id_untyped(&mut self, type_id: TypeId) -> Option<&mut Untyped> { - self.map.get_mut(&type_id).map(|any| any.as_mut()) - } - - pub fn multi_mut(&mut self) -> ResourceMultiMut<'_> { - ResourceMultiMut::new(&mut self.map) - } - - pub fn contains(&self) -> bool { - self.map.contains_key(&TypeId::of::()) - } -} - -// helper -impl Resources { - fn downcast_unchecked(boxed: Box) -> Box { - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) } - } - - fn downcast_ref_unchecked(boxed_ref: &Box) -> &T { - unsafe { - let ptr_to_ptr: *const *const T = - transmute(destructure_traitobject::data(boxed_ref as *const _)); - - &**ptr_to_ptr - } - } - - fn downcast_mut_unchecked(boxed_ref: &mut Box) -> &mut T { - unsafe { - let ptr_to_ptr: *mut *mut T = - transmute(destructure_traitobject::data(boxed_ref as *mut _)); - - &mut **ptr_to_ptr - } - } -} - -/// Allows mutable access to multiple components at once -pub struct ResourceMultiMut<'a> { - map: &'a mut HashMap>, - buffer: Vec<*mut Box>, -} - -impl<'a> ResourceMultiMut<'a> { - fn new(map: &'a mut HashMap>) -> Self { - ResourceMultiMut { - map, - buffer: Vec::new(), - } - } - - /// Returns requested type on success - pub fn get(&mut self) -> &'a mut T { - self.get_by_type_id(&TypeId::of::()) - .map(|component| Resources::downcast_mut_unchecked(component)) - .unwrap() - } - - /// Returns requested type behind this type id on success - pub fn get_by_type_id( - &mut self, - type_id: &TypeId, - ) -> Option<&'a mut Box> { - self.map.get_mut(type_id).map(|v| { - let ptr = v as *mut _; - - match self.buffer.iter().find(|v| **v == ptr) { - Some(_) => { - panic!("This key has already been borrowed!"); - } - None => { - self.buffer.push(ptr); - } - } - - let t: Option<&'a mut Box> = unsafe { transmute(ptr) }; - - t.unwrap() - }) - } - - /// # Safety - /// - /// use this only when there are no references left - pub unsafe fn clear_all_usages(&mut self) { - self.buffer.clear(); - } -} diff --git a/ecs/src/type_map.rs b/ecs/src/type_map.rs deleted file mode 100644 index 3dfb1a1..0000000 --- a/ecs/src/type_map.rs +++ /dev/null @@ -1,332 +0,0 @@ -use std::mem::transmute; -use std::{ - any::{Any, TypeId}, - collections::{ - HashMap, - hash_map::{Iter, IterMut}, - }, - fmt::Display, -}; - -use anyhow::Result; -use destructure_traitobject; -use serde::{Deserialize, Serialize}; - -use crate::World; - -pub trait EntityComponent: Any + Send + Sync { - fn enable(&mut self, _world: &mut World) -> Result<()> { - Ok(()) - } - - fn disable(&mut self, _world: &mut World) -> Result<()> { - Ok(()) - } - - fn name(&self) -> &str; -} - -pub trait ComponentDebug { - fn debug_name() -> &'static str; -} - -pub trait ComponentCreateInfo<'de>: Serialize + Deserialize<'de> { - fn to_string(&self) -> Result { - Ok(ron::to_string(self)?) - } - - fn from_str(s: &'de str) -> Option { - match ron::from_str(s) { - Ok(t) => Some(t), - Err(err) => { - println!("{:?}", err); - - None - } - } - } -} - -pub struct TypeMap { - map: HashMap>, -} - -impl Default for TypeMap { - fn default() -> Self { - Self { - map: HashMap::new(), - } - } -} - -impl TypeMap { - pub fn insert(&mut self, value: T) -> Option { - self.map - .insert(TypeId::of::(), Box::new(value)) - .map(|any| *Self::downcast_unchecked(any)) - } - - pub fn insert_type( - &mut self, - type_id: TypeId, - component: Box, - ) -> Option> { - self.map.insert(type_id, component) - } - - pub fn remove(&mut self) -> Option { - self.remove_by_type_id(&TypeId::of::()) - .map(|any| *Self::downcast_unchecked(any)) - } - - pub fn remove_by_type_id(&mut self, type_id: &TypeId) -> Option> { - self.map.remove(type_id) - } - - pub fn get( - &self, - ) -> std::result::Result<&T, ComponentNotFoundError> { - self.map - .get(&TypeId::of::()) - .map(|any| Self::downcast_ref_unchecked(any)) - .ok_or_else(ComponentNotFoundError::component::) - } - - pub fn get_by_type_id( - &self, - type_id: &TypeId, - ) -> std::result::Result<&Box, ComponentNotFoundError> { - self.map - .get(type_id) - .ok_or_else(|| ComponentNotFoundError::type_id(*type_id)) - } - - pub fn get_mut( - &mut self, - ) -> std::result::Result<&mut T, ComponentNotFoundError> { - self.map - .get_mut(&TypeId::of::()) - .map(|any| Self::downcast_mut_unchecked(any)) - .ok_or_else(ComponentNotFoundError::component::) - } - - pub fn get_mut_by_type_id( - &mut self, - type_id: &TypeId, - ) -> std::result::Result<&mut Box, ComponentNotFoundError> { - self.map - .get_mut(type_id) - .ok_or_else(|| ComponentNotFoundError::type_id(*type_id)) - } - - pub fn contains(&self) -> bool { - self.contains_type_id(&TypeId::of::()) - } - - pub fn contains_type_id(&self, type_id: &TypeId) -> bool { - self.map.contains_key(type_id) - } - - pub fn multi_mut(&mut self) -> MultiMut<'_> { - MultiMut::new(&mut self.map) - } - - pub fn iter(&self) -> Iter<'_, TypeId, Box> { - self.map.iter() - } - - pub fn iter_mut(&mut self) -> IterMut<'_, TypeId, Box> { - self.map.iter_mut() - } - - fn downcast_unchecked(boxed: Box) -> Box { - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) } - } - - pub fn downcast_ref_unchecked(boxed_ref: &Box) -> &T { - unsafe { - let ptr_to_ptr: *const *const T = - transmute(destructure_traitobject::data(boxed_ref as *const _)); - - &**ptr_to_ptr - } - } - - pub fn downcast_mut_unchecked( - boxed_ref: &mut Box, - ) -> &mut T { - unsafe { - let ptr_to_ptr: *mut *mut T = - transmute(destructure_traitobject::data(boxed_ref as *mut _)); - - &mut **ptr_to_ptr - } - } -} - -/// Allows mutable access to multiple components at once -pub struct MultiMut<'a> { - map: &'a mut HashMap>, - buffer: Vec<*mut Box>, -} - -impl<'a> MultiMut<'a> { - fn new(map: &'a mut HashMap>) -> Self { - MultiMut { - map, - buffer: Vec::new(), - } - } - - /// Returns requested type on success - pub fn get( - &mut self, - ) -> std::result::Result<&'a mut T, ComponentNotFoundError> { - self.get_by_type_id(&TypeId::of::()) - .map(|component| TypeMap::downcast_mut_unchecked(component)) - .map_err(|_| ComponentNotFoundError::component::()) - } - - /// Returns requested type behind this type id on success - pub fn get_by_type_id( - &mut self, - type_id: &TypeId, - ) -> std::result::Result<&'a mut Box, ComponentNotFoundError> { - match self.map.get_mut(type_id) { - Some(v) => { - let ptr = v as *mut _; - - match self.buffer.iter().find(|v| **v == ptr) { - Some(_) => { - panic!("This key has already been borrowed!"); - } - None => { - self.buffer.push(ptr); - } - } - - let t: Option<&'a mut Box> = unsafe { transmute(ptr) }; - - t.ok_or_else(|| ComponentNotFoundError::type_id(*type_id)) - } - None => Err(ComponentNotFoundError::type_id(*type_id)), - } - } - - /// # Safety - /// - /// use this only when there are no references left - pub unsafe fn clear_all_usages(&mut self) { - self.buffer.clear(); - } -} - -#[derive(Debug)] -pub enum ComponentRequestType { - TypeId(TypeId), - ComponentName(&'static str), -} - -#[derive(Debug)] -pub struct ComponentNotFoundError { - pub request_type: ComponentRequestType, -} - -impl ComponentNotFoundError { - fn type_id(type_id: TypeId) -> Self { - Self { - request_type: ComponentRequestType::TypeId(type_id), - } - } - - fn component() -> Self { - Self { - request_type: ComponentRequestType::ComponentName(T::debug_name()), - } - } -} - -impl Display for ComponentNotFoundError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Entity Component ({:?}) not found!", self.request_type) - } -} - -impl std::error::Error for ComponentNotFoundError {} - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -struct Test { - x: u32, - y: u32, - z: u32, -} - -impl EntityComponent for Test { - fn name(&self) -> &str { - "Test" - } -} - -impl ComponentDebug for Test { - fn debug_name() -> &'static str { - "Test" - } -} - -impl PartialEq for Test { - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y && self.z == other.z - } -} - -#[test] -fn verify_multi_mut() { - let mut map = TypeMap::default(); - - map.insert(Test::default()); - - // test it multiple times, just for sanity - for _ in 0..10 { - let test = map.get::().unwrap().clone(); - - let mut multi_mut = map.multi_mut(); - - let multi_mut_test = multi_mut.get::().unwrap().clone(); - - assert_eq!(test, multi_mut_test); - } -} - -#[test] -fn verify_insert() { - let mut map = TypeMap::default(); - - let reference = Test { x: 5, y: 20, z: 30 }; - - map.insert(reference.clone()); - let old = map.insert(reference.clone()).unwrap(); - - assert_eq!(old, reference); -} - -#[test] -fn verify_get() { - let mut map = TypeMap::default(); - - let reference = Test { x: 5, y: 20, z: 30 }; - - map.insert(reference.clone()); - - assert_eq!(map.get::().unwrap().clone(), reference); -} - -#[test] -fn verify_get_mut() { - let mut map = TypeMap::default(); - - let reference = Test { x: 5, y: 20, z: 30 }; - - map.insert(reference.clone()); - - assert_eq!(map.get_mut::().unwrap().clone(), reference); -} diff --git a/ecs/src/unsafe_component_store.rs b/ecs/src/unsafe_component_store.rs deleted file mode 100644 index cdf17af..0000000 --- a/ecs/src/unsafe_component_store.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::{fmt, ptr}; - -#[derive(Clone)] -pub struct UnsafeComponentStore { - ptr: *mut T, -} - -impl UnsafeComponentStore { - /// # Safety - /// - /// Creates structure with null pointer. Should never be called like this. - pub unsafe fn empty() -> Self { - Self { - ptr: ptr::null_mut(), - } - } - - /// # Safety - /// - /// Returns mutable reference to the inner pointer. Use always with caution - /// and make 100% sure that the actual struct is still present. - #[allow(clippy::mut_from_ref)] - pub unsafe fn as_mut(&self) -> &mut T { - assert_ne!( - self.ptr, - ptr::null_mut(), - "Called UnsafeComponentStore while being empty" - ); - - unsafe { self.ptr.as_mut().unwrap() } - } - - pub fn is_init(&self) -> bool { - !self.ptr.is_null() - } -} - -impl From<&mut T> for UnsafeComponentStore { - fn from(ptr: &mut T) -> Self { - Self { ptr: ptr as *mut T } - } -} - -impl From<&T> for UnsafeComponentStore { - fn from(ptr: &T) -> Self { - Self { - ptr: ptr as *const T as *mut T, - } - } -} - -impl fmt::Debug for UnsafeComponentStore { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("UnsafeComponentStore") - .field("ptr", &self.ptr) - .finish() - } -} - -impl Default for UnsafeComponentStore { - fn default() -> Self { - unsafe { Self::empty() } - } -} - -unsafe impl Send for UnsafeComponentStore {} -unsafe impl Sync for UnsafeComponentStore {} diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs deleted file mode 100644 index 638b324..0000000 --- a/ecs/src/updates.rs +++ /dev/null @@ -1,675 +0,0 @@ -#![allow(clippy::type_complexity)] - -use std::any::TypeId; - -use std::marker::PhantomData; -#[cfg(feature = "timings")] -use std::time::Instant; - -use anyhow::Result; -use indexmap::IndexMap; - -#[cfg(feature = "timings")] -use super::super::timings::Timings; - -use crate::*; -use scene_update_macros::implement_pair_update; - -macro_rules! impl_singleton_update { - ( $name: ident, $([$var: ident]$(,)?)+ ) => { - impl Archetype { - paste::item! { - pub fn [](f: F, filter: Filter) -> Self - where - F: Fn(&mut World, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, - Filter: CheckFilter + 'static, - $( - $var: EntityComponent + ComponentDebug, - )+ - { - $( - 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, scene_contents| { - unsafe { f(scene_contents, e, $([< $var:lower >].as_mut(),)+) } - })) - }), - - entities: IndexMap::new(), - } - } - } - } - - impl AddUpdates2<( $( $var, )+ ), Func, Filter> for Updates - where - $( - $var: EntityComponent + ComponentDebug, - )+ - Func: Fn(& mut World, 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::[](func, filter))) - } - } - } - - impl AddUpdates<( $( $var, )+ ), Func, Filter> for WorldBuilder - where - $( - $var: EntityComponent + ComponentDebug, - )+ - Func: Fn(& mut World, 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) - } - } - }; -} - -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 [] - (f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self - where - F: Fn(&mut World, (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, scene_contents| { - unsafe { f(scene_contents, (lhs_e, $($lhs_little.as_mut(),)+), (rhs_e, $($rhs_little.as_mut(),)+) ) } - })) - }), - - entities: IndexMap::new(), - } - } - } - } - - impl AddUpdates2<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for Updates - where - $( - $rhs_big: EntityComponent + ComponentDebug, - )+ - $( - $lhs_big: EntityComponent + ComponentDebug, - )+ - Func: Fn(& mut World, (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::[](func, filter.0, filter.1)))?; - } - - Ok(()) - } - } - - impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for WorldBuilder - where - $( - $rhs_big: EntityComponent + ComponentDebug, - )+ - $( - $lhs_big: EntityComponent + ComponentDebug, - )+ - Func: Fn(& mut World, (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 { - ( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => { - paste::item! { - pub struct [<$name Filter>]<$($big: EntityComponent,)+> { - $( - $little: std::marker::PhantomData<$big>, - )+ - } - - impl<$($big: EntityComponent,)+> Default for [<$name Filter>]<$($big,)+> { - fn default() -> Self { - Self { - $( - $little: std::marker::PhantomData, - )+ - } - } - } - - impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> { - fn check(&self, entity: &EntityObject) -> bool { - $( - if entity.contains_component::<$big>() { - return false; - } - )+ - - true - } - - fn verify_dedup(&self) { - $( - if TypeId::of::() == TypeId::of::<$big>() { - panic!("Type is used as input and filter at the same time"); - } - )+ - } - } - - impl<$($big: EntityComponent,)+> Clone for [<$name Filter>]<$($big,)+> { - fn clone(&self) -> Self { - Self { - $( - $little: self.$little.clone(), - )+ - } - } - } - } - }; -} - -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<()>; -} - -trait AddUpdates2 { - fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>; -} - -pub trait CheckFilter: Send + Sync + Default + Clone { - fn check(&self, entity: &EntityObject) -> bool; - fn verify_dedup(&self); -} - -#[derive(Default, Clone)] -pub struct EmptyFilter; - -impl CheckFilter for EmptyFilter { - fn check(&self, _entity: &EntityObject) -> bool { - true - } - - fn verify_dedup(&self) {} -} - -#[derive(Default, Clone, Debug)] -pub struct ArchetypeInfo { - entities: Vec<(Entity, Option)>, -} - -impl ArchetypeInfo { - pub fn new(entities: Vec<(Entity, Option)>) -> Self { - Self { entities } - } - - pub fn entities(&self) -> &[(Entity, Option)] { - &self.entities - } - - pub fn count(&self) -> usize { - self.entities.len() - } -} - -pub struct Archetype { - check_entity: Box bool + Send + Sync>, - create_callback: Box< - dyn Fn(&EntityObject) -> Result Result<()> + Send + Sync>> - + Send - + Sync, - >, - - entities: IndexMap Result<()> + Send + Sync>>, -} - -impl Archetype { - pub fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> { - if (self.check_entity)(entity_object) { - let cb = (self.create_callback)(entity_object)?; - - self.entities.insert(entity_object.as_entity(), cb); - } - - Ok(()) - } - - pub fn remove_entity(&mut self, entity: Entity) { - self.entities.swap_remove(&entity); - } - - pub fn execute(&self, scene_contents: &mut World) -> Result<()> { - for (entity, callback) in self.entities.iter() { - callback(*entity, scene_contents)?; - } - - Ok(()) - } - - pub fn entities( - &self, - ) -> &IndexMap Result<()> + Send + Sync>> { - &self.entities - } -} - -pub struct ArchetypePair { - check_left_entity: Box bool + Send + Sync>, - check_right_entity: Box bool + Send + Sync>, - - create_callback: Box< - dyn Fn( - &EntityObject, - &EntityObject, - ) - -> Result Result<()> + Send + Sync>> - + Send - + Sync, - >, - - entities: IndexMap< - (Entity, Entity), - Box Result<()> + Send + Sync>, - >, -} - -impl ArchetypePair { - pub(crate) fn add_entity( - &mut self, - entity_object: &EntityObject, - entities: &IndexMap, - ) -> 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, scene_contents: &mut World) -> Result<()> { - for ((left_entity, right_entity), callback) in self.entities.iter() { - callback(*left_entity, *right_entity, scene_contents)?; - } - - Ok(()) - } -} - -pub enum Update { - Single(Archetype), - Pair(ArchetypePair), -} - -impl From for Update { - fn from(archetype: Archetype) -> Self { - Self::Single(archetype) - } -} - -impl From for Update { - fn from(pair: ArchetypePair) -> Self { - Self::Pair(pair) - } -} - -pub struct Updates { - #[cfg(feature = "timings")] - timings: Timings, - - updates: Vec<(String, u32, Update)>, -} - -impl Default for Updates { - fn default() -> Self { - Self { - #[cfg(feature = "timings")] - timings: Timings::default, - - updates: Vec::new(), - } - } -} - -impl Updates { - 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 - .iter() - .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( - &mut self, - entity_object: &EntityObject, - entities: &IndexMap, - ) -> Result<()> { - for (_, _, update) in self.updates.iter_mut() { - match update { - Update::Single(archetype) => { - archetype.add_entity(entity_object)?; - } - Update::Pair(archetype_pair) => { - archetype_pair.add_entity(entity_object, entities)?; - } - } - } - - Ok(()) - } - - pub(crate) fn remove_entity(&mut self, entity: Entity) { - for (_, _, update) in self.updates.iter_mut() { - match update { - Update::Single(archetype) => { - archetype.remove_entity(entity); - } - Update::Pair(archetype_pair) => { - archetype_pair.remove_entity(entity); - } - } - } - } - - // pub(crate) fn clear(&mut self) { - // self.updates.clear(); - - // #[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(()) - } -} - -// #[derive(Default)] -// pub struct Archetypes { -// archetypes: HashMap, -// } - -// 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 clear(&mut self) { -// self.archetypes.clear(); -// } - -// 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, -// scene_contents: &mut SceneContents<'_>, -// ) -> Result<()> { -// self.archetypes[name].execute(scene_contents) -// } -// } - -#[rustfmt::skip] -impl_singleton_update!(single, [R]); -#[rustfmt::skip] -impl_singleton_update!(double, [R], [S]); -#[rustfmt::skip] -impl_singleton_update!(triple, [R], [S], [T]); -#[rustfmt::skip] -impl_singleton_update!(quadruple, [R], [S], [T], [U]); -#[rustfmt::skip] -impl_singleton_update!(quintuple, [R], [S], [T], [U], [V]); -#[rustfmt::skip] -impl_singleton_update!(sextuple, [R], [S], [T], [U], [V], [W]); -#[rustfmt::skip] -impl_singleton_update!(septuple, [R], [S], [T], [U], [V], [W], [X]); -#[rustfmt::skip] -impl_singleton_update!(octuple, [R], [S], [T], [U], [V], [W], [X], [Y]); -#[rustfmt::skip] -impl_singleton_update!(ninetuple, [R], [S], [T], [U], [V], [W], [X], [Y], [Z]); - -implement_pair_update!(impl_pair_update, 1, 10); - -#[rustfmt::skip] -impl_update_filter!(Monuple, [R, r]); -#[rustfmt::skip] -impl_update_filter!(Couple, [R, r], [S, s]); -#[rustfmt::skip] -impl_update_filter!(Triple, [R, r], [S, s], [T, t]); -#[rustfmt::skip] -impl_update_filter!(Quadruple, [R, r], [S, s], [T, t], [U, u]); -#[rustfmt::skip] -impl_update_filter!(Quintuple, [R, r], [S, s], [T, t], [U, u], [V, v]); -#[rustfmt::skip] -impl_update_filter!(Sextuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w]); -#[rustfmt::skip] -impl_update_filter!(Septuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x]); -#[rustfmt::skip] -impl_update_filter!(Octuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y]); -#[rustfmt::skip] -impl_update_filter!(Nonuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z]); -#[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]); diff --git a/ecs/src/world.rs b/ecs/src/world.rs deleted file mode 100644 index cbb648e..0000000 --- a/ecs/src/world.rs +++ /dev/null @@ -1,362 +0,0 @@ -use std::{ - any::TypeId, - collections::HashMap, - time::{Duration, Instant}, -}; - -use anyhow::{Result, bail}; -use indexmap::IndexMap; -use utilities::prelude::{remove_life_time, remove_life_time_mut}; - -use crate::{entity_object_manager::EntityObjectManager, *}; - -pub struct WorldBuilder { - pub(crate) updates: Updates, - pub events: Events, - pub resources: Resources, - systems: Vec Result + Send + Sync + 'static>>, -} - -impl WorldBuilder { - pub fn add_system(&mut self, f: F) - where - F: Fn(&mut World) -> Result + Send + Sync + 'static, - { - self.systems.push(Box::new(f)); - } -} - -impl WorldBuilder { - pub fn build(self) -> World { - World { - updates: self.updates, - events: self.events, - resources: self.resources, - entities: Default::default(), - - entities_to_remove: Default::default(), - entities_to_add: Default::default(), - entities_updates: Default::default(), - - entity_object_manager: Default::default(), - - start_time: Instant::now(), - - systems: self.systems, - } - } -} - -enum ComponentChange { - Added(TypeId, Box), - Removed(TypeId), -} - -pub struct World { - pub(crate) updates: Updates, - pub events: Events, - pub resources: Resources, - pub(crate) entities: IndexMap, - - entities_to_remove: Vec, - entities_to_add: Vec, - entities_updates: HashMap>, - - entity_object_manager: EntityObjectManager, - - start_time: Instant, - - systems: Vec Result + Send + Sync + 'static>>, -} - -impl World { - pub fn builder() -> WorldBuilder { - WorldBuilder { - updates: Default::default(), - events: Default::default(), - resources: Default::default(), - systems: Default::default(), - } - } - - pub fn now(&self) -> Duration { - self.start_time.elapsed() - } - - pub fn new_entity(&mut self) -> EntityObject { - self.entity_object_manager.create_entity() - } - - pub fn clone_without_components(&mut self, entity: &EntityObject) -> EntityObject { - entity.clone_without_components(self.entity_object_manager.fetch_add_entity_id()) - } - - pub fn entities(&self) -> impl Iterator { - self.entities.values() - } - - pub fn entity( - &self, - entity: Entity, - ) -> std::result::Result<&EntityObject, EntityNotFoundError> { - self.entities - .get(&entity) - .ok_or_else(|| EntityNotFoundError::new(entity)) - } - - pub unsafe fn entity_unchecked<'a>( - &self, - entity: Entity, - ) -> std::result::Result<&'a EntityObject, EntityNotFoundError> { - self.entity(entity).map(|e| unsafe { remove_life_time(e) }) - } - - pub fn entity_mut( - &mut self, - entity: Entity, - ) -> std::result::Result<&mut EntityObject, EntityNotFoundError> { - self.entities - .get_mut(&entity) - .ok_or_else(|| EntityNotFoundError::new(entity)) - } - - pub unsafe fn entity_mut_unchecked<'a>( - &mut self, - entity: Entity, - ) -> std::result::Result<&'a mut EntityObject, EntityNotFoundError> { - self.entity_mut(entity) - .map(|e| unsafe { remove_life_time_mut(e) }) - } - - pub fn entities_multi_mut(&mut self) -> EntityMultiMut<'_> { - EntityMultiMut::new(&mut self.entities) - } - - pub fn add_entity(&mut self, entity_object: EntityObject) -> Result { - let entity = entity_object.as_entity(); - self.entities_to_add.push(entity_object); - - Ok(entity) - } - - pub fn insert_component( - &mut self, - entity: Entity, - component: T, - ) -> Result<()> { - println!("insert component {}", T::debug_name()); - - let change = ComponentChange::Added(TypeId::of::(), Box::new(component)); - - match self.entities_updates.get_mut(&entity) { - Some(changes) => { - changes.push(change); - } - None => { - self.entities_updates.insert(entity, vec![change]); - } - } - - Ok(()) - } - - pub fn remove_component( - &mut self, - entity: Entity, - ) -> Result<()> { - println!("remove component {}", T::debug_name()); - - let change = ComponentChange::Removed(TypeId::of::()); - - match self.entities_updates.get_mut(&entity) { - Some(changes) => { - changes.push(change); - } - None => { - self.entities_updates.insert(entity, vec![change]); - } - } - - Ok(()) - } - - pub fn remove_entity(&mut self, entity: Entity) -> Result> { - self.entities_to_remove.push(entity); - - Ok(None) - } -} - -// async application of changes -impl World { - fn _add_entity(&mut self, mut entity: EntityObject) -> Result { - // call enable event for all components - for (_, component) in entity.components.iter_mut() { - component.enable(self)?; - } - - entity.activation_state.apply_change(); - - let e = entity.as_entity(); - - self.updates.add_entity(&mut entity, &self.entities)?; - assert!(self.entities.insert(e, entity).is_none()); - - Ok(e) - } - - fn _remove_entity(&mut self, entity: Entity) -> Result> { - if let Some(mut entity_object) = self.entities.swap_remove(&entity) { - for (_, component) in entity_object.components.iter_mut() { - component.disable(self)?; - } - - entity_object.activation_state.apply_change(); - self.updates.remove_entity(entity); - - return Ok(Some(entity_object)); - } - - Ok(None) - } - - fn _insert_component( - &mut self, - entity: Entity, - mut component: T, - ) -> Result<()> { - let entities = unsafe { remove_life_time_mut(&mut self.entities) }; - - let entity_object = entities - .get_mut(&entity) - .ok_or_else(|| EntityNotFoundError::new(entity))?; - - self.updates.remove_entity(entity); - - entity_object.activation_state.apply_change(); - - component.enable(self)?; - if entity_object.insert_component(component).is_some() { - bail!("component {} already present", T::debug_name()); - } - - entity_object.activation_state.apply_change(); - - self.updates.add_entity(entity_object, &self.entities)?; - - Ok(()) - } - - fn _remove_component( - &mut self, - entity: Entity, - ) -> Result<()> { - let entities = unsafe { remove_life_time_mut(&mut self.entities) }; - - let entity_object = entities - .get_mut(&entity) - .ok_or_else(|| EntityNotFoundError::new(entity))?; - - self.updates.remove_entity(entity); - - entity_object.activation_state.apply_change(); - - if let Some(mut component) = entity_object.remove_component_by_id(TypeId::of::()) { - component.disable(self)?; - } - - entity_object.activation_state.apply_change(); - - self.updates.add_entity(entity_object, &self.entities)?; - - Ok(()) - } - - fn commit_entity_changes(&mut self) -> Result<()> { - if !self.entities_to_remove.is_empty() { - println!("entities to remove {}", self.entities_to_remove.len()); - } - - for entity in core::mem::take(&mut self.entities_to_remove) { - self._remove_entity(entity)?; - } - - if !self.entities_to_add.is_empty() { - println!("entities to add {}", self.entities_to_add.len()); - } - - for entity_object in core::mem::take(&mut self.entities_to_add) { - self._add_entity(entity_object)?; - } - - if !self.entities_updates.is_empty() { - println!("entities to update {}", self.entities_updates.len()); - } - - for (entity, changes) in core::mem::take(&mut self.entities_updates) { - self.updates.remove_entity(entity); - - if let Some(entity_object) = unsafe { self.entity_mut_unchecked(entity).ok() } { - entity_object.activation_state.apply_change(); - - for change in changes { - match change { - ComponentChange::Added(type_id, mut component) => { - component.enable(self)?; - let name = component.name().to_string(); - - if entity_object - .insert_component_by_id(type_id, component) - .is_some() - { - bail!("component {name} already present"); - } - } - ComponentChange::Removed(type_id) => { - if let Some(mut component) = - entity_object.remove_component_by_id(type_id) - { - component.disable(self)?; - } - } - } - } - - entity_object.activation_state.apply_change(); - - self.updates.add_entity(entity_object, &self.entities)?; - } - } - - Ok(()) - } -} - -impl World { - pub fn run(&mut self) -> Result<()> { - let systems = std::mem::take(&mut self.systems); - - loop { - // we need to take all events because of borrowing rules - let mut events = self.events.take_events(); - events.fire_events(self)?; - - { - // actually safe: - // - updates can't be altered on a running world - // - entity changes are processed afterwards - let w = unsafe { remove_life_time_mut(self) }; - - self.updates.update(w)?; - } - - self.commit_entity_changes()?; - - for system in systems.iter() { - if !system(self)? { - return Ok(()); - } - } - } - } -} diff --git a/engine/Cargo.toml b/engine/Cargo.toml index f223732..d51dfc6 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -16,12 +16,12 @@ indexmap = { workspace = true } utilities = { workspace = true } assetpath = { workspace = true } shaderc = { workspace = true } +ecs = { workspace = true } config_handler = { path = "../config_handler" } asset = { path = "../asset" } loading_screen = { path = "../loading-screen" } context = { path = "../context", features = ["bundle_sdl2", "sound"] } -ecs = { path = "../ecs" } [features] timings = [] diff --git a/engine/src/engine/engine.rs b/engine/src/engine/engine.rs index 297726b..2b5f5c9 100644 --- a/engine/src/engine/engine.rs +++ b/engine/src/engine/engine.rs @@ -260,7 +260,7 @@ impl Engine { }, )?; - gui_handler.process_callbacks()?; + gui_handler.process_callbacks(world)?; Ok(res) } diff --git a/engine/src/engine/engine_event_handling.rs b/engine/src/engine/engine_event_handling.rs index 7b3bcb7..2a77c21 100644 --- a/engine/src/engine/engine_event_handling.rs +++ b/engine/src/engine/engine_event_handling.rs @@ -183,7 +183,7 @@ impl Engine { } } Keycode::Escape => { - if gui_handler.decline_topgui()? { + if gui_handler.decline_topgui(world)? { return Ok(()); } } @@ -262,31 +262,31 @@ impl Engine { } ControllerButton::B => { - if gui_handler.decline_topgui()? { + if gui_handler.decline_topgui(world)? { return Ok(()); } } ControllerButton::RightButton => { - if gui_handler.next_tab_topgui(false)? { + if gui_handler.next_tab_topgui(world, false)? { return Ok(()); } } ControllerButton::LeftButton => { - if gui_handler.previous_tab_topgui(false)? { + if gui_handler.previous_tab_topgui(world, false)? { return Ok(()); } } ControllerButton::RightTrigger => { - if gui_handler.next_tab_topgui(true)? { + if gui_handler.next_tab_topgui(world, true)? { return Ok(()); } } ControllerButton::LeftTrigger => { - if gui_handler.previous_tab_topgui(true)? { + if gui_handler.previous_tab_topgui(world, true)? { return Ok(()); } } @@ -330,7 +330,7 @@ impl Engine { _ => (), } - if !gui_handler.accept_custom_selection(button)? { + if !gui_handler.accept_custom_selection(world, button)? { consumer.event(world, EngineEvent::ControllerButtonDown(controller, button))?; } diff --git a/examples/simple_window/Cargo.toml b/examples/simple_window/Cargo.toml index a71cc04..491e55a 100644 --- a/examples/simple_window/Cargo.toml +++ b/examples/simple_window/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] plexus = "0.0.11" anyhow.workspace = true +ecs.workspace = true -ecs = { path = "../../ecs" } engine = { path = "../../engine" } skybox = { path = "../../skybox" } diff --git a/presentation/Cargo.toml b/presentation/Cargo.toml index d97e826..6ace477 100644 --- a/presentation/Cargo.toml +++ b/presentation/Cargo.toml @@ -13,7 +13,7 @@ anyhow = { workspace = true } openxr = { workspace = true, optional = true } openvr = { workspace = true, optional = true } -ecs = { path = "../ecs" } +ecs = { workspace = true } [features] OpenXR = ["openxr"] diff --git a/scene_update_macros/Cargo.toml b/scene_update_macros/Cargo.toml deleted file mode 100644 index c6f9228..0000000 --- a/scene_update_macros/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "scene_update_macros" -version = "0.1.0" -authors = ["hodasemi "] -edition = "2024" - -[lib] -proc-macro = true - -[dependencies] -syn = { workspace = true } -quote = { workspace = true } -proc-macro2 = { workspace = true } diff --git a/scene_update_macros/src/lib.rs b/scene_update_macros/src/lib.rs deleted file mode 100644 index 097017f..0000000 --- a/scene_update_macros/src/lib.rs +++ /dev/null @@ -1,117 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{format_ident, quote}; -use syn::{ - parse::{Parse, ParseStream}, - parse_macro_input, - token::Comma, - Ident, LitInt, Result, -}; - -struct InputInfo { - macro_ident: Ident, - start: usize, - end: usize, -} - -impl Parse for InputInfo { - fn parse(input: ParseStream) -> Result { - let macro_ident = input.parse::()?; - input.parse::()?; - let start = input.parse::()?.base10_parse()?; - input.parse::()?; - let end = input.parse::()?.base10_parse()?; - - Ok(Self { - macro_ident, - start, - end, - }) - } -} - -struct TupleType { - little: Ident, - big: Ident, -} - -#[proc_macro] -pub fn implement_pair_update(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as InputInfo); - - 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, Vec)> = 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 = 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 = lhs - .iter() - .map(|tuple| { - let little = &tuple.little; - let big = &tuple.big; - - quote! { - [#little: #big], - } - }) - .collect(); - - let rhs_args: Vec = 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 - )* - }) -} diff --git a/skybox/Cargo.toml b/skybox/Cargo.toml index b220e36..ccdcfcc 100644 --- a/skybox/Cargo.toml +++ b/skybox/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" anyhow.workspace = true plexus.workspace = true utilities.workspace = true +ecs.workspace = true -ecs = { path = "../ecs" } context = { path = "../context" } engine = { path = "../engine" }