Remove an unwrap and move outcome sfx to ron

This commit is contained in:
James Melkonian 2021-04-27 21:01:06 +00:00 committed by Marcel
parent ffd3ef3f14
commit 2f00af83d8
4 changed files with 166 additions and 112 deletions

View File

@ -710,17 +710,87 @@
], ],
threshold: 0.3, threshold: 0.3,
), ),
//Explosion: ( Explosion: (
// files: [ files: [
// // in code "voxygen.audio.sfx.abilities.explosion",
// ], ],
// threshold: 0.2, threshold: 0.2,
//), ),
//ProjectileShot: ( ArrowShot: (
// files: [ files: [
// // in code "voxygen.audio.sfx.abilities.arrow_shot_1",
// ], "voxygen.audio.sfx.abilities.arrow_shot_2",
// threshold: 0.5, "voxygen.audio.sfx.abilities.arrow_shot_3",
//), "voxygen.audio.sfx.abilities.arrow_shot_4",
],
threshold: 0.2,
),
FireShot: (
files: [
"voxygen.audio.sfx.abilities.fire_shot_1",
"voxygen.audio.sfx.abilities.fire_shot_2",
],
threshold: 0.2,
),
ArrowMiss: (
files: [
"voxygen.audio.sfx.character.arrow_miss",
],
threshold: 0.2,
),
ArrowHit: (
files: [
"voxygen.audio.sfx.character.arrow_hit",
],
threshold: 0.2,
),
SkillPointGain: (
files: [
"voxygen.audio.sfx.character.level_up_sound_-_shorter_wind_up",
],
threshold: 0.2,
),
HealingBeam: (
files: [
"voxygen.audio.sfx.abilities.sceptre_channeling",
],
threshold: 0.2,
),
FlameThrower: (
files: [
"voxygen.audio.sfx.abilities.flame_thrower",
],
threshold: 0.2,
),
BreakBlock: (
files: [
"voxygen.audio.sfx.footsteps.stone_step_1",
],
threshold: 0.2,
),
Damage: (
files: [
"voxygen.audio.sfx.character.hit_1",
"voxygen.audio.sfx.character.hit_2",
"voxygen.audio.sfx.character.hit_3",
"voxygen.audio.sfx.character.hit_4",
],
threshold: 0.2,
),
Block: (
files: [
"voxygen.audio.sfx.character.block_1",
"voxygen.audio.sfx.character.block_2",
"voxygen.audio.sfx.character.block_3",
],
threshold: 0.2,
),
Parry: (
files: [
"voxygen.audio.sfx.character.parry_1",
"voxygen.audio.sfx.character.parry_2",
],
threshold: 0.2,
),
} }
) )

View File

@ -13,7 +13,7 @@ use music::MusicTransitionManifest;
use sfx::{SfxEvent, SfxTriggerItem}; use sfx::{SfxEvent, SfxTriggerItem};
use soundcache::OggSound; use soundcache::OggSound;
use std::time::Duration; use std::time::Duration;
use tracing::{debug, error}; use tracing::{debug, error, warn};
use common::assets::{AssetExt, AssetHandle}; use common::assets::{AssetExt, AssetHandle};
use rodio::{source::Source, OutputStream, OutputStreamHandle, StreamError}; use rodio::{source::Source, OutputStream, OutputStreamHandle, StreamError};
@ -206,7 +206,11 @@ impl AudioFrontend {
}, },
}; };
self.play_sfx(sfx_file, self.listener.pos, None); // TODO: Should this take `underwater` into consideration?
match self.play_sfx(sfx_file, self.listener.pos, None, false) {
Ok(_) => {},
Err(e) => warn!("Failed to play sfx. {}", e),
}
} else { } else {
debug!("Missing sfx trigger config for external sfx event.",); debug!("Missing sfx trigger config for external sfx event.",);
} }
@ -238,10 +242,9 @@ impl AudioFrontend {
}, },
}; };
if underwater { match self.play_sfx(sfx_file, position, volume, underwater) {
self.play_underwater_sfx(sfx_file, position, volume); Ok(_) => {},
} else { Err(e) => warn!("Failed to play sfx. {}", e),
self.play_sfx(sfx_file, position, volume);
} }
} else { } else {
debug!( debug!(
@ -251,40 +254,33 @@ impl AudioFrontend {
} }
} }
/// Play (once) an sfx file by file path at the give position and volume /// Play (once) an sfx file by file path at the given position and volume.
pub fn play_sfx(&mut self, sound: &str, pos: Vec3<f32>, vol: Option<f32>) { /// If `underwater` is true, the sound is played with a low pass filter
pub fn play_sfx(
&mut self,
sound: &str,
pos: Vec3<f32>,
vol: Option<f32>,
underwater: bool,
) -> Result<(), rodio::decoder::DecoderError> {
if self.audio_stream.is_some() { if self.audio_stream.is_some() {
let sound = OggSound::load_expect(sound) let sound = OggSound::load_expect(sound)
.cloned() .cloned()
.decoder() .decoder()?
.amplify(vol.unwrap_or(1.0)); .amplify(vol.unwrap_or(1.0));
let listener = self.listener.clone(); let listener = self.listener.clone();
if let Some(channel) = self.get_sfx_channel() { if let Some(channel) = self.get_sfx_channel() {
channel.set_pos(pos); channel.set_pos(pos);
channel.update(&listener); channel.update(&listener);
if underwater {
channel.play_with_low_pass_filter(sound.convert_samples());
} else {
channel.play(sound); channel.play(sound);
} }
} }
} }
Ok(())
/// Play (once) an sfx file by file path at the give position and volume
/// but with the sound passed through a low pass filter to simulate
/// being underwater
pub fn play_underwater_sfx(&mut self, sound: &str, pos: Vec3<f32>, vol: Option<f32>) {
if self.audio_stream.is_some() {
let sound = OggSound::load_expect(sound)
.cloned()
.decoder()
.amplify(vol.unwrap_or(1.0));
let listener = self.listener.clone();
if let Some(channel) = self.get_sfx_channel() {
channel.set_pos(pos);
channel.update(&listener);
channel.play_with_low_pass_filter(sound.convert_samples());
}
}
} }
fn play_ambient( fn play_ambient(
@ -295,11 +291,12 @@ impl AudioFrontend {
) { ) {
if self.audio_stream.is_some() { if self.audio_stream.is_some() {
if let Some(channel) = self.get_ambient_channel(channel_tag, volume_multiplier) { if let Some(channel) = self.get_ambient_channel(channel_tag, volume_multiplier) {
let sound = OggSound::load_expect(sound).cloned().decoder(); if let Ok(sound) = OggSound::load_expect(sound).cloned().decoder() {
channel.play(sound); channel.play(sound);
} }
} }
} }
}
fn get_ambient_channel( fn get_ambient_channel(
&mut self, &mut self,
@ -352,11 +349,12 @@ impl AudioFrontend {
fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) { fn play_music(&mut self, sound: &str, channel_tag: MusicChannelTag) {
if self.music_enabled() { if self.music_enabled() {
if let Some(channel) = self.get_music_channel(channel_tag) { if let Some(channel) = self.get_music_channel(channel_tag) {
let sound = OggSound::load_expect(sound).cloned().decoder(); if let Ok(sound) = OggSound::load_expect(sound).cloned().decoder() {
channel.play(sound, channel_tag); channel.play(sound, channel_tag);
} }
} }
} }
}
/* These functions are saved for if we want music playback control at some /* These functions are saved for if we want music playback control at some
* point. They are not used currently but may be useful for later work. * point. They are not used currently but may be useful for later work.

View File

@ -92,7 +92,7 @@ use common::{
assets::{self, AssetExt, AssetHandle}, assets::{self, AssetExt, AssetHandle},
comp::{ comp::{
beam, beam,
item::{ItemKind, Reagent, ToolKind}, item::{ItemKind, ToolKind},
object, Body, CharacterAbilityType, InventoryUpdateEvent, object, Body, CharacterAbilityType, InventoryUpdateEvent,
}, },
outcome::Outcome, outcome::Outcome,
@ -167,8 +167,17 @@ pub enum SfxEvent {
Unwield(ToolKind), Unwield(ToolKind),
Inventory(SfxInventoryEvent), Inventory(SfxInventoryEvent),
Explosion, Explosion,
ProjectileShot,
Damage, Damage,
Parry,
Block,
BreakBlock,
HealingBeam,
SkillPointGain,
ArrowHit,
ArrowMiss,
ArrowShot,
FireShot,
FlameThrower,
// Poise(StunState), // Poise(StunState),
} }
@ -301,30 +310,20 @@ impl SfxMgr {
if !audio.sfx_enabled() { if !audio.sfx_enabled() {
return; return;
} }
let triggers = self.triggers.read();
// TODO handle underwater
match outcome { match outcome {
Outcome::Explosion { Outcome::Explosion { pos, power, .. } => {
pos, let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Explosion);
power, audio.emit_sfx(
is_attack, sfx_trigger_item,
reagent,
..
} => {
let file_ref = if *is_attack && matches!(reagent, Some(Reagent::Green)) {
"voxygen.audio.sfx.abilities.heal_bomb"
} else {
"voxygen.audio.sfx.abilities.explosion"
};
audio.play_sfx(
// TODO: from sfx config?
file_ref,
*pos, *pos,
Some((power.abs() / 2.5).min(1.5)), Some((power.abs() / 2.5).min(1.5)),
false,
); );
}, },
Outcome::ProjectileShot { pos, body, .. } => { Outcome::ProjectileShot { pos, body, .. } => {
// TODO: from sfx config?
match body { match body {
Body::Object( Body::Object(
object::Body::Arrow object::Body::Arrow
@ -332,26 +331,16 @@ impl SfxMgr {
| object::Body::ArrowSnake | object::Body::ArrowSnake
| object::Body::ArrowTurret, | object::Body::ArrowTurret,
) => { ) => {
let file_ref = vec![ let sfx_trigger_item = triggers.get_key_value(&SfxEvent::ArrowShot);
"voxygen.audio.sfx.abilities.arrow_shot_1", audio.emit_sfx(sfx_trigger_item, *pos, None, false);
"voxygen.audio.sfx.abilities.arrow_shot_2",
"voxygen.audio.sfx.abilities.arrow_shot_3",
"voxygen.audio.sfx.abilities.arrow_shot_4",
][rand::thread_rng().gen_range(1..4)];
audio.play_sfx(file_ref, *pos, None);
}, },
Body::Object( Body::Object(
object::Body::BoltFire object::Body::BoltFire
| object::Body::BoltFireBig | object::Body::BoltFireBig
| object::Body::BoltNature, | object::Body::BoltNature,
) => { ) => {
let file_ref = vec![ let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FireShot);
"voxygen.audio.sfx.abilities.fire_shot_1", audio.emit_sfx(sfx_trigger_item, *pos, None, false);
"voxygen.audio.sfx.abilities.fire_shot_2",
][rand::thread_rng().gen_range(1..2)];
audio.play_sfx(file_ref, *pos, None);
}, },
_ => { _ => {
// not mapped to sfx file // not mapped to sfx file
@ -372,66 +361,61 @@ impl SfxMgr {
| object::Body::ArrowTurret, | object::Body::ArrowTurret,
) => { ) => {
if target.is_none() { if target.is_none() {
audio.play_sfx("voxygen.audio.sfx.character.arrow_miss", *pos, Some(2.0)); let sfx_trigger_item = triggers.get_key_value(&SfxEvent::ArrowMiss);
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), false);
} else if *source == client.uid() { } else if *source == client.uid() {
audio.play_sfx( let sfx_trigger_item = triggers.get_key_value(&SfxEvent::ArrowHit);
"voxygen.audio.sfx.character.arrow_hit", audio.emit_sfx(
sfx_trigger_item,
client.position().unwrap_or(*pos), client.position().unwrap_or(*pos),
Some(2.0), Some(2.0),
false,
); );
} else { } else {
audio.play_sfx("voxygen.audio.sfx.character.arrow_hit", *pos, Some(2.0)); let sfx_trigger_item = triggers.get_key_value(&SfxEvent::ArrowHit);
audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), false);
} }
}, },
_ => {}, _ => {},
}, },
Outcome::SkillPointGain { pos, .. } => { Outcome::SkillPointGain { pos, .. } => {
let file_ref = "voxygen.audio.sfx.character.level_up_sound_-_shorter_wind_up"; let sfx_trigger_item = triggers.get_key_value(&SfxEvent::SkillPointGain);
audio.play_sfx(file_ref, *pos, None); audio.emit_sfx(sfx_trigger_item, *pos, None, false);
}, },
Outcome::Beam { pos, specifier } => match specifier { Outcome::Beam { pos, specifier } => match specifier {
beam::FrontendSpecifier::LifestealBeam | beam::FrontendSpecifier::HealingBeam => { beam::FrontendSpecifier::LifestealBeam | beam::FrontendSpecifier::HealingBeam => {
let file_ref = "voxygen.audio.sfx.abilities.sceptre_channeling";
if thread_rng().gen_bool(0.5) { if thread_rng().gen_bool(0.5) {
audio.play_sfx(file_ref, *pos, None); let sfx_trigger_item = triggers.get_key_value(&SfxEvent::HealingBeam);
audio.emit_sfx(sfx_trigger_item, *pos, None, false);
}; };
}, },
beam::FrontendSpecifier::Flamethrower | beam::FrontendSpecifier::Cultist => { beam::FrontendSpecifier::Flamethrower | beam::FrontendSpecifier::Cultist => {
let file_ref = "voxygen.audio.sfx.abilities.flame_thrower";
if thread_rng().gen_bool(0.5) { if thread_rng().gen_bool(0.5) {
audio.play_sfx(file_ref, *pos, None); let sfx_trigger_item = triggers.get_key_value(&SfxEvent::FlameThrower);
audio.emit_sfx(sfx_trigger_item, *pos, None, false);
} }
}, },
}, },
Outcome::BreakBlock { pos, .. } => { Outcome::BreakBlock { pos, .. } => {
let file_ref = "voxygen.audio.sfx.footsteps.stone_step_1"; let sfx_trigger_item = triggers.get_key_value(&SfxEvent::BreakBlock);
audio.play_sfx(file_ref, pos.map(|e| e as f32 + 0.5), Some(3.0)); audio.emit_sfx(
sfx_trigger_item,
pos.map(|e| e as f32 + 0.5),
Some(3.0),
false,
);
}, },
Outcome::Damage { pos, .. } => { Outcome::Damage { pos, .. } => {
let file_ref = vec![ let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Damage);
"voxygen.audio.sfx.character.hit_1", audio.emit_sfx(sfx_trigger_item, *pos, None, false);
"voxygen.audio.sfx.character.hit_2",
"voxygen.audio.sfx.character.hit_3",
"voxygen.audio.sfx.character.hit_4",
][rand::thread_rng().gen_range(1..4)];
audio.play_sfx(file_ref, *pos, None);
}, },
Outcome::Block { pos, parry, .. } => { Outcome::Block { pos, parry, .. } => {
let block_sfx = vec![
"voxygen.audio.sfx.character.block_1",
"voxygen.audio.sfx.character.block_2",
"voxygen.audio.sfx.character.block_3",
];
let parry_sfx = vec![
"voxygen.audio.sfx.character.parry_1",
"voxygen.audio.sfx.character.parry_2",
];
if *parry { if *parry {
let file_ref = parry_sfx[rand::thread_rng().gen_range(1..parry_sfx.len())]; let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Parry);
audio.play_sfx(file_ref, *pos, Some(2.0)); audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), false);
} else { } else {
let file_ref = block_sfx[rand::thread_rng().gen_range(1..block_sfx.len())]; let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Block);
audio.play_sfx(file_ref, *pos, Some(2.0)); audio.emit_sfx(sfx_trigger_item, *pos, Some(2.0), false);
} }
}, },
Outcome::ExpChange { .. } Outcome::ExpChange { .. }

View File

@ -37,9 +37,11 @@ impl assets::Asset for OggSound {
/// Wrapper for decoded audio data /// Wrapper for decoded audio data
impl OggSound { impl OggSound {
pub fn decoder(self) -> rodio::Decoder<io::Cursor<OggSound>> { pub fn decoder(
self,
) -> Result<rodio::Decoder<io::Cursor<OggSound>>, rodio::decoder::DecoderError> {
let cursor = io::Cursor::new(self); let cursor = io::Cursor::new(self);
rodio::Decoder::new(cursor).unwrap() rodio::Decoder::new(cursor)
} }
pub fn empty() -> OggSound { pub fn empty() -> OggSound {