|  |  | @ -3,15 +3,30 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | // Editor for creating Monologue Trees levels
 |  |  |  | // Editor for creating Monologue Trees levels
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //
 |  |  |  | //
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // BUGS:
 |  |  |  | // BUGS:
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * Camera order ambiguity
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * Load new GLTF -> Despawn all level entities
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //
 |  |  |  | //
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // TODO:
 |  |  |  | // TODO:
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // * edit textbox with actions
 |  |  |  | // * Disable auto start/load
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | // * (brutal) export level
 |  |  |  | // * Better handle hide/close monologue
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | // * (hard) import level
 |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | // * (hard) Harden Active Camera
 |  |  |  | // * (hard) Harden Active Camera
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * (medium) Despawn entire scene when GLTF changed?
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * (medium) Select Font -> "Default Font" Resource
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // * (medium) Pre-compute animation target entities
 |  |  |  | // * (medium) Pre-compute animation target entities
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // * make min/max/close buttons into actions not selects
 |  |  |  | // * (medium) Animation buttons only visible when playable
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | // * (???) Better handle hide/close monologue
 |  |  |  | // * (easy) Clear button to wipe spawned scene
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * (brutal) export level
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * (hard) import level
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // Asset types:
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * Audios (done)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //   * Loop individual (done)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * Gltfs (doing)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //   * Scenes
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //   * Animations
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //      * Play/Pause all
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * Fonts (done)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * Monologues (done)
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use bevy::{ |  |  |  | use bevy::{ | 
			
		
	
		
		
			
				
					
					|  |  |  |     asset::{Asset, AssetLoader, Assets, ChangeWatcher, LoadContext, LoadedAsset}, |  |  |  |     asset::{Asset, AssetLoader, Assets, ChangeWatcher, LoadContext, LoadedAsset}, | 
			
		
	
	
		
		
			
				
					|  |  | @ -24,8 +39,9 @@ use monologue_trees::{debug::*, ui}; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | const WELCOME_MESSAGES: &'static [&'static str] = &[ |  |  |  | const WELCOME_MESSAGES: &'static [&'static str] = &[ | 
			
		
	
		
		
			
				
					
					|  |  |  |     "Welcome to the Monologue Trees editor!", |  |  |  |     "Welcome to the Monologue Trees editor!", | 
			
		
	
		
		
			
				
					
					|  |  |  |     "Import assets by dragging and dropping files or folders into the editor!", |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     concat!( |  |  |  |     concat!( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         "Import assets by dragging and dropping files into the editor\n", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         "\n", | 
			
		
	
		
		
			
				
					
					|  |  |  |         "Supported file types (for now):\n", |  |  |  |         "Supported file types (for now):\n", | 
			
		
	
		
		
			
				
					
					|  |  |  |         "* 3D: .gltf, .glb\n", |  |  |  |         "* 3D: .gltf, .glb\n", | 
			
		
	
		
		
			
				
					
					|  |  |  |         "* Audio: .ogg\n", |  |  |  |         "* Audio: .ogg\n", | 
			
		
	
	
		
		
			
				
					|  |  | @ -51,15 +67,13 @@ fn main() { | 
			
		
	
		
		
			
				
					
					|  |  |  |                     ..default() |  |  |  |                     ..default() | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }), |  |  |  |                 }), | 
			
		
	
		
		
			
				
					
					|  |  |  |             DebugInfoPlugin, |  |  |  |             DebugInfoPlugin, | 
			
		
	
		
		
			
				
					
					|  |  |  |             ui::GameUiPlugin { |  |  |  |             ui::GameUiPlugin, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 enable_alerts: true, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             }, |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         )) |  |  |  |         )) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .register_type::<LevelRoot>() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .init_resource::<AssetRegistry>() |  |  |  |         .init_resource::<AssetRegistry>() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .init_resource::<FontInfo>() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_asset::<Monologue>() |  |  |  |         .add_asset::<Monologue>() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .init_asset_loader::<MonologueLoader>() |  |  |  |         .init_asset_loader::<MonologueLoader>() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .add_event::<CustomAssetEvent<Scene>>() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         .add_event::<CustomAssetEvent<AnimationClip>>() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message)) |  |  |  |         .add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message)) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems( |  |  |  |         .add_systems( | 
			
		
	
		
		
			
				
					
					|  |  |  |             Update, |  |  |  |             Update, | 
			
		
	
	
		
		
			
				
					|  |  | @ -75,25 +89,26 @@ fn main() { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Update, |  |  |  |             Update, | 
			
		
	
		
		
			
				
					
					|  |  |  |             (remove_scenes_ui, add_scenes_ui, control_active_scenes), |  |  |  |             (remove_scenes_ui, add_scenes_ui, control_active_scenes), | 
			
		
	
		
		
			
				
					
					|  |  |  |         ) |  |  |  |         ) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems(Update, (cameras_ui, manage_active_camera, fallback_camera)) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems(Update, (audio_ui, play_audio, pause_audio)) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems( |  |  |  |         .add_systems( | 
			
		
	
		
		
			
				
					
					|  |  |  |             Update, |  |  |  |             Update, | 
			
		
	
		
		
			
				
					
					|  |  |  |             ( |  |  |  |             ( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 gltf_ui, |  |  |  |                 cameras_ui, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 texts_ui, |  |  |  |                 manage_active_camera, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 control_active_gltf, |  |  |  |                 control_active_camera, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 show_preview_text, |  |  |  |                 fallback_camera, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 sync_monologue_font, |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             ), |  |  |  |             ), | 
			
		
	
		
		
			
				
					
					|  |  |  |         ) |  |  |  |         ) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems(Update, (fonts_ui, set_active_font)) |  |  |  |         .add_systems(Update, (audio_ui, play_audio)) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems(Startup, reload_assets) |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         .add_systems( |  |  |  |         .add_systems( | 
			
		
	
		
		
			
				
					
					|  |  |  |             Update, |  |  |  |             Update, | 
			
		
	
		
		
			
				
					
					|  |  |  |             ( |  |  |  |             ( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 reload_assets.run_if(ui::activated::<ReloadAssets>), |  |  |  |                 import_files, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 clear_assets.run_if(ui::activated::<ClearAssets>), |  |  |  |                 gltf_ui, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 fonts_ui, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 texts_ui, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 manage_active_gltf, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 show_preview_text, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 sync_monologue_font, | 
			
		
	
		
		
			
				
					
					|  |  |  |             ), |  |  |  |             ), | 
			
		
	
		
		
			
				
					
					|  |  |  |         ) |  |  |  |         ) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems( |  |  |  |         .add_systems( | 
			
		
	
	
		
		
			
				
					|  |  | @ -104,27 +119,23 @@ fn main() { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 directional_light_force_shadows, |  |  |  |                 directional_light_force_shadows, | 
			
		
	
		
		
			
				
					
					|  |  |  |             ), |  |  |  |             ), | 
			
		
	
		
		
			
				
					
					|  |  |  |         ) |  |  |  |         ) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems(Update, clear_level) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .add_systems( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Update, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 level_ui, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 load_level, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 export_level.run_if(ui::activated::<ExportLevel>), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 rehydrate_level, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .run(); |  |  |  |         .run(); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Resource, Default)] |  |  |  | #[derive(Resource, Default)] | 
			
		
	
		
		
			
				
					
					|  |  |  | pub struct AssetRegistry(Vec<HandleUntyped>); |  |  |  | pub struct AssetRegistry(Vec<HandleUntyped>); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #[derive(Event)] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | pub enum CustomAssetEvent<T: Asset> { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     Add { handle: Handle<T>, name: String }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     Remove { handle: Handle<T> }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     Clear, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Debug, Component)] |  |  |  | #[derive(Debug, Component)] | 
			
		
	
		
		
			
				
					
					|  |  |  | pub struct TabRoot; |  |  |  | pub struct TabRoot; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Debug, Component, Reflect, Default)] |  |  |  | #[derive(Debug, Component)] | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | #[reflect(Component)] |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | pub struct LevelRoot; |  |  |  | pub struct LevelRoot; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #[derive(Debug, Component)] |  |  |  | #[derive(Debug, Component)] | 
			
		
	
	
		
		
			
				
					|  |  | @ -132,7 +143,7 @@ pub struct EditorCamera; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fn initialize_ui(mut commands: Commands) { |  |  |  | fn initialize_ui(mut commands: Commands) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Empty entity for populating the level being edited
 |  |  |  |     // Empty entity for populating the level being edited
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     commands.spawn((SpatialBundle { ..default() }, LevelRoot::default())); |  |  |  |     commands.spawn((SpatialBundle { ..default() }, LevelRoot)); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     commands.spawn(( |  |  |  |     commands.spawn(( | 
			
		
	
		
		
			
				
					
					|  |  |  |         Camera2dBundle { ..default() }, |  |  |  |         Camera2dBundle { ..default() }, | 
			
		
	
	
		
		
			
				
					|  |  | @ -150,15 +161,6 @@ fn initialize_ui(mut commands: Commands) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         ..default() |  |  |  |         ..default() | 
			
		
	
		
		
			
				
					
					|  |  |  |     }; |  |  |  |     }; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let simple_button = ButtonBundle { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         style: Style { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ..base_style.clone() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         background_color: Color::WHITE.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         border_color: Color::BLACK.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     }; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     commands |  |  |  |     commands | 
			
		
	
		
		
			
				
					
					|  |  |  |         .spawn(NodeBundle { |  |  |  |         .spawn(NodeBundle { | 
			
		
	
		
		
			
				
					
					|  |  |  |             style: Style { |  |  |  |             style: Style { | 
			
		
	
	
		
		
			
				
					|  |  | @ -230,11 +232,6 @@ fn initialize_ui(mut commands: Commands) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 parent, |  |  |  |                                 parent, | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 ui::Select::Multi, |  |  |  |                                 ui::Select::Multi, | 
			
		
	
		
		
			
				
					
					|  |  |  |                             )); |  |  |  |                             )); | 
			
		
	
		
		
			
				
					
					|  |  |  |                             content_containers.push(spawn_tab_container::<LevelWidget>( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 "Level", |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 parent, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 ui::Select::Single, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             )); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             content_containers.push(spawn_tab_container::<GltfWidget>( |  |  |  |                             content_containers.push(spawn_tab_container::<GltfWidget>( | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 "Gltf", |  |  |  |                                 "Gltf", | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 parent, |  |  |  |                                 parent, | 
			
		
	
	
		
		
			
				
					|  |  | @ -277,19 +274,24 @@ fn initialize_ui(mut commands: Commands) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             ui::Select::Single, |  |  |  |                             ui::Select::Single, | 
			
		
	
		
		
			
				
					
					|  |  |  |                         )) |  |  |  |                         )) | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .with_children(|parent| { |  |  |  |                         .with_children(|parent| { | 
			
		
	
		
		
			
				
					
					|  |  |  |                             content_containers.iter().enumerate().for_each( |  |  |  |                             let b = ButtonBundle { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                 |(i, (name, target))| { |  |  |  |                                 style: Style { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                     parent.spawn(( |  |  |  |                                     ..base_style.clone() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                         simple_button.clone(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         ui::Title { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                             text: name.clone(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                             ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         ui::Collapse { target: *target }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         ui::Sorting(i as u8), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     )); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                                 }, |  |  |  |                                 }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                             ); |  |  |  |                                 background_color: Color::WHITE.into(), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 border_color: Color::BLACK.into(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 ..default() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             content_containers.iter().for_each(|(name, target)| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 parent.spawn(( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     b.clone(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     ui::Title { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         text: name.clone(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         ..default() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     ui::Collapse { target: *target }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 )); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             }); | 
			
		
	
		
		
			
				
					
					|  |  |  |                         }); |  |  |  |                         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |                 }) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .id(); |  |  |  |                 .id(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -303,91 +305,6 @@ fn initialize_ui(mut commands: Commands) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ui::Sorting(0), |  |  |  |                 ui::Sorting(0), | 
			
		
	
		
		
			
				
					
					|  |  |  |             )); |  |  |  |             )); | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     commands |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .spawn(NodeBundle { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             style: Style { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 bottom: Val::Px(0.0), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 left: Val::Px(0.0), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 position_type: PositionType::Absolute, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 border: UiRect::all(Val::Px(1.0)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 margin: UiRect::all(Val::Px(1.0)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 padding: UiRect::all(Val::Px(1.0)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 flex_direction: FlexDirection::Column, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 overflow: Overflow::clip(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             background_color: Color::WHITE.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             border_color: Color::BLACK.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .with_children(|parent| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             let container = parent |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .spawn(( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     NodeBundle { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         style: Style { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             border: UiRect::all(Val::Px(1.0)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             margin: UiRect::all(Val::Px(1.0)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             padding: UiRect::all(Val::Px(1.0)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             flex_direction: FlexDirection::Column, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             overflow: Overflow::clip(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         background_color: Color::WHITE.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         border_color: Color::BLACK.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     ui::Sorting(99), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     ui::Select::Action, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 )) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .with_children(|parent| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     parent.spawn(( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         simple_button.clone(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         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(3), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         ui::Title { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             text: "Reset Level".into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     )); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .id(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             parent.spawn(( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ui::TitleBarBase::new(Color::WHITE).bundle(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ui::Title { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     text: "Actions".into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ui::Minimize { target: container }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ui::Sorting(0), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             )); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fn welcome_message(mut writer: EventWriter<ui::Alert>) { |  |  |  | fn welcome_message(mut writer: EventWriter<ui::Alert>) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -428,6 +345,27 @@ fn spawn_tab_container<T: Default + Component>( | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) |  |  |  |     ) | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | fn import_files( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     mut events: EventReader<FileDragAndDrop>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     server: Res<AssetServer>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     mut registry: ResMut<AssetRegistry>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     events.iter().for_each(|event| match event { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         FileDragAndDrop::DroppedFile { path_buf, .. } => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             registry.0.push( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 server.load_untyped( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     path_buf | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .clone() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .into_os_string() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .into_string() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .expect("Path converts to string"), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 ), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         _ => (), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     }) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use audio::*; |  |  |  | use audio::*; | 
			
		
	
		
		
			
				
					
					|  |  |  | mod audio { |  |  |  | mod audio { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -504,40 +442,28 @@ mod audio { | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn play_audio(events: Query<&AudioSink, (With<Button>, Added<ui::Active>)>) { |  |  |  |     pub fn play_audio( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         events.iter().for_each(|sink| { |  |  |  |         events: Query<(Entity, &Interaction, &AudioSink), (With<Button>, Changed<Interaction>)>, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             sink.play(); |  |  |  |         mut commands: Commands, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |     ) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn pause_audio(mut events: RemovedComponents<ui::Active>, sinks: Query<&AudioSink>) { |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         events |  |  |  |         events | 
			
		
	
		
		
			
				
					
					|  |  |  |             .iter() |  |  |  |             .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |             .filter_map(|entity| sinks.get(entity).ok()) |  |  |  |             .filter(|(_, &interaction, _)| interaction == Interaction::Pressed) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             .for_each(|sink| sink.stop()); |  |  |  |             .for_each(|(entity, _, sink)| { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 sink.toggle(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if sink.is_paused() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     commands.entity(entity).remove::<ui::Active>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     commands.entity(entity).insert(ui::Active); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use assets::*; |  |  |  | use assets::*; | 
			
		
	
		
		
			
				
					
					|  |  |  | mod assets { |  |  |  | mod assets { | 
			
		
	
		
		
			
				
					
					|  |  |  |     use super::*; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[derive(Debug, Component)] |  |  |  |     use super::*; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct ReloadAssets; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn reload_assets( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         server: Res<AssetServer>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut registry: ResMut<AssetRegistry>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut writer: EventWriter<ui::Alert>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         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<T: Asset>(server: &AssetServer, handle: Handle<T>) -> String { |  |  |  |     pub fn get_asset_name<T: Asset>(server: &AssetServer, handle: Handle<T>) -> String { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if let Some(asset_path) = server.get_handle_path(handle.clone()) { |  |  |  |         if let Some(asset_path) = server.get_handle_path(handle.clone()) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -652,6 +578,7 @@ mod gltf { | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[derive(Debug, Component, Default)] |  |  |  |     #[derive(Debug, Component, Default)] | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct GltfWidget; |  |  |  |     pub struct GltfWidget; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // TODO: Mark selected gltf as active ~single exclusive~
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn gltf_ui( |  |  |  |     pub fn gltf_ui( | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut events: EventReader<AssetEvent<Gltf>>, |  |  |  |         mut events: EventReader<AssetEvent<Gltf>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |         mut commands: Commands, | 
			
		
	
	
		
		
			
				
					|  |  | @ -704,17 +631,28 @@ mod gltf { | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn control_active_gltf( |  |  |  |     pub fn manage_active_gltf( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         events: Query<Entity, (With<ui::TargetAsset<Gltf>>, Added<ui::Active>)>, |  |  |  |         events: Query< | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         root: Query<Entity, With<LevelRoot>>, |  |  |  |             (Entity, &Interaction, Option<&ui::Active>), | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             (With<Button>, Changed<Interaction>), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         >, | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |         mut commands: Commands, | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |     ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         events.iter().for_each(|_| { |  |  |  |         events | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             commands.entity(root.single()).despawn_descendants(); |  |  |  |             .iter() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |             .filter(|(_, &interaction, _)| interaction == Interaction::Pressed) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             .for_each(|(entity, _, active_ish)| match active_ish { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 Some(_) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     commands.entity(entity).remove::<ui::Active>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 None => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     commands.entity(entity).insert(ui::Active); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // TODO: Mark loaded animation as active
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use scenes::*; |  |  |  | use scenes::*; | 
			
		
	
		
		
			
				
					
					|  |  |  | mod scenes { |  |  |  | mod scenes { | 
			
		
	
		
		
			
				
					
					|  |  |  |     use super::*; |  |  |  |     use super::*; | 
			
		
	
	
		
		
			
				
					|  |  | @ -808,6 +746,8 @@ mod scenes { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // TODO: Play all animations
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // TODO: Mark playing animation as active
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use animations::*; |  |  |  | use animations::*; | 
			
		
	
		
		
			
				
					
					|  |  |  | mod animations { |  |  |  | mod animations { | 
			
		
	
		
		
			
				
					
					|  |  |  |     use super::*; |  |  |  |     use super::*; | 
			
		
	
	
		
		
			
				
					|  |  | @ -846,7 +786,6 @@ mod animations { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// When a new scene is loaded, add any newly compatible animations
 |  |  |  |     /// When a new scene is loaded, add any newly compatible animations
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// TODO: Add target entity(s) too
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn add_animations_ui( |  |  |  |     pub fn add_animations_ui( | 
			
		
	
		
		
			
				
					
					|  |  |  |         player_spawned: Query<&Name, Added<AnimationPlayer>>, |  |  |  |         player_spawned: Query<&Name, Added<AnimationPlayer>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         widget: Query<Entity, With<AnimationWidget>>, |  |  |  |         widget: Query<Entity, With<AnimationWidget>>, | 
			
		
	
	
		
		
			
				
					|  |  | @ -883,6 +822,7 @@ mod animations { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // When a scene is de-selected, remove any outdated animation options
 |  |  |  |     // When a scene is de-selected, remove any outdated animation options
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn remove_animations_ui( |  |  |  |     pub fn remove_animations_ui( | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut removed_players: RemovedComponents<Handle<Scene>>, |  |  |  |         mut removed_players: RemovedComponents<Handle<Scene>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         names: Query<&Name>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>, |  |  |  |         current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         clips: Res<Assets<AnimationClip>>, |  |  |  |         clips: Res<Assets<AnimationClip>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         targets: Query<(&AnimationPlayer, &Name)>, |  |  |  |         targets: Query<(&AnimationPlayer, &Name)>, | 
			
		
	
	
		
		
			
				
					|  |  | @ -981,11 +921,6 @@ mod fonts { | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[derive(Debug, Component, Default)] |  |  |  |     #[derive(Debug, Component, Default)] | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct FontWidget; |  |  |  |     pub struct FontWidget; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[derive(Debug, Resource, Default)] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct FontInfo { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         pub default: Option<Handle<Font>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn fonts_ui( |  |  |  |     pub fn fonts_ui( | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut events: EventReader<AssetEvent<Font>>, |  |  |  |         mut events: EventReader<AssetEvent<Font>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |         mut commands: Commands, | 
			
		
	
	
		
		
			
				
					|  |  | @ -1037,15 +972,6 @@ mod fonts { | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn set_active_font( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         events: Query<&ui::TargetAsset<Font>, Added<ui::Active>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut font: ResMut<FontInfo>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         events |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .iter() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .for_each(|ui::TargetAsset { handle }| font.default = Some(handle.clone())); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use monologues::*; |  |  |  | use monologues::*; | 
			
		
	
	
		
		
			
				
					|  |  | @ -1169,7 +1095,6 @@ mod monologues { | 
			
		
	
		
		
			
				
					
					|  |  |  |         monologues: Res<Assets<Monologue>>, |  |  |  |         monologues: Res<Assets<Monologue>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         container: Query<Entity, With<MonologueContainer>>, |  |  |  |         container: Query<Entity, With<MonologueContainer>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |         mut commands: Commands, | 
			
		
	
		
		
			
				
					
					|  |  |  |         font: Res<FontInfo>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |     ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         added |  |  |  |         added | 
			
		
	
		
		
			
				
					
					|  |  |  |             .iter() |  |  |  |             .iter() | 
			
		
	
	
		
		
			
				
					|  |  | @ -1206,21 +1131,15 @@ mod monologues { | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     }, |  |  |  |                                     }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     ui::Sorting(0), |  |  |  |                                     ui::Sorting(0), | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 )); |  |  |  |                                 )); | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 let style = match &font.default { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     Some(handle) => TextStyle { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         color: Color::BLACK.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         font_size: 16.0, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         font: handle.clone(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     None => TextStyle { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         color: Color::BLACK.into(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         font_size: 16.0, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                         ..default() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 }; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 parent.spawn(( |  |  |  |                                 parent.spawn(( | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     TextBundle::from_section(monologue.text.clone(), style), |  |  |  |                                     TextBundle::from_section( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         monologue.text.clone(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         TextStyle { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                             color: Color::BLACK.into(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                             font_size: 16.0, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                             ..default() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     ), | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     handle.clone(), |  |  |  |                                     handle.clone(), | 
			
		
	
		
		
			
				
					
					|  |  |  |                                 )); |  |  |  |                                 )); | 
			
		
	
		
		
			
				
					
					|  |  |  |                             }); |  |  |  |                             }); | 
			
		
	
	
		
		
			
				
					|  |  | @ -1230,19 +1149,16 @@ mod monologues { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // TODO: Sync Handle<Monologue> and TextStyle components to automagically generate and sync text
 |  |  |  |     // TODO: Sync Handle<Monologue> and TextStyle components to automagically generate and sync text
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn sync_monologue_font( |  |  |  |     pub fn sync_monologue_font( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         events: Query<&ui::TargetAsset<Font>, Added<ui::Active>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut texts: Query<&mut Text, With<Handle<Monologue>>>, |  |  |  |         mut texts: Query<&mut Text, With<Handle<Monologue>>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         font: Res<FontInfo>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |     ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if font.is_changed() || font.is_added() { |  |  |  |         events.iter().for_each(|ui::TargetAsset { handle }| { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             texts.iter_mut().for_each(|mut text| { |  |  |  |             texts.iter_mut().for_each(|mut text| { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 text.sections |  |  |  |                 text.sections.iter_mut().for_each(|section| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     .iter_mut() |  |  |  |                     section.style.font = handle.clone(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     .for_each(|section| match &font.default { |  |  |  |                 }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         Some(handle) => section.style.font = handle.clone(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         None => section.style.font = Handle::default(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     }); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |             }); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         }); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -1254,9 +1170,8 @@ mod cameras { | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct CameraWidget; |  |  |  |     pub struct CameraWidget; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn cameras_ui( |  |  |  |     pub fn cameras_ui( | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut added: Query<(Entity, &mut Camera, &Name), Added<Camera>>, |  |  |  |         mut added: Query<(Entity, &mut Camera, &Name), (Added<Camera>, Without<EditorCamera>)>, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         mut removed: RemovedComponents<Camera>, |  |  |  |         mut removed: RemovedComponents<Camera>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         editor_camera: Query<Entity, With<EditorCamera>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         widget: Query<Entity, With<CameraWidget>>, |  |  |  |         widget: Query<Entity, With<CameraWidget>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         current: Query<(Entity, &ui::TargetEntity)>, |  |  |  |         current: Query<(Entity, &ui::TargetEntity)>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |         mut commands: Commands, | 
			
		
	
	
		
		
			
				
					|  |  | @ -1273,25 +1188,47 @@ mod cameras { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ui::TargetEntity { entity }, |  |  |  |                 ui::TargetEntity { entity }, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 name.as_str().into(), |  |  |  |                 name.as_str().into(), | 
			
		
	
		
		
			
				
					
					|  |  |  |             ); |  |  |  |             ); | 
			
		
	
		
		
			
				
					
					|  |  |  |             camera.is_active = entity == editor_camera.single(); |  |  |  |             camera.is_active = false; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     /// Set the camera active component based on button clicks
 |  |  |  |     /// Set the camera active component based on button clicks
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn manage_active_camera( |  |  |  |     pub fn manage_active_camera( | 
			
		
	
		
		
			
				
					
					|  |  |  |         events: Query<&ui::TargetEntity, Added<ui::Active>>, |  |  |  |         events: Query<(&Interaction, &ui::TargetEntity), Changed<Interaction>>, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         mut cameras: Query<(Entity, &mut Camera)>, |  |  |  |         cameras: Query<Entity, With<Camera>>, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         mut commands: Commands, | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |     ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         events.iter().for_each(|ui::TargetEntity { entity }| { |  |  |  |         events | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             cameras.iter_mut().for_each(|(this_entity, mut camera)| { |  |  |  |             .iter() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 if this_entity == *entity { |  |  |  |             .filter(|(&interaction, _)| interaction == Interaction::Pressed) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     info!("Marking {:?} as active camera", entity); |  |  |  |             .for_each(|(_, ui::TargetEntity { entity })| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     camera.is_active = true; |  |  |  |                 cameras.iter().for_each(|this_entity| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } else { |  |  |  |                     if this_entity == *entity { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     info!("Marking {:?} as inactive camera", entity); |  |  |  |                         info!("Marking {:?} as active camera", entity); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     camera.is_active = false; |  |  |  |                         commands.entity(this_entity).insert(ui::Active); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 } |  |  |  |                     } else { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         info!("Marking {:?} as inactive camera", entity); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         commands.entity(this_entity).remove::<ui::Active>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 }); | 
			
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |             }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     /// Set the active camera based on the Active marker component
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     pub fn control_active_camera( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         added: Query<Entity, (Added<ui::Active>, With<Camera>)>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         mut removed: RemovedComponents<ui::Active>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         mut cameras: Query<&mut Camera>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         removed.iter().for_each(|entity| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if let Ok(mut camera) = cameras.get_mut(entity) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 camera.is_active = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         added.iter().for_each(|entity| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if let Ok(mut camera) = cameras.get_mut(entity) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 camera.is_active = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -1337,226 +1274,3 @@ mod lighting { | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |         }) | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | use reset::*; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | mod reset { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     use super::*; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[derive(Debug, Component)] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct ClearLevel; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn clear_level( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         events: Query<Entity, (With<ClearLevel>, Added<ui::Active>)>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         actives: Query< |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Entity, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::Active>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Or<( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetEntity>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetAsset<Gltf>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetAsset<Scene>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetAsset<AnimationClip>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetAsset<AudioSource>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetAsset<Monologue>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     With<ui::TargetAsset<Font>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 )>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         >, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         root: Query<Entity, With<LevelRoot>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         events.iter().for_each(|_| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             actives.iter().for_each(|entity| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 commands.entity(entity).remove::<ui::Active>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             commands.entity(root.single()).despawn_descendants(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     #[derive(Debug, Component)] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub struct ClearAssets; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     pub fn clear_assets( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         asset_holders: Query< |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Entity, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Or<( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::TargetAsset<Gltf>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<Handle<Gltf>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::TargetAsset<Scene>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<Handle<Scene>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::TargetAsset<AnimationClip>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<Handle<AnimationClip>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::TargetAsset<AudioSource>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<Handle<AudioSource>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::TargetAsset<Monologue>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<Handle<Monologue>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<ui::TargetAsset<Font>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 With<Handle<Font>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             )>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         >, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut registry: ResMut<AssetRegistry>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         info!("Clearing assets"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Clear buttons holding asset references
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         asset_holders |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .iter() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .for_each(|entity| commands.entity(entity).despawn_recursive()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Empty asset registry
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         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<AssetEvent<Level>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         widget: Query<Entity, With<LevelWidget>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         current: Query<(Entity, &ui::TargetAsset<Level>)>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         server: Res<AssetServer>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         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<DynamicScene>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (Added<ui::Active>, With<ui::TargetAsset<DynamicScene>>), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         >, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         root: Query<Entity, With<LevelRoot>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         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<Entity, With<LevelRoot>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         children: Query<&Children>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         world: &World, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let app_type_registry = world.resource::<AppTypeRegistry>().clone(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let mut builder = DynamicSceneBuilder::from_world(world.clone()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.deny_all_resources(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // builder.allow_all();
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.deny::<ComputedVisibility>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Level administrivia
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<LevelRoot>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Scene components
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<Handle<Scene>>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<Visibility>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<Transform>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<GlobalTransform>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Audio components
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<Handle<AudioSource>>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         builder.allow::<PlaybackSettings>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         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<Entity, (Added<Visibility>, Without<ComputedVisibility>)>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mut commands: Commands, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         events.iter().for_each(|entity| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             commands |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .entity(entity) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .insert(ComputedVisibility::default()); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
	
		
		
			
				
					|  |  | 
 |