1#![doc = include_str!("../README.md")]
2#![allow(clippy::unseparated_literal_suffix, clippy::manual_string_new)]
3
4pub mod active_status_effects;
5pub mod attributes;
6mod flags;
7pub mod hitbox;
8pub mod manager;
9pub mod query;
10pub mod tracked_data;
11
12use bevy_app::prelude::*;
13use bevy_ecs::prelude::*;
14use derive_more::{Deref, DerefMut};
15pub use manager::EntityManager;
16use paste::paste;
17use tracing::warn;
18use tracked_data::TrackedData;
19use valence_math::{DVec3, Vec3};
20use valence_protocol::{Decode, Encode, VarInt};
21use valence_server_common::{Despawned, UniqueId};
22
23use crate::attributes::TrackedEntityAttributes;
24
25include!(concat!(env!("OUT_DIR"), "/entity.rs"));
26
27pub struct EntityPlugin;
28
29#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
37pub struct InitEntitiesSet;
38
39#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
44pub struct UpdateTrackedDataSet;
45
46#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
53pub struct ClearEntityChangesSet;
54
55impl Plugin for EntityPlugin {
56 fn build(&self, app: &mut App) {
57 app.insert_resource(EntityManager::new())
58 .configure_sets(
59 PostUpdate,
60 (
61 InitEntitiesSet,
62 UpdateTrackedDataSet,
63 ClearEntityChangesSet
64 .after(InitEntitiesSet)
65 .after(UpdateTrackedDataSet),
66 ),
67 )
68 .add_systems(
69 PostUpdate,
70 (remove_despawned_from_manager, init_entities)
71 .chain()
72 .in_set(InitEntitiesSet),
73 )
74 .add_systems(
75 PostUpdate,
76 (
77 clear_status_changes,
78 clear_animation_changes,
79 clear_tracked_data_changes,
80 clear_tracked_attributes_changes,
81 update_old_position,
82 update_old_layer_id,
83 )
84 .in_set(ClearEntityChangesSet),
85 );
86
87 add_tracked_data_systems(app);
88 }
89}
90
91fn update_old_position(mut query: Query<(&Position, &mut OldPosition)>) {
92 for (pos, mut old_pos) in &mut query {
93 old_pos.0 = pos.0;
94 }
95}
96
97fn update_old_layer_id(mut query: Query<(&EntityLayerId, &mut OldEntityLayerId)>) {
98 for (loc, mut old_loc) in &mut query {
99 old_loc.0 = loc.0;
100 }
101}
102
103fn remove_despawned_from_manager(
104 entities: Query<&EntityId, (With<EntityKind>, With<Despawned>)>,
105 mut manager: ResMut<EntityManager>,
106) {
107 for id in &entities {
108 manager.id_to_entity.remove(&id.0);
109 }
110}
111
112fn init_entities(
113 mut entities: Query<
114 (Entity, &mut EntityId, &Position, &mut OldPosition),
115 (Added<EntityKind>, Without<Despawned>),
116 >,
117 mut manager: ResMut<EntityManager>,
118) {
119 for (entity, mut id, pos, mut old_pos) in &mut entities {
120 *old_pos = OldPosition::new(pos.0);
121
122 if *id == EntityId::default() {
123 *id = manager.next_id();
124 }
125
126 if let Some(conflict) = manager.id_to_entity.insert(id.0, entity) {
127 warn!(
128 "entity {entity:?} has conflicting entity ID of {} with entity {conflict:?}",
129 id.0
130 );
131 }
132 }
133}
134
135fn clear_status_changes(mut statuses: Query<&mut EntityStatuses, Changed<EntityStatuses>>) {
136 for mut statuses in &mut statuses {
137 statuses.0 = 0;
138 }
139}
140
141fn clear_animation_changes(
142 mut animations: Query<&mut EntityAnimations, Changed<EntityAnimations>>,
143) {
144 for mut animations in &mut animations {
145 animations.0 = 0;
146 }
147}
148
149fn clear_tracked_data_changes(mut tracked_data: Query<&mut TrackedData, Changed<TrackedData>>) {
150 for mut tracked_data in &mut tracked_data {
151 tracked_data.clear_update_values();
152 }
153}
154
155fn clear_tracked_attributes_changes(
156 mut attributes: Query<&mut TrackedEntityAttributes, Changed<TrackedEntityAttributes>>,
157) {
158 for mut attributes in &mut attributes {
159 attributes.clear();
160 }
161}
162
163#[derive(Component, Copy, Clone, PartialEq, Eq, Debug, Deref)]
165pub struct EntityLayerId(pub Entity);
166
167impl Default for EntityLayerId {
168 fn default() -> Self {
169 Self(Entity::PLACEHOLDER)
170 }
171}
172
173impl PartialEq<OldEntityLayerId> for EntityLayerId {
174 fn eq(&self, other: &OldEntityLayerId) -> bool {
175 self.0 == other.0
176 }
177}
178
179#[derive(Component, Copy, Clone, PartialEq, Eq, Debug, Deref)]
181pub struct OldEntityLayerId(Entity);
182
183impl OldEntityLayerId {
184 pub fn get(&self) -> Entity {
185 self.0
186 }
187}
188
189impl Default for OldEntityLayerId {
190 fn default() -> Self {
191 Self(Entity::PLACEHOLDER)
192 }
193}
194
195impl PartialEq<EntityLayerId> for OldEntityLayerId {
196 fn eq(&self, other: &EntityLayerId) -> bool {
197 self.0 == other.0
198 }
199}
200
201#[derive(Component, Copy, Clone, PartialEq, Default, Debug, Deref, DerefMut)]
202pub struct Position(pub DVec3);
203
204impl Position {
205 pub fn new<P: Into<DVec3>>(pos: P) -> Self {
206 Self(pos.into())
207 }
208
209 pub fn get(self) -> DVec3 {
210 self.0
211 }
212
213 pub fn set<P: Into<DVec3>>(&mut self, pos: P) {
214 self.0 = pos.into();
215 }
216}
217
218impl PartialEq<OldPosition> for Position {
219 fn eq(&self, other: &OldPosition) -> bool {
220 self.0 == other.0
221 }
222}
223
224#[derive(Component, Clone, PartialEq, Default, Debug, Deref)]
228pub struct OldPosition(DVec3);
229
230impl OldPosition {
231 pub fn new<P: Into<DVec3>>(pos: P) -> Self {
232 Self(pos.into())
233 }
234
235 pub fn get(&self) -> DVec3 {
236 self.0
237 }
238}
239
240impl PartialEq<Position> for OldPosition {
241 fn eq(&self, other: &Position) -> bool {
242 self.0 == other.0
243 }
244}
245
246#[derive(Component, Copy, Clone, PartialEq, Default, Debug)]
248pub struct Look {
249 pub yaw: f32,
257 pub pitch: f32,
262}
263
264impl Look {
265 pub const fn new(yaw: f32, pitch: f32) -> Self {
266 Self { yaw, pitch }
267 }
268
269 pub fn vec(self) -> Vec3 {
271 let (yaw_sin, yaw_cos) = (self.yaw + 90.0).to_radians().sin_cos();
272 let (pitch_sin, pitch_cos) = (-self.pitch).to_radians().sin_cos();
273
274 Vec3::new(yaw_cos * pitch_cos, pitch_sin, yaw_sin * pitch_cos)
275 }
276
277 pub fn set_vec(&mut self, dir: Vec3) {
279 debug_assert!(
280 dir.is_normalized(),
281 "the direction vector should be normalized"
282 );
283
284 if dir.x != 0.0 || dir.z != 0.0 {
286 self.yaw = f32::atan2(dir.z, dir.x).to_degrees() - 90.0;
287 }
288
289 self.pitch = -(dir.y).asin().to_degrees();
290 }
291}
292
293#[derive(Component, Copy, Clone, PartialEq, Eq, Default, Debug, Deref, DerefMut)]
294pub struct OnGround(pub bool);
295
296#[derive(Component, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Deref)]
304pub struct EntityId(i32);
305
306impl EntityId {
307 pub fn get(self) -> i32 {
309 self.0
310 }
311}
312
313impl Default for EntityId {
315 fn default() -> Self {
316 Self(-1)
317 }
318}
319
320#[derive(Component, Copy, Clone, PartialEq, Default, Debug, Deref, DerefMut)]
321pub struct HeadYaw(pub f32);
322
323#[derive(Component, Copy, Clone, Default, Debug, Deref, DerefMut)]
325pub struct Velocity(pub Vec3);
326
327impl Velocity {
328 pub fn to_packet_units(self) -> valence_protocol::Velocity {
329 valence_protocol::Velocity::from_ms_f32(self.0.into())
330 }
331}
332
333#[derive(Component, Copy, Clone, Default, Debug, Deref, DerefMut)]
336pub struct EntityStatuses(pub u64);
337
338impl EntityStatuses {
339 pub fn trigger(&mut self, status: EntityStatus) {
340 self.set(status, true);
341 }
342
343 pub fn set(&mut self, status: EntityStatus, triggered: bool) {
344 self.0 |= u64::from(triggered) << status as u64;
345 }
346
347 pub fn get(&self, status: EntityStatus) -> bool {
348 (self.0 >> status as u64) & 1 == 1
349 }
350}
351
352#[derive(Component, Default, Debug, Copy, Clone, Deref, DerefMut)]
353pub struct EntityAnimations(pub u8);
354
355impl EntityAnimations {
356 pub fn trigger(&mut self, anim: EntityAnimation) {
357 self.set(anim, true);
358 }
359
360 pub fn set(&mut self, anim: EntityAnimation, triggered: bool) {
361 self.0 |= u8::from(triggered) << anim as u8;
362 }
363
364 pub fn get(&self, anim: EntityAnimation) -> bool {
365 (self.0 >> anim as u8) & 1 == 1
366 }
367}
368
369#[derive(Component, Default, Debug, Deref, DerefMut)]
380pub struct ObjectData(pub i32);
381
382#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
383pub struct VillagerData {
384 pub kind: VillagerKind,
385 pub profession: VillagerProfession,
386 pub level: i32,
387}
388
389impl VillagerData {
390 pub const fn new(kind: VillagerKind, profession: VillagerProfession, level: i32) -> Self {
391 Self {
392 kind,
393 profession,
394 level,
395 }
396 }
397}
398
399impl Default for VillagerData {
400 fn default() -> Self {
401 Self {
402 kind: Default::default(),
403 profession: Default::default(),
404 level: 1,
405 }
406 }
407}
408
409impl Encode for VillagerData {
410 fn encode(&self, mut w: impl std::io::Write) -> anyhow::Result<()> {
411 self.kind.encode(&mut w)?;
412 self.profession.encode(&mut w)?;
413 VarInt(self.level).encode(w)
414 }
415}
416
417impl Decode<'_> for VillagerData {
418 fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
419 Ok(Self {
420 kind: VillagerKind::decode(r)?,
421 profession: VillagerProfession::decode(r)?,
422 level: VarInt::decode(r)?.0,
423 })
424 }
425}
426
427#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
428pub enum VillagerKind {
429 Desert,
430 Jungle,
431 #[default]
432 Plains,
433 Savanna,
434 Snow,
435 Swamp,
436 Taiga,
437}
438
439#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
440pub enum VillagerProfession {
441 #[default]
442 None,
443 Armorer,
444 Butcher,
445 Cartographer,
446 Cleric,
447 Farmer,
448 Fisherman,
449 Fletcher,
450 Leatherworker,
451 Librarian,
452 Mason,
453 Nitwit,
454 Shepherd,
455 Toolsmith,
456 Weaponsmith,
457}
458
459#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
460pub enum Pose {
461 #[default]
462 Standing,
463 FallFlying,
464 Sleeping,
465 Swimming,
466 SpinAttack,
467 Sneaking,
468 LongJumping,
469 Dying,
470 Croaking,
471 UsingTongue,
472 Roaring,
473 Sniffing,
474 Emerging,
475 Digging,
476}
477
478#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
479pub enum BoatKind {
480 #[default]
481 Oak,
482 Spruce,
483 Birch,
484 Jungle,
485 Acacia,
486 DarkOak,
487}
488
489#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
490pub enum CatKind {
491 Tabby,
492 #[default]
493 Black,
494 Red,
495 Siamese,
496 BritishShorthair,
497 Calico,
498 Persian,
499 Ragdoll,
500 White,
501 Jellie,
502 AllBlack,
503}
504
505#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
506pub enum FrogKind {
507 #[default]
508 Temperate,
509 Warm,
510 Cold,
511}
512
513#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
514pub enum PaintingKind {
515 #[default]
516 Kebab,
517 Aztec,
518 Alban,
519 Aztec2,
520 Bomb,
521 Plant,
522 Wasteland,
523 Pool,
524 Courbet,
525 Sea,
526 Sunset,
527 Creebet,
528 Wanderer,
529 Graham,
530 Match,
531 Bust,
532 Stage,
533 Void,
534 SkullAndRoses,
535 Wither,
536 Fighters,
537 Pointer,
538 Pigscene,
539 BurningSkull,
540 Skeleton,
541 Earth,
542 Wind,
543 Water,
544 Fire,
545 DonkeyKong,
546}
547
548#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encode, Decode)]
549pub enum SnifferState {
550 #[default]
551 Idling,
552 FeelingHappy,
553 Scenting,
554 Sniffing,
555 Searching,
556 Digging,
557 Rising,
558}
559
560#[derive(Clone, Copy, PartialEq, PartialOrd, Debug, Encode, Decode)]
561pub struct EulerAngle {
562 pub pitch: f32,
563 pub yaw: f32,
564 pub roll: f32,
565}
566
567#[derive(Copy, Clone)]
568struct OptionalInt(Option<i32>);
569
570impl Encode for OptionalInt {
571 fn encode(&self, w: impl std::io::Write) -> anyhow::Result<()> {
572 if let Some(n) = self.0 {
573 VarInt(n.wrapping_add(1))
574 } else {
575 VarInt(0)
576 }
577 .encode(w)
578 }
579}
580
581impl Decode<'_> for OptionalInt {
582 fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
583 let n = VarInt::decode(r)?.0;
584
585 Ok(Self(if n == 0 {
586 None
587 } else {
588 Some(n.wrapping_sub(1))
589 }))
590 }
591}