#![deny(clippy::all, clippy::pedantic)] use std::any::{type_name, TypeId}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; use std::mem::ManuallyDrop; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use crate::actions::Action; use crate::component::storage::Storage as ComponentStorage; use crate::component::{Component, Id as ComponentId, Sequence as ComponentSequence}; use crate::entity::Uid as EntityUid; use crate::event::component::{ create_added_id as create_component_added_event_id, create_removed_id as create_component_removed_event_id, ComponentToAddedEvent, }; use crate::event::start::Start as StartEvent; use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence}; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::Lock; use crate::query::options::Options as QueryOptions; use crate::sole::Sole; use crate::system::{System, TypeErased as TypeErasedSystem}; use crate::tuple::Reduce as TupleReduce; use crate::type_name::TypeName; pub mod actions; pub mod component; pub mod entity; pub mod event; pub mod extension; pub mod lock; pub mod query; pub mod relationship; pub mod sole; pub mod system; pub mod tuple; pub mod type_name; mod archetype; mod util; pub use ecs_macros::{Component, Sole}; pub use crate::query::Query; #[derive(Debug, Default)] pub struct World { systems: Vec, data: WorldData, stop: AtomicBool, } impl World { #[must_use] pub fn new() -> Self { Self::default() } /// Creates a new entity with the given components. /// /// # Panics /// Will panic if mutable internal lock cannot be acquired. pub fn create_entity(&mut self, components: Comps) -> EntityUid where Comps: ComponentSequence + TupleReduce, Comps::Out: EventSequence, { let (_, entity_uid) = self .data .component_storage .write_nonblock() .expect("Failed to acquire read-write component storage lock") .push_entity(EntityUid::new_unique(), components.into_vec()); for component_added_event_id in ::ids().iter() { self.emit_event_by_id(*component_added_event_id); } entity_uid } /// Adds a globally shared singleton value. /// /// # Errors /// Returns `Err` if this [`Sole`] has already been added. pub fn add_sole(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> where SoleT: Sole, { self.data.sole_storage.insert(sole) } pub fn register_system<'this, EventT, SystemImpl>( &'this mut self, event: EventT, system: impl System<'this, SystemImpl>, ) where EventT: Event, { self.systems.push(system.into_type_erased()); self.data .events .entry(EventT::id()) .or_default() .push(self.systems.len() - 1); drop(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); } /// Emits a event, running all systems listening to the event for each compatible /// entity. /// /// # Panics /// Will panic if a system has dissapeared. pub fn emit(&self, event: EventT) where EventT: Event, { self.emit_event_by_id(EventT::id()); drop(event); } pub fn query(&self) -> Query where Comps: ComponentSequence, OptionsT: QueryOptions, { Query::new(&self.data.component_storage) } /// Peforms the actions that have been queued up using [`Actions`]. /// /// # Panics /// Will panic if a mutable internal lock cannot be acquired. pub 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) => { let mut component_storage_lock = self.data.component_storage.write_nonblock().expect( "Failed to acquire read-write component storage lock", ); let component_ids = components .iter() .map(|component| component.id()) .collect::>(); component_storage_lock .push_entity(EntityUid::new_unique(), components); drop(component_storage_lock); if !has_swapped_active_queue { 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; } for component_id in component_ids { self.emit_event_by_id(create_component_added_event_id( component_id, )); } } Action::AddComponents(entity_uid, components) => { let mut component_storage_lock = self.data.component_storage.write_nonblock().expect( "Failed to acquire read-write component storage lock", ); let component_ids = components .iter() .map(|component| component.id()) .collect::>(); component_storage_lock .add_components_to_entity(entity_uid, components); drop(component_storage_lock); if !has_swapped_active_queue { 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; } for component_id in component_ids { self.emit_event_by_id(create_component_added_event_id( component_id, )); } } Action::RemoveComponents(entity_uid, components_metadata) => { let mut component_storage_lock = self.data.component_storage.write_nonblock().expect( "Failed to acquire read-write component storage lock", ); component_storage_lock.remove_components_from_entity( entity_uid, components_metadata .iter() .map(|component_metadata| component_metadata.id), ); drop(component_storage_lock); if !has_swapped_active_queue { 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; } for component_metadata in components_metadata { self.emit_event_by_id(create_component_removed_event_id( component_metadata.id, )); } } Action::Stop => { self.stop.store(true, Ordering::Relaxed); } } } } /// A event loop which runs until a stop is issued with [`Flags::stop`]. Before the /// loop begins, [`StartEvent`] is emitted. /// /// # Panics /// Will panic if a internal lock cannot be acquired. pub fn event_loop(&self) { self.emit(StartEvent); let event_seq = EventSeq::ids(); loop { for event_id in event_seq.iter() { self.emit_event_by_id(*event_id); } self.perform_queued_actions(); if self.stop.load(Ordering::Relaxed) { break; } } } fn emit_event_by_id(&self, event_id: EventId) { let Some(system_indices) = self.data.events.get(&event_id) else { return; }; for system_index in system_indices { let system = self.systems.get(*system_index).unwrap(); // SAFETY: The world lives long enough unsafe { system.run(&self); } } } } #[derive(Debug, Default)] pub struct WorldData { events: HashMap>, component_storage: Arc>, sole_storage: SoleStorage, action_queue: Arc, } #[derive(Debug)] #[non_exhaustive] pub struct EntityComponent { pub id: ComponentId, pub name: &'static str, pub component: Lock>, } impl From> for EntityComponent { fn from(component: Box) -> Self { Self { id: component.id(), name: component.type_name(), component: Lock::new(component), } } } #[derive(Debug, Default, Clone, Copy)] enum ActiveActionQueue { #[default] A, B, } #[derive(Debug, Default)] struct ActionQueue { queue_a: Lock>, queue_b: Lock>, active_queue: RefCell, } 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::() } } #[derive(Debug, thiserror::Error)] #[error("Sole {0} already exists")] pub struct SoleAlreadyExistsError(pub &'static str); #[derive(Debug)] struct StoredSole { sole: Arc>>, drop_last: bool, } #[derive(Debug, Default)] struct SoleStorage { storage: HashMap>, } impl SoleStorage { fn get(&self) -> Option<&Arc>>> { self.storage .get(&TypeId::of::()) .map(|sole| &sole.sole) } fn insert(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> { let sole_type_id = TypeId::of::(); if self.storage.contains_key(&sole_type_id) { return Err(SoleAlreadyExistsError(type_name::())); } 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 { #[cfg(feature = "debug")] tracing::debug!( "Sole {} pushed to dropping last queue", sole.sole.read_nonblock().unwrap().type_name() ); soles_to_drop_last.push(sole); continue; } #[cfg(feature = "debug")] tracing::debug!( "Dropping sole {}", sole.sole.read_nonblock().unwrap().type_name() ); unsafe { ManuallyDrop::drop(sole); } } for sole in &mut soles_to_drop_last { #[cfg(feature = "debug")] tracing::debug!( "Dropping sole {} last", sole.sole.read_nonblock().unwrap().type_name() ); unsafe { ManuallyDrop::drop(sole); } } } }