Merge branch 'sam/better-inventory-loadout-swapping' into 'master'

Restricts when players can change their loadout to non-attack states

See merge request veloren/veloren!1761
This commit is contained in:
Samuel Keiffer 2021-02-09 18:23:55 +00:00
commit 155feb8e8a
17 changed files with 186 additions and 70 deletions

View File

@ -22,8 +22,9 @@ use common::{
chat::{KillSource, KillType},
group,
skills::Skill,
slot::Slot,
ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InventoryManip,
InventoryUpdateEvent,
InventoryUpdateEvent, LoadoutManip,
},
event::{EventBus, LocalEvent},
grid::Grid,
@ -598,22 +599,39 @@ impl Client {
self.send_msg(ClientGeneral::SetViewDistance(self.view_distance.unwrap()));
}
pub fn use_slot(&mut self, slot: comp::slot::Slot) {
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Use(slot),
)));
pub fn use_slot(&mut self, slot: Slot) {
match slot {
Slot::Equip(equip) => {
self.control_action(ControlAction::LoadoutManip(LoadoutManip::Use(equip)))
},
Slot::Inventory(inv) => self.send_msg(ClientGeneral::ControlEvent(
ControlEvent::InventoryManip(InventoryManip::Use(inv)),
)),
}
}
pub fn swap_slots(&mut self, a: comp::slot::Slot, b: comp::slot::Slot) {
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Swap(a, b),
)));
pub fn swap_slots(&mut self, a: Slot, b: Slot) {
match (a, b) {
(Slot::Equip(equip), slot) | (slot, Slot::Equip(equip)) => {
self.control_action(ControlAction::LoadoutManip(LoadoutManip::Swap(equip, slot)))
},
(Slot::Inventory(inv1), Slot::Inventory(inv2)) => {
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Swap(inv1, inv2),
)))
},
}
}
pub fn drop_slot(&mut self, slot: comp::slot::Slot) {
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryManip(
InventoryManip::Drop(slot),
)));
pub fn drop_slot(&mut self, slot: Slot) {
match slot {
Slot::Equip(equip) => {
self.control_action(ControlAction::LoadoutManip(LoadoutManip::Drop(equip)))
},
Slot::Inventory(inv) => self.send_msg(ClientGeneral::ControlEvent(
ControlEvent::InventoryManip(InventoryManip::Drop(inv)),
)),
}
}
pub fn pick_up(&mut self, entity: EcsEntity) {
@ -807,7 +825,7 @@ impl Client {
/// Checks whether a player can swap their weapon+ability `Loadout` settings
/// and sends the `ControlAction` event that signals to do the swap.
pub fn swap_loadout(&mut self) { self.control_action(ControlAction::SwapLoadout) }
pub fn swap_loadout(&mut self) { self.control_action(ControlAction::SwapEquippedWeapons) }
pub fn toggle_wield(&mut self) {
let is_wielding = self

View File

@ -16,7 +16,7 @@ pub struct StateUpdate {
pub vel: Vel,
pub ori: Ori,
pub energy: Energy,
pub swap_loadout: bool,
pub swap_equipped_weapons: bool,
pub local_events: VecDeque<LocalEvent>,
pub server_events: VecDeque<ServerEvent>,
}
@ -28,7 +28,7 @@ impl From<&JoinData<'_>> for StateUpdate {
vel: *data.vel,
ori: *data.ori,
energy: *data.energy,
swap_loadout: false,
swap_equipped_weapons: false,
character: data.character.clone(),
local_events: VecDeque::new(),
server_events: VecDeque::new(),

View File

@ -1,5 +1,8 @@
use crate::{
comp::{inventory::slot::Slot, BuffKind},
comp::{
inventory::slot::{EquipSlot, InvSlotId, Slot},
BuffKind,
},
uid::Uid,
util::Dir,
};
@ -14,6 +17,23 @@ pub const DEFAULT_HOLD_DURATION: Duration = Duration::from_millis(200);
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum InventoryManip {
Pickup(Uid),
Collect(Vec3<i32>),
Use(InvSlotId),
Swap(InvSlotId, InvSlotId),
Drop(InvSlotId),
CraftRecipe(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum LoadoutManip {
Use(EquipSlot),
Swap(EquipSlot, Slot),
Drop(EquipSlot),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum SlotManip {
Pickup(Uid),
Collect(Vec3<i32>),
Use(Slot),
@ -22,6 +42,31 @@ pub enum InventoryManip {
CraftRecipe(String),
}
impl From<LoadoutManip> for SlotManip {
fn from(loadout_manip: LoadoutManip) -> Self {
match loadout_manip {
LoadoutManip::Use(equip) => Self::Use(Slot::Equip(equip)),
LoadoutManip::Swap(equip, slot) => Self::Swap(Slot::Equip(equip), slot),
LoadoutManip::Drop(equip) => Self::Drop(Slot::Equip(equip)),
}
}
}
impl From<InventoryManip> for SlotManip {
fn from(inv_manip: InventoryManip) -> Self {
match inv_manip {
InventoryManip::Pickup(pickup) => Self::Pickup(pickup),
InventoryManip::Collect(collect) => Self::Collect(collect),
InventoryManip::Use(inv) => Self::Use(Slot::Inventory(inv)),
InventoryManip::Swap(inv1, inv2) => {
Self::Swap(Slot::Inventory(inv1), Slot::Inventory(inv2))
},
InventoryManip::Drop(inv) => Self::Drop(Slot::Inventory(inv)),
InventoryManip::CraftRecipe(recipe) => Self::CraftRecipe(recipe),
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupManip {
Invite(Uid),
@ -48,7 +93,8 @@ pub enum ControlEvent {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum ControlAction {
SwapLoadout,
SwapEquippedWeapons,
LoadoutManip(LoadoutManip),
Wield,
GlideWield,
Unwield,

View File

@ -46,7 +46,7 @@ pub use chat::{
};
pub use controller::{
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, Input,
InventoryManip, MountState, Mounting,
InventoryManip, LoadoutManip, MountState, Mounting, SlotManip,
};
pub use energy::{Energy, EnergyChange, EnergySource};
pub use group::Group;

View File

@ -46,7 +46,7 @@ pub enum ServerEvent {
entity: EcsEntity,
cause: comp::HealthSource,
},
InventoryManip(EcsEntity, comp::InventoryManip),
InventoryManip(EcsEntity, comp::SlotManip),
GroupManip(EcsEntity, comp::GroupManip),
Respawn(EcsEntity),
Shoot {

View File

@ -1,7 +1,7 @@
use crate::{
comp::{
Beam, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy, Health,
Inventory, Melee, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
Inventory, LoadoutManip, Melee, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
},
resources::DeltaTime,
uid::Uid,
@ -16,7 +16,10 @@ use specs_idvs::IdvStorage;
pub trait CharacterBehavior {
fn behavior(&self, data: &JoinData) -> StateUpdate;
// Impl these to provide behavior for these inputs
fn swap_loadout(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn manipulate_loadout(&self, data: &JoinData, _loadout_manip: LoadoutManip) -> StateUpdate {
StateUpdate::from(data)
}
fn wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn glide_wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn unwield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
@ -27,7 +30,10 @@ pub trait CharacterBehavior {
fn talk(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn handle_event(&self, data: &JoinData, event: ControlAction) -> StateUpdate {
match event {
ControlAction::SwapLoadout => self.swap_loadout(data),
ControlAction::SwapEquippedWeapons => self.swap_equipped_weapons(data),
ControlAction::LoadoutManip(loadout_manip) => {
self.manipulate_loadout(data, loadout_manip)
},
ControlAction::Wield => self.wield(data),
ControlAction::GlideWield => self.glide_wield(data),
ControlAction::Unwield => self.unwield(data),

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, StateUpdate},
comp::{CharacterState, LoadoutManip, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -41,4 +41,10 @@ impl CharacterBehavior for Data {
update.character = CharacterState::Idle;
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{slot::EquipSlot, CharacterState, EnergySource, StateUpdate},
comp::{slot::EquipSlot, CharacterState, EnergySource, LoadoutManip, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
@ -68,4 +68,10 @@ impl CharacterBehavior for Data {
update.character = CharacterState::Idle;
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::StateUpdate,
comp::{LoadoutManip, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
@ -55,9 +55,15 @@ impl CharacterBehavior for Data {
update
}
fn swap_loadout(&self, data: &JoinData) -> StateUpdate {
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_swap_loadout(data, &mut update);
attempt_swap_equipped_weapons(data, &mut update);
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, StateUpdate},
comp::{CharacterState, LoadoutManip, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -41,4 +41,10 @@ impl CharacterBehavior for Data {
update.character = CharacterState::Idle;
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, StateUpdate},
comp::{CharacterState, LoadoutManip, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
@ -48,9 +48,9 @@ impl CharacterBehavior for Data {
update
}
fn swap_loadout(&self, data: &JoinData) -> StateUpdate {
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_swap_loadout(data, &mut update);
attempt_swap_equipped_weapons(data, &mut update);
update
}
@ -59,4 +59,10 @@ impl CharacterBehavior for Data {
update.character = CharacterState::Idle;
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, StateUpdate},
comp::{CharacterState, LoadoutManip, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -46,4 +46,10 @@ impl CharacterBehavior for Data {
update.character = CharacterState::Idle;
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -4,10 +4,10 @@ use crate::{
item::{Hands, ItemKind, Tool, ToolKind},
quadruped_low, quadruped_medium,
skills::{AxeSkill, BowSkill, HammerSkill, Skill, StaffSkill, SwordSkill},
theropod, Body, CharacterState, StateUpdate,
theropod, Body, CharacterState, LoadoutManip, StateUpdate,
},
consts::{FRIC_GROUND, GRAVITY},
event::LocalEvent,
event::{LocalEvent, ServerEvent},
states::{behavior::JoinData, *},
util::Dir,
};
@ -353,12 +353,24 @@ pub fn handle_climb(data: &JoinData, update: &mut StateUpdate) {
}
/// Checks that player can Swap Weapons and updates `Loadout` if so
pub fn attempt_swap_loadout(data: &JoinData, update: &mut StateUpdate) {
pub fn attempt_swap_equipped_weapons(data: &JoinData, update: &mut StateUpdate) {
if data.inventory.equipped(EquipSlot::Offhand).is_some() {
update.swap_loadout = true;
update.swap_equipped_weapons = true;
}
}
/// Handles inventory manipulations that affect the loadout
pub fn handle_manipulate_loadout(
data: &JoinData,
update: &mut StateUpdate,
loadout_manip: LoadoutManip,
) {
update.server_events.push_front(ServerEvent::InventoryManip(
data.entity,
loadout_manip.into(),
));
}
/// Checks that player can wield the glider and updates `CharacterState` if so
pub fn attempt_glide_wield(data: &JoinData, update: &mut StateUpdate) {
if data.inventory.equipped(EquipSlot::Glider).is_some()

View File

@ -1,6 +1,9 @@
use super::utils::*;
use crate::{
comp::{CharacterState, StateUpdate},
comp::{
slot::{EquipSlot, Slot},
CharacterState, LoadoutManip, StateUpdate,
},
states::behavior::{CharacterBehavior, JoinData},
};
@ -51,9 +54,23 @@ impl CharacterBehavior for Data {
update
}
fn swap_loadout(&self, data: &JoinData) -> StateUpdate {
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_swap_loadout(data, &mut update);
attempt_swap_equipped_weapons(data, &mut update);
update
}
fn manipulate_loadout(&self, data: &JoinData, loadout_manip: LoadoutManip) -> StateUpdate {
let mut update = StateUpdate::from(data);
match loadout_manip {
LoadoutManip::Drop(EquipSlot::Mainhand)
| LoadoutManip::Swap(EquipSlot::Mainhand, _)
| LoadoutManip::Swap(_, Slot::Equip(EquipSlot::Mainhand)) => {
update.character = CharacterState::Idle;
},
_ => (),
}
handle_manipulate_loadout(&data, &mut update, loadout_manip);
update
}
}

View File

@ -30,7 +30,7 @@ fn incorporate_update(tuple: &mut JoinTuple, state_update: StateUpdate) {
if tuple.6.get_unchecked() != &state_update.energy {
*tuple.6.get_mut_unchecked() = state_update.energy
};
if state_update.swap_loadout {
if state_update.swap_equipped_weapons {
let mut inventory = tuple.7.get_mut_unchecked();
let inventory = &mut *inventory;
inventory

View File

@ -1,8 +1,5 @@
use common::{
comp::{
slot::{EquipSlot, Slot},
BuffChange, CharacterState, ControlEvent, Controller, InventoryManip,
},
comp::{BuffChange, ControlEvent, Controller},
event::{EventBus, LocalEvent, ServerEvent},
metrics::SysMetrics,
resources::DeltaTime,
@ -30,7 +27,6 @@ impl<'a> System<'a> for Sys {
Read<'a, DeltaTime>,
ReadExpect<'a, SysMetrics>,
WriteStorage<'a, Controller>,
WriteStorage<'a, CharacterState>,
ReadStorage<'a, Uid>,
);
@ -44,7 +40,6 @@ impl<'a> System<'a> for Sys {
_dt,
sys_metrics,
mut controllers,
mut character_states,
uids,
): Self::SystemData,
) {
@ -52,9 +47,7 @@ impl<'a> System<'a> for Sys {
span!(_guard, "run", "controller::Sys::run");
let mut server_emitter = server_bus.emitter();
for (entity, _uid, controller, mut character_state) in
(&entities, &uids, &mut controllers, &mut character_states).join()
{
for (entity, _uid, controller) in (&entities, &uids, &mut controllers).join() {
let mut inputs = &mut controller.inputs;
// Note(imbris): I avoided incrementing the duration with inputs.tick() because
@ -106,19 +99,7 @@ impl<'a> System<'a> for Sys {
}
},
ControlEvent::InventoryManip(manip) => {
// Unwield if a wielded equipment slot is being modified, to avoid entering
// a barehanded wielding state.
if character_state.is_wield() {
match manip {
InventoryManip::Drop(Slot::Equip(EquipSlot::Mainhand))
| InventoryManip::Swap(_, Slot::Equip(EquipSlot::Mainhand))
| InventoryManip::Swap(Slot::Equip(EquipSlot::Mainhand), _) => {
*character_state = CharacterState::Idle;
},
_ => (),
}
}
server_emitter.emit(ServerEvent::InventoryManip(entity, manip))
server_emitter.emit(ServerEvent::InventoryManip(entity, manip.into()));
},
ControlEvent::GroupManip(manip) => {
server_emitter.emit(ServerEvent::GroupManip(entity, manip))

View File

@ -37,7 +37,7 @@ pub fn snuff_lantern(storage: &mut WriteStorage<comp::LightEmitter>, entity: Ecs
#[allow(clippy::blocks_in_if_conditions)]
#[allow(clippy::same_item_push)] // TODO: Pending review in #587
pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::InventoryManip) {
pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::SlotManip) {
let state = server.state_mut();
let mut dropped_items = Vec::new();
let mut thrown_items = Vec::new();
@ -60,7 +60,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
};
match manip {
comp::InventoryManip::Pickup(uid) => {
comp::SlotManip::Pickup(uid) => {
let picked_up_item: Option<comp::Item>;
let item_entity = if let (Some((item, item_entity)), Some(mut inv)) = (
state
@ -133,7 +133,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
state.write_component(entity, event);
},
comp::InventoryManip::Collect(pos) => {
comp::SlotManip::Collect(pos) => {
let block = state.terrain().get(pos).ok().copied();
if let Some(block) = block {
@ -204,7 +204,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
},
comp::InventoryManip::Use(slot) => {
comp::SlotManip::Use(slot) => {
let mut inventories = state.ecs().write_storage::<comp::Inventory>();
let mut inventory = if let Some(inventory) = inventories.get_mut(entity) {
inventory
@ -405,7 +405,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
},
comp::InventoryManip::Swap(a, b) => {
comp::SlotManip::Swap(a, b) => {
let ecs = state.ecs();
if let Some(pos) = ecs.read_storage::<comp::Pos>().get(entity) {
@ -429,7 +429,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
);
},
comp::InventoryManip::Drop(slot) => {
comp::SlotManip::Drop(slot) => {
let item = match slot {
Slot::Inventory(slot) => state
.ecs()
@ -462,7 +462,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
);
},
comp::InventoryManip::CraftRecipe(recipe) => {
comp::SlotManip::CraftRecipe(recipe) => {
if let Some(mut inv) = state
.ecs()
.write_storage::<comp::Inventory>()