veloren_voxygen/ecs/sys/
interpolation.rs

1use crate::ecs::comp::Interpolated;
2use common::{
3    comp::{Body, Ori, Pos, Vel, object},
4    resources::DeltaTime,
5};
6use common_ecs::{Job, Origin, Phase, System};
7use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
8use tracing::warn;
9use vek::*;
10
11/// This system will allow NPCs to modify their controller
12#[derive(Default)]
13pub struct Sys;
14impl<'a> System<'a> for Sys {
15    type SystemData = (
16        Entities<'a>,
17        Read<'a, DeltaTime>,
18        ReadStorage<'a, Pos>,
19        ReadStorage<'a, Ori>,
20        ReadStorage<'a, Vel>,
21        ReadStorage<'a, Body>,
22        WriteStorage<'a, Interpolated>,
23    );
24
25    const NAME: &'static str = "interpolation";
26    const ORIGIN: Origin = Origin::Frontend("voxygen");
27    const PHASE: Phase = Phase::Create;
28
29    fn run(
30        _job: &mut Job<Self>,
31        (entities, dt, positions, orientations, velocities, bodies, mut interpolated): Self::SystemData,
32    ) {
33        // Update interpolated positions and orientations
34        for (pos, ori, i, body, vel) in (
35            &positions,
36            &orientations,
37            &mut interpolated,
38            &bodies,
39            &velocities,
40        )
41            .join()
42        {
43            // Update interpolation values, but don't interpolate far things or objects
44            if i.pos.distance_squared(pos.0) < 64.0 * 64.0 && !matches!(body, Body::Object(_)) {
45                // Note, these values are specifically tuned for smoother motion with high
46                // network latency or low network sampling rate and for smooth
47                // block hopping (which is instantaneous)
48                const POS_LERP_RATE_FACTOR: f32 = 10.0;
49                i.pos = Lerp::lerp(i.pos, pos.0 + vel.0 * 0.03, POS_LERP_RATE_FACTOR * dt.0);
50                i.ori = Ori::slerp(i.ori, *ori, base_ori_interp(body) * dt.0);
51            } else {
52                i.pos = pos.0;
53                i.ori = *ori;
54            }
55        }
56        // Insert interpolation components for entities which don't have them
57        for (entity, pos, ori) in (&entities, &positions, &orientations, !&interpolated)
58            .join()
59            .map(|(e, p, o, _)| (e, p.0, *o))
60            .collect::<Vec<_>>()
61        {
62            interpolated
63                .insert(entity, Interpolated { pos, ori })
64                .err()
65                .map(|e| warn!(?e, "Error inserting Interpolated component"));
66        }
67        // Remove Interpolated component from entities which don't have a position or an
68        // orientation or a velocity
69        for entity in (&entities, !&positions, &interpolated)
70            .join()
71            .map(|(e, _, _)| e)
72            .collect::<Vec<_>>()
73        {
74            interpolated.remove(entity);
75        }
76        for entity in (&entities, !&orientations, &interpolated)
77            .join()
78            .map(|(e, _, _)| e)
79            .collect::<Vec<_>>()
80        {
81            interpolated.remove(entity);
82        }
83        for entity in (&entities, !&velocities, &interpolated)
84            .join()
85            .map(|(e, _, _)| e)
86            .collect::<Vec<_>>()
87        {
88            interpolated.remove(entity);
89        }
90    }
91}
92
93fn base_ori_interp(body: &Body) -> f32 {
94    match body {
95        Body::Object(
96            object::Body::Crossbow
97            | object::Body::Flamethrower
98            | object::Body::Lavathrower
99            | object::Body::HaniwaSentry
100            | object::Body::TerracottaStatue
101            | object::Body::MinotaurAxe,
102        ) => 100.0,
103        _ => 10.0,
104    }
105}