veloren_server/sys/msg/
gizmos.rs1use common::{
2 CachedSpatialGrid,
3 comp::{
4 self, GizmoSubscriber,
5 gizmos::{GizmoSubscription, Gizmos},
6 },
7 uid::IdMaps,
8};
9use common_ecs::{Job, Origin, Phase, System};
10use common_net::msg::ServerGeneral;
11use specs::{Entity, Join, Read, ReadExpect, ReadStorage, shred};
12use vek::{Rgb, Rgba};
13
14use crate::client::Client;
15
16#[derive(specs::SystemData)]
17pub struct ReadData<'a> {
18 id_maps: Read<'a, IdMaps>,
19 spatial_grid: ReadExpect<'a, CachedSpatialGrid>,
20 subscribers: ReadStorage<'a, GizmoSubscriber>,
21 agents: ReadStorage<'a, comp::Agent>,
22 position: ReadStorage<'a, comp::Pos>,
23 client: ReadStorage<'a, Client>,
24}
25
26#[derive(Default)]
27pub struct Sys;
28
29impl<'a> System<'a> for Sys {
30 type SystemData = ReadData<'a>;
31
32 const NAME: &'static str = "msg::gizmos";
33 const ORIGIN: Origin = Origin::Server;
34 const PHASE: Phase = Phase::Create;
35
36 fn run(_job: &mut Job<Self>, data: Self::SystemData) {
37 for (subscriber, client, pos) in (&data.subscribers, &data.client, &data.position).join() {
38 let mut gizmos = Vec::new();
39 for (kind, target) in subscriber.gizmos.iter() {
40 match target {
41 comp::gizmos::GizmoContext::Disabled => {},
42 comp::gizmos::GizmoContext::Enabled => {
43 gizmos_for(&mut gizmos, kind, *pos, subscriber.range, &data);
44 },
45 comp::gizmos::GizmoContext::EnabledWithTarget(uid) => {
46 if let Some(target) = data.id_maps.uid_entity(*uid) {
47 gizmos_for_target(&mut gizmos, kind, target, subscriber.range, &data)
48 }
49 },
50 }
51 }
52
53 if !gizmos.is_empty() {
54 client.send_fallible(ServerGeneral::Gizmos(gizmos));
55 }
56 }
57 }
58}
59
60fn pathfind_gizmos(gizmos: &mut Vec<Gizmos>, agent: &comp::Agent) {
61 if let Some(route) = agent.chaser.get_route() {
62 if let Some(traversed) = route
63 .get_path()
64 .nodes
65 .get(..route.next_idx())
66 .filter(|n| n.len() >= 2)
67 {
68 gizmos.push(Gizmos::line_strip(
69 traversed.iter().map(|p| p.as_() + 0.5).collect(),
70 Rgba::new(255, 255, 255, 100),
71 ));
72 }
73 if let Some(to_traverse) = route
74 .get_path()
75 .nodes
76 .get(route.next_idx().saturating_sub(1)..)
77 .filter(|n| n.len() >= 2)
78 {
79 gizmos.push(Gizmos::line_strip(
80 to_traverse.iter().map(|p| p.as_() + 0.5).collect(),
81 Rgb::red(),
82 ));
83 }
84 }
85 if let Some(target) = agent.chaser.last_target() {
86 gizmos.push(Gizmos::sphere(target, 0.3, Rgba::new(255, 0, 0, 200)));
87 }
88}
89
90fn gizmos_for_target(
91 gizmos: &mut Vec<Gizmos>,
92 subscription: GizmoSubscription,
93 target: Entity,
94 _range: f32,
95 data: &ReadData,
96) {
97 match subscription {
98 GizmoSubscription::PathFinding => {
99 if let Some(agent) = data.agents.get(target) {
100 pathfind_gizmos(gizmos, agent);
101 }
102 },
103 }
104}
105
106fn gizmos_for(
107 gizmos: &mut Vec<Gizmos>,
108 subscription: GizmoSubscription,
109 pos: comp::Pos,
110 range: f32,
111 data: &ReadData,
112) {
113 match subscription {
114 GizmoSubscription::PathFinding => {
115 for target in data.spatial_grid.0.in_circle_aabr(pos.0.xy(), range) {
116 gizmos_for_target(gizmos, subscription, target, range, data);
117 }
118 },
119 }
120}