veloren_server/events/
mounting.rs1#[cfg(feature = "worldgen")] use std::sync::Arc;
2
3use common::{
4 comp::{self, pet::is_mountable},
5 consts::{MAX_MOUNT_RANGE, MAX_SPRITE_MOUNT_RANGE},
6 event::MountEvent,
7 link::Is,
8 mounting::{Mounting, Rider, VolumeMounting, VolumePos, VolumeRider},
9 uid::Uid,
10};
11#[cfg(feature = "worldgen")]
12use common::{rtsim::RtSimEntity, uid::IdMaps};
13use specs::{Entity as EcsEntity, WorldExt};
14use vek::Vec3;
15
16#[cfg(feature = "worldgen")]
17use crate::rtsim::RtSim;
18use crate::{Server, state_ext::StateExt};
19
20pub fn within_mounting_range(
21 player_position: Option<&comp::Pos>,
22 mount_position: Option<&comp::Pos>,
23) -> bool {
24 match (player_position, mount_position) {
25 (Some(ppos), Some(ipos)) => ppos.0.distance_squared(ipos.0) < MAX_MOUNT_RANGE.powi(2),
26 _ => false,
27 }
28}
29
30pub fn handle_mount(server: &mut Server, event: MountEvent) {
31 match event {
32 MountEvent::MountEntity(rider, mount) => handle_mount_entity(server, rider, mount),
33 MountEvent::MountVolume(rider, mount) => handle_mount_volume(server, rider, mount),
34 MountEvent::Unmount(rider) => handle_unmount(server, rider),
35 }
36}
37
38fn handle_mount_entity(server: &mut Server, rider: EcsEntity, mount: EcsEntity) {
39 let state = server.state_mut();
40
41 let within_range = {
42 let positions = state.ecs().read_storage::<comp::Pos>();
43 within_mounting_range(positions.get(rider), positions.get(mount))
44 };
45
46 if within_range {
47 let uids = state.ecs().read_storage::<Uid>();
48 if let (Some(rider_uid), Some(mount_uid)) =
49 (uids.get(rider).copied(), uids.get(mount).copied())
50 {
51 let is_pet_of = |mount, rider_uid| {
52 matches!(
53 state
54 .ecs()
55 .read_storage::<comp::Alignment>()
56 .get(mount),
57 Some(comp::Alignment::Owned(owner)) if *owner == rider_uid,
58 )
59 };
60
61 let can_ride = state
62 .ecs()
63 .read_storage()
64 .get(mount)
65 .zip(state.ecs().read_storage().get(mount))
66 .is_some_and(|(mount_body, mount_mass)| {
67 is_mountable(
68 mount_body,
69 mount_mass,
70 state.ecs().read_storage().get(rider),
71 state.ecs().read_storage().get(rider),
72 )
73 });
74
75 let is_stay = state
76 .ecs()
77 .read_storage::<comp::Agent>()
78 .get(mount)
79 .and_then(|x| x.stay_pos)
80 .is_some();
81
82 if (is_pet_of(mount, rider_uid) || is_pet_of(rider, mount_uid)) && can_ride && !is_stay
83 {
84 drop(uids);
85 let _ = state.link(Mounting {
86 mount: mount_uid,
87 rider: rider_uid,
88 });
89 }
90 }
91 }
92}
93
94fn handle_mount_volume(server: &mut Server, rider: EcsEntity, volume_pos: VolumePos) {
95 let state = server.state_mut();
96
97 let mount_mat = volume_pos.get_mount_mat(
98 &state.terrain(),
99 &state.ecs().read_resource(),
100 |e| {
101 state
102 .read_storage()
103 .get(e)
104 .copied()
105 .zip(state.read_storage().get(e).copied())
106 },
107 &state.read_storage(),
108 );
109
110 if let Some((mat, block)) = mount_mat {
111 let mount_pos = mat.mul_point(Vec3::zero());
112 let within_range = {
113 let positions = state.ecs().read_storage::<comp::Pos>();
114 positions.get(rider).is_some_and(|pos| {
115 pos.0.distance_squared(mount_pos) < MAX_SPRITE_MOUNT_RANGE.powi(2)
116 })
117 };
118
119 let maybe_uid = state.ecs().read_storage::<Uid>().get(rider).copied();
120
121 if let Some(rider) = maybe_uid
122 && within_range
123 {
124 let _link_successful = state
125 .link(VolumeMounting {
126 pos: volume_pos,
127 block,
128 rider,
129 })
130 .is_ok();
131 #[cfg(feature = "worldgen")]
132 if _link_successful {
133 let uid_allocator = state.ecs().read_resource::<IdMaps>();
134 if let Some(rider_entity) = uid_allocator.uid_entity(rider)
135 && let Some(rider_actor) = state.entity_as_actor(rider_entity)
136 && let Some(volume_pos) = volume_pos.try_map_entity(|uid| {
137 let entity = uid_allocator.uid_entity(uid)?;
138 state.read_storage::<RtSimEntity>().get(entity).map(|v| v.0)
139 })
140 {
141 state
142 .ecs()
143 .write_resource::<RtSim>()
144 .hook_character_mount_volume(
145 &state.ecs().read_resource::<Arc<world::World>>(),
146 state
147 .ecs()
148 .read_resource::<world::IndexOwned>()
149 .as_index_ref(),
150 volume_pos,
151 rider_actor,
152 );
153 }
154 }
155 }
156 }
157}
158
159fn handle_unmount(server: &mut Server, rider: EcsEntity) {
160 let state = server.state_mut();
161 state.ecs().write_storage::<Is<Rider>>().remove(rider);
162 state.ecs().write_storage::<Is<VolumeRider>>().remove(rider);
163}