Piggyback on the InventoryUpdate events and attach some additional event info so that we can detect why the inventory update was triggered, and emit an associated sfx event that matches it.

This commit is contained in:
S Handley 2020-03-04 10:09:48 +00:00 committed by Acrimon
parent e89810e0a1
commit b0ca85069b
19 changed files with 159 additions and 26 deletions

View File

@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added new orc hairstyles - Added new orc hairstyles
- Added sfx for wielding/unwielding weapons - Added sfx for wielding/unwielding weapons
- Fixed NPCs attacking the player forever after killing them - Fixed NPCs attacking the player forever after killing them
- Added sfx for collecting, dropping and using inventory items
### Changed ### Changed

View File

@ -35,5 +35,59 @@
], ],
threshold: 0.5, threshold: 0.5,
), ),
Inventory(Collected): (
files: [
"voxygen.audio.sfx.inventory.add_item",
],
threshold: 0.5,
),
Inventory(Swapped): (
files: [
"voxygen.audio.sfx.inventory.add_item",
],
threshold: 0.5,
),
Inventory(Given): (
files: [
"voxygen.audio.sfx.inventory.add_item",
],
threshold: 0.5,
),
Inventory(Dropped): (
files: [
"voxygen.audio.sfx.footsteps.stepgrass_4",
],
threshold: 0.5,
),
Inventory(Consumed(Potion)): (
files: [
"voxygen.audio.sfx.inventory.consumable.liquid",
],
threshold: 0.3,
),
Inventory(Consumed(PotionMinor)): (
files: [
"voxygen.audio.sfx.inventory.consumable.liquid",
],
threshold: 0.3,
),
Inventory(Consumed(Apple)): (
files: [
"voxygen.audio.sfx.inventory.consumable.apple",
],
threshold: 0.3,
),
Inventory(Consumed(Mushroom)): (
files: [
"voxygen.audio.sfx.inventory.consumable.food",
],
threshold: 0.3,
),
Inventory(Consumed(Cheese)): (
files: [
"voxygen.audio.sfx.inventory.consumable.food",
],
threshold: 0.3,
)
} }
) )

BIN
assets/voxygen/audio/sfx/inventory/add_item.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/inventory/consumable/apple.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/inventory/consumable/food.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/inventory/consumable/liquid.wav (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -14,6 +14,7 @@ pub use specs::{
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use common::{ use common::{
comp::{self, ControlEvent, Controller, ControllerInputs, InventoryManip}, comp::{self, ControlEvent, Controller, ControllerInputs, InventoryManip},
event::{EventBus, SfxEvent, SfxEventItem},
msg::{ msg::{
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate, validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
RequestStateError, ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG, RequestStateError, ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG,
@ -377,6 +378,7 @@ impl Client {
} }
} }
} }
// Handle new messages from the server. // Handle new messages from the server.
frontend_events.append(&mut self.handle_new_messages()?); frontend_events.append(&mut self.handle_new_messages()?);
@ -669,8 +671,14 @@ impl Client {
self.state.write_component(entity, character_state); self.state.write_component(entity, character_state);
} }
}, },
ServerMsg::InventoryUpdate(inventory) => { ServerMsg::InventoryUpdate(inventory, event) => {
self.state.write_component(self.entity, inventory) self.state.write_component(self.entity, inventory);
self.state
.ecs()
.read_resource::<EventBus<SfxEventItem>>()
.emitter()
.emit(SfxEventItem::at_player_position(SfxEvent::Inventory(event)));
}, },
ServerMsg::TerrainChunkUpdate { key, chunk } => { ServerMsg::TerrainChunkUpdate { key, chunk } => {
if let Ok(chunk) = chunk { if let Ok(chunk) = chunk {

View File

@ -90,7 +90,7 @@ pub enum Armor {
Necklace, Necklace,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Consumable { pub enum Consumable {
Apple, Apple,
Cheese, Cheese,

View File

@ -1,10 +1,11 @@
pub mod item; pub mod item;
// Reexports // Reexports
pub use item::{Debug, Item, ItemKind, Tool}; pub use item::{Consumable, Debug, Item, ItemKind, Tool};
use crate::assets; use crate::assets;
use specs::{Component, HashMapStorage, NullStorage}; use specs::{Component, FlaggedStorage, HashMapStorage};
use specs_idvs::IDVStorage;
use std::ops::Not; use std::ops::Not;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -136,12 +137,37 @@ impl Component for Inventory {
type Storage = HashMapStorage<Self>; type Storage = HashMapStorage<Self>;
} }
// ForceUpdate #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum InventoryUpdateEvent {
Init,
Used,
Consumed(Consumable),
Gave,
Given,
Swapped,
Dropped,
Collected,
Possession,
Debug,
}
impl Default for InventoryUpdateEvent {
fn default() -> Self { Self::Init }
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct InventoryUpdate; pub struct InventoryUpdate {
event: InventoryUpdateEvent,
}
impl InventoryUpdate {
pub fn new(event: InventoryUpdateEvent) -> Self { Self { event } }
pub fn event(&self) -> InventoryUpdateEvent { self.event }
}
impl Component for InventoryUpdate { impl Component for InventoryUpdate {
type Storage = NullStorage<Self>; type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
} }
#[cfg(test)] mod test; #[cfg(test)] mod test;

View File

@ -28,7 +28,7 @@ pub use controller::{
}; };
pub use energy::{Energy, EnergySource}; pub use energy::{Energy, EnergySource};
pub use inputs::CanBuild; pub use inputs::CanBuild;
pub use inventory::{item, Inventory, InventoryUpdate, Item, ItemKind}; pub use inventory::{item, Inventory, InventoryUpdate, InventoryUpdateEvent, Item, ItemKind};
pub use last::Last; pub use last::Last;
pub use location::{Waypoint, WaypointArea}; pub use location::{Waypoint, WaypointArea};
pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel}; pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel};

View File

@ -1,5 +1,5 @@
use crate::{comp, sync::Uid}; use crate::{comp, sync::Uid};
use comp::item::Tool; use comp::{item::Tool, InventoryUpdateEvent};
use parking_lot::Mutex; use parking_lot::Mutex;
use serde::Deserialize; use serde::Deserialize;
use specs::Entity as EcsEntity; use specs::Entity as EcsEntity;
@ -42,6 +42,7 @@ pub enum SfxEvent {
LevelUp, LevelUp,
Wield(Tool), Wield(Tool),
Unwield(Tool), Unwield(Tool),
Inventory(InventoryUpdateEvent),
} }
pub enum LocalEvent { pub enum LocalEvent {

View File

@ -71,7 +71,7 @@ pub enum ServerMsg {
entity: u64, entity: u64,
character_state: comp::CharacterState, character_state: comp::CharacterState,
}, },
InventoryUpdate(comp::Inventory), InventoryUpdate(comp::Inventory, comp::InventoryUpdateEvent),
TerrainChunkUpdate { TerrainChunkUpdate {
key: Vec2<i32>, key: Vec2<i32>,
chunk: Result<Box<TerrainChunk>, ()>, chunk: Result<Box<TerrainChunk>, ()>,

View File

@ -262,6 +262,7 @@ lazy_static! {
), ),
]; ];
} }
fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) { fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) {
if let Ok(item) = assets::load_cloned(&args) { if let Ok(item) = assets::load_cloned(&args) {
server server
@ -274,7 +275,10 @@ fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &C
.state .state
.ecs() .ecs()
.write_storage::<comp::InventoryUpdate>() .write_storage::<comp::InventoryUpdate>()
.insert(entity, comp::InventoryUpdate); .insert(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Given),
);
} else { } else {
server.notify_client(entity, ServerMsg::private(String::from("Invalid item!"))); server.notify_client(entity, ServerMsg::private(String::from("Invalid item!")));
} }
@ -1113,7 +1117,10 @@ fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action:
.state .state
.ecs() .ecs()
.write_storage::<comp::InventoryUpdate>() .write_storage::<comp::InventoryUpdate>()
.insert(entity, comp::InventoryUpdate); .insert(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Debug),
);
} else { } else {
server.notify_client( server.notify_client(
entity, entity,

View File

@ -106,7 +106,10 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
} }
} }
ecs.write_storage::<comp::InventoryUpdate>() ecs.write_storage::<comp::InventoryUpdate>()
.insert(possesse, comp::InventoryUpdate) .insert(
possesse,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Possession),
)
.err() .err()
.map(|e| { .map(|e| {
error!( error!(

View File

@ -48,7 +48,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
} }
} }
state.write_component(entity, comp::InventoryUpdate); state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected),
);
}, },
comp::InventoryManip::Collect(pos) => { comp::InventoryManip::Collect(pos) => {
@ -76,6 +79,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.get_mut(entity) .get_mut(entity)
.and_then(|inv| inv.remove(slot)); .and_then(|inv| inv.remove(slot));
let mut event = comp::InventoryUpdateEvent::Used;
if let Some(item) = item_opt { if let Some(item) = item_opt {
match item.kind { match item.kind {
comp::ItemKind::Tool { .. } => { comp::ItemKind::Tool { .. } => {
@ -94,7 +99,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
stats.equipment.main = Some(item); stats.equipment.main = Some(item);
} }
}, },
comp::ItemKind::Consumable { effect, .. } => { comp::ItemKind::Consumable { kind, effect } => {
event = comp::InventoryUpdateEvent::Consumed(kind);
state.apply_effect(entity, effect); state.apply_effect(entity, effect);
}, },
comp::ItemKind::Utility { kind } => match kind { comp::ItemKind::Utility { kind } => match kind {
@ -168,7 +174,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
} }
} }
state.write_component(entity, comp::InventoryUpdate); state.write_component(entity, comp::InventoryUpdate::new(event));
}, },
comp::InventoryManip::Swap(a, b) => { comp::InventoryManip::Swap(a, b) => {
@ -177,7 +183,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.write_storage::<comp::Inventory>() .write_storage::<comp::Inventory>()
.get_mut(entity) .get_mut(entity)
.map(|inv| inv.swap_slots(a, b)); .map(|inv| inv.swap_slots(a, b));
state.write_component(entity, comp::InventoryUpdate); state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Swapped),
);
}, },
comp::InventoryManip::Drop(slot) => { comp::InventoryManip::Drop(slot) => {
@ -201,7 +210,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
item, item,
)); ));
} }
state.write_component(entity, comp::InventoryUpdate); state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Dropped),
);
}, },
} }

View File

@ -282,7 +282,10 @@ impl Server {
state.write_component(entity, comp::CharacterState::default()); state.write_component(entity, comp::CharacterState::default());
state.write_component(entity, comp::Alignment::Owned(entity)); state.write_component(entity, comp::Alignment::Owned(entity));
state.write_component(entity, comp::Inventory::default()); state.write_component(entity, comp::Inventory::default());
state.write_component(entity, comp::InventoryUpdate); state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::default()),
);
// Make sure physics are accepted. // Make sure physics are accepted.
state.write_component(entity, comp::ForceUpdate); state.write_component(entity, comp::ForceUpdate);
@ -606,7 +609,10 @@ impl StateExt for State {
.map(|inv| inv.push(item).is_none()) .map(|inv| inv.push(item).is_none())
.unwrap_or(false); .unwrap_or(false);
if success { if success {
self.write_component(entity, comp::InventoryUpdate); self.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected),
);
} }
success success
} }

View File

@ -328,8 +328,11 @@ impl<'a> System<'a> for Sys {
// TODO: Sync clients that don't have a position? // TODO: Sync clients that don't have a position?
// Sync inventories // Sync inventories
for (client, inventory, _) in (&mut clients, &inventories, &inventory_updates).join() { for (client, inventory, update) in (&mut clients, &inventories, &inventory_updates).join() {
client.notify(ServerMsg::InventoryUpdate(inventory.clone())); client.notify(ServerMsg::InventoryUpdate(
inventory.clone(),
update.event(),
));
} }
// Remove all force flags. // Remove all force flags.

View File

@ -1,5 +1,5 @@
pub mod movement; mod movement;
pub mod progression; mod progression;
use movement::MovementEventMapper; use movement::MovementEventMapper;
use progression::ProgressionEventMapper; use progression::ProgressionEventMapper;

View File

@ -172,7 +172,7 @@ impl MovementEventMapper {
match ( match (
current_event.movement, current_event.movement,
current_event.action, current_event.action,
previous_event.event, previous_event.event.clone(),
) { ) {
(_, ActionState::Roll { .. }, _) => SfxEvent::Roll, (_, ActionState::Roll { .. }, _) => SfxEvent::Roll,
(MovementState::Climb, ..) => SfxEvent::Climb, (MovementState::Climb, ..) => SfxEvent::Climb,