|
|
|
|
@ -61,7 +61,7 @@ fn main() {
|
|
|
|
|
.init_asset_loader::<MonologueLoader>()
|
|
|
|
|
.add_event::<CustomAssetEvent<Scene>>()
|
|
|
|
|
.add_event::<CustomAssetEvent<AnimationClip>>()
|
|
|
|
|
.add_systems(Startup, (initialize_ui, welcome_message))
|
|
|
|
|
.add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message))
|
|
|
|
|
.add_systems(
|
|
|
|
|
Update,
|
|
|
|
|
(
|
|
|
|
|
@ -80,6 +80,7 @@ fn main() {
|
|
|
|
|
manage_camera,
|
|
|
|
|
play_animation,
|
|
|
|
|
play_audio,
|
|
|
|
|
show_preview_text,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.run();
|
|
|
|
|
@ -184,6 +185,11 @@ fn initialize_ui(mut commands: Commands) {
|
|
|
|
|
parent,
|
|
|
|
|
ui::Select::Single,
|
|
|
|
|
));
|
|
|
|
|
content_containers.push(spawn_tab_container::<MonologueWidget>(
|
|
|
|
|
"Monologue",
|
|
|
|
|
parent,
|
|
|
|
|
ui::Select::Single,
|
|
|
|
|
));
|
|
|
|
|
content_containers.push(spawn_tab_container::<AudioWidget>(
|
|
|
|
|
"Audio",
|
|
|
|
|
parent,
|
|
|
|
|
@ -265,7 +271,7 @@ fn initialize_ui(mut commands: Commands) {
|
|
|
|
|
justify_content: JustifyContent::SpaceBetween,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: Color::ALICE_BLUE.into(),
|
|
|
|
|
background_color: Color::WHITE.into(),
|
|
|
|
|
border_color: Color::BLACK.into(),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
@ -365,16 +371,7 @@ mod audio {
|
|
|
|
|
current: Query<(Entity, &ui::TargetAsset<AudioSource>)>,
|
|
|
|
|
server: Res<AssetServer>,
|
|
|
|
|
) {
|
|
|
|
|
events
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|&event| match event {
|
|
|
|
|
AssetEvent::Created { handle }
|
|
|
|
|
| AssetEvent::Removed { handle }
|
|
|
|
|
| AssetEvent::Modified { handle } => {
|
|
|
|
|
has_extensions(&server, handle.clone(), &["ogg"])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.for_each(|event| match event {
|
|
|
|
|
events.iter().for_each(|event| match event {
|
|
|
|
|
AssetEvent::Created { handle } => {
|
|
|
|
|
info!("Asset created! {:?}", event);
|
|
|
|
|
let id = create_asset_button(
|
|
|
|
|
@ -579,16 +576,7 @@ mod gltf {
|
|
|
|
|
current: Query<(Entity, &ui::TargetAsset<Gltf>)>,
|
|
|
|
|
server: Res<AssetServer>,
|
|
|
|
|
) {
|
|
|
|
|
events
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|&event| match event {
|
|
|
|
|
AssetEvent::Created { handle }
|
|
|
|
|
| AssetEvent::Removed { handle }
|
|
|
|
|
| AssetEvent::Modified { handle } => {
|
|
|
|
|
has_extensions(&server, handle.clone(), &["gltf", "glb"])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.for_each(|event| match event {
|
|
|
|
|
events.iter().for_each(|event| match event {
|
|
|
|
|
AssetEvent::Created { handle } => {
|
|
|
|
|
info!("Asset created! {:?}", event);
|
|
|
|
|
create_asset_button(
|
|
|
|
|
@ -902,16 +890,7 @@ mod fonts {
|
|
|
|
|
current: Query<(Entity, &ui::TargetAsset<Font>)>,
|
|
|
|
|
server: Res<AssetServer>,
|
|
|
|
|
) {
|
|
|
|
|
events
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|&event| match event {
|
|
|
|
|
AssetEvent::Created { handle }
|
|
|
|
|
| AssetEvent::Removed { handle }
|
|
|
|
|
| AssetEvent::Modified { handle } => {
|
|
|
|
|
has_extensions(&server, handle.clone(), &["ttf", "otf"])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.for_each(|event| match event {
|
|
|
|
|
events.iter().for_each(|event| match event {
|
|
|
|
|
AssetEvent::Created { handle } => {
|
|
|
|
|
info!("Asset created! {:?}", event);
|
|
|
|
|
create_asset_button(
|
|
|
|
|
@ -960,7 +939,10 @@ mod fonts {
|
|
|
|
|
use monologues::*;
|
|
|
|
|
mod monologues {
|
|
|
|
|
use super::*;
|
|
|
|
|
use bevy::reflect::{TypePath, TypeUuid};
|
|
|
|
|
use bevy::{
|
|
|
|
|
reflect::{TypePath, TypeUuid},
|
|
|
|
|
ui::FocusPolicy,
|
|
|
|
|
};
|
|
|
|
|
use serde::Deserialize;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component, Default)]
|
|
|
|
|
@ -972,6 +954,12 @@ mod monologues {
|
|
|
|
|
text: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub struct MonologueModal;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub struct MonologueContainer;
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct MonologueLoader;
|
|
|
|
|
|
|
|
|
|
@ -982,28 +970,160 @@ mod monologues {
|
|
|
|
|
load_context: &'a mut LoadContext,
|
|
|
|
|
) -> BoxedFuture<'a, Result<(), bevy::asset::Error>> {
|
|
|
|
|
Box::pin(async move {
|
|
|
|
|
load_context.set_default_asset(LoadedAsset::new(
|
|
|
|
|
String::from_utf8(bytes.to_vec()).expect("Convert bytes to String"),
|
|
|
|
|
));
|
|
|
|
|
let asset = Monologue {
|
|
|
|
|
text: String::from_utf8(bytes.to_vec())?,
|
|
|
|
|
};
|
|
|
|
|
load_context.set_default_asset(LoadedAsset::new(asset));
|
|
|
|
|
Ok(())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn extensions(&self) -> &[&str] {
|
|
|
|
|
&[".monologue.txt"]
|
|
|
|
|
&["monologue.txt"]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn init_texts_ui(mut commands: Commands) {
|
|
|
|
|
commands.spawn((
|
|
|
|
|
NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
width: Val::Percent(100.0),
|
|
|
|
|
align_items: AlignItems::Center,
|
|
|
|
|
justify_content: JustifyContent::Center,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
focus_policy: FocusPolicy::Pass,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
MonologueContainer,
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Load .txt files for monologues
|
|
|
|
|
pub fn texts_ui(
|
|
|
|
|
mut events: EventReader<AssetEvent<Monologue>>,
|
|
|
|
|
mut _commands: Commands,
|
|
|
|
|
_widget: Query<Entity, With<MonologueWidget>>,
|
|
|
|
|
_current: Query<(Entity, &ui::TargetAsset<Monologue>)>,
|
|
|
|
|
_server: Res<AssetServer>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
widget: Query<Entity, With<MonologueWidget>>,
|
|
|
|
|
current: Query<(Entity, &ui::TargetAsset<Monologue>)>,
|
|
|
|
|
server: Res<AssetServer>,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(|_event| {
|
|
|
|
|
info!("Loading monologue");
|
|
|
|
|
events.iter().for_each(|event| match event {
|
|
|
|
|
AssetEvent::Created { handle } => {
|
|
|
|
|
info!("Monologue created! {:?}", event);
|
|
|
|
|
create_asset_button(
|
|
|
|
|
&widget,
|
|
|
|
|
&mut commands,
|
|
|
|
|
ui::TargetAsset {
|
|
|
|
|
handle: handle.clone(),
|
|
|
|
|
},
|
|
|
|
|
get_asset_name(&server, handle.clone()),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
AssetEvent::Removed { handle } => {
|
|
|
|
|
info!("Monologue removed! {:?}", event);
|
|
|
|
|
destroy_asset_button(
|
|
|
|
|
¤t,
|
|
|
|
|
&mut commands,
|
|
|
|
|
&ui::TargetAsset {
|
|
|
|
|
handle: handle.clone(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
AssetEvent::Modified { handle } => {
|
|
|
|
|
info!("Monologue 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,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO(BUG): Better handle hide/close monologue
|
|
|
|
|
pub fn show_preview_text(
|
|
|
|
|
show: Query<Entity, (With<Button>, Added<ui::Active>)>,
|
|
|
|
|
mut removed: RemovedComponents<ui::Active>,
|
|
|
|
|
monologue_handles: Query<&ui::TargetAsset<Monologue>>,
|
|
|
|
|
monologues: Res<Assets<Monologue>>,
|
|
|
|
|
container: Query<Entity, With<MonologueContainer>>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
) {
|
|
|
|
|
removed
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|entity| monologue_handles.get(entity).ok())
|
|
|
|
|
.for_each(|_| {
|
|
|
|
|
commands.entity(container.single()).despawn_descendants();
|
|
|
|
|
});
|
|
|
|
|
show.iter()
|
|
|
|
|
.filter_map(|entity| monologue_handles.get(entity).ok())
|
|
|
|
|
.for_each(|ui::TargetAsset { handle }| {
|
|
|
|
|
let monologue = monologues.get(handle).expect("Preview loaded monologue");
|
|
|
|
|
commands
|
|
|
|
|
.entity(container.single())
|
|
|
|
|
.despawn_descendants()
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent
|
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
max_width: Val::Percent(50.0),
|
|
|
|
|
padding: UiRect::all(Val::Px(1.0)),
|
|
|
|
|
margin: UiRect::all(Val::Px(1.0)),
|
|
|
|
|
border: UiRect::all(Val::Px(1.0)),
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
background_color: Color::WHITE.into(),
|
|
|
|
|
border_color: Color::BLACK.into(),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent.spawn((
|
|
|
|
|
NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
padding: UiRect::all(Val::Px(1.0)),
|
|
|
|
|
margin: UiRect::all(Val::Px(1.0)),
|
|
|
|
|
border: UiRect::all(Val::Px(1.0)),
|
|
|
|
|
flex_direction: FlexDirection::Row,
|
|
|
|
|
align_items: AlignItems::Center,
|
|
|
|
|
justify_content: JustifyContent::SpaceBetween,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: Color::VIOLET.into(),
|
|
|
|
|
border_color: Color::BLACK.into(),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
ui::Title {
|
|
|
|
|
text: "Monologue".into(),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
ui::Close {
|
|
|
|
|
target: parent.parent_entity(),
|
|
|
|
|
},
|
|
|
|
|
ui::Sorting(0),
|
|
|
|
|
));
|
|
|
|
|
parent.spawn(TextBundle::from_section(
|
|
|
|
|
monologue.text.clone(),
|
|
|
|
|
TextStyle {
|
|
|
|
|
color: Color::BLACK.into(),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|