veloren_common/comp/
presence.rs1use crate::{ViewDistances, character::CharacterId};
2use serde::{Deserialize, Serialize};
3use specs::Component;
4use std::time::{Duration, Instant};
5use vek::*;
6
7#[derive(Debug)]
8pub struct Presence {
9 pub terrain_view_distance: ViewDistance,
10 pub entity_view_distance: ViewDistance,
11 pub kind: PresenceKind,
15 pub lossy_terrain_compression: bool,
16}
17
18impl Presence {
19 pub fn new(view_distances: ViewDistances, kind: PresenceKind) -> Self {
20 let now = Instant::now();
21 Self {
22 terrain_view_distance: ViewDistance::new(view_distances.terrain, now),
23 entity_view_distance: ViewDistance::new(view_distances.entity, now),
24 kind,
25 lossy_terrain_compression: false,
26 }
27 }
28}
29
30impl Component for Presence {
31 type Storage = specs::DenseVecStorage<Self>;
32}
33
34#[derive(Debug, Clone, Copy)]
35pub struct SpectatingEntity(pub specs::Entity);
37
38impl Component for SpectatingEntity {
39 type Storage = specs::DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
43pub enum PresenceKind {
44 Spectator,
45 LoadingCharacter(CharacterId),
49 Character(CharacterId),
50 Possessor,
51}
52
53impl PresenceKind {
54 pub fn controlling_char(&self) -> bool { matches!(self, Self::Character(_) | Self::Possessor) }
58
59 pub fn character_id(&self) -> Option<CharacterId> {
60 if let Self::Character(character_id) = self {
61 Some(*character_id)
62 } else {
63 None
64 }
65 }
66
67 pub fn sync_me(&self) -> bool {
73 match self {
74 Self::Spectator | Self::LoadingCharacter(_) => false,
75 Self::Character(_) | Self::Possessor => true,
76 }
77 }
78}
79
80#[derive(PartialEq, Debug, Clone, Copy)]
81enum Direction {
82 Up,
83 Down,
84}
85
86#[derive(Debug, Clone, Copy)]
94pub struct ViewDistance {
95 direction: Direction,
96 last_direction_change_time: Instant,
97 target: Option<u32>,
98 current: u32,
99}
100
101impl ViewDistance {
102 const TIME_PER_DIR_CHANGE: Duration = Duration::from_millis(300);
104
105 pub fn new(start_value: u32, now: Instant) -> Self {
106 Self {
107 direction: Direction::Up,
108 last_direction_change_time: now.checked_sub(Self::TIME_PER_DIR_CHANGE).unwrap_or(now),
109 target: None,
110 current: start_value,
111 }
112 }
113
114 pub fn current(&self) -> u32 { self.current }
116
117 pub fn update(&mut self, now: Instant) {
120 if let Some(target_val) = self.target {
121 if now.saturating_duration_since(self.last_direction_change_time)
122 > Self::TIME_PER_DIR_CHANGE
123 {
124 self.last_direction_change_time = now;
125 self.current = target_val;
126 self.target = None;
127 }
128 }
129 }
130
131 pub fn set_target(&mut self, new_target: u32, now: Instant) {
138 use core::cmp::Ordering;
139 let new_direction = match new_target.cmp(&self.current) {
140 Ordering::Equal => return, Ordering::Less => Direction::Down,
142 Ordering::Greater => Direction::Up,
143 };
144
145 if new_direction == self.direction {
147 self.current = new_target;
148 self.target = None;
149 } else if now.saturating_duration_since(self.last_direction_change_time)
152 > Self::TIME_PER_DIR_CHANGE
153 {
154 self.direction = new_direction;
155 self.last_direction_change_time = now;
156 self.current = new_target;
157 self.target = None;
158 } else {
160 self.target = Some(new_target);
161 }
162 }
163}