veloren_server/sys/
waypoint.rs

1use crate::client::Client;
2use common::{
3    comp::{PhysicsState, Player, Pos, Vel, Waypoint, WaypointArea},
4    resources::Time,
5};
6use common_ecs::{Job, Origin, Phase, System};
7use common_net::msg::{Notification, ServerGeneral};
8use specs::{Entities, Join, LendJoin, Read, ReadStorage, WriteStorage};
9
10/// Cooldown time (in seconds) for "Waypoint Saved" notifications
11const NOTIFY_TIME: f64 = 10.0;
12
13/// This system updates player waypoints
14/// TODO: Make this faster by only considering local waypoints
15#[derive(Default)]
16pub struct Sys;
17impl<'a> System<'a> for Sys {
18    type SystemData = (
19        Entities<'a>,
20        ReadStorage<'a, Pos>,
21        ReadStorage<'a, Player>,
22        ReadStorage<'a, WaypointArea>,
23        WriteStorage<'a, Waypoint>,
24        ReadStorage<'a, Client>,
25        Read<'a, Time>,
26        ReadStorage<'a, PhysicsState>,
27        ReadStorage<'a, Vel>,
28    );
29
30    const NAME: &'static str = "waypoint";
31    const ORIGIN: Origin = Origin::Server;
32    const PHASE: Phase = Phase::Create;
33
34    fn run(
35        _job: &mut Job<Self>,
36        (
37            entities,
38            positions,
39            players,
40            waypoint_areas,
41            mut waypoints,
42            clients,
43            time,
44            physics_states,
45            velocities,
46        ): Self::SystemData,
47    ) {
48        for (entity, player_pos, _, client, physics, velocity) in (
49            &entities,
50            &positions,
51            &players,
52            &clients,
53            physics_states.maybe(),
54            &velocities,
55        )
56            .join()
57        {
58            if physics.is_none_or(|ps| ps.on_ground.is_some()) && velocity.0.z >= 0.0 {
59                for (waypoint_pos, waypoint_area) in (&positions, &waypoint_areas).join() {
60                    if player_pos.0.distance_squared(waypoint_pos.0)
61                        < waypoint_area.radius().powi(2)
62                    {
63                        if let Ok(wp_old) =
64                            waypoints.insert(entity, Waypoint::new(player_pos.0, *time))
65                        {
66                            if wp_old.is_none_or(|w| w.elapsed(*time) > NOTIFY_TIME) {
67                                client.send_fallible(ServerGeneral::Notification(
68                                    Notification::WaypointSaved,
69                                ));
70                            }
71                        }
72                    }
73                }
74            }
75        }
76    }
77}