veloren/common/src/event.rs
Imbris 334937568e Add an entity view distance setting that allows limiting the distance
entities are synced from and displayed in.

NOTE: Syncing entities work at the granularity regions which are
multi-chunk squares but the display of entities in voxygen is limited in
a circle with the radiues of the supplied distance.

Additional details and changes:
* Added `ViewDistances` struct in `common` that contains separate
  terrain and entity view distances (the entity view distance will be
  clamped by the terrain view distance in uses of this).
* View distance requests from the client to the server now use this
  type.
* When requesting the character or spectate state the client now passes
  its desired view distances. This is exposed as a new parameter on
  `Client::request_character`/`Client::request_spectate`. And the client
  no longer needs to send a view distance request after entering these
  states. This also allows us to avoid needing to initialize `Presence`
  with a default view distance value on the server.
* Removed `DerefFlaggedStorage` from `Presence` and `RegionSubscription` since the
  change tracking isn't used for these components.
* Add sliders in voxygen graphics and network tabs for this new setting.
  Show the clamped value as well as the selected value next to the
  slider.
* Rename existing "Entities View Distance" slider (which AFAIK controls
  the distance at which different LOD levels apply to figures) to
  "Entities Detail Distance" so we can use the former name for this new
  slider.
2022-08-25 23:24:43 -04:00

270 lines
6.8 KiB
Rust

use crate::{
character::CharacterId,
comp::{
self,
agent::Sound,
invite::{InviteKind, InviteResponse},
DisconnectReason, Ori, Pos,
},
lottery::LootSpec,
outcome::Outcome,
rtsim::RtSimEntity,
terrain::SpriteKind,
trade::{TradeAction, TradeId},
uid::Uid,
util::Dir,
Explosion,
};
use specs::Entity as EcsEntity;
use std::{collections::VecDeque, ops::DerefMut, sync::Mutex};
use vek::*;
pub type SiteId = u64;
pub enum LocalEvent {
/// Applies upward force to entity's `Vel`
Jump(EcsEntity, f32),
/// Applies the `impulse` to `entity`'s `Vel`
ApplyImpulse {
entity: EcsEntity,
impulse: Vec3<f32>,
},
/// Applies `vel` velocity to `entity`
Boost { entity: EcsEntity, vel: Vec3<f32> },
/// Creates an outcome
CreateOutcome(Outcome),
}
#[allow(clippy::large_enum_variant)] // TODO: Pending review in #587
#[derive(strum::EnumDiscriminants)]
#[strum_discriminants(repr(usize))]
#[strum_discriminants(derive(strum::EnumVariantNames))]
pub enum ServerEvent {
Explosion {
pos: Vec3<f32>,
explosion: Explosion,
owner: Option<Uid>,
},
Bonk {
pos: Vec3<f32>,
owner: Option<Uid>,
target: Option<Uid>,
},
HealthChange {
entity: EcsEntity,
change: comp::HealthChange,
},
PoiseChange {
entity: EcsEntity,
change: comp::PoiseChange,
},
Delete(EcsEntity),
Destroy {
entity: EcsEntity,
cause: comp::HealthChange,
},
InventoryManip(EcsEntity, comp::InventoryManip),
GroupManip(EcsEntity, comp::GroupManip),
Respawn(EcsEntity),
Shoot {
entity: EcsEntity,
pos: Pos,
dir: Dir,
body: comp::Body,
light: Option<comp::LightEmitter>,
projectile: comp::Projectile,
speed: f32,
object: Option<comp::Object>,
},
Shockwave {
properties: comp::shockwave::Properties,
pos: Pos,
ori: Ori,
},
Knockback {
entity: EcsEntity,
impulse: Vec3<f32>,
},
BeamSegment {
properties: comp::beam::Properties,
pos: Pos,
ori: Ori,
},
LandOnGround {
entity: EcsEntity,
vel: Vec3<f32>,
},
EnableLantern(EcsEntity),
DisableLantern(EcsEntity),
NpcInteract(EcsEntity, EcsEntity),
InviteResponse(EcsEntity, InviteResponse),
InitiateInvite(EcsEntity, Uid, InviteKind),
ProcessTradeAction(EcsEntity, TradeId, TradeAction),
Mount(EcsEntity, EcsEntity),
Unmount(EcsEntity),
Possess(Uid, Uid),
/// Inserts default components for a character when loading into the game
InitCharacterData {
entity: EcsEntity,
character_id: CharacterId,
requested_view_distances: crate::ViewDistances,
},
InitSpectator(EcsEntity, crate::ViewDistances),
UpdateCharacterData {
entity: EcsEntity,
components: (
comp::Body,
comp::Stats,
comp::SkillSet,
comp::Inventory,
Option<comp::Waypoint>,
Vec<(comp::Pet, comp::Body, comp::Stats)>,
comp::ActiveAbilities,
Option<comp::MapMarker>,
),
},
ExitIngame {
entity: EcsEntity,
},
// TODO: to avoid breakage when adding new fields, perhaps have an `NpcBuilder` type?
CreateNpc {
pos: Pos,
stats: comp::Stats,
skill_set: comp::SkillSet,
health: Option<comp::Health>,
poise: comp::Poise,
inventory: comp::inventory::Inventory,
body: comp::Body,
agent: Option<comp::Agent>,
alignment: comp::Alignment,
scale: comp::Scale,
anchor: Option<comp::Anchor>,
loot: LootSpec<String>,
rtsim_entity: Option<RtSimEntity>,
projectile: Option<comp::Projectile>,
},
CreateShip {
pos: Pos,
ship: comp::ship::Body,
mountable: bool,
agent: Option<comp::Agent>,
rtsim_entity: Option<RtSimEntity>,
},
CreateWaypoint(Vec3<f32>),
ClientDisconnect(EcsEntity, DisconnectReason),
ClientDisconnectWithoutPersistence(EcsEntity),
Command(EcsEntity, String, Vec<String>),
/// Send a chat message to the player from an npc or other player
Chat(comp::UnresolvedChatMsg),
Aura {
entity: EcsEntity,
aura_change: comp::AuraChange,
},
Buff {
entity: EcsEntity,
buff_change: comp::BuffChange,
},
EnergyChange {
entity: EcsEntity,
change: f32,
},
ComboChange {
entity: EcsEntity,
change: i32,
},
Parry {
entity: EcsEntity,
energy_cost: f32,
},
RequestSiteInfo {
entity: EcsEntity,
id: SiteId,
},
// Attempt to mine a block, turning it into an item
MineBlock {
entity: EcsEntity,
pos: Vec3<i32>,
tool: Option<comp::tool::ToolKind>,
},
TeleportTo {
entity: EcsEntity,
target: Uid,
max_range: Option<f32>,
},
CreateSafezone {
range: Option<f32>,
pos: Pos,
},
Sound {
sound: Sound,
},
CreateSprite {
pos: Vec3<i32>,
sprite: SpriteKind,
},
TamePet {
pet_entity: EcsEntity,
owner_entity: EcsEntity,
},
EntityAttackedHook {
entity: EcsEntity,
},
ChangeAbility {
entity: EcsEntity,
slot: usize,
auxiliary_key: comp::ability::AuxiliaryKey,
new_ability: comp::ability::AuxiliaryAbility,
},
UpdateMapMarker {
entity: EcsEntity,
update: comp::MapMarkerChange,
},
}
pub struct EventBus<E> {
queue: Mutex<VecDeque<E>>,
}
impl<E> Default for EventBus<E> {
fn default() -> Self {
Self {
queue: Mutex::new(VecDeque::new()),
}
}
}
impl<E> EventBus<E> {
pub fn emitter(&self) -> Emitter<E> {
Emitter {
bus: self,
events: VecDeque::new(),
}
}
pub fn emit_now(&self, event: E) { self.queue.lock().unwrap().push_back(event); }
pub fn recv_all(&self) -> impl ExactSizeIterator<Item = E> {
std::mem::take(self.queue.lock().unwrap().deref_mut()).into_iter()
}
}
pub struct Emitter<'a, E> {
bus: &'a EventBus<E>,
events: VecDeque<E>,
}
impl<'a, E> Emitter<'a, E> {
pub fn emit(&mut self, event: E) { self.events.push_back(event); }
pub fn emit_many(&mut self, events: impl IntoIterator<Item = E>) { self.events.extend(events); }
pub fn append(&mut self, other: &mut VecDeque<E>) { self.events.append(other) }
// TODO: allow just emitting the whole vec of events at once? without copying
pub fn append_vec(&mut self, vec: Vec<E>) { self.events.extend(vec) }
}
impl<'a, E> Drop for Emitter<'a, E> {
fn drop(&mut self) { self.bus.queue.lock().unwrap().append(&mut self.events); }
}