1#![doc = include_str!("../README.md")]
2#![allow(clippy::derived_hash_with_manual_eq)]
3
4pub mod attributes;
5mod data;
6pub mod dimensions;
7mod effects;
8pub mod inventory;
9#[cfg(feature = "bevy_ecs")]
10pub mod metadata;
11pub mod mining;
12pub mod particle;
13#[cfg(feature = "bevy_ecs")]
14mod plugin;
15pub mod vec_delta_codec;
16
17use std::{
18 f64::consts::PI,
19 fmt::{self, Debug},
20 hash::{Hash, Hasher},
21};
22
23pub use attributes::Attributes;
24use azalea_block::fluid_state::FluidKind;
25use azalea_buf::AzBuf;
26use azalea_core::{
27 aabb::Aabb,
28 math,
29 position::{BlockPos, ChunkPos, Vec3},
30};
31use azalea_registry::builtin::EntityKind;
32pub use data::*;
33use derive_more::{Deref, DerefMut};
34pub use effects::{ActiveEffects, MobEffectData};
35use uuid::Uuid;
36use vec_delta_codec::VecDeltaCodec;
37
38use self::attributes::AttributeInstance;
39use crate::dimensions::EntityDimensions;
40#[cfg(feature = "bevy_ecs")]
41pub use crate::plugin::*;
42
43pub fn move_relative(
44 physics: &mut Physics,
45 direction: LookDirection,
46 speed: f32,
47 acceleration: Vec3,
48) {
49 let input_vector = input_vector(direction, speed, acceleration);
50 physics.velocity += input_vector;
51}
52
53pub fn input_vector(direction: LookDirection, speed: f32, acceleration: Vec3) -> Vec3 {
54 let distance = acceleration.length_squared();
55 if distance < 1.0e-7 {
56 return Vec3::ZERO;
57 }
58 let acceleration = if distance > 1. {
59 acceleration.normalize()
60 } else {
61 acceleration
62 }
63 .scale(speed as f64);
64 let y_rot = math::sin(direction.y_rot * (PI / 180.) as f32);
65 let x_rot = math::cos(direction.y_rot * (PI / 180.) as f32);
66 Vec3 {
67 x: acceleration.x * (x_rot as f64) - acceleration.z * (y_rot as f64),
68 y: acceleration.y,
69 z: acceleration.z * (x_rot as f64) + acceleration.x * (y_rot as f64),
70 }
71}
72
73pub fn view_vector(look_direction: LookDirection) -> Vec3 {
74 let x_rot = look_direction.x_rot * 0.017453292;
75 let y_rot = -look_direction.y_rot * 0.017453292;
76 let y_rot_cos = math::cos(y_rot);
77 let y_rot_sin = math::sin(y_rot);
78 let x_rot_cos = math::cos(x_rot);
79 let x_rot_sin = math::sin(x_rot);
80 Vec3 {
81 x: (y_rot_sin * x_rot_cos) as f64,
82 y: (-x_rot_sin) as f64,
83 z: (y_rot_cos * x_rot_cos) as f64,
84 }
85}
86
87#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
92#[derive(Clone, Copy, Default, Deref, DerefMut, PartialEq)]
93pub struct EntityUuid(Uuid);
94impl EntityUuid {
95 pub fn new(uuid: Uuid) -> Self {
96 Self(uuid)
97 }
98}
99impl Debug for EntityUuid {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 (self.0).fmt(f)
102 }
103}
104
105#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
113#[derive(Clone, Copy, Debug, Default, Deref, DerefMut, PartialEq)]
114pub struct Position(Vec3);
115impl Position {
116 pub fn new(pos: Vec3) -> Self {
117 Self(pos)
118 }
119}
120impl From<&Position> for Vec3 {
121 fn from(value: &Position) -> Self {
122 value.0
123 }
124}
125impl From<Position> for ChunkPos {
126 fn from(value: Position) -> Self {
127 ChunkPos::from(&value.0)
128 }
129}
130impl From<Position> for BlockPos {
131 fn from(value: Position) -> Self {
132 BlockPos::from(&value.0)
133 }
134}
135impl From<&Position> for ChunkPos {
136 fn from(value: &Position) -> Self {
137 ChunkPos::from(value.0)
138 }
139}
140impl From<&Position> for BlockPos {
141 fn from(value: &Position) -> Self {
142 BlockPos::from(value.0)
143 }
144}
145
146#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
151#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
152pub struct LookDirection {
153 y_rot: f32,
155 x_rot: f32,
157}
158
159impl LookDirection {
160 pub fn new(y_rot: f32, x_rot: f32) -> Self {
162 Self { y_rot, x_rot }.clamped()
163 }
164 pub fn y_rot(&self) -> f32 {
169 self.y_rot
170 }
171 pub fn x_rot(&self) -> f32 {
175 self.x_rot
176 }
177
178 pub fn update(&mut self, new: LookDirection) {
183 self.update_with_sensitivity(new, 1.);
184 }
185 pub fn update_y_rot(&mut self, new_y_rot: f32) {
190 self.update(LookDirection {
191 y_rot: new_y_rot,
192 x_rot: self.x_rot,
193 });
194 }
195 pub fn update_x_rot(&mut self, new_x_rot: f32) {
200 self.update(LookDirection {
201 y_rot: self.y_rot,
202 x_rot: new_x_rot,
203 });
204 }
205
206 pub fn update_with_sensitivity(&mut self, new: LookDirection, sensitivity: f32) {
212 let mut delta_y_rot = new.y_rot.rem_euclid(360.) - self.y_rot.rem_euclid(360.);
213 let delta_x_rot = new.x_rot - self.x_rot;
214
215 if delta_y_rot > 180. {
216 delta_y_rot -= 360.;
217 } else if delta_y_rot < -180. {
218 delta_y_rot += 360.;
219 }
220
221 let sensitivity = sensitivity * 0.15;
222 let delta_y_rot = (delta_y_rot / sensitivity).round() * sensitivity;
223 let delta_x_rot = (delta_x_rot / sensitivity).round() * sensitivity;
224
225 self.y_rot += delta_y_rot;
226 self.x_rot += delta_x_rot;
227 }
228
229 #[must_use]
232 pub fn clamped(mut self) -> Self {
233 self.x_rot = self.x_rot.clamp(-90., 90.);
234 self
235 }
236}
237
238impl From<LookDirection> for (f32, f32) {
239 fn from(value: LookDirection) -> Self {
240 (value.y_rot, value.x_rot)
241 }
242}
243impl From<(f32, f32)> for LookDirection {
244 fn from((y_rot, x_rot): (f32, f32)) -> Self {
245 Self { y_rot, x_rot }
246 }
247}
248
249impl Hash for LookDirection {
250 fn hash<H: Hasher>(&self, state: &mut H) {
251 self.y_rot.to_bits().hash(state);
252 self.x_rot.to_bits().hash(state);
253 }
254}
255impl Eq for LookDirection {}
256
257#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
260#[derive(Clone, Debug, Default)]
261pub struct Physics {
262 pub velocity: Vec3,
268 pub vec_delta_codec: VecDeltaCodec,
269
270 pub old_position: Vec3,
274
275 pub x_acceleration: f32,
281 pub y_acceleration: f32,
282 pub z_acceleration: f32,
283
284 on_ground: bool,
285 last_on_ground: bool,
286
287 pub no_jump_delay: u32,
292
293 pub bounding_box: Aabb,
297
298 pub has_impulse: bool,
299
300 pub horizontal_collision: bool,
301 pub minor_horizontal_collision: bool,
303 pub vertical_collision: bool,
304
305 pub water_fluid_height: f64,
306 pub lava_fluid_height: f64,
307 pub was_touching_water: bool,
308
309 pub fall_distance: f64,
310 pub remaining_fire_ticks: i32,
312}
313
314impl Physics {
315 pub fn new(dimensions: &EntityDimensions, pos: Vec3) -> Self {
316 Self {
317 velocity: Vec3::ZERO,
318 vec_delta_codec: VecDeltaCodec::new(pos),
319
320 old_position: pos,
321
322 x_acceleration: 0.,
323 y_acceleration: 0.,
324 z_acceleration: 0.,
325
326 on_ground: false,
327 last_on_ground: false,
328
329 no_jump_delay: 0,
330
331 bounding_box: dimensions.make_bounding_box(pos),
332
333 has_impulse: false,
334
335 horizontal_collision: false,
336 minor_horizontal_collision: false,
337 vertical_collision: false,
338
339 water_fluid_height: 0.,
340 lava_fluid_height: 0.,
341 was_touching_water: false,
342
343 fall_distance: 0.,
344 remaining_fire_ticks: 0,
345 }
346 }
347
348 pub fn on_ground(&self) -> bool {
349 self.on_ground
350 }
351 pub fn set_on_ground(&mut self, on_ground: bool) {
353 self.last_on_ground = self.on_ground;
354 self.on_ground = on_ground;
355 }
356
357 pub fn last_on_ground(&self) -> bool {
362 self.last_on_ground
363 }
364 pub fn set_last_on_ground(&mut self, last_on_ground: bool) {
365 self.last_on_ground = last_on_ground;
366 }
367
368 pub fn reset_fall_distance(&mut self) {
369 self.fall_distance = 0.;
370 }
371 pub fn clear_fire(&mut self) {
372 self.remaining_fire_ticks = 0;
373 }
374
375 pub fn is_in_water(&self) -> bool {
376 self.was_touching_water
377 }
378 pub fn is_in_lava(&self) -> bool {
379 self.lava_fluid_height > 0.
381 }
382
383 pub fn set_old_pos(&mut self, pos: Position) {
384 self.old_position = *pos;
385 }
386}
387
388impl Attributes {
389 pub fn new(_entity_kind: EntityKind) -> Self {
390 Attributes {
393 movement_speed: AttributeInstance::new(0.1f32 as f64),
394 sneaking_speed: AttributeInstance::new(0.3),
395 attack_speed: AttributeInstance::new(4.0),
396 water_movement_efficiency: AttributeInstance::new(0.0),
397 mining_efficiency: AttributeInstance::new(0.0),
398 block_interaction_range: AttributeInstance::new(4.5),
399 entity_interaction_range: AttributeInstance::new(3.0),
400 step_height: AttributeInstance::new(0.6),
401 }
402 }
403}
404
405#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
410#[derive(Clone, Debug, Default)]
411pub struct PlayerAbilities {
412 pub invulnerable: bool,
413 pub flying: bool,
414 pub can_fly: bool,
415 pub instant_break: bool,
418
419 pub flying_speed: f32,
420 pub walking_speed: f32,
422}
423
424#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
427#[derive(Clone, Copy, Debug, Deref, DerefMut, PartialEq)]
428pub struct FluidOnEyes(FluidKind);