use std::collections::HashMap;
use freecs::Entity;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::asset_uuid::AssetUuid;
use super::components::Scene;
use crate::ecs::world::World;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FieldKind {
Bool,
I32,
U32,
F32,
String,
Vec3,
Enum { variants: Vec<String> },
Color,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldDescriptor {
pub name: String,
pub kind: FieldKind,
#[serde(default)]
pub display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentDescriptor {
pub name: String,
#[serde(default)]
pub display_name: Option<String>,
pub fields: Vec<FieldDescriptor>,
#[serde(default)]
pub persistence: Persistence,
}
#[derive(Debug, Clone, Default)]
pub struct ComponentTypeRegistry {
pub descriptors: HashMap<String, ComponentDescriptor>,
}
pub fn register_component_descriptor(world: &mut World, descriptor: ComponentDescriptor) {
world
.resources
.component_types
.descriptors
.insert(descriptor.name.clone(), descriptor);
}
pub fn component_descriptor<'a>(world: &'a World, name: &str) -> Option<&'a ComponentDescriptor> {
world.resources.component_types.descriptors.get(name)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum Persistence {
Authored,
Runtime,
#[default]
Both,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TypedPayload(pub serde_json::Value);
impl Default for TypedPayload {
fn default() -> Self {
Self(serde_json::Value::Null)
}
}
impl Serialize for TypedPayload {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
self.0.serialize(serializer)
} else {
let encoded = serde_json::to_string(&self.0).map_err(serde::ser::Error::custom)?;
encoded.serialize(serializer)
}
}
}
impl<'de> Deserialize<'de> for TypedPayload {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
if deserializer.is_human_readable() {
serde_json::Value::deserialize(deserializer).map(TypedPayload)
} else {
let encoded = String::deserialize(deserializer)?;
serde_json::from_str(&encoded)
.map(TypedPayload)
.map_err(serde::de::Error::custom)
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TypedComponent {
pub name: String,
pub data: TypedPayload,
#[serde(default)]
pub persistence: Persistence,
#[serde(default)]
pub field_overrides: Vec<crate::ecs::prefab::components::FieldOverride>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TypedResource {
pub name: String,
pub data: TypedPayload,
#[serde(default)]
pub persistence: Persistence,
}
pub fn apply_field_overrides(
base: &serde_json::Value,
overrides: &[crate::ecs::prefab::components::FieldOverride],
) -> serde_json::Value {
let mut merged = base.clone();
if let serde_json::Value::Object(map) = &mut merged {
for entry in overrides {
map.insert(entry.field_name.clone(), entry.value.0.clone());
}
}
merged
}
pub trait SceneSerializer {
fn populate_scene(
&self,
world: &World,
entity_uuids: &HashMap<Entity, AssetUuid>,
scene: &mut Scene,
);
}
pub trait SceneDeserializer {
fn populate_world(
&mut self,
world: &mut World,
uuid_to_entity: &HashMap<AssetUuid, Entity>,
scene: &Scene,
);
}