use concinnity_core::components::PropCollider;
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
#[serde(default)]
pub struct Prefab {
pub props: Vec<PrefabEntry>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum PrefabKind {
#[default]
Prop,
PointLight,
Prefab,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(default)]
pub struct PrefabEntry {
pub name: String,
pub kind: PrefabKind,
pub position: [f32; 3],
pub rotation_deg: [f32; 3],
pub scale: [f32; 3],
#[serde(skip_serializing_if = "String::is_empty")]
pub model: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub mesh: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub material: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub texture: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub parent: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub collider: Option<PropCollider>,
pub interactable: bool,
pub pickup: bool,
pub light_color: [f32; 3],
pub light_intensity: f32,
pub light_range: f32,
#[serde(skip_serializing_if = "String::is_empty")]
pub prefab: String,
}
impl Default for PrefabEntry {
fn default() -> Self {
Self {
name: String::new(),
kind: PrefabKind::Prop,
position: [0.0, 0.0, 0.0],
rotation_deg: [0.0, 0.0, 0.0],
scale: [1.0, 1.0, 1.0],
model: String::new(),
mesh: String::new(),
material: String::new(),
texture: String::new(),
parent: String::new(),
collider: None,
interactable: false,
pickup: false,
light_color: [1.0, 1.0, 1.0],
light_intensity: 8.0,
light_range: 6.0,
prefab: String::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn each_kind_deserialises_with_its_fields() {
let prop: PrefabEntry = serde_json::from_str(
r#"{"name":"table","kind":"prop","model":"model_table","position":[1.0,0.0,2.0]}"#,
)
.unwrap();
assert_eq!(prop.kind, PrefabKind::Prop);
assert_eq!(prop.name, "table");
assert_eq!(prop.model, "model_table");
assert_eq!(prop.position, [1.0, 0.0, 2.0]);
assert_eq!(prop.scale, [1.0, 1.0, 1.0]);
let light: PrefabEntry =
serde_json::from_str(r#"{"name":"lamp","kind":"point_light","light_intensity":5.0}"#)
.unwrap();
assert_eq!(light.kind, PrefabKind::PointLight);
assert_eq!(light.light_intensity, 5.0);
assert_eq!(light.light_range, 6.0);
assert_eq!(light.light_color, [1.0, 1.0, 1.0]);
let nested: PrefabEntry =
serde_json::from_str(r#"{"name":"inner","kind":"prefab","prefab":"other"}"#).unwrap();
assert_eq!(nested.kind, PrefabKind::Prefab);
assert_eq!(nested.prefab, "other");
}
#[test]
fn kind_defaults_to_prop_when_omitted() {
let e: PrefabEntry = serde_json::from_str(r#"{"name":"x","mesh":"box"}"#).unwrap();
assert_eq!(e.kind, PrefabKind::Prop);
assert_eq!(e.mesh, "box");
}
}