Compare commits

..

No commits in common. 'b91561d4fc9c06ade9ec11264df4d7455bca06e2' and '7621db220e7d1f61aa753beb0ef891abaa4ce5e4' have entirely different histories.

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

@ -5,16 +5,15 @@ pub struct EditorAnimationPlugin;
impl Plugin for EditorAnimationPlugin {
fn build(&self, app: &mut App) {
app.add_event::<ControlAnimation>()
.add_systems(Update, sync_asset_buttons::<AnimationClip>)
app.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, ui_control_animations)
.add_systems(Update, ui_active_animation);
.add_systems(Update, play_animation);
}
}
@ -24,7 +23,7 @@ pub struct AnimationWidget;
#[derive(Debug, Component)]
pub struct AnimationPlayAll;
fn init_animations_ui(events: Query<Entity, Added<AnimationWidget>>, mut commands: Commands) {
pub 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((
@ -50,7 +49,7 @@ fn init_animations_ui(events: Query<Entity, Added<AnimationWidget>>, mut command
/// When a new scene is loaded, add any newly compatible animations
/// TODO: Add target entity(s) too
fn add_animations_ui(
pub fn add_animations_ui(
player_spawned: Query<&Name, Added<AnimationPlayer>>,
widget: Query<Entity, With<AnimationWidget>>,
mut commands: Commands,
@ -80,7 +79,7 @@ fn add_animations_ui(
}
// When a scene is de-selected, remove any outdated animation options
fn remove_animations_ui(
pub fn remove_animations_ui(
mut removed_players: RemovedComponents<Handle<Scene>>,
current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>,
clips: Res<Assets<AnimationClip>>,
@ -113,125 +112,61 @@ fn remove_animations_ui(
});
}
#[derive(Debug, Event)]
pub enum ControlAnimation {
Play(Handle<AnimationClip>),
Pause(Handle<AnimationClip>),
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);
})
});
}
fn play_animation(
mut events: EventReader<ControlAnimation>,
pub fn play_animation(
start: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut stop: RemovedComponents<ui::Active>,
clip_refs: Query<&ui::TargetAsset<AnimationClip>>,
mut targets: Query<(&mut AnimationPlayer, &Name), With<Transform>>,
clips: Res<Assets<AnimationClip>>,
) {
events.iter().for_each(|event| match event {
ControlAnimation::Play(handle) => {
stop.iter().for_each(|entity| {
if let Ok(ui::TargetAsset { handle }) = clip_refs.get(entity) {
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();
})
}
});
}
ControlAnimation::Pause(handle) => {
let clip = clips.get(handle).expect("Load animation clip");
start.iter().for_each(|entity| {
if let Ok(ui::TargetAsset { handle }) = clip_refs.get(entity) {
let clip = clips.get(&handle).expect("Load animation clip");
targets
.iter_mut()
.filter(|(_, name)| clip.compatible_with(name))
.for_each(|(mut player, _)| {
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);
});
if player.is_paused() {
player.resume();
} else {
player.play(handle.clone()).repeat();
}
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.init_resource::<AssetRegistry>()
.add_systems(Startup, reload_assets)
app.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;
fn reload_assets(
pub fn reload_assets(
server: Res<AssetServer>,
mut registry: ResMut<AssetRegistry>,
mut writer: EventWriter<ui::Alert>,
@ -142,10 +142,14 @@ pub fn sync_asset_buttons<T: Asset>(
buttons
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
(handle == this_handle).then_some(entity)
if handle == this_handle {
Some(entity)
} else {
None
}
})
.into_iter()
.for_each(|entity| {
.iter()
.for_each(|&entity| {
commands.entity(entity).insert(ui::Active);
});
});
@ -162,16 +166,20 @@ pub fn sync_remove_asset_buttons<T: Asset>(
events
.iter()
.find_map(|this_asset_entity| asset_entities.get(this_asset_entity).ok())
.into_iter()
.iter()
.for_each(|this_handle| {
debug!("Syncing removal of {:?}", this_handle);
info!("Syncing removal of {:?}", this_handle);
buttons
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
(handle == this_handle).then_some(entity)
if handle == *this_handle {
Some(entity)
} else {
None
}
})
.into_iter()
.for_each(|entity| {
.iter()
.for_each(|&entity| {
commands.entity(entity).remove::<ui::Active>();
});
});
@ -180,7 +188,7 @@ pub fn sync_remove_asset_buttons<T: Asset>(
#[derive(Debug, Component)]
pub struct ClearAssets;
fn clear_assets(
pub fn clear_assets(
asset_holders: Query<
Entity,
Or<(

@ -1,5 +1,3 @@
// TODO: Stop all button
use crate::editor::prelude::*;
use bevy::audio::PlaybackMode;
@ -8,17 +6,15 @@ pub struct EditorAudioPlugin;
impl Plugin for EditorAudioPlugin {
fn build(&self, app: &mut App) {
app.register_type::<AudioRoot>()
.add_event::<ControlAudio>()
.add_systems(Update, init_audio_ui)
app.add_systems(Update, audio_ui)
.add_systems(Update, ui_control_audio)
.add_systems(Update, ui_active::<AudioSource>)
.add_systems(Update, ui_inactive::<AudioSource>)
.add_systems(Update, control_audio)
.add_systems(Update, sync_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);
.register_type::<AudioRoot>()
.add_event::<ControlAudio>()
.add_systems(Update, sync_remove_asset_buttons::<AudioSource>);
}
}
@ -29,34 +25,7 @@ pub struct AudioRoot;
#[derive(Debug, Component, Default)]
pub struct AudioWidget;
#[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(
pub fn audio_ui(
mut events: EventReader<AssetEvent<AudioSource>>,
mut commands: Commands,
widget: Query<Entity, With<AudioWidget>>,
@ -65,7 +34,7 @@ fn audio_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
debug!("Audio asset created! {:?}", event);
info!("Asset created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -77,7 +46,7 @@ fn audio_ui(
);
}
AssetEvent::Removed { handle } => {
debug!("Asset removed! {:?}", event);
info!("Asset removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -87,7 +56,7 @@ fn audio_ui(
);
}
AssetEvent::Modified { handle } => {
debug!("Asset modified! {:?}", event);
info!("Asset modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -114,7 +83,7 @@ pub enum ControlAudio {
Stop(Handle<AudioSource>),
}
fn control_audio(
pub fn control_audio(
mut events: EventReader<ControlAudio>,
root: Query<Entity, With<AudioRoot>>,
mut commands: Commands,
@ -122,7 +91,7 @@ fn control_audio(
) {
events.iter().for_each(|event| match event {
ControlAudio::Loop(handle) => {
debug!("Looping audio {:?}", handle);
info!("Looping audio {:?}", handle);
let root = if let Ok(entity) = root.get_single() {
entity
} else {
@ -137,24 +106,30 @@ fn control_audio(
..default()
},
});
debug!("Done spawning {:?}", handle);
info!("Done spawning");
});
}
ControlAudio::Stop(handle) => {
info!("Stopping audio {:?}", handle);
sources
.iter()
.find_map(|(entity, source_handle)| (source_handle == handle).then_some(entity))
.into_iter()
.for_each(|entity| {
debug!("Stopping audio {:?}", handle);
.find_map(|(entity, source_handle)| {
if source_handle == handle {
Some(entity)
} else {
None
}
})
.iter()
.for_each(|&entity| {
commands.entity(entity).despawn_recursive();
debug!("Done despawning {:?}", handle);
info!("Done despawning");
});
}
});
}
fn ui_control_audio(
pub fn ui_control_audio(
events: Query<
(
&Interaction,
@ -178,19 +153,3 @@ 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,10 +5,8 @@ pub struct EditorCameraPlugin;
impl Plugin for EditorCameraPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(Msaa::Sample4)
.add_systems(Update, cameras_ui)
.add_systems(Update, control_active_camera)
.add_systems(Update, ui_control_active_camera)
app.add_systems(Update, cameras_ui)
.add_systems(Update, manage_active_camera)
.add_systems(Update, fallback_camera);
}
}
@ -19,7 +17,7 @@ pub struct EditorCamera;
#[derive(Debug, Component, Default)]
pub struct CameraWidget;
fn cameras_ui(
pub fn cameras_ui(
mut added: Query<(Entity, &mut Camera, &Name), Added<Camera>>,
mut removed: RemovedComponents<Camera>,
editor_camera: Query<Entity, With<EditorCamera>>,
@ -28,11 +26,11 @@ fn cameras_ui(
mut commands: Commands,
) {
removed.iter().for_each(|entity| {
debug!("Destroy button for {:?}", entity);
info!("Destroy button for {:?}", entity);
destroy_entity_button(&current, &mut commands, &ui::TargetEntity { entity });
});
added.iter_mut().for_each(|(entity, mut camera, name)| {
debug!("Camera added {:?} {:?}", entity, name);
info!("Camera added {:?} {:?}", entity, name);
create_entity_button(
&widget,
&mut commands,
@ -44,52 +42,17 @@ fn cameras_ui(
}
/// Set the camera active component based on button clicks
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>)>,
pub fn manage_active_camera(
events: Query<&ui::TargetEntity, Added<ui::Active>>,
mut cameras: Query<(Entity, &mut Camera)>,
) {
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() {
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);
camera.is_active = true;
} else {
camera.is_active = !active.is_some();
}
} else {
info!("Marking {:?} as inactive camera", entity);
camera.is_active = false;
}
});
@ -97,7 +60,7 @@ fn ui_control_active_camera(
}
// In the event that an active camera is despawned, fall back to the editor camera
fn fallback_camera(
pub 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.init_resource::<FontInfo>()
.add_systems(Update, sync_asset_buttons::<Font>)
app.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>>,
}
fn fonts_ui(
pub fn fonts_ui(
mut events: EventReader<AssetEvent<Font>>,
mut commands: Commands,
widget: Query<Entity, With<FontWidget>>,
@ -31,7 +31,7 @@ fn fonts_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
debug!("Font asset created! {:?}", event);
info!("Asset created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -43,7 +43,7 @@ fn fonts_ui(
);
}
AssetEvent::Removed { handle } => {
debug!("Font asset removed! {:?}", event);
info!("Asset removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -53,7 +53,7 @@ fn fonts_ui(
);
}
AssetEvent::Modified { handle } => {
debug!("Font asset modified! {:?}", event);
info!("Asset modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -74,7 +74,7 @@ fn fonts_ui(
});
}
fn ui_control_font(
pub fn ui_control_font(
events: Query<
(&Interaction, &ui::TargetAsset<Font>, Option<&ui::Active>),
(With<Button>, Changed<Interaction>),
@ -95,7 +95,7 @@ fn ui_control_font(
});
}
fn sync_font(
pub fn sync_font(
query: Query<(Entity, &ui::TargetAsset<Font>)>,
font: Res<FontInfo>,
mut commands: Commands,

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

@ -11,13 +11,13 @@ impl Plugin for EditorLightingPlugin {
}
}
fn spot_light_force_shadows(mut spot_lights: Query<&mut SpotLight, Added<SpotLight>>) {
pub 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;
})
}
fn directional_light_force_shadows(
pub 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 @@ fn directional_light_force_shadows(
})
}
fn point_light_force_shadows(mut point_lights: Query<&mut PointLight, Added<PointLight>>) {
pub 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,6 +3,7 @@ pub mod assets;
pub mod audio;
pub mod camera;
pub mod font;
pub mod gltf;
pub mod level;
pub mod lighting;
pub mod monologue;
@ -25,11 +26,15 @@ pub fn ui_active<T: Asset>(
buttons
.iter()
.find_map(|(entity, ui::TargetAsset { handle })| {
(handle == this_handle).then_some(entity)
if handle == this_handle {
Some(entity)
} else {
None
}
})
.into_iter()
.for_each(|entity| {
.and_then(|entity| {
commands.entity(entity).insert(ui::Active);
Some(())
});
});
}
@ -43,12 +48,12 @@ pub fn ui_inactive<T: Asset>(
events.iter().for_each(|_| {
targets
.iter()
.filter_map(|(entity, ui::TargetAsset { handle })| {
.find_map(|(entity, ui::TargetAsset { handle })| {
(!sources.iter().any(|this_handle| this_handle == handle)).then_some(entity)
})
.for_each(|entity| {
debug!("handle entity remove Active {:?}", entity);
.and_then(|entity| {
commands.entity(entity).remove::<ui::Active>();
Some(())
});
});
}
@ -151,6 +156,8 @@ 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,16 +14,15 @@ 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_systems(Startup, init_texts_ui)
.add_systems(Update, texts_ui);
.add_event::<ControlMonologue>();
}
}
@ -71,7 +70,7 @@ impl AssetLoader for MonologueLoader {
}
}
fn init_texts_ui(mut commands: Commands) {
pub fn init_texts_ui(mut commands: Commands) {
commands.spawn((
NodeBundle {
style: Style {
@ -87,7 +86,7 @@ fn init_texts_ui(mut commands: Commands) {
));
}
fn texts_ui(
pub fn texts_ui(
mut events: EventReader<AssetEvent<Monologue>>,
mut commands: Commands,
widget: Query<Entity, With<MonologueWidget>>,
@ -96,7 +95,7 @@ fn texts_ui(
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } => {
debug!("Monologue created! {:?}", event);
info!("Monologue created! {:?}", event);
create_asset_button(
&widget,
&mut commands,
@ -108,7 +107,7 @@ fn texts_ui(
);
}
AssetEvent::Removed { handle } => {
debug!("Monologue removed! {:?}", event);
info!("Monologue removed! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -118,7 +117,7 @@ fn texts_ui(
);
}
AssetEvent::Modified { handle } => {
debug!("Monologue modified! {:?}", event);
info!("Monologue modified! {:?}", event);
destroy_asset_button(
&current,
&mut commands,
@ -139,7 +138,7 @@ fn texts_ui(
});
}
fn control_monologue(
pub fn control_monologue(
mut events: EventReader<ControlMonologue>,
monologues: Res<Assets<Monologue>>,
container: Query<Entity, With<MonologueContainer>>,
@ -206,7 +205,7 @@ fn control_monologue(
});
}
fn ui_control_monologue(
pub fn ui_control_monologue(
events: Query<
(
&Interaction,
@ -232,7 +231,10 @@ fn ui_control_monologue(
}
// TODO: Sync Handle<Monologue> and TextStyle components to automagically generate and sync text
fn sync_monologue_font(mut texts: Query<&mut Text, With<Handle<Monologue>>>, font: Res<FontInfo>) {
pub 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,6 +10,7 @@ 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())
@ -17,6 +18,7 @@ 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::*, level::*, lighting::*, monologue::*,
quit::*, scene::*, timeline::*, *,
animation::*, assets::*, audio::*, camera::*, font::*, gltf::*, level::*, lighting::*,
monologue::*, quit::*, scene::*, timeline::*, *,
},
ui,
};

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

@ -5,42 +5,24 @@ pub struct EditorScenePlugin;
impl Plugin for EditorScenePlugin {
fn build(&self, app: &mut App) {
app.add_event::<ControlScene>()
.add_systems(Update, sync_asset_buttons::<Scene>)
.add_systems(Update, sync_remove_asset_buttons::<Scene>)
.add_systems(Update, ui_active::<Scene>)
.add_systems(Update, ui_inactive::<Scene>)
app.add_systems(Update, remove_scenes_ui)
.add_systems(Update, add_scenes_ui)
.add_systems(Update, remove_scenes_ui)
.add_systems(Update, control_scene)
.add_systems(Update, ui_control_scene);
}
.add_systems(Update, control_active_scenes)
.add_systems(Update, sync_asset_buttons::<Scene>)
.add_systems(Update, sync_remove_asset_buttons::<Scene>);
}
#[derive(Debug, Event)]
pub enum ControlScene {
Spawn(Handle<Scene>),
Despawn(Handle<Scene>),
}
#[derive(Debug, Component, Default)]
pub struct SceneWidget;
fn add_scenes_ui(
mut events: EventReader<AssetEvent<Gltf>>,
pub fn add_scenes_ui(
gltf_selected: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
mut commands: Commands,
gltfs: Res<Assets<Gltf>>,
widget: Query<Entity, With<SceneWidget>>,
server: Res<AssetServer>,
) {
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());
gltf_selected.iter().for_each(|ui::TargetAsset { handle }| {
if let Some(gltf) = gltfs.get(&handle.clone()) {
gltf.named_scenes.iter().for_each(|(name, handle)| {
create_asset_button(
@ -49,7 +31,7 @@ fn add_scenes_ui(
ui::TargetAsset {
handle: handle.clone(),
},
format!("({}) {}", gltf_name, name),
name.clone(),
None,
);
})
@ -57,7 +39,7 @@ fn add_scenes_ui(
});
}
fn remove_scenes_ui(
pub fn remove_scenes_ui(
mut gltf_unselected: RemovedComponents<ui::Active>,
target_assets: Query<&ui::TargetAsset<Gltf>>,
current: Query<(Entity, &ui::TargetAsset<Scene>)>,
@ -81,48 +63,44 @@ fn remove_scenes_ui(
});
}
fn control_scene(
mut events: EventReader<ControlScene>,
root: Query<Entity, With<LevelRoot>>,
pub fn control_active_scenes(
added: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut removed: RemovedComponents<ui::Active>,
scene_refs: Query<&ui::TargetAsset<Scene>>,
scenes: Query<(Entity, &Handle<Scene>)>,
level_root: Query<Entity, With<LevelRoot>>,
mut commands: Commands,
) {
events.iter().for_each(|event| match event {
ControlScene::Spawn(handle) => {
commands.entity(root.single()).with_children(|parent| {
// 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| {
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,9 +19,7 @@ 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, set_epoch_animations)
.add_systems(Update, load_epoch_animations);
.add_systems(Update, load_epoch_sfx);
}
}
@ -89,7 +87,7 @@ pub struct EpochAnimations {
/// System for adding an epoch to the level's timeline
/// Triggered when a button with the AddEpoch marker is Active
fn add_timeline_epoch(
pub fn add_timeline_epoch(
root: Query<(Entity, &Children), With<TimelineWidget>>,
mut commands: Commands,
) {
@ -121,7 +119,7 @@ fn add_timeline_epoch(
}
/// Set the GLTF for the current epoch
fn set_epoch_gltf(
pub fn set_epoch_gltf(
events: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -140,13 +138,13 @@ fn set_epoch_gltf(
});
}
fn load_epoch_gltf(events: Query<Option<&EpochGltf>, (Added<ui::Active>, With<EpochId>)>) {
pub fn load_epoch_gltf(events: Query<Option<&EpochGltf>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_gltf| {
warn!("TODO: Load epoch GLTF!");
})
}
fn set_epoch_scene(
pub fn set_epoch_scene(
events: Query<&ui::TargetAsset<Scene>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -163,13 +161,13 @@ fn set_epoch_scene(
});
}
fn load_epoch_scene(events: Query<Option<&EpochScene>, (Added<ui::Active>, With<EpochId>)>) {
pub fn load_epoch_scene(events: Query<Option<&EpochScene>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_scene| {
warn!("TODO: Load epoch Scene!");
})
}
fn set_epoch_camera(
pub fn set_epoch_camera(
events: Query<&ui::TargetEntity, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -186,13 +184,13 @@ fn set_epoch_camera(
});
}
fn load_epoch_camera(events: Query<Option<&EpochCamera>, (Added<ui::Active>, With<EpochId>)>) {
pub fn load_epoch_camera(events: Query<Option<&EpochCamera>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_camera| {
warn!("TODO: Load epoch Camera");
})
}
fn set_epoch_music(
pub fn set_epoch_music(
events: Query<&ui::TargetAsset<AudioSource>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -209,13 +207,13 @@ fn set_epoch_music(
});
}
fn load_epoch_music(events: Query<Option<&EpochMusic>, (Added<ui::Active>, With<EpochId>)>) {
pub fn load_epoch_music(events: Query<Option<&EpochMusic>, (Added<ui::Active>, With<EpochId>)>) {
events.iter().for_each(|epoch_music| {
warn!("TODO: Load epoch music!");
})
}
fn set_epoch_monologue(
pub fn set_epoch_monologue(
events: Query<&ui::TargetAsset<Monologue>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -232,7 +230,7 @@ fn set_epoch_monologue(
});
}
fn load_epoch_monologue(
pub fn load_epoch_monologue(
events: Query<Option<&EpochMonologue>, (Added<ui::Active>, With<EpochId>)>,
) {
events.iter().for_each(|epoch_monologue| {
@ -245,7 +243,7 @@ fn load_epoch_monologue(
});
}
fn set_epoch_font(
pub fn set_epoch_font(
events: Query<&ui::TargetAsset<Font>, Added<ui::Active>>,
active_epoch: Query<Entity, (With<ui::Active>, With<EpochId>)>,
mut commands: Commands,
@ -262,7 +260,7 @@ fn set_epoch_font(
});
}
fn load_epoch_font(
pub fn load_epoch_font(
events: Query<Option<&EpochFont>, (Added<ui::Active>, With<EpochId>)>,
mut font_info: ResMut<FontInfo>,
) {
@ -271,7 +269,7 @@ fn load_epoch_font(
});
}
fn set_epoch_sfx(
pub 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,
@ -293,7 +291,7 @@ fn set_epoch_sfx(
});
}
fn load_epoch_sfx(
pub fn load_epoch_sfx(
added: Query<Entity, (Added<ui::Active>, With<EpochId>)>,
mut removed: RemovedComponents<ui::Active>,
epoch_sfx: Query<&EpochSfx>,
@ -315,7 +313,7 @@ fn load_epoch_sfx(
});
}
fn set_epoch_animations(
pub fn set_epoch_animations(
events: Query<&ui::TargetAsset<AnimationClip>, Added<ui::Active>>,
mut active_epoch: Query<
(Entity, Option<&mut EpochAnimations>),
@ -341,7 +339,7 @@ fn set_epoch_animations(
});
}
fn load_epoch_animations(
pub fn load_epoch_animations(
events: Query<Option<&EpochAnimations>, (Added<ui::Active>, With<EpochId>)>,
) {
events.iter().for_each(|epoch_animations| {

@ -367,11 +367,17 @@ mod collapse {
events.iter().for_each(|(entity, children)| {
// Find any tabs which have this as a target
tabs.iter_mut()
.find_map(|(button, collapse)| (entity == collapse.target).then_some(button))
.into_iter()
.find_map(|(button, collapse)| {
if entity == collapse.target {
Some(button)
} else {
None
}
})
.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