veloren_server/sys/
pets.rs1use common::{
2 comp::{Agent, Alignment, Pet, PhysicsState, Pos},
3 terrain::TerrainGrid,
4 uid::IdMaps,
5};
6use common_ecs::{Job, Origin, Phase, System};
7use specs::{Entities, Entity, Join, Read, ReadExpect, ReadStorage, WriteStorage};
8
9#[derive(Default)]
11pub struct Sys;
12impl<'a> System<'a> for Sys {
13 type SystemData = (
14 Entities<'a>,
15 ReadExpect<'a, TerrainGrid>,
16 WriteStorage<'a, Pos>,
17 ReadStorage<'a, Alignment>,
18 ReadStorage<'a, Pet>,
19 ReadStorage<'a, Agent>,
20 ReadStorage<'a, PhysicsState>,
21 Read<'a, IdMaps>,
22 );
23
24 const NAME: &'static str = "pets";
25 const ORIGIN: Origin = Origin::Server;
26 const PHASE: Phase = Phase::Create;
27
28 fn run(
29 _job: &mut Job<Self>,
30 (entities, terrain, mut positions, alignments, pets, agn, physics, id_maps): Self::SystemData,
31 ) {
32 const LOST_PET_DISTANCE_THRESHOLD: f32 = 200.0;
33
34 let lost_pets: Vec<(Entity, Pos)> = (&entities, &positions, &alignments, &pets)
36 .join()
37 .filter_map(|(entity, pos, alignment, _)| match alignment {
38 Alignment::Owned(owner_uid) => Some((entity, pos, *owner_uid)),
39 _ => None,
40 })
41 .filter_map(|(pet_entity, pet_pos, owner_uid)| {
42 id_maps.uid_entity(owner_uid).and_then(|owner_entity| {
43 match (positions.get(owner_entity), physics.get(owner_entity)) {
44 (Some(position), Some(physics)) => {
45 Some((pet_entity, position, physics, pet_pos))
46 },
47 _ => None,
48 }
49 })
50 })
51 .filter(|(_, owner_pos, owner_physics, pet_pos)| {
52 owner_physics.on_ground.is_some()
55 && owner_pos.0.distance_squared(pet_pos.0) > LOST_PET_DISTANCE_THRESHOLD.powi(2)
56 })
57 .map(|(entity, owner_pos, _, _)| (entity, *owner_pos))
58 .collect();
59
60 for (pet_entity, owner_pos) in lost_pets.iter() {
61 let stay = agn.get(*pet_entity).and_then(|x| x.stay_pos).is_some();
62 if let Some(pet_pos) = positions.get_mut(*pet_entity)
63 && !stay
64 {
65 pet_pos.0 = terrain
69 .find_ground(owner_pos.0.map(|e| e.floor() as i32))
70 .map(|e| e as f32);
71 }
72 }
73 }
74}