nightshade 0.48.0

A cross-platform data-oriented game engine.
Documentation
use crate::ecs::light::components::Light;
use crate::ecs::material::components::Material;
use crate::ecs::physics::components::{ColliderComponent, ColliderShape, RigidBodyComponent};
use crate::ecs::physics::types::{InteractionGroups, LockedAxes, RigidBodyType};
use crate::ecs::world::components::{
    BoundingVolume, Camera, LocalTransform, Name, RenderMesh, Visibility,
};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PrefabBodyType {
    Dynamic,
    Kinematic,
    Static,
}

pub fn prefab_body_type_to_rigid_body_type(body_type: PrefabBodyType) -> RigidBodyType {
    match body_type {
        PrefabBodyType::Dynamic => RigidBodyType::Dynamic,
        PrefabBodyType::Kinematic => RigidBodyType::KinematicPositionBased,
        PrefabBodyType::Static => RigidBodyType::Fixed,
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrefabRigidBody {
    pub body_type: PrefabBodyType,
    pub mass: f32,
}

impl Default for PrefabRigidBody {
    fn default() -> Self {
        Self {
            body_type: PrefabBodyType::Dynamic,
            mass: 1.0,
        }
    }
}

pub fn prefab_rigid_body_to_component(prefab: &PrefabRigidBody) -> RigidBodyComponent {
    RigidBodyComponent {
        handle: None,
        body_type: prefab_body_type_to_rigid_body_type(prefab.body_type),
        translation: [0.0, 0.0, 0.0],
        rotation: [0.0, 0.0, 0.0, 1.0],
        linvel: [0.0, 0.0, 0.0],
        angvel: [0.0, 0.0, 0.0],
        mass: prefab.mass,
        linear_damping: 0.0,
        angular_damping: 0.0,
        gravity_scale: 1.0,
        locked_axes: LockedAxes::empty(),
        ccd_enabled: false,
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrefabCollider {
    pub shape: ColliderShape,
    pub friction: f32,
    pub restitution: f32,
    pub density: f32,
    pub is_sensor: bool,
}

impl Default for PrefabCollider {
    fn default() -> Self {
        Self {
            shape: ColliderShape::Cuboid {
                hx: 0.5,
                hy: 0.5,
                hz: 0.5,
            },
            friction: 0.5,
            restitution: 0.0,
            density: 1.0,
            is_sensor: false,
        }
    }
}

pub fn prefab_collider_to_component(prefab: &PrefabCollider) -> ColliderComponent {
    ColliderComponent {
        handle: None,
        shape: prefab.shape.clone(),
        friction: prefab.friction,
        restitution: prefab.restitution,
        density: prefab.density,
        is_sensor: prefab.is_sensor,
        collision_groups: InteractionGroups::all(),
        solver_groups: InteractionGroups::all(),
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Prefab {
    pub name: String,
    pub root_nodes: Vec<PrefabNode>,
    /// Names declared by `KHR_materials_variants` at the document root.
    /// Indices into this list match `MaterialVariants::mappings`'s
    /// `variant_indices`.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub material_variants: Vec<String>,
}

/// A single variant override on a primitive node: when any of the listed
/// variant names is active, swap the entity's material to the supplied
/// [`Material`].
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrefabMaterialVariant {
    pub variant_names: Vec<String>,
    pub material: Material,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrefabNode {
    pub local_transform: LocalTransform,
    pub components: PrefabComponents,
    pub children: Vec<PrefabNode>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub node_index: Option<usize>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PrefabSource {
    pub prefab_name: String,
    pub source_path: Option<String>,
    /// Stable identifier of the originating prefab file (the `prefab_id`
    /// in the `.nsprefab` SceneHeader). Persists the link from a
    /// spawned prefab instance back to its source so editor tooling
    /// (e.g. "refresh from source", "find all instances of prefab X")
    /// can reach across maps without relying on filesystem paths.
    #[cfg(feature = "scene_graph")]
    #[serde(default)]
    pub source_uuid: Option<crate::ecs::scene::AssetUuid>,
}

pub fn prefab_source_new(prefab_name: impl Into<String>) -> PrefabSource {
    PrefabSource {
        prefab_name: prefab_name.into(),
        source_path: None,
        #[cfg(feature = "scene_graph")]
        source_uuid: None,
    }
}

pub fn prefab_source_with_path(
    prefab_name: impl Into<String>,
    source_path: impl Into<String>,
) -> PrefabSource {
    PrefabSource {
        prefab_name: prefab_name.into(),
        source_path: Some(source_path.into()),
        #[cfg(feature = "scene_graph")]
        source_uuid: None,
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PrefabComponents {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Name>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub render_mesh: Option<RenderMesh>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub material: Option<Material>,

    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub material_variants: Vec<PrefabMaterialVariant>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub camera: Option<Camera>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub light: Option<Light>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub visibility: Option<Visibility>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub bounding_volume: Option<BoundingVolume>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub rigid_body: Option<PrefabRigidBody>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub collider: Option<PrefabCollider>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub skin_index: Option<usize>,

    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub instances: Vec<crate::ecs::world::components::LocalTransform>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FieldOverride {
    pub field_name: String,
    pub value: crate::ecs::scene::TypedPayload,
}