use core::fmt; use std::any::TypeId; use std::collections::HashSet; use std::{num::ParseIntError, str::FromStr}; use anyhow::Result; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use crate::{ComponentDebug, ComponentNotFoundError, EntityComponent, MultiMut, TypeMap}; #[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 {} #[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; } } pub struct EntityObject { #[cfg(debug_assertions)] pub debug_name: Option, // gltf file name pub gltf_file: Option, // activation state of Entity pub(crate) activation_state: ActivationState, // program local ID pub entity_id: u32, // component map pub components: TypeMap, #[cfg(debug_assertions)] component_names: Vec, } unsafe impl Send for EntityObject {} unsafe impl Sync for EntityObject {} impl EntityObject { 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() } pub fn multi_mut(&mut self) -> MultiMut<'_> { self.components.multi_mut() } pub fn insert_component( &mut self, component: T, ) -> Option { 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, component: Box, ) -> Option> { 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) } pub fn remove_component(&mut self) -> Option { assert!( !self.activation_state.is_active(), "removing components while the entity is activated is not allowed" ); let t: Option = 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, ) -> Option> { 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 } pub fn get_component( &self, ) -> std::result::Result<&T, ComponentNotFoundError> { self.components.get() } pub fn get_component_mut( &mut self, ) -> std::result::Result<&mut T, ComponentNotFoundError> { self.components.get_mut() } pub fn contains_component(&self) -> bool { self.components.contains::() } pub fn is_activated(&self) -> bool { self.activation_state.is_active() } pub fn as_entity(&self) -> Entity { Entity { id: self.entity_id } } pub(crate) fn clone_without_components(&self, id: u32) -> EntityObject { EntityObject { #[cfg(debug_assertions)] debug_name: self.debug_name.clone(), // gltf file name gltf_file: self.gltf_file.clone(), activation_state: Default::default(), entity_id: id, // component map components: TypeMap::default(), #[cfg(debug_assertions)] component_names: Vec::new(), } } pub fn clone_component_from( &mut self, other: &Self, ) -> Result<()> { let component = other.get_component::()?; 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, } impl PartialEq for Entity { fn eq(&self, entity: &EntityObject) -> bool { self.id == entity.entity_id } } impl PartialEq 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 { Ok(Self { id: s.parse()? }) } } pub struct EntityMultiMut<'a> { entities: &'a mut IndexMap, buffer: HashSet, } impl<'a> EntityMultiMut<'a> { pub(crate) fn new(entities: &'a mut IndexMap) -> 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)), } } }