diff --git a/Cargo.lock b/Cargo.lock index ba64438..639aefc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -709,19 +709,6 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15702dff420fac72c2ab92428a8600e079ae89c5845401c4e39b843665a3d2d0" -[[package]] -name = "bevy_rapier3d" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12402872b857ba490f1040ab6212915bd9bf25f8584b31f2c43cef41b33f3be4" -dependencies = [ - "bevy", - "bitflags 1.3.2", - "log", - "nalgebra", - "rapier3d", -] - [[package]] name = "bevy_reflect" version = "0.11.2" @@ -1361,20 +1348,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -1385,40 +1358,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -1463,12 +1402,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - [[package]] name = "encase" version = "0.6.1" @@ -2108,12 +2041,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "libm" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" - [[package]] name = "libudev-sys" version = "0.1.4" @@ -2167,31 +2094,12 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matrixmultiply" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" -dependencies = [ - "autocfg", - "rawpointer", -] - [[package]] name = "memchr" version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "metal" version = "0.24.0" @@ -2239,7 +2147,6 @@ name = "monologue-trees" version = "0.1.0" dependencies = [ "bevy", - "bevy_rapier3d", "serde", ] @@ -2284,34 +2191,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "nalgebra" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" -dependencies = [ - "approx", - "glam", - "matrixmultiply", - "nalgebra-macros", - "num-complex", - "num-rational", - "num-traits", - "simba", - "typenum", -] - -[[package]] -name = "nalgebra-macros" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ndk" version = "0.7.0" @@ -2411,15 +2290,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-complex" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" -dependencies = [ - "num-traits", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -2459,7 +2329,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2596,12 +2465,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "optional" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978aa494585d3ca4ad74929863093e87cac9790d81fe7aba2b3dc2890643a0fc" - [[package]] name = "orbclient" version = "0.3.46" @@ -2655,27 +2518,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "parry3d" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55dc0e6db79bddbc5fd583569f7356cdcc63e1e9b2b93a9ab70dd8e717160e0" -dependencies = [ - "approx", - "arrayvec", - "bitflags 1.3.2", - "downcast-rs", - "either", - "nalgebra", - "num-derive", - "num-traits", - "rustc-hash", - "simba", - "slab", - "smallvec", - "spade", -] - [[package]] name = "paste" version = "1.0.14" @@ -2784,38 +2626,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" -[[package]] -name = "rapier3d" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62a8a0bd9d3135f7b4eb45d0796540e7bab47b6b7c974f90567ccc5a0454f42b" -dependencies = [ - "approx", - "arrayvec", - "bit-vec", - "bitflags 1.3.2", - "crossbeam", - "downcast-rs", - "nalgebra", - "num-derive", - "num-traits", - "parry3d", - "rustc-hash", - "simba", -] - [[package]] name = "raw-window-handle" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - [[package]] name = "rectangle-pack" version = "0.4.2" @@ -2881,12 +2697,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b" -[[package]] -name = "robust" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5864e7ef1a6b7bcf1d6ca3f655e65e724ed3b52546a0d0a663c991522f552ea" - [[package]] name = "rodio" version = "0.17.1" @@ -2938,15 +2748,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" -[[package]] -name = "safe_arch" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" -dependencies = [ - "bytemuck", -] - [[package]] name = "same-file" version = "1.0.6" @@ -3008,19 +2809,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" -[[package]] -name = "simba" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" -dependencies = [ - "approx", - "num-complex", - "num-traits", - "paste", - "wide", -] - [[package]] name = "simd-adler32" version = "0.3.7" @@ -3063,18 +2851,6 @@ dependencies = [ "serde", ] -[[package]] -name = "spade" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88e65803986868d2372c582007c39ba89936a36ea5f236bf7a7728dc258f04f9" -dependencies = [ - "num-traits", - "optional", - "robust", - "smallvec", -] - [[package]] name = "spirv" version = "0.2.0+1.5.4" @@ -3325,12 +3101,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - [[package]] name = "unicode-ident" version = "1.0.11" @@ -3586,16 +3356,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wide" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" -dependencies = [ - "bytemuck", - "safe_arch", -] - [[package]] name = "widestring" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index cfc32ba..498c40b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ path = "bin/serialize-wtf.rs" [dependencies] bevy = "0.11" -bevy_rapier3d = "*" +# bevy_rapier3d = "*" serde = "1" # From rapier docs diff --git a/assets/foo/bar/baz/inspect.glb b/assets/foo/bar/baz/inspect.glb deleted file mode 100644 index b96f116..0000000 --- a/assets/foo/bar/baz/inspect.glb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:976d82ec5c0039852a3f7e5991a60536b0c4050f7910bd55ca01e6b73fbdc8c9 -size 1244020 diff --git a/assets/output.scn.ron b/assets/output.scn.ron index 2e87fc6..9442783 100644 --- a/assets/output.scn.ron +++ b/assets/output.scn.ron @@ -1,8 +1,9 @@ ( resources: {}, entities: { - 19: ( + 1: ( components: { + "bevy_render::view::visibility::Visibility": Inherited, "bevy_transform::components::transform::Transform": ( translation: ( x: 0.0, @@ -40,23 +41,15 @@ z: 0.0, ), )), - "bevy_render::view::visibility::Visibility": Inherited, + "editor::LevelRoot": (), "bevy_hierarchy::components::children::Children": ([ - 20, - 21, + 198, ]), }, ), - 20: ( - components: { - "bevy_hierarchy::components::parent::Parent": (19), - "bevy_asset::handle::Handle": ( - id: AssetPathId(((5718828327369153735), (8823233378563626002))), - ), - }, - ), - 21: ( + 198: ( components: { + "bevy_render::view::visibility::Visibility": Inherited, "bevy_transform::components::transform::Transform": ( translation: ( x: 0.0, @@ -94,13 +87,12 @@ z: 0.0, ), )), - "bevy_render::view::visibility::Visibility": Inherited, - "bevy_hierarchy::components::parent::Parent": (19), + "bevy_hierarchy::components::parent::Parent": (1), "bevy_hierarchy::components::children::Children": ([ - 22, + 199, ]), "bevy_asset::handle::Handle": ( - id: AssetPathId(((8329447081204006281), (13531267934229906755))), + id: AssetPathId(((13241355290950327508), (2370051114748836591))), ), }, ), diff --git a/assets/scratch/BOUNCY GUM.ttf b/assets/scratch/BOUNCY GUM.ttf deleted file mode 100644 index 08cd35e..0000000 Binary files a/assets/scratch/BOUNCY GUM.ttf and /dev/null differ diff --git a/assets/scratch/Death Spirit.ttf b/assets/scratch/Death Spirit.ttf deleted file mode 100644 index df0f1ef..0000000 Binary files a/assets/scratch/Death Spirit.ttf and /dev/null differ diff --git a/assets/scratch/JMH Typewriter-Black.otf b/assets/scratch/JMH Typewriter-Black.otf deleted file mode 100644 index 1eb4171..0000000 Binary files a/assets/scratch/JMH Typewriter-Black.otf and /dev/null differ diff --git a/assets/scratch/JMH Typewriter-Bold.otf b/assets/scratch/JMH Typewriter-Bold.otf deleted file mode 100644 index e791089..0000000 Binary files a/assets/scratch/JMH Typewriter-Bold.otf and /dev/null differ diff --git a/assets/scratch/JMH Typewriter-Thin.otf b/assets/scratch/JMH Typewriter-Thin.otf deleted file mode 100644 index 4393a2f..0000000 Binary files a/assets/scratch/JMH Typewriter-Thin.otf and /dev/null differ diff --git a/assets/scratch/JMH Typewriter.otf b/assets/scratch/JMH Typewriter.otf deleted file mode 100644 index 5ee4685..0000000 Binary files a/assets/scratch/JMH Typewriter.otf and /dev/null differ diff --git a/assets/scratch/a.monologue.txt b/assets/scratch/a.monologue.txt deleted file mode 100644 index 1e7b6d2..0000000 --- a/assets/scratch/a.monologue.txt +++ /dev/null @@ -1,10 +0,0 @@ -Voluptatem culpa quo quia alias minima amet. Consequatur fugit et vitae qui dolor. Aut ea dolorum dicta quas ex et recusandae et. Nostrum eos quia quis est consequuntur. - -Ratione facilis aliquid et. Dolores expedita magni suscipit minima. Voluptatem in pariatur vitae laboriosam aliquam non ducimus. Laudantium illum provident et libero assumenda et sunt similique. Corporis tenetur repellat enim perferendis ut minus omnis. - -Blanditiis vitae quae ut ipsum consequatur. Ratione dignissimos exercitationem autem accusamus. Qui molestiae ipsam pariatur quis amet quia voluptate sunt. In voluptate dolorum in quia. Sit ut non voluptatem qui placeat quis. Ducimus ipsa adipisci eligendi dolor id. - -Ex totam nam laudantium quis. Omnis saepe mollitia eligendi unde rerum. Odit voluptatum repellat rem est iure neque saepe. - -Nulla est consequatur sint amet nesciunt quam. Qui fuga excepturi veritatis quia. Saepe natus et enim eveniet voluptates velit quod sint. Dolores reprehenderit eligendi aut. Et voluptate ea aliquam. - diff --git a/assets/scratch/b.monologue.txt b/assets/scratch/b.monologue.txt deleted file mode 100644 index 3fdb30d..0000000 --- a/assets/scratch/b.monologue.txt +++ /dev/null @@ -1 +0,0 @@ -This is a placeholder monologue diff --git a/bin/editor.rs b/bin/editor.rs index 248efa4..a7d1ebd 100644 --- a/bin/editor.rs +++ b/bin/editor.rs @@ -5,17 +5,12 @@ // BUGS: // // TODO: -// * re-load assets dir when new asset is copied -// * copy-and-reload drag-and-drop dirs -// * font resource for monologues // * edit textbox with actions -// * run_if logic for actions where possible -// * make min/max/close buttons into actions not selects -// * (medium) Select Font -> "Default Font" Resource -// * (medium) Pre-compute animation target entities -// * (hard) Harden Active Camera // * (brutal) export level // * (hard) import level +// * (hard) Harden Active Camera +// * (medium) Pre-compute animation target entities +// * make min/max/close buttons into actions not selects // * (???) Better handle hide/close monologue use bevy::{ @@ -60,10 +55,9 @@ fn main() { enable_alerts: true, }, )) + .register_type::() .init_resource::() - .insert_resource(AssetsDir::new("assets/scratch")) .init_resource::() - .add_event::() .add_asset::() .init_asset_loader::() .add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message)) @@ -98,11 +92,7 @@ fn main() { .add_systems( Update, ( - init_assets_dir, - import_assets, - import_file, - import_folder, - reload_assets.run_if(ui::event::), + reload_assets.run_if(ui::activated::), clear_assets.run_if(ui::activated::), ), ) @@ -115,6 +105,15 @@ fn main() { ), ) .add_systems(Update, clear_level) + .add_systems( + Update, + ( + level_ui, + load_level, + export_level.run_if(ui::activated::), + rehydrate_level, + ), + ) .run(); } @@ -124,7 +123,8 @@ pub struct AssetRegistry(Vec); #[derive(Debug, Component)] pub struct TabRoot; -#[derive(Debug, Component)] +#[derive(Debug, Component, Reflect, Default)] +#[reflect(Component)] pub struct LevelRoot; #[derive(Debug, Component)] @@ -132,7 +132,7 @@ pub struct EditorCamera; fn initialize_ui(mut commands: Commands) { // Empty entity for populating the level being edited - commands.spawn((SpatialBundle { ..default() }, LevelRoot)); + commands.spawn((SpatialBundle { ..default() }, LevelRoot::default())); commands.spawn(( Camera2dBundle { ..default() }, @@ -230,6 +230,11 @@ fn initialize_ui(mut commands: Commands) { parent, ui::Select::Multi, )); + content_containers.push(spawn_tab_container::( + "Level", + parent, + ui::Select::Single, + )); content_containers.push(spawn_tab_container::( "Gltf", parent, @@ -337,17 +342,35 @@ fn initialize_ui(mut commands: Commands) { .with_children(|parent| { parent.spawn(( simple_button.clone(), - ClearAssets, + ReloadAssets, ui::Sorting(1), + ui::Title { + text: "Reload Assets".into(), + ..default() + }, + )); + parent.spawn(( + simple_button.clone(), + ClearAssets, + ui::Sorting(2), ui::Title { text: "Clear Assets".into(), ..default() }, )); + parent.spawn(( + simple_button.clone(), + ExportLevel, + ui::Sorting(3), + ui::Title { + text: "Export Level".into(), + ..default() + }, + )); parent.spawn(( simple_button.clone(), ClearLevel, - ui::Sorting(2), + ui::Sorting(3), ui::Title { text: "Reset Level".into(), ..default() @@ -497,146 +520,23 @@ mod audio { use assets::*; mod assets { - use std::{ - fs::DirBuilder, - fs::{copy, create_dir_all, read_dir}, - path::PathBuf, - }; - - use bevy::tasks::IoTaskPool; - use super::*; - #[derive(Debug, Resource)] - pub struct AssetsDir { - pub root: PathBuf, - } - - impl AssetsDir { - pub fn new(root: &str) -> Self { - AssetsDir { - root: PathBuf::from(root) - .canonicalize() - .expect("Setting assets dir"), - } - } - } - - pub fn init_assets_dir(assets_dir: Res) { - if assets_dir.is_added() || assets_dir.is_changed() { - let d = assets_dir.root.clone(); - IoTaskPool::get() - .spawn(async move { - match DirBuilder::new().create(d) { - Ok(_) => info!("Created assets directory"), - Err(e) => warn!("Error creating assets directory {:?}", e), - } - }) - .detach(); - } - } - - #[derive(Debug, Event)] - pub enum ImportAsset { - File(PathBuf), - Dir(PathBuf), - } - - pub fn import_assets( - mut events: EventReader, - mut writer: EventWriter, - ) { - events.iter().for_each(|event| match event { - FileDragAndDrop::DroppedFile { path_buf, .. } => { - if path_buf.is_file() { - writer.send(ImportAsset::File(path_buf.clone())); - } else if path_buf.is_dir() { - writer.send(ImportAsset::Dir(path_buf.clone())); - } else { - warn!("Could not identify filetype for {:?}", path_buf) - } - } - _ => (), - }) - } - - pub fn import_file(mut events: EventReader, assets_dir: Res) { - events - .iter() - .filter_map(|event| match event { - ImportAsset::File(path) => Some(path.clone()), - _ => None, - }) - .for_each(|path| { - let fname = path.file_name().expect("PathBuf should have file name"); - let newpath = PathBuf::from(assets_dir.root.clone()).join(fname); - IoTaskPool::get() - .spawn(async move { - if path == newpath { - info!("Skipping copying {:?} to itself {:?}", path, newpath); - } else { - match copy(path, newpath) { - Ok(_) => info!("Created assets directory"), - Err(e) => warn!("Error creating assets directory {:?}", e), - } - } - }) - .detach(); - }); - } - - fn copy_dir(from: PathBuf, to: PathBuf) -> std::io::Result<()> { - if let Ok(entries) = read_dir(from) { - for entry in entries.filter_map(|e| e.ok()) { - if entry.path().is_file() { - let from_file = entry.path(); - let to_file = to.join(entry.file_name()); - copy(from_file, to_file).map(|_| ())?; - } else if entry.path().is_dir() { - info!("Recursive"); - let target = to.join(entry.file_name()); - create_dir_all(target.clone())?; - copy_dir(entry.path(), target.clone())?; - } - } - } - Ok(()) - } - - pub fn import_folder(mut events: EventReader, assets_dir: Res) { - events - .iter() - .filter_map(|event| match event { - ImportAsset::Dir(path) => Some(path.clone()), - _ => None, - }) - .for_each(|path| { - let fname = path.file_name().expect("PathBuf should have file name"); - let newpath = PathBuf::from(assets_dir.root.clone()).join(fname); - info!("copying folder {:?} to {:?}", path.clone(), newpath); - IoTaskPool::get() - .spawn(async move { - if path.clone() == newpath { - info!("Skipping copying {:?} to itself {:?}", path, newpath); - } else { - match copy_dir(path.clone(), newpath) { - Ok(_) => info!("Created assets directory"), - Err(e) => warn!("Error creating assets directory {:?}", e), - } - } - }) - .detach(); - }); - } + #[derive(Debug, Component)] + pub struct ReloadAssets; pub fn reload_assets( server: Res, mut registry: ResMut, - assets_dir: Res, + mut writer: EventWriter, ) { - registry.0 = server - .load_folder(assets_dir.root.clone()) - .expect("Reload assets folder"); + match server.load_folder(".") { + Ok(handles) => registry.0 = handles, + Err(e) => writer.send(ui::Alert::Warn(format!( + "Could not find `assets` folder!\n{:?}", + e + ))), + } } pub fn get_asset_name(server: &AssetServer, handle: Handle) -> String { @@ -1508,3 +1408,155 @@ mod reset { registry.0.clear(); } } + +pub use level::*; +mod level { + use std::fs::File; + use std::io::Write; + + use bevy::tasks::IoTaskPool; + + use super::*; + + type Level = DynamicScene; + + #[derive(Debug, Component, Default)] + pub struct LevelWidget; + + #[derive(Debug, Component)] + pub struct ExportLevel; + + pub fn level_ui( + mut events: EventReader>, + mut commands: Commands, + widget: Query>, + current: Query<(Entity, &ui::TargetAsset)>, + server: Res, + ) { + events.iter().for_each(|event| match event { + AssetEvent::Created { handle } => { + info!("Asset created! {:?}", event); + create_asset_button( + &widget, + &mut commands, + ui::TargetAsset { + handle: handle.clone(), + }, + get_asset_name(&server, handle.clone()), + None, + ); + } + AssetEvent::Removed { handle } => { + info!("Asset removed! {:?}", event); + destroy_asset_button( + ¤t, + &mut commands, + &ui::TargetAsset { + handle: handle.clone(), + }, + ); + } + AssetEvent::Modified { handle } => { + info!("Asset modified! {:?}", event); + destroy_asset_button( + ¤t, + &mut commands, + &ui::TargetAsset { + handle: handle.clone(), + }, + ); + create_asset_button( + &widget, + &mut commands, + ui::TargetAsset { + handle: handle.clone(), + }, + get_asset_name(&server, handle.clone()), + None, + ); + } + }); + } + + pub fn load_level( + events: Query< + &ui::TargetAsset, + (Added, With>), + >, + root: Query>, + mut commands: Commands, + ) { + events.iter().for_each(|ui::TargetAsset { handle }| { + commands.entity(root.single()).despawn_recursive(); + commands.spawn(DynamicSceneBundle { + scene: handle.clone(), + ..default() + }); + }); + } + + pub fn export_level( + root: Query>, + children: Query<&Children>, + world: &World, + ) { + let app_type_registry = world.resource::().clone(); + let mut builder = DynamicSceneBuilder::from_world(world.clone()); + + builder.deny_all_resources(); + + // builder.allow_all(); + builder.deny::(); + + // Level administrivia + builder.allow::(); + + // Scene components + builder.allow::>(); + builder.allow::(); + builder.allow::(); + builder.allow::(); + + // Audio components + builder.allow::>(); + builder.allow::(); + + root.iter().for_each(|r| { + // Extract the level root + builder.extract_entity(r); + + match children.get(r) { + Ok(cs) => { + builder.extract_entities(cs.iter().map(|&entity| entity)); + } + Err(e) => warn!("Empty level! {:?}", e), + } + }); + + let scene = builder.build(); + + let serialized = scene + .serialize_ron(&app_type_registry) + .expect("Serialize scene"); + + IoTaskPool::get() + .spawn(async move { + // Write the scene RON data to file + File::create(format!("assets/output.scn.ron")) + .and_then(|mut file| file.write(serialized.as_bytes())) + .expect("Error while writing scene to file"); + }) + .detach(); + } + + pub fn rehydrate_level( + events: Query, Without)>, + mut commands: Commands, + ) { + events.iter().for_each(|entity| { + commands + .entity(entity) + .insert(ComputedVisibility::default()); + }); + } +} diff --git a/bin/serialize-wtf.rs b/bin/serialize-wtf.rs index 871f7fc..657df82 100644 --- a/bin/serialize-wtf.rs +++ b/bin/serialize-wtf.rs @@ -5,24 +5,13 @@ // * Copy assets into local folder in leue of importing them // * Check portability by moving binary + folder to new location -use std::{ - fs::{DirBuilder, File}, - io::Write, - time::Duration, -}; +use std::time::Duration; -use bevy::{ - asset::{Asset, ChangeWatcher}, - audio::PlaybackMode, - gltf::Gltf, - prelude::*, - tasks::IoTaskPool, -}; +use bevy::{asset::ChangeWatcher, prelude::*}; use monologue_trees::{debug::*, ui}; fn main() { App::new() - .init_resource::() .add_plugins(( DefaultPlugins .set(WindowPlugin { @@ -42,386 +31,75 @@ fn main() { DebugInfoPlugin, ui::GameUiPlugin { ..default() }, )) - .add_systems(Startup, (init, init_assets_dir)) - .add_systems( - Update, - ( - export.run_if(interaction_condition::), - clear.run_if(interaction_condition::), - import.run_if(interaction_condition::), - inspect.run_if(interaction_condition::), - load.run_if(interaction_condition::), - unload.run_if(interaction_condition::), - spawn_level.run_if(interaction_condition::), - asset_inspector::, - asset_inspector::, - ), - ) - .add_systems( - PostUpdate, - ( - rehydrate::, - rehydrate::, PlaybackSettings>, - fallback_camera.run_if(fallback_camera_condition), - ), - ) + .register_type::() + .register_type::() + .register_type::() + .add_systems(Startup, init) + .add_systems(Update, serialize_debug.run_if(pending)) .run(); } -#[derive(Debug, Component, Reflect, Default)] +#[derive(Debug, Component, Default, Reflect)] #[reflect(Component)] struct LevelRoot; -#[derive(Debug, Component)] -struct ExportAction; - -#[derive(Debug, Component)] -struct ClearAction; - -#[derive(Debug, Component)] -struct ImportAction; - -#[derive(Debug, Component)] -struct InspectAction; - -#[derive(Debug, Component)] -struct LoadAssetsAction; - -#[derive(Debug, Component)] -struct UnloadAssetsAction; - -#[derive(Debug, Component)] -struct SpawnLevelAction; - -#[derive(Debug, Resource, Default)] -struct AssetRegistry { - handles: Vec, +#[derive(Debug, Component, Default, Reflect)] +#[reflect(Component)] +struct Other { + inner: String, } -fn init_assets_dir() { - IoTaskPool::get() - .spawn(async move { - match DirBuilder::new().create("assets") { - Ok(_) => info!("Created assets directory"), - Err(e) => warn!("Error creating assets directory", e), - } - }) - .detach(); +#[derive(Debug, Component, Default, Reflect)] +#[reflect(Component)] +enum Choice { + #[reflect(default)] + #[default] + One, + Two, + Three, } fn init(mut commands: Commands) { commands.spawn(( - Camera2dBundle { ..default() }, - UiCameraConfig { show_ui: true }, + SpatialBundle { ..default() }, + LevelRoot::default(), + Name::new("Root Entity"), + Other::default(), + Choice::default(), )); - - commands - .spawn(( - NodeBundle { - style: Style { - top: Val::Px(0.0), - right: Val::Px(0.0), - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - position_type: PositionType::Absolute, - ..default() - }, - background_color: Color::WHITE.into(), - border_color: Color::BLACK.into(), - ..default() - }, - ui::Select::Action, - )) - .with_children(|parent| { - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Load Assets".into(), - ..default() - }, - LoadAssetsAction, - )); - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Dump Assets".into(), - ..default() - }, - UnloadAssetsAction, - )); - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Spawn Level".into(), - ..default() - }, - SpawnLevelAction, - )); - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Export".into(), - ..default() - }, - ExportAction, - )); - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Clear".into(), - ..default() - }, - ClearAction, - )); - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Import".into(), - ..default() - }, - ImportAction, - )); - parent.spawn(( - ButtonBundle { - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - ..default() - }, - border_color: Color::BLACK.into(), - ..default() - }, - ui::Title { - text: "Inspect".into(), - ..default() - }, - InspectAction, - )); - }); } -fn interaction_condition( - events: Query<&Interaction, (Changed, With)>, -) -> bool { - events - .iter() - .find(|&interaction| *interaction == Interaction::Pressed) - .is_some() +fn serialize_debug(query: Query>, world: &World) { + let entities = query.iter().collect(); + print!("{}", ser(entities, world)); } -fn rehydrate( - events: Query, Without)>, - mut commands: Commands, -) { - events.iter().for_each(|entity| { - info!("Rehydrating {:?}", WO::default()); - commands.entity(entity).insert(WO::default()); - }); +fn pending(query: Query>, mut done: Local) -> bool { + if !*done { + if query.iter().len() > 0 { + *done = true; + } else { + *done = false; + } + return *done; + } + return false; } -fn ser( - root: &Query>, - children: &Query<&Children>, - world: &World, -) -> String { +fn ser(entities: Vec, world: &World) -> String { let app_type_registry = world.resource::().clone(); - let mut builder = DynamicSceneBuilder::from_world(world.clone()); - - builder.deny_all_resources(); - - // builder.allow_all(); - builder.deny::(); - - // Level administrivia - builder.allow::(); - // Scene components - builder.allow::>(); - builder.allow::(); - builder.allow::(); - builder.allow::(); - - // Audio components - builder.allow::>(); - builder.allow::(); - - root.iter().for_each(|r| { - // Extract the level root - builder.extract_entity(r); - - // Extract all level root children - builder.extract_entities( - children - .get(r) - .expect("Root has children") - .iter() - .map(|&entity| entity), - ); - }); - - let scene = builder.build(); + let scene = { + let mut builder = DynamicSceneBuilder::from_world(world.clone()); + builder + .allow_all_resources() + .allow_all() + .deny::() + .extract_entities(entities.into_iter()); + builder.build() + }; scene .serialize_ron(&app_type_registry) .expect("Serialize scene") } - -fn export(root: Query>, children: Query<&Children>, world: &World) { - info!("Export level"); - - let serialized = ser(&root, &children, world); - - IoTaskPool::get() - .spawn(async move { - // Write the scene RON data to file - File::create(format!("assets/output.scn.ron")) - .and_then(|mut file| file.write(serialized.as_bytes())) - .expect("Error while writing scene to file"); - }) - .detach(); -} - -fn inspect(root: Query>, children: Query<&Children>, world: &World) { - info!("Inexpect level"); - - let serialized = ser(&root, &children, world); - - print!("{}", serialized); -} - -fn clear(root: Query>, mut commands: Commands) { - info!("Clearing level"); - - root.iter().for_each(|entity| { - commands.entity(entity).despawn_recursive(); - }); -} - -// TODO: Figure out how to import the same asset from a differnt source -// How do the plugins do it?? -fn import(mut commands: Commands, server: Res) { - info!("Importing level"); - - let scene_handle: Handle = server.load("output.scn.ron"); - commands.spawn(( - LevelRoot, - DynamicSceneBundle { - scene: scene_handle.clone(), - ..default() - }, - )); -} - -fn fallback_camera_condition( - added: Query>, - mut removed: RemovedComponents, -) -> bool { - added.iter().chain(removed.iter()).count() > 0 -} - -fn fallback_camera( - mut ui_camera: Query<&mut Camera, With>, - cameras: Query<&mut Camera, Without>, -) { - ui_camera.single_mut().is_active = cameras.iter().len() <= 0; -} - -fn asset_inspector(mut events: EventReader>) { - events.iter().for_each(|event| match event { - AssetEvent::Created { handle } => info!("Asset Created {:?}", handle), - AssetEvent::Modified { handle } => info!("Asset Modified {:?}", handle), - AssetEvent::Removed { handle } => info!("Asset Removed {:?}", handle), - }); -} - -// OK seems like `load_folder` does not automatically pick up added files -fn load(mut registry: ResMut, server: Res) { - info!("Loading assets"); - - registry.handles = server.load_folder("./dynamic").unwrap(); - info!("Current files: {:?}", registry.handles); -} - -fn unload(mut registry: ResMut, mut gltfs: ResMut>) { - info!("Unloading asstes"); - - registry.handles.clear(); - - // This is required to clear scenes from asset cache - gltfs.clear(); -} - -fn spawn_level(mut commands: Commands, server: Res) { - commands - .spawn((SpatialBundle { ..default() }, LevelRoot)) - .with_children(|parent| { - parent.spawn(AudioSourceBundle { - source: server.load::("dynamic/Lake Sound 1.ogg"), - settings: PlaybackSettings { - mode: PlaybackMode::Loop, - paused: false, - ..default() - }, - }); - parent.spawn((SceneBundle { - scene: server.load("dynamic/materials.glb#Scene0"), - ..default() - },)); - }); -}