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(CapsulePrism),
123    Point,
124}
125
126#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
127pub struct CapsulePrism {
128    pub p0: Vec2<f32>,
129    pub p1: Vec2<f32>,
130    pub radius: f32,
131    pub z_min: f32,
132    pub z_max: f32,
133}
134
135impl Collider {
136    pub fn is_voxel(&self) -> bool { matches!(self, Collider::Voxel { .. } | Collider::Volume(_)) }
137
138    pub fn get_vol<'a>(&'a self, ship_spec: &'a ShipSpec) -> Option<&'a VoxelCollider> {
139        match self {
140            Collider::Voxel { id } => ship_spec.colliders.get(id),
141            Collider::Volume(vol) => Some(&**vol),
142            _ => None,
143        }
144    }
145
146    pub fn bounding_radius(&self) -> f32 {
147        match self {
148            Collider::Voxel { .. } | Collider::Volume(_) => 1.0,
149            Collider::CapsulePrism(CapsulePrism { radius, p0, p1, .. }) => {
150                let a = p0.distance(*p1);
151                a / 2.0 + *radius
152            },
153            Collider::Point => 0.0,
154        }
155    }
156
157    pub fn get_height(&self) -> f32 {
158        let (z_min, z_max) = self.get_z_limits(1.0);
159        z_max - z_min
160    }
161
162    pub fn get_z_limits(&self, modifier: f32) -> (f32, f32) {
163        match self {
164            Collider::Voxel { .. } | Collider::Volume(_) => (0.0, 2.0),
165            Collider::CapsulePrism(CapsulePrism { z_min, z_max, .. }) => {
166                (*z_min * modifier, *z_max * modifier)
167            },
168            Collider::Point => (0.0, 0.0),
169        }
170    }
171}
172
173impl Component for Collider {
174    type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
175}
176
177#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
178pub struct Sticky;
179
180impl Component for Sticky {
181    type Storage = DerefFlaggedStorage<Self, NullStorage<Self>>;
182}
183
184#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
185pub struct Immovable;
186
187impl Component for Immovable {
188    type Storage = DerefFlaggedStorage<Self, NullStorage<Self>>;
189}
190
191// PhysicsState
192#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
193pub struct PhysicsState {
194    pub on_ground: Option<Block>,
195    pub on_ceiling: bool,
196    pub on_wall: Option<Vec3<f32>>,
197    pub touch_entities: HashMap<Uid, Vec3<f32>>,
198    pub in_fluid: Option<Fluid>,
199    pub ground_vel: Vec3<f32>,
200    pub footwear: Friction,
201    pub skating_last_height: f32,
202    pub skating_active: bool,
203}
204
205impl PhysicsState {
206    pub fn reset(&mut self) {
207        // Avoid allocation overhead!
208        let mut touch_entities = std::mem::take(&mut self.touch_entities);
209        touch_entities.clear();
210        *self = Self {
211            touch_entities,
212            ground_vel: self.ground_vel, /* Preserved, since it's the velocity of the last
213                                          * contact point */
214            ..Self::default()
215        }
216    }
217
218    pub fn on_surface(&self) -> Option<Vec3<f32>> {
219        self.on_ground
220            .map(|_| -Vec3::unit_z())
221            .or_else(|| self.on_ceiling.then_some(Vec3::unit_z()))
222            .or(self.on_wall)
223    }
224
225    pub fn in_liquid(&self) -> Option<f32> { self.in_fluid.and_then(|fluid| fluid.depth()) }
226}
227
228impl Component for PhysicsState {
229    type Storage = VecStorage<Self>;
230}
231
232/// Used to forcefully update the position, velocity, and orientation of the
233/// client
234#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
235pub struct ForceUpdate {
236    flag: bool,
237    counter: u64,
238}
239
240impl ForceUpdate {
241    pub fn forced() -> Self {
242        Self {
243            flag: true,
244            counter: 0,
245        }
246    }
247
248    pub fn update(&mut self) {
249        self.flag = true;
250        self.counter = self.counter.wrapping_add(1);
251    }
252
253    pub fn clear(&mut self) { self.flag = false; }
254
255    pub fn is_forced(&self) -> bool { self.flag }
256
257    pub fn counter(&self) -> u64 { self.counter }
258}
259
260impl Component for ForceUpdate {
261    type Storage = VecStorage<Self>;
262}