Half way implementing fog tweakfile changes

Parsing the fog parameter in toml is a PITA but a good lesson for future
tweaks I guess...
main
Elijah C. Voigt 2 years ago
parent ff7b707bef
commit 296d79afeb

@ -1,15 +1,15 @@
[display2d] [audio.display2d]
pick_up = "/SFX/2D/2DPickUpPiece" pick_up = "/SFX/2D/2DPickUpPiece"
put_down = "/SFX/2D/2DPutDownPiece" put_down = "/SFX/2D/2DPutDownPiece"
[display3d] [audio.display3d]
pick_up = "/SFX/3D/3DPickUpPiece" pick_up = "/SFX/3D/3DPickUpPiece"
put_down = "/SFX/3D/3DPutDownPiece" put_down = "/SFX/3D/3DPutDownPiece"
idle = "/SFX/3D/3DPickup-Idle-PutdownWhirr" idle = "/SFX/3D/3DPickup-Idle-PutdownWhirr"
invalid = "/sfx/3D/3DInvalidMove" invalid = "/sfx/3D/3DInvalidMove"
[music] [audio.music]
main = "/Music/Main Track2" main = "/Music/Main Track2"
[menu] [audio.menu]
select = "/SFX/MenuSelect" select = "/SFX/MenuSelect"

@ -2,12 +2,7 @@
/// TODO: Custom Asset: FmodEventMapper /// TODO: Custom Asset: FmodEventMapper
/// ///
use crate::prelude::*; use crate::prelude::*;
use bevy::{ use bevy::prelude::*;
asset::{AssetLoader, LoadContext, LoadedAsset},
prelude::*,
reflect::{TypePath, TypeUuid},
utils::BoxedFuture,
};
use bevy_fmod::prelude::AudioSource; use bevy_fmod::prelude::AudioSource;
use bevy_fmod::prelude::*; use bevy_fmod::prelude::*;
use serde::Deserialize; use serde::Deserialize;
@ -18,8 +13,6 @@ impl Plugin for AudioPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<AudioEvent>(); app.add_event::<AudioEvent>();
app.add_systems(OnEnter(GameState::Loading), load_tweakfile);
app.add_plugins(FmodPlugin { app.add_plugins(FmodPlugin {
audio_banks_paths: &[ audio_banks_paths: &[
"./assets/audio/Martian Chess Audio/Build/Desktop/Master.bank", "./assets/audio/Martian Chess Audio/Build/Desktop/Master.bank",
@ -28,8 +21,6 @@ impl Plugin for AudioPlugin {
"./assets/audio/Martian Chess Audio/Build/Desktop/SFX.bank", "./assets/audio/Martian Chess Audio/Build/Desktop/SFX.bank",
], ],
}); });
app.add_asset::<AudioSettings>()
.init_asset_loader::<AudioSettingsLoader>();
app.add_systems(OnEnter(GameState::Menu), play_background); app.add_systems(OnEnter(GameState::Menu), play_background);
app.add_systems( app.add_systems(
@ -55,14 +46,6 @@ pub enum AudioEvent {
Invalid, Invalid,
} }
#[derive(Resource)]
struct AudioTweakfile(Handle<AudioSettings>);
fn load_tweakfile(server: Res<AssetServer>, mut commands: Commands) {
let handle: Handle<AudioSettings> = server.load("audio/martian.audio.tweak");
commands.insert_resource(AudioTweakfile(handle));
}
fn play_background(mut events: EventWriter<AudioEvent>) { fn play_background(mut events: EventWriter<AudioEvent>) {
events.send(AudioEvent::MainMusic); events.send(AudioEvent::MainMusic);
} }
@ -77,33 +60,33 @@ fn audio_trigger(
studio: Res<FmodStudio>, studio: Res<FmodStudio>,
mut commands: Commands, mut commands: Commands,
server: Res<AssetServer>, server: Res<AssetServer>,
audio_settings: Res<Assets<AudioSettings>>, tweakfiles: Res<Assets<tweak::Tweakfile>>,
display_state: Res<State<DisplayState>>, display_state: Res<State<DisplayState>>,
) { ) {
let tweak = audio_settings let tweak = tweakfiles
.get(&server.load("audio/martian.audio.tweak")) .get(&server.load("martian.tweak.toml"))
.expect("Load audio tweakfile"); .expect("Load tweakfile");
debug!("Audio tweaks: {:?}", tweak); debug!("Audio tweaks: {:?}", tweak.audio);
let state = display_state.get(); let state = display_state.get();
events.iter().for_each(|event| { events.iter().for_each(|event| {
let aud = match event { let aud = match event {
AudioEvent::MainMusic | AudioEvent::StopMainMusic => tweak.music.main.clone(), AudioEvent::MainMusic | AudioEvent::StopMainMusic => tweak.audio.music.main.clone(),
AudioEvent::MenuSelect => tweak.menu.select.clone(), AudioEvent::MenuSelect => tweak.audio.menu.select.clone(),
AudioEvent::PickUp => match state { AudioEvent::PickUp => match state {
DisplayState::Display2d => tweak.display2d.pick_up.clone(), DisplayState::Display2d => tweak.audio.display2d.pick_up.clone(),
DisplayState::Display3d => tweak.display3d.pick_up.clone(), DisplayState::Display3d => tweak.audio.display3d.pick_up.clone(),
}, },
AudioEvent::PutDown => match state { AudioEvent::PutDown => match state {
DisplayState::Display2d => tweak.display2d.put_down.clone(), DisplayState::Display2d => tweak.audio.display2d.put_down.clone(),
DisplayState::Display3d => tweak.display3d.put_down.clone(), DisplayState::Display3d => tweak.audio.display3d.put_down.clone(),
}, },
AudioEvent::Idle | AudioEvent::StopIdle => match state { AudioEvent::Idle | AudioEvent::StopIdle => match state {
DisplayState::Display2d => tweak.display2d.idle.clone(), DisplayState::Display2d => tweak.audio.display2d.idle.clone(),
DisplayState::Display3d => tweak.display3d.idle.clone(), DisplayState::Display3d => tweak.audio.display3d.idle.clone(),
}, },
AudioEvent::Invalid => match state { AudioEvent::Invalid => match state {
DisplayState::Display2d => tweak.display2d.invalid.clone(), DisplayState::Display2d => tweak.audio.display2d.invalid.clone(),
DisplayState::Display3d => tweak.display3d.invalid.clone(), DisplayState::Display3d => tweak.audio.display3d.invalid.clone(),
}, },
}; };
// There is an event for this // There is an event for this
@ -146,9 +129,9 @@ fn audio_trigger(
}); });
} }
#[derive(Debug, Deserialize, TypeUuid, TypePath)] /// Tweaks made to audio in the Tweakfile
#[uuid = "5c7a67ee-56a9-4fe9-9e91-1a709fbc3cf0"] #[derive(Debug, Deserialize, Default)]
pub(crate) struct AudioSettings { pub(crate) struct AudioTweaks {
#[serde(default)] #[serde(default)]
display2d: PlaySettings, display2d: PlaySettings,
#[serde(default)] #[serde(default)]
@ -181,26 +164,4 @@ struct PlaySettings {
idle: String, idle: String,
#[serde(default)] #[serde(default)]
invalid: String, invalid: String,
} }
#[derive(Default)]
pub struct AudioSettingsLoader;
impl AssetLoader for AudioSettingsLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), bevy::asset::Error>> {
Box::pin(async move {
let s = std::str::from_utf8(bytes)?;
let custom_asset = toml::from_str::<AudioSettings>(s)?;
load_context.set_default_asset(LoadedAsset::new(custom_asset));
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["audio.tweak"]
}
}

@ -1,5 +1,5 @@
use crate::{ use crate::{
game::{Board, BoardIndex, Piece, Side, BoardComponent}, game::{Board, BoardIndex, Piece, Side},
prelude::*, prelude::*,
}; };
use bevy::{ use bevy::{
@ -11,6 +11,7 @@ use bevy::{
}, },
window::PrimaryWindow, window::PrimaryWindow,
}; };
use serde::{Deserialize, Deserializer};
pub(crate) struct Display3dPlugin; pub(crate) struct Display3dPlugin;
@ -82,6 +83,54 @@ impl Plugin for Display3dPlugin {
} }
} }
#[derive(Deserialize, Default)]
struct Display3dTweaks {
#[serde(default)]
fog: FogTweaks,
}
#[derive(Deserialize)]
struct FogTweaks {
#[serde(default)]
color: Color,
#[serde(default)]
light_color: Color,
#[serde(default)]
exponent: f32,
#[serde(default = "default_fog_falloff", deserialize_with = "deserialize_fog_falloff")]
falloff: FogFalloff,
}
fn default_fog_falloff() -> FogFalloff {
FogFalloff::Exponential {
density: 1.0,
}
}
fn deserialize_fog_falloff<'de, D: Deserializer<'de>>(deserializer: D) -> Result<FogFalloff, D::Error> {
if let Ok(s) = String::deserailize(deserializer) {
// Linear [start f32] [end f32]
if s.starts_with("Linear") {
todo!("Parse linear parameters");
Ok(FogFalloff::Linear { ..default() })
// Exponential [density f32]
} else if s.starts_with("Exponential") {
todo!("Parse exponential parameters");
Ok(FogFalloff::Exponential { ..default() })
// ExponentialSquared [density f32]
} else if s.starts_with("ExponentialSquared") {
todo!("Parse exponentialsquared parameters");
Ok(FogFalloff::ExponentialSquared { ..default() })
// Atmospheric (extinction [r: f32] [g: f32] [b: f32]) (inscattering [r: f32] [g: f32] [b: f32])
} else if s.startswith("Atmospheric") {
todo!("Parse atmospheric parameters");
Ok(FogFalloff::Atmospheric { ..default() })
} else {
Err(D::Error)
}
}
}
#[derive(Debug, Component)] #[derive(Debug, Component)]
pub(crate) struct Display3d; pub(crate) struct Display3d;

@ -54,7 +54,7 @@ fn loading(
server: Res<AssetServer>, server: Res<AssetServer>,
sprites: Res<Assets<Image>>, sprites: Res<Assets<Image>>,
gltfs: Res<Assets<Gltf>>, gltfs: Res<Assets<Gltf>>,
tweakfile: Res<Assets<audio::AudioSettings>>, tweakfile: Res<Assets<tweak::Tweakfile>>,
mut next_state: ResMut<NextState<GameState>>, mut next_state: ResMut<NextState<GameState>>,
) { ) {
let s_ids = sprites let s_ids = sprites
@ -67,16 +67,16 @@ fn loading(
.filter(|&id| matches!(id, HandleId::AssetPathId(_))) .filter(|&id| matches!(id, HandleId::AssetPathId(_)))
.collect::<Vec<HandleId>>(); .collect::<Vec<HandleId>>();
let a_ids = tweakfile let t_ids = tweakfile
.ids() .ids()
.filter(|&id| matches!(id, HandleId::AssetPathId(_))) .filter(|&id| matches!(id, HandleId::AssetPathId(_)))
.collect::<Vec<HandleId>>(); .collect::<Vec<HandleId>>();
debug!( debug!(
"Sprite len: {:?} | GLTF len: {:?} | Audio Tweakfile: {:?}", "Sprite len: {:?} | GLTF len: {:?} | Tweakfile: {:?}",
s_ids.len(), s_ids.len(),
g_ids.len(), g_ids.len(),
a_ids.len(), t_ids.len(),
); );
if s_ids.len() > 0 && g_ids.len() > 0 { if s_ids.len() > 0 && g_ids.len() > 0 {
@ -86,10 +86,10 @@ fn loading(
let g_ready = g_ids let g_ready = g_ids
.iter() .iter()
.all(|&id| server.get_load_state(id) == LoadState::Loaded); .all(|&id| server.get_load_state(id) == LoadState::Loaded);
let a_ready = a_ids let t_ready = t_ids
.iter() .iter()
.all(|&id| server.get_load_state(id) == LoadState::Loaded); .all(|&id| server.get_load_state(id) == LoadState::Loaded);
if s_ready && g_ready && a_ready { if s_ready && g_ready && t_ready {
next_state.set(GameState::Menu) next_state.set(GameState::Menu)
} }
} }

@ -11,13 +11,14 @@ mod hit;
mod loading; mod loading;
mod menu; mod menu;
mod prelude; mod prelude;
mod tweak;
mod ui; mod ui;
use std::time::Duration; use std::time::Duration;
use bevy::{ use bevy::{
asset::{ChangeWatcher, HandleId}, asset::{ChangeWatcher, HandleId},
input::ButtonState, input::ButtonState, pbr::FogPlugin, core_pipeline::fxaa::FxaaPlugin,
}; };
use crate::prelude::*; use crate::prelude::*;
@ -70,6 +71,7 @@ fn main() {
app.add_plugins(menu::MenuPlugin); app.add_plugins(menu::MenuPlugin);
app.add_plugins(audio::AudioPlugin); app.add_plugins(audio::AudioPlugin);
app.add_plugins(ui::UiPlugin); app.add_plugins(ui::UiPlugin);
app.add_plugins(tweak::TweakPlugin);
app.run(); app.run();
} }

@ -0,0 +1,60 @@
use crate::prelude::*;
use bevy::{
asset::{AssetLoader, LoadContext, LoadedAsset},
reflect::{TypePath, TypeUuid},
utils::BoxedFuture,
};
use serde::Deserialize;
/// A Tweakfile is resource used to specify game customization like asset names,
/// and non-user customizations made to the game during development.
pub(crate) struct TweakPlugin;
impl Plugin for TweakPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(GameState::Loading), load_tweakfile);
app.add_asset::<Tweakfile>()
.init_asset_loader::<TweakfileLoader>();
}
}
fn load_tweakfile(server: Res<AssetServer>, mut commands: Commands) {
let handle: Handle<Tweakfile> = server.load("martian.tweak.toml");
commands.insert_resource(GameTweakfile(handle));
}
#[derive(Debug, Resource)]
struct GameTweakfile(Handle<Tweakfile>);
/// Tweakfile contains tweaks made to other parts of the game
#[derive(Debug, Deserialize, TypeUuid, TypePath)]
#[uuid = "e5768efe-edce-4267-bdf4-dd8f8ca613c7"]
pub(crate) struct Tweakfile {
#[serde(default)]
pub audio: audio::AudioTweaks,
}
#[derive(Default)]
pub struct TweakfileLoader;
impl AssetLoader for TweakfileLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), bevy::asset::Error>> {
Box::pin(async move {
let s = std::str::from_utf8(bytes)?;
let custom_asset = toml::from_str::<Tweakfile>(s)?;
load_context.set_default_asset(LoadedAsset::new(custom_asset));
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["tweak.toml"]
}
}
Loading…
Cancel
Save