veloren_server/sys/
object.rs1use common::{
2 CachedSpatialGrid,
3 comp::{Body, Object, Pos, Teleporting, object},
4 consts::TELEPORTER_RADIUS,
5 event::{ChangeBodyEvent, DeleteEvent, EmitExt, EventBus, ExplosionEvent, ShootEvent},
6 event_emitters,
7 outcome::Outcome,
8 resources::{DeltaTime, Time},
9};
10use common_ecs::{Job, Origin, Phase, System};
11use specs::{Entities, Join, LendJoin, Read, ReadStorage};
12
13event_emitters! {
14 struct Events[Emitters] {
15 delete: DeleteEvent,
16 explosion: ExplosionEvent,
17 shoot: ShootEvent,
18 change_body: ChangeBodyEvent,
19 }
20}
21
22#[derive(Default)]
24pub struct Sys;
25impl<'a> System<'a> for Sys {
26 type SystemData = (
27 Entities<'a>,
28 Events<'a>,
29 Read<'a, DeltaTime>,
30 Read<'a, Time>,
31 Read<'a, EventBus<Outcome>>,
32 Read<'a, CachedSpatialGrid>,
33 ReadStorage<'a, Pos>,
34 ReadStorage<'a, Object>,
35 ReadStorage<'a, Body>,
36 ReadStorage<'a, Teleporting>,
37 );
38
39 const NAME: &'static str = "object";
40 const ORIGIN: Origin = Origin::Server;
41 const PHASE: Phase = Phase::Create;
42
43 fn run(
44 _job: &mut Job<Self>,
45 (
46 entities,
47 events,
48 _dt,
49 time,
50 outcome_bus,
51 spatial_grid,
52 positions,
53 objects,
54 bodies,
55 teleporting,
56 ): Self::SystemData,
57 ) {
58 let mut emitters = events.get_emitters();
59
60 for (entity, pos, object, body) in (&entities, &positions, &objects, bodies.maybe()).join()
62 {
63 match object {
64 Object::DeleteAfter {
65 spawned_at,
66 timeout,
67 } => {
68 if (time.0 - spawned_at.0).max(0.0) > timeout.as_secs_f64() {
69 emitters.emit(DeleteEvent(entity));
70 }
71 },
72 Object::Portal { .. } => {
73 let is_active = spatial_grid
74 .0
75 .in_circle_aabr(pos.0.xy(), TELEPORTER_RADIUS)
76 .any(|entity| {
77 (&positions, &teleporting)
78 .lend_join()
79 .get(entity, &entities)
80 .is_some_and(|(teleporter_pos, _)| {
81 pos.0.distance_squared(teleporter_pos.0)
82 <= TELEPORTER_RADIUS.powi(2)
83 })
84 });
85
86 if body.is_some_and(|body| {
87 (*body == Body::Object(object::Body::PortalActive)) != is_active
88 }) {
89 emitters.emit(ChangeBodyEvent {
90 entity,
91 new_body: Body::Object(if is_active {
92 outcome_bus.emit_now(Outcome::PortalActivated { pos: pos.0 });
93 object::Body::PortalActive
94 } else {
95 object::Body::Portal
96 }),
97 });
98 }
99 },
100 }
101 }
102 }
103}