1#![allow(clippy::derived_hash_with_manual_eq)]
2
3pub mod attributes;
4mod data;
5mod dimensions;
6mod effects;
7mod enchantments;
8pub mod metadata;
9pub mod mining;
10pub mod particle;
11mod plugin;
12pub mod vec_delta_codec;
13
14use std::{
15 fmt::Debug,
16 hash::{Hash, Hasher},
17};
18
19pub use attributes::Attributes;
20use azalea_block::{BlockState, fluid_state::FluidKind};
21use azalea_buf::AzBuf;
22use azalea_core::{
23 aabb::AABB,
24 math,
25 position::{BlockPos, ChunkPos, Vec3},
26 resource_location::ResourceLocation,
27};
28use azalea_world::{ChunkStorage, InstanceName};
29use bevy_ecs::{bundle::Bundle, component::Component};
30pub use data::*;
31use derive_more::{Deref, DerefMut};
32pub use dimensions::EntityDimensions;
33use plugin::indexing::EntityChunkPos;
34use uuid::Uuid;
35use vec_delta_codec::VecDeltaCodec;
36
37use self::attributes::AttributeInstance;
38pub use crate::plugin::*;
39
40pub fn move_relative(
41 physics: &mut Physics,
42 direction: &LookDirection,
43 speed: f32,
44 acceleration: &Vec3,
45) {
46 let input_vector = input_vector(direction, speed, acceleration);
47 physics.velocity += input_vector;
48}
49
50pub fn input_vector(direction: &LookDirection, speed: f32, acceleration: &Vec3) -> Vec3 {
51 let distance = acceleration.length_squared();
52 if distance < 1.0E-7 {
53 return Vec3::ZERO;
54 }
55 let acceleration = if distance > 1.0 {
56 acceleration.normalize()
57 } else {
58 *acceleration
59 }
60 .scale(speed as f64);
61 let y_rot = math::sin(direction.y_rot * 0.017453292f32);
62 let x_rot = math::cos(direction.y_rot * 0.017453292f32);
63 Vec3 {
64 x: acceleration.x * (x_rot as f64) - acceleration.z * (y_rot as f64),
65 y: acceleration.y,
66 z: acceleration.z * (x_rot as f64) + acceleration.x * (y_rot as f64),
67 }
68}
69
70pub fn view_vector(look_direction: &LookDirection) -> Vec3 {
71 let x_rot = look_direction.x_rot * 0.017453292;
72 let y_rot = -look_direction.y_rot * 0.017453292;
73 let y_rot_cos = math::cos(y_rot);
74 let y_rot_sin = math::sin(y_rot);
75 let x_rot_cos = math::cos(x_rot);
76 let x_rot_sin = math::sin(x_rot);
77 Vec3 {
78 x: (y_rot_sin * x_rot_cos) as f64,
79 y: (-x_rot_sin) as f64,
80 z: (y_rot_cos * x_rot_cos) as f64,
81 }
82}
83
84pub fn on_pos_legacy(chunk_storage: &ChunkStorage, position: &Position) -> BlockPos {
86 on_pos(0.2, chunk_storage, position)
87}
88
89pub fn on_pos(offset: f32, chunk_storage: &ChunkStorage, pos: &Position) -> BlockPos {
102 let x = pos.x.floor() as i32;
103 let y = (pos.y - offset as f64).floor() as i32;
104 let z = pos.z.floor() as i32;
105 let pos = BlockPos { x, y, z };
106
107 let block_pos = pos.down(1);
109 let block_state = chunk_storage.get_block_state(&block_pos);
110 if block_state == Some(BlockState::AIR) {
111 let block_pos_below = block_pos.down(1);
112 let block_state_below = chunk_storage.get_block_state(&block_pos_below);
113 if let Some(_block_state_below) = block_state_below {
114 }
121 }
122
123 pos
124}
125
126#[derive(Component, Deref, DerefMut, Clone, Copy, Default)]
129pub struct EntityUuid(Uuid);
130impl EntityUuid {
131 pub fn new(uuid: Uuid) -> Self {
132 Self(uuid)
133 }
134}
135impl Debug for EntityUuid {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 (self.0).fmt(f)
138 }
139}
140
141#[derive(Component, Clone, Copy, Debug, Default, PartialEq, Deref, DerefMut)]
149pub struct Position(Vec3);
150impl Position {
151 pub fn new(pos: Vec3) -> Self {
152 Self(pos)
153 }
154}
155impl From<&Position> for Vec3 {
156 fn from(value: &Position) -> Self {
157 value.0
158 }
159}
160impl From<Position> for ChunkPos {
161 fn from(value: Position) -> Self {
162 ChunkPos::from(&value.0)
163 }
164}
165impl From<Position> for BlockPos {
166 fn from(value: Position) -> Self {
167 BlockPos::from(&value.0)
168 }
169}
170impl From<&Position> for ChunkPos {
171 fn from(value: &Position) -> Self {
172 ChunkPos::from(value.0)
173 }
174}
175impl From<&Position> for BlockPos {
176 fn from(value: &Position) -> Self {
177 BlockPos::from(value.0)
178 }
179}
180
181#[derive(Component, Clone, Copy, Debug, Default, PartialEq, Deref, DerefMut)]
184pub struct LastSentPosition(Vec3);
185impl From<&LastSentPosition> for Vec3 {
186 fn from(value: &LastSentPosition) -> Self {
187 value.0
188 }
189}
190impl From<LastSentPosition> for ChunkPos {
191 fn from(value: LastSentPosition) -> Self {
192 ChunkPos::from(&value.0)
193 }
194}
195impl From<LastSentPosition> for BlockPos {
196 fn from(value: LastSentPosition) -> Self {
197 BlockPos::from(&value.0)
198 }
199}
200impl From<&LastSentPosition> for ChunkPos {
201 fn from(value: &LastSentPosition) -> Self {
202 ChunkPos::from(value.0)
203 }
204}
205impl From<&LastSentPosition> for BlockPos {
206 fn from(value: &LastSentPosition) -> Self {
207 BlockPos::from(value.0)
208 }
209}
210
211#[derive(Debug, Component, Copy, Clone, Deref, DerefMut, Default, PartialEq, Eq)]
216pub struct Jumping(pub bool);
217
218#[derive(Debug, Component, Copy, Clone, Default, PartialEq, AzBuf)]
220pub struct LookDirection {
221 pub y_rot: f32,
223 pub x_rot: f32,
225}
226
227impl LookDirection {
228 pub fn new(y_rot: f32, x_rot: f32) -> Self {
229 Self { y_rot, x_rot }
230 }
231}
232
233impl From<LookDirection> for (f32, f32) {
234 fn from(value: LookDirection) -> Self {
235 (value.y_rot, value.x_rot)
236 }
237}
238impl From<(f32, f32)> for LookDirection {
239 fn from((y_rot, x_rot): (f32, f32)) -> Self {
240 Self { y_rot, x_rot }
241 }
242}
243
244impl Hash for LookDirection {
245 fn hash<H: Hasher>(&self, state: &mut H) {
246 self.y_rot.to_bits().hash(state);
247 self.x_rot.to_bits().hash(state);
248 }
249}
250impl Eq for LookDirection {}
251
252#[derive(Debug, Component, Clone, Default)]
255pub struct Physics {
256 pub velocity: Vec3,
260 pub vec_delta_codec: VecDeltaCodec,
261
262 pub old_position: Vec3,
266
267 pub x_acceleration: f32,
273 pub y_acceleration: f32,
274 pub z_acceleration: f32,
275
276 on_ground: bool,
277 last_on_ground: bool,
278
279 pub no_jump_delay: u32,
284
285 pub dimensions: EntityDimensions,
287 pub bounding_box: AABB,
290
291 pub has_impulse: bool,
292
293 pub horizontal_collision: bool,
294 pub vertical_collision: bool,
296
297 pub water_fluid_height: f64,
298 pub lava_fluid_height: f64,
299 pub was_touching_water: bool,
300
301 pub fall_distance: f32,
303 pub remaining_fire_ticks: i32,
305}
306
307impl Physics {
308 pub fn new(dimensions: EntityDimensions, pos: Vec3) -> Self {
309 Self {
310 velocity: Vec3::ZERO,
311 vec_delta_codec: VecDeltaCodec::new(pos),
312
313 old_position: pos,
314
315 x_acceleration: 0.,
316 y_acceleration: 0.,
317 z_acceleration: 0.,
318
319 on_ground: false,
320 last_on_ground: false,
321
322 no_jump_delay: 0,
323
324 bounding_box: dimensions.make_bounding_box(&pos),
325 dimensions,
326
327 has_impulse: false,
328
329 horizontal_collision: false,
330 vertical_collision: false,
331
332 water_fluid_height: 0.,
333 lava_fluid_height: 0.,
334 was_touching_water: false,
335
336 fall_distance: 0.,
337 remaining_fire_ticks: 0,
338 }
339 }
340
341 pub fn on_ground(&self) -> bool {
342 self.on_ground
343 }
344 pub fn set_on_ground(&mut self, on_ground: bool) {
346 self.last_on_ground = self.on_ground;
347 self.on_ground = on_ground;
348 }
349
350 pub fn last_on_ground(&self) -> bool {
355 self.last_on_ground
356 }
357 pub fn set_last_on_ground(&mut self, last_on_ground: bool) {
358 self.last_on_ground = last_on_ground;
359 }
360
361 pub fn reset_fall_distance(&mut self) {
362 self.fall_distance = 0.;
363 }
364 pub fn clear_fire(&mut self) {
365 self.remaining_fire_ticks = 0;
366 }
367
368 pub fn is_in_water(&self) -> bool {
369 self.was_touching_water
370 }
371 pub fn is_in_lava(&self) -> bool {
372 self.lava_fluid_height > 0.
374 }
375
376 pub fn set_old_pos(&mut self, pos: &Position) {
377 self.old_position = **pos;
378 }
379}
380
381#[derive(Component, Copy, Clone, Default)]
385pub struct Dead;
386
387#[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)]
393pub struct EyeHeight(f32);
394impl EyeHeight {
395 pub fn new(height: f32) -> Self {
396 Self(height)
397 }
398}
399impl From<EyeHeight> for f32 {
400 fn from(value: EyeHeight) -> Self {
401 value.0
402 }
403}
404impl From<EyeHeight> for f64 {
405 fn from(value: EyeHeight) -> Self {
406 value.0 as f64
407 }
408}
409impl From<&EyeHeight> for f32 {
410 fn from(value: &EyeHeight) -> Self {
411 value.0
412 }
413}
414impl From<&EyeHeight> for f64 {
415 fn from(value: &EyeHeight) -> Self {
416 value.0 as f64
417 }
418}
419
420#[derive(Component, Clone, Copy, Debug, PartialEq, Deref)]
425pub struct EntityKind(pub azalea_registry::EntityKind);
426
427#[derive(Bundle)]
430pub struct EntityBundle {
431 pub kind: EntityKind,
432 pub uuid: EntityUuid,
433 pub world_name: InstanceName,
434 pub position: Position,
435 pub last_sent_position: LastSentPosition,
436
437 pub chunk_pos: EntityChunkPos,
438
439 pub physics: Physics,
440 pub direction: LookDirection,
441 pub eye_height: EyeHeight,
442 pub attributes: Attributes,
443 pub jumping: Jumping,
444 pub fluid_on_eyes: FluidOnEyes,
445 pub on_climbable: OnClimbable,
446}
447
448impl EntityBundle {
449 pub fn new(
450 uuid: Uuid,
451 pos: Vec3,
452 kind: azalea_registry::EntityKind,
453 world_name: ResourceLocation,
454 ) -> Self {
455 let dimensions = EntityDimensions::from(kind);
456 let eye_height = dimensions.height * 0.85;
457
458 Self {
459 kind: EntityKind(kind),
460 uuid: EntityUuid(uuid),
461 world_name: InstanceName(world_name),
462 position: Position(pos),
463 chunk_pos: EntityChunkPos(ChunkPos::from(&pos)),
464 last_sent_position: LastSentPosition(pos),
465 physics: Physics::new(dimensions, pos),
466 eye_height: EyeHeight(eye_height),
467 direction: LookDirection::default(),
468
469 attributes: Attributes {
470 speed: AttributeInstance::new(0.1),
473 attack_speed: AttributeInstance::new(4.0),
474 water_movement_efficiency: AttributeInstance::new(0.0),
475 },
476
477 jumping: Jumping(false),
478 fluid_on_eyes: FluidOnEyes(FluidKind::Empty),
479 on_climbable: OnClimbable(false),
480 }
481 }
482}
483
484#[derive(Component, Clone, Debug, Default)]
491pub struct LocalEntity;
492
493#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]
494pub struct FluidOnEyes(FluidKind);
495
496impl FluidOnEyes {
497 pub fn new(fluid: FluidKind) -> Self {
498 Self(fluid)
499 }
500}
501
502#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]
503pub struct OnClimbable(bool);