2020-10-16 06:08:45 +00:00
|
|
|
use crate::{
|
2021-02-08 17:31:17 +00:00
|
|
|
comp::{
|
2021-02-08 18:55:50 +00:00
|
|
|
inventory::slot::{EquipSlot, InvSlotId, Slot},
|
2021-02-13 23:32:55 +00:00
|
|
|
invite::{InviteKind, InviteResponse},
|
2021-02-08 17:31:17 +00:00
|
|
|
BuffKind,
|
|
|
|
},
|
2021-02-13 23:32:55 +00:00
|
|
|
trade::{TradeAction, TradeId},
|
2020-12-13 17:11:55 +00:00
|
|
|
uid::Uid,
|
2020-10-16 06:08:45 +00:00
|
|
|
util::Dir,
|
|
|
|
};
|
2020-07-06 14:23:08 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-01-07 20:25:12 +00:00
|
|
|
use specs::{Component, DerefFlaggedStorage};
|
2020-07-06 05:56:02 +00:00
|
|
|
use specs_idvs::IdvStorage;
|
2019-11-29 15:20:35 +00:00
|
|
|
use std::time::Duration;
|
2019-07-29 19:54:58 +00:00
|
|
|
use vek::*;
|
2019-06-09 14:20:20 +00:00
|
|
|
|
2019-12-03 06:30:08 +00:00
|
|
|
/// Default duration before an input is considered 'held'.
|
|
|
|
pub const DEFAULT_HOLD_DURATION: Duration = Duration::from_millis(200);
|
2019-11-29 15:20:35 +00:00
|
|
|
|
2020-04-04 17:51:41 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum InventoryManip {
|
|
|
|
Pickup(Uid),
|
|
|
|
Collect(Vec3<i32>),
|
2021-02-08 18:55:50 +00:00
|
|
|
Use(InvSlotId),
|
|
|
|
Swap(InvSlotId, InvSlotId),
|
|
|
|
Drop(InvSlotId),
|
2020-07-14 20:11:39 +00:00
|
|
|
CraftRecipe(String),
|
2020-04-04 17:51:41 +00:00
|
|
|
}
|
|
|
|
|
2021-02-07 16:57:41 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum LoadoutManip {
|
2021-02-08 18:55:50 +00:00
|
|
|
Use(EquipSlot),
|
2021-02-08 17:31:17 +00:00
|
|
|
Swap(EquipSlot, Slot),
|
|
|
|
Drop(EquipSlot),
|
2021-02-07 16:57:41 +00:00
|
|
|
}
|
|
|
|
|
2021-02-08 18:55:50 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum SlotManip {
|
|
|
|
Pickup(Uid),
|
|
|
|
Collect(Vec3<i32>),
|
|
|
|
Use(Slot),
|
|
|
|
Swap(Slot, Slot),
|
|
|
|
Drop(Slot),
|
|
|
|
CraftRecipe(String),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<LoadoutManip> for SlotManip {
|
2021-02-07 16:57:41 +00:00
|
|
|
fn from(loadout_manip: LoadoutManip) -> Self {
|
|
|
|
match loadout_manip {
|
2021-02-08 18:55:50 +00:00
|
|
|
LoadoutManip::Use(equip) => Self::Use(Slot::Equip(equip)),
|
2021-02-08 17:31:17 +00:00
|
|
|
LoadoutManip::Swap(equip, slot) => Self::Swap(Slot::Equip(equip), slot),
|
|
|
|
LoadoutManip::Drop(equip) => Self::Drop(Slot::Equip(equip)),
|
2021-02-07 16:57:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 18:55:50 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-26 17:03:19 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum GroupManip {
|
|
|
|
Leave,
|
|
|
|
Kick(Uid),
|
|
|
|
AssignLeader(Uid),
|
|
|
|
}
|
|
|
|
|
2019-09-09 19:11:40 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum ControlEvent {
|
2020-10-07 02:23:20 +00:00
|
|
|
//ToggleLantern,
|
|
|
|
EnableLantern,
|
|
|
|
DisableLantern,
|
2021-01-31 20:29:50 +00:00
|
|
|
Interact(Uid),
|
2021-02-13 23:32:55 +00:00
|
|
|
InitiateInvite(Uid, InviteKind),
|
|
|
|
InviteResponse(InviteResponse),
|
|
|
|
PerformTradeAction(TradeId, TradeAction),
|
2019-09-09 19:11:40 +00:00
|
|
|
Mount(Uid),
|
|
|
|
Unmount,
|
2019-10-15 04:06:14 +00:00
|
|
|
InventoryManip(InventoryManip),
|
2020-04-26 17:03:19 +00:00
|
|
|
GroupManip(GroupManip),
|
2020-10-19 03:00:35 +00:00
|
|
|
RemoveBuff(BuffKind),
|
2020-03-24 07:38:16 +00:00
|
|
|
Respawn,
|
|
|
|
}
|
|
|
|
|
2021-02-07 16:57:41 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
2020-03-24 07:38:16 +00:00
|
|
|
pub enum ControlAction {
|
2021-02-08 17:31:17 +00:00
|
|
|
SwapEquippedWeapons,
|
|
|
|
LoadoutManip(LoadoutManip),
|
2020-03-26 15:05:17 +00:00
|
|
|
Wield,
|
2020-06-16 21:32:39 +00:00
|
|
|
GlideWield,
|
2020-03-26 15:05:17 +00:00
|
|
|
Unwield,
|
|
|
|
Sit,
|
2020-05-27 06:41:55 +00:00
|
|
|
Dance,
|
2020-08-02 05:09:11 +00:00
|
|
|
Sneak,
|
2020-03-26 15:05:17 +00:00
|
|
|
Stand,
|
2021-01-31 20:29:50 +00:00
|
|
|
Talk,
|
2020-03-24 07:38:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
enum Freshness {
|
|
|
|
New,
|
|
|
|
TickedOnce,
|
|
|
|
Old,
|
2019-09-09 19:11:40 +00:00
|
|
|
}
|
|
|
|
|
2019-11-29 15:20:35 +00:00
|
|
|
/// Whether a key is pressed or unpressed
|
|
|
|
/// and how long it has been in that state
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub struct Input {
|
2019-12-03 06:30:08 +00:00
|
|
|
/// Should not be pub because duration should
|
|
|
|
/// always be reset when state is updated
|
2020-03-24 07:38:16 +00:00
|
|
|
pressed: bool,
|
2019-12-03 06:30:08 +00:00
|
|
|
/// Should only be updated by npc agents
|
|
|
|
/// through appropriate fn
|
2019-11-29 15:20:35 +00:00
|
|
|
duration: Duration,
|
2020-03-24 07:38:16 +00:00
|
|
|
/// How fresh is the last change to the input state
|
|
|
|
freshness: Freshness,
|
2019-11-29 15:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Input {
|
2020-03-24 07:38:16 +00:00
|
|
|
fn tick(&mut self, dt: Duration) {
|
2019-12-03 06:30:08 +00:00
|
|
|
// Increase how long input has been in current state
|
|
|
|
self.duration = self.duration.checked_add(dt).unwrap_or_default();
|
2020-03-24 07:38:16 +00:00
|
|
|
self.tick_freshness();
|
|
|
|
}
|
2020-03-23 17:13:44 +00:00
|
|
|
|
2020-03-24 07:38:16 +00:00
|
|
|
fn tick_freshness(&mut self) {
|
|
|
|
self.freshness = match self.freshness {
|
|
|
|
Freshness::New => Freshness::TickedOnce,
|
|
|
|
Freshness::TickedOnce => Freshness::Old,
|
|
|
|
Freshness::Old => Freshness::Old,
|
2020-03-23 17:13:44 +00:00
|
|
|
};
|
2019-12-03 06:30:08 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 07:38:16 +00:00
|
|
|
/// Update input with newer version
|
2020-08-25 12:21:25 +00:00
|
|
|
/// Used to update inputs with input received from clients
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn update_with_new(&mut self, new: Self) {
|
|
|
|
if self.pressed != new.pressed {
|
|
|
|
self.freshness = Freshness::New;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.pressed = new.pressed;
|
|
|
|
self.duration = new.duration;
|
|
|
|
}
|
|
|
|
|
2020-03-23 17:13:44 +00:00
|
|
|
/// Whether input is being pressed down
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn is_pressed(&self) -> bool { self.pressed }
|
2019-12-03 06:30:08 +00:00
|
|
|
|
2020-03-23 17:13:44 +00:00
|
|
|
/// Whether it's the first frame this input has been pressed
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn is_just_pressed(&self) -> bool { self.is_pressed() && self.freshness != Freshness::Old }
|
2019-12-03 06:30:08 +00:00
|
|
|
|
2020-03-23 17:13:44 +00:00
|
|
|
/// Whether it's the first frame this input has been unpressed
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn is_just_unpressed(&self) -> bool {
|
|
|
|
!self.is_pressed() && self.freshness != Freshness::Old
|
|
|
|
}
|
2020-03-23 17:13:44 +00:00
|
|
|
|
|
|
|
/// Whether input has been pressed longer than
|
2019-11-29 15:20:35 +00:00
|
|
|
/// `DEFAULT_HOLD_DURATION`
|
|
|
|
pub fn is_held_down(&self) -> bool {
|
2020-02-09 21:15:10 +00:00
|
|
|
self.is_pressed() && self.duration >= DEFAULT_HOLD_DURATION
|
2019-11-29 15:20:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-23 17:13:44 +00:00
|
|
|
/// Whether input has been unpressed longer than
|
|
|
|
/// `DEFAULT_HOLD_DURATION`
|
|
|
|
pub fn is_held_up(&self) -> bool {
|
|
|
|
!self.is_pressed() && self.duration >= DEFAULT_HOLD_DURATION
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether input has been pressed for longer than `threshold` duration
|
|
|
|
pub fn held_for_dur(&self, threshold: Duration) -> bool {
|
2020-03-07 21:03:10 +00:00
|
|
|
self.is_pressed() && self.duration >= threshold
|
2020-01-08 13:17:36 +00:00
|
|
|
}
|
|
|
|
|
2020-03-23 17:13:44 +00:00
|
|
|
/// Handles logic of updating state of Input
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn set_state(&mut self, pressed: bool) {
|
|
|
|
if self.pressed != pressed {
|
|
|
|
self.pressed = pressed;
|
|
|
|
self.duration = Duration::default();
|
|
|
|
self.freshness = Freshness::New;
|
|
|
|
}
|
|
|
|
}
|
2020-03-23 17:13:44 +00:00
|
|
|
|
2020-03-24 07:38:16 +00:00
|
|
|
/// Increases `input.duration` by `dur`
|
2019-11-29 15:20:35 +00:00
|
|
|
pub fn inc_dur(&mut self, dur: Duration) {
|
2019-12-03 06:30:08 +00:00
|
|
|
self.duration = self.duration.checked_add(dur).unwrap_or_default();
|
2019-11-29 15:20:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 07:38:16 +00:00
|
|
|
/// Returns `input.duration`
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn get_dur(&self) -> Duration { self.duration }
|
2019-11-29 15:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Input {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2020-03-24 07:38:16 +00:00
|
|
|
pressed: false,
|
2019-11-29 15:20:35 +00:00
|
|
|
duration: Duration::default(),
|
2020-03-24 07:38:16 +00:00
|
|
|
freshness: Freshness::New,
|
2019-11-29 15:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-24 07:38:16 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum Climb {
|
|
|
|
Up,
|
|
|
|
Down,
|
|
|
|
Hold,
|
|
|
|
}
|
|
|
|
|
2019-06-09 14:20:20 +00:00
|
|
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
2019-10-15 04:06:14 +00:00
|
|
|
pub struct ControllerInputs {
|
2019-11-29 15:20:35 +00:00
|
|
|
pub primary: Input,
|
|
|
|
pub secondary: Input,
|
2020-03-24 12:59:53 +00:00
|
|
|
pub ability3: Input,
|
2021-02-13 00:43:33 +00:00
|
|
|
pub ability4: Input,
|
2019-11-29 15:20:35 +00:00
|
|
|
pub jump: Input,
|
|
|
|
pub roll: Input,
|
|
|
|
pub glide: Input,
|
2020-11-03 22:46:07 +00:00
|
|
|
pub fly: Input, // Flying entities only
|
2019-11-29 15:20:35 +00:00
|
|
|
pub wall_leap: Input,
|
2019-12-03 06:30:08 +00:00
|
|
|
pub charge: Input,
|
2020-03-24 07:38:16 +00:00
|
|
|
pub climb: Option<Climb>,
|
2019-10-15 04:06:14 +00:00
|
|
|
pub move_dir: Vec2<f32>,
|
2020-11-03 22:46:07 +00:00
|
|
|
pub move_z: f32, /* z axis (not combined with move_dir because they may have independent
|
|
|
|
* limits) */
|
2020-03-28 01:31:22 +00:00
|
|
|
pub look_dir: Dir,
|
2019-10-15 04:06:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub struct Controller {
|
|
|
|
pub inputs: ControllerInputs,
|
2019-10-21 00:59:53 +00:00
|
|
|
// TODO: consider SmallVec
|
2019-09-09 19:11:40 +00:00
|
|
|
pub events: Vec<ControlEvent>,
|
2020-03-24 07:38:16 +00:00
|
|
|
pub actions: Vec<ControlAction>,
|
2019-09-09 19:11:40 +00:00
|
|
|
}
|
|
|
|
|
2019-11-29 15:20:35 +00:00
|
|
|
impl ControllerInputs {
|
|
|
|
/// Updates all inputs, accounting for delta time
|
2020-03-24 07:38:16 +00:00
|
|
|
pub fn tick(&mut self, dt: Duration) {
|
|
|
|
self.primary.tick(dt);
|
|
|
|
self.secondary.tick(dt);
|
|
|
|
self.ability3.tick(dt);
|
2021-02-13 00:43:33 +00:00
|
|
|
self.ability4.tick(dt);
|
2020-03-24 07:38:16 +00:00
|
|
|
self.jump.tick(dt);
|
|
|
|
self.roll.tick(dt);
|
|
|
|
self.glide.tick(dt);
|
2020-11-03 22:46:07 +00:00
|
|
|
self.fly.tick(dt);
|
2020-03-24 07:38:16 +00:00
|
|
|
self.wall_leap.tick(dt);
|
|
|
|
self.charge.tick(dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn tick_freshness(&mut self) {
|
|
|
|
self.primary.tick_freshness();
|
|
|
|
self.secondary.tick_freshness();
|
|
|
|
self.ability3.tick_freshness();
|
2021-02-13 00:43:33 +00:00
|
|
|
self.ability4.tick_freshness();
|
2020-03-24 07:38:16 +00:00
|
|
|
self.jump.tick_freshness();
|
|
|
|
self.roll.tick_freshness();
|
|
|
|
self.glide.tick_freshness();
|
2020-11-03 22:46:07 +00:00
|
|
|
self.fly.tick_freshness();
|
2020-03-24 07:38:16 +00:00
|
|
|
self.wall_leap.tick_freshness();
|
|
|
|
self.charge.tick_freshness();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Updates Controller inputs with new version received from the client
|
|
|
|
pub fn update_with_new(&mut self, new: Self) {
|
|
|
|
self.primary.update_with_new(new.primary);
|
|
|
|
self.secondary.update_with_new(new.secondary);
|
|
|
|
self.ability3.update_with_new(new.ability3);
|
2021-02-13 00:43:33 +00:00
|
|
|
self.ability4.update_with_new(new.ability4);
|
2020-03-24 07:38:16 +00:00
|
|
|
self.jump.update_with_new(new.jump);
|
|
|
|
self.roll.update_with_new(new.roll);
|
|
|
|
self.glide.update_with_new(new.glide);
|
2020-11-03 22:46:07 +00:00
|
|
|
self.fly.update_with_new(new.fly);
|
2020-03-24 07:38:16 +00:00
|
|
|
self.wall_leap.update_with_new(new.wall_leap);
|
|
|
|
self.charge.update_with_new(new.charge);
|
|
|
|
self.climb = new.climb;
|
|
|
|
self.move_dir = new.move_dir;
|
2020-11-03 22:46:07 +00:00
|
|
|
self.move_z = new.move_z;
|
2020-03-24 07:38:16 +00:00
|
|
|
self.look_dir = new.look_dir;
|
2019-12-03 06:30:08 +00:00
|
|
|
}
|
2020-03-24 12:59:53 +00:00
|
|
|
|
|
|
|
pub fn holding_ability_key(&self) -> bool {
|
2021-02-13 00:43:33 +00:00
|
|
|
self.primary.is_pressed()
|
|
|
|
|| self.secondary.is_pressed()
|
|
|
|
|| self.ability3.is_pressed()
|
|
|
|
|| self.ability4.is_pressed()
|
2020-03-24 12:59:53 +00:00
|
|
|
}
|
2019-11-29 15:20:35 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 19:11:40 +00:00
|
|
|
impl Controller {
|
2019-11-29 15:20:35 +00:00
|
|
|
/// Sets all inputs to default
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn reset(&mut self) { *self = Self::default(); }
|
2019-09-09 19:11:40 +00:00
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn clear_events(&mut self) { self.events.clear(); }
|
2019-09-09 19:11:40 +00:00
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn push_event(&mut self, event: ControlEvent) { self.events.push(event); }
|
2019-06-09 14:20:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Component for Controller {
|
2020-11-25 22:47:16 +00:00
|
|
|
type Storage = IdvStorage<Self>;
|
2019-06-09 14:20:20 +00:00
|
|
|
}
|
2019-09-09 19:11:40 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum MountState {
|
|
|
|
Unmounted,
|
|
|
|
MountedBy(Uid),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Component for MountState {
|
2021-01-07 20:25:12 +00:00
|
|
|
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
2019-09-09 19:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub struct Mounting(pub Uid);
|
|
|
|
|
|
|
|
impl Component for Mounting {
|
2021-01-07 20:25:12 +00:00
|
|
|
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
2019-09-09 19:11:40 +00:00
|
|
|
}
|