use super::{components::*, ffi, ffi::ComponentType, World};
pub use ffi::MeshOrigin;
use std::{collections::HashMap, fmt};
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "with_speedy", derive(speedy::Writable, speedy::Readable))]
#[repr(transparent)]
pub struct Entity(pub ffi::EntityHandle);
impl fmt::Debug for Entity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_valid() {
write!(
f,
"Entity {{ handle: 0x{:X}, name: {:?} }}",
self.0,
self.name()
)
} else {
f.write_str("INVALID")
}
}
}
#[allow(missing_docs)]
impl Entity {
#[inline]
pub fn from_ffi(h: ffi::EntityHandle) -> Self {
Self(h)
}
#[inline]
pub fn as_ffi(self) -> ffi::EntityHandle {
self.0
}
pub fn is_valid_handle(self) -> bool {
(self.0 & 0xFFFF_FFFF) != 0xFFFF_FFFF
}
pub fn invalid() -> Self {
Self(0x0000_0001_FFFF_FFFF)
}
pub fn try_from_ffi(h: ffi::EntityHandle) -> Option<Self> {
let eh = Self::from_ffi(h);
eh.is_valid().then(|| eh)
}
pub fn try_to_ffi(self) -> Option<ffi::EntityHandle> {
self.is_valid().then(|| self.as_ffi())
}
}
#[must_use]
#[derive(Eq, PartialEq, Hash)]
pub struct EntityOwned {
entity: Entity,
}
impl Drop for EntityOwned {
fn drop(&mut self) {
self.destroy();
}
}
impl fmt::Debug for EntityOwned {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EntityOwned")
.field("entity", &self.entity)
.finish()
}
}
impl Entity {
pub fn create_empty(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create_empty(name))
}
pub fn create(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create(name))
}
pub fn create_non_physics(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create_non_physics(name))
}
pub fn create_camera(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create_camera(name))
}
#[inline]
pub fn from_entity_owned(entity: &EntityOwned) -> Self {
entity.entity
}
pub fn try_into_entity_owned(self) -> Option<EntityOwned> {
EntityArena::global().remove(self)
}
#[inline]
pub fn is_valid(self) -> bool {
World::is_valid_entity(self)
}
pub fn clone_entity(self, name: &str) -> Self {
let entity = World::clone_entity(name, self);
EntityArena::global().insert(EntityOwned { entity })
}
pub fn try_destroy(self) {
let _ = EntityArena::global().remove(self);
}
pub fn schedule_for_destruction(self) {
let _ = EntityArena::global().schedule_for_destruction(self);
}
pub fn add_component(self, component_type: ComponentType) {
World::add_component(self, component_type);
}
pub fn add<T: ComponentTrait>(self) -> T {
World::add_component(self, T::get_type());
T::from_entity(self)
}
pub fn copy_component(self, src: Self, component_type: ComponentType) {
World::copy_component(self, src, component_type);
}
pub fn copy<T: ComponentTrait>(self, src: Self) -> T {
World::copy_component(self, src, T::get_type());
T::from_entity(self)
}
#[inline]
pub fn has<T: ComponentTrait>(self) -> bool {
World::has_component(self, T::get_type())
}
#[inline]
pub fn get<T: ComponentTrait>(self) -> Option<T> {
self.has::<T>().then(|| T::from_entity(self))
}
#[inline]
pub fn has_component(self, component_type: ComponentType) -> bool {
World::has_component(self, component_type)
}
pub fn remove_component(self, component_type: ComponentType) {
World::remove_component(self, component_type);
}
pub fn remove<T: ComponentTrait>(self) {
World::remove_component(self, T::get_type());
}
pub fn name(self) -> String {
if !self.is_valid() {
"<invalid>".to_owned()
} else if let Some(entity_info) = self.get::<EntityInfo>() {
entity_info.name()
} else {
"<unknown>".to_owned()
}
}
#[inline]
pub fn entity_info(self) -> EntityInfo {
EntityInfo::from_entity(self)
}
#[inline]
pub fn mesh_style(self) -> MeshStyle {
MeshStyle::from_entity(self)
}
#[inline]
pub fn transform(self) -> Transform {
Transform::from_entity(self)
}
#[inline]
pub fn physics(self) -> Physics {
Physics::from_entity(self)
}
#[inline]
pub fn render(self) -> Render {
Render::from_entity(self)
}
#[inline]
pub fn joint(self) -> Joint {
Joint::from_entity(self)
}
#[inline]
pub fn d6_joint(self) -> D6Joint {
D6Joint::from_entity(self)
}
#[inline]
pub fn camera(self) -> Camera {
Camera::from_entity(self)
}
#[inline]
pub fn velocity(self) -> Velocity {
Velocity::from_entity(self)
}
#[inline]
pub fn bounds(self) -> Bounds {
Bounds::from_entity(self)
}
#[inline]
pub fn tag(self) -> Tag {
Tag::from_entity(self)
}
#[inline]
pub fn layer(self) -> Layer {
Layer::from_entity(self)
}
#[inline]
pub fn physics_character(self) -> PhysicsCharacter {
PhysicsCharacter::from_entity(self)
}
#[inline]
pub fn sdf_model(self) -> SdfModel {
SdfModel::from_entity(self)
}
#[inline]
pub fn audio_source(self) -> AudioSource {
AudioSource::from_entity(self)
}
}
impl EntityOwned {
#[inline]
pub fn is_valid(&self) -> bool {
self.entity.is_valid()
}
pub fn create_empty(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::Empty);
Self { entity }
}
pub fn create(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::PhysicsObject);
Self { entity }
}
pub fn create_non_physics(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::NonPhysicsObject);
Self { entity }
}
pub fn create_camera(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::Camera);
Self { entity }
}
pub fn clone_entity(&self, name: &str) -> Self {
let entity = World::clone_entity(name, self.entity);
Self { entity }
}
pub fn add_component(&self, component_type: ComponentType) {
self.entity.add_component(component_type);
}
pub fn add<T: ComponentTrait>(&self) -> T {
self.entity.add::<T>()
}
pub fn copy_component(&self, src: Entity, component_type: ComponentType) {
self.entity.copy_component(src, component_type);
}
pub fn copy<T: ComponentTrait>(&self, src: Entity) -> T {
self.entity.copy::<T>(src)
}
#[inline]
pub fn has<T: ComponentTrait>(&self) -> bool {
self.entity.has::<T>()
}
#[inline]
pub fn get<T: ComponentTrait>(&self) -> Option<T> {
self.entity.get::<T>()
}
#[inline]
pub fn has_component(&self, component_type: ComponentType) -> bool {
self.entity.has_component(component_type)
}
pub fn remove_component(&self, component_type: ComponentType) {
self.entity.remove_component(component_type);
}
pub fn remove<T: ComponentTrait>(&self) {
self.entity.remove::<T>();
}
fn destroy(&self) {
World::destroy_entity(self.entity);
crate::world::World::instance_mut().notify_destroyed(self.entity);
}
#[inline]
pub fn mesh_style(&self) -> MeshStyle {
self.entity.mesh_style()
}
#[inline]
pub fn transform(&self) -> Transform {
self.entity.transform()
}
#[inline]
pub fn physics(&self) -> Physics {
self.entity.physics()
}
#[inline]
pub fn render(&self) -> Render {
self.entity.render()
}
#[inline]
pub fn joint(&self) -> Joint {
self.entity.joint()
}
#[inline]
pub fn d6_joint(&self) -> D6Joint {
self.entity.d6_joint()
}
#[inline]
pub fn camera(&self) -> Camera {
self.entity.camera()
}
#[inline]
pub fn velocity(&self) -> Velocity {
self.entity.velocity()
}
#[inline]
pub fn bounds(&self) -> Bounds {
self.entity.bounds()
}
#[inline]
pub fn tag(&self) -> Tag {
self.entity.tag()
}
#[inline]
pub fn layer(&self) -> Layer {
self.entity.layer()
}
#[inline]
pub fn physics_character(&self) -> PhysicsCharacter {
self.entity.physics_character()
}
#[inline]
pub fn sdf_model(&self) -> SdfModel {
self.entity.sdf_model()
}
#[inline]
pub fn audio_source(&self) -> AudioSource {
self.entity.audio_source()
}
#[inline]
pub fn as_ffi(&self) -> ffi::EntityHandle {
self.as_entity().as_ffi()
}
#[inline]
pub fn as_entity(&self) -> Entity {
self.entity
}
#[inline]
pub fn name(&self) -> String {
self.entity.name()
}
}
impl From<&EntityOwned> for Entity {
#[inline]
fn from(item: &EntityOwned) -> Self {
item.entity
}
}
impl AsRef<Entity> for EntityOwned {
#[inline]
fn as_ref(&self) -> &Entity {
&self.entity
}
}
#[derive(Default)]
pub struct EntityArena {
entities: HashMap<Entity, EntityOwned>,
pending_destroys: Option<Vec<Entity>>,
}
impl EntityArena {
pub fn insert(&mut self, entity: EntityOwned) -> Entity {
let key = entity.entity;
let _ = self.entities.insert(key, entity);
key
}
#[inline]
pub fn remove(&mut self, entity: Entity) -> Option<EntityOwned> {
self.entities.remove(&entity)
}
pub fn schedule_for_destruction(&mut self, entity: Entity) -> Option<Entity> {
if self.entities.contains_key(&entity) {
if let Some(pending_destroys) = &mut self.pending_destroys {
pending_destroys.push(entity);
} else {
self.pending_destroys = Some(vec![entity]);
}
Some(entity)
} else {
None
}
}
pub fn destroy_pending_entities(&mut self) {
puffin::profile_function!();
if let Some(pending_destroys) = &mut self.pending_destroys {
while let Some(pending_destroy) = pending_destroys.pop() {
self.entities.remove(&pending_destroy);
}
pending_destroys.clear();
}
}
#[inline]
pub fn destroy_all(&mut self) {
self.entities.clear();
}
#[inline]
pub fn global() -> &'static mut Self {
unsafe {
static mut GLOBAL: Option<EntityArena> = None;
if GLOBAL.is_none() {
GLOBAL = Some(Self::default());
}
GLOBAL.as_mut().unwrap()
}
}
}