diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index 6b2dba57..d5f40678 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -141,8 +141,12 @@ impl From for PlayerAbilities { #[derive(Component, Clone, Default, Deref, DerefMut)] pub struct PermissionLevel(pub u8); -/// A component that contains a map of player UUIDs to their information in the -/// tab list. +/// A component and resource that contains a map of player UUIDs to their +/// information in the tab list. +/// +/// This is a component on local players in case you want to get the tab list +/// that a certain client is seeing, and it's also a resource in case you know +/// that the server gives the same tab list to every player. /// /// ``` /// # use azalea_client::TabList; @@ -153,7 +157,7 @@ pub struct PermissionLevel(pub u8); /// println!("- {} ({}ms)", player_info.profile.name, player_info.latency); /// } /// # } -#[derive(Component, Clone, Debug, Deref, DerefMut, Default)] +#[derive(Component, Resource, Clone, Debug, Deref, DerefMut, Default)] pub struct TabList(HashMap); /// An error that happened while joining the server. @@ -648,7 +652,8 @@ impl Plugin for AzaleaPlugin { ), ) .add_event::() - .init_resource::(); + .init_resource::() + .init_resource::(); } } diff --git a/azalea-client/src/packet_handling.rs b/azalea-client/src/packet_handling.rs index 44cc30ca..6ac657d7 100644 --- a/azalea-client/src/packet_handling.rs +++ b/azalea-client/src/packet_handling.rs @@ -466,7 +466,9 @@ pub fn process_packet_events(ecs: &mut World) { z: new_pos_z, }; - **position = new_pos; + if new_pos != **position { + **position = new_pos; + } local_player.write_packet(ServerboundAcceptTeleportationPacket { id: p.id }.get()); local_player.write_packet( @@ -485,13 +487,19 @@ pub fn process_packet_events(ecs: &mut World) { ClientboundGamePacket::PlayerInfoUpdate(p) => { debug!("Got player info packet {:?}", p); + #[allow(clippy::type_complexity)] let mut system_state: SystemState<( Query<&mut TabList>, EventWriter, EventWriter, + ResMut, )> = SystemState::new(ecs); - let (mut query, mut add_player_events, mut update_player_events) = - system_state.get_mut(ecs); + let ( + mut query, + mut add_player_events, + mut update_player_events, + mut tab_list_resource, + ) = system_state.get_mut(ecs); let mut tab_list = query.get_mut(player_entity).unwrap(); for updated_info in &p.entries { @@ -532,13 +540,17 @@ pub fn process_packet_events(ecs: &mut World) { ); } } + + *tab_list_resource = tab_list.clone(); } ClientboundGamePacket::PlayerInfoRemove(p) => { let mut system_state: SystemState<( Query<&mut TabList>, EventWriter, + ResMut, )> = SystemState::new(ecs); - let (mut query, mut remove_player_events) = system_state.get_mut(ecs); + let (mut query, mut remove_player_events, mut tab_list_resource) = + system_state.get_mut(ecs); let mut tab_list = query.get_mut(player_entity).unwrap(); for uuid in &p.profile_ids { @@ -548,6 +560,7 @@ pub fn process_packet_events(ecs: &mut World) { info, }); } + tab_list_resource.remove(uuid); } } ClientboundGamePacket::SetChunkCacheCenter(p) => { @@ -785,12 +798,14 @@ pub fn process_packet_events(ecs: &mut World) { let entity = entity_id_index.get(&MinecraftEntityId(p.id)); if let Some(entity) = entity { - let new_position = p.position; + let new_pos = p.position; commands.entity(entity).add(RelativeEntityUpdate { partial_world: local_player.partial_instance.clone(), update: Box::new(move |entity| { let mut position = entity.get_mut::().unwrap(); - **position = new_position; + if new_pos != **position { + **position = new_pos; + } }), }); } else { @@ -821,7 +836,10 @@ pub fn process_packet_events(ecs: &mut World) { partial_world: local_player.partial_instance.clone(), update: Box::new(move |entity_mut| { let mut position = entity_mut.get_mut::().unwrap(); - **position = position.with_delta(&delta); + let new_pos = position.with_delta(&delta); + if new_pos != **position { + **position = new_pos; + } }), }); } else { @@ -849,7 +867,10 @@ pub fn process_packet_events(ecs: &mut World) { partial_world: local_player.partial_instance.clone(), update: Box::new(move |entity_mut| { let mut position = entity_mut.get_mut::().unwrap(); - **position = position.with_delta(&delta); + let new_pos = position.with_delta(&delta); + if new_pos != **position { + **position = new_pos; + } }), }); } else { diff --git a/azalea-core/src/delta.rs b/azalea-core/src/delta.rs index ce49ab50..05bf662a 100755 --- a/azalea-core/src/delta.rs +++ b/azalea-core/src/delta.rs @@ -40,7 +40,7 @@ impl PositionDeltaTrait for PositionDelta8 { impl Vec3 { #[must_use] - pub fn with_delta(&self, delta: &dyn PositionDeltaTrait) -> Vec3 { + pub fn with_delta(&self, delta: &impl PositionDeltaTrait) -> Vec3 { Vec3 { x: self.x + delta.x(), y: self.y + delta.y(), diff --git a/azalea-entity/src/plugin/indexing.rs b/azalea-entity/src/plugin/indexing.rs index a8ea9d85..d2049b6e 100644 --- a/azalea-entity/src/plugin/indexing.rs +++ b/azalea-entity/src/plugin/indexing.rs @@ -126,7 +126,7 @@ pub fn deduplicate_entities( info!( "Entity with id {id:?} / {new_entity:?} already existed in the world, merging it with {old_entity:?}" ); - break; + continue; } } else { error!("Entity was inserted into a world that doesn't exist."); @@ -309,6 +309,6 @@ pub fn remove_despawned_entities_from_indexes( // and now remove the entity from the ecs commands.entity(entity).despawn(); debug!("Despawned entity {entity:?} because it was not loaded by anything."); - return; + continue; } } diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index de9439ca..1013b4fc 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -8,6 +8,7 @@ use std::ops::Add; use azalea_core::{Axis, Vec3, AABB, EPSILON}; use azalea_world::{Instance, MoveEntityError}; +use bevy_ecs::world::Mut; pub use blocks::BlockWithShape; pub use discrete_voxel_shape::*; pub use shape::*; @@ -138,7 +139,7 @@ pub fn move_colliding( _mover_type: &MoverType, movement: &Vec3, world: &Instance, - position: &mut azalea_entity::Position, + mut position: Mut, physics: &mut azalea_entity::Physics, ) -> Result<(), MoveEntityError> { // TODO: do all these @@ -177,7 +178,9 @@ pub fn move_colliding( } }; - **position = new_pos; + if new_pos != **position { + **position = new_pos; + } } let x_collision = movement.x != collide_result.x; @@ -189,7 +192,7 @@ pub fn move_colliding( // TODO: minecraft checks for a "minor" horizontal collision here - let _block_pos_below = azalea_entity::on_pos_legacy(&world.chunks, position); + let _block_pos_below = azalea_entity::on_pos_legacy(&world.chunks, &position); // let _block_state_below = self // .world // .get_block_state(&block_pos_below) diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 52bb4b9c..5fe7d218 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -16,6 +16,7 @@ use bevy_ecs::{ query::With, schedule::{IntoSystemConfigs, SystemSet}, system::{Query, Res}, + world::Mut, }; use collision::{move_colliding, MoverType}; @@ -53,7 +54,7 @@ fn travel( >, instance_container: Res, ) { - for (mut physics, direction, mut position, sprinting, attributes, world_name) in &mut query { + for (mut physics, direction, position, sprinting, attributes, world_name) in &mut query { let world_lock = instance_container .get(world_name) .expect("All entities should be in a valid world"); @@ -93,7 +94,7 @@ fn travel( &world, &mut physics, &direction, - &mut position, + position, attributes, sprinting.map(|s| **s).unwrap_or(false), ); @@ -222,7 +223,8 @@ fn handle_relative_friction_and_calculate_movement( world: &Instance, physics: &mut Physics, direction: &LookDirection, - position: &mut Position, + // this is kept as a Mut for bevy change tracking + position: Mut, attributes: &Attributes, is_sprinting: bool, ) -> Vec3 { diff --git a/azalea-world/src/heightmap.rs b/azalea-world/src/heightmap.rs index 81aeb1e2..5fa3f260 100644 --- a/azalea-world/src/heightmap.rs +++ b/azalea-world/src/heightmap.rs @@ -122,7 +122,7 @@ impl Heightmap { /// Get an iterator over the top available block positions in this /// heightmap. - pub fn iter_first_available<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter_first_available(&self) -> impl Iterator + '_ { self.data.iter().enumerate().map(move |(index, height)| { let x = (index % 16) as u8; let z = (index / 16) as u8; @@ -131,7 +131,7 @@ impl Heightmap { } /// Get an iterator over the top block positions in this heightmap. - pub fn iter_highest_taken<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter_highest_taken(&self) -> impl Iterator + '_ { self.data.iter().enumerate().map(move |(index, height)| { let x = (index % 16) as u8; let z = (index / 16) as u8; diff --git a/azalea/src/lib.rs b/azalea/src/lib.rs index 02ea1207..b6cd4e9d 100644 --- a/azalea/src/lib.rs +++ b/azalea/src/lib.rs @@ -23,7 +23,7 @@ pub use azalea_client::*; pub use azalea_core::{BlockPos, ChunkPos, ResourceLocation, Vec3}; pub use azalea_entity as entity; pub use azalea_protocol as protocol; -pub use azalea_registry::{Block, EntityKind, Item}; +pub use azalea_registry as registry; pub use azalea_world as world; pub use bot::*; use ecs::component::Component;