engine/ecs/src/entity.rs

314 lines
7.6 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
use core::fmt;
use std::any::TypeId;
2025-02-26 11:22:32 +00:00
use std::collections::HashSet;
2024-08-23 11:22:09 +00:00
use std::{num::ParseIntError, str::FromStr};
use anyhow::Result;
2025-02-26 11:22:32 +00:00
use indexmap::IndexMap;
2025-02-26 07:39:19 +00:00
use serde::{Deserialize, Serialize};
2024-08-23 11:22:09 +00:00
2025-02-26 07:39:19 +00:00
use crate::{ComponentDebug, ComponentNotFoundError, EntityComponent, MultiMut, TypeMap};
2024-08-23 11:22:09 +00:00
2025-02-26 11:22:32 +00:00
#[derive(Debug)]
pub struct EntityNotFoundError {
entity: Entity,
}
impl EntityNotFoundError {
pub(crate) fn new(entity: Entity) -> Self {
Self { entity }
}
}
impl std::fmt::Display for EntityNotFoundError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Entity (ID: {}) not found!", self.entity)
}
}
impl std::error::Error for EntityNotFoundError {}
2024-08-23 11:22:09 +00:00
#[derive(Default)]
pub struct ActivationState {
activated: bool,
}
impl ActivationState {
pub fn is_active(&self) -> bool {
self.activated
}
pub(crate) fn apply_change(&mut self) {
self.activated = !self.activated;
}
}
2025-02-26 11:22:32 +00:00
pub struct EntityObject {
2024-08-23 11:22:09 +00:00
#[cfg(debug_assertions)]
pub debug_name: Option<String>,
// gltf file name
2025-02-27 05:29:28 +00:00
pub gltf_file: Option<String>,
2024-08-23 11:22:09 +00:00
// activation state of Entity
pub(crate) activation_state: ActivationState,
// program local ID
pub entity_id: u32,
// component map
2025-02-26 11:22:32 +00:00
pub components: TypeMap,
2024-08-23 11:22:09 +00:00
#[cfg(debug_assertions)]
component_names: Vec<String>,
}
2025-02-26 11:22:32 +00:00
unsafe impl Send for EntityObject {}
unsafe impl Sync for EntityObject {}
2024-08-23 11:22:09 +00:00
2025-02-26 11:22:32 +00:00
impl EntityObject {
2024-08-23 11:22:09 +00:00
pub(crate) fn new(id: u32) -> Self {
Self {
#[cfg(debug_assertions)]
debug_name: None,
gltf_file: None,
activation_state: ActivationState::default(),
entity_id: id,
components: TypeMap::default(),
#[cfg(debug_assertions)]
component_names: Vec::new(),
}
}
pub fn gltf_file(&self) -> Option<&String> {
self.gltf_file.as_ref()
}
2025-02-26 11:22:32 +00:00
pub fn multi_mut(&mut self) -> MultiMut<'_> {
2024-08-23 11:22:09 +00:00
self.components.multi_mut()
}
2025-02-26 11:22:32 +00:00
pub fn insert_component<T: EntityComponent + ComponentDebug>(
2024-08-23 11:22:09 +00:00
&mut self,
component: T,
) -> Option<T> {
assert!(
!self.activation_state.is_active(),
"inserting components while the entity is activated is not allowed"
);
#[cfg(debug_assertions)]
{
let name = component.name().to_string();
if !self.component_names.contains(&name) {
self.component_names.push(name);
}
}
self.components.insert(component)
}
pub(crate) fn insert_component_by_id(
&mut self,
type_id: TypeId,
2025-02-26 11:22:32 +00:00
component: Box<dyn EntityComponent>,
) -> Option<Box<dyn EntityComponent>> {
2024-08-23 11:22:09 +00:00
assert!(
!self.activation_state.is_active(),
"inserting components while the entity is activated is not allowed"
);
#[cfg(debug_assertions)]
{
let name = component.name().to_string();
if !self.component_names.contains(&name) {
self.component_names.push(name);
}
}
self.components.insert_type(type_id, component)
}
2025-02-26 11:22:32 +00:00
pub fn remove_component<T: EntityComponent>(&mut self) -> Option<T> {
2024-08-23 11:22:09 +00:00
assert!(
!self.activation_state.is_active(),
"removing components while the entity is activated is not allowed"
);
let t: Option<T> = self.components.remove();
#[cfg(debug_assertions)]
if let Some(t) = &t {
if let Some(index) = self
.component_names
.iter()
.position(|name| name == t.name())
{
self.component_names.remove(index);
}
}
t
}
pub(crate) fn remove_component_by_id(
&mut self,
type_id: TypeId,
2025-02-26 11:22:32 +00:00
) -> Option<Box<dyn EntityComponent>> {
2024-08-23 11:22:09 +00:00
assert!(
!self.activation_state.is_active(),
"removing components while the entity is activated is not allowed"
);
let t = self.components.remove_by_type_id(&type_id);
#[cfg(debug_assertions)]
if let Some(t) = &t {
if let Some(index) = self
.component_names
.iter()
.position(|name| name == t.name())
{
self.component_names.remove(index);
}
}
t
}
#[cfg(debug_assertions)]
pub fn component_names(&self) -> &[String] {
&self.component_names
}
2025-02-26 11:22:32 +00:00
pub fn get_component<T: EntityComponent + ComponentDebug>(
2024-08-23 11:22:09 +00:00
&self,
) -> std::result::Result<&T, ComponentNotFoundError> {
self.components.get()
}
2025-02-26 11:22:32 +00:00
pub fn get_component_mut<T: EntityComponent + ComponentDebug>(
2024-08-23 11:22:09 +00:00
&mut self,
) -> std::result::Result<&mut T, ComponentNotFoundError> {
self.components.get_mut()
}
2025-02-26 11:22:32 +00:00
pub fn contains_component<T: EntityComponent>(&self) -> bool {
2024-08-23 11:22:09 +00:00
self.components.contains::<T>()
}
pub fn is_activated(&self) -> bool {
self.activation_state.is_active()
}
pub fn as_entity(&self) -> Entity {
Entity { id: self.entity_id }
}
2025-02-26 11:22:32 +00:00
pub(crate) fn clone_without_components(&self, id: u32) -> EntityObject {
2024-08-23 11:22:09 +00:00
EntityObject {
#[cfg(debug_assertions)]
debug_name: self.debug_name.clone(),
// gltf file name
gltf_file: self.gltf_file.clone(),
activation_state: Default::default(),
2025-02-26 07:39:19 +00:00
entity_id: id,
2024-08-23 11:22:09 +00:00
// component map
2025-02-26 07:39:19 +00:00
components: TypeMap::default(),
2024-08-23 11:22:09 +00:00
#[cfg(debug_assertions)]
component_names: Vec::new(),
}
}
2025-02-26 11:22:32 +00:00
pub fn clone_component_from<T: EntityComponent + ComponentDebug + Clone>(
2024-08-23 11:22:09 +00:00
&mut self,
other: &Self,
) -> Result<()> {
let component = other.get_component::<T>()?;
self.insert_component(component.clone());
Ok(())
}
}
#[allow(clippy::derive_hash_xor_eq)]
#[derive(Debug, Clone, Copy, Hash, Eq, Serialize, Deserialize)]
pub struct Entity {
pub(crate) id: u32,
}
2025-02-26 11:22:32 +00:00
impl PartialEq<EntityObject> for Entity {
fn eq(&self, entity: &EntityObject) -> bool {
2024-08-23 11:22:09 +00:00
self.id == entity.entity_id
}
}
impl PartialEq<Entity> for Entity {
fn eq(&self, entity: &Entity) -> bool {
self.id == entity.id
}
}
impl fmt::Display for Entity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.id)
}
}
impl FromStr for Entity {
type Err = ParseIntError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(Self { id: s.parse()? })
}
}
2025-02-26 11:22:32 +00:00
pub struct EntityMultiMut<'a> {
entities: &'a mut IndexMap<Entity, EntityObject>,
buffer: HashSet<Entity>,
}
impl<'a> EntityMultiMut<'a> {
pub(crate) fn new(entities: &'a mut IndexMap<Entity, EntityObject>) -> Self {
Self {
entities,
buffer: HashSet::new(),
}
}
pub fn get(
&mut self,
entity: Entity,
) -> std::result::Result<&'a mut EntityObject, EntityNotFoundError> {
match self.entities.get_mut(&entity) {
Some(v) => {
let ptr = v as *mut EntityObject;
assert!(
self.buffer.get(&entity).is_none(),
"Entity ({}) already borrowed",
entity.id
);
self.buffer.insert(entity);
let e: Option<&'a mut EntityObject> = Some(unsafe { &mut *ptr });
e.ok_or_else(|| EntityNotFoundError::new(entity))
}
None => Err(EntityNotFoundError::new(entity)),
}
}
}