diff --git a/Cargo.toml b/Cargo.toml index bd9262b..502d710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,26 +2,28 @@ resolver = "2" members = [ - "asset", "ConfigHandler", + "Networking", + "asset", + "character_window", "context", "controllable_thread", + "ecs", "engine", + "entity_manager", + "examples/simple_window", "gavania-core", "gltf-loader", "loading-screen", "lua-wrapper", + "map", "math", - "Networking", "presentation", "promise", "ring_buffer", + "rpg_components", "scene_update_macros", "transaction_derive", - "map", - "rpg_components", - "entity_manager", - "character_window", "ecs", ] [workspace.dependencies] @@ -43,7 +45,7 @@ reqwest = { version = "0.12.5", features = ["blocking"] } shared_library = "0.1.9" gltf = { version = "1.4.1", features = ["extras", "names"] } mlua = { version = "0.9.9", features = ["lua54", "send", "vendored"] } -public-ip = { version = "0.2.2", default-features = false, features = ["tokio-dns-resolver", "all-providers"] } +public-ip = { version = "0.2.2", default-features = false, features = ["all-providers", "tokio-dns-resolver"] } async-std = { version = "1.12.0" } if-addrs = { version = "0.13.0" } hostname = { version = "0.3.1" } @@ -51,7 +53,7 @@ trust-dns-resolver = { version = "0.23.2" } openxr = { version = "0.19.0", default-features = false, features = ["static"] } openvr = { version = "0.6.0" } sdl2 = { version = "0.37.0" } -syn = { version = "2.0.67", features = ["extra-traits", "full"] } +syn = { version = "2.0.67", features = ["extra-traits", "full"] } quote = "1.0.35" proc-macro2 = "1.0.86" downcast-rs = "1.2.1" @@ -61,7 +63,7 @@ vulkan-rs = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } 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" } +ui = { git = "https://gavania.de/hodasemi/ui.git" } [profile.release-lto] inherits = "release" diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml index 0c75686..78870a1 100644 --- a/ecs/Cargo.toml +++ b/ecs/Cargo.toml @@ -11,6 +11,7 @@ indexmap.workspace = true serde = { workspace = true, features = ["derive"] } paste.workspace = true ron.workspace = true +utilities.workspace = true scene_update_macros = { path = "../scene_update_macros" } diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs index 0356a3b..e28a285 100644 --- a/ecs/src/entity.rs +++ b/ecs/src/entity.rs @@ -1,14 +1,35 @@ 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}; pub const COMPONENT_SEPARATOR: char = 'ยง'; +#[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, @@ -24,7 +45,7 @@ impl ActivationState { } } -pub struct EntityObject { +pub struct EntityObject { #[cfg(debug_assertions)] pub debug_name: Option, @@ -38,16 +59,16 @@ pub struct EntityObject { pub entity_id: u32, // component map - pub(crate) components: TypeMap, + pub components: TypeMap, #[cfg(debug_assertions)] component_names: Vec, } -unsafe impl Send for EntityObject {} -unsafe impl Sync for EntityObject {} +unsafe impl Send for EntityObject {} +unsafe impl Sync for EntityObject {} -impl EntityObject { +impl EntityObject { pub(crate) fn new(id: u32) -> Self { Self { #[cfg(debug_assertions)] @@ -70,11 +91,11 @@ impl EntityObject { self.gltf_file.as_ref() } - pub fn multi_mut(&mut self) -> MultiMut<'_, S> { + pub fn multi_mut(&mut self) -> MultiMut<'_> { self.components.multi_mut() } - pub fn insert_component + ComponentDebug>( + pub fn insert_component( &mut self, component: T, ) -> Option { @@ -98,11 +119,8 @@ impl EntityObject { pub(crate) fn insert_component_by_id( &mut self, type_id: TypeId, - component: Box>, - ) -> Option>> - where - S: 'static, - { + component: Box, + ) -> Option> { assert!( !self.activation_state.is_active(), "inserting components while the entity is activated is not allowed" @@ -120,7 +138,7 @@ impl EntityObject { self.components.insert_type(type_id, component) } - pub fn remove_component>(&mut self) -> Option { + pub fn remove_component(&mut self) -> Option { assert!( !self.activation_state.is_active(), "removing components while the entity is activated is not allowed" @@ -145,10 +163,7 @@ impl EntityObject { pub(crate) fn remove_component_by_id( &mut self, type_id: TypeId, - ) -> Option>> - where - S: 'static, - { + ) -> Option> { assert!( !self.activation_state.is_active(), "removing components while the entity is activated is not allowed" @@ -175,19 +190,19 @@ impl EntityObject { &self.component_names } - pub fn get_component + ComponentDebug>( + pub fn get_component( &self, ) -> std::result::Result<&T, ComponentNotFoundError> { self.components.get() } - pub fn get_component_mut + ComponentDebug>( + pub fn get_component_mut( &mut self, ) -> std::result::Result<&mut T, ComponentNotFoundError> { self.components.get_mut() } - pub fn contains_component>(&self) -> bool { + pub fn contains_component(&self) -> bool { self.components.contains::() } @@ -199,7 +214,7 @@ impl EntityObject { Entity { id: self.entity_id } } - pub(crate) fn clone_without_components(&self, id: u32) -> EntityObject { + pub(crate) fn clone_without_components(&self, id: u32) -> EntityObject { EntityObject { #[cfg(debug_assertions)] debug_name: self.debug_name.clone(), @@ -219,7 +234,7 @@ impl EntityObject { } } - pub fn clone_component_from + ComponentDebug + Clone>( + pub fn clone_component_from( &mut self, other: &Self, ) -> Result<()> { @@ -236,8 +251,8 @@ pub struct Entity { pub(crate) id: u32, } -impl PartialEq> for Entity { - fn eq(&self, entity: &EntityObject) -> bool { +impl PartialEq for Entity { + fn eq(&self, entity: &EntityObject) -> bool { self.id == entity.entity_id } } @@ -261,3 +276,40 @@ impl FromStr for Entity { 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 new file mode 100644 index 0000000..e16afcd --- /dev/null +++ b/ecs/src/entity_object_manager.rs @@ -0,0 +1,19 @@ +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 index b9ec535..71abc73 100644 --- a/ecs/src/events.rs +++ b/ecs/src/events.rs @@ -1,21 +1,23 @@ use std::{ any::{Any, TypeId}, collections::HashMap, - mem, ops::DerefMut, + sync::Arc, }; -pub struct Events { +use crate::World; + +pub struct Events { events: HashMap< - TypeId, + TypeId, // TypeId of Payload ( - Vec>, - Vec anyhow::Result<()> + Send + Sync>>, + Vec>, // Payload + Vec anyhow::Result<()> + Send + Sync>>, // Listener on Payload ), >, } -impl Default for Events { +impl Default for Events { fn default() -> Self { Self { events: HashMap::new(), @@ -23,28 +25,20 @@ impl Default for Events { } } -impl Events { - pub(crate) fn clone_from_register(&self) -> Self { +impl Events { + pub(crate) fn take_events(&mut self) -> Self { Self { events: self .events - .keys() - .map(|type_id| (*type_id, (Vec::new(), Vec::new()))) + .iter_mut() + .filter_map(|(type_id, (payload, listener))| { + (!payload.is_empty()) + .then(|| (*type_id, (std::mem::take(payload), listener.clone()))) + }) .collect(), } } - pub(crate) fn move_events(&mut self, other: &mut Self) { - for (type_id, (payloads, _)) in other.events.iter_mut() { - if !payloads.is_empty() { - let mut tmp = Vec::new(); - mem::swap(payloads, &mut tmp); - - self.events.get_mut(type_id).unwrap().0.extend(tmp); - } - } - } - pub fn clear(&mut self) { for (payloads, listener) in self.events.values_mut() { payloads.clear(); @@ -59,13 +53,13 @@ impl Events { pub fn add_reader(&mut self, f: F) where - F: Fn(&mut C, &T) -> anyhow::Result<()> + Send + Sync + 'static, + F: Fn(&mut World, &T) -> anyhow::Result<()> + Send + Sync + 'static, { match self.events.get_mut(&TypeId::of::()) { - Some((_, listener)) => listener.push(Box::new(move |c, payload| { + Some((_, listener)) => listener.push(Arc::new(move |world, payload| { let typed_payload: &T = payload.downcast_ref().unwrap(); - f(c, typed_payload) + f(world, typed_payload) })), None => panic!("register event type first!"), } @@ -78,11 +72,11 @@ impl Events { } } - pub(crate) fn fire_events(&mut self, c: &mut C) -> anyhow::Result<()> { + 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)(c, payload.deref_mut())?; + (listener)(world, payload.deref_mut())?; } } diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 3011d6c..b74be15 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,4 +1,5 @@ mod entity; +mod entity_object_manager; mod events; mod resources; mod type_map; @@ -6,7 +7,7 @@ mod unsafe_component_store; mod updates; mod world; -pub use crate::entity::{Entity, EntityObject}; +pub use crate::entity::{Entity, EntityMultiMut, EntityNotFoundError, EntityObject}; pub use crate::events::Events; pub use crate::resources::{ResourceMultiMut, Resources}; pub use crate::type_map::{ @@ -14,4 +15,4 @@ pub use crate::type_map::{ }; pub use crate::unsafe_component_store::UnsafeComponentStore; pub use crate::updates::*; -pub use crate::world::World; +pub use crate::world::{World, WorldBuilder}; diff --git a/ecs/src/type_map.rs b/ecs/src/type_map.rs index 4d0d962..d0aa76d 100644 --- a/ecs/src/type_map.rs +++ b/ecs/src/type_map.rs @@ -12,12 +12,14 @@ use anyhow::Result; use destructure_traitobject; use serde::{Deserialize, Serialize}; -pub trait EntityComponent: Any + Send + Sync { - fn enable(&mut self, _scene: &mut S) -> Result<()> { +use crate::World; + +pub trait EntityComponent: Any + Send + Sync { + fn enable(&mut self, _world: &mut World) -> Result<()> { Ok(()) } - fn disable(&mut self, _scene: &mut S) -> Result<()> { + fn disable(&mut self, _world: &mut World) -> Result<()> { Ok(()) } @@ -45,11 +47,11 @@ pub trait ComponentCreateInfo<'de>: Serialize + Deserialize<'de> { } } -pub struct TypeMap { - map: HashMap>>, +pub struct TypeMap { + map: HashMap>, } -impl Default for TypeMap { +impl Default for TypeMap { fn default() -> Self { Self { map: HashMap::new(), @@ -57,8 +59,8 @@ impl Default for TypeMap { } } -impl TypeMap { - pub fn insert + ComponentDebug>(&mut self, value: T) -> Option { +impl TypeMap { + pub fn insert(&mut self, value: T) -> Option { self.map .insert(TypeId::of::(), Box::new(value)) .map(|any| *Self::downcast_unchecked(any)) @@ -67,21 +69,21 @@ impl TypeMap { pub fn insert_type( &mut self, type_id: TypeId, - component: Box>, - ) -> Option>> { + component: Box, + ) -> Option> { self.map.insert(type_id, component) } - pub fn remove>(&mut self) -> Option { + 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>> { + pub fn remove_by_type_id(&mut self, type_id: &TypeId) -> Option> { self.map.remove(type_id) } - pub fn get + ComponentDebug>( + pub fn get( &self, ) -> std::result::Result<&T, ComponentNotFoundError> { self.map @@ -93,13 +95,13 @@ impl TypeMap { pub fn get_by_type_id( &self, type_id: &TypeId, - ) -> std::result::Result<&Box>, ComponentNotFoundError> { + ) -> std::result::Result<&Box, ComponentNotFoundError> { self.map .get(type_id) .ok_or_else(|| ComponentNotFoundError::type_id(*type_id)) } - pub fn get_mut + ComponentDebug>( + pub fn get_mut( &mut self, ) -> std::result::Result<&mut T, ComponentNotFoundError> { self.map @@ -111,13 +113,13 @@ impl TypeMap { pub fn get_mut_by_type_id( &mut self, type_id: &TypeId, - ) -> std::result::Result<&mut Box>, ComponentNotFoundError> { + ) -> 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 { + pub fn contains(&self) -> bool { self.contains_type_id(&TypeId::of::()) } @@ -125,25 +127,23 @@ impl TypeMap { self.map.contains_key(type_id) } - pub fn multi_mut(&mut self) -> MultiMut<'_, S> { + pub fn multi_mut(&mut self) -> MultiMut<'_> { MultiMut::new(&mut self.map) } - pub fn iter(&self) -> Iter<'_, TypeId, Box>> { + pub fn iter(&self) -> Iter<'_, TypeId, Box> { self.map.iter() } - pub fn iter_mut(&mut self) -> IterMut<'_, TypeId, Box>> { + pub fn iter_mut(&mut self) -> IterMut<'_, TypeId, Box> { self.map.iter_mut() } - fn downcast_unchecked>(boxed: Box>) -> Box { + 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 { + 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 _)); @@ -152,8 +152,8 @@ impl TypeMap { } } - pub fn downcast_mut_unchecked>( - boxed_ref: &mut Box>, + pub fn downcast_mut_unchecked( + boxed_ref: &mut Box, ) -> &mut T { unsafe { let ptr_to_ptr: *mut *mut T = @@ -165,13 +165,13 @@ impl TypeMap { } /// Allows mutable access to multiple components at once -pub struct MultiMut<'a, S> { - map: &'a mut HashMap>>, - buffer: Vec<*mut Box>>, +pub struct MultiMut<'a> { + map: &'a mut HashMap>, + buffer: Vec<*mut Box>, } -impl<'a, S> MultiMut<'a, S> { - fn new(map: &'a mut HashMap>>) -> Self { +impl<'a> MultiMut<'a> { + fn new(map: &'a mut HashMap>) -> Self { MultiMut { map, buffer: Vec::new(), @@ -179,7 +179,7 @@ impl<'a, S> MultiMut<'a, S> { } /// Returns requested type on success - pub fn get + ComponentDebug>( + pub fn get( &mut self, ) -> std::result::Result<&'a mut T, ComponentNotFoundError> { self.get_by_type_id(&TypeId::of::()) @@ -191,7 +191,7 @@ impl<'a, S> MultiMut<'a, S> { pub fn get_by_type_id( &mut self, type_id: &TypeId, - ) -> std::result::Result<&'a mut Box>, ComponentNotFoundError> { + ) -> std::result::Result<&'a mut Box, ComponentNotFoundError> { match self.map.get_mut(type_id) { Some(v) => { let ptr = v as *mut _; @@ -205,7 +205,7 @@ impl<'a, S> MultiMut<'a, S> { } } - let t: Option<&'a mut Box>> = unsafe { transmute(ptr) }; + let t: Option<&'a mut Box> = unsafe { transmute(ptr) }; t.ok_or_else(|| ComponentNotFoundError::type_id(*type_id)) } @@ -261,7 +261,7 @@ struct Test { z: u32, } -impl EntityComponent for Test { +impl EntityComponent for Test { fn name(&self) -> &str { "Test" } @@ -281,7 +281,7 @@ impl PartialEq for Test { #[test] fn verify_multi_mut() { - let mut map = TypeMap::<()>::default(); + let mut map = TypeMap::default(); map.insert(Test::default()); @@ -299,7 +299,7 @@ fn verify_multi_mut() { #[test] fn verify_insert() { - let mut map = TypeMap::<()>::default(); + let mut map = TypeMap::default(); let reference = Test { x: 5, y: 20, z: 30 }; @@ -311,7 +311,7 @@ fn verify_insert() { #[test] fn verify_get() { - let mut map = TypeMap::<()>::default(); + let mut map = TypeMap::default(); let reference = Test { x: 5, y: 20, z: 30 }; @@ -322,7 +322,7 @@ fn verify_get() { #[test] fn verify_get_mut() { - let mut map = TypeMap::<()>::default(); + let mut map = TypeMap::default(); let reference = Test { x: 5, y: 20, z: 30 }; diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs index b614a42..7b80fc4 100644 --- a/ecs/src/updates.rs +++ b/ecs/src/updates.rs @@ -17,14 +17,14 @@ use scene_update_macros::implement_pair_update; macro_rules! impl_singleton_update { ( $name: ident, $([$var: ident]$(,)?)+ ) => { - impl Archetype { + impl Archetype { paste::item! { pub fn [](f: F, filter: Filter) -> Self where - F: Fn(&mut C, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, - Filter: CheckFilter + 'static, + F: Fn(&mut World, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, + Filter: CheckFilter + 'static, $( - $var: EntityComponent + ComponentDebug, + $var: EntityComponent + ComponentDebug, )+ { $( @@ -68,36 +68,34 @@ macro_rules! impl_singleton_update { } } - impl AddUpdates2 for Updates + impl AddUpdates2<( $( $var, )+ ), Func, Filter> for Updates where $( - $var: EntityComponent + ComponentDebug, + $var: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut C, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, - Filter: CheckFilter + 'static + 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, - entities: &IndexMap> + filter: Filter ) -> Result<()> { paste::item! { - self.add(name, priority, Update::Single(Archetype::[](func, filter)), entities) + self.add(name, priority, Update::Single(Archetype::[](func, filter))) } } } - impl AddUpdates<( $( $var, )+ ), Func, Filter> for World + impl AddUpdates<( $( $var, )+ ), Func, Filter> for WorldBuilder where $( - $var: EntityComponent + ComponentDebug, + $var: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut C, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, - Filter: CheckFilter + 'static, - C: Send + Sync + Func: Fn(& mut World, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, + Filter: CheckFilter + 'static { fn add_update( &mut self, @@ -106,29 +104,9 @@ macro_rules! impl_singleton_update { func: Func, filter: Filter, ) -> Result<()> { - self.updates.add_update(name, priority, func, filter, &self.entities) + self.updates.add_update(name, priority, func, filter) } } - - // impl Scene { - // paste::item! { - // pub fn [](&mut self, name: impl ToString, f: F, filter: Filter) -> Result<()> - // where - // F: Fn(&mut SceneContents<'_>, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, - // Filter: CheckFilter + 'static, - // $( - // $var: EntityComponent + ComponentDebug, - // )+ - // { - // let mut archetype = Archetype::[](f, filter); - // archetype.setup(&self.entities)?; - - // self.archetypes.insert(name.to_string(), archetype); - - // Ok(()) - // } - // } - // } }; } @@ -139,19 +117,19 @@ macro_rules! impl_pair_update { $rhs_id: expr, ( $([$rhs_little: ident: $rhs_big: ident]$(,)?)+ ) ) => { - impl ArchetypePair { + impl ArchetypePair { paste::item! { pub fn [] (f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self where - F: Fn(&mut C, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, - LeftFilter: CheckFilter + 'static, - RightFilter: CheckFilter + 'static, + 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, + $rhs_big: EntityComponent + ComponentDebug, )+ $( - $lhs_big: EntityComponent + ComponentDebug, + $lhs_big: EntityComponent + ComponentDebug, )+ { $( @@ -220,46 +198,44 @@ macro_rules! impl_pair_update { } } - impl AddUpdates2 for Updates + impl AddUpdates2<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for Updates where $( - $rhs_big: EntityComponent + ComponentDebug, + $rhs_big: EntityComponent + ComponentDebug, )+ $( - $lhs_big: EntityComponent + ComponentDebug, + $lhs_big: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut C, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, - LhsFilter: CheckFilter + 'static, - RhsFilter: CheckFilter + 'static + 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), - entities: &IndexMap> + filter: (LhsFilter, RhsFilter) ) -> Result<()> { paste::item! { - self.add(name, priority, Update::Pair(ArchetypePair::[](func, filter.0, filter.1)), entities)?; + self.add(name, priority, Update::Pair(ArchetypePair::[](func, filter.0, filter.1)))?; } Ok(()) } } - impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for World + impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for WorldBuilder where $( - $rhs_big: EntityComponent + ComponentDebug, + $rhs_big: EntityComponent + ComponentDebug, )+ $( - $lhs_big: EntityComponent + ComponentDebug, + $lhs_big: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut C, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, - LhsFilter: CheckFilter + 'static, - RhsFilter: CheckFilter + 'static, - C: Send + Sync + 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, @@ -268,60 +244,24 @@ macro_rules! impl_pair_update { func: Func, filter: (LhsFilter, RhsFilter), ) -> Result<()> { - self.updates.add_update(name, priority, func, filter, &self.entities) + self.updates.add_update(name, priority, func, filter) } } - - // impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, Filter> for Scene - // where - // $( - // $rhs_big: EntityComponent + ComponentDebug, - // )+ - // $( - // $lhs_big: EntityComponent + ComponentDebug, - // )+ - // Func: Fn(& mut SceneContents<'_>, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> 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.updates.add_update(name, priority, func, (filter.clone(), filter), &self.entities)?; - // } - - // Ok(()) - // } - // } }; } macro_rules! impl_update_filter { ( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => { paste::item! { - pub struct [<$name Filter>],)+> - where - C: Send + Sync - { - c: std::marker::PhantomData, - + pub struct [<$name Filter>]<$($big: EntityComponent,)+> { $( $little: std::marker::PhantomData<$big>, )+ } - impl,)+> Default for [<$name Filter>] - where - C: Send + Sync - { + impl<$($big: EntityComponent,)+> Default for [<$name Filter>]<$($big,)+> { fn default() -> Self { Self { - c: std::marker::PhantomData, - $( $little: std::marker::PhantomData, )+ @@ -329,11 +269,8 @@ macro_rules! impl_update_filter { } } - impl,)+> CheckFilter for [<$name Filter>] - where - C: Send + Sync - { - fn check(&self, entity: &EntityObject) -> bool { + impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> { + fn check(&self, entity: &EntityObject) -> bool { $( if entity.contains_component::<$big>() { return false; @@ -343,7 +280,7 @@ macro_rules! impl_update_filter { true } - fn verify_dedup>(&self) { + fn verify_dedup(&self) { $( if TypeId::of::() == TypeId::of::<$big>() { panic!("Type is used as input and filter at the same time"); @@ -352,14 +289,9 @@ macro_rules! impl_update_filter { } } - impl,)+> Clone for [<$name Filter>] - where - C: Send + Sync - { + impl<$($big: EntityComponent,)+> Clone for [<$name Filter>]<$($big,)+> { fn clone(&self) -> Self { Self { - c: self.c.clone(), - $( $little: self.$little.clone(), )+ @@ -370,41 +302,33 @@ macro_rules! impl_update_filter { }; } -pub struct Query +pub struct Query where - F: CheckFilter, + F: CheckFilter, { pub components: T, d: PhantomData, - c: 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, - entities: &IndexMap>, - ) -> 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); +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 { +impl CheckFilter for EmptyFilter { + fn check(&self, _entity: &EntityObject) -> bool { true } @@ -430,19 +354,19 @@ impl ArchetypeInfo { } } -pub struct Archetype { - check_entity: Box) -> bool + Send + Sync>, +pub struct Archetype { + check_entity: Box bool + Send + Sync>, create_callback: Box< - dyn Fn(&EntityObject) -> Result Result<()> + Send + Sync>> + dyn Fn(&EntityObject) -> Result Result<()> + Send + Sync>> + Send + Sync, >, - entities: IndexMap Result<()> + Send + Sync>>, + entities: IndexMap Result<()> + Send + Sync>>, } -impl Archetype { - pub fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> { +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)?; @@ -456,7 +380,7 @@ impl Archetype { self.entities.swap_remove(&entity); } - pub fn execute(&self, scene_contents: &mut C) -> Result<()> { + pub fn execute(&self, scene_contents: &mut World) -> Result<()> { for (entity, callback) in self.entities.iter() { callback(*entity, scene_contents)?; } @@ -464,48 +388,38 @@ impl Archetype { Ok(()) } - pub fn setup(&mut self, entities: &IndexMap>) -> Result<()> { - for (entity, entity_object) in entities.iter() { - if (self.check_entity)(entity_object) { - let cb = (self.create_callback)(entity_object)?; - - self.entities.insert(entity.clone(), cb); - } - } - - Ok(()) - } - pub(crate) fn entities( &self, - ) -> &IndexMap Result<()> + Send + Sync>> { + ) -> &IndexMap Result<()> + Send + Sync>> { &self.entities } } -pub struct ArchetypePair { - check_left_entity: Box) -> bool + Send + Sync>, - check_right_entity: Box) -> bool + Send + Sync>, +pub struct ArchetypePair { + check_left_entity: Box bool + Send + Sync>, + check_right_entity: Box bool + Send + Sync>, create_callback: Box< dyn Fn( - &EntityObject, - &EntityObject, + &EntityObject, + &EntityObject, ) - -> Result Result<()> + Send + Sync>> + -> Result Result<()> + Send + Sync>> + Send + Sync, >, - entities: - IndexMap<(Entity, Entity), Box Result<()> + Send + Sync>>, + entities: IndexMap< + (Entity, Entity), + Box Result<()> + Send + Sync>, + >, } -impl ArchetypePair { +impl ArchetypePair { pub(crate) fn add_entity( &mut self, - entity_object: &EntityObject, - entities: &IndexMap>, + entity_object: &EntityObject, + entities: &IndexMap, ) -> Result<()> { for (other_entity, other_entity_object) in entities.iter() { if entity_object.as_entity() == *other_entity { @@ -546,57 +460,40 @@ impl ArchetypePair { } } - pub(crate) fn execute(&self, scene_contents: &mut C) -> Result<()> { + 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(crate) fn setup(&mut self, entities: &IndexMap>) -> Result<()> { - for (lhs_entity, lhs_entity_object) in entities.iter() { - for (rhs_entity, rhs_entity_object) in entities.iter() { - if lhs_entity != rhs_entity - && (self.check_left_entity)(lhs_entity_object) - && (self.check_right_entity)(rhs_entity_object) - { - let cb = (self.create_callback)(lhs_entity_object, rhs_entity_object)?; - - self.entities.insert((*lhs_entity, *rhs_entity), cb); - } - } - } - - Ok(()) - } } -pub enum Update { - Single(Archetype), - Pair(ArchetypePair), +pub enum Update { + Single(Archetype), + Pair(ArchetypePair), } -impl From> for Update { - fn from(archetype: Archetype) -> Self { +impl From for Update { + fn from(archetype: Archetype) -> Self { Self::Single(archetype) } } -impl From> for Update { - fn from(pair: ArchetypePair) -> Self { +impl From for Update { + fn from(pair: ArchetypePair) -> Self { Self::Pair(pair) } } -pub struct Updates { +pub struct Updates { #[cfg(feature = "timings")] timings: Timings, - updates: Vec<(String, u32, Update)>, + updates: Vec<(String, u32, Update)>, } -impl Default for Updates { +impl Default for Updates { fn default() -> Self { Self { #[cfg(feature = "timings")] @@ -607,10 +504,10 @@ impl Default for Updates { } } -impl Updates { - pub(crate) fn update(&mut self, scene_contents: &mut C) -> Result<()> { +impl Updates { + pub(crate) fn update(&mut self, world: &mut World) -> Result<()> { #[cfg(feature = "timings")] - if let Some(timings) = self.timings.check_timing(scene_contents.now(), None) { + if let Some(timings) = self.timings.check_timing(world.now(), None) { if !timings.is_empty() { println!("timings: {:#?}", timings); } @@ -627,10 +524,10 @@ impl Updates { match update { Update::Single(archetype) => { - archetype.execute(scene_contents)?; + archetype.execute(world)?; } Update::Pair(archetype_pair) => { - archetype_pair.execute(scene_contents)?; + archetype_pair.execute(world)?; } } @@ -645,8 +542,8 @@ impl Updates { pub(crate) fn add_entity( &mut self, - entity_object: &EntityObject, - entities: &IndexMap>, + entity_object: &EntityObject, + entities: &IndexMap, ) -> Result<()> { for (_, _, update) in self.updates.iter_mut() { match update { @@ -682,18 +579,7 @@ impl Updates { self.timings.clear(); } - pub(crate) fn add( - &mut self, - name: &str, - priority: u32, - mut update: Update, - entities: &IndexMap>, - ) -> Result<()> { - match &mut update { - Update::Single(archetype) => archetype.setup(entities)?, - Update::Pair(archetype_pair) => archetype_pair.setup(entities)?, - } - + pub(crate) fn add(&mut self, name: &str, priority: u32, update: Update) -> Result<()> { #[cfg(feature = "timings")] self.timings.add_timing_afterwards(name); diff --git a/ecs/src/world.rs b/ecs/src/world.rs index ffbc971..2404dcd 100644 --- a/ecs/src/world.rs +++ b/ecs/src/world.rs @@ -1,21 +1,330 @@ +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::*; +use crate::{entity_object_manager::EntityObjectManager, *}; -pub struct World { - pub(crate) updates: Updates, - pub(crate) events: Events, - pub(crate) resources: Resources, - pub(crate) entities: IndexMap>, +pub struct WorldBuilder { + pub(crate) updates: Updates, + pub events: Events, + pub resources: Resources, } -impl Default for World { - fn default() -> Self { - Self { - updates: Updates::default(), - events: Events::default(), - resources: Resources::default(), - entities: IndexMap::default(), +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(), + } + } +} + +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, +} + +impl World { + pub fn builder() -> WorldBuilder { + WorldBuilder { + updates: Default::default(), + events: Default::default(), + resources: Default::default(), + } + } + + pub fn new_entity(&mut self) -> EntityObject { + self.entity_object_manager.create_entity() + } + + pub fn now(&self) -> Duration { + self.start_time.elapsed() + } + + 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<()> { + loop { + 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()?; } } } diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 485eb2d..28a4dcd 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -25,6 +25,7 @@ scene_update_macros = { path = "../scene_update_macros" } 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/assets/assetmanager.rs b/engine/src/assets/assetmanager.rs index c4907ff..4b1a2bd 100644 --- a/engine/src/assets/assetmanager.rs +++ b/engine/src/assets/assetmanager.rs @@ -1,4 +1,3 @@ -use super::entity_object_manager::EntityObjectManager; use crate::prelude::*; use anyhow::Result; diff --git a/engine/src/assets/entity_object_manager.rs b/engine/src/assets/entity_object_manager.rs deleted file mode 100644 index aaae548..0000000 --- a/engine/src/assets/entity_object_manager.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; - -use crate::prelude::EntityObject; - -#[derive(Default)] -pub struct EntityObjectManager { - current_entity_id: AtomicU32, -} - -impl EntityObjectManager { - pub(crate) fn fetch_add_entity_id(&self) -> u32 { - self.current_entity_id.fetch_add(1, SeqCst) - } - - pub(crate) fn create_entity(&self) -> EntityObject { - EntityObject::new(self.fetch_add_entity_id()) - } -} diff --git a/engine/src/assets/mod.rs b/engine/src/assets/mod.rs index 93cbb2f..cd2e396 100644 --- a/engine/src/assets/mod.rs +++ b/engine/src/assets/mod.rs @@ -1,9 +1,6 @@ pub mod assetcache; - pub mod assetmanager; -pub mod entity_object_manager; - use std::{collections::HashMap, path::Path}; use anyhow::Result; diff --git a/engine/src/engine/asset_handler.rs b/engine/src/engine/asset_handler.rs index 2430d4c..51b748d 100644 --- a/engine/src/engine/asset_handler.rs +++ b/engine/src/engine/asset_handler.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, RwLock}; use crate::assets::assetmanager::AssetManager; -use crate::{assets::entity_object_manager::EntityObjectManager, prelude::*}; +use crate::prelude::*; use anyhow::Result; diff --git a/engine/src/engine/engine.rs b/engine/src/engine/engine.rs index e034f7c..14af51d 100644 --- a/engine/src/engine/engine.rs +++ b/engine/src/engine/engine.rs @@ -11,7 +11,6 @@ use context::prelude::cgmath::vec3; use loading_screen::LoadingScreen; use crate::assets::assetmanager::AssetManager; -use crate::assets::entity_object_manager::EntityObjectManager; use crate::prelude::*; use std::sync::{Arc, RwLock, RwLockReadGuard}; diff --git a/engine/src/prelude.rs b/engine/src/prelude.rs index b5b7b50..860bd66 100644 --- a/engine/src/prelude.rs +++ b/engine/src/prelude.rs @@ -24,6 +24,7 @@ pub use serde::{ ser::{SerializeMap, SerializeSeq, SerializeStruct}, }; +pub use ecs::*; pub use ron; pub use crate::assets::assetcache::AssetCache; diff --git a/engine/src/scene/content/components/animation.rs b/engine/src/scene/content/components/animation.rs index d2679f8..60ae59d 100644 --- a/engine/src/scene/content/components/animation.rs +++ b/engine/src/scene/content/components/animation.rs @@ -175,7 +175,7 @@ impl Clone for Animation { impl EntityComponent for Animation { fn name(&self) -> &str { - "Animation" + Self::debug_name() } } diff --git a/engine/src/scene/content/components/audio.rs b/engine/src/scene/content/components/audio.rs index b215c7f..81ff832 100644 --- a/engine/src/scene/content/components/audio.rs +++ b/engine/src/scene/content/components/audio.rs @@ -164,11 +164,11 @@ impl EntityComponent for Audio { Self::debug_name() } - fn enable(&mut self, _scene: &mut Scene) -> Result<()> { + fn enable(&mut self, _world: &mut World) -> Result<()> { self.play(ON_ENABLE_SOUND, false) } - fn disable(&mut self, _scene: &mut Scene) -> Result<()> { + fn disable(&mut self, _world: &mut World) -> Result<()> { self.play(ON_DISABLE_SOUND, false) } } diff --git a/engine/src/scene/content/components/bounding_box.rs b/engine/src/scene/content/components/bounding_box.rs index 01f47ff..1524fd3 100644 --- a/engine/src/scene/content/components/bounding_box.rs +++ b/engine/src/scene/content/components/bounding_box.rs @@ -105,7 +105,7 @@ impl From for BoundingBox { impl EntityComponent for BoundingBox { fn name(&self) -> &str { - "BoundingBox" + Self::debug_name() } } diff --git a/engine/src/scene/content/components/draw.rs b/engine/src/scene/content/components/draw.rs index 2b10856..4f3d759 100644 --- a/engine/src/scene/content/components/draw.rs +++ b/engine/src/scene/content/components/draw.rs @@ -118,7 +118,7 @@ impl Index for Draw { impl EntityComponent for Draw { fn name(&self) -> &str { - "Draw" + Self::debug_name() } } diff --git a/engine/src/scene/content/components/particle_system.rs b/engine/src/scene/content/components/particle_system.rs index b5b37b9..3449989 100644 --- a/engine/src/scene/content/components/particle_system.rs +++ b/engine/src/scene/content/components/particle_system.rs @@ -2,7 +2,7 @@ use crate::prelude::*; use asset::*; -use utilities::prelude::cgmath::{vec3, Deg, InnerSpace, Matrix4}; +use utilities::prelude::cgmath::{Deg, InnerSpace, Matrix4, vec3}; use std::sync::{Arc, Mutex, MutexGuard}; @@ -138,7 +138,7 @@ impl ParticleSystemInfoBuffer { pub struct ParticleSystemVulkanObjects { descriptor_set_layout: Arc, - pipeline: Arc, + pub(crate) pipeline: Arc, command_buffer: Arc, @@ -251,7 +251,7 @@ impl ParticleSystem { pub fn new( info: ParticleSystemInfo, engine: &Engine, - scene: &impl SceneEntities, + scene: &Scene, draw: &mut Draw, ) -> Result { Self::_new( @@ -410,12 +410,12 @@ impl ParticleSystem { pub(crate) fn animate( &self, recorder: &mut CommandBufferRecorder<'_>, - scene: &SceneContents<'_>, - time: Duration, + pipeline: &Arc, + world: &World, ) -> Result<()> { - recorder.bind_pipeline(&scene.particle_system_vulkan_objects().pipeline)?; + recorder.bind_pipeline(pipeline)?; recorder.bind_descriptor_sets_minimal(&[&self.descriptor_set]); - recorder.push_constants(VK_SHADER_STAGE_COMPUTE_BIT, &time.as_secs_f32()); + recorder.push_constants(VK_SHADER_STAGE_COMPUTE_BIT, &world.now().as_secs_f32()); recorder.dispatch(self.particle_buffer.size() as u32, 1, 1); recorder.buffer_barrier( @@ -565,8 +565,8 @@ impl ParticleSystem { } impl EntityComponent for ParticleSystem { - fn enable(&mut self, scene: &mut Scene) -> Result<()> { - let now = scene.now(); + fn enable(&mut self, world: &mut World) -> Result<()> { + let now = world.now(); self.start = now; // Copy gpu only buffer into temporary cpu buffer to modify starting time @@ -574,15 +574,15 @@ impl EntityComponent for ParticleSystem { { let now_f32 = now.as_secs_f32(); - let fence = Fence::builder().build(scene.device().clone())?; + let fence = Fence::builder().build(world.device().clone())?; let command_buffer = CommandBuffer::new_primary() - .build(scene.device().clone(), scene.queue().clone())?; + .build(world.device().clone(), world.queue().clone())?; let cpu_buffer: Arc> = Buffer::builder() .set_memory_usage(MemoryUsage::GpuToCpu) .set_usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT) .set_size(self.particle_buffer.size()) - .build(scene.device().clone())?; + .build(world.device().clone())?; { let mut recorder = command_buffer.begin(VkCommandBufferBeginInfo::new( @@ -602,12 +602,12 @@ impl EntityComponent for ParticleSystem { // submit let submit = SubmitInfo::default().add_command_buffer(&command_buffer); - scene + world .queue() .lock() .unwrap() .submit(Some(&fence), &[submit])?; - scene + world .device() .wait_for_fences(&[&fence], true, Duration::from_secs(1))?; @@ -653,12 +653,12 @@ impl EntityComponent for ParticleSystem { // submit let submit = SubmitInfo::default().add_command_buffer(&command_buffer); - scene + world .queue() .lock() .unwrap() .submit(Some(&fence), &[submit])?; - scene + world .device() .wait_for_fences(&[&fence], true, Duration::from_secs(1))?; } @@ -667,7 +667,7 @@ impl EntityComponent for ParticleSystem { } fn name(&self) -> &str { - "ParticleSystem" + Self::debug_name() } } diff --git a/engine/src/scene/content/mod.rs b/engine/src/scene/content/mod.rs index e343be4..137f4d4 100644 --- a/engine/src/scene/content/mod.rs +++ b/engine/src/scene/content/mod.rs @@ -2,4 +2,4 @@ pub mod components; pub mod map; pub mod prelude; -mod query; +// mod query; diff --git a/engine/src/scene/content/prelude.rs b/engine/src/scene/content/prelude.rs index 2a838ad..b320b94 100644 --- a/engine/src/scene/content/prelude.rs +++ b/engine/src/scene/content/prelude.rs @@ -9,4 +9,4 @@ pub use super::components::{ particle_system::*, }; -pub use super::query::SceneQuery; +// pub use super::query::SceneQuery; diff --git a/engine/src/scene/content/query.rs b/engine/src/scene/content/query.rs index a2dbf11..81db097 100644 --- a/engine/src/scene/content/query.rs +++ b/engine/src/scene/content/query.rs @@ -87,64 +87,64 @@ macro_rules! impl_add_query { } - impl< 'a, $( $var, )+ > CheckEntity< ( $( $var, )+ ) > for Entities<'a> - where - $( - $var: EntityComponent + ComponentDebug, - )+ - { - fn check_entity(entity: &EntityObject) -> bool - where - Filter: CheckFilter, - { - let filter = Filter::default(); + // impl< 'a, $( $var, )+ > CheckEntity< ( $( $var, )+ ) > for Entities<'a> + // where + // $( + // $var: EntityComponent + ComponentDebug, + // )+ + // { + // fn check_entity(entity: &EntityObject) -> bool + // where + // Filter: CheckFilter, + // { + // let filter = Filter::default(); - $( - filter.verify_dedup::<$var>(); - )+ + // $( + // filter.verify_dedup::<$var>(); + // )+ - $( - if !entity.components.contains::<$var>() { - return false; - } - )+ + // $( + // if !entity.components.contains::<$var>() { + // return false; + // } + // )+ - if !filter.check(entity) { - return false; - } + // if !filter.check(entity) { + // return false; + // } - true - } - } + // true + // } + // } - impl<'a, $( $var, )+ F > SceneQuery<'a, ( $( &'a $var, )+ ), F > for Entities<'a> - where - $( - $var: EntityComponent + ComponentDebug, - )+ - Self: CheckEntity<( $( $var, )+ )>, - F: FnMut(Entity, $( &'a $var, )+) -> Result<()>, - { - fn query(&'a self, mut f: F) -> Result<()> - where - Filter: CheckFilter, - { - paste::paste! { - self.entities.iter().filter_map(|(entity, object)| { - if Self::check_entity::(object) { - $( - let [< $var:lower >] = object.get_component::<$var>().unwrap(); - )+ + // impl<'a, $( $var, )+ F > SceneQuery<'a, ( $( &'a $var, )+ ), F > for Entities<'a> + // where + // $( + // $var: EntityComponent + ComponentDebug, + // )+ + // Self: CheckEntity<( $( $var, )+ )>, + // F: FnMut(Entity, $( &'a $var, )+) -> Result<()>, + // { + // fn query(&'a self, mut f: F) -> Result<()> + // where + // Filter: CheckFilter, + // { + // paste::paste! { + // self.entities.iter().filter_map(|(entity, object)| { + // if Self::check_entity::(object) { + // $( + // let [< $var:lower >] = object.get_component::<$var>().unwrap(); + // )+ - Some(( entity, $( [< $var:lower >], )+ )) - } else { - None - } - }) - .try_for_each(|( entity, $( [< $var:lower >], )+ )| f( *entity, $( [< $var:lower >], )+ )) - } - } - } + // Some(( entity, $( [< $var:lower >], )+ )) + // } else { + // None + // } + // }) + // .try_for_each(|( entity, $( [< $var:lower >], )+ )| f( *entity, $( [< $var:lower >], )+ )) + // } + // } + // } }; } diff --git a/engine/src/scene/rendering/shared/shadercompiler.rs b/engine/src/scene/rendering/shared/shadercompiler.rs index 945e8de..c73e611 100644 --- a/engine/src/scene/rendering/shared/shadercompiler.rs +++ b/engine/src/scene/rendering/shared/shadercompiler.rs @@ -9,6 +9,20 @@ use std::sync::Arc; pub const SHADER_OPTION_COUNT: usize = 9; +#[macro_export] +macro_rules! include_shader { + ($path: expr) => {{ + let shader = include_str!($path); + let file_name = std::path::Path::new($path) + .file_name() + .unwrap() + .to_str() + .unwrap(); + + (shader, file_name) + }}; +} + pub enum ShadersType { Graphics( Arc>, @@ -56,10 +70,10 @@ pub struct ShaderCompiler<'a> { } impl<'a> ShaderCompiler<'a> { - pub fn new(files: Vec<(&'a str, &'a str)>) -> Result> { + pub fn new(files: impl IntoIterator) -> Result> { Ok(ShaderCompiler { compiler: Self::create_compiler()?, - files, + files: files.into_iter().collect(), }) } diff --git a/engine/src/scene/scene/mod.rs b/engine/src/scene/scene/mod.rs index 8fbca3e..fe85c47 100644 --- a/engine/src/scene/scene/mod.rs +++ b/engine/src/scene/scene/mod.rs @@ -1,4 +1,4 @@ pub mod prelude; mod scene_base; -mod scene_content; +// mod scene_content; diff --git a/engine/src/scene/scene/prelude.rs b/engine/src/scene/scene/prelude.rs index 641a749..efe1dcf 100644 --- a/engine/src/scene/scene/prelude.rs +++ b/engine/src/scene/scene/prelude.rs @@ -1,2 +1,2 @@ pub use super::scene_base::Scene; -pub use super::scene_content::{ContentEvents, Entities, SceneContents, SceneEntities}; +// pub use super::scene_content::{ContentEvents, Entities, SceneContents, SceneEntities}; diff --git a/engine/src/scene/scene/scene_base.rs b/engine/src/scene/scene/scene_base.rs index 6010e6a..0ea1a63 100644 --- a/engine/src/scene/scene/scene_base.rs +++ b/engine/src/scene/scene/scene_base.rs @@ -1,74 +1,29 @@ -use crate::scene::content::events::Events; -use crate::scene::rendering::rasterizer::deferred::Rasterizer; -use crate::scene::rendering::rasterizer::traditional::TraditionalRasterizer; -use crate::scene::rendering::raytracer::hardwareraytracer::HardwareRayTracer; -use crate::scene::rendering::raytracer::raytracer::RayTracer; -use crate::scene::rendering::raytracer::softwareraytracer::SoftwareRayTracer; -use crate::scene::rendering::shared::shadercompiler::{ShaderCompiler, ShaderTypeConverter}; -use crate::{prelude::*, scene::content::updates::Updates}; - -use crate::scene::content::entity::EntityObject; - -use crate::scene::rendering::{ExtensionCheck, RenderingFrontEnd}; +use crate::scene::rendering::{ + ExtensionCheck, RenderingFrontEnd, + rasterizer::{deferred::Rasterizer, traditional::TraditionalRasterizer}, + raytracer::{ + hardwareraytracer::HardwareRayTracer, raytracer::RayTracer, + softwareraytracer::SoftwareRayTracer, + }, + shared::shadercompiler::{ShaderCompiler, ShaderTypeConverter}, +}; +use crate::{include_shader, prelude::*}; #[cfg(feature = "timings")] use super::super::timings::Timings; -use super::scene_content::EntityNotFoundError; - -use utilities::prelude::cgmath::{vec3, Matrix4, Vector3}; - -use anyhow::{bail, Error, Result}; - -use indexmap::IndexMap; +use anyhow::Result; +use ecs::*; use rayon::prelude::*; - -use std::any::{Any, TypeId}; +use utilities::prelude::cgmath::{Matrix4, Vector3, vec3}; use std::sync::Mutex; use std::time::Instant; #[cfg(feature = "timings")] use std::time::Instant; -use std::{collections::HashSet, mem, time::Duration}; -use std::{ptr::NonNull, sync::Arc}; - -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)), - } - } -} +use std::sync::Arc; +use std::time::Duration; pub struct Scene { screen_width: f32, @@ -79,12 +34,6 @@ pub struct Scene { pub(crate) render_type: SceneType, - pub(crate) updates: Updates, - pub(crate) archetypes: Archetypes, - pub(crate) events: Events, - pub resources: Resources, - - pub(crate) entities: IndexMap, pub(crate) map: Option>, pub(crate) start_time: Instant, @@ -117,7 +66,8 @@ impl Scene { rasterizer_info: RasterizerInfo, raytracer_info: RaytracingInfo, graphics_info: GraphicsInfo, - ) -> Result { + world: &mut WorldBuilder, + ) -> Result<()> { let (renderer, render_type): (Box, SceneType) = Self::create_rendering_front_end( device, @@ -129,9 +79,8 @@ impl Scene { graphics_info, )?; - let compiler = ShaderCompiler::new(vec![( - include_str!("../content/components/particle_system.comp"), - "particle_system.comp", + let compiler = ShaderCompiler::new([include_shader!( + "../content/components/particle_system.comp" )])?; let cs = compiler.compile::<_, 0>(device, &[], |_| {})?; @@ -146,12 +95,6 @@ impl Scene { device: device.clone(), queue: queue.clone(), - - updates: Updates::default(), - archetypes: Archetypes::default(), - events: Events::default(), - resources: Resources::default(), - entities: IndexMap::new(), map: None, frustum_check: None, @@ -174,22 +117,15 @@ impl Scene { .add_timing("renderer"), }; - scene.insert_default_updates()?; + Self::insert_default_updates(world)?; + world.resources.insert(scene); - Ok(scene) + Ok(()) } } // object handling impl Scene { - #[inline] - fn _entity_mut( - entities: &mut IndexMap, - entity: Entity, - ) -> Option<&mut EntityObject> { - entities.get_mut(&entity) - } - pub fn set_map(&mut self, map_opt: Option>) -> Result<()> { if let Some(old_map) = self.map.take() { old_map.disable(self)?; @@ -199,150 +135,6 @@ impl Scene { Ok(()) } - - pub fn clear_content(&mut self) -> Result<()> { - let mut entities = IndexMap::new(); - mem::swap(&mut self.entities, &mut entities); - - for (_, entity) in entities.iter_mut() { - for (_, component) in entity.components.iter_mut() { - component.disable(self)?; - } - } - - self.map = None; - self.updates.clear(); - self.archetypes.clear(); - self.events.clear(); - - self.insert_default_updates()?; - - Ok(()) - } - - pub fn view_resource(&mut self) -> (&mut View, &mut Resources) { - (self.renderer.view_mut(), &mut self.resources) - } -} - -impl Scene { - pub fn add_archetype(&mut self, id: impl ToString, mut archetype: Archetype) -> Result<()> { - archetype.setup(&self.entities)?; - self.archetypes.insert(id.to_string(), archetype); - - Ok(()) - } - - pub fn register_event(&mut self) { - self.events.register_event::(); - } - - pub fn add_event_reader(&mut self, f: F) - where - F: Fn(&mut SceneContents<'_>, &T) -> anyhow::Result<()> + Send + Sync + 'static, - { - self.events.add_reader(f); - } - - pub fn write_event(&mut self, payload: T) { - self.events.write_event(payload); - } - - pub fn as_scene_contents(&mut self) -> SceneContents<'_> { - SceneContents::new( - &self.device, - &self.queue, - self.render_type, - self.frame_time, - self.start_time, - (self.screen_width, self.screen_height), - &mut self.entities, - &self.map, - (&mut self.renderer, &mut self.particle_system_vulkan_objects), - &self.archetypes, - &mut self.events, - &mut self.resources, - ) - } - - pub(crate) fn update(&mut self) -> Result<()> { - let mut temp_events = self.events.clone_from_register(); - - let mut scene_content = SceneContents::new( - &self.device, - &self.queue, - self.render_type, - self.frame_time, - self.start_time, - (self.screen_width, self.screen_height), - &mut self.entities, - &self.map, - (&mut self.renderer, &mut self.particle_system_vulkan_objects), - &self.archetypes, - &mut temp_events, - &mut self.resources, - ); - - #[cfg(feature = "timings")] - let before = Instant::now(); - - self.events.fire_events(&mut scene_content)?; - - #[cfg(feature = "timings")] - self.timings - .add("fire events", Instant::now().duration_since(before)); - - #[cfg(feature = "timings")] - let before = Instant::now(); - - self.updates.update(&mut scene_content)?; - - #[cfg(feature = "timings")] - self.timings - .add("updates", Instant::now().duration_since(before)); - - #[cfg(feature = "timings")] - let before = Instant::now(); - - self.events.move_events(scene_content.events.events); - - #[cfg(feature = "timings")] - self.timings - .add("move events", Instant::now().duration_since(before)); - - #[cfg(feature = "timings")] - let before = Instant::now(); - - scene_content.entity_changes().commit(self)?; - - #[cfg(feature = "timings")] - self.timings - .add("entity changes", Instant::now().duration_since(before)); - - Ok(()) - } - - pub fn execute_archetype(&mut self, name: impl ToString) -> Result<()> { - let mut scene_content = SceneContents::new( - &self.device, - &self.queue, - self.render_type, - self.frame_time, - self.start_time, - (self.screen_width, self.screen_height), - &mut self.entities, - &self.map, - (&mut self.renderer, &mut self.particle_system_vulkan_objects), - &self.archetypes, - &mut self.events, - &mut self.resources, - ); - - self.archetypes - .execute(&name.to_string(), &mut scene_content)?; - - scene_content.entity_changes().commit(self) - } } impl Scene { @@ -368,31 +160,26 @@ impl Scene { Ok((x, y)) } - pub(crate) fn insert_default_updates(&mut self) -> Result<()> { - self.add_update( + pub(crate) fn insert_default_updates(world: &mut WorldBuilder) -> Result<()> { + world.add_update( "animate", 5_500_000, - |scene_contents: &mut SceneContents<'_>, - _entity, - draw: &mut Draw, - animation: &mut Animation| { - animation.animate(scene_contents.now(), draw)?; + |world: &mut World, _entity, draw: &mut Draw, animation: &mut Animation| { + animation.animate(world.now(), draw)?; Ok(()) }, EmptyFilter, )?; - self.add_update( + world.add_update( "particle_system", 5_000_000, - |scene_contents: &mut SceneContents<'_>, - entity, - particle_system: &mut ParticleSystem| { - let now = scene_contents.now(); + |world: &mut World, entity, particle_system: &mut ParticleSystem| { + let now = world.now(); if !particle_system.update(now) { - scene_contents.remove_entity(entity)?; + world.remove_entity(entity)?; return Ok(()); } @@ -402,13 +189,12 @@ impl Scene { VkCommandBufferBeginInfo::new(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); begin_info.set_inheritance_info(&inheritance_info); - let unsafe_scene = unsafe { remove_life_time_mut(scene_contents) }; + let scene = world.resources.get_mut::(); - let mut recorder = scene_contents - .particle_system_vulkan_objects_mut() - .begin(begin_info)?; + let particle_handles = scene.particle_system_vulkan_objects_mut(); + let mut recorder = particle_handles.begin(begin_info)?; - particle_system.animate(&mut recorder, unsafe_scene, now)?; + particle_system.animate(&mut recorder, &particle_handles.pipeline, world)?; } Ok(()) @@ -616,7 +402,7 @@ impl Scene { let frustum = view.frustum(); let planes = frustum.planes(); - let content: Vec> = self + let content: Vec>> = self .entities .par_values() .map(|entity_object| { @@ -652,199 +438,8 @@ impl Scene { Ok(()) } -} -impl SceneEntities for Scene { - fn device(&self) -> &Arc { - &self.device - } - - fn queue(&self) -> &Arc> { - &self.queue - } - - fn entity(&self, entity: Entity) -> std::result::Result<&EntityObject, EntityNotFoundError> { - self.entities - .get(&entity) - .ok_or_else(|| EntityNotFoundError::new(entity)) - } - - fn entity_mut( - &mut self, - entity: Entity, - ) -> std::result::Result<&mut EntityObject, EntityNotFoundError> { - self.entities - .get_mut(&entity) - .ok_or_else(|| EntityNotFoundError::new(entity)) - } - - fn entities_multi_mut(&mut self) -> EntityMultiMut<'_> { - EntityMultiMut::new(&mut self.entities) - } - - 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)?; - self.archetypes.add_entity(&mut entity)?; - assert!(self.entities.insert(e, entity).is_none()); - - Ok(e) - } - - fn entity_resource(&mut self, entity: Entity) -> Result<(&mut Resources, &mut EntityObject)> { - Ok(( - unsafe { remove_life_time_mut(&mut self.resources) }, - self.entity_mut(entity)?, - )) - } - - fn archetype_info(&self, name: impl ToString) -> Result { - let name = name.to_string(); - let archetype = self - .archetypes - .get(&name) - .ok_or_else(|| Error::msg(format!("requested archetype ({}) not found", name)))?; - - let mut entities = Vec::new(); - - for entity in archetype.entities().keys() { - #[cfg(debug_assertions)] - let debug_name = self.entity(*entity)?.debug_name.clone(); - - #[cfg(not(debug_assertions))] - let debug_name = None; - - entities.push((*entity, debug_name)); - } - - Ok(ArchetypeInfo::new(entities)) - } - - 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); - self.archetypes.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)?; - self.archetypes.add_entity(entity_object)?; - - 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); - self.archetypes.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)?; - self.archetypes.add_entity(entity_object)?; - - Ok(()) - } - - fn write_event(&mut self, payload: T) { - self.write_event(payload); - } - - 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); - self.archetypes.remove_entity(entity); - - return Ok(Some(entity_object)); - } - - Ok(None) - } - - // This function will panic if map is not set! - fn map(&mut self, f: F) -> Result - where - F: FnOnce(&Box, &mut SceneContents<'_>) -> Result, - { - let map = self - .map - .as_ref() - .expect("Map is not set while trying to call map"); - let p = map as *const Box as *mut Box; - - let mut scene_content = SceneContents::new( - &self.device, - &self.queue, - self.render_type, - self.frame_time, - self.start_time, - (self.screen_width, self.screen_height), - &mut self.entities, - &self.map, - (&mut self.renderer, &mut self.particle_system_vulkan_objects), - &self.archetypes, - &mut self.events, - &mut self.resources, - ); - - let result = f( - unsafe { NonNull::new_unchecked(p).as_ref() }, - &mut scene_content, - )?; - - scene_content.entity_changes().commit(self)?; - - Ok(result) - } - - fn now(&self) -> Duration { - Instant::now().duration_since(self.start_time) - } - - fn world_to_screen_space(&self, world_space: Vector3) -> Result<(i32, i32)> { + pub fn world_to_screen_space(&self, world_space: Vector3) -> Result<(i32, i32)> { Self::_world_to_screen_space( (self.screen_width, self.screen_height), world_space, @@ -852,48 +447,48 @@ impl SceneEntities for Scene { ) } - fn screen_space_to_world(&self, x: u32, y: u32) -> Result>> { + pub fn screen_space_to_world(&self, x: u32, y: u32) -> Result>> { let scale = self.renderer.render_scale(); self.renderer .screen_to_world((x as f32 * scale) as u32, (y as f32 * scale) as u32) } - fn particle_system_vulkan_objects_mut(&mut self) -> &mut ParticleSystemVulkanObjects { + pub fn particle_system_vulkan_objects_mut(&mut self) -> &mut ParticleSystemVulkanObjects { &mut self.particle_system_vulkan_objects } - fn particle_system_vulkan_objects(&self) -> &ParticleSystemVulkanObjects { + pub fn particle_system_vulkan_objects(&self) -> &ParticleSystemVulkanObjects { &self.particle_system_vulkan_objects } - fn add_light(&mut self, light: Light) -> Result<()> { + pub fn add_light(&mut self, light: Light) -> Result<()> { self.renderer.add_light(light)?; Ok(()) } - fn remove_light(&mut self, light: Light) -> Result<()> { + pub fn remove_light(&mut self, light: Light) -> Result<()> { self.renderer.remove_light(light)?; Ok(()) } - fn clear_lights(&mut self) -> Result<()> { + pub fn clear_lights(&mut self) -> Result<()> { self.renderer.clear_lights()?; Ok(()) } - fn view_mut(&mut self) -> &mut View { + pub fn view_mut(&mut self) -> &mut View { self.renderer.view_mut() } - fn render_type(&self) -> SceneType { + pub fn render_type(&self) -> SceneType { self.render_type } - fn frame_time(&self) -> Duration { + pub fn frame_time(&self) -> Duration { self.frame_time } } diff --git a/engine/src/scene/scene/scene_content.rs b/engine/src/scene/scene/scene_content.rs index 11c05fa..aaf8ecd 100644 --- a/engine/src/scene/scene/scene_content.rs +++ b/engine/src/scene/scene/scene_content.rs @@ -8,7 +8,7 @@ use std::{ use utilities::prelude::cgmath::Vector3; -use anyhow::{bail, Error, Result}; +use anyhow::{Error, Result, bail}; use indexmap::IndexMap; use crate::scene::{content::events::Events, rendering::RenderingFrontEnd}; @@ -17,25 +17,6 @@ use crate::prelude::*; use super::scene_base::EntityMultiMut; -#[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 {} - pub trait SceneEntities { fn device(&self) -> &Arc; fn queue(&self) -> &Arc>; diff --git a/examples/simple_window/Cargo.toml b/examples/simple_window/Cargo.toml new file mode 100644 index 0000000..c833f43 --- /dev/null +++ b/examples/simple_window/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "simple_window" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow.workspace = true + +ecs = { path = "../../ecs" } diff --git a/examples/simple_window/src/main.rs b/examples/simple_window/src/main.rs new file mode 100644 index 0000000..2c71064 --- /dev/null +++ b/examples/simple_window/src/main.rs @@ -0,0 +1,9 @@ +use anyhow::Result; +use ecs::*; + +fn main() -> Result<()> { + let mut world_builder = World::builder(); + // world_builder. + + world_builder.build().run() +}