aboutsummaryrefslogtreecommitdiff
path: root/src/preload
diff options
context:
space:
mode:
Diffstat (limited to 'src/preload')
-rw-r--r--src/preload/events.rs12
-rw-r--r--src/preload/mod.rs82
-rw-r--r--src/preload/resources.rs7
-rw-r--r--src/preload/systems.rs41
4 files changed, 142 insertions, 0 deletions
diff --git a/src/preload/events.rs b/src/preload/events.rs
new file mode 100644
index 0000000..7167d73
--- /dev/null
+++ b/src/preload/events.rs
@@ -0,0 +1,12 @@
+use bevy::prelude::*;
+
+/// Event used to trigger preload callbacks after the asset file has been pre-processed to extract
+/// the payload
+#[derive(Debug, Event, Clone)]
+pub struct DirworldPreload {
+ /// Entity with the `[DirworldEntity]` component corresponding to the entity being preloaded
+ pub entity: Entity,
+ /// The data portion of the file after being pre-processed
+ pub data: Option<Vec<u8>>,
+}
+
diff --git a/src/preload/mod.rs b/src/preload/mod.rs
new file mode 100644
index 0000000..b90db38
--- /dev/null
+++ b/src/preload/mod.rs
@@ -0,0 +1,82 @@
+use crate::cache::DirworldCache;
+use crate::{
+ components::DirworldEntity,
+ resources::{DirworldCodecs, DirworldObservers, EntryType},
+ utils::extract_entity_payload,
+ Extensions,
+};
+use bevy::prelude::*;
+use std::{collections::HashMap, path::PathBuf};
+
+mod systems;
+
+mod resources;
+pub use resources::*;
+
+mod events;
+pub use events::DirworldPreload;
+
+pub(crate) struct DirworldPreloadPlugin;
+
+impl Plugin for DirworldPreloadPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(
+ PostUpdate,
+ systems::handle_preload.run_if(in_state(PreloadState::Loading)),
+ )
+ .add_systems(OnEnter(PreloadState::Done), systems::handle_spawn)
+ .init_resource::<RoomAssets>()
+ .init_state::<PreloadState>();
+ }
+}
+
+/// State of asset preloading
+#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default)]
+pub enum PreloadState {
+ /// Indicates assets are in the process of loading
+ #[default]
+ Loading,
+ /// Indicates all room assets are finished loading, i.e. all assets are loaded with
+ /// dependencies
+ Done,
+}
+
+/// Initiates loading of an asset
+// TODO: Make into a command extension
+pub fn load_entity(
+ entry: &PathBuf,
+ cache: &mut DirworldCache,
+ codecs: &DirworldCodecs,
+ observers: &DirworldObservers,
+ commands: &mut Commands,
+ preload_state: &mut NextState<PreloadState>,
+ room_assets: &mut RoomAssets,
+) {
+ let (mut payload, data) = extract_entity_payload(&entry, &codecs);
+ payload = payload.map(|p| cache.get_entity_cache(&entry).unwrap_or(p));
+ let entry_type = if entry.is_dir() {
+ EntryType::Folder
+ } else {
+ EntryType::File(entry.extensions())
+ };
+ let transform = payload
+ .as_ref()
+ .map(|payload| payload.transform.clone())
+ .unwrap_or_default();
+ let entity = commands
+ .spawn((
+ *transform,
+ Visibility::Inherited,
+ DirworldEntity {
+ path: entry.clone(),
+ payload,
+ },
+ ))
+ .id();
+ if let Some(observer) = observers.get(&entry_type) {
+ preload_state.set(PreloadState::Loading);
+ room_assets.insert(entry.clone(), HashMap::default());
+ commands.trigger_targets(DirworldPreload { entity, data }, observer.clone());
+ info!("Triggered preload for {entry:?}");
+ }
+}
diff --git a/src/preload/resources.rs b/src/preload/resources.rs
new file mode 100644
index 0000000..4060c10
--- /dev/null
+++ b/src/preload/resources.rs
@@ -0,0 +1,7 @@
+use std::{collections::HashMap, path::PathBuf};
+
+use bevy::prelude::*;
+
+/// A map of asset handles required by each entry in a room, indexed by their paths
+#[derive(Resource, Default, Debug, Deref, DerefMut)]
+pub struct RoomAssets(pub HashMap<PathBuf, HashMap<String, UntypedHandle>>);
diff --git a/src/preload/systems.rs b/src/preload/systems.rs
new file mode 100644
index 0000000..ec867ae
--- /dev/null
+++ b/src/preload/systems.rs
@@ -0,0 +1,41 @@
+use bevy::prelude::*;
+
+use crate::{components::DirworldEntity, events::DirworldSpawn, resources::{DirworldObservers, EntryType}, Extensions};
+
+use super::{PreloadState, RoomAssets};
+
+pub fn handle_preload(
+ asset_server: Res<AssetServer>,
+ room_assets: Res<RoomAssets>,
+ mut next_state: ResMut<NextState<PreloadState>>,
+) {
+ if room_assets.is_empty()
+ || room_assets
+ .values()
+ .flat_map(|v| v.values())
+ .all(|a| asset_server.is_loaded_with_dependencies(a))
+ {
+ info!("Preload Done.");
+ next_state.set(PreloadState::Done);
+ }
+}
+
+pub fn handle_spawn(
+ dirworld_entity_query: Query<(Entity, &DirworldEntity)>,
+ mut commands: Commands,
+ observers: Res<DirworldObservers>,
+) {
+ info!("Spawning");
+ for (entity, DirworldEntity { path, .. }) in dirworld_entity_query.iter() {
+ let entry_type = if path.is_dir() {
+ EntryType::Folder
+ } else {
+ EntryType::File(path.extensions())
+ };
+ if let Some(observer) = observers.get(&entry_type) {
+ info!("Found observer {observer:?} for {entry_type:?}");
+ commands.trigger_targets(DirworldSpawn(entity), observer.clone());
+ }
+ }
+}
+