1use azalea_block::{Block, BlockState};
2use azalea_core::{aabb::AABB, position::Vec3};
3use azalea_entity::{
4 metadata::Sprinting, move_relative, Attributes, InLoadedChunk, Jumping, LocalEntity,
5 LookDirection, OnClimbable, Physics, Pose, Position,
6};
7use azalea_world::{Instance, InstanceContainer, InstanceName};
8use bevy_ecs::prelude::*;
9
10use crate::{
11 collision::{move_colliding, MoverType},
12 get_block_pos_below_that_affects_movement, handle_relative_friction_and_calculate_movement,
13 HandleRelativeFrictionAndCalculateMovementOpts,
14};
15
16#[allow(clippy::type_complexity)]
19pub fn travel(
20 mut query: Query<
21 (
22 &mut Physics,
23 &mut LookDirection,
24 &mut Position,
25 Option<&Sprinting>,
26 Option<&Pose>,
27 &Attributes,
28 &InstanceName,
29 &OnClimbable,
30 &Jumping,
31 ),
32 (With<LocalEntity>, With<InLoadedChunk>),
33 >,
34 instance_container: Res<InstanceContainer>,
35) {
36 for (
37 mut physics,
38 direction,
39 position,
40 sprinting,
41 pose,
42 attributes,
43 world_name,
44 on_climbable,
45 jumping,
46 ) in &mut query
47 {
48 let Some(world_lock) = instance_container.get(world_name) else {
49 continue;
50 };
51 let world = world_lock.read();
52
53 let sprinting = *sprinting.unwrap_or(&Sprinting(false));
54
55 if physics.is_in_water() || physics.is_in_lava() {
58 travel_in_fluid(
62 &mut physics,
63 &direction,
64 position,
65 attributes,
66 sprinting,
67 on_climbable,
68 &world,
69 );
70 } else {
71 travel_in_air(
72 &mut physics,
73 &direction,
74 position,
75 attributes,
76 sprinting,
77 on_climbable,
78 pose,
79 jumping,
80 &world,
81 );
82 }
83 }
84}
85
86#[allow(clippy::too_many_arguments)]
88fn travel_in_air(
89 physics: &mut Physics,
90 direction: &LookDirection,
91 position: Mut<Position>,
92 attributes: &Attributes,
93 sprinting: Sprinting,
94 on_climbable: &OnClimbable,
95 pose: Option<&Pose>,
96 jumping: &Jumping,
97 world: &Instance,
98) {
99 let gravity = get_effective_gravity();
100
101 let block_pos_below = get_block_pos_below_that_affects_movement(&position);
102
103 let block_state_below = world
104 .chunks
105 .get_block_state(&block_pos_below)
106 .unwrap_or(BlockState::AIR);
107 let block_below: Box<dyn Block> = block_state_below.into();
108 let block_friction = block_below.behavior().friction;
109
110 let inertia = if physics.on_ground() {
111 block_friction * 0.91
112 } else {
113 0.91
114 };
115
116 let mut movement = handle_relative_friction_and_calculate_movement(
118 HandleRelativeFrictionAndCalculateMovementOpts {
119 block_friction,
120 world,
121 physics,
122 direction,
123 position,
124 attributes,
125 is_sprinting: *sprinting,
126 on_climbable,
127 pose,
128 jumping,
129 },
130 );
131
132 movement.y -= gravity;
133
134 if false {
142 physics.velocity = movement;
143 } else {
144 physics.velocity = Vec3 {
145 x: movement.x * inertia as f64,
146 y: movement.y * 0.9800000190734863f64,
147 z: movement.z * inertia as f64,
148 };
149 }
150}
151
152fn travel_in_fluid(
153 physics: &mut Physics,
154 direction: &LookDirection,
155 mut position: Mut<Position>,
156 attributes: &Attributes,
157 sprinting: Sprinting,
158 on_climbable: &OnClimbable,
159 world: &Instance,
160) {
161 let moving_down = physics.velocity.y <= 0.;
162 let y = position.y;
163 let gravity = get_effective_gravity();
164
165 let acceleration = Vec3::new(
166 physics.x_acceleration as f64,
167 physics.y_acceleration as f64,
168 physics.z_acceleration as f64,
169 );
170
171 if physics.was_touching_water {
172 let mut water_movement_speed = if *sprinting { 0.9 } else { 0.8 };
173 let mut speed = 0.02;
174 let mut water_efficiency_modifier = attributes.water_movement_efficiency.calculate() as f32;
175 if !physics.on_ground() {
176 water_efficiency_modifier *= 0.5;
177 }
178
179 if water_efficiency_modifier > 0. {
180 water_movement_speed += (0.54600006 - water_movement_speed) * water_efficiency_modifier;
181 speed += (attributes.speed.calculate() as f32 - speed) * water_efficiency_modifier;
182 }
183
184 move_relative(physics, direction, speed, &acceleration);
189 move_colliding(
190 MoverType::Own,
191 &physics.velocity.clone(),
192 world,
193 &mut position,
194 physics,
195 )
196 .expect("Entity should exist");
197
198 let mut new_velocity = physics.velocity;
199 if physics.horizontal_collision && **on_climbable {
200 new_velocity.y = 0.2;
202 }
203 new_velocity.x *= water_movement_speed as f64;
204 new_velocity.y *= 0.8;
205 new_velocity.z *= water_movement_speed as f64;
206 physics.velocity =
207 get_fluid_falling_adjusted_movement(gravity, moving_down, new_velocity, sprinting);
208 } else {
209 move_relative(physics, direction, 0.02, &acceleration);
210 move_colliding(
211 MoverType::Own,
212 &physics.velocity.clone(),
213 world,
214 &mut position,
215 physics,
216 )
217 .expect("Entity should exist");
218
219 if physics.lava_fluid_height <= fluid_jump_threshold() {
220 physics.velocity.x *= 0.5;
221 physics.velocity.y *= 0.8;
222 physics.velocity.z *= 0.5;
223 let new_velocity = get_fluid_falling_adjusted_movement(
224 gravity,
225 moving_down,
226 physics.velocity,
227 sprinting,
228 );
229 physics.velocity = new_velocity;
230 } else {
231 physics.velocity *= 0.5;
232 }
233
234 if gravity != 0.0 {
235 physics.velocity.y -= gravity / 4.0;
236 }
237 }
238
239 let velocity = physics.velocity;
240 if physics.horizontal_collision
241 && is_free(
242 physics.bounding_box,
243 world,
244 velocity.x,
245 velocity.y + 0.6 - position.y + y,
246 velocity.z,
247 )
248 {
249 physics.velocity.y = 0.3;
250 }
251}
252
253fn get_fluid_falling_adjusted_movement(
254 gravity: f64,
255 moving_down: bool,
256 new_velocity: Vec3,
257 sprinting: Sprinting,
258) -> Vec3 {
259 if gravity != 0. && !*sprinting {
260 let new_y_velocity = if moving_down
261 && (new_velocity.y - 0.005).abs() >= 0.003
262 && f64::abs(new_velocity.y - gravity / 16.0) < 0.003
263 {
264 -0.003
265 } else {
266 new_velocity.y - gravity / 16.0
267 };
268
269 Vec3 {
270 x: new_velocity.x,
271 y: new_y_velocity,
272 z: new_velocity.z,
273 }
274 } else {
275 new_velocity
276 }
277}
278
279fn is_free(bounding_box: AABB, world: &Instance, x: f64, y: f64, z: f64) -> bool {
280 let _ = (bounding_box, world, x, y, z);
283
284 true
287}
288
289fn get_effective_gravity() -> f64 {
290 0.08
292}
293
294pub fn fluid_jump_threshold() -> f64 {
295 0.4
299}