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 sfx for wielding/unwielding weapons
- Fixed NPCs attacking the player forever after killing them
- Added sfx for collecting, dropping and using inventory items
### Changed

View File

@ -35,5 +35,59 @@
],
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 common::{
comp::{self, ControlEvent, Controller, ControllerInputs, InventoryManip},
event::{EventBus, SfxEvent, SfxEventItem},
msg::{
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
RequestStateError, ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG,
@ -377,6 +378,7 @@ impl Client {
}
}
}
// Handle new messages from the server.
frontend_events.append(&mut self.handle_new_messages()?);
@ -669,8 +671,14 @@ impl Client {
self.state.write_component(entity, character_state);
}
},
ServerMsg::InventoryUpdate(inventory) => {
self.state.write_component(self.entity, inventory)
ServerMsg::InventoryUpdate(inventory, event) => {
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 } => {
if let Ok(chunk) = chunk {

View File

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

View File

@ -1,10 +1,11 @@
pub mod item;
// Reexports
pub use item::{Debug, Item, ItemKind, Tool};
pub use item::{Consumable, Debug, Item, ItemKind, Tool};
use crate::assets;
use specs::{Component, HashMapStorage, NullStorage};
use specs::{Component, FlaggedStorage, HashMapStorage};
use specs_idvs::IDVStorage;
use std::ops::Not;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -136,12 +137,37 @@ impl Component for Inventory {
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)]
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 {
type Storage = NullStorage<Self>;
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}
#[cfg(test)] mod test;

View File

@ -28,7 +28,7 @@ pub use controller::{
};
pub use energy::{Energy, EnergySource};
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 location::{Waypoint, WaypointArea};
pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel};

View File

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

View File

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

View File

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

View File

@ -106,7 +106,10 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
}
}
ecs.write_storage::<comp::InventoryUpdate>()
.insert(possesse, comp::InventoryUpdate)
.insert(
possesse,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Possession),
)
.err()
.map(|e| {
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) => {
@ -76,6 +79,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.get_mut(entity)
.and_then(|inv| inv.remove(slot));
let mut event = comp::InventoryUpdateEvent::Used;
if let Some(item) = item_opt {
match item.kind {
comp::ItemKind::Tool { .. } => {
@ -94,7 +99,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
stats.equipment.main = Some(item);
}
},
comp::ItemKind::Consumable { effect, .. } => {
comp::ItemKind::Consumable { kind, effect } => {
event = comp::InventoryUpdateEvent::Consumed(kind);
state.apply_effect(entity, effect);
},
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) => {
@ -177,7 +183,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.write_storage::<comp::Inventory>()
.get_mut(entity)
.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) => {
@ -201,7 +210,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
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::Alignment::Owned(entity));
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.
state.write_component(entity, comp::ForceUpdate);
@ -606,7 +609,10 @@ impl StateExt for State {
.map(|inv| inv.push(item).is_none())
.unwrap_or(false);
if success {
self.write_component(entity, comp::InventoryUpdate);
self.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected),
);
}
success
}

View File

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

View File

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

View File

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