use super::{components::*, ffi, ffi::ComponentType, World};
pub use ffi::MeshOrigin;
use std::{collections::HashMap, fmt};
/// An Entity is a single "thing" in the gameworld.
///
/// It can have multiple components attached,
/// giving it a position in the world, a mesh to display, physical properties, and so forth.
///
/// The Entity struct has accessors to access its components, like `transform`, `mesh_style`,
/// `physics` and so on.
///
/// Represents a raw non-owned reference to an entity, an `EntityHandle` with functionality.
/// Use `EntityOwned` if you want the entity to get destroyed if it goes out of scope.
#[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
}
/// Check if handle is valid
///
/// NOTE: This does not check whether there's actually an entity represented by this
/// entity handle. For that, use `World::is_valid_entity`.
pub fn is_valid_handle(self) -> bool {
(self.0 & 0xFFFF_FFFF) != 0xFFFF_FFFF
}
/// Returns an eternally invalid entity handle.
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_some(eh)
}
pub fn try_to_ffi(self) -> Option<ffi::EntityHandle> {
self.is_valid().then(|| self.as_ffi())
}
}
/// An Entity is a single "thing" in the gameworld.
///
/// It can have multiple components attached,
/// giving it a position in the world, a mesh to display, physical properties, and so forth.
///
/// The Entity struct has accessors to access its components, like `transform`, `mesh_style`,
/// `physics` and so on.
///
/// This type will own its entity and destroy it when drop is called (i.e. when it goes out of scope).
#[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()
}
}
/// Non-owning reference to an entity
//pub type EntityRef = std::mem::ManuallyDrop<Entity>;
impl Entity {
/// Creates an empty world entity with just a name.
///
/// Add components of your preference to it.
pub fn create_empty(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create_empty(name))
}
/// Creates a world entity with [`Transform`], [`Render`], [`Physics`], and [`MeshStyle`] components.
///
/// `name` - only used for display in the inspector and similar, it cannot later
/// be changed or queried to affect the game so don't store data in it.
pub fn create(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create(name))
}
/// Creates a world entity with [`Transform`], [`Render`] and [`MeshStyle`] components.
///
/// `name` - only used for display in the inspector and similar, it cannot later
/// be changed or queried to affect the game so don't store data in it.
pub fn create_non_physics(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create_non_physics(name))
}
/// Creates a world entity with a [`Camera`] and [`Transform`] component.
///
/// An entity with a [`Camera`] component is special in that the
/// rotation of its transform component will be controlled directly by the client.
/// See the documentation of [`Camera`] for more details.
pub fn create_camera(name: &str) -> Self {
EntityArena::global().insert(EntityOwned::create_camera(name))
}
/// Creates a reference to an entity from an owned entity. This one won't be owning the entity.
#[inline]
pub fn from_entity_owned(entity: &EntityOwned) -> Self {
entity.entity
}
/// If the entity exists in the global arena, you can use this to get ownership of this entity
pub fn try_into_entity_owned(self) -> Option<EntityOwned> {
EntityArena::global().remove(self)
}
/// Lets you check whether this entity still exists and is valid.
#[inline]
pub fn is_valid(self) -> bool {
World::is_valid_entity(self)
}
/// Clones this world entity and all its components.
///
/// `name` - only used for display in the inspector and similar, it cannot later
/// be changed or queried to affect the game so don't store data in it.
/// Will be concatenated to the name of the source of the clone.
///
/// Will always be cloned and placed in the global `EntityArena`.
pub fn clone_entity(self, name: &str) -> Self {
let entity = World::clone_entity(name, self);
EntityArena::global().insert(EntityOwned { entity })
}
/// Destroys the entity if it is in a global arena.
///
/// Further access to the entity (like by keeping the id around) after
/// this is an error.
pub fn try_destroy(self) {
let _ = EntityArena::global().remove(self);
}
/// Schedules the entity for destruction if it is in a global arena.
/// A call to `EntityArena::global().destroy_pending_entities()` will
/// execute the order. Should usually be executed at the beginning of the
/// update function to destroy entities after an update step.
///
/// Further access to the entity (like by keeping the id around) after
/// `EntityArena::global().destroy_pending_entities()` has been executed
/// is an error.
pub fn schedule_for_destruction(self) {
let _ = EntityArena::global().schedule_for_destruction(self);
}
/// Adds a component to an entity.
pub fn add_component(self, component_type: ComponentType) {
World::add_component(self, component_type);
}
/// Adds a component to an entity.
pub fn add<T: ComponentTrait>(self) -> T {
World::add_component(self, T::get_type());
T::from_entity(self)
}
/// Copies a component from the entity in `src`.
pub fn copy_component(self, src: Self, component_type: ComponentType) {
World::copy_component(self, src, component_type);
}
/// Copies a component from the entity in `src`.
pub fn copy<T: ComponentTrait>(self, src: Self) -> T {
World::copy_component(self, src, T::get_type());
T::from_entity(self)
}
/// Returns whether the entity has the component or not.
#[inline]
pub fn has<T: ComponentTrait>(self) -> bool {
World::has_component(self, T::get_type())
}
/// Gets an interface to the component.
///
/// Returns an option, none if the component doesn't exist.
#[inline]
pub fn get<T: ComponentTrait>(self) -> Option<T> {
self.has::<T>().then(|| T::from_entity(self))
}
/// Returns whether the entity has the component or not.
#[inline]
pub fn has_component(self, component_type: ComponentType) -> bool {
World::has_component(self, component_type)
}
/// Removes a component from an entity.
pub fn remove_component(self, component_type: ComponentType) {
World::remove_component(self, component_type);
}
/// Removes a component from an entity.
pub fn remove<T: ComponentTrait>(self) {
World::remove_component(self, T::get_type());
}
/// Retrieves the name of the entity
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()
}
}
/// Accessor for the `EntityInfo` component, if it exists.
#[inline]
pub fn entity_info(self) -> EntityInfo {
EntityInfo::from_entity(self)
}
/// Accessor for the `MeshStyle` component, if it exists.
#[inline]
pub fn mesh_style(self) -> MeshStyle {
MeshStyle::from_entity(self)
}
/// Accessor for the `Transform` component, if it exists.
#[inline]
pub fn transform(self) -> Transform {
Transform::from_entity(self)
}
/// Accessor for the `Physics` component, if it exists.
#[inline]
pub fn physics(self) -> Physics {
Physics::from_entity(self)
}
/// Accessor for the `Render` component, if it exists.
#[inline]
pub fn render(self) -> Render {
Render::from_entity(self)
}
/// Accessor for the `Joint` component, if it exists.
#[inline]
pub fn joint(self) -> Joint {
Joint::from_entity(self)
}
/// Accessor for the `D6Joint` component, if it exists.
#[inline]
pub fn d6_joint(self) -> D6Joint {
D6Joint::from_entity(self)
}
/// Accessor for the `Camera` component, if it exists.
#[inline]
pub fn camera(self) -> Camera {
Camera::from_entity(self)
}
/// Accessor for the `Bounds` component, if it exists.
#[inline]
pub fn bounds(self) -> Bounds {
Bounds::from_entity(self)
}
/// Accessor for the `Tag` component, if it exists.
#[inline]
pub fn tag(self) -> Tag {
Tag::from_entity(self)
}
/// Accessor for the `Layer` component, if it exists.
#[inline]
pub fn layer(self) -> Layer {
Layer::from_entity(self)
}
/// Accessor for the `SdfModel` component, if it exists.
#[inline]
pub fn sdf_model(self) -> SdfModel {
SdfModel::from_entity(self)
}
/// Accessor for the `AudioSource` component, if it exists.
#[inline]
pub fn audio_source(self) -> AudioSource {
AudioSource::from_entity(self)
}
}
impl EntityOwned {
/// Lets you check whether this entity still exists and is valid.
#[inline]
pub fn is_valid(&self) -> bool {
self.entity.is_valid()
}
/// Creates an empty world entity with just a name.
///
/// Add components of your preference to it.
pub fn create_empty(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::Empty);
Self { entity }
}
/// Creates a world entity with [`Transform`], [`Render`], [`Physics`], and [`MeshStyle`] components.
///
/// `name` - only used for display in the inspector and similar, it cannot later
/// be changed or queried to affect the game so don't store data in it.
pub fn create(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::PhysicsObject);
Self { entity }
}
/// Creates a world entity with [`Transform`], [`Render`] and [`MeshStyle`] components.
///
/// `name` - only used for display in the inspector and similar, it cannot later
/// be changed or queried to affect the game so don't store data in it.
pub fn create_non_physics(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::NonPhysicsObject);
Self { entity }
}
/// Creates a world entity with a [`Camera`] and [`Transform`] component.
///
/// An entity with a [`Camera`] component is special in that the
/// rotation of its transform component will be controlled directly by the client.
/// See the documentation of [`Camera`] for more details.
pub fn create_camera(name: &str) -> Self {
let entity = World::create_entity(name, ffi::EntityTemplate::Camera);
Self { entity }
}
/// Clones this world entity and all its components.
///
/// `name` - only used for display in the inspector and similar, it cannot later
/// be changed or queried to affect the game so don't store data in it.
/// Will be concatenated to the name of the source of the clone.
pub fn clone_entity(&self, name: &str) -> Self {
let entity = World::clone_entity(name, self.entity);
Self { entity }
}
/// Adds a component to an entity.
pub fn add_component(&self, component_type: ComponentType) {
self.entity.add_component(component_type);
}
/// Adds a component to an entity.
pub fn add<T: ComponentTrait>(&self) -> T {
self.entity.add::<T>()
}
/// Copies a component from the entity in `src`.
pub fn copy_component(&self, src: Entity, component_type: ComponentType) {
self.entity.copy_component(src, component_type);
}
/// Copies a component from the entity in `src`.
pub fn copy<T: ComponentTrait>(&self, src: Entity) -> T {
self.entity.copy::<T>(src)
}
/// Returns whether the entity has the component or not.
#[inline]
pub fn has<T: ComponentTrait>(&self) -> bool {
self.entity.has::<T>()
}
/// Gets an interface to the component.
///
/// Returns an option, none if the component doesn't exist.
#[inline]
pub fn get<T: ComponentTrait>(&self) -> Option<T> {
self.entity.get::<T>()
}
/// Returns whether the entity has the component or not.
#[inline]
pub fn has_component(&self, component_type: ComponentType) -> bool {
self.entity.has_component(component_type)
}
/// Removes a component from an entity.
pub fn remove_component(&self, component_type: ComponentType) {
self.entity.remove_component(component_type);
}
/// Removes a component from an entity.
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);
}
/// Accessor for the `MeshStyle` component, if it exists.
#[inline]
pub fn mesh_style(&self) -> MeshStyle {
self.entity.mesh_style()
}
/// Accessor for the `Transform` component, if it exists.
#[inline]
pub fn transform(&self) -> Transform {
self.entity.transform()
}
/// Accessor for the `Physics` component, if it exists.
#[inline]
pub fn physics(&self) -> Physics {
self.entity.physics()
}
/// Accessor for the `Render` component, if it exists.
#[inline]
pub fn render(&self) -> Render {
self.entity.render()
}
/// Accessor for the `Joint` component, if it exists.
#[inline]
pub fn joint(&self) -> Joint {
self.entity.joint()
}
/// Accessor for the `D6Joint` component, if it exists.
#[inline]
pub fn d6_joint(&self) -> D6Joint {
self.entity.d6_joint()
}
/// Accessor for the `Camera` component, if it exists.
#[inline]
pub fn camera(&self) -> Camera {
self.entity.camera()
}
/// Accessor for the `Bounds` component, if it exists.
#[inline]
pub fn bounds(&self) -> Bounds {
self.entity.bounds()
}
/// Accessor for the `Tag` component, if it exists.
#[inline]
pub fn tag(&self) -> Tag {
self.entity.tag()
}
/// Accessor for the `Layer` component, if it exists.
#[inline]
pub fn layer(&self) -> Layer {
self.entity.layer()
}
/// Accessor for the `Sdf` component, if it exists.
#[inline]
pub fn sdf_model(&self) -> SdfModel {
self.entity.sdf_model()
}
/// Accessor for the `AudioSource` component, if it exists.
#[inline]
pub fn audio_source(&self) -> AudioSource {
self.entity.audio_source()
}
/// Gets the raw entity id.
#[inline]
pub fn as_ffi(&self) -> ffi::EntityHandle {
self.as_entity().as_ffi()
}
/// Gets the inner `Entity`
#[inline]
pub fn as_entity(&self) -> Entity {
self.entity
}
/// Retrieves the name of the 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
}
}
/// An `EntityArena` is a collection for holding on to entities. Use it to keep track of sets of entities
/// A global arena exists in which entities can be created and cloned
#[derive(Default)]
pub struct EntityArena {
// Do this for simplicity now. We might want to store more data in `EntityOwned`.
// Use slotmap as the host?
entities: HashMap<Entity, EntityOwned>,
pending_destroys: Option<Vec<Entity>>,
}
impl EntityArena {
/// Adds an owned entity to the arena
pub fn insert(&mut self, entity: EntityOwned) -> Entity {
let key = entity.entity;
let _ = self.entities.insert(key, entity);
key
}
/// Removes an entity from the arena using the entity handle,
/// If the entity was in the arena it is returned, otherwise None.
#[inline]
pub fn remove(&mut self, entity: Entity) -> Option<EntityOwned> {
self.entities.remove(&entity)
}
/// Schedules an entity for destruction using the entity handle,
/// Will be destroyed on the next call to `destroy_pending_entities`.
/// If the entity is in the arena a handle to it is returned, otherwise None.
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
}
}
/// Destroys all entities that have been scheduled for destruction using the
/// `schedule_for_destruction` function.
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();
}
// We don't set it to None here as we most likely will use it again.
}
/// Destroys all entities in the arena
#[inline]
pub fn destroy_all(&mut self) {
self.entities.clear();
}
/// Returns the global entity arena, used by `Entity::create` functions
#[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()
}
}
}