summaryrefslogtreecommitdiff
path: root/ecs/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r--ecs/src/lib.rs750
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);
- }
- }
- }
-}