aboutsummaryrefslogtreecommitdiff
path: root/azalea-entity/src/plugin/mod.rs
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2023-07-23 22:17:17 -0500
committermat <git@matdoes.dev>2023-07-23 22:17:17 -0500
commitd99ba0da5500a1a4917bf9c8c9e93e2caa4ada99 (patch)
tree08af266f9ccc9a6dea7593198bfe50dab2a307eb /azalea-entity/src/plugin/mod.rs
parent2ab16402de3ac12c04696833450cd8d2f7b39b85 (diff)
downloadazalea-drasl-d99ba0da5500a1a4917bf9c8c9e93e2caa4ada99.tar.xz
clean up azalea-entity a little
Diffstat (limited to 'azalea-entity/src/plugin/mod.rs')
-rw-r--r--azalea-entity/src/plugin/mod.rs147
1 files changed, 147 insertions, 0 deletions
diff --git a/azalea-entity/src/plugin/mod.rs b/azalea-entity/src/plugin/mod.rs
new file mode 100644
index 00000000..7b514fcc
--- /dev/null
+++ b/azalea-entity/src/plugin/mod.rs
@@ -0,0 +1,147 @@
+pub mod indexing;
+mod relative_updates;
+
+use std::collections::HashSet;
+
+use azalea_core::{BlockPos, Vec3};
+use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId};
+use bevy_app::{App, Plugin, PostUpdate, PreUpdate, Update};
+use bevy_ecs::prelude::*;
+use derive_more::{Deref, DerefMut};
+use log::debug;
+
+use crate::{
+ metadata::Health, Dead, EyeHeight, FluidOnEyes, Local, LookDirection, Physics, Position,
+};
+
+use indexing::EntityUuidIndex;
+pub use relative_updates::RelativeEntityUpdate;
+
+/// A Bevy [`SystemSet`] for various types of entity updates.
+#[derive(SystemSet, Debug, Hash, Eq, PartialEq, Clone)]
+pub enum EntityUpdateSet {
+ /// Remove ECS entities that refer to an entity that was already in the ECS
+ /// before.
+ Deduplicate,
+ /// Create search indexes for entities.
+ Index,
+ /// Remove despawned entities from search indexes.
+ Deindex,
+}
+
+/// Plugin handling some basic entity functionality.
+pub struct EntityPlugin;
+impl Plugin for EntityPlugin {
+ fn build(&self, app: &mut App) {
+ // entities get added pre-update
+ // added to indexes during update (done by this plugin)
+ // modified during update
+ // despawned post-update (done by this plugin)
+ app.add_systems(
+ PreUpdate,
+ indexing::remove_despawned_entities_from_indexes.in_set(EntityUpdateSet::Deindex),
+ )
+ .add_systems(
+ PostUpdate,
+ (
+ indexing::deduplicate_entities,
+ indexing::deduplicate_local_entities,
+ )
+ .in_set(EntityUpdateSet::Deduplicate),
+ )
+ .add_systems(
+ Update,
+ (
+ (
+ indexing::update_entity_chunk_positions,
+ indexing::update_uuid_index,
+ indexing::update_entity_by_id_index,
+ )
+ .in_set(EntityUpdateSet::Index),
+ (
+ relative_updates::add_updates_received,
+ relative_updates::debug_detect_updates_received_on_local_entities,
+ debug_new_entity,
+ add_dead,
+ update_bounding_box,
+ clamp_look_direction,
+ update_fluid_on_eyes,
+ ),
+ ),
+ )
+ .init_resource::<EntityUuidIndex>();
+ }
+}
+
+fn debug_new_entity(query: Query<(Entity, Option<&Local>), Added<MinecraftEntityId>>) {
+ for (entity, local) in query.iter() {
+ if local.is_some() {
+ debug!("new local entity: {:?}", entity);
+ } else {
+ debug!("new entity: {:?}", entity);
+ }
+ }
+}
+
+/// System that adds the [`Dead`] marker component if an entity's health is set
+/// to 0 (or less than 0). This will be present if an entity is doing the death
+/// animation.
+///
+/// Entities that are dead can not be revived.
+/// TODO: fact check this in-game by setting an entity's health to 0 and then
+/// not 0
+pub fn add_dead(mut commands: Commands, query: Query<(Entity, &Health), Changed<Health>>) {
+ for (entity, health) in query.iter() {
+ if **health <= 0.0 {
+ commands.entity(entity).insert(Dead);
+ }
+ }
+}
+
+pub fn update_fluid_on_eyes(
+ mut query: Query<(&mut FluidOnEyes, &Position, &EyeHeight, &InstanceName)>,
+ instance_container: Res<InstanceContainer>,
+) {
+ for (mut fluid_on_eyes, position, eye_height, instance_name) in query.iter_mut() {
+ let Some(instance) = instance_container.get(instance_name) else {
+ continue;
+ };
+
+ let adjusted_eye_y = position.y + (**eye_height as f64) - 0.1111111119389534;
+ let eye_block_pos = BlockPos::from(Vec3::new(position.x, adjusted_eye_y, position.z));
+ let fluid_at_eye = instance
+ .read()
+ .get_fluid_state(&eye_block_pos)
+ .unwrap_or_default();
+ let fluid_cutoff_y = eye_block_pos.y as f64 + (fluid_at_eye.height as f64 / 16f64);
+ if fluid_cutoff_y > adjusted_eye_y {
+ **fluid_on_eyes = fluid_at_eye.fluid;
+ } else {
+ **fluid_on_eyes = azalea_registry::Fluid::Empty;
+ }
+ }
+}
+
+/// A component that lists all the local player entities that have this entity
+/// loaded. If this is empty, the entity will be removed from the ECS.
+#[derive(Component, Clone, Deref, DerefMut)]
+pub struct LoadedBy(pub HashSet<Entity>);
+
+pub fn clamp_look_direction(mut query: Query<&mut LookDirection>) {
+ for mut look_direction in &mut query {
+ look_direction.y_rot %= 360.0;
+ look_direction.x_rot = look_direction.x_rot.clamp(-90.0, 90.0) % 360.0;
+ }
+}
+
+/// Sets the position of the entity. This doesn't update the cache in
+/// azalea-world, and should only be used within azalea-world!
+///
+/// # Safety
+/// Cached position in the world must be updated.
+pub fn update_bounding_box(mut query: Query<(&Position, &mut Physics), Changed<Position>>) {
+ for (position, mut physics) in query.iter_mut() {
+ let bounding_box = physics.dimensions.make_bounding_box(position);
+ physics.bounding_box = bounding_box;
+ }
+}