io/
load_project.rs

1//! Contains the [`LoadProjectEvent`] and it's handler systems.
2use crate::document::Document;
3use anyhow::Context;
4use bevy::prelude::{BevyError, Commands, Event, EventReader, Transform, default};
5use data::{Layer, Level, Project};
6use serialization::deserialize;
7use std::fs::read;
8use std::path::PathBuf;
9
10/// Emitting this event will cause the software to attempt loading a project file at the given `input`.
11///
12/// The progress, result or failure of this event's actions will also be emitted as events.
13/// TODO: add events to indicate progress, success or failure
14#[derive(Event, Debug)]
15pub struct LoadProjectEvent {
16    /// The path to the project file to load.
17    pub input: PathBuf,
18}
19
20/// Bevy system that handles `LoadProjectEvent` events that were fired.
21#[utils::bevy_system]
22pub fn handle_load_project_event(
23    mut events: EventReader<LoadProjectEvent>,
24    mut commands: Commands,
25) -> Result<(), BevyError> {
26    // Only handle a single load event per frame, we don't want to cram too much work in a single frame.
27    let Some(event) = events.read().next() else {
28        return Ok(());
29    };
30
31    let content = read(event.input.clone())
32        .with_context(|| format!("Failed to open project file: '{}'", event.input.display()))?;
33    let project = deserialize::<Document>(&content, &default())
34        .with_context(|| format!("Failed to parse project file '{}'", event.input.display()))?;
35
36    commands
37        .spawn(Project::new(project.name))
38        .with_children(|commands| {
39            for level in project.levels {
40                commands
41                    .spawn(Level::new(level.name))
42                    .with_children(|commands| {
43                        for layer in level.layers {
44                            commands
45                                .spawn(Layer::new(
46                                    layer.name,
47                                    Transform::from_xyz(0.0, 0.0, layer.order),
48                                ))
49                                .with_children(|_commands| {
50                                    for _item in layer.items {
51                                        // TODO: spawn item
52                                    }
53                                });
54                        }
55                    });
56            }
57        });
58
59    Ok(())
60}