ark-api 0.17.0-pre.15

Ark API
Documentation
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()
        }
    }
}