summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-11-11 00:11:22 +0100
committerHampusM <hampus@hampusmat.com>2024-11-11 00:11:22 +0100
commitdaf0bc236df25c0e9f44bc3e30839c16cda3f638 (patch)
tree7475e4e58686dd34366e641ec32f5a9374d66533
parent17f63d9859e1c82a30c07bf110cf2b9872e2427e (diff)
refactor(ecs): use same ID for entities & components
-rw-r--r--ecs/src/actions.rs14
-rw-r--r--ecs/src/archetype.rs4
-rw-r--r--ecs/src/component.rs89
-rw-r--r--ecs/src/component/local.rs9
-rw-r--r--ecs/src/component/storage.rs72
-rw-r--r--ecs/src/entity.rs37
-rw-r--r--ecs/src/event/component.rs11
-rw-r--r--ecs/src/lib.rs24
-rw-r--r--ecs/src/query.rs4
-rw-r--r--ecs/src/query/options.rs4
-rw-r--r--ecs/src/relationship.rs52
-rw-r--r--ecs/src/system/stateful.rs9
-rw-r--r--ecs/src/uid.rs42
13 files changed, 202 insertions, 169 deletions
diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs
index 5cd7b00..72cc95d 100644
--- a/ecs/src/actions.rs
+++ b/ecs/src/actions.rs
@@ -7,8 +7,8 @@ use crate::component::{
Metadata as ComponentMetadata,
Sequence as ComponentSequence,
};
-use crate::entity::Uid as EntityUid;
use crate::system::{NoInitParamFlag, Param as SystemParam, System};
+use crate::uid::{Kind as UidKind, Uid};
use crate::{ActionQueue, World};
/// Used to to queue up actions for a [`World`] to perform.
@@ -28,19 +28,23 @@ impl<'world> Actions<'world>
}
/// Adds component(s) to a entity.
- pub fn add_components<Comps>(&mut self, entity_uid: EntityUid, components: Comps)
+ pub fn add_components<Comps>(&mut self, entity_uid: Uid, components: Comps)
where
Comps: ComponentSequence,
{
+ debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
+
self.action_queue
.push(Action::AddComponents(entity_uid, components.into_vec()));
}
/// Removes component(s) from a entity.
- pub fn remove_components<Comps>(&mut self, entity_uid: EntityUid)
+ pub fn remove_components<Comps>(&mut self, entity_uid: Uid)
where
Comps: ComponentSequence,
{
+ debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
+
self.action_queue
.push(Action::RemoveComponents(entity_uid, Comps::metadata()));
}
@@ -149,8 +153,8 @@ impl<'weak_ref> Ref<'weak_ref>
pub(crate) enum Action
{
Spawn(Vec<Box<dyn Component>>),
- AddComponents(EntityUid, Vec<Box<dyn Component>>),
- RemoveComponents(EntityUid, Vec<ComponentMetadata>),
+ AddComponents(Uid, Vec<Box<dyn Component>>),
+ RemoveComponents(Uid, Vec<ComponentMetadata>),
Stop,
}
diff --git a/ecs/src/archetype.rs b/ecs/src/archetype.rs
index 808d006..5c104b7 100644
--- a/ecs/src/archetype.rs
+++ b/ecs/src/archetype.rs
@@ -1,10 +1,10 @@
use std::hash::{DefaultHasher, Hash, Hasher};
use crate::component::{
- Id as ComponentId,
IsOptional as ComponentIsOptional,
Metadata as ComponentMetadata,
};
+use crate::uid::Uid;
/// Archetype ID.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
@@ -33,7 +33,7 @@ impl Id
}
/// Returns the ID of a archetype with the given components.
- fn new(component_ids: impl IntoIterator<Item = ComponentId>) -> Self
+ fn new(component_ids: impl IntoIterator<Item = Uid>) -> Self
{
let mut hasher = DefaultHasher::new();
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 0506346..e1f2858 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -1,8 +1,9 @@
-use std::any::{type_name, Any, TypeId};
+use std::any::{type_name, Any};
use std::fmt::Debug;
use seq_macro::seq;
+use crate::uid::Uid;
use crate::lock::{ReadGuard, WriteGuard};
use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput};
use crate::type_name::TypeName;
@@ -27,8 +28,13 @@ pub trait Component: SystemInput + Any + TypeName
where
Self: Sized;
- /// Returns the ID of this component's type.
- fn id(&self) -> Id;
+ /// Returns the ID of this component.
+ fn id() -> Uid
+ where
+ Self: Sized;
+
+ /// The ID of the component `self`. Returns the same value as [`Component::id`].
+ fn self_id(&self) -> Uid;
#[doc(hidden)]
fn as_any_mut(&mut self) -> &mut dyn Any;
@@ -36,9 +42,19 @@ pub trait Component: SystemInput + Any + TypeName
#[doc(hidden)]
fn as_any(&self) -> &dyn Any;
- fn is_optional(&self) -> bool
+ /// Whether the component `self` is optional. Returns the same value as
+ /// [`Component::is_optional`].
+ fn self_is_optional(&self) -> IsOptional
{
- false
+ IsOptional::No
+ }
+
+ /// Returns whether this component is optional.
+ fn is_optional() -> IsOptional
+ where
+ Self: Sized,
+ {
+ IsOptional::No
}
}
@@ -84,9 +100,14 @@ where
type Ref<'component> = Option<ComponentRef<'component, ComponentT>>;
type RefMut<'component> = Option<ComponentRefMut<'component, ComponentT>>;
- fn id(&self) -> Id
+ fn id() -> Uid
+ {
+ ComponentT::id()
+ }
+
+ fn self_id(&self) -> Uid
{
- Id::of::<Self>()
+ Self::id()
}
fn as_any_mut(&mut self) -> &mut dyn Any
@@ -99,9 +120,14 @@ where
self
}
- fn is_optional(&self) -> bool
+ fn self_is_optional(&self) -> IsOptional
+ {
+ Self::is_optional()
+ }
+
+ fn is_optional() -> IsOptional
{
- true
+ IsOptional::Yes
}
}
@@ -117,24 +143,6 @@ where
impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component {}
-/// The ID of a [`Component`] type.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Id
-{
- inner: TypeId,
-}
-
-impl Id
-{
- #[must_use]
- pub fn of<ComponentT>() -> Self
- where
- ComponentT: Component,
- {
- Self { inner: TypeId::of::<ComponentT>() }
- }
-}
-
/// A sequence of components.
pub trait Sequence
{
@@ -172,7 +180,7 @@ pub trait Sequence
#[non_exhaustive]
pub struct Metadata
{
- pub id: Id,
+ pub id: Uid,
pub is_optional: IsOptional,
}
@@ -181,8 +189,8 @@ impl Metadata
pub fn of<ComponentT: Component + ?Sized>(component: &ComponentT) -> Self
{
Self {
- id: component.id(),
- is_optional: component.is_optional().into(),
+ id: component.self_id(),
+ is_optional: component.self_is_optional(),
}
}
}
@@ -207,19 +215,6 @@ impl From<bool> for IsOptional
}
}
-/// Returns whether the given component type is a optional component.
-///
-/// Will return `true` if the component is a [`Option`].
-#[must_use]
-pub fn is_optional<ComponentT: Component>() -> bool
-{
- if Id::of::<ComponentT>() == Id::of::<Option<ComponentT::Component>>() {
- return true;
- }
-
- false
-}
-
pub trait FromOptionalMut<'comp>
{
fn from_optional_mut_component(
@@ -260,8 +255,8 @@ macro_rules! inner {
vec![
#(
Metadata {
- id: Id::of::<Comp~I>(),
- is_optional: is_optional::<Comp~I>().into()
+ id: Comp~I::id(),
+ is_optional: Comp~I::is_optional()
},
)*
]
@@ -281,7 +276,7 @@ macro_rules! inner {
for comp in components {
#(
- if comp.id == Id::of::<Comp~I::Component>() {
+ if comp.id == Comp~I::Component::id() {
comp_~I = Some(lock_component(comp));
continue;
}
@@ -308,7 +303,7 @@ macro_rules! inner {
for comp in components {
#(
- if comp.id == Id::of::<Comp~I::Component>() {
+ if comp.id == Comp~I::Component::id() {
comp_~I = Some(lock_component(comp));
continue;
}
diff --git a/ecs/src/component/local.rs b/ecs/src/component/local.rs
index a365efe..9d32d47 100644
--- a/ecs/src/component/local.rs
+++ b/ecs/src/component/local.rs
@@ -1,7 +1,8 @@
use std::any::Any;
use std::ops::{Deref, DerefMut};
-use crate::component::{Component, Id};
+use crate::component::Component;
+use crate::uid::Uid;
use crate::system::{ComponentRefMut, Param as SystemParam, System};
use crate::World;
@@ -43,16 +44,16 @@ where
{
let other_comparable = Other::get_comparable();
- let Some(other_id) = other_comparable.downcast_ref::<Id>() else {
+ let Some(other_id) = other_comparable.downcast_ref::<Uid>() else {
return true;
};
- Id::of::<LocalComponent>() != *other_id
+ LocalComponent::id() != *other_id
}
fn get_comparable() -> Box<dyn Any>
{
- Box::new(Id::of::<LocalComponent>())
+ Box::new(LocalComponent::id())
}
}
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
index 041c124..141fea7 100644
--- a/ecs/src/component/storage.rs
+++ b/ecs/src/component/storage.rs
@@ -8,12 +8,11 @@ use std::vec::IntoIter as OwnedVecIter;
use crate::archetype::Id as ArchetypeId;
use crate::component::{
Component,
- Id as ComponentId,
IsOptional as ComponentIsOptional,
Metadata as ComponentMetadata,
};
-use crate::entity::Uid as EntityUid;
use crate::type_name::TypeName;
+use crate::uid::Uid;
use crate::util::Sortable;
use crate::EntityComponent;
@@ -22,7 +21,7 @@ pub struct Storage
{
archetypes: Vec<Archetype>,
archetype_lookup: RefCell<HashMap<ArchetypeId, ArchetypeLookupEntry>>,
- entity_archetype_lookup: HashMap<EntityUid, ArchetypeId>,
+ entity_archetype_lookup: HashMap<Uid, ArchetypeId>,
}
impl Storage
@@ -72,7 +71,7 @@ impl Storage
self.iter_archetypes_by_lookup(archetype_id)
}
- pub fn get_entity_archetype(&self, entity_uid: EntityUid) -> Option<&Archetype>
+ pub fn get_entity_archetype(&self, entity_uid: Uid) -> Option<&Archetype>
{
let archetype_id = self.entity_archetype_lookup.get(&entity_uid)?;
@@ -85,15 +84,15 @@ impl Storage
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
pub fn push_entity(
&mut self,
- entity_uid: EntityUid,
+ entity_uid: Uid,
mut components: Vec<Box<dyn Component>>,
- ) -> Result<(ArchetypeId, EntityUid), Error>
+ ) -> Result<(ArchetypeId, Uid), Error>
{
if self.entity_archetype_lookup.contains_key(&entity_uid) {
return Err(Error::EntityAlreadyExists(entity_uid));
}
- components.sort_by_key(|component| component.id());
+ components.sort_by_key(|component| component.self_id());
#[cfg(feature = "debug")]
tracing::debug!(
@@ -141,7 +140,7 @@ impl Storage
pub fn add_components_to_entity(
&mut self,
- entity_uid: EntityUid,
+ entity_uid: Uid,
components: Vec<Box<dyn Component>>,
) -> Option<()>
{
@@ -154,7 +153,7 @@ impl Storage
let contains_component_already = components
.iter()
- .any(|component| archetype.component_ids.contains_key(&component.id()));
+ .any(|component| archetype.component_ids.contains_key(&component.self_id()));
if contains_component_already {
let component_cnt = components.len();
@@ -193,8 +192,8 @@ impl Storage
pub fn remove_components_from_entity(
&mut self,
- entity_uid: EntityUid,
- component_ids: impl IntoIterator<Item = ComponentId>,
+ entity_uid: Uid,
+ component_ids: impl IntoIterator<Item = Uid>,
) -> Option<()>
{
let archetype_id = self.entity_archetype_lookup.get(&entity_uid)?;
@@ -216,7 +215,7 @@ impl Storage
.components
.into_iter()
.map(|component| component.component.into_inner())
- .filter(|component| !component_ids_set.contains(&component.id()))
+ .filter(|component| !component_ids_set.contains(&component.self_id()))
.collect(),
)
.expect("Not supposed to return Err since the entity is removed");
@@ -226,7 +225,7 @@ impl Storage
fn populate_matching_archetype_lookup_entries(
&mut self,
- comp_ids_set: &HashSet<ComponentId>,
+ comp_ids_set: &HashSet<Uid>,
archetype_index: usize,
)
{
@@ -251,7 +250,7 @@ impl Storage
fn get_or_create_archetype(
&mut self,
archetype_id: ArchetypeId,
- comp_ids_set: &HashSet<ComponentId>,
+ comp_ids_set: &HashSet<Uid>,
components: &[Box<dyn Component>],
) -> usize
{
@@ -266,7 +265,7 @@ impl Storage
if lookup_entry.archetype_indices.is_empty() {
self.archetypes.push(Archetype::new(
- components.iter().map(|component| component.id()),
+ components.iter().map(|component| component.self_id()),
));
lookup_entry
@@ -282,7 +281,7 @@ impl Storage
fn find_archetype_index_with_entity(
&self,
archetype_id: ArchetypeId,
- entity_uid: EntityUid,
+ entity_uid: Uid,
) -> Option<usize>
{
let archetype_lookup = self.archetype_lookup.borrow_mut();
@@ -330,7 +329,7 @@ impl Storage
pub enum Error
{
#[error("Entity already exists")]
- EntityAlreadyExists(EntityUid),
+ EntityAlreadyExists(Uid),
}
impl TypeName for Storage
@@ -344,21 +343,21 @@ impl TypeName for Storage
#[derive(Debug)]
struct ArchetypeLookupEntry
{
- component_ids: HashSet<ComponentId>,
+ component_ids: HashSet<Uid>,
archetype_indices: Vec<usize>,
}
#[derive(Debug)]
pub struct Archetype
{
- component_ids: HashMap<ComponentId, usize>,
- entity_lookup: HashMap<EntityUid, usize>,
+ component_ids: HashMap<Uid, usize>,
+ entity_lookup: HashMap<Uid, usize>,
entities: Vec<ArchetypeEntity>,
}
impl Archetype
{
- fn new(component_ids: impl IntoIterator<Item = ComponentId>) -> Self
+ fn new(component_ids: impl IntoIterator<Item = Uid>) -> Self
{
Self {
component_ids: component_ids
@@ -371,10 +370,7 @@ impl Archetype
}
}
- pub fn component_ids_is_superset(
- &self,
- other_component_ids: &HashSet<ComponentId>,
- ) -> bool
+ pub fn component_ids_is_superset(&self, other_component_ids: &HashSet<Uid>) -> bool
{
if other_component_ids.len() <= self.component_ids.len() {
other_component_ids
@@ -385,7 +381,7 @@ impl Archetype
}
}
- pub fn get_entity(&self, entity_uid: EntityUid) -> Option<&ArchetypeEntity>
+ pub fn get_entity(&self, entity_uid: Uid) -> Option<&ArchetypeEntity>
{
let entity_index = *self.entity_lookup.get(&entity_uid)?;
@@ -397,14 +393,14 @@ impl Archetype
EntityIter { iter: self.entities.iter() }
}
- pub fn get_index_for_component(&self, component_id: &ComponentId) -> Option<usize>
+ pub fn get_index_for_component(&self, component_id: &Uid) -> Option<usize>
{
self.component_ids.get(component_id).copied()
}
fn push_entity(
&mut self,
- entity_uid: EntityUid,
+ entity_uid: Uid,
components: impl IntoIterator<Item = Box<dyn Component>>,
)
{
@@ -414,7 +410,7 @@ impl Archetype
});
}
- pub fn take_entity(&mut self, entity_uid: EntityUid) -> Option<ArchetypeEntity>
+ pub fn take_entity(&mut self, entity_uid: Uid) -> Option<ArchetypeEntity>
{
let entity_index = self.entity_lookup.remove(&entity_uid)?;
@@ -429,7 +425,7 @@ impl Archetype
Some(entity)
}
- fn has_entity(&self, entity_uid: EntityUid) -> bool
+ fn has_entity(&self, entity_uid: Uid) -> bool
{
self.entity_lookup.contains_key(&entity_uid)
}
@@ -438,13 +434,13 @@ impl Archetype
#[derive(Debug)]
pub struct ArchetypeEntity
{
- uid: EntityUid,
+ uid: Uid,
components: Vec<EntityComponent>,
}
impl ArchetypeEntity
{
- pub fn uid(&self) -> EntityUid
+ pub fn uid(&self) -> Uid
{
self.uid
}
@@ -501,7 +497,7 @@ impl<'archetype> Iterator for EntityIter<'archetype>
fn create_non_opt_component_id_set<Item>(
component_metadata_iter: impl IntoIterator<Item = Item>,
-) -> HashSet<ComponentId>
+) -> HashSet<Uid>
where
Item: Borrow<ComponentMetadata>,
{
@@ -528,11 +524,11 @@ mod tests
use super::Storage;
use crate::archetype::Id as ArchetypeId;
use crate::component::{
- Id as ComponentId,
+ Component,
IsOptional as ComponentIsOptional,
Metadata as ComponentMetadata,
};
- use crate::entity::Uid as EntityUid;
+ use crate::uid::{Kind as UidKind, Uid};
use crate::{self as ecs};
#[derive(Debug, Component)]
@@ -569,7 +565,7 @@ mod tests
component_storage
.push_entity(
- EntityUid::new_unique(),
+ Uid::new_unique(UidKind::Entity),
vec![
Box::new(HealthPotion { _hp_restoration: 12 }),
Box::new(Hookshot { _range: 50 }),
@@ -600,11 +596,11 @@ mod tests
let mut components_metadata = [
ComponentMetadata {
- id: ComponentId::of::<HealthPotion>(),
+ id: HealthPotion::id(),
is_optional: ComponentIsOptional::No,
},
ComponentMetadata {
- id: ComponentId::of::<Hookshot>(),
+ id: Hookshot::id(),
is_optional: ComponentIsOptional::No,
},
];
diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs
index 18f229a..fff66f5 100644
--- a/ecs/src/entity.rs
+++ b/ecs/src/entity.rs
@@ -1,43 +1,14 @@
-use std::sync::atomic::{AtomicU64, Ordering};
-
use linkme::distributed_slice;
use crate::World;
-static NEXT_UID: AtomicU64 = AtomicU64::new(0);
-
-/// Unique entity ID.
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Uid
-{
- inner: u64,
-}
-
-impl Uid
-{
- pub fn new(uid: u64) -> Self
- {
- debug_assert!(
- uid < NEXT_UID.load(Ordering::Relaxed),
- "Invalid entity UID {uid}"
- );
-
- Self { inner: uid }
- }
-
- pub fn new_unique() -> Self
- {
- Self {
- inner: NEXT_UID.fetch_add(1, Ordering::Relaxed),
- }
- }
-}
-
#[macro_export]
macro_rules! static_entity {
($visibility: vis $ident: ident, $components: expr) => {
- $visibility static $ident: ::std::sync::LazyLock<$crate::entity::Uid> =
- ::std::sync::LazyLock::new(|| $crate::entity::Uid::new_unique());
+ $visibility static $ident: ::std::sync::LazyLock<$crate::uid::Uid> =
+ ::std::sync::LazyLock::new(|| {
+ $crate::uid::Uid::new_unique($crate::uid::Kind::Entity)
+ });
$crate::private::paste::paste! {
mod [<__ecs_ $ident:lower _static_entity_priv>] {
diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs
index 40cd20d..8b066a7 100644
--- a/ecs/src/event/component.rs
+++ b/ecs/src/event/component.rs
@@ -5,7 +5,8 @@ use std::marker::PhantomData;
use ecs_macros::Component;
-use crate::component::{Component, Id as ComponentId};
+use crate::component::Component;
+use crate::uid::Uid;
use crate::event::{Event, Id};
use crate::tuple::{ReduceElement as TupleReduceElement, With as TupleWith};
@@ -50,7 +51,7 @@ where
where
Self: Sized,
{
- Id::new::<Added<ComponentForId>, _>(Some(ComponentId::of::<ComponentT>()))
+ Id::new::<Added<ComponentForId>, _>(Some(ComponentT::id()))
}
}
@@ -93,18 +94,18 @@ where
where
Self: Sized,
{
- Id::new::<Removed<ComponentForId>, _>(Some(ComponentId::of::<ComponentT>()))
+ Id::new::<Removed<ComponentForId>, _>(Some(ComponentT::id()))
}
}
#[must_use]
-pub fn create_added_id(component_id: ComponentId) -> Id
+pub fn create_added_id(component_id: Uid) -> Id
{
Id::new::<Added<ComponentForId>, _>(Some(component_id))
}
#[must_use]
-pub fn create_removed_id(component_id: ComponentId) -> Id
+pub fn create_removed_id(component_id: Uid) -> Id
{
Id::new::<Removed<ComponentForId>, _>(Some(component_id))
}
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 6725d81..a643bec 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -10,8 +10,8 @@ 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, CREATE_STATIC_ENTITIES};
+use crate::component::{Component, Sequence as ComponentSequence};
+use crate::entity::CREATE_STATIC_ENTITIES;
use crate::event::component::{
create_added_id as create_component_added_event_id,
create_removed_id as create_component_removed_event_id,
@@ -27,6 +27,7 @@ use crate::stats::Stats;
use crate::system::{System, TypeErased as TypeErasedSystem};
use crate::tuple::Reduce as TupleReduce;
use crate::type_name::TypeName;
+use crate::uid::{Kind as UidKind, Uid};
pub mod actions;
pub mod component;
@@ -41,6 +42,7 @@ pub mod stats;
pub mod system;
pub mod tuple;
pub mod type_name;
+pub mod uid;
#[doc(hidden)]
pub mod private;
@@ -78,12 +80,12 @@ impl World
///
/// # Panics
/// Will panic if mutable internal lock cannot be acquired.
- pub fn create_entity<Comps>(&mut self, components: Comps) -> EntityUid
+ pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid
where
Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>,
Comps::Out: EventSequence,
{
- let entity_uid = EntityUid::new_unique();
+ let entity_uid = Uid::new_unique(UidKind::Entity);
self.create_entity_with_uid(components, entity_uid);
@@ -91,11 +93,13 @@ impl World
}
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
- pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: EntityUid)
+ pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid)
where
Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>,
Comps::Out: EventSequence,
{
+ debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
+
#[allow(unused_variables)]
if let Err(err) = self
.data
@@ -206,12 +210,12 @@ impl World
let component_ids = components
.iter()
- .map(|component| component.id())
+ .map(|component| component.self_id())
.collect::<Vec<_>>();
#[allow(unused_variables)]
if let Err(err) = component_storage_lock
- .push_entity(EntityUid::new_unique(), components)
+ .push_entity(Uid::new_unique(UidKind::Entity), components)
{
#[cfg(feature = "debug")]
tracing::error!("Failed to create entity: {err}");
@@ -236,7 +240,7 @@ impl World
let component_ids = components
.iter()
- .map(|component| component.id())
+ .map(|component| component.self_id())
.collect::<Vec<_>>();
component_storage_lock
@@ -375,7 +379,7 @@ pub struct WorldData
#[non_exhaustive]
pub struct EntityComponent
{
- pub id: ComponentId,
+ pub id: Uid,
pub name: &'static str,
pub component: Lock<Box<dyn Component>>,
}
@@ -385,7 +389,7 @@ impl From<Box<dyn Component>> for EntityComponent
fn from(component: Box<dyn Component>) -> Self
{
Self {
- id: component.id(),
+ id: component.self_id(),
name: component.type_name(),
component: Lock::new(component),
}
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index e7fd7a6..69bb35d 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -15,7 +15,6 @@ use crate::component::{
Metadata as ComponentMetadata,
Sequence as ComponentSequence,
};
-use crate::entity::Uid as EntityUid;
use crate::lock::{ReadGuard, WriteGuard};
use crate::query::options::Options;
use crate::system::{
@@ -23,6 +22,7 @@ use crate::system::{
Param as SystemParam,
System,
};
+use crate::uid::Uid;
use crate::{EntityComponent, World};
pub mod options;
@@ -86,7 +86,7 @@ where
/// Returns the UID of the entity at the given query iteration index.
#[must_use]
- pub fn entity_uid(&self, entity_index: usize) -> Option<EntityUid>
+ pub fn get_entity_uid(&self, entity_index: usize) -> Option<Uid>
{
Some(
self.component_storage
diff --git a/ecs/src/query/options.rs b/ecs/src/query/options.rs
index d895073..bbbe0a8 100644
--- a/ecs/src/query/options.rs
+++ b/ecs/src/query/options.rs
@@ -1,7 +1,7 @@
use std::collections::HashSet;
use std::marker::PhantomData;
-use crate::component::{Component, Id as ComponentId};
+use crate::component::Component;
use crate::EntityComponent;
/// Query options.
@@ -42,7 +42,7 @@ where
.map(|component| component.id)
.collect::<HashSet<_>>();
- ids_set.contains(&ComponentId::of::<ComponentT>())
+ ids_set.contains(&ComponentT::id())
}
}
diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs
index 4db29da..9f2a81e 100644
--- a/ecs/src/relationship.rs
+++ b/ecs/src/relationship.rs
@@ -1,24 +1,24 @@
use std::any::{type_name, Any};
use std::marker::PhantomData;
+use std::sync::LazyLock;
use crate::component::storage::Storage as ComponentStorage;
use crate::component::{
Component,
FromOptional as FromOptionalComponent,
FromOptionalMut as FromOptionalMutComponent,
- Id as ComponentId,
};
-use crate::entity::Uid as EntityUid;
use crate::lock::ReadGuard;
use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput};
use crate::type_name::TypeName;
+use crate::uid::{Kind as UidKind, Uid};
use crate::World;
/// A relationship to one or more targets.
#[derive(Debug)]
pub struct Relationship<Kind, ComponentT: Component>
{
- entity_uid: SingleOrMultiple<EntityUid>,
+ entity_uid: SingleOrMultiple<Uid>,
_pd: PhantomData<(Kind, ComponentT)>,
}
@@ -28,8 +28,10 @@ where
{
/// Creates a new `Relationship` with a single target.
#[must_use]
- pub fn new(entity_uid: EntityUid) -> Self
+ pub fn new(entity_uid: Uid) -> Self
{
+ debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
+
Self {
entity_uid: SingleOrMultiple::Single(entity_uid),
_pd: PhantomData,
@@ -38,15 +40,24 @@ where
/// Creates a new `Relationship` with multiple targets.
#[must_use]
- pub fn new_multiple(entity_uids: impl IntoIterator<Item = EntityUid>) -> Self
+ pub fn new_multiple(entity_uids: impl IntoIterator<Item = Uid>) -> Self
{
+ let uids = entity_uids.into_iter().collect::<Vec<_>>();
+
+ for euid in &uids {
+ debug_assert_eq!(euid.kind(), UidKind::Entity);
+ }
+
Self {
- entity_uid: SingleOrMultiple::Multiple(entity_uids.into_iter().collect()),
+ entity_uid: SingleOrMultiple::Multiple(uids),
_pd: PhantomData,
}
}
}
+static COMPONENT_EUID: LazyLock<Uid> =
+ LazyLock::new(|| Uid::new_unique(UidKind::Component));
+
impl<Kind, ComponentT> Component for Relationship<Kind, ComponentT>
where
Kind: 'static,
@@ -56,9 +67,16 @@ where
type Ref<'component> = Relation<'component, Kind, ComponentT>;
type RefMut<'component> = RelationMut<'component, Kind, ComponentT>;
- fn id(&self) -> ComponentId
+ fn id() -> Uid
+ where
+ Self: Sized,
{
- ComponentId::of::<Self>()
+ *COMPONENT_EUID
+ }
+
+ fn self_id(&self) -> Uid
+ {
+ Self::id()
}
fn as_any_mut(&mut self) -> &mut dyn Any
@@ -151,8 +169,7 @@ where
.get_entity(*target)
.expect("Target entity is gone from archetype");
- let component_index =
- archetype.get_index_for_component(&ComponentId::of::<ComponentT>())?;
+ let component_index = archetype.get_index_for_component(&ComponentT::id())?;
let component = ComponentRefMut::new(
entity
@@ -172,7 +189,7 @@ where
/// Returns a reference to the target at the specified index.
#[must_use]
- pub fn get_target(&self, index: usize) -> Option<&EntityUid>
+ pub fn get_target(&self, index: usize) -> Option<&Uid>
{
match &self.relationship_comp.entity_uid {
SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid),
@@ -183,7 +200,7 @@ where
/// Returns a mutable reference to the target at the specified index.
#[must_use]
- pub fn get_target_mut(&mut self, index: usize) -> Option<&mut EntityUid>
+ pub fn get_target_mut(&mut self, index: usize) -> Option<&mut Uid>
{
match &mut self.relationship_comp.entity_uid {
SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid),
@@ -193,8 +210,10 @@ where
}
/// Adds a target to the relationship.
- pub fn add_target(&mut self, entity_uid: EntityUid)
+ pub fn add_target(&mut self, entity_uid: Uid)
{
+ debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
+
match &mut self.relationship_comp.entity_uid {
SingleOrMultiple::Single(prev_entity_uid) => {
self.relationship_comp.entity_uid =
@@ -205,7 +224,7 @@ where
}
/// Removes a target to the relationship, returning it.
- pub fn remove_target(&mut self, index: usize) -> Option<EntityUid>
+ pub fn remove_target(&mut self, index: usize) -> Option<Uid>
{
match &mut self.relationship_comp.entity_uid {
SingleOrMultiple::Single(entity_uid) => {
@@ -354,8 +373,7 @@ where
.get_entity(*target)
.expect("Target entity is gone from archetype");
- let component_index =
- archetype.get_index_for_component(&ComponentId::of::<ComponentT>())?;
+ let component_index = archetype.get_index_for_component(&ComponentT::id())?;
let component = ComponentRef::new(
entity
@@ -375,7 +393,7 @@ where
/// Returns a reference to the target at the specified index.
#[must_use]
- pub fn get_target(&self, index: usize) -> Option<&EntityUid>
+ pub fn get_target(&self, index: usize) -> Option<&Uid>
{
match &self.relationship_comp.entity_uid {
SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid),
diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs
index 99b56c1..810a071 100644
--- a/ecs/src/system/stateful.rs
+++ b/ecs/src/system/stateful.rs
@@ -4,7 +4,7 @@ use std::panic::{RefUnwindSafe, UnwindSafe};
use seq_macro::seq;
-use crate::component::{Component, Id as ComponentId};
+use crate::component::Component;
use crate::lock::Lock;
use crate::system::util::check_params_are_compatible;
use crate::system::{
@@ -21,13 +21,14 @@ use crate::tuple::{
TakeOptionElementResult as TupleTakeOptionElementResult,
WithOptionElements as TupleWithOptionElements,
};
+use crate::uid::Uid;
use crate::World;
/// A stateful system.
pub struct Stateful<Func>
{
func: Func,
- local_components: HashMap<ComponentId, Lock<Box<dyn Component>>>,
+ local_components: HashMap<Uid, Lock<Box<dyn Component>>>,
}
macro_rules! impl_system {
@@ -125,7 +126,7 @@ macro_rules! impl_system {
) -> Option<ComponentRefMut<LocalComponent>>
{
let local_component = self.local_components
- .get(&ComponentId::of::<LocalComponent>())?
+ .get(&LocalComponent::id())?
.write_nonblock()
.expect("Failed to aquire read-write local component lock");
@@ -139,7 +140,7 @@ macro_rules! impl_system {
{
self.local_components
.insert(
- ComponentId::of::<LocalComponent>(),
+ LocalComponent::id(),
Lock::new(Box::new(local_component))
);
}
diff --git a/ecs/src/uid.rs b/ecs/src/uid.rs
new file mode 100644
index 0000000..56d84f9
--- /dev/null
+++ b/ecs/src/uid.rs
@@ -0,0 +1,42 @@
+use std::mem::transmute;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+static NEXT: AtomicU32 = AtomicU32::new(1);
+
+// Bit 0 and 1 for the kind
+const KIND_BITS: u64 = 0x03;
+
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(u8)]
+pub enum Kind
+{
+ Entity = 2,
+ Component = 1,
+}
+
+/// Unique entity/component ID.
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Uid
+{
+ inner: u64,
+}
+
+impl Uid
+{
+ /// Returns a new unique entity/component ID.
+ pub fn new_unique(kind: Kind) -> Self
+ {
+ let id_part = NEXT.fetch_add(1, Ordering::Relaxed);
+
+ Self {
+ inner: ((id_part as u64) << 32) | kind as u64,
+ }
+ }
+
+ pub fn kind(&self) -> Kind
+ {
+ // SAFETY: The kind bits cannot be invalid since they are set using the Kind enum
+ // in the new_unique function
+ unsafe { transmute((self.inner & KIND_BITS) as u8) }
+ }
+}