#![deny(clippy::all, clippy::pedantic)] use std::any::{type_name, Any, TypeId}; use std::fmt::Debug; use std::mem::ManuallyDrop; use std::rc::Rc; 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, IntoParts as IntoComponentParts, Parts as ComponentParts, Sequence as ComponentSequence, }; use crate::entity::{Declaration as EntityDeclaration, Handle as EntityHandle}; use crate::event::{Emitted as EmittedEvent, NewEvents, Submitter as EventSubmitter}; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::Lock; use crate::pair::{ChildOf, DependsOn, Pair, Wildcard}; use crate::phase::{Phase, START as START_PHASE}; use crate::query::flexible::Query as FlexibleQuery; use crate::query::term::Without; use crate::query::{ TermWithFieldTuple as QueryTermWithFieldTuple, TermWithoutFieldTuple as QueryTermWithoutFieldTuple, Terms as QueryTerms, TermsBuilderInterface, MAX_TERM_CNT as QUERY_MAX_TERM_CNT, }; use crate::sole::{Single, Sole}; use crate::stats::Stats; use crate::system::observer::{Observer, WrapperComponent as ObserverWrapperComponent}; use crate::system::{Callbacks, Metadata as SystemMetadata, System, SystemComponent}; use crate::uid::{Kind as UidKind, Uid}; pub mod actions; pub mod component; pub mod entity; pub mod event; pub mod extension; pub mod pair; pub mod phase; pub mod query; pub mod sole; pub mod stats; pub mod system; pub mod tuple; pub mod uid; pub mod util; mod lock; 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), }; crate::phase::spawn_entities(&mut world); world.add_sole(Stats::default()).ok(); world } /// Creates a entity with the given components. A new unique [`Uid`] will be generated /// for this entity. pub fn create_entity(&mut self, components: Comps) -> Uid where Comps: ComponentSequence, { let entity_uid = Uid::new_unique(UidKind::Entity); self.create_entity_with_uid(entity_uid, components); entity_uid } /// Creates a entity with the given components. The entity will have the specified /// [`Uid`]. #[tracing::instrument(skip_all)] pub fn create_entity_with_uid(&mut self, entity_uid: Uid, components: Comps) where Comps: ComponentSequence, { self.create_ent(entity_uid, components.into_parts_array()); } pub fn add_component(&mut self, entity_id: Uid, component_parts: ComponentParts) { Self::add_entity_components( entity_id, [component_parts], &mut self.data.component_storage, ); } pub fn create_declared_entity(&mut self, entity_decl: &EntityDeclaration) { entity_decl.create(self); } /// 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_observer<'this, SystemImpl, ObserverT>( &'this mut self, observer: ObserverT, ) where ObserverT: Observer<'this, SystemImpl>, { let (wrapper_comp, mut system_callbacks) = observer.finish_observer(); let ent_id = Uid::new_unique(UidKind::Entity); self.create_ent( ent_id, [wrapper_comp.into_parts()].into_iter().chain( ObserverT::observed_events() .into_iter() .map(IntoComponentParts::into_parts), ), ); system_callbacks.on_created(self, SystemMetadata { ent_id }); } pub fn register_system<'this, SystemImpl>( &'this mut self, phase_euid: Uid, system: impl System<'this, SystemImpl>, ) { let (type_erased_system, mut system_callbacks) = system.finish(); let system_ent_id = self.create_entity(( SystemComponent { system: type_erased_system }, Pair::new::(phase_euid), )); system_callbacks.on_created(self, SystemMetadata { ent_id: system_ent_id }); } /// Adds a extensions. pub fn add_extension(&mut self, extension: impl Extension) { let extension_collector = ExtensionCollector::new(self); extension.collect(extension_collector); } pub fn query( &self, ) -> Query<'_, FieldTerms, FieldlessTerms> where FieldTerms: QueryTermWithFieldTuple, FieldlessTerms: QueryTermWithoutFieldTuple, { Query::new(self) } pub fn flexible_query( &self, terms: QueryTerms, ) -> FlexibleQuery<'_, MAX_TERM_CNT> { FlexibleQuery::new(self, terms) } pub fn get_entity(&self, entity_id: Uid) -> Option> { let archetype = self .data .component_storage .get_entity_archetype(entity_id)?; let Some(entity) = archetype.get_entity_by_id(entity_id) else { unreachable!("Should exist since archetype was found by entity id"); }; Some(EntityHandle::new(archetype, entity, self)) } pub fn get_sole(&self) -> Option> { Some(Single::new(self.data.sole_storage.get::()?)) } pub fn event_submitter(&self) -> EventSubmitter<'_> { EventSubmitter::new(self) } /// Performs a single tick. /// # Panics /// Will panic if mutable internal lock cannot be acquired. pub fn step(&mut 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.emit_new_events(); self.data.component_storage.create_imaginary_archetypes(); self.perform_queued_actions(); if self.stop.load(Ordering::Relaxed) { return StepResult::Stop; } let Some(mut stats) = self.get_sole::() else { unreachable!(); // Reason: is added in World::new }; stats.current_tick += 1; StepResult::Continue } /// Starts a loop which calls [`Self::step`] until the world is stopped. pub fn start_loop(&mut self) { while let StepResult::Continue = self.step() {} } #[cfg(feature = "vizoxide")] pub fn create_vizoxide_archetype_graph( &self, name: impl AsRef, ) -> Result { use std::borrow::Cow; use crate::component::storage::{ VizoxideArchetypeGraphEdgeKind, VizoxideArchetypeGraphParams, }; self.data.component_storage.create_vizoxide_archetype_graph( name, VizoxideArchetypeGraphParams { create_node_name: |archetype, _| { Cow::Owned(format!( "[{}]", archetype .component_ids_sorted() .into_iter() .map(|comp_id| comp_id.to_string()) .collect::>() .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", }, ) }, }, ) } #[tracing::instrument(skip_all)] fn create_ent( &mut self, entity_uid: Uid, components: impl IntoIterator, ) { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); if let Err(err) = self.data.component_storage.create_entity(entity_uid) { tracing::warn!("Failed to create entity: {err}"); return; } Self::add_entity_components( entity_uid, components, &mut self.data.component_storage, ); } fn query_and_run_systems(&self, phase_euid: Uid) { let system_query = Query::<(&SystemComponent,)>::from_flexible_query( self.flexible_query( QueryTerms::::builder() .with_required([ SystemComponent::id(), Pair::new::(phase_euid).id(), ]) .build(), ), ); for (system_ent_id, (system_component,)) in system_query.iter_with_euids() { // SAFETY: The world lives long enough unsafe { system_component .system .run(self, SystemMetadata { ent_id: system_ent_id }); } } } fn perform_child_phases(&self, parent_phase_euid: Uid) { let phase_query = self.flexible_query( QueryTerms::<2>::builder() .with_required([ Phase::id(), Pair::new::(parent_phase_euid).id(), ]) .build(), ); for child_phase_entity in &phase_query { self.query_and_run_systems(child_phase_entity.uid()); self.perform_child_phases(child_phase_entity.uid()); } } fn perform_phases(&self) { let phase_query = self.query::<(&Phase,), (Without>,)>(); for (phase_entity_id, _) in phase_query.iter_with_euids() { if phase_entity_id == *START_PHASE { continue; } self.query_and_run_systems(phase_entity_id); self.perform_child_phases(phase_entity_id); } } fn emit_new_events(&self) { let new_events = self .data .new_events .write_nonblock() .expect("Failed to acquire read-write lock to new events") .take(); for (event_id, event_matches) in new_events { self.emit_event_observers( event_id, &EmittedEvent { event: event_id, match_ids: &event_matches.match_ids, }, ); } } #[tracing::instrument(skip_all)] fn perform_queued_actions(&mut self) { let mut action_queue_lock = self .data .action_queue .queue .write_nonblock() .unwrap_or_else(|err| { panic!("Failed to take read-write action queue lock: {err}",); }); for action in action_queue_lock.drain(..) { match action { Action::Spawn(components) => { let new_entity_uid = Uid::new_unique(UidKind::Entity); if let Err(err) = self.data.component_storage.create_entity(new_entity_uid) { tracing::warn!("Failed to create entity: {err}"); continue; } Self::add_entity_components( new_entity_uid, components, &mut self.data.component_storage, ); } Action::Despawn(entity_uid) => { if let Err(err) = self.data.component_storage.remove_entity(entity_uid) { tracing::error!("Failed to despawn entity: {err}"); } } Action::AddComponents(entity_uid, components) => { Self::add_entity_components( entity_uid, components, &mut self.data.component_storage, ); } Action::RemoveComponents(entity_uid, component_ids) => { Self::remove_entity_components( entity_uid, component_ids, &mut self.data.component_storage, ); } Action::Stop => { self.stop.store(true, Ordering::Relaxed); } } } } fn add_entity_components( entity_uid: Uid, components: impl IntoIterator, component_storage: &mut ComponentStorage, ) -> Vec { let component_iter = components.into_iter(); let mut added_component_ids = Vec::::with_capacity(component_iter.size_hint().0); for component_parts in component_iter { let comp_id = component_parts.id(); if let Err(err) = component_storage.add_entity_component( entity_uid, (comp_id, component_parts.name(), component_parts.into_data()), ) { tracing::error!("Failed to add component to entity: {err}"); continue; } added_component_ids.push(comp_id); } added_component_ids } fn remove_entity_components( entity_uid: Uid, component_ids: impl IntoIterator, component_storage: &mut ComponentStorage, ) -> Vec { let component_id_iter = component_ids.into_iter(); let mut removed_component_ids = Vec::::with_capacity(component_id_iter.size_hint().0); for component_id in component_id_iter { if let Err(err) = component_storage.remove_entity_component(entity_uid, component_id) { tracing::error!("Failed to remove component to entity: {err}"); continue; } removed_component_ids.push(component_id); } removed_component_ids } fn emit_event_observers(&self, event_id: Uid, emitted_event: &EmittedEvent<'_>) { assert_eq!(event_id.kind(), UidKind::Pair); let query = Query::<(&ObserverWrapperComponent,)>::from_flexible_query( self.flexible_query( QueryTerms::::builder() .with_required([ObserverWrapperComponent::id(), event_id]) .build(), ), ); for (observer_ent_id, (observer,)) in query.iter_with_euids() { unsafe { observer.run( self, SystemMetadata { ent_id: observer_ent_id }, emitted_event.clone(), ); } } } } 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: ComponentStorage, sole_storage: SoleStorage, action_queue: Rc, new_events: Lock, } #[derive(Debug, Clone)] pub struct EntityComponentRef<'a> { component_id: Uid, component: &'a ArchetypeEntityComponent, entity_id: Uid, } impl<'a> EntityComponentRef<'a> { fn component(&self) -> &'a Lock> { self.component.component() } #[must_use] pub fn id(&self) -> Uid { self.component_id } #[must_use] pub fn entity_id(&self) -> Uid { self.entity_id } fn new(component_id: Uid, comp: &'a ArchetypeEntityComponent, entity_id: Uid) -> Self { Self { component_id, component: comp, entity_id, } } } #[derive(Debug, Default)] struct ActionQueue { queue: Lock>, } impl ActionQueue { fn push(&self, action: Action) { self.queue .write_nonblock() .expect("Failed to aquire read-write lock to action queue") .push(action); } } #[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), type_name::())), 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 { soles_to_drop_last.push(sole); continue; } unsafe { ManuallyDrop::drop(sole); } } for sole in &mut soles_to_drop_last { unsafe { ManuallyDrop::drop(sole); } } } }