khora_data/scene/
definition_strategy.rs1use super::{DeserializationError, SerializationError, SerializationStrategy};
22use crate::ecs::World;
23use crate::scene::registry::ComponentRegistration;
24use khora_core::ecs::entity::EntityId;
25use serde::{Deserialize, Serialize};
26use std::collections::HashMap;
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ComponentDefinition {
31 pub type_name: String,
33 pub data_base64: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct EntityDefinition {
40 pub id: EntityId,
42 pub components: Vec<ComponentDefinition>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct SceneDefinition {
49 pub entities: Vec<EntityDefinition>,
51}
52
53#[derive(Default)]
59pub struct DefinitionSerializationStrategy;
60
61impl DefinitionSerializationStrategy {
62 pub fn new() -> Self {
64 Self
65 }
66}
67
68impl SerializationStrategy for DefinitionSerializationStrategy {
69 fn get_strategy_id(&self) -> &'static str {
70 "KH_DEFINITION_RON_V1"
71 }
72
73 fn serialize(&self, world: &World) -> Result<Vec<u8>, SerializationError> {
74 let mut entity_defs = Vec::new();
75
76 for entity_id in world.iter_entities() {
77 let mut component_defs = Vec::new();
78
79 for (type_name, data) in crate::scene::serialize_all_components(world, entity_id) {
82 component_defs.push(ComponentDefinition {
83 type_name,
84 data_base64: base64_encode(&data),
85 });
86 }
87
88 if !component_defs.is_empty() {
89 entity_defs.push(EntityDefinition {
90 id: entity_id,
91 components: component_defs,
92 });
93 }
94 }
95
96 let scene_definition = SceneDefinition {
97 entities: entity_defs,
98 };
99
100 let pretty_config = ron::ser::PrettyConfig::default().indentor(" ".to_string());
101 ron::ser::to_string_pretty(&scene_definition, pretty_config)
102 .map(|s| s.into_bytes())
103 .map_err(|e| SerializationError::ProcessingFailed(e.to_string()))
104 }
105
106 fn deserialize(&self, data: &[u8], world: &mut World) -> Result<(), DeserializationError> {
107 let scene_def: SceneDefinition = ron::de::from_bytes(data)
108 .map_err(|e| DeserializationError::InvalidFormat(e.to_string()))?;
109
110 let mut id_map = HashMap::<EntityId, EntityId>::new();
111
112 for entity_def in &scene_def.entities {
114 let new_id = world.spawn(());
115 id_map.insert(entity_def.id, new_id);
116 }
117
118 for entity_def in &scene_def.entities {
120 let new_id = id_map[&entity_def.id];
121
122 for comp_def in &entity_def.components {
123 let data = base64_decode(&comp_def.data_base64)
124 .map_err(DeserializationError::InvalidFormat)?;
125
126 for reg in inventory::iter::<ComponentRegistration> {
128 if reg.type_name == comp_def.type_name {
129 if let Err(e) = (reg.deserialize_recipe)(world, new_id, &data) {
130 log::warn!("Failed to deserialize {}: {}", comp_def.type_name, e);
131 }
132 break;
133 }
134 }
135 }
136 }
137
138 Ok(())
139 }
140}
141
142fn base64_encode(data: &[u8]) -> String {
144 use std::fmt::Write;
145 const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
146 let mut out = String::with_capacity(data.len().div_ceil(3) * 4);
147 let mut chunks = data.chunks_exact(3);
148 for chunk in chunks.by_ref() {
149 let n = ((chunk[0] as u32) << 16) | ((chunk[1] as u32) << 8) | (chunk[2] as u32);
150 write!(
151 out,
152 "{}{}{}{}",
153 CHARS[((n >> 18) & 0x3F) as usize] as char,
154 CHARS[((n >> 12) & 0x3F) as usize] as char,
155 CHARS[((n >> 6) & 0x3F) as usize] as char,
156 CHARS[(n & 0x3F) as usize] as char,
157 )
158 .unwrap();
159 }
160 let rem = chunks.remainder();
161 if rem.len() == 1 {
162 let n = (rem[0] as u32) << 16;
163 write!(
164 out,
165 "{}{}==",
166 CHARS[((n >> 18) & 0x3F) as usize] as char,
167 CHARS[((n >> 12) & 0x3F) as usize] as char,
168 )
169 .unwrap();
170 } else if rem.len() == 2 {
171 let n = ((rem[0] as u32) << 16) | ((rem[1] as u32) << 8);
172 write!(
173 out,
174 "{}{}{}=",
175 CHARS[((n >> 18) & 0x3F) as usize] as char,
176 CHARS[((n >> 12) & 0x3F) as usize] as char,
177 CHARS[((n >> 6) & 0x3F) as usize] as char,
178 )
179 .unwrap();
180 }
181 out
182}
183
184fn base64_decode(input: &str) -> Result<Vec<u8>, String> {
185 let input = input.trim_end_matches('=');
186 let mut out = Vec::with_capacity(input.len() * 3 / 4);
187 let mut buf = 0u32;
188 let mut bits = 0u8;
189 for c in input.chars() {
190 let val = match c {
191 'A'..='Z' => c as u32 - 'A' as u32,
192 'a'..='z' => c as u32 - 'a' as u32 + 26,
193 '0'..='9' => c as u32 - '0' as u32 + 52,
194 '+' => 62,
195 '/' => 63,
196 _ => return Err(format!("Invalid base64 character: {}", c)),
197 };
198 buf = (buf << 6) | val;
199 bits += 6;
200 if bits >= 8 {
201 bits -= 8;
202 out.push((buf >> bits) as u8);
203 }
204 }
205 Ok(out)
206}