diff options
Diffstat (limited to 'ecs/src/lib.rs')
| -rw-r--r-- | ecs/src/lib.rs | 750 |
1 files changed, 0 insertions, 750 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs deleted file mode 100644 index 3caaa6b..0000000 --- a/ecs/src/lib.rs +++ /dev/null @@ -1,750 +0,0 @@ -#![deny(clippy::all, clippy::pedantic)] - -use std::any::{type_name, TypeId}; -use std::cell::RefCell; -use std::fmt::Debug; -use std::mem::ManuallyDrop; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use hashbrown::HashMap; - -use crate::actions::Action; -use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComponent; -use crate::component::storage::Storage as ComponentStorage; -use crate::component::{Component, Sequence as ComponentSequence}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::Kind as ComponentEventKind; -use crate::extension::{Collector as ExtensionCollector, Extension}; -use crate::lock::{Lock, WriteGuard}; -use crate::phase::{Phase, START as START_PHASE}; -use crate::query::flexible::Query as FlexibleQuery; -use crate::query::term::Without; -use crate::query::{ - Iter as QueryIter, - TermWithFieldTuple as QueryTermWithFieldTuple, - TermWithoutFieldTuple as QueryTermWithoutFieldTuple, - Terms as QueryTerms, - TermsBuilderInterface, -}; -use crate::relationship::{ChildOf, DependsOn, Relationship}; -use crate::sole::Sole; -use crate::stats::Stats; -use crate::system::{System, SystemComponent}; -use crate::type_name::TypeName; -use crate::uid::{Kind as UidKind, Uid}; - -pub mod actions; -pub mod component; -pub mod entity; -pub mod event; -pub mod extension; -pub mod lock; -pub mod phase; -pub mod query; -pub mod relationship; -pub mod sole; -pub mod stats; -pub mod system; -pub mod tuple; -pub mod type_name; -pub mod uid; -pub mod util; - -#[doc(hidden)] -pub mod private; - -pub use ecs_macros::{Component, Sole}; - -pub use crate::query::Query; - -#[derive(Debug)] -pub struct World -{ - data: WorldData, - stop: AtomicBool, - is_first_tick: AtomicBool, -} - -impl World -{ - #[must_use] - pub fn new() -> Self - { - let mut world = Self { - data: WorldData::default(), - stop: AtomicBool::new(false), - is_first_tick: AtomicBool::new(false), - }; - - world.add_sole(Stats::default()).ok(); - - for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(&world); - } - - world - } - - /// Creates a new entity with the given components. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. - pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid - where - Comps: ComponentSequence, - { - let entity_uid = Uid::new_unique(UidKind::Entity); - - self.create_entity_with_uid(components, entity_uid); - - entity_uid - } - - #[tracing::instrument(skip_all)] - #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) - where - Comps: ComponentSequence, - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - if let Err(err) = component_storage_lock.create_entity(entity_uid) { - tracing::warn!("Failed to create entity: {err}"); - return; - }; - - Self::add_entity_components( - entity_uid, - components.into_array(), - &mut component_storage_lock, - ); - } - - for added_event_id in Comps::added_event_ids() { - self.emit_event_by_id(added_event_id); - } - } - - /// Adds a globally shared singleton value. - /// - /// # Errors - /// Returns `Err` if this [`Sole`] has already been added. - pub fn add_sole<SoleT>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> - where - SoleT: Sole, - { - self.data.sole_storage.insert(sole) - } - - pub fn register_system<'this, SystemImpl>( - &'this mut self, - phase_euid: Uid, - system: impl System<'this, SystemImpl>, - ) - { - self.create_entity(( - SystemComponent { system: system.into_type_erased() }, - Relationship::<DependsOn, Phase>::new(phase_euid), - )); - } - - pub fn register_observer_system<'this, SystemImpl, Event>( - &'this mut self, - system: impl System<'this, SystemImpl>, - event: Event, - ) where - Event: Component, - { - self.create_entity::<(SystemComponent, Event)>(( - SystemComponent { system: system.into_type_erased() }, - event, - )); - } - - /// Adds a extensions. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. - pub fn add_extension(&mut self, extension: impl Extension) - { - let extension_collector = ExtensionCollector::new(self); - - extension.collect(extension_collector); - } - - pub fn query<FieldTerms, FieldlessTerms>(&self) -> Query<FieldTerms, FieldlessTerms> - where - FieldTerms: QueryTermWithFieldTuple, - FieldlessTerms: QueryTermWithoutFieldTuple, - { - Query::new(self) - } - - pub fn flexible_query<'terms>( - &self, - terms: QueryTerms<'terms>, - ) -> FlexibleQuery<'_, 'terms> - { - FlexibleQuery::new(self, terms) - } - - /// Performs a single tick. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn step(&self) -> StepResult - { - if self.stop.load(Ordering::Relaxed) { - return StepResult::Stop; - } - - if self - .is_first_tick - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { - self.query_and_run_systems(*START_PHASE); - } - - self.perform_phases(); - - self.lock_component_storage_rw() - .create_imaginary_archetypes(); - - self.perform_queued_actions(); - - if self.stop.load(Ordering::Relaxed) { - return StepResult::Stop; - } - - let mut stats_lock = self - .data - .sole_storage - .get::<Stats>() - .expect("No stats sole found") - .write_nonblock() - .expect("Failed to aquire read-write stats sole lock"); - - let stats = stats_lock - .downcast_mut::<Stats>() - .expect("Casting stats sole to Stats type failed"); - - stats.current_tick += 1; - - StepResult::Continue - } - - /// Starts a loop which calls [`Self::step`] until the world is stopped. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn start_loop(&self) - { - while let StepResult::Continue = self.step() {} - } - - #[cfg(feature = "vizoxide")] - pub fn create_vizoxide_archetype_graph( - &self, - name: impl AsRef<str>, - ) -> Result<vizoxide::Graph, vizoxide::GraphvizError> - { - use std::borrow::Cow; - - use crate::component::storage::{ - VizoxideArchetypeGraphEdgeKind, - VizoxideArchetypeGraphParams, - }; - - let component_storage_lock = self - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"); - - component_storage_lock.create_vizoxide_archetype_graph( - name, - VizoxideArchetypeGraphParams { - create_node_name: |archetype, _| { - Cow::Owned(format!( - "[{}]", - archetype - .component_ids_sorted() - .into_iter() - .map(|comp_id| comp_id.id().to_string()) - .collect::<Vec<_>>() - .join(", ") - )) - }, - create_node_cb: |_archetype, archetype_metadata, node_builder| { - if archetype_metadata.is_imaginary { - return node_builder.attribute("shape", "ellipse"); - } - - node_builder.attribute("shape", "box") - }, - create_edge_cb: |_, _, edge_kind, edge_builder| { - edge_builder.attribute( - "color", - match edge_kind { - VizoxideArchetypeGraphEdgeKind::Add => "green", - VizoxideArchetypeGraphEdgeKind::Remove => "red", - }, - ) - }, - }, - ) - } - - fn query_and_run_systems(&self, phase_euid: Uid) - { - let system_comps_query = - self.query::<(&SystemComponent, &Relationship<DependsOn, Phase>), ()>(); - - let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { - phase_rel - .target_uids() - .any(|target_uid| target_uid == phase_euid) - }); - - for (system_component, _) in system_iter { - // SAFETY: The world lives long enough - unsafe { - system_component.system.run(self); - } - } - } - - fn perform_child_phases(&self, parent_phase_euid: Uid) - { - let phase_query = self.query::<(&Phase, &Relationship<ChildOf, Phase>), ()>(); - - for (child_phase_euid, (_, phase_rel)) in phase_query.iter_with_euids() { - if !phase_rel - .target_uids() - .any(|phase_euid| phase_euid == parent_phase_euid) - { - continue; - } - - self.query_and_run_systems(child_phase_euid); - self.perform_child_phases(child_phase_euid); - } - } - - fn perform_phases(&self) - { - let phase_query = - self.query::<(&Phase,), (Without<Relationship<ChildOf, Phase>>,)>(); - - for (phase_euid, (_,)) in phase_query.iter_with_euids() { - if phase_euid == *START_PHASE { - continue; - } - - self.query_and_run_systems(phase_euid); - self.perform_child_phases(phase_euid); - } - } - - #[tracing::instrument(skip_all)] - fn perform_queued_actions(&self) - { - let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() - { - ActiveActionQueue::A => &self.data.action_queue.queue_a, - ActiveActionQueue::B => &self.data.action_queue.queue_b, - } - .write_nonblock() - .unwrap_or_else(|err| { - panic!( - "Failed to take read-write action queue lock {:?}: {err}", - self.data.action_queue.active_queue - ); - }); - - let mut has_swapped_active_queue = false; - - for action in active_action_queue.drain(..) { - match action { - Action::Spawn(components, component_added_event_ids) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let new_entity_uid = Uid::new_unique(UidKind::Entity); - - if let Err(err) = - component_storage_lock.create_entity(new_entity_uid) - { - tracing::warn!("Failed to create entity: {err}"); - continue; - }; - - Self::add_entity_components( - new_entity_uid, - components, - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } - } - Action::Despawn(entity_uid) => { - self.despawn_entity(entity_uid, &mut has_swapped_active_queue); - } - Action::AddComponents( - entity_uid, - components, - component_added_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::add_entity_components( - entity_uid, - components, - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - // TODO: Fix that events are emitted for components that haven't been - // added because a error occurred (for example, the entity already has - // the component) - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } - } - Action::RemoveComponents( - entity_uid, - components_metadata, - component_removed_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::remove_entity_components( - entity_uid, - components_metadata - .iter() - .map(|comp_metadata| comp_metadata.id), - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - // TODO: Fix that events are emitted for components that haven't been - // removed because a error occurred (for example, the entity does not - // have the component) - for comp_removed_event_id in component_removed_event_ids.ids { - self.emit_event_by_id(comp_removed_event_id); - } - } - Action::Stop => { - self.stop.store(true, Ordering::Relaxed); - } - } - } - } - - #[tracing::instrument(skip_all)] - fn despawn_entity(&self, entity_uid: Uid, has_swapped_active_queue: &mut bool) - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let removed_entity = match component_storage_lock.remove_entity(entity_uid) { - Ok(components) => components, - Err(err) => { - tracing::error!("Failed to despawn entity: {err}"); - return; - } - }; - - let component_removed_event_uids = removed_entity - .components() - .iter() - .map(|component| { - component - .component() - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-only {} component lock", - component.name() - ) - }) - .get_event_uid(ComponentEventKind::Removed) - }) - .collect::<Vec<_>>(); - - drop(component_storage_lock); - - if !*has_swapped_active_queue { - self.swap_event_queue(has_swapped_active_queue); - } - - for comp_removed_event_id in component_removed_event_uids { - self.emit_event_by_id(comp_removed_event_id); - } - } - - fn add_entity_components( - entity_uid: Uid, - components: impl IntoIterator<Item = (Uid, Box<dyn Component>)>, - component_storage: &mut ComponentStorage, - ) - { - for (component_id, component) in components { - if let Err(err) = component_storage - .add_entity_component(entity_uid, (component_id, component)) - { - tracing::error!("Failed to add component to entity: {err}"); - } - } - } - - fn remove_entity_components( - entity_uid: Uid, - component_ids: impl IntoIterator<Item = Uid>, - component_storage: &mut ComponentStorage, - ) - { - for component_id in component_ids { - if let Err(err) = - component_storage.remove_entity_component(entity_uid, component_id) - { - tracing::error!("Failed to remove component to entity: {err}"); - } - } - } - - fn emit_event_by_id(&self, event_id: Uid) - { - let mut query_required_ids = [SystemComponent::id(), event_id]; - - let query = self.flexible_query( - QueryTerms::builder() - .with_required_ids(&mut query_required_ids) - .build(), - ); - - for (system,) in QueryIter::<(&SystemComponent,), _>::new(self, query.iter()) { - unsafe { - system.system.run(self); - } - } - } - - fn swap_event_queue(&self, has_swapped_active_queue: &mut bool) - { - let mut active_queue = self.data.action_queue.active_queue.borrow_mut(); - - *active_queue = match *active_queue { - ActiveActionQueue::A => ActiveActionQueue::B, - ActiveActionQueue::B => ActiveActionQueue::A, - }; - - *has_swapped_active_queue = true; - } - - fn lock_component_storage_rw(&self) -> WriteGuard<'_, ComponentStorage> - { - self.data - .component_storage - .write_nonblock() - .expect("Failed to acquire read-write component storage lock") - } -} - -impl Default for World -{ - fn default() -> Self - { - Self::new() - } -} - -/// The result of calling [`World::step`]. -pub enum StepResult -{ - /// Another step can be made. - Continue, - - /// The world have been stopped so no step can be made again. - Stop, -} - -#[derive(Debug, Default)] -pub struct WorldData -{ - component_storage: Arc<Lock<ComponentStorage>>, - sole_storage: SoleStorage, - action_queue: Arc<ActionQueue>, -} - -#[derive(Debug)] -pub struct EntityComponentRef<'a> -{ - comp: &'a ArchetypeEntityComponent, -} - -impl<'a> EntityComponentRef<'a> -{ - pub fn component(&self) -> &'a Lock<Box<dyn Component>> - { - self.comp.component() - } - - fn new(comp: &'a ArchetypeEntityComponent) -> Self - { - Self { comp } - } -} - -#[derive(Debug, Default, Clone, Copy)] -enum ActiveActionQueue -{ - #[default] - A, - B, -} - -#[derive(Debug, Default)] -struct ActionQueue -{ - queue_a: Lock<Vec<Action>>, - queue_b: Lock<Vec<Action>>, - active_queue: RefCell<ActiveActionQueue>, -} - -impl ActionQueue -{ - fn push(&self, action: Action) - { - match *self.active_queue.borrow() { - ActiveActionQueue::A => self - .queue_a - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - ActiveActionQueue::B => self - .queue_b - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - } - } -} - -impl TypeName for ActionQueue -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} - -#[derive(Debug, thiserror::Error)] -#[error("Sole {0} already exists")] -pub struct SoleAlreadyExistsError(pub &'static str); - -#[derive(Debug)] -struct StoredSole -{ - sole: Arc<Lock<Box<dyn Sole>>>, - drop_last: bool, -} - -#[derive(Debug, Default)] -struct SoleStorage -{ - storage: HashMap<TypeId, ManuallyDrop<StoredSole>>, -} - -impl SoleStorage -{ - fn get<SoleT: Sole>(&self) -> Option<&Arc<Lock<Box<dyn Sole>>>> - { - self.storage - .get(&TypeId::of::<SoleT>()) - .map(|sole| &sole.sole) - } - - fn insert<SoleT: Sole>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> - { - let sole_type_id = TypeId::of::<SoleT>(); - - if self.storage.contains_key(&sole_type_id) { - return Err(SoleAlreadyExistsError(type_name::<SoleT>())); - } - - let drop_last = sole.drop_last(); - - // TODO: Reconsider this maybe? - #[allow(clippy::arc_with_non_send_sync)] - self.storage.insert( - sole_type_id, - ManuallyDrop::new(StoredSole { - sole: Arc::new(Lock::new(Box::new(sole))), - drop_last, - }), - ); - - Ok(()) - } -} - -impl Drop for SoleStorage -{ - fn drop(&mut self) - { - let mut soles_to_drop_last = Vec::new(); - - for sole in self.storage.values_mut() { - if sole.drop_last { - tracing::trace!( - "Sole {} pushed to dropping last queue", - sole.sole.read_nonblock().unwrap().type_name() - ); - - soles_to_drop_last.push(sole); - continue; - } - tracing::trace!( - "Dropping sole {}", - sole.sole.read_nonblock().unwrap().type_name() - ); - - unsafe { - ManuallyDrop::drop(sole); - } - } - - for sole in &mut soles_to_drop_last { - tracing::trace!( - "Dropping sole {} last", - sole.sole.read_nonblock().unwrap().type_name() - ); - - unsafe { - ManuallyDrop::drop(sole); - } - } - } -} |
