bevy_dirworld/src/observers.rs
Silas Bartha f5f80e156a
Some checks failed
Build / Build (push) Failing after 2h11m45s
Tue Mar 18 07:18:34 PM EDT 2025
2025-03-18 19:18:34 -04:00

203 lines
6.5 KiB
Rust

use std::ops::Deref;
use avian3d::prelude::{Physics, PhysicsTime};
use bevy::prelude::*;
use notify::{
event::{MetadataKind, ModifyKind, RenameMode},
EventKind,
};
use crate::{
cache::DirworldCache,
components::{DirworldEntity, Persist},
events::{
DirworldChangeRoot, DirworldEnterRoom, DirworldLeaveRoom,
},
preload::{load_entity, DirworldPreloadBegin, PreloadState, RoomAssets},
resources::{
DirworldCodecs, DirworldCurrentDir, DirworldObservers, DirworldRootDir, DirworldTasks,
},
utils::{despawn_entity_by_path, extract_entity_payload},
DirworldWatcherEvent,
};
/// On navigation from a room, insert modified payloads into the cache
pub fn navigate_from_room(
trigger: Trigger<DirworldLeaveRoom>,
entities: Query<(Entity, Ref<DirworldEntity>), Without<Persist>>,
mut cache: ResMut<DirworldCache>,
mut commands: Commands,
mut event_writer: EventWriter<DirworldLeaveRoom>,
) {
for (entity, dirworld_entity) in entities.iter() {
cache.cache_entity(&dirworld_entity);
commands.entity(entity).despawn_recursive();
}
event_writer.send(trigger.event().clone());
}
pub fn navigate_to_room(
trigger: Trigger<DirworldEnterRoom>,
root_dir: Res<DirworldRootDir>,
mut cache: ResMut<DirworldCache>,
observers: Res<DirworldObservers>,
codecs: Res<DirworldCodecs>,
mut commands: Commands,
mut event_writer: EventWriter<DirworldEnterRoom>,
mut preload_event_writer: EventWriter<DirworldPreloadBegin>,
mut current_dir: ResMut<DirworldCurrentDir>,
mut next_preload_state: ResMut<NextState<PreloadState>>,
mut room_assets: ResMut<RoomAssets>,
mut dirworld_tasks: ResMut<DirworldTasks>,
persitent_entities: Query<&DirworldEntity, With<Persist>>,
mut time: ResMut<Time<Physics>>,
) {
time.pause();
dirworld_tasks.insert("Loading Room".into(), None);
let DirworldEnterRoom {
exited: old_path,
entered: path,
} = &trigger.event();
let room_payload = extract_entity_payload(&path.join(".door"), &codecs).0;
*current_dir = DirworldCurrentDir {
path: path.to_path_buf(),
payload: room_payload,
};
let entries = match path.read_dir() {
Ok(entries) => entries
.flatten()
.map(|entry| entry.path().canonicalize())
.flatten()
.filter(|entry| {
!entry
.file_name()
.is_some_and(|file_name| file_name.to_string_lossy().starts_with("."))
})
.chain(
root_dir
.clone()
.map(|root_dir| {
info!("Root: {root_dir:?}, Path: {path:?}");
if root_dir == *path {
None
} else {
Some(path.join(".."))
}
})
.into_iter()
.flatten(),
),
Err(e) => {
error!("Failed to read directory \"{}\", ({:?})", path.display(), e);
return;
}
};
for entry in entries {
load_entity(
&entry,
&mut cache,
&codecs,
&observers,
&mut commands,
&mut next_preload_state,
&mut room_assets,
&root_dir,
&persitent_entities,
);
}
preload_event_writer.send(DirworldPreloadBegin { old_path: old_path.clone(), path: path.clone() });
event_writer.send(trigger.event().clone());
}
pub fn handle_changes(
trigger: Trigger<DirworldWatcherEvent>,
mut commands: Commands,
dirworld_entities: Query<(Entity, &DirworldEntity)>,
observers: Res<DirworldObservers>,
codecs: Res<DirworldCodecs>,
mut cache: ResMut<DirworldCache>,
mut event_writer: EventWriter<DirworldWatcherEvent>,
mut next_preload_state: ResMut<NextState<PreloadState>>,
mut room_assets: ResMut<RoomAssets>,
persitent_entities: Query<&DirworldEntity, With<Persist>>,
root_dir: Res<DirworldRootDir>,
) {
let event = &trigger.event().0;
info!("Watcher Event: {event:?}");
match event.kind {
EventKind::Remove(_) | EventKind::Modify(ModifyKind::Name(RenameMode::From)) => {
for path in &event.paths {
despawn_entity_by_path(&mut commands, &dirworld_entities, path);
}
}
EventKind::Create(_) | EventKind::Modify(ModifyKind::Name(RenameMode::To)) => {
for path in &event.paths {
load_entity(
&path,
&mut cache,
&codecs,
&observers,
&mut commands,
&mut next_preload_state,
&mut room_assets,
&root_dir,
&persitent_entities,
);
}
}
EventKind::Modify(ModifyKind::Name(RenameMode::Both)) => {
despawn_entity_by_path(&mut commands, &dirworld_entities, &event.paths[0]);
load_entity(
&event.paths[1],
&mut cache,
&codecs,
&observers,
&mut commands,
&mut next_preload_state,
&mut room_assets,
&root_dir,
&persitent_entities,
);
}
EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)) => {
despawn_entity_by_path(&mut commands, &dirworld_entities, &event.paths[1]);
load_entity(
&event.paths[0],
&mut cache,
&codecs,
&observers,
&mut commands,
&mut next_preload_state,
&mut room_assets,
&root_dir,
&persitent_entities,
);
}
_ => {
// warn!("Not Processed.")
}
}
event_writer.send(trigger.event().clone());
}
pub fn change_root(
trigger: Trigger<DirworldChangeRoot>,
mut root_dir: ResMut<DirworldRootDir>,
mut commands: Commands,
) {
if let DirworldRootDir(Some(old_dir)) = root_dir.deref() {
commands.trigger(DirworldLeaveRoom(old_dir.to_path_buf()));
};
let new_root = &trigger.event().0.canonicalize().unwrap();
info!("Changing Root to {}", new_root.display());
**root_dir = Some(new_root.to_path_buf());
commands.trigger(DirworldEnterRoom {
exited: new_root.to_path_buf(),
entered: new_root.to_path_buf(),
});
}