Compare commits

..

5 Commits

@ -23,7 +23,7 @@
// * make min/max/close buttons into actions not selects
// * (???) Better handle hide/close monologue
use bevy::{asset::ChangeWatcher, gltf::Gltf, prelude::*, utils::Duration};
use bevy::{asset::ChangeWatcher, prelude::*, utils::Duration};
use monologue_trees::{debug::*, editor::plugin::EditorPlugin, ui};
fn main() {

@ -5,15 +5,16 @@ pub struct EditorAnimationPlugin;
impl Plugin for EditorAnimationPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, sync_asset_buttons::<AnimationClip>)
app.add_event::<ControlAnimation>()
.add_systems(Update, sync_asset_buttons::<AnimationClip>)
.add_systems(Update, sync_remove_asset_buttons::<AnimationClip>)
.add_systems(Update, set_epoch_animations)
.add_systems(Update, load_epoch_animations)
.add_systems(Update, init_animations_ui)
.add_systems(Update, remove_animations_ui)
.add_systems(Update, add_animations_ui)
.add_systems(Update, play_all_animations)
.add_systems(Update, play_animation);
.add_systems(Update, play_animation)
.add_systems(Update, ui_control_animations)
.add_systems(Update, ui_active_animation);
}
}
@ -23,7 +24,7 @@ pub struct AnimationWidget;
#[derive(Debug, Component)]
pub struct AnimationPlayAll;
pub fn init_animations_ui(events: Query<Entity, Added<AnimationWidget>>, mut commands: Commands) {
fn init_animations_ui(events: Query<Entity, Added<AnimationWidget>>, mut commands: Commands) {
events.iter().for_each(|entity| {
commands.entity(entity).with_children(|parent| {
parent.spawn((
@ -49,7 +50,7 @@ pub fn init_animations_ui(events: Query<Entity, Added<AnimationWidget>>, mut com
/// When a new scene is loaded, add any newly compatible animations
/// TODO: Add target entity(s) too
pub fn add_animations_ui(
fn add_animations_ui(
player_spawned: Query<&Name, Added<AnimationPlayer>>,
widget: Query<Entity, With<AnimationWidget>>,
mut commands: Commands,
@ -79,7 +80,7 @@ pub fn add_animations_ui(
}
// When a scene is de-selected, remove any outdated animation options
pub fn remove_animations_ui(
fn remove_animations_ui(
mut removed_players: RemovedComponents<Handle<Scene>>,
current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>,
clips: Res<Assets<AnimationClip>>,
@ -112,61 +113,125 @@ pub fn remove_animations_ui(
});
}
pub fn play_all_animations(
start: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut stop: RemovedComponents<ui::Active>,
play_all_btn: Query<Entity, With<AnimationPlayAll>>,
clip_btns: Query<Entity, With<ui::TargetAsset<AnimationClip>>>,
mut commands: Commands,
) {
stop.iter()
.filter(|&entity| play_all_btn.contains(entity))
.for_each(|_| {
clip_btns.iter().for_each(|entity| {
commands.entity(entity).remove::<ui::Active>();
})
});
start
.iter()
.filter(|&entity| play_all_btn.contains(entity))
.for_each(|_| {
clip_btns.iter().for_each(|entity| {
commands.entity(entity).insert(ui::Active);
})
});
#[derive(Debug, Event)]
pub enum ControlAnimation {
Play(Handle<AnimationClip>),
Pause(Handle<AnimationClip>),
}
pub fn play_animation(
start: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut stop: RemovedComponents<ui::Active>,
clip_refs: Query<&ui::TargetAsset<AnimationClip>>,
fn play_animation(
mut events: EventReader<ControlAnimation>,
mut targets: Query<(&mut AnimationPlayer, &Name), With<Transform>>,
clips: Res<Assets<AnimationClip>>,
) {
stop.iter().for_each(|entity| {
if let Ok(ui::TargetAsset { handle }) = clip_refs.get(entity) {
events.iter().for_each(|event| match event {
ControlAnimation::Play(handle) => {
let clip = clips.get(&handle).expect("Load animation clip");
targets
.iter_mut()
.filter(|(_, name)| clip.compatible_with(name))
.for_each(|(mut player, _)| {
player.pause();
})
if player.is_paused() {
player.resume();
} else {
player.play(handle.clone()).repeat();
}
});
start.iter().for_each(|entity| {
if let Ok(ui::TargetAsset { handle }) = clip_refs.get(entity) {
let clip = clips.get(&handle).expect("Load animation clip");
}
ControlAnimation::Pause(handle) => {
let clip = clips.get(handle).expect("Load animation clip");
targets
.iter_mut()
.filter(|(_, name)| clip.compatible_with(name))
.for_each(|(mut player, _)| {
if player.is_paused() {
player.resume();
} else {
player.play(handle.clone()).repeat();
player.pause();
});
}
});
}
fn play_all_animations(
events: Query<
(Entity, &Interaction, Option<&ui::Active>),
(With<AnimationPlayAll>, Changed<Interaction>),
>,
clip_btns: Query<&ui::TargetAsset<AnimationClip>>,
mut writer: EventWriter<ControlAnimation>,
mut commands: Commands,
) {
events
.iter()
.filter_map(|(entity, &interaction, active)| {
(interaction == Interaction::Pressed).then_some((entity, active))
})
.for_each(|(entity, active)| match active {
Some(_) => {
commands.entity(entity).remove::<ui::Active>();
clip_btns.iter().for_each(|ui::TargetAsset { handle }| {
writer.send(ControlAnimation::Pause(handle.clone()));
});
}
None => {
commands.entity(entity).insert(ui::Active);
clip_btns.iter().for_each(|ui::TargetAsset { handle }| {
writer.send(ControlAnimation::Play(handle.clone()));
});
}
})
}
fn ui_control_animations(
events: Query<
(
&Interaction,
&ui::TargetAsset<AnimationClip>,
Option<&ui::Active>,
),
(With<Button>, Changed<Interaction>),
>,
mut writer: EventWriter<ControlAnimation>,
) {
events
.iter()
.filter_map(
|(interaction, ui::TargetAsset { handle }, active)| match interaction {
Interaction::Pressed => Some((handle, active)),
_ => None,
},
)
.for_each(|(handle, active)| match active {
Some(_) => writer.send(ControlAnimation::Pause(handle.clone())),
None => writer.send(ControlAnimation::Play(handle.clone())),
});
}
fn ui_active_animation(
mut events: EventReader<ControlAnimation>,
targets: Query<(Entity, &ui::TargetAsset<AnimationClip>)>,
mut commands: Commands,
) {
events.iter().for_each(|event| match event {
ControlAnimation::Play(this_handle) => {
targets
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
(handle == this_handle).then_some(entity)
})
.into_iter()
.for_each(|entity| {
commands.entity(entity).insert(ui::Active);
});
}
ControlAnimation::Pause(this_handle) => {
targets
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
(handle == this_handle).then_some(entity)
})
.into_iter()
.for_each(|entity| {
commands.entity(entity).remove::<ui::Active>();
});
}
});
}

@ -5,9 +5,9 @@ pub struct EditorAssetsPlugin;
impl Plugin for EditorAssetsPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, reload_assets)
app.init_resource::<AssetRegistry>()
.add_systems(Startup, reload_assets)
.add_systems(Update, reload_assets.run_if(ui::activated::<ReloadAssets>))
.init_resource::<AssetRegistry>()
.add_systems(Update, clear_assets.run_if(ui::activated::<ClearAssets>));
}
}
@ -18,7 +18,7 @@ pub struct AssetRegistry(pub Vec<HandleUntyped>);
#[derive(Debug, Component)]
pub struct ReloadAssets;
pub fn reload_assets(
fn reload_assets(
server: Res<AssetServer>,
mut registry: ResMut<AssetRegistry>,
mut writer: EventWriter<ui::Alert>,
@ -142,14 +142,10 @@ pub fn sync_asset_buttons<T: Asset>(
buttons
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
if handle == this_handle {
Some(entity)
} else {
None
}
(handle == this_handle).then_some(entity)
})
.iter()
.for_each(|&entity| {
.into_iter()
.for_each(|entity| {
commands.entity(entity).insert(ui::Active);
});
});
@ -166,20 +162,16 @@ pub fn sync_remove_asset_buttons<T: Asset>(
events
.iter()
.find_map(|this_asset_entity| asset_entities.get(this_asset_entity).ok())
.iter()
.into_iter()
.for_each(|this_handle| {
info!("Syncing removal of {:?}", this_handle);
debug!("Syncing removal of {:?}", this_handle);
buttons
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
if handle == *this_handle {
Some(entity)
} else {
None
}
(handle == this_handle).then_some(entity)
})
.iter()
.for_each(|&entity| {
.into_iter()
.for_each(|entity| {
commands.entity(entity).remove::<ui::Active>();
});
});
@ -188,7 +180,7 @@ pub fn sync_remove_asset_buttons<T: Asset>(
#[derive(Debug, Component)]
pub struct ClearAssets;
pub fn clear_assets(
fn clear_assets(
asset_holders: Query<
Entity,
Or<(

@ -1,3 +1,5 @@
// TODO: Stop all button
use crate::editor::prelude::*;
use bevy::audio::PlaybackMode;
@ -6,15 +8,17 @@ pub struct EditorAudioPlugin;
impl Plugin for EditorAudioPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, audio_ui)
.add_systems(Update, ui_control_audio)
app.register_type::<AudioRoot>()
.add_event::<ControlAudio>()
.add_systems(Update, init_audio_ui)
.add_systems(Update, ui_active::<AudioSource>)
.add_systems(Update, ui_inactive::<AudioSource>)
.add_systems(Update, control_audio)
.add_systems(Update, sync_asset_buttons::<AudioSource>)
.register_type::<AudioRoot>()
.add_event::<ControlAudio>()
.add_systems(Update, sync_remove_asset_buttons::<AudioSource>);
.add_systems(Update, sync_remove_asset_buttons::<AudioSource>)
.add_systems(Update, audio_ui)
.add_systems(Update, ui_control_audio)
.add_systems(Update, stop_all_audio)
.add_systems(Update, control_audio);
}
}
@ -25,7 +29,34 @@ pub struct AudioRoot;
#[derive(Debug, Component, Default)]
pub struct AudioWidget;
pub fn audio_ui(
#[derive(Debug, Component)]
struct AudioStopAll;
fn init_audio_ui(events: Query<Entity, Added<AudioWidget>>, mut commands: Commands) {
events.iter().for_each(|entity| {
commands.entity(entity).with_children(|parent| {
parent.spawn((
AudioStopAll,
ButtonBundle {
style: Style {
border: UiRect::all(Val::Px(1.0)),
margin: UiRect::all(Val::Px(1.0)),
padding: UiRect::all(Val::Px(1.0)),
..default()
},
border_color: Color::BLACK.into(),
..default()
},
ui::Title {
text: "Stop All".into(),
..default()
},
));
});
})
}
fn audio_ui(
mut events: EventReader<AssetEvent<AudioSource>>,
mut commands: Commands,
widget: Query<Entity, With<AudioWidget>>,
@ -34,7 +65,7 @@ pub fn audio_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
info!("Asset created! {:?}", event);
debug!("Audio asset created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -46,7 +77,7 @@ pub fn audio_ui(
);
}
AssetEvent::Removed { handle } => {
info!("Asset removed! {:?}", event);
debug!("Asset removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -56,7 +87,7 @@ pub fn audio_ui(
);
}
AssetEvent::Modified { handle } => {
info!("Asset modified! {:?}", event);
debug!("Asset modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -83,7 +114,7 @@ pub enum ControlAudio {
Stop(Handle<AudioSource>),
}
pub fn control_audio(
fn control_audio(
mut events: EventReader<ControlAudio>,
root: Query<Entity, With<AudioRoot>>,
mut commands: Commands,
@ -91,7 +122,7 @@ pub fn control_audio(
) {
events.iter().for_each(|event| match event {
ControlAudio::Loop(handle) => {
info!("Looping audio {:?}", handle);
debug!("Looping audio {:?}", handle);
let root = if let Ok(entity) = root.get_single() {
entity
} else {
@ -106,30 +137,24 @@ pub fn control_audio(
..default()
},
});
info!("Done spawning");
debug!("Done spawning {:?}", handle);
});
}
ControlAudio::Stop(handle) => {
info!("Stopping audio {:?}", handle);
sources
.iter()
.find_map(|(entity, source_handle)| {
if source_handle == handle {
Some(entity)
} else {
None
}
})
.iter()
.for_each(|&entity| {
.find_map(|(entity, source_handle)| (source_handle == handle).then_some(entity))
.into_iter()
.for_each(|entity| {
debug!("Stopping audio {:?}", handle);
commands.entity(entity).despawn_recursive();
info!("Done despawning");
debug!("Done despawning {:?}", handle);
});
}
});
}
pub fn ui_control_audio(
fn ui_control_audio(
events: Query<
(
&Interaction,
@ -153,3 +178,19 @@ pub fn ui_control_audio(
None => writer.send(ControlAudio::Loop(handle.clone())),
});
}
fn stop_all_audio(
events: Query<&Interaction, With<AudioStopAll>>,
targets: Query<&ui::TargetAsset<AudioSource>>,
mut writer: EventWriter<ControlAudio>,
) {
events
.into_iter()
.filter(|&interaction| *interaction == Interaction::Pressed)
.into_iter()
.for_each(|_| {
targets.iter().for_each(|ui::TargetAsset { handle }| {
writer.send(ControlAudio::Stop(handle.clone()));
});
});
}

@ -5,8 +5,10 @@ pub struct EditorCameraPlugin;
impl Plugin for EditorCameraPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, cameras_ui)
.add_systems(Update, manage_active_camera)
app.insert_resource(Msaa::Sample4)
.add_systems(Update, cameras_ui)
.add_systems(Update, control_active_camera)
.add_systems(Update, ui_control_active_camera)
.add_systems(Update, fallback_camera);
}
}
@ -17,7 +19,7 @@ pub struct EditorCamera;
#[derive(Debug, Component, Default)]
pub struct CameraWidget;
pub fn cameras_ui(
fn cameras_ui(
mut added: Query<(Entity, &mut Camera, &Name), Added<Camera>>,
mut removed: RemovedComponents<Camera>,
editor_camera: Query<Entity, With<EditorCamera>>,
@ -26,11 +28,11 @@ pub fn cameras_ui(
mut commands: Commands,
) {
removed.iter().for_each(|entity| {
info!("Destroy button for {:?}", entity);
debug!("Destroy button for {:?}", entity);
destroy_entity_button(&current, &mut commands, &ui::TargetEntity { entity });
});
added.iter_mut().for_each(|(entity, mut camera, name)| {
info!("Camera added {:?} {:?}", entity, name);
debug!("Camera added {:?} {:?}", entity, name);
create_entity_button(
&widget,
&mut commands,
@ -42,17 +44,52 @@ pub fn cameras_ui(
}
/// Set the camera active component based on button clicks
pub fn manage_active_camera(
events: Query<&ui::TargetEntity, Added<ui::Active>>,
mut cameras: Query<(Entity, &mut Camera)>,
fn control_active_camera(
events: Query<(Entity, &Camera), Changed<Camera>>,
buttons: Query<(Entity, &ui::TargetEntity)>,
mut commands: Commands,
) {
events
.iter()
.filter_map(|(e, c)| {
buttons
.iter()
.find_map(|(button, ui::TargetEntity { entity })| {
(e == *entity).then_some((button, c))
})
})
.for_each(|(button, camera)| {
if camera.is_active {
commands.entity(button).insert(ui::Active);
} else {
commands.entity(button).remove::<ui::Active>();
}
});
}
fn ui_control_active_camera(
events: Query<
(&Interaction, &ui::TargetEntity, Option<&ui::Active>),
(With<Button>, Changed<Interaction>),
>,
mut cameras: Query<(Entity, &mut Camera, Option<&EditorCamera>)>,
) {
events.iter().for_each(|ui::TargetEntity { entity }| {
cameras.iter_mut().for_each(|(this_entity, mut camera)| {
if this_entity == *entity {
info!("Marking {:?} as active camera", entity);
events
.iter()
.filter_map(|(&interaction, ui::TargetEntity { entity }, active)| {
(interaction == Interaction::Pressed).then_some((entity, active))
})
.for_each(|(&entity, active)| {
cameras
.iter_mut()
.for_each(|(this, mut camera, editor_cam)| {
if this == entity {
if editor_cam.is_some() {
camera.is_active = true;
} else {
info!("Marking {:?} as inactive camera", entity);
camera.is_active = !active.is_some();
}
} else {
camera.is_active = false;
}
});
@ -60,7 +97,7 @@ pub fn manage_active_camera(
}
// In the event that an active camera is despawned, fall back to the editor camera
pub fn fallback_camera(
fn fallback_camera(
modified: Query<Entity, (Changed<Camera>, Without<EditorCamera>)>,
mut removed: RemovedComponents<Camera>,
other_cameras: Query<&Camera, Without<EditorCamera>>,

@ -5,11 +5,11 @@ pub struct EditorFontPlugin;
impl Plugin for EditorFontPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, sync_asset_buttons::<Font>)
app.init_resource::<FontInfo>()
.add_systems(Update, sync_asset_buttons::<Font>)
.add_systems(Update, sync_remove_asset_buttons::<Font>)
.add_systems(Update, fonts_ui)
.add_systems(Update, ui_control_font)
.init_resource::<FontInfo>()
.add_systems(Update, sync_font);
}
}
@ -22,7 +22,7 @@ pub struct FontInfo {
pub default: Option<Handle<Font>>,
}
pub fn fonts_ui(
fn fonts_ui(
mut events: EventReader<AssetEvent<Font>>,
mut commands: Commands,
widget: Query<Entity, With<FontWidget>>,
@ -31,7 +31,7 @@ pub fn fonts_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
info!("Asset created! {:?}", event);
debug!("Font asset created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -43,7 +43,7 @@ pub fn fonts_ui(
);
}
AssetEvent::Removed { handle } => {
info!("Asset removed! {:?}", event);
debug!("Font asset removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -53,7 +53,7 @@ pub fn fonts_ui(
);
}
AssetEvent::Modified { handle } => {
info!("Asset modified! {:?}", event);
debug!("Font asset modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -74,7 +74,7 @@ pub fn fonts_ui(
});
}
pub fn ui_control_font(
fn ui_control_font(
events: Query<
(&Interaction, &ui::TargetAsset<Font>, Option<&ui::Active>),
(With<Button>, Changed<Interaction>),
@ -95,7 +95,7 @@ pub fn ui_control_font(
});
}
pub fn sync_font(
fn sync_font(
query: Query<(Entity, &ui::TargetAsset<Font>)>,
font: Res<FontInfo>,
mut commands: Commands,

@ -1,79 +0,0 @@
use crate::editor::prelude::*;
#[derive(Debug, Default)]
pub struct EditorGltfPlugin;
impl Plugin for EditorGltfPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, sync_asset_buttons::<Gltf>)
.add_systems(Update, sync_remove_asset_buttons::<Gltf>)
.add_systems(Update, gltf_ui);
}
}
#[derive(Debug, Component, Default)]
pub struct GltfWidget;
pub fn gltf_ui(
mut events: EventReader<AssetEvent<Gltf>>,
mut commands: Commands,
widget: Query<Entity, With<GltfWidget>>,
current: Query<(Entity, &ui::TargetAsset<Gltf>)>,
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(
&current,
&mut commands,
&ui::TargetAsset {
handle: handle.clone(),
},
);
}
AssetEvent::Modified { handle } => {
info!("Asset modified! {:?}", event);
destroy_asset_button(
&current,
&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 control_active_gltf(
events: Query<Entity, (With<ui::TargetAsset<Gltf>>, Added<ui::Active>)>,
root: Query<Entity, With<LevelRoot>>,
mut commands: Commands,
) {
events.iter().for_each(|_| {
root.iter().for_each(|entity| {
commands.entity(entity).despawn_descendants();
});
});
}

@ -32,7 +32,7 @@ pub struct LevelWidget;
#[derive(Debug, Component)]
pub struct ExportLevel;
pub fn level_ui(
fn level_ui(
mut events: EventReader<AssetEvent<Level>>,
mut commands: Commands,
widget: Query<Entity, With<LevelWidget>>,
@ -41,7 +41,7 @@ pub fn level_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
info!("Asset created! {:?}", event);
debug!("Level asset created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -53,7 +53,7 @@ pub fn level_ui(
);
}
AssetEvent::Removed { handle } => {
info!("Asset removed! {:?}", event);
debug!("Level asset removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -63,7 +63,7 @@ pub fn level_ui(
);
}
AssetEvent::Modified { handle } => {
info!("Asset modified! {:?}", event);
debug!("Level asset modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -84,7 +84,7 @@ pub fn level_ui(
});
}
pub fn load_level(
fn load_level(
events: Query<
&ui::TargetAsset<DynamicScene>,
(Added<ui::Active>, With<ui::TargetAsset<DynamicScene>>),
@ -103,7 +103,7 @@ pub fn load_level(
});
}
pub fn export_level(
fn export_level(
level_root: Query<Entity, With<LevelRoot>>,
audio_root: Query<Entity, With<AudioRoot>>,
children: Query<&Children>,
@ -176,7 +176,7 @@ pub fn export_level(
.detach();
}
pub fn rehydrate_level<W: Component, WO: Component + Default>(
fn rehydrate_level<W: Component, WO: Component + Default>(
events: Query<Entity, (Added<W>, Without<WO>)>,
mut commands: Commands,
) {
@ -188,7 +188,7 @@ pub fn rehydrate_level<W: Component, WO: Component + Default>(
#[derive(Debug, Component)]
pub struct ClearLevel;
pub fn clear_level(
fn clear_level(
events: Query<Entity, (With<ClearLevel>, Added<ui::Active>)>,
actives: Query<
Entity,

@ -11,13 +11,13 @@ impl Plugin for EditorLightingPlugin {
}
}
pub fn spot_light_force_shadows(mut spot_lights: Query<&mut SpotLight, Added<SpotLight>>) {
fn spot_light_force_shadows(mut spot_lights: Query<&mut SpotLight, Added<SpotLight>>) {
spot_lights.iter_mut().for_each(|mut light| {
light.shadows_enabled = true;
})
}
pub fn directional_light_force_shadows(
fn directional_light_force_shadows(
mut directional_lights: Query<&mut DirectionalLight, Added<DirectionalLight>>,
) {
directional_lights.iter_mut().for_each(|mut light| {
@ -25,7 +25,7 @@ pub fn directional_light_force_shadows(
})
}
pub fn point_light_force_shadows(mut point_lights: Query<&mut PointLight, Added<PointLight>>) {
fn point_light_force_shadows(mut point_lights: Query<&mut PointLight, Added<PointLight>>) {
point_lights.iter_mut().for_each(|mut light| {
light.shadows_enabled = true;
})

@ -3,7 +3,6 @@ pub mod assets;
pub mod audio;
pub mod camera;
pub mod font;
pub mod gltf;
pub mod level;
pub mod lighting;
pub mod monologue;
@ -26,15 +25,11 @@ pub fn ui_active<T: Asset>(
buttons
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
if handle == this_handle {
Some(entity)
} else {
None
}
(handle == this_handle).then_some(entity)
})
.and_then(|entity| {
.into_iter()
.for_each(|entity| {
commands.entity(entity).insert(ui::Active);
Some(())
});
});
}
@ -48,12 +43,12 @@ pub fn ui_inactive<T: Asset>(
events.iter().for_each(|_| {
targets
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
.filter_map(|(entity, ui::TargetAsset { handle })| {
(!sources.iter().any(|this_handle| this_handle == handle)).then_some(entity)
})
.and_then(|entity| {
.for_each(|entity| {
debug!("handle entity remove Active {:?}", entity);
commands.entity(entity).remove::<ui::Active>();
Some(())
});
});
}
@ -156,8 +151,6 @@ fn initialize_ui(mut commands: Commands) {
.push(spawn_tab_container::<AudioWidget>("Audio", parent));
content_containers
.push(spawn_tab_container::<LevelWidget>("Level", parent));
content_containers
.push(spawn_tab_container::<GltfWidget>("Gltf", parent));
content_containers
.push(spawn_tab_container::<SceneWidget>("Scene", parent));
content_containers

@ -14,15 +14,16 @@ impl Plugin for EditorMonologuePlugin {
fn build(&self, app: &mut App) {
app.add_asset::<Monologue>()
.init_asset_loader::<MonologueLoader>()
.add_event::<ControlMonologue>()
.add_systems(Update, sync_asset_buttons::<Monologue>)
.add_systems(Update, sync_remove_asset_buttons::<Monologue>)
.add_systems(Update, control_active_gltf)
.add_systems(Update, control_monologue)
.add_systems(Update, ui_control_monologue)
.add_systems(Update, ui_active::<Monologue>)
.add_systems(Update, ui_inactive::<Monologue>)
.add_systems(Update, sync_monologue_font)
.add_event::<ControlMonologue>();
.add_systems(Startup, init_texts_ui)
.add_systems(Update, texts_ui);
}
}
@ -70,7 +71,7 @@ impl AssetLoader for MonologueLoader {
}
}
pub fn init_texts_ui(mut commands: Commands) {
fn init_texts_ui(mut commands: Commands) {
commands.spawn((
NodeBundle {
style: Style {
@ -86,7 +87,7 @@ pub fn init_texts_ui(mut commands: Commands) {
));
}
pub fn texts_ui(
fn texts_ui(
mut events: EventReader<AssetEvent<Monologue>>,
mut commands: Commands,
widget: Query<Entity, With<MonologueWidget>>,
@ -95,7 +96,7 @@ pub fn texts_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
info!("Monologue created! {:?}", event);
debug!("Monologue created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -107,7 +108,7 @@ pub fn texts_ui(
);
}
AssetEvent::Removed { handle } => {
info!("Monologue removed! {:?}", event);
debug!("Monologue removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -117,7 +118,7 @@ pub fn texts_ui(
);
}
AssetEvent::Modified { handle } => {
info!("Monologue modified! {:?}", event);
debug!("Monologue modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -138,7 +139,7 @@ pub fn texts_ui(
});
}
pub fn control_monologue(
fn control_monologue(
mut events: EventReader<ControlMonologue>,
monologues: Res<Assets<Monologue>>,
container: Query<Entity, With<MonologueContainer>>,
@ -205,7 +206,7 @@ pub fn control_monologue(
});
}
pub fn ui_control_monologue(
fn ui_control_monologue(
events: Query<
(
&Interaction,
@ -231,10 +232,7 @@ pub fn ui_control_monologue(
}
// TODO: Sync Handle<Monologue> and TextStyle components to automagically generate and sync text
pub fn sync_monologue_font(
mut texts: Query<&mut Text, With<Handle<Monologue>>>,
font: Res<FontInfo>,
) {
fn sync_monologue_font(mut texts: Query<&mut Text, With<Handle<Monologue>>>, font: Res<FontInfo>) {
if font.is_changed() || font.is_added() {
texts.iter_mut().for_each(|mut text| {
text.sections

@ -10,7 +10,6 @@ impl Plugin for EditorPlugin {
.add_plugins(EditorAudioPlugin::default())
.add_plugins(EditorCameraPlugin::default())
.add_plugins(EditorFontPlugin::default())
.add_plugins(EditorGltfPlugin::default())
.add_plugins(EditorLevelPlugin::default())
.add_plugins(EditorLightingPlugin::default())
.add_plugins(EditorMonologuePlugin::default())
@ -18,7 +17,6 @@ impl Plugin for EditorPlugin {
.add_plugins(EditorScenePlugin::default())
.add_plugins(EditorTimelinePlugin::default())
.add_systems(Startup, initialize_ui)
.add_systems(Startup, init_texts_ui)
.add_systems(Startup, welcome_message);
}
}

@ -1,7 +1,7 @@
pub use crate::{
editor::{
animation::*, assets::*, audio::*, camera::*, font::*, gltf::*, level::*, lighting::*,
monologue::*, quit::*, scene::*, timeline::*, *,
animation::*, assets::*, audio::*, camera::*, font::*, level::*, lighting::*, monologue::*,
quit::*, scene::*, timeline::*, *,
},
ui,
};

@ -14,6 +14,6 @@ impl Plugin for EditorQuitPlugin {
#[derive(Debug, Component, Default)]
pub struct QuitAction;
pub fn quit(mut exit: EventWriter<AppExit>) {
fn quit(mut exit: EventWriter<AppExit>) {
exit.send(AppExit);
}

@ -5,24 +5,42 @@ pub struct EditorScenePlugin;
impl Plugin for EditorScenePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, remove_scenes_ui)
.add_systems(Update, add_scenes_ui)
.add_systems(Update, control_active_scenes)
app.add_event::<ControlScene>()
.add_systems(Update, sync_asset_buttons::<Scene>)
.add_systems(Update, sync_remove_asset_buttons::<Scene>);
.add_systems(Update, sync_remove_asset_buttons::<Scene>)
.add_systems(Update, ui_active::<Scene>)
.add_systems(Update, ui_inactive::<Scene>)
.add_systems(Update, add_scenes_ui)
.add_systems(Update, remove_scenes_ui)
.add_systems(Update, control_scene)
.add_systems(Update, ui_control_scene);
}
}
#[derive(Debug, Event)]
pub enum ControlScene {
Spawn(Handle<Scene>),
Despawn(Handle<Scene>),
}
#[derive(Debug, Component, Default)]
pub struct SceneWidget;
pub fn add_scenes_ui(
gltf_selected: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
fn add_scenes_ui(
mut events: EventReader<AssetEvent<Gltf>>,
mut commands: Commands,
gltfs: Res<Assets<Gltf>>,
widget: Query<Entity, With<SceneWidget>>,
server: Res<AssetServer>,
) {
gltf_selected.iter().for_each(|ui::TargetAsset { handle }| {
events
.iter()
.filter_map(|event| match event {
AssetEvent::Created { handle } => Some(handle),
_ => None,
})
.for_each(|handle| {
let gltf_name = get_asset_name(&server, handle.clone());
if let Some(gltf) = gltfs.get(&handle.clone()) {
gltf.named_scenes.iter().for_each(|(name, handle)| {
create_asset_button(
@ -31,7 +49,7 @@ pub fn add_scenes_ui(
ui::TargetAsset {
handle: handle.clone(),
},
name.clone(),
format!("({}) {}", gltf_name, name),
None,
);
})
@ -39,7 +57,7 @@ pub fn add_scenes_ui(
});
}
pub fn remove_scenes_ui(
fn remove_scenes_ui(
mut gltf_unselected: RemovedComponents<ui::Active>,
target_assets: Query<&ui::TargetAsset<Gltf>>,
current: Query<(Entity, &ui::TargetAsset<Scene>)>,
@ -63,44 +81,48 @@ pub fn remove_scenes_ui(
});
}
pub fn control_active_scenes(
added: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut removed: RemovedComponents<ui::Active>,
scene_refs: Query<&ui::TargetAsset<Scene>>,
fn control_scene(
mut events: EventReader<ControlScene>,
root: Query<Entity, With<LevelRoot>>,
scenes: Query<(Entity, &Handle<Scene>)>,
level_root: Query<Entity, With<LevelRoot>>,
mut commands: Commands,
) {
// A scene button was marked inactive
removed.iter().for_each(|entity| {
// Get the handle associated with that button
scene_refs
.get(entity)
.iter()
.for_each(|ui::TargetAsset { handle }| {
scenes
.iter()
.find_map(|(entity, this_handle)| (this_handle == handle).then_some(entity))
.iter()
.for_each(|&entity| {
commands.entity(entity).despawn_recursive();
});
});
});
added.iter().for_each(|entity| {
scene_refs
.get(entity)
.iter()
.for_each(|ui::TargetAsset { handle }| {
info!("Spawning Scene {:?}", handle);
commands
.entity(level_root.single())
.with_children(|parent| {
events.iter().for_each(|event| match event {
ControlScene::Spawn(handle) => {
commands.entity(root.single()).with_children(|parent| {
parent.spawn(SceneBundle {
scene: handle.clone(),
..default()
});
});
}
ControlScene::Despawn(handle) => {
scenes
.iter()
.find_map(|(entity, this_handle)| (handle == this_handle).then_some(entity))
.into_iter()
.for_each(|entity| commands.entity(entity).despawn_recursive());
}
});
}
fn ui_control_scene(
events: Query<
(&Interaction, &ui::TargetAsset<Scene>, Option<&ui::Active>),
(With<Button>, Changed<Interaction>),
>,
mut writer: EventWriter<ControlScene>,
) {
events
.iter()
.filter_map(
|(interaction, ui::TargetAsset { handle }, active)| match interaction {
Interaction::Pressed => Some((handle, active)),
_ => None,
},
)
.for_each(|(handle, active)| match active {
Some(_) => writer.send(ControlScene::Despawn(handle.clone())),
None => writer.send(ControlScene::Spawn(handle.clone())),
});
}

@ -19,7 +19,9 @@ impl Plugin for EditorTimelinePlugin {
.add_systems(Update, set_epoch_font)
.add_systems(Update, load_epoch_font)
.add_systems(Update, set_epoch_sfx)
.add_systems(Update, load_epoch_sfx);
.add_systems(Update, load_epoch_sfx)
.add_systems(Update, set_epoch_animations)
.add_systems(Update, load_epoch_animations);
}
}
@ -87,7 +89,7 @@ pub struct EpochAnimations {
/// System for adding an epoch to the level's timeline
/// Triggered when a button with the AddEpoch marker is Active
pub fn add_timeline_epoch(
fn add_timeline_epoch(
root: Query<(Entity, &Children), With<TimelineWidget>>,
mut commands: Commands,
) {
@ -119,7 +121,7 @@ pub fn add_timeline_epoch(
}
/// Set the GLTF for the current epoch
pub fn set_epoch_gltf(
fn set_epoch_gltf(
events: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -138,13 +140,13 @@ pub fn set_epoch_gltf(
});
}
pub fn load_epoch_gltf(events: Query<Option<&EpochGltf>, (Added<ui::Active>, With<EpochId>)>) {
fn load_epoch_gltf(events: Query<Option<&EpochGltf>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_gltf| {
warn!("TODO: Load epoch GLTF!");
})
}
pub fn set_epoch_scene(
fn set_epoch_scene(
events: Query<&ui::TargetAsset<Scene>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -161,13 +163,13 @@ pub fn set_epoch_scene(
});
}
pub fn load_epoch_scene(events: Query<Option<&EpochScene>, (Added<ui::Active>, With<EpochId>)>) {
fn load_epoch_scene(events: Query<Option<&EpochScene>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_scene| {
warn!("TODO: Load epoch Scene!");
})
}
pub fn set_epoch_camera(
fn set_epoch_camera(
events: Query<&ui::TargetEntity, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -184,13 +186,13 @@ pub fn set_epoch_camera(
});
}
pub fn load_epoch_camera(events: Query<Option<&EpochCamera>, (Added<ui::Active>, With<EpochId>)>) {
fn load_epoch_camera(events: Query<Option<&EpochCamera>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_camera| {
warn!("TODO: Load epoch Camera");
})
}
pub fn set_epoch_music(
fn set_epoch_music(
events: Query<&ui::TargetAsset<AudioSource>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -207,13 +209,13 @@ pub fn set_epoch_music(
});
}
pub fn load_epoch_music(events: Query<Option<&EpochMusic>, (Added<ui::Active>, With<EpochId>)>) {
fn load_epoch_music(events: Query<Option<&EpochMusic>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_music| {
warn!("TODO: Load epoch music!");
})
}
pub fn set_epoch_monologue(
fn set_epoch_monologue(
events: Query<&ui::TargetAsset<Monologue>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -230,7 +232,7 @@ pub fn set_epoch_monologue(
});
}
pub fn load_epoch_monologue(
fn load_epoch_monologue(
events: Query<Option<&EpochMonologue>, (Added<ui::Active>, With<EpochId>)>,
) {
events.iter().for_each(|epoch_monologue| {
@ -243,7 +245,7 @@ pub fn load_epoch_monologue(
});
}
pub fn set_epoch_font(
fn set_epoch_font(
events: Query<&ui::TargetAsset<Font>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -260,7 +262,7 @@ pub fn set_epoch_font(
});
}
pub fn load_epoch_font(
fn load_epoch_font(
events: Query<Option<&EpochFont>, (Added<ui::Active>, With<EpochId>)>,
mut font_info: ResMut<FontInfo>,
) {
@ -269,7 +271,7 @@ pub fn load_epoch_font(
});
}
pub fn set_epoch_sfx(
fn set_epoch_sfx(
events: Query<&ui::TargetAsset<AudioSource>, Added<ui::Active>>,
mut active_epoch: Query<(Entity, Option<&mut EpochSfx>), (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -291,7 +293,7 @@ pub fn set_epoch_sfx(
});
}
pub fn load_epoch_sfx(
fn load_epoch_sfx(
added: Query<Entity, (Added<ui::Active>, With<EpochId>)>,
mut removed: RemovedComponents<ui::Active>,
epoch_sfx: Query<&EpochSfx>,
@ -313,7 +315,7 @@ pub fn load_epoch_sfx(
});
}
pub fn set_epoch_animations(
fn set_epoch_animations(
events: Query<&ui::TargetAsset<AnimationClip>, Added<ui::Active>>,
mut active_epoch: Query<
(Entity, Option<&mut EpochAnimations>),
@ -339,7 +341,7 @@ pub fn set_epoch_animations(
});
}
pub fn load_epoch_animations(
fn load_epoch_animations(
events: Query<Option<&EpochAnimations>, (Added<ui::Active>, With<EpochId>)>,
) {
events.iter().for_each(|epoch_animations| {

@ -367,17 +367,11 @@ mod collapse {
events.iter().for_each(|(entity, children)| {
// Find any tabs which have this as a target
tabs.iter_mut()
.find_map(|(button, collapse)| {
if entity == collapse.target {
Some(button)
} else {
None
}
})
.iter()
.find_map(|(button, collapse)| (entity == collapse.target).then_some(button))
.into_iter()
.for_each(|button| {
let num_children = children.len();
commands.entity(*button).insert(Note {
commands.entity(button).insert(Note {
text: format!("({})", num_children),
});
});

Loading…
Cancel
Save