veloren_server/sys/
waypoint.rs1use std::sync::Arc;
2
3use crate::client::Client;
4use common::{
5 comp::{CharacterState, PhysicsState, Player, Pos, Vel, Waypoint, WaypointArea},
6 resources::Time,
7};
8use common_ecs::{Job, Origin, Phase, System};
9use common_net::msg::{Notification, ServerGeneral};
10use specs::{Entities, Join, LendJoin, Read, ReadExpect, ReadStorage, WriteStorage};
11use world::{IndexOwned, World};
12
13const NOTIFY_TIME: f64 = 10.0;
15
16#[derive(Default)]
20pub struct Sys;
21impl<'a> System<'a> for Sys {
22 type SystemData = (
23 Entities<'a>,
24 ReadStorage<'a, Pos>,
25 ReadStorage<'a, Player>,
26 ReadStorage<'a, WaypointArea>,
27 WriteStorage<'a, Waypoint>,
28 ReadStorage<'a, Client>,
29 Read<'a, Time>,
30 ReadStorage<'a, PhysicsState>,
31 ReadStorage<'a, Vel>,
32 ReadExpect<'a, Arc<World>>,
33 ReadExpect<'a, IndexOwned>,
34 ReadStorage<'a, CharacterState>,
35 );
36
37 const NAME: &'static str = "waypoint";
38 const ORIGIN: Origin = Origin::Server;
39 const PHASE: Phase = Phase::Create;
40
41 fn run(
42 _job: &mut Job<Self>,
43 (
44 entities,
45 positions,
46 players,
47 waypoint_areas,
48 mut waypoints,
49 clients,
50 time,
51 physics_states,
52 velocities,
53 world,
54 index,
55 character_states,
56 ): Self::SystemData,
57 ) {
58 for (entity, player_pos, _, client, physics, velocity, character_state) in (
59 &entities,
60 &positions,
61 &players,
62 &clients,
63 physics_states.maybe(),
64 &velocities,
65 &character_states,
66 )
67 .join()
68 {
69 if character_state.is_sitting()
70 && physics.is_none_or(|ps| ps.on_ground.is_some())
71 && velocity.0.z >= 0.0
72 {
73 for (waypoint_pos, waypoint_area) in (&positions, &waypoint_areas).join() {
74 if player_pos.0.distance_squared(waypoint_pos.0)
75 < waypoint_area.radius().powi(2)
76 {
77 if let Ok(wp_old) =
78 waypoints.insert(entity, Waypoint::new(player_pos.0, *time))
79 {
80 if wp_old.is_none_or(|w| w.elapsed(*time) > NOTIFY_TIME) {
81 let location_name = world.get_location_name(
82 index.as_index_ref(),
83 player_pos.0.xy().as_::<i32>(),
84 );
85
86 if let Some(location_name) = location_name {
87 client.send_fallible(ServerGeneral::Notification(
88 Notification::WaypointSaved { location_name },
89 ));
90 }
91 }
92 }
93 }
94 }
95 }
96 }
97 }
98}