goud_engine/context_registry/scene/
loading.rs1use std::sync::mpsc;
8
9use crate::core::error::GoudError;
10
11use super::data::SceneData;
12use super::manager::{SceneId, SceneManager};
13use super::serialization::{deserialize_scene, scene_from_json, scene_to_json, serialize_scene};
14
15pub struct SceneLoader;
21
22impl SceneLoader {
23 pub fn load_scene(
35 manager: &mut SceneManager,
36 name: &str,
37 data: SceneData,
38 ) -> Result<SceneId, GoudError> {
39 let id = manager.create_scene(name)?;
40 let world = manager.get_scene_mut(id).ok_or_else(|| {
41 GoudError::InternalError("Scene was created but not accessible".to_string())
42 })?;
43 world.register_builtin_serializables();
44 deserialize_scene(&data, world)?;
45 Ok(id)
46 }
47
48 pub fn unload_scene(manager: &mut SceneManager, name: &str) -> Result<(), GoudError> {
59 let id = manager
60 .get_scene_by_name(name)
61 .ok_or_else(|| GoudError::ResourceNotFound(format!("Scene '{}' not found", name)))?;
62 manager.destroy_scene(id)
63 }
64
65 pub fn load_scene_from_json(
76 manager: &mut SceneManager,
77 name: &str,
78 json: &str,
79 ) -> Result<SceneId, GoudError> {
80 let data = scene_from_json(json)?;
81 Self::load_scene(manager, name, data)
82 }
83
84 pub fn save_scene_to_json(manager: &SceneManager, id: SceneId) -> Result<String, GoudError> {
95 let world = manager
96 .get_scene(id)
97 .ok_or_else(|| GoudError::ResourceNotFound(format!("Scene id {} not found", id)))?;
98 let name = manager
99 .get_scene_name(id)
100 .ok_or_else(|| GoudError::ResourceNotFound(format!("Scene id {} not found", id)))?;
101 let scene_data = serialize_scene(world, name)?;
102 scene_to_json(&scene_data)
103 }
104}
105
106struct DeferredResult {
112 name: String,
114 data: Result<SceneData, GoudError>,
116}
117
118pub struct DeferredSceneLoad {
134 sender: mpsc::Sender<DeferredResult>,
135 receiver: mpsc::Receiver<DeferredResult>,
136}
137
138impl DeferredSceneLoad {
139 pub fn new() -> Self {
141 let (sender, receiver) = mpsc::channel();
142 Self { sender, receiver }
143 }
144
145 pub fn request_load(&self, name: String, json: String) {
151 let sender = self.sender.clone();
152 std::thread::spawn(move || {
153 let data = scene_from_json(&json);
154 let _ = sender.send(DeferredResult { name, data });
156 });
157 }
158
159 pub fn process_completed(&self, manager: &mut SceneManager) -> Vec<Result<SceneId, GoudError>> {
165 let mut results = Vec::new();
166 while let Ok(deferred) = self.receiver.try_recv() {
167 let result = match deferred.data {
168 Ok(data) => SceneLoader::load_scene(manager, &deferred.name, data),
169 Err(e) => Err(e),
170 };
171 results.push(result);
172 }
173 results
174 }
175}
176
177impl Default for DeferredSceneLoad {
178 fn default() -> Self {
179 Self::new()
180 }
181}
182
183#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::core::math::Vec2;
191 use crate::ecs::components::hierarchy::Name;
192 use crate::ecs::components::Transform2D;
193 use crate::ecs::World;
194
195 fn sample_scene_data() -> SceneData {
197 let mut world = World::new();
198 world.register_builtin_serializables();
199
200 let e = world.spawn_empty();
201 world.insert(e, Name::new("hero"));
202 world.insert(e, Transform2D::new(Vec2::new(10.0, 20.0), 0.0, Vec2::one()));
203
204 serialize_scene(&world, "sample").unwrap()
205 }
206
207 #[test]
210 fn test_load_scene_creates_entities() {
211 let mut mgr = SceneManager::new();
212 let data = sample_scene_data();
213
214 let id = SceneLoader::load_scene(&mut mgr, "level", data).unwrap();
215
216 let world = mgr.get_scene(id).unwrap();
217 assert!(
218 world.entity_count() > 0,
219 "loaded scene should have entities"
220 );
221 }
222
223 #[test]
226 fn test_unload_scene_removes_from_manager() {
227 let mut mgr = SceneManager::new();
228 let data = sample_scene_data();
229
230 SceneLoader::load_scene(&mut mgr, "level", data).unwrap();
231 SceneLoader::unload_scene(&mut mgr, "level").unwrap();
232
233 assert!(
234 mgr.get_scene_by_name("level").is_none(),
235 "scene should be gone after unload"
236 );
237 }
238
239 #[test]
240 fn test_load_then_unload_entity_count_returns_to_zero() {
241 let mut mgr = SceneManager::new();
242
243 let data = sample_scene_data();
244 let id = SceneLoader::load_scene(&mut mgr, "level", data).unwrap();
245
246 let world = mgr.get_scene(id).unwrap();
248 assert!(
249 world.entity_count() > 0,
250 "loaded scene should have entities"
251 );
252
253 SceneLoader::unload_scene(&mut mgr, "level").unwrap();
255
256 assert!(
258 mgr.get_scene(id).is_none(),
259 "scene should be gone after unload"
260 );
261 }
262
263 #[test]
266 fn test_load_scene_from_json() {
267 let mut mgr = SceneManager::new();
268 let data = sample_scene_data();
269 let json = scene_to_json(&data).unwrap();
270
271 let id = SceneLoader::load_scene_from_json(&mut mgr, "json_level", &json).unwrap();
272
273 let world = mgr.get_scene(id).unwrap();
274 assert!(world.entity_count() > 0);
275 }
276
277 #[test]
280 fn test_save_scene_to_json() {
281 let mut mgr = SceneManager::new();
282 let data = sample_scene_data();
283 let id = SceneLoader::load_scene(&mut mgr, "save_test", data).unwrap();
284
285 let json = SceneLoader::save_scene_to_json(&mgr, id).unwrap();
286 assert!(json.contains("entities"));
287 }
288
289 #[test]
292 fn test_unload_nonexistent_scene_errors() {
293 let mut mgr = SceneManager::new();
294 let result = SceneLoader::unload_scene(&mut mgr, "nope");
295 assert!(result.is_err());
296 }
297
298 #[test]
299 fn test_load_duplicate_name_errors() {
300 let mut mgr = SceneManager::new();
301 let data = sample_scene_data();
302
303 SceneLoader::load_scene(&mut mgr, "dup", data.clone()).unwrap();
304 let result = SceneLoader::load_scene(&mut mgr, "dup", data);
305 assert!(result.is_err());
306 }
307
308 #[test]
311 fn test_deferred_load_creates_scene() {
312 let mut mgr = SceneManager::new();
313 let data = sample_scene_data();
314 let json = scene_to_json(&data).unwrap();
315
316 let deferred = DeferredSceneLoad::new();
317 deferred.request_load("deferred_level".to_string(), json);
318
319 let start = std::time::Instant::now();
321 let timeout = std::time::Duration::from_secs(5);
322 let results = loop {
323 let results = deferred.process_completed(&mut mgr);
324 if !results.is_empty() {
325 break results;
326 }
327 if start.elapsed() > timeout {
328 panic!("Deferred load did not complete within timeout");
329 }
330 std::thread::yield_now();
331 };
332
333 assert_eq!(results.len(), 1);
334 assert!(results[0].is_ok());
335
336 let id = results[0].as_ref().unwrap();
337 let world = mgr.get_scene(*id).unwrap();
338 assert!(world.entity_count() > 0);
339 }
340
341 #[test]
342 fn test_deferred_load_invalid_json_returns_error() {
343 let mut mgr = SceneManager::new();
344
345 let deferred = DeferredSceneLoad::new();
346 deferred.request_load("bad".to_string(), "not valid json".to_string());
347
348 let start = std::time::Instant::now();
350 let timeout = std::time::Duration::from_secs(5);
351 let results = loop {
352 let results = deferred.process_completed(&mut mgr);
353 if !results.is_empty() {
354 break results;
355 }
356 if start.elapsed() > timeout {
357 panic!("Deferred load did not complete within timeout");
358 }
359 std::thread::yield_now();
360 };
361
362 assert_eq!(results.len(), 1);
363 assert!(results[0].is_err());
364 }
365}