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::{self, 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_registry::EntityKind;
29use azalea_world::{ChunkStorage, InstanceName};
30use bevy_ecs::{bundle::Bundle, component::Component};
31pub use data::*;
32use derive_more::{Deref, DerefMut};
33pub use dimensions::EntityDimensions;
34use plugin::indexing::EntityChunkPos;
35use uuid::Uuid;
36use vec_delta_codec::VecDeltaCodec;
37
38use self::attributes::AttributeInstance;
39pub use crate::plugin::*;
40
41pub fn move_relative(
42 physics: &mut Physics,
43 direction: LookDirection,
44 speed: f32,
45 acceleration: Vec3,
46) {
47 let input_vector = input_vector(direction, speed, acceleration);
48 physics.velocity += input_vector;
49}
50
51pub fn input_vector(direction: LookDirection, speed: f32, acceleration: Vec3) -> Vec3 {
52 let distance = acceleration.length_squared();
53 if distance < 1.0E-7 {
54 return Vec3::ZERO;
55 }
56 let acceleration = if distance > 1.0 {
57 acceleration.normalize()
58 } else {
59 acceleration
60 }
61 .scale(speed as f64);
62 let y_rot = math::sin(direction.y_rot * 0.017453292f32);
63 let x_rot = math::cos(direction.y_rot * 0.017453292f32);
64 Vec3 {
65 x: acceleration.x * (x_rot as f64) - acceleration.z * (y_rot as f64),
66 y: acceleration.y,
67 z: acceleration.z * (x_rot as f64) + acceleration.x * (y_rot as f64),
68 }
69}
70
71pub fn view_vector(look_direction: LookDirection) -> Vec3 {
72 let x_rot = look_direction.x_rot * 0.017453292;
73 let y_rot = -look_direction.y_rot * 0.017453292;
74 let y_rot_cos = math::cos(y_rot);
75 let y_rot_sin = math::sin(y_rot);
76 let x_rot_cos = math::cos(x_rot);
77 let x_rot_sin = math::sin(x_rot);
78 Vec3 {
79 x: (y_rot_sin * x_rot_cos) as f64,
80 y: (-x_rot_sin) as f64,
81 z: (y_rot_cos * x_rot_cos) as f64,
82 }
83}
84
85pub fn on_pos_legacy(chunk_storage: &ChunkStorage, position: Position) -> BlockPos {
87 on_pos(0.2, chunk_storage, position)
88}
89
90pub fn on_pos(offset: f32, chunk_storage: &ChunkStorage, pos: Position) -> BlockPos {
103 let x = pos.x.floor() as i32;
104 let y = (pos.y - offset as f64).floor() as i32;
105 let z = pos.z.floor() as i32;
106 let pos = BlockPos { x, y, z };
107
108 let block_pos = pos.down(1);
110 let block_state = chunk_storage.get_block_state(block_pos);
111 if block_state == Some(BlockState::AIR) {
112 let block_pos_below = block_pos.down(1);
113 let block_state_below = chunk_storage.get_block_state(block_pos_below);
114 if let Some(_block_state_below) = block_state_below {
115 }
122 }
123
124 pos
125}
126
127#[derive(Component, Deref, DerefMut, Clone, Copy, Default)]
130pub struct EntityUuid(Uuid);
131impl EntityUuid {
132 pub fn new(uuid: Uuid) -> Self {
133 Self(uuid)
134 }
135}
136impl Debug for EntityUuid {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 (self.0).fmt(f)
139 }
140}
141
142#[derive(Component, Clone, Copy, Debug, Default, PartialEq, Deref, DerefMut)]
150pub struct Position(Vec3);
151impl Position {
152 pub fn new(pos: Vec3) -> Self {
153 Self(pos)
154 }
155}
156impl From<&Position> for Vec3 {
157 fn from(value: &Position) -> Self {
158 value.0
159 }
160}
161impl From<Position> for ChunkPos {
162 fn from(value: Position) -> Self {
163 ChunkPos::from(&value.0)
164 }
165}
166impl From<Position> for BlockPos {
167 fn from(value: Position) -> Self {
168 BlockPos::from(&value.0)
169 }
170}
171impl From<&Position> for ChunkPos {
172 fn from(value: &Position) -> Self {
173 ChunkPos::from(value.0)
174 }
175}
176impl From<&Position> for BlockPos {
177 fn from(value: &Position) -> Self {
178 BlockPos::from(value.0)
179 }
180}
181
182#[derive(Component, Clone, Copy, Debug, Default, PartialEq, Deref, DerefMut)]
185pub struct LastSentPosition(Vec3);
186impl From<&LastSentPosition> for Vec3 {
187 fn from(value: &LastSentPosition) -> Self {
188 value.0
189 }
190}
191impl From<LastSentPosition> for ChunkPos {
192 fn from(value: LastSentPosition) -> Self {
193 ChunkPos::from(&value.0)
194 }
195}
196impl From<LastSentPosition> for BlockPos {
197 fn from(value: LastSentPosition) -> Self {
198 BlockPos::from(&value.0)
199 }
200}
201impl From<&LastSentPosition> for ChunkPos {
202 fn from(value: &LastSentPosition) -> Self {
203 ChunkPos::from(value.0)
204 }
205}
206impl From<&LastSentPosition> for BlockPos {
207 fn from(value: &LastSentPosition) -> Self {
208 BlockPos::from(value.0)
209 }
210}
211
212#[derive(Debug, Component, Copy, Clone, Deref, DerefMut, Default, PartialEq, Eq)]
217pub struct Jumping(pub bool);
218
219#[derive(Debug, Component, Copy, Clone, Default, PartialEq, AzBuf)]
221pub struct LookDirection {
222 pub y_rot: f32,
224 pub x_rot: f32,
226}
227
228impl LookDirection {
229 pub fn new(y_rot: f32, x_rot: f32) -> Self {
232 apply_clamp_look_direction(Self { y_rot, x_rot })
233 }
234}
235
236impl From<LookDirection> for (f32, f32) {
237 fn from(value: LookDirection) -> Self {
238 (value.y_rot, value.x_rot)
239 }
240}
241impl From<(f32, f32)> for LookDirection {
242 fn from((y_rot, x_rot): (f32, f32)) -> Self {
243 Self { y_rot, x_rot }
244 }
245}
246
247impl Hash for LookDirection {
248 fn hash<H: Hasher>(&self, state: &mut H) {
249 self.y_rot.to_bits().hash(state);
250 self.x_rot.to_bits().hash(state);
251 }
252}
253impl Eq for LookDirection {}
254
255#[derive(Debug, Component, Clone, Default)]
258pub struct Physics {
259 pub velocity: Vec3,
265 pub vec_delta_codec: VecDeltaCodec,
266
267 pub old_position: Vec3,
271
272 pub x_acceleration: f32,
278 pub y_acceleration: f32,
279 pub z_acceleration: f32,
280
281 on_ground: bool,
282 last_on_ground: bool,
283
284 pub no_jump_delay: u32,
289
290 pub dimensions: EntityDimensions,
292 pub bounding_box: AABB,
295
296 pub has_impulse: bool,
297
298 pub horizontal_collision: bool,
299 pub vertical_collision: bool,
301
302 pub water_fluid_height: f64,
303 pub lava_fluid_height: f64,
304 pub was_touching_water: bool,
305
306 pub fall_distance: f32,
308 pub remaining_fire_ticks: i32,
310}
311
312impl Physics {
313 pub fn new(dimensions: EntityDimensions, pos: Vec3) -> Self {
314 Self {
315 velocity: Vec3::ZERO,
316 vec_delta_codec: VecDeltaCodec::new(pos),
317
318 old_position: pos,
319
320 x_acceleration: 0.,
321 y_acceleration: 0.,
322 z_acceleration: 0.,
323
324 on_ground: false,
325 last_on_ground: false,
326
327 no_jump_delay: 0,
328
329 bounding_box: dimensions.make_bounding_box(pos),
330 dimensions,
331
332 has_impulse: false,
333
334 horizontal_collision: false,
335 vertical_collision: false,
336
337 water_fluid_height: 0.,
338 lava_fluid_height: 0.,
339 was_touching_water: false,
340
341 fall_distance: 0.,
342 remaining_fire_ticks: 0,
343 }
344 }
345
346 pub fn on_ground(&self) -> bool {
347 self.on_ground
348 }
349 pub fn set_on_ground(&mut self, on_ground: bool) {
351 self.last_on_ground = self.on_ground;
352 self.on_ground = on_ground;
353 }
354
355 pub fn last_on_ground(&self) -> bool {
360 self.last_on_ground
361 }
362 pub fn set_last_on_ground(&mut self, last_on_ground: bool) {
363 self.last_on_ground = last_on_ground;
364 }
365
366 pub fn reset_fall_distance(&mut self) {
367 self.fall_distance = 0.;
368 }
369 pub fn clear_fire(&mut self) {
370 self.remaining_fire_ticks = 0;
371 }
372
373 pub fn is_in_water(&self) -> bool {
374 self.was_touching_water
375 }
376 pub fn is_in_lava(&self) -> bool {
377 self.lava_fluid_height > 0.
379 }
380
381 pub fn set_old_pos(&mut self, pos: Position) {
382 self.old_position = *pos;
383 }
384}
385
386#[derive(Component, Copy, Clone, Default)]
390pub struct Dead;
391
392#[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)]
400pub struct EyeHeight(f32);
401impl EyeHeight {
402 pub fn new(height: f32) -> Self {
403 Self(height)
404 }
405}
406impl From<EyeHeight> for f32 {
407 fn from(value: EyeHeight) -> Self {
408 value.0
409 }
410}
411impl From<EyeHeight> for f64 {
412 fn from(value: EyeHeight) -> Self {
413 value.0 as f64
414 }
415}
416impl From<&EyeHeight> for f32 {
417 fn from(value: &EyeHeight) -> Self {
418 value.0
419 }
420}
421impl From<&EyeHeight> for f64 {
422 fn from(value: &EyeHeight) -> Self {
423 value.0 as f64
424 }
425}
426
427#[derive(Component, Clone, Copy, Debug, PartialEq, Deref)]
432pub struct EntityKindComponent(pub azalea_registry::EntityKind);
433
434#[derive(Bundle)]
437pub struct EntityBundle {
438 pub kind: EntityKindComponent,
439 pub uuid: EntityUuid,
440 pub world_name: InstanceName,
441 pub position: Position,
442 pub last_sent_position: LastSentPosition,
443
444 pub chunk_pos: EntityChunkPos,
445
446 pub physics: Physics,
447 pub direction: LookDirection,
448 pub eye_height: EyeHeight,
449 pub attributes: Attributes,
450 pub jumping: Jumping,
451 pub fluid_on_eyes: FluidOnEyes,
452 pub on_climbable: OnClimbable,
453}
454
455impl EntityBundle {
456 pub fn new(
457 uuid: Uuid,
458 pos: Vec3,
459 kind: azalea_registry::EntityKind,
460 world_name: ResourceLocation,
461 ) -> Self {
462 let dimensions = EntityDimensions::from(kind);
463 let eye_height = match kind {
464 azalea_registry::EntityKind::Player => 1.62,
467 _ => dimensions.height * 0.85,
468 };
469
470 Self {
471 kind: EntityKindComponent(kind),
472 uuid: EntityUuid(uuid),
473 world_name: InstanceName(world_name),
474 position: Position(pos),
475 chunk_pos: EntityChunkPos(ChunkPos::from(&pos)),
476 last_sent_position: LastSentPosition(pos),
477 physics: Physics::new(dimensions, pos),
478 eye_height: EyeHeight(eye_height),
479 direction: LookDirection::default(),
480
481 attributes: default_attributes(EntityKind::Player),
482
483 jumping: Jumping(false),
484 fluid_on_eyes: FluidOnEyes(FluidKind::Empty),
485 on_climbable: OnClimbable(false),
486 }
487 }
488}
489
490pub fn default_attributes(_entity_kind: EntityKind) -> Attributes {
491 Attributes {
494 speed: AttributeInstance::new(0.1),
495 attack_speed: AttributeInstance::new(4.0),
496 water_movement_efficiency: AttributeInstance::new(0.0),
497 block_interaction_range: AttributeInstance::new(4.5),
498 entity_interaction_range: AttributeInstance::new(3.0),
499 }
500}
501
502#[derive(Component, Clone, Copy, Debug, Default)]
509pub struct LocalEntity;
510
511#[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)]
512pub struct FluidOnEyes(FluidKind);
513
514impl FluidOnEyes {
515 pub fn new(fluid: FluidKind) -> Self {
516 Self(fluid)
517 }
518}
519
520#[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)]
521pub struct OnClimbable(bool);