Fully move sfx away from ECS event bus

This commit is contained in:
jiminycrick 2020-11-16 15:32:23 -08:00
parent b3aa454f8e
commit 3b47add55a
16 changed files with 207 additions and 252 deletions

View File

@ -181,24 +181,24 @@
],
threshold: 0.5,
),
//Attack(ComboMelee(Swing, 1), Sword): (
// files: [
// "voxygen.audio.sfx.abilities.swing_sword",
// ],
// threshold: 0.7,
//),
//Attack(ComboMelee(Swing, 2), Sword): (
// files: [
// "voxygen.audio.sfx.abilities.separated_second_swing",
// ],
// threshold: 0.7,
//),
//Attack(ComboMelee(Swing, 3), Sword): (
// files: [
// "voxygen.audio.sfx.abilities.separated_third_swing",
// ],
// threshold: 0.7,
//),
Attack(ComboMelee(Swing, 1), Sword): (
files: [
"voxygen.audio.sfx.abilities.swing_sword",
],
threshold: 0.7,
),
Attack(ComboMelee(Swing, 2), Sword): (
files: [
"voxygen.audio.sfx.abilities.separated_second_swing",
],
threshold: 0.7,
),
Attack(ComboMelee(Swing, 3), Sword): (
files: [
"voxygen.audio.sfx.abilities.separated_third_swing",
],
threshold: 0.7,
),
Attack(DashMelee(Swing), Sword): (
files: [
"voxygen.audio.sfx.abilities.sword_dash",
@ -319,12 +319,12 @@
],
threshold: 0.5,
),
//Attack(BasicBeam, Staff): (
// files: [
// "voxygen.audio.sfx.abilities.flame_thrower",
// ],
// threshold: 0.2,
//),
Attack(BasicBeam, Staff): (
files: [
"voxygen.audio.sfx.abilities.flame_thrower",
],
threshold: 0.2,
),
Attack(BasicRanged, Staff): (
files: [
// "voxygen.audio.sfx.abilities.staff_channeling",
@ -353,12 +353,12 @@
],
threshold: 0.5,
),
Attack(BasicRanged, Bow): (
files: [
// channeling sound.
],
threshold: 0.8,
),
//Attack(BasicRanged, Bow): (
// files: [
// // channeling sound.
// ],
// threshold: 0.8,
//),
Inventory(CollectedTool(Bow)): (
files: [
"voxygen.audio.sfx.inventory.add_item",
@ -381,12 +381,6 @@
],
threshold: 0.5,
),
//Attack(BasicBeam, Sceptre): (
// files: [
// "voxygen.audio.sfx.abilities.staff_channeling",
// ],
// threshold: 0.6,
//),
//
// Dagger

View File

@ -858,15 +858,11 @@ impl Client {
self.state.terrain().get_key_arc(chunk_pos).cloned()
}
pub fn current<C: Component>(&self) -> Option<C> where
C: Clone,
{
Some(
self.state
.read_storage::<C>()
.get(self.entity)
.cloned()?,
)
pub fn current<C: Component>(&self) -> Option<C>
where
C: Clone,
{
Some(self.state.read_storage::<C>().get(self.entity).cloned()?)
}
pub fn current_biome(&self) -> BiomeKind {

View File

@ -9,8 +9,6 @@ use std::{collections::VecDeque, ops::DerefMut};
use vek::*;
pub enum LocalEvent {
/// An attack for use with particles and sfx
Attack(EcsEntity),
/// Applies upward force to entity's `Vel`
Jump(EcsEntity),
/// Applies the `impulse` to `entity`'s `Vel`

View File

@ -1,5 +1,5 @@
use crate::comp;
use comp::{item::Reagent, CharacterState, Loadout};
use comp::item::Reagent;
use serde::{Deserialize, Serialize};
use vek::*;
@ -22,11 +22,6 @@ pub enum Outcome {
body: comp::Body,
vel: Vec3<f32>,
},
Attack {
pos: Vec3<f32>,
character_state: CharacterState,
loadout: Loadout,
},
LevelUp {
pos: Vec3<f32>,
},
@ -41,7 +36,6 @@ impl Outcome {
match self {
Outcome::Explosion { pos, .. } => Some(*pos),
Outcome::ProjectileShot { pos, .. } => Some(*pos),
Outcome::Attack { pos, .. } => Some(*pos),
Outcome::LevelUp { pos } => Some(*pos),
Outcome::Beam { pos, .. } => Some(*pos),
}

View File

@ -2,7 +2,6 @@ use crate::{
comp,
event::{EventBus, LocalEvent, ServerEvent},
metrics::{PhysicsMetrics, SysMetrics},
outcome::Outcome,
region::RegionMap,
sync::WorldSyncExt,
sys,
@ -188,9 +187,6 @@ impl State {
ecs.insert(SysMetrics::default());
ecs.insert(PhysicsMetrics::default());
// Register outcomes
ecs.insert(Vec::<Outcome>::new());
ecs
}
@ -392,28 +388,7 @@ impl State {
for event in events {
let mut velocities = self.ecs.write_storage::<comp::Vel>();
let mut controllers = self.ecs.write_storage::<comp::Controller>();
let positions = self.ecs.read_storage::<comp::Pos>();
let character_states = self.ecs.read_storage::<comp::CharacterState>();
let loadouts = self.ecs.read_storage::<comp::Loadout>();
match event {
LocalEvent::Attack(entity) => {
self.ecs
.write_resource::<Vec<Outcome>>()
.push(Outcome::Attack {
pos: positions
.get(entity)
.expect("Failed to fetch attacking entity")
.0,
character_state: character_states
.get(entity)
.expect("Failed to get the character state of the attacking entity")
.clone(),
loadout: loadouts
.get(entity)
.expect("Failed to get attacking entity's loadout")
.clone(),
});
},
LocalEvent::Jump(entity) => {
if let Some(vel) = velocities.get_mut(entity) {
vel.0.z = HUMANOID_JUMP_ACCEL;

View File

@ -56,7 +56,7 @@ impl<'a> System<'a> for Sys {
let start_time = std::time::Instant::now();
span!(_guard, "run", "melee::Sys::run");
let mut server_emitter = server_bus.emitter();
let mut local_emitter = local_bus.emitter();
let _local_emitter = local_bus.emitter();
// Attacks
for (entity, uid, pos, ori, scale_maybe, attack) in (
&entities,
@ -72,7 +72,6 @@ impl<'a> System<'a> for Sys {
continue;
}
attack.applied = true;
local_emitter.emit(LocalEvent::Attack(entity));
// Go through all other entities
for (b, pos_b, scale_b_maybe, health_b, body_b, char_state_b_maybe) in (

View File

@ -9,9 +9,10 @@ pub mod soundcache;
use channel::{AmbientChannel, AmbientChannelTag, MusicChannel, MusicChannelTag, SfxChannel};
use fader::Fader;
use sfx::{SfxEvent, SfxTriggerItem};
use soundcache::SoundCache;
use std::time::Duration;
//use tracing::warn;
use tracing::debug;
use common::assets;
use rodio::{source::Source, Decoder, OutputStream, OutputStreamHandle, StreamError};
@ -162,6 +163,71 @@ impl AudioFrontend {
self.music_channels.last_mut()
}
/// Function to play sfx from external places. Useful for UI and
/// inventory events
pub fn emit_sfx_item(&mut self, trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>) {
if let Some((event, item)) = trigger_item {
let sfx_file = match item.files.len() {
0 => {
debug!("Sfx event {:?} is missing audio file.", event);
"voxygen.audio.sfx.placeholder"
},
1 => item
.files
.last()
.expect("Failed to determine sound file for this trigger item."),
_ => {
// If more than one file is listed, choose one at random
let rand_step = rand::random::<usize>() % item.files.len();
&item.files[rand_step]
},
};
self.play_sfx(sfx_file, self.listener.pos, None);
} else {
debug!("Missing sfx trigger config for external sfx event.",);
}
}
/// Play an sfx file given the position, SfxEvent, and whether it is
/// underwater or not
pub fn emit_sfx(
&mut self,
trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
position: Vec3<f32>,
volume: Option<f32>,
underwater: bool,
) {
if let Some((event, item)) = trigger_item {
let sfx_file = match item.files.len() {
0 => {
debug!("Sfx event {:?} is missing audio file.", event);
"voxygen.audio.sfx.placeholder"
},
1 => item
.files
.last()
.expect("Failed to determine sound file for this trigger item."),
_ => {
// If more than one file is listed, choose one at random
let rand_step = rand::random::<usize>() % item.files.len();
&item.files[rand_step]
},
};
if underwater {
self.play_underwater_sfx(sfx_file, position, volume);
} else {
self.play_sfx(sfx_file, position, volume);
}
} else {
debug!(
"Missing sfx trigger config for sfx event at position: {:?}",
position
);
}
}
/// Play (once) an sfx file by file path at the give position and volume
pub fn play_sfx(&mut self, sound: &str, pos: Vec3<f32>, vol: Option<f32>) {
if self.audio_stream.is_some() {

View File

@ -1,19 +1,22 @@
/// EventMapper::Block watches the sound emitting blocks within
/// chunk range of the player and emits ambient sfx
use crate::{
audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
scene::{terrain::BlocksOfInterest, Camera, Terrain},
AudioFrontend,
};
use super::EventMapper;
use client::Client;
use common::{
comp::Pos, event::EventBus, spiral::Spiral2d, state::State, terrain::TerrainChunk,
vol::RectRasterableVol,
comp::Pos,
spiral::Spiral2d,
state::State,
terrain::{BlockKind, TerrainChunk},
vol::{ReadVol, RectRasterableVol},
};
use hashbrown::HashMap;
use rand::{thread_rng, Rng};
use specs::WorldExt;
use std::time::Instant;
use vek::*;
@ -39,6 +42,7 @@ pub struct BlockEventMapper {
impl EventMapper for BlockEventMapper {
fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
camera: &Camera,
@ -46,11 +50,6 @@ impl EventMapper for BlockEventMapper {
terrain: &Terrain<TerrainChunk>,
client: &Client,
) {
let ecs = state.ecs();
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
let mut sfx_emitter = sfx_event_bus.emitter();
let focus_off = camera.get_focus_pos().map(f32::trunc);
let cam_pos = camera.dependents().cam_pos + focus_off;
@ -175,21 +174,29 @@ impl EventMapper for BlockEventMapper {
continue;
}
let block_pos: Vec3<i32> = absolute_pos + block;
let state = self.history.entry(block_pos).or_default();
let internal_state = self.history.entry(block_pos).or_default();
let block_pos = block_pos.map(|x| x as f32);
if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) {
if Self::should_emit(internal_state, triggers.get_key_value(&sounds.sfx)) {
// If the camera is within SFX distance
if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR {
sfx_emitter.emit(SfxEventItem::new(
sounds.sfx.clone(),
Some(block_pos),
let underwater = state
.terrain()
.get(cam_pos.map(|e| e.floor() as i32))
.map(|b| b.kind() == BlockKind::Water)
.unwrap_or(false);
let sfx_trigger_item = triggers.get_key_value(&sounds.sfx);
audio.emit_sfx(
sfx_trigger_item,
block_pos,
Some(sounds.volume),
));
underwater,
);
}
state.time = Instant::now();
state.event = sounds.sfx.clone();
internal_state.time = Instant::now();
internal_state.event = sounds.sfx.clone();
}
}
});

View File

@ -1,7 +1,8 @@
/// EventMapper::Campfire maps sfx to campfires
use crate::{
audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
scene::{Camera, Terrain},
AudioFrontend,
};
use super::EventMapper;
@ -9,9 +10,9 @@ use super::EventMapper;
use client::Client;
use common::{
comp::{object, Body, Pos},
event::EventBus,
state::State,
terrain::TerrainChunk,
terrain::{BlockKind, TerrainChunk},
vol::ReadVol,
};
use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join, WorldExt};
@ -39,6 +40,7 @@ pub struct CampfireEventMapper {
impl EventMapper for CampfireEventMapper {
fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
camera: &Camera,
@ -47,10 +49,6 @@ impl EventMapper for CampfireEventMapper {
_client: &Client,
) {
let ecs = state.ecs();
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
let mut sfx_emitter = sfx_event_bus.emitter();
let focus_off = camera.get_focus_pos().map(f32::trunc);
let cam_pos = camera.dependents().cam_pos + focus_off;
for (entity, body, pos) in (
@ -62,24 +60,25 @@ impl EventMapper for CampfireEventMapper {
.filter(|(_, _, e_pos)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR)
{
if let Body::Object(object::Body::CampfireLit) = body {
let state = self.event_history.entry(entity).or_default();
let internal_state = self.event_history.entry(entity).or_default();
let mapped_event = SfxEvent::Campfire;
// Check for SFX config entry for this movement
if Self::should_emit(state, triggers.get_key_value(&mapped_event)) {
sfx_emitter.emit(SfxEventItem::new(
mapped_event.clone(),
Some(pos.0),
Some(0.25),
));
state.time = Instant::now();
if Self::should_emit(internal_state, triggers.get_key_value(&mapped_event)) {
let underwater = state
.terrain()
.get(cam_pos.map(|e| e.floor() as i32))
.map(|b| b.kind() == BlockKind::Water)
.unwrap_or(false);
let sfx_trigger_item = triggers.get_key_value(&mapped_event);
audio.emit_sfx(sfx_trigger_item, pos.0, None, underwater);
internal_state.time = Instant::now();
}
// update state to determine the next event. We only record the time (above) if
// it was dispatched
state.event = mapped_event;
internal_state.event = mapped_event;
}
}
self.cleanup(player_entity);

View File

@ -1,8 +1,9 @@
/// EventMapper::Combat watches the combat states of surrounding entities' and
/// emits sfx related to weapons and attacks/abilities
use crate::{
audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
scene::{Camera, Terrain},
AudioFrontend,
};
use super::EventMapper;
@ -10,9 +11,9 @@ use super::EventMapper;
use client::Client;
use common::{
comp::{item::ItemKind, CharacterAbilityType, CharacterState, Loadout, Pos},
event::EventBus,
state::State,
terrain::TerrainChunk,
terrain::{BlockKind, TerrainChunk},
vol::ReadVol,
};
use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join, WorldExt};
@ -42,6 +43,7 @@ pub struct CombatEventMapper {
impl EventMapper for CombatEventMapper {
fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
camera: &Camera,
@ -51,9 +53,6 @@ impl EventMapper for CombatEventMapper {
) {
let ecs = state.ecs();
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
let mut sfx_emitter = sfx_event_bus.emitter();
let focus_off = camera.get_focus_pos().map(f32::trunc);
let cam_pos = camera.dependents().cam_pos + focus_off;
@ -67,21 +66,27 @@ impl EventMapper for CombatEventMapper {
.filter(|(_, e_pos, ..)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR)
{
if let Some(character) = character {
let state = self.event_history.entry(entity).or_default();
let sfx_state = self.event_history.entry(entity).or_default();
let mapped_event = Self::map_event(character, state, loadout);
let mapped_event = Self::map_event(character, sfx_state, loadout);
// Check for SFX config entry for this movement
if Self::should_emit(state, triggers.get_key_value(&mapped_event)) {
sfx_emitter.emit(SfxEventItem::new(mapped_event.clone(), Some(pos.0), None));
if Self::should_emit(sfx_state, triggers.get_key_value(&mapped_event)) {
let underwater = state
.terrain()
.get(cam_pos.map(|e| e.floor() as i32))
.map(|b| b.kind() == BlockKind::Water)
.unwrap_or(false);
state.time = Instant::now();
let sfx_trigger_item = triggers.get_key_value(&mapped_event);
audio.emit_sfx(sfx_trigger_item, pos.0, None, underwater);
sfx_state.time = Instant::now();
}
// update state to determine the next event. We only record the time (above) if
// it was dispatched
state.event = mapped_event;
state.weapon_drawn = Self::weapon_drawn(character);
sfx_state.event = mapped_event;
sfx_state.weapon_drawn = Self::weapon_drawn(character);
}
}

View File

@ -12,11 +12,15 @@ use combat::CombatEventMapper;
use movement::MovementEventMapper;
use super::SfxTriggers;
use crate::scene::{Camera, Terrain};
use crate::{
scene::{Camera, Terrain},
AudioFrontend,
};
trait EventMapper {
fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
camera: &Camera,
@ -44,6 +48,7 @@ impl SfxEventMapper {
pub fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
camera: &Camera,
@ -52,7 +57,15 @@ impl SfxEventMapper {
client: &Client,
) {
for mapper in &mut self.mappers {
mapper.maintain(state, player_entity, camera, triggers, terrain, client);
mapper.maintain(
audio,
state,
player_entity,
camera,
triggers,
terrain,
client,
);
}
}
}

View File

@ -3,15 +3,16 @@
/// proportionate to the extity's size
use super::EventMapper;
use crate::{
audio::sfx::{SfxEvent, SfxEventItem, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
audio::sfx::{SfxEvent, SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR},
scene::{Camera, Terrain},
AudioFrontend,
};
use client::Client;
use common::{
comp::{Body, CharacterState, PhysicsState, Pos, Vel},
event::EventBus,
state::State,
terrain::{BlockKind, TerrainChunk},
vol::ReadVol,
};
use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join, WorldExt};
@ -44,6 +45,7 @@ pub struct MovementEventMapper {
impl EventMapper for MovementEventMapper {
fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
camera: &Camera,
@ -53,9 +55,6 @@ impl EventMapper for MovementEventMapper {
) {
let ecs = state.ecs();
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
let mut sfx_emitter = sfx_event_bus.emitter();
let focus_off = camera.get_focus_pos().map(f32::trunc);
let cam_pos = camera.dependents().cam_pos + focus_off;
@ -99,12 +98,19 @@ impl EventMapper for MovementEventMapper {
// Check for SFX config entry for this movement
if Self::should_emit(internal_state, triggers.get_key_value(&mapped_event)) {
sfx_emitter.emit(SfxEventItem::new(
mapped_event.clone(),
Some(pos.0),
Some(Self::get_volume_for_body_type(body)),
));
let underwater = state
.terrain()
.get(cam_pos.map(|e| e.floor() as i32))
.map(|b| b.kind() == BlockKind::Water)
.unwrap_or(false);
let sfx_trigger_item = triggers.get_key_value(&mapped_event);
audio.emit_sfx(
sfx_trigger_item,
pos.0,
Some(Self::get_volume_for_body_type(body)),
underwater,
);
internal_state.time = Instant::now();
}

View File

@ -94,19 +94,15 @@ use common::{
item::{ItemKind, ToolKind},
object, Body, CharacterAbilityType, InventoryUpdateEvent,
},
event::EventBus,
outcome::Outcome,
state::State,
states::utils::StageSection,
terrain::{BlockKind, TerrainChunk},
vol::ReadVol,
terrain::TerrainChunk,
};
use event_mapper::SfxEventMapper;
use hashbrown::HashMap;
use rand::prelude::*;
use serde::Deserialize;
use specs::WorldExt;
use tracing::{debug, warn};
use tracing::warn;
use vek::*;
/// We watch the states of nearby entities in order to emit SFX at their
@ -241,7 +237,7 @@ impl SfxTriggers {
}
pub struct SfxMgr {
triggers: SfxTriggers,
pub triggers: SfxTriggers,
event_mapper: SfxEventMapper,
}
@ -269,25 +265,16 @@ impl SfxMgr {
if !audio.sfx_enabled() {
return;
}
let ecs = state.ecs();
// This checks to see if the camera is underwater. If it is,
// we pass all sfx through a low pass filter
let focus_off = camera.get_focus_pos().map(f32::trunc);
let underwater = state
.terrain()
.get((camera.dependents().cam_pos + focus_off).map(|e| e.floor() as i32))
.map(|b| b.kind())
.unwrap_or(BlockKind::Air)
== BlockKind::Water;
let cam_pos = camera.dependents().cam_pos + focus_off;
// Sets the listener position to the camera position facing the
// same direction as the camera
audio.set_listener_pos(cam_pos, camera.dependents().cam_dir);
// TODO: replace; deprecated in favor of outcomes
self.event_mapper.maintain(
audio,
state,
player_entity,
camera,
@ -295,42 +282,6 @@ impl SfxMgr {
terrain,
client,
);
// TODO: replace; deprecated in favor of outcomes
let events = ecs.read_resource::<EventBus<SfxEventItem>>().recv_all();
for event in events {
let position = match event.pos {
Some(pos) => pos,
_ => cam_pos,
};
if let Some(item) = self.triggers.get_trigger(&event.sfx) {
let sfx_file = match item.files.len() {
0 => {
debug!("Sfx event {:?} is missing audio file.", event.sfx);
"voxygen.audio.sfx.placeholder"
},
1 => item
.files
.last()
.expect("Failed to determine sound file for this trigger item."),
_ => {
// If more than one file is listed, choose one at random
let rand_step = rand::random::<usize>() % item.files.len();
&item.files[rand_step]
},
};
if underwater {
audio.play_underwater_sfx(sfx_file, position, event.vol);
} else {
audio.play_sfx(sfx_file, position, event.vol);
}
} else {
debug!("Missing sfx trigger config for sfx event. {:?}", event.sfx);
}
}
}
pub fn handle_outcome(&mut self, outcome: &Outcome, audio: &mut AudioFrontend) {
@ -392,54 +343,6 @@ impl SfxMgr {
audio.play_sfx(file_ref, *pos, None);
}
},
Outcome::Attack {
pos,
character_state,
loadout,
} => {
if let Some(item_config) = &loadout.active_item {
if let ItemKind::Tool(data) = item_config.item.kind() {
if character_state.is_attack() {
match (
CharacterAbilityType::from(character_state),
data.kind.clone(),
) {
(
CharacterAbilityType::ComboMelee(StageSection::Swing, 1),
ToolKind::Sword,
) => {
audio.play_sfx(
"voxygen.audio.sfx.abilities.swing_sword",
*pos,
None,
);
},
(
CharacterAbilityType::ComboMelee(StageSection::Swing, 2),
ToolKind::Sword,
) => {
audio.play_sfx(
"voxygen.audio.sfx.abilities.separated_second_swing",
*pos,
None,
);
},
(
CharacterAbilityType::ComboMelee(StageSection::Swing, 3),
ToolKind::Sword,
) => {
audio.play_sfx(
"voxygen.audio.sfx.abilities.separated_third_swing",
*pos,
None,
);
},
_ => {},
}
}
}
}
},
}
}

View File

@ -2,7 +2,7 @@ pub mod comp;
pub mod sys;
use crate::audio::sfx::SfxEventItem;
use common::event::EventBus;
use common::{event::EventBus, outcome::Outcome};
use specs::{Entity, World, WorldExt};
#[derive(Copy, Clone, Debug)]
@ -27,6 +27,7 @@ pub fn init(world: &mut World) {
world.register::<comp::HpFloaterList>();
world.register::<comp::Interpolated>();
world.insert(MyExpFloaterList::default());
world.insert(Vec::<Outcome>::new());
// Voxygen event buses
world.insert(EventBus::<SfxEventItem>::default());

View File

@ -101,7 +101,7 @@ pub struct Scene {
particle_mgr: ParticleMgr,
figure_mgr: FigureMgr,
sfx_mgr: SfxMgr,
pub sfx_mgr: SfxMgr,
music_mgr: MusicMgr,
ambient_mgr: AmbientMgr,
}

View File

@ -1,5 +1,5 @@
use crate::{
audio::sfx::{SfxEvent, SfxEventItem},
audio::sfx::SfxEvent,
ecs::MyEntity,
hud::{DebugInfo, Event as HudEvent, Hud, HudInfo, PressBehavior},
i18n::{i18n_asset_key, Localization},
@ -17,7 +17,6 @@ use common::{
comp,
comp::{ChatMsg, ChatType, InventoryUpdateEvent, Pos, Vel},
consts::{MAX_MOUNT_RANGE, MAX_PICKUP_RANGE},
event::EventBus,
msg::PresenceKind,
outcome::Outcome,
span,
@ -121,12 +120,12 @@ impl SessionState {
self.hud.new_message(m);
},
client::Event::InventoryUpdated(inv_event) => {
let sfx_event = SfxEvent::from(&inv_event);
client
.state()
.ecs()
.read_resource::<EventBus<SfxEventItem>>()
.emit_now(SfxEventItem::at_player_position(sfx_event));
let sfx_trigger_item = self
.scene
.sfx_mgr
.triggers
.get_key_value(&SfxEvent::from(&inv_event));
global_state.audio.emit_sfx_item(sfx_trigger_item);
match inv_event {
InventoryUpdateEvent::CollectFailed => {