ark-api 0.17.0-pre.15

Ark API
Documentation
//! # 🌐 World API
//!
//! A world consists of entities, which each simply is a set of components such as transform,
//! render properties, physical properties and so on. The World API lets you create, change
//! manipulate and destroy entities.
//!
//! For an overview, check out our [Developer Guide](https://ark.embark.dev/guide/api/world/index.html)
//!
//! If you're looking for immediate mode rendering instead of having persistent entities or physics managed
//! for you, you're probably more interested in the [Render API](https://ark.embark.dev/api/ark_api/render/index.html).
//! You can even combine the two. One possibility would be to do rendering of World API entities manually using the Render API
//! `Render` components, or simply to render transient visual effects using the Render API on top of a world.
//!
//! The documentation of `Entity` is a good starting point to figure out what can be done.
//!
//! ## Example
//!
//! Quick example of setting up a ball on a square piece of ground:
//!
//! ```
//! let ground_mesh = ...;
//! let ground_entity = Entity::create("ground");
//! ground_entity.render().mesh().set(ground_mesh);
//! ground_entity.physics().enable_static(PhysicsShape::Box);
//!
//! let ball_mesh = ...;
//! let ball_entity = Entity::create("ball");
//! ball_entity.render().mesh().set(ball_mesh);
//! ball_entity
//!     .transform()
//!     .position()
//!     .set(Vec3::new(0.0, 2.5, -40.0));
//! ball_entity.physics().enable_dynamic(10.0, PhysicsShape::Sphere);
//! ball_entity.physics().add_force(
//!     ForceType::Force,
//!     ForceMode::Impulse,
//!     Vec3::new(0.0, 0.0, 50000.0),
//! );
//! ```

mod ffi {
    pub use crate::ffi::{world_v0 as v0, world_v0::*};
    pub use crate::ffi::{world_v1 as v1, world_v1::*};
    pub use crate::ffi::{world_v2 as v2, world_v2::*};
    pub use crate::ffi::{world_v3 as v3, world_v3::*};
    pub use crate::ffi::{world_v4 as v4, world_v4::*};
}

pub use ffi::{
    AudioClipInfo, BoneWeightFlags, CameraProjectionMode, CombineMode, ComponentMetaDataEntry,
    ComponentType, ComponentsMetaDataEntry, CreateDataType, D6Axis, D6Drive, D6MotionType,
    DynamicLockFlags, EntityTemplate, ForceMode, ForceType, JointLimitType, JointType,
    MeshStyleFlags, MeshVisibilityFlags, ParameterMetaDataEntry, ParameterSemantic, RigidBodyMode,
    SdfSkinInfo, Space, TriggerEvent, Value, ValueData, ValueType, WorldDataType,
    {AnimationCurve, AnimationOptions, SpatialQueryOptions},
};

use crate::{Error, Quat, Vec2, Vec3, Vec4};

pub use ffi::MaterialDesc;

#[doc(hidden)]
pub use ffi::v3::API as FFI_API;

pub use ffi::v3::BoneTransform;
pub use ffi::v4::{
    EntityBounds, EntityDebugOptions, EntityMeshStyleTint, EntityRenderEnable, EntityStateFlags,
    EntityTransformConformal3, EntityValueType, EntityVelocity, MeasuredTextSize,
    RaycastQueryOptions, RaycastQueryWithOptions,
};

mod mesh;
pub use mesh::*;

mod entity;
pub use entity::*;

mod value_converter;
pub use value_converter::*;

#[macro_use]
mod value_accessor;
pub use value_accessor::*;

mod entity_messenger;
pub use entity_messenger::*;

#[macro_use]
mod components;
pub use components::*;

mod data;
pub use data::*;

mod player;
pub use player::*;

mod reflection;
pub use reflection::*;

mod param_type;
pub use param_type::*;

mod query;
pub use query::*;

use crate::api::world::entity_messenger::AnimationReplyFn;

use std::{
    cell::RefCell,
    ops::{Deref, DerefMut},
};

///////////////////////////////////////////////////////////////////////////////

#[derive(Copy, Clone, Debug, PartialEq)]
/// The limits for a parameter.
pub struct LimitPair {
    /// Lower limit.
    pub lower: f32,
    /// Upper limit.
    pub upper: f32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
/// A position and orientation, together.
pub struct Pose {
    /// The position of the pose.
    pub pos: Vec3,
    /// The rotation of the pose.
    pub orientation: Quat,
}

/// Query parameters for doing raycasts.
#[derive(Copy, Clone, Debug)]
pub struct RaycastQuery {
    /// Ray to check for obstacles along.
    pub ray: macaw::Ray3,
    /// Layers to include in the check.
    /// Defaults to everything.
    pub layer_mask: EntityLayerMask,
    /// Optional entity to ignore.
    /// Even if the ray intersects this entity, no hit will be reported for it.
    /// Defaults to None.
    pub ignore_entity: Option<Entity>,
    /// No hits above this distance will be reported.
    /// Defaults to infinity.
    pub max_distance: f32,
    /// Additional options for this raycast query.
    pub options: RaycastQueryOptions,
    /// If >0, sweep a sphere rather than a ray.
    pub spherecast_radius: f32,
}

impl Default for RaycastQuery {
    fn default() -> Self {
        Self {
            ray: macaw::Ray3::ZERO,
            layer_mask: EntityLayerMask::everything(),
            ignore_entity: None,
            max_distance: std::f32::INFINITY,
            options: RaycastQueryOptions::empty(),
            spherecast_radius: 0.0,
        }
    }
}

/// A single hit from a raycast query.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct RaycastHit {
    /// Point in world space that was hit.
    ///
    /// This could technically be calculated by using the original ray together with the `distance` field.
    /// But that would require callers to keep track of their query object and also ensure their ray directions are normalized
    /// which is not as convenient.
    pub point: Vec3,

    /// The distance along the ray.
    ///
    /// The hits are sorted by this distance when returned from raycast and spherecast queries.
    /// In a raycast this is equal to `ray.origin.distance(hit.position)`,
    /// but in a spherecast it can be different.
    pub distance: f32,

    /// World space normal of the surface that was hit.
    pub normal: Vec3,

    /// Entity that was hit.
    pub entity: Entity,
}

impl RaycastQuery {
    fn as_ffi(&self) -> ffi::v4::SpherecastQuery {
        ffi::v4::SpherecastQuery {
            ray: ffi::Ray {
                origin: self.ray.origin.into(),
                dir: self.ray.dir.into(),
            },
            layer_mask: self.layer_mask.value(),
            ignore_entity: self.ignore_entity.unwrap_or_else(Entity::invalid).as_ffi(),
            max_distance: self.max_distance,
            options: self.options,
            spherecast_radius: self.spherecast_radius,
            _pad: Default::default(),
        }
    }
}

impl RaycastHit {
    fn from_ffi(hit: ffi::v3::RaycastHit) -> Self {
        Self {
            point: hit.point.into(),
            distance: hit.distance,
            normal: hit.normal.into(),
            entity: Entity::from_ffi(hit.entity),
        }
    }
}

/// Mesh style. Differs from `world::MeshStyle` in that `MeshStyle` is an entity, but
/// `MeshStyleData` is plain data.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct MeshStyleData {
    /// Diffuse color tint
    pub diffuse_tint: Vec4,
    /// Style flags
    pub flags: MeshStyleFlags,
}

impl MeshStyleData {
    /// Creates a mesh style with a diffuse tint
    pub fn new(diffuse_tint: Vec4) -> Self {
        Self {
            diffuse_tint,
            flags: MeshStyleFlags::default(),
        }
    }
}

impl Default for MeshStyleData {
    fn default() -> Self {
        Self {
            diffuse_tint: Vec4::ONE,
            flags: MeshStyleFlags::default(),
        }
    }
}

/// Create `MeshStyle` through builder pattern
#[derive(Default, Debug, Clone, Copy)]
pub struct MeshStyleDataBuilder {
    style: MeshStyleData,
}

impl MeshStyleDataBuilder {
    /// Creates a new builder
    pub fn new() -> Self {
        Self::default()
    }

    /// Adds diffuse color tinting
    pub fn with_diffuse_tint(&mut self, tint: Vec4) -> &mut Self {
        self.style.diffuse_tint = tint;
        self
    }

    /// Sets lighting toggle
    pub fn with_lighting(&mut self, e: bool) -> &mut Self {
        self.style.flags.set(MeshStyleFlags::LIGHTING, e);
        self
    }

    /// Sets alpha blending toggle
    pub fn with_alpha_blending(&mut self, e: bool) -> &mut Self {
        self.style.flags.set(MeshStyleFlags::ALPHA_BLENDING, e);
        self
    }

    /// Sets pre-multiplied alpha toggle
    pub fn with_premultiplied_alpha(&mut self, e: bool) -> &mut Self {
        self.style.flags.set(MeshStyleFlags::PREMULTIPLIED_ALPHA, e);
        self
    }

    /// Sets flat shading toggle. Flat shading gives smooth objects a faceted look, by not interpolating
    /// normals across surfaces before lighting.
    pub fn with_flat_shading(&mut self, e: bool) -> &mut Self {
        self.style.flags.set(MeshStyleFlags::FLAT_SHADING, e);
        self
    }

    /// Will make the mesh face the camera at all times, can be handy for things like particles or ui.
    pub fn with_billboard_rendering(&mut self, e: bool) -> &mut Self {
        self.style.flags.set(MeshStyleFlags::BILLBOARD, e);
        self
    }

    /// Will make the mesh two-sided (backface culling is not applied).
    /// Only recommended for solid meshes (and even then, when you don't need this, don't use it).
    pub fn with_two_sided(&mut self, e: bool) -> &mut Self {
        self.style.flags.set(MeshStyleFlags::TWO_SIDED, e);
        self
    }

    /// Builds mesh style
    pub fn build(&self) -> MeshStyleData {
        self.style
    }
}

/// Error value that is returned from get/set entity value functions.
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum EntityValueError {
    /// The component parameter value is a NaN value.
    NanValue,
    /// The component parameter value is an infinite value.
    InfiniteParamValue,
    /// The supplied component type is invalid.
    InvalidComponentType,
    /// The supplied component parameter id is invalid.
    InvalidComponentParameterId,
    /// The component did not exist.
    InvalidComponent,
    /// Invalid supplied entity key
    InvalidEntityKey,
    /// Invalid parent of parent (a parent was pointing to an invalid entity)
    InvalidParentOfParent,
    /// Trying to set an entity value that is incompatible with the component parameter value type.
    IncompatibleValueType,
    /// Trying to set an entity value that is incompatible with the component parameter value.
    IncompatibleValue,
    /// Could not set the entity component parameter value.
    Unsettable,
    /// Could not get the entity component parameter value.
    Ungettable,
    /// The component was not available.
    NotAvailable,
    /// Unknown error occurred.
    Unknown(String),
}

impl std::fmt::Display for EntityValueError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            EntityValueError::NanValue => {
                write!(f, "The component parameter value is a NaN value.")
            }
            EntityValueError::InfiniteParamValue => {
                write!(f, "The component parameter value is an infinite value.")
            }
            EntityValueError::InvalidComponentType => {
                write!(f, "The supplied component type is invalid.")
            }
            EntityValueError::InvalidComponentParameterId => {
                write!(f, "The supplied component parameter id is invalid.")
            }
            EntityValueError::InvalidComponent => write!(f, "The component did not exist."),
            EntityValueError::InvalidEntityKey => write!(f, "Invalid supplied entity key."),
            EntityValueError::InvalidParentOfParent => write!(
                f,
                " Invalid parent of parent (a parent was pointing to an invalid entity)."
            ),
            EntityValueError::IncompatibleValueType => {
                write!(f, "Trying to set an entity value that is incompatible with the component parameter value type.")
            }
            EntityValueError::IncompatibleValue => {
                write!(f, "Trying to set an entity value that is incompatible with the component parameter value.")
            }
            EntityValueError::Unsettable => {
                write!(f, "Could not set the entity component parameter value.")
            }
            EntityValueError::Ungettable => {
                write!(f, "Could not get the entity component parameter value.")
            }
            EntityValueError::NotAvailable => {
                write!(f, "The component was not available.")
            }
            EntityValueError::Unknown(e) => {
                write!(f, "{e}")
            }
        }?;
        Ok(())
    }
}

impl std::error::Error for EntityValueError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

impl From<ffi::v4::EntityValueError> for EntityValueError {
    fn from(error: ffi::v4::EntityValueError) -> Self {
        match error {
            ffi::v4::EntityValueError::NanValue => EntityValueError::NanValue,
            ffi::v4::EntityValueError::InfiniteParamValue => EntityValueError::InfiniteParamValue,
            ffi::v4::EntityValueError::InvalidComponentType => {
                EntityValueError::InvalidComponentType
            }
            ffi::v4::EntityValueError::InvalidComponentParameterId => {
                EntityValueError::InvalidComponentParameterId
            }
            ffi::v4::EntityValueError::InvalidComponent => EntityValueError::InvalidComponent,
            ffi::v4::EntityValueError::InvalidEntityKey => EntityValueError::InvalidEntityKey,
            ffi::v4::EntityValueError::InvalidParentOfParent => {
                EntityValueError::InvalidParentOfParent
            }
            ffi::v4::EntityValueError::IncompatibleValueType => {
                EntityValueError::IncompatibleValueType
            }
            ffi::v4::EntityValueError::IncompatibleValue => EntityValueError::IncompatibleValue,
            ffi::v4::EntityValueError::Unsettable => EntityValueError::Unsettable,
            ffi::v4::EntityValueError::Ungettable => EntityValueError::Ungettable,
            ffi::v4::EntityValueError::NotAvailable => EntityValueError::NotAvailable,
            e @ (ffi::v4::EntityValueError::Undefined | _) => {
                EntityValueError::Unknown(format!("Unknown error code '{e:?}' returned."))
            }
        }
    }
}

/// World implements the low-level entity API and the mesh API.
///
/// For ease of development, the wrappers (`Entity`, `Environment` etc) are recommended for
/// entity management.
pub struct World {
    // We double buffer this to keep track of what was destroyed previous frame.
    entities_destroyed_this_frame: Vec<Entity>,
    entities_destroyed_previous_frame: Vec<Entity>,
}

static mut WORLD: Option<RefCell<World>> = None;

impl World {
    fn new() -> Self {
        Self {
            entities_destroyed_this_frame: vec![],
            entities_destroyed_previous_frame: vec![],
        }
    }

    /// Get the `World` singleton.
    pub fn instance_mut() -> impl DerefMut<Target = World> {
        unsafe { WORLD.get_or_insert_with(|| RefCell::new(Self::new())) }.borrow_mut()
    }

    /// Get the `World` singleton.
    pub fn instance() -> impl Deref<Target = World> {
        unsafe { WORLD.get_or_insert_with(|| RefCell::new(Self::new())) }.borrow()
    }

    fn next_frame(&mut self) {
        std::mem::swap(
            &mut self.entities_destroyed_previous_frame,
            &mut self.entities_destroyed_this_frame,
        );
        self.entities_destroyed_this_frame.clear();
    }

    /// Creates a world entity, from one of several templates (`entity_type`).
    ///
    /// * `name`: only relevant for keeping track of your object during development
    ///
    /// * `entity_template`: Chooses between one of a few "templates" (sets of precreated components):
    ///   - `EntityTemplate::Empty`
    ///   - `EntityTemplate::Object`
    ///   - `EntityTemplate::Environment`
    ///   - `EntityTemplate::MeshStyle`
    ///   - `EntityTemplate::Camera`
    #[inline]
    pub fn create_entity(name: &str, entity_template: EntityTemplate) -> Entity {
        Entity::from_ffi(ffi::create_entity(name, entity_template))
    }

    /// Adds a component to an entity.
    #[inline]
    pub fn add_component(entity: Entity, component_type: ComponentType) {
        assert!(
            entity.is_valid(),
            "Trying to access {:?} on invalid entity",
            component_type
        );
        ffi::add_component(entity.0, component_type);
    }

    /// Removes a component from an entity.
    #[inline]
    pub fn remove_component(entity: Entity, component_type: ComponentType) {
        assert!(
            entity.is_valid(),
            "Trying to access {:?} on invalid entity",
            component_type
        );
        ffi::remove_component(entity.0, component_type);
    }

    /// Checks whether an entity has a component.
    #[inline]
    pub fn has_component(entity: Entity, component_type: ComponentType) -> bool {
        assert!(
            entity.is_valid(),
            "Trying to access {:?} on invalid entity",
            component_type
        );
        ffi::has_component(entity.0, component_type) != 0
    }

    /// Destroys an entity. Attempting to access the entity after this is an error.
    #[inline]
    pub fn destroy_entity(entity: Entity) {
        ffi::destroy_entity(entity.0);
    }

    /// Clones an entity with all its components and returns the handle to the new entity.
    #[inline]
    pub fn clone_entity(name: &str, entity_src: Entity) -> Entity {
        let mut dest = Entity::invalid().as_ffi();
        ffi::clone_entities(name, std::slice::from_mut(&mut dest), &[entity_src.0]);
        Entity::from_ffi(dest)
    }

    /// Clones multiple entities with all their components and returns the handles to the new entities.
    ///
    /// The name passed will be concatenated to the name of each source entity.
    #[inline]
    pub fn clone_entities(name: &str, entity_dst: &mut [Entity], entity_src: &[Entity]) {
        let src = unsafe { &*(entity_src as *const [Entity] as *const [ffi::EntityHandle]) };
        let dst = unsafe { &mut *(entity_dst as *mut [Entity] as *mut [ffi::EntityHandle]) };
        ffi::clone_entities(name, dst, src);
    }

    /// Copies a component from an entity to another. Creates the component if it doesn't exists.
    #[inline]
    pub fn copy_component(entity_dst: Entity, entity_src: Entity, component_type: ComponentType) {
        ffi::copy_component(entity_dst.0, entity_src.0, component_type);
    }

    /// Lets you check whether an `EntityHandle` points to a valid entity.
    ///
    /// If it has existed but been destroyed, the return value is false.
    #[inline]
    pub fn is_valid_entity(entity: Entity) -> bool {
        ffi::is_valid_entity(entity.0) != 0
    }

    /// Sets the value of a property of a component belonging to an entity.
    ///
    /// This can panic if an invalid entity handle, component type, parameter id, or value was supplied.
    /// Make sure the entity and component actually exist and use the right value for it.
    ///
    /// Use `try_set_entity_value` for a non panicking version of this function.
    #[inline]
    pub fn set_entity_value(
        entity: Entity,
        component_type: ComponentType,
        param_id: u32,
        value: &Value,
    ) {
        ffi::set_entity_value_checked(entity.0, component_type, param_id, value);
    }

    /// Tries to set the value of a property of a component belonging to an entity.
    ///
    /// Returns `EntityValueError` if the set operation failed.
    #[inline]
    pub fn try_set_entity_value(
        entity: Entity,
        component_type: ComponentType,
        param_id: u32,
        value: &Value,
    ) -> Result<(), EntityValueError> {
        let mut error = ffi::v4::EntityValueError::Undefined;

        let ffi_result =
            ffi::try_set_entity_value(entity.0, component_type.into(), param_id, value, &mut error);

        match ffi_result {
            Ok(_) => Ok(()),
            Err(_e) => Err(error.into()),
        }
    }

    /// Gets the value of a property of a component belonging to an entity.
    ///
    /// This can panic if an invalid entity handle, component type, or parameter id was supplied.
    /// Make sure the entity and component actually exist.
    ///
    /// Use `try_set_entity_value` for a non panicking version of this function.
    #[inline]
    pub fn get_entity_value(entity: Entity, component_type: ComponentType, param_id: u32) -> Value {
        let mut value = unsafe { std::mem::zeroed::<Value>() };
        ffi::get_entity_value_checked(entity.0, component_type, param_id, &mut value);
        value
    }

    /// Tries to get the value of a property of a component belonging to an entity.
    ///
    /// Returns `EntityValueError` if the get operation failed.
    #[inline]
    pub fn try_get_entity_value(
        entity: Entity,
        component_type: ComponentType,
        param_id: u32,
    ) -> Result<Value, EntityValueError> {
        let mut error = ffi::v4::EntityValueError::Undefined;
        let mut value = unsafe { std::mem::zeroed::<Value>() };

        let ffi_result = ffi::try_get_entity_value(
            entity.0,
            component_type.into(),
            param_id,
            &mut value,
            &mut error,
        );

        match ffi_result {
            Ok(_) => Ok(value),
            Err(_e) => Err(error.into()),
        }
    }

    /// Retrieves values of the entities passed through the slice `entities`.
    ///
    /// Careful attention that the `out_data` element size and layout matches the corresponding `EntityValueType` struct, should be
    /// taken.
    #[inline]
    pub fn get_entity_values<T: Sized>(
        entities: &[Entity],
        value_type: ffi::v4::EntityValueType,
        out_data: &mut Vec<T>,
    ) -> Result<(), Error> {
        if std::mem::size_of::<T>() != value_type.size_of_element() as usize {
            return Err(Error::InvalidArguments);
        }

        out_data.reserve(entities.len());

        // Our Entity wrapper is just a transparent newtype wrapper around the ffi::EntityHandle
        // so we can safely transmute a slice of it. Also we want to cast the typed slice into
        // a slice of bytes.
        let (entities, out_data_slice) = unsafe {
            out_data.set_len(entities.len());

            (
                &*(entities as *const [Entity] as *const [u64]),
                std::slice::from_raw_parts_mut(
                    out_data.as_mut_ptr().cast::<u8>(),
                    out_data.len() * std::mem::size_of::<T>(),
                ),
            )
        };
        ffi::v4::get_entity_values(entities, value_type, out_data_slice);
        Ok(())
    }

    /// Sets the values of the entities passed through the slice `entities`. The length
    /// of the `out_data` slice needs to be the same as `entities` or a single value in which case
    /// it will be applied to all entities.
    ///
    /// Careful attention that the `in_data` element size and layout matches the corresponding `EntityValueType` struct, should be
    /// taken.
    pub fn set_entity_values<T: Sized>(
        entities: &[Entity],
        value_type: ffi::v4::EntityValueType,
        in_data: &[T],
    ) -> Result<(), Error> {
        if std::mem::size_of::<T>() != value_type.size_of_element() as usize {
            return Err(Error::InvalidArguments);
        }

        // Our Entity wrapper is just a transparent newtype wrapper around the ffi::EntityHandle
        // so we can safely transmute a slice of it. Also we want to cast the typed slice into
        // a slice of bytes.
        let (entities, in_data_slice) = unsafe {
            (
                &*(entities as *const [Entity] as *const [u64]),
                std::slice::from_raw_parts(
                    in_data.as_ptr().cast::<u8>(),
                    in_data.len() * std::mem::size_of::<T>(),
                ),
            )
        };
        ffi::v4::set_entity_values(entities, value_type, in_data_slice);

        Ok(())
    }

    /// Sets the local transforms of the entities passed through the slice `entities`. The length
    /// of the `input` slice needs to be the same as `entities` or a single value in which case
    /// it will be applied to all entities.
    ///
    pub fn set_entity_local_transforms(
        entities: &[Entity],
        input: &[ffi::v4::EntityTransformConformal3],
    ) {
        Self::set_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityLocalTransformConformal3,
            input,
        )
        .expect("Failed to execute set_entity_values. Invalid arguments.");
    }

    /// Retrieves the local transforms of the entities passed through the slice `entities`.
    pub fn get_entity_local_transforms(
        entities: &[Entity],
        output: &mut Vec<ffi::v4::EntityTransformConformal3>,
    ) {
        Self::get_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityLocalTransformConformal3,
            output,
        )
        .expect("Failed to execute get_entity_values. Invalid arguments.");
    }

    /// Sets the world transforms of the entities passed through the slice `entities`. The length
    /// of the `input` slice needs to be the same as `entities` or a single value in which case
    /// it will be applied to all entities.
    ///
    pub fn set_entity_world_transforms(
        entities: &[Entity],
        input: &[ffi::v4::EntityTransformConformal3],
    ) {
        Self::set_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityWorldTransformConformal3,
            input,
        )
        .expect("Failed to execute set_entity_values. Invalid arguments.");
    }

    /// Retrieves the world transforms of the entities passed through the slice `entities`.
    pub fn get_entity_world_transforms(
        entities: &[Entity],
        output: &mut Vec<ffi::v4::EntityTransformConformal3>,
    ) {
        Self::get_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityWorldTransformConformal3,
            output,
        )
        .expect("Failed to execute get_entity_values. Invalid arguments.");
    }

    /// Retrieves the state of the local transforms of the entities passed through the slice `entities`.
    ///
    /// It is useful to call this method before [`World::get_entity_local_transforms`] to figure out which
    /// entities actually have the value.
    pub fn get_entities_state(entities: &[Entity], output: &mut Vec<ffi::v4::EntityStateFlags>) {
        Self::get_entity_values(entities, ffi::v4::EntityValueType::EntityStateFlags, output)
            .expect("Failed to execute get_entity_values. Invalid arguments.");
    }

    /// Retrieves the local bounds of the entities passed through the slice `entities`.
    pub fn get_entity_local_bounds(entities: &[Entity], output: &mut Vec<ffi::v4::EntityBounds>) {
        Self::get_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityLocalBounds,
            output,
        )
        .expect("Failed to execute get_entity_values. Invalid arguments.");
    }

    /// Retrieves the physics velocities of the entities passed through the slice `entities`.
    pub fn get_entity_physics_velocities(
        entities: &[Entity],
        output: &mut Vec<ffi::v4::EntityVelocity>,
    ) {
        Self::get_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityPhysicsVelocity,
            output,
        )
        .expect("Failed to execute get_entity_values. Invalid arguments.");
    }

    /// Sets the mesh style tints referenced from the entities passed through the slice `entities`. The length
    /// of the `input` slice needs to be the same as `entities` or a single value in which case
    /// it will be applied to all the entities.
    ///
    /// Note: Will set the tint on the mesh style that is used by this entity. This assumes
    /// each entity uses its own `MeshStyle`.
    ///
    pub fn set_entity_render_tints(entities: &[Entity], input: &[ffi::v4::EntityMeshStyleTint]) {
        Self::set_entity_values(entities, ffi::v4::EntityValueType::EntityRenderTint, input)
            .expect("Failed to execute set_entity_values. Invalid arguments.");
    }

    /// Sets if rendering is enabled for the entities passed through the slice `entities`. The length
    /// of the `input` slice needs to be the same as `entities` or a single value in which case
    /// it will be applied to all the entities.
    ///
    pub fn set_entity_render_enables(entities: &[Entity], input: &[ffi::v4::EntityRenderEnable]) {
        Self::set_entity_values(
            entities,
            ffi::v4::EntityValueType::EntityRenderEnable,
            input,
        )
        .expect("Failed to execute set_entity_values. Invalid arguments.");
    }

    /// Creates a physics body in the middle of the frame
    ///
    /// Takes parameters from the Physics component.
    /// Automatically used by the World API in `enable_dynamic` and similar functions.
    pub fn create_body_immediate(entity: Entity) {
        ffi::v3::create_body_immediate(entity.0);
    }

    /// Lets you query some properties of a raw mesh, including its bounding volume.
    #[inline]
    pub fn get_mesh_properties(mesh_handle: DataHandle) -> MeshProperties {
        ffi::get_mesh_properties(mesh_handle.as_ffi())
    }

    /// Lets you query the names of any morph targets associated with the mesh.
    ///
    /// It is recommended to store the return value instead of calling it every frame.
    #[inline]
    pub fn get_mesh_morph_target_names(mesh_handle: DataHandle) -> Vec<String> {
        let count = ffi::get_mesh_morph_target_count(mesh_handle.as_ffi());
        let mut retval = Vec::with_capacity(count as usize);
        for i in 0..count {
            let name_len = ffi::get_mesh_morph_target_name_len(mesh_handle.as_ffi(), i);
            let mut v = vec![0; name_len as usize];
            ffi::get_mesh_morph_target_name(mesh_handle.as_ffi(), i, &mut v);
            retval.push(String::from_utf8(v).unwrap());
        }
        retval
    }

    /// Lets you check whether a `DataHandle` points to a valid mesh.
    ///
    /// If it has existed but been destroyed, the return value is false.
    pub fn is_valid_mesh(mesh_handle: DataHandle) -> bool {
        ffi::is_valid_mesh(mesh_handle.0) != 0
    }

    /// Casts a ray through the world, returning the first hit.
    ///
    /// You can also use this to do spherecasts (a.k.a sphere sweeps or "thick" raycasts)
    /// by setting [`RaycastQuery::spherecast_radius`].
    pub fn raycast(raycast: &RaycastQuery) -> Option<RaycastHit> {
        let hit = RaycastHit::from_ffi(ffi::v4::spherecast(&raycast.as_ffi()));
        hit.entity.is_valid().then_some(hit)
    }

    /// Casts multiple rays through the world, returning the first hit for each.
    /// This is faster than calling `raycast` multiple times.
    ///
    /// You can also use this to do spherecasts (a.k.a sphere sweeps or "thick" raycasts)
    /// by setting [`RaycastQuery::spherecast_radius`].
    pub fn raycast_batched(
        raycasts: impl Iterator<Item = RaycastQuery>,
    ) -> Vec<Option<RaycastHit>> {
        // TODO: This is an annoying amount of unnecessary allocations and copies.
        // It would be nicer if we could just pass a [RaycastQuery] directly.
        // queries have almost the same memory representation, just a Option<Entity> replaced by a potentially invalid entity.
        // Raycast hits have exactly the same memory representation, but we do also wrap them in an Option.
        let raycasts_ffi = raycasts.map(|r| r.as_ffi()).collect::<Vec<_>>();
        let mut hits_ffi = Vec::<ffi::v3::RaycastHit>::with_capacity(raycasts_ffi.len());
        // SAFETY: The host will assign all items, and the ffi types do not have destructors or anything
        // Note that if `spherecast_batched` returns an API error then this data may remain uninitialized
        // but that's ok because we unwrap the result.
        #[allow(clippy::uninit_vec)]
        unsafe {
            hits_ffi.set_len(raycasts_ffi.len());
        }
        ffi::v4::spherecast_batched(&raycasts_ffi, &mut hits_ffi);

        hits_ffi
            .into_iter()
            .map(|h| {
                let hit = RaycastHit::from_ffi(h);
                hit.entity.is_valid().then_some(hit)
            })
            .collect::<Vec<_>>()
    }

    /// Casts a ray through the world (SLOW!).
    ///
    /// Reports the first hit or optionally any hit, which can be somewhat faster to compute,
    /// but which hit you get is not guaranteed in any way).
    ///
    /// One entity can be excluded to avoid self-hits.
    #[deprecated(note = "Use raycast instead")]
    pub fn ray_cast(
        ray_origin: Vec3,
        ray_dir: Vec3,
        min_t: f32,
        max_t: f32,
        any_hit: bool,
        exclude_entity: Entity,
    ) -> Option<(Entity, f32)> {
        let ray = ffi::Ray {
            origin: ray_origin.into(),
            dir: ray_dir.into(),
        };
        let mut t: f32 = -1.0;
        let handle = ffi::ray_cast(
            &ray,
            min_t,
            max_t,
            u32::from(any_hit),
            &mut t,
            exclude_entity.as_ffi(),
        );
        Entity::try_from_ffi(handle).map(|entity| (entity, t))
    }

    /// Sends multiple messages to an entity.
    #[inline]
    pub fn send_messages(entity: Entity, messages: &[ffi::Message]) {
        ffi::send_messages(
            std::mem::size_of::<ffi::Message>() as u32,
            &[ffi::MessageRangeAndReceiver {
                entity: entity.as_ffi(),
                start_index: 0u32,
                length: messages.len() as u32,
            }],
            messages,
        );
    }

    /// Retrieves the number of messages in the entity's outbox
    #[inline]
    fn get_message_count(entity: Entity) -> u32 {
        let entities = &[entity.as_ffi()];
        let mut message_counts = [0u32];
        let mut total = 0u32;
        ffi::get_message_counts(
            std::mem::size_of::<ffi::Message>() as u32,
            entities,
            &mut message_counts,
            &mut total,
        );
        let count = *message_counts.first().unwrap();
        assert_eq!(count, total);
        count
    }

    /// Retrieves a copy of the entity's outbox as a Vec
    pub fn retrieve_messages(entity: Entity) -> Vec<ffi::Message> {
        let count = World::get_message_count(entity) as usize;
        if count == 0 {
            return vec![];
        }

        let mut out_messages = vec![ffi::Message::invalid(); count];

        ffi::retrieve_messages(
            std::mem::size_of::<ffi::Message>() as u32,
            &[entity.as_ffi()],
            &mut out_messages,
        );

        out_messages
    }

    /// Gets all components an entity has, returns the number of components.
    #[inline]
    pub fn get_components(entity: Entity, components: &mut [ComponentType]) -> u32 {
        ffi::get_components(entity.0, components)
    }

    /// Gets all components an entity has
    pub fn get_components_vec(entity: Entity) -> Vec<ComponentType> {
        let mut c = [ComponentType::Invalid; 128];
        let size = Self::get_components(entity, &mut c) as usize;

        c[0..size].to_vec()
    }

    /// Creates a new data object from a `CreateDataType` and slice of bytes.
    #[inline]
    pub fn create_data(create_data_type: CreateDataType, data: &[u8]) -> DataHandle {
        DataHandle::from_ffi(ffi::create_data(create_data_type, data))
    }

    /// Gets data from the data referenced by the handle. Always returns the number of bytes even if the output is empty
    /// (so you can allocate the right amount)
    #[inline]
    pub fn retrieve_data(
        data_handle: DataHandle,
        retrieve_data_type: ffi::RetrieveDataType,
        out_data: &mut [u8],
    ) -> u32 {
        ffi::retrieve_data(data_handle.0, retrieve_data_type, out_data)
    }

    /// Retrieves data by this `DataHandle` and `RetrieveDataType` as a Vec of bytes.
    pub fn retrieve_data_vec(
        data_handle: DataHandle,
        retrieve_data_type: ffi::RetrieveDataType,
    ) -> Vec<u8> {
        let len = Self::retrieve_data(data_handle, retrieve_data_type, &mut []);
        let mut data: Vec<u8> = vec![0u8; len as usize];
        let new_len = Self::retrieve_data(data_handle, retrieve_data_type, &mut data);
        assert!(new_len == len);
        data
    }

    /// Decreases the ref count of a data object. When ref count reaches zero it is destroyed. Attempting to access the data after this is an error.
    #[inline]
    pub fn destroy_data(data: DataHandle) {
        ffi::destroy_data(data.0);
    }

    /// Increases the ref count of a data object.
    #[inline]
    pub fn retain_data(data: DataHandle) {
        ffi::retain_data(data.0);
    }

    /// Lets you check whether a `DataHandle` points to a valid data object. If it has existed
    /// but been destroyed, the return value is false.
    #[inline]
    pub fn is_valid_data(data_handle: DataHandle) -> bool {
        ffi::is_valid_data(data_handle.0) != 0
    }

    /// Sets a debug name of this data object. Useful for debugging memory usage and leaks.
    #[inline]
    pub fn set_data_debug_name(data_handle: DataHandle, name: &str) {
        ffi::v4::set_data_debug_name(data_handle.0, name);
    }

    /// Gets a debug name of this data object.
    #[inline]
    pub fn get_data_debug_name(data_handle: DataHandle) -> String {
        ffi::v4::get_data_debug_name(data_handle.0)
    }

    /// Sets debug options of this entity such as whether to enable physics shape debug rendering or not.
    /// An empty slice will mean to apply the options to all entities in the world.
    #[inline]
    pub fn set_entity_debug_options(entities: &[Entity], options: EntityDebugOptions) {
        ffi::v4::set_entity_debug_options(
            unsafe { &*(entities as *const [Entity] as *const [u64]) },
            &options,
        );
    }

    pub(crate) fn notify_destroyed(&mut self, entity: Entity) {
        self.entities_destroyed_this_frame.push(entity);
    }

    pub(crate) fn entities_destroyed_this_and_last_frame(&self) -> impl Iterator<Item = &Entity> {
        self.entities_destroyed_previous_frame
            .iter()
            .chain(self.entities_destroyed_this_frame.iter())
    }

    fn pre_update() {
        puffin::profile_function!();

        {
            let mut instance = Self::instance_mut();
            instance.next_frame();
        }

        EntityArena::global().destroy_pending_entities();
        EntityMessenger::get().process_messages();
        EntityMessageDispatcher::global().update();
    }

    fn post_update() {
        puffin::profile_function!();
        EntityMessenger::get().send_messages();
    }

    /// Pass your world update function to this. Will make sure
    /// messages are received, sent and transient entities are destroyed in
    /// the right order.
    pub fn update<F: FnOnce()>(f: F) {
        puffin::profile_function!();
        Self::pre_update();
        f();
        Self::post_update();
    }

    /// Measures the layout size of a chunk of formatted text. Formatting is embedded directly
    /// into the string using a simple markup language, documented elsewhere.
    pub fn measure_formatted_text(formatted_text: &FormattedText) -> MeasuredTextSize {
        let mut text_size = MeasuredTextSize {
            min_x: 0.0,
            min_y: 0.0,
            width: 0.0,
            height: 0.0,
        };
        ffi::v4::measure_formatted_text(formatted_text.data.get_data_handle().0, &mut text_size);
        text_size
    }
}