veloren_common/comp/
phys.rs

1use super::{Fluid, Ori, ship::figuredata::ShipSpec};
2use crate::{
3    comp::{body::ship::figuredata::VoxelCollider, inventory::item::armor::Friction},
4    consts::WATER_DENSITY,
5    terrain::Block,
6    uid::Uid,
7    util::Dir,
8};
9use hashbrown::HashMap;
10use serde::{Deserialize, Serialize};
11use specs::{Component, DerefFlaggedStorage, NullStorage, VecStorage};
12use std::sync::Arc;
13use vek::*;
14
15/// Position
16#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
17pub struct Pos(pub Vec3<f32>);
18
19impl Component for Pos {
20    type Storage = VecStorage<Self>;
21}
22
23/// Velocity
24#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
25pub struct Vel(pub Vec3<f32>);
26
27impl Vel {
28    pub fn zero() -> Self { Vel(Vec3::zero()) }
29
30    pub fn to_dir(&self) -> Dir { Dir::from_unnormalized(self.0).unwrap_or_default() }
31}
32
33impl Component for Vel {
34    type Storage = VecStorage<Self>;
35}
36
37/// Used to defer writes to Pos/Vel in nested join loops
38#[derive(Copy, Clone, Debug)]
39pub struct PosVelOriDefer {
40    pub pos: Option<Pos>,
41    pub vel: Option<Vel>,
42    pub ori: Option<Ori>,
43}
44
45impl Component for PosVelOriDefer {
46    type Storage = VecStorage<Self>;
47}
48
49/// Cache of Velocity (of last tick) * dt (of curent tick)
50/// It's updated and read in physics sys to speed up entity<->entity collisions
51/// no need to send it via network
52#[derive(Copy, Clone, Default, Debug, PartialEq)]
53pub struct PreviousPhysCache {
54    pub velocity: Vec3<f32>,
55    pub velocity_dt: Vec3<f32>,
56    pub in_fluid: Option<Fluid>,
57    /// Center of bounding sphere that encompasses the entity along its path for
58    /// this tick
59    pub center: Vec3<f32>,
60    /// Calculates a Sphere over the Entity for quick boundary checking
61    pub collision_boundary: f32,
62    pub scale: f32,
63    /// Approximate radius of cylinder of collider.
64    pub scaled_radius: f32,
65    /// Radius of stadium of collider.
66    pub neighborhood_radius: f32,
67    /// relative p0 and p1 of collider's statium, None if cylinder.
68    pub origins: Option<(Vec2<f32>, Vec2<f32>)>,
69    pub pos: Option<Pos>,
70    pub ori: Quaternion<f32>,
71}
72
73impl Component for PreviousPhysCache {
74    type Storage = VecStorage<Self>;
75}
76
77// Scale
78#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
79pub struct Scale(pub f32);
80
81impl Component for Scale {
82    type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
83}
84
85// Mass
86#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
87pub struct Mass(pub f32);
88
89impl Default for Mass {
90    fn default() -> Mass { Mass(1.0) }
91}
92
93impl Component for Mass {
94    type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
95}
96
97/// The average density (specific mass) of an entity.
98/// Units used for reference is kg/m³
99#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
100pub struct Density(pub f32);
101
102impl Default for Density {
103    fn default() -> Density { Density(WATER_DENSITY) }
104}
105
106impl Component for Density {
107    type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
108}
109
110// Collider
111#[derive(Clone, Debug, Serialize, Deserialize)]
112pub enum Collider {
113    /// A volume based on an existing voxel asset.
114    // TODO: pass the map from ids -> voxel data to get_radius
115    // and get_z_limits to compute a bounding cylinder.
116    Voxel {
117        id: String,
118    },
119    /// A mutable volume.
120    Volume(Arc<VoxelCollider>),
121    /// Capsule prism with line segment from p0 to p1
122    CapsulePrism {
123        p0: Vec2<f32>,
124        p1: Vec2<f32>,
125        radius: f32,
126        z_min: f32,
127        z_max: f32,
128    },
129    Point,
130}
131
132impl Collider {
133    pub fn is_voxel(&self) -> bool { matches!(self, Collider::Voxel { .. } | Collider::Volume(_)) }
134
135    pub fn get_vol<'a>(&'a self, ship_spec: &'a ShipSpec) -> Option<&'a VoxelCollider> {
136        match self {
137            Collider::Voxel { id } => ship_spec.colliders.get(id),
138            Collider::Volume(vol) => Some(&**vol),
139            _ => None,
140        }
141    }
142
143    pub fn bounding_radius(&self) -> f32 {
144        match self {
145            Collider::Voxel { .. } | Collider::Volume(_) => 1.0,
146            Collider::CapsulePrism { radius, p0, p1, .. } => {
147                let a = p0.distance(*p1);
148                a / 2.0 + *radius
149            },
150            Collider::Point => 0.0,
151        }
152    }
153
154    pub fn get_height(&self) -> f32 {
155        let (z_min, z_max) = self.get_z_limits(1.0);
156        z_max - z_min
157    }
158
159    pub fn get_z_limits(&self, modifier: f32) -> (f32, f32) {
160        match self {
161            Collider::Voxel { .. } | Collider::Volume(_) => (0.0, 2.0),
162            Collider::CapsulePrism { z_min, z_max, .. } => (*z_min * modifier, *z_max * modifier),
163            Collider::Point => (0.0, 0.0),
164        }
165    }
166}
167
168impl Component for Collider {
169    type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
170}
171
172#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
173pub struct Sticky;
174
175impl Component for Sticky {
176    type Storage = DerefFlaggedStorage<Self, NullStorage<Self>>;
177}
178
179#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
180pub struct Immovable;
181
182impl Component for Immovable {
183    type Storage = DerefFlaggedStorage<Self, NullStorage<Self>>;
184}
185
186// PhysicsState
187#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
188pub struct PhysicsState {
189    pub on_ground: Option<Block>,
190    pub on_ceiling: bool,
191    pub on_wall: Option<Vec3<f32>>,
192    pub touch_entities: HashMap<Uid, Vec3<f32>>,
193    pub in_fluid: Option<Fluid>,
194    pub ground_vel: Vec3<f32>,
195    pub footwear: Friction,
196    pub skating_last_height: f32,
197    pub skating_active: bool,
198}
199
200impl PhysicsState {
201    pub fn reset(&mut self) {
202        // Avoid allocation overhead!
203        let mut touch_entities = std::mem::take(&mut self.touch_entities);
204        touch_entities.clear();
205        *self = Self {
206            touch_entities,
207            ground_vel: self.ground_vel, /* Preserved, since it's the velocity of the last
208                                          * contact point */
209            ..Self::default()
210        }
211    }
212
213    pub fn on_surface(&self) -> Option<Vec3<f32>> {
214        self.on_ground
215            .map(|_| -Vec3::unit_z())
216            .or_else(|| self.on_ceiling.then_some(Vec3::unit_z()))
217            .or(self.on_wall)
218    }
219
220    pub fn in_liquid(&self) -> Option<f32> { self.in_fluid.and_then(|fluid| fluid.depth()) }
221}
222
223impl Component for PhysicsState {
224    type Storage = VecStorage<Self>;
225}
226
227/// Used to forcefully update the position, velocity, and orientation of the
228/// client
229#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
230pub struct ForceUpdate {
231    flag: bool,
232    counter: u64,
233}
234
235impl ForceUpdate {
236    pub fn forced() -> Self {
237        Self {
238            flag: true,
239            counter: 0,
240        }
241    }
242
243    pub fn update(&mut self) {
244        self.flag = true;
245        self.counter = self.counter.wrapping_add(1);
246    }
247
248    pub fn clear(&mut self) { self.flag = false; }
249
250    pub fn is_forced(&self) -> bool { self.flag }
251
252    pub fn counter(&self) -> u64 { self.counter }
253}
254
255impl Component for ForceUpdate {
256    type Storage = VecStorage<Self>;
257}