diff options
Diffstat (limited to 'azalea-client/src')
| -rw-r--r-- | azalea-client/src/client.rs | 47 | ||||
| -rw-r--r-- | azalea-client/src/plugins/attack.rs | 2 | ||||
| -rw-r--r-- | azalea-client/src/plugins/packet/game/mod.rs | 16 |
3 files changed, 55 insertions, 10 deletions
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index 72175dab..bb3d52e7 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -39,7 +39,7 @@ use azalea_protocol::{ }, resolver, }; -use azalea_world::{Instance, InstanceContainer, InstanceName, PartialInstance}; +use azalea_world::{Instance, InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance}; use bevy_app::{App, Plugin, PluginGroup, PluginGroupBuilder, PluginsState, Update}; use bevy_ecs::{ bundle::Bundle, @@ -587,6 +587,20 @@ impl Client { self.ecs.lock().resource::<T>().clone() } + /// Get a required ECS resource and call the given function with it. + pub fn map_resource<T: Resource, R>(&self, f: impl FnOnce(&T) -> R) -> R { + let ecs = self.ecs.lock(); + let value = ecs.resource::<T>(); + f(value) + } + + /// Get an optional ECS resource and call the given function with it. + pub fn map_get_resource<T: Resource, R>(&self, f: impl FnOnce(Option<&T>) -> R) -> R { + let ecs = self.ecs.lock(); + let value = ecs.get_resource::<T>(); + f(value) + } + /// Get a required component for this client and call the given function. /// /// Similar to [`Self::component`], but doesn't clone the component since @@ -760,6 +774,37 @@ impl Client { (*self.component::<TabList>()).clone() } + /// A convenience function to get the Minecraft Uuid of a player by their + /// username, if they're present in the tab list. + /// + /// You can chain this with [`Client::entity_by_uuid`] to get the ECS + /// `Entity` for the player. + pub fn player_uuid_by_username(&self, username: &str) -> Option<Uuid> { + self.tab_list() + .values() + .find(|player| player.profile.name == username) + .map(|player| player.profile.uuid) + } + + /// Get an ECS `Entity` in the world by its Minecraft UUID, if it's within + /// render distance. + pub fn entity_by_uuid(&self, uuid: Uuid) -> Option<Entity> { + self.map_resource::<EntityUuidIndex, _>(|entity_uuid_index| entity_uuid_index.get(&uuid)) + } + + /// Convert an ECS `Entity` to a [`MinecraftEntityId`]. + pub fn minecraft_entity_by_ecs_entity(&self, entity: Entity) -> Option<MinecraftEntityId> { + self.map_component::<EntityIdIndex, _>(|entity_id_index| { + entity_id_index.get_by_ecs_entity(entity) + }) + } + /// Convert a [`MinecraftEntityId`] to an ECS `Entity`. + pub fn ecs_entity_by_minecraft_entity(&self, entity: MinecraftEntityId) -> Option<Entity> { + self.map_component::<EntityIdIndex, _>(|entity_id_index| { + entity_id_index.get_by_minecraft_entity(entity) + }) + } + /// Call the given function with the client's [`RegistryHolder`]. /// /// The player's instance (aka world) will be locked during this time, which diff --git a/azalea-client/src/plugins/attack.rs b/azalea-client/src/plugins/attack.rs index 226ae603..5ba84772 100644 --- a/azalea-client/src/plugins/attack.rs +++ b/azalea-client/src/plugins/attack.rs @@ -41,7 +41,7 @@ impl Plugin for AttackPlugin { impl Client { /// Attack the entity with the given id. - pub fn attack(&mut self, entity_id: MinecraftEntityId) { + pub fn attack(&self, entity_id: MinecraftEntityId) { self.ecs.lock().send_event(AttackEvent { entity: self.entity, target: entity_id, diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs index ae1f3deb..8d896e65 100644 --- a/azalea-client/src/plugins/packet/game/mod.rs +++ b/azalea-client/src/plugins/packet/game/mod.rs @@ -744,7 +744,7 @@ impl GamePacketHandler<'_> { )>(self.ecs, |(mut commands, query, entity_kind_query)| { let (entity_id_index, instance_holder) = query.get(self.player).unwrap(); - let entity = entity_id_index.get(p.id); + let entity = entity_id_index.get_by_minecraft_entity(p.id); let Some(entity) = entity else { // some servers like hypixel trigger this a lot :( @@ -803,7 +803,7 @@ impl GamePacketHandler<'_> { |(mut commands, query)| { let (entity_id_index, instance_holder) = query.get(self.player).unwrap(); - let Some(entity) = entity_id_index.get(p.id) else { + let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else { // note that this log (and some other ones like the one in RemoveEntities) // sometimes happens when killing mobs. it seems to be a vanilla bug, which is // why it's a debug log instead of a warning @@ -876,7 +876,7 @@ impl GamePacketHandler<'_> { |(mut commands, mut query)| { let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); - let Some(entity) = entity_id_index.get(p.id) else { + let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else { warn!("Got teleport entity packet for unknown entity id {}", p.id); return; }; @@ -922,7 +922,7 @@ impl GamePacketHandler<'_> { debug!("Got move entity pos packet {p:?}"); let entity_id = p.entity_id; - let Some(entity) = entity_id_index.get(entity_id) else { + let Some(entity) = entity_id_index.get_by_minecraft_entity(entity_id) else { debug!("Got move entity pos packet for unknown entity id {entity_id}"); return; }; @@ -964,7 +964,7 @@ impl GamePacketHandler<'_> { debug!("Got move entity pos rot packet {p:?}"); - let entity = entity_id_index.get(p.entity_id); + let entity = entity_id_index.get_by_minecraft_entity(p.entity_id); let Some(entity) = entity else { // often triggered by hypixel :( @@ -1016,7 +1016,7 @@ impl GamePacketHandler<'_> { |(mut commands, mut query)| { let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); - let entity = entity_id_index.get(p.entity_id); + let entity = entity_id_index.get_by_minecraft_entity(p.entity_id); if let Some(entity) = entity { let new_look_direction = LookDirection { x_rot: (p.x_rot as i32 * 360) as f32 / 256., @@ -1075,7 +1075,7 @@ impl GamePacketHandler<'_> { }; for &id in &p.entity_ids { - let Some(entity) = entity_id_index.remove(id) else { + let Some(entity) = entity_id_index.remove_by_minecraft_entity(id) else { debug!( "Tried to remove entity with id {id} but it wasn't in the EntityIdIndex. This may be expected on certain server setups (like if they're using VeryManyPlayers)." ); @@ -1524,7 +1524,7 @@ impl GamePacketHandler<'_> { |(mut commands, mut query)| { let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap(); - let Some(entity) = entity_id_index.get(p.id) else { + let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else { debug!("Got teleport entity packet for unknown entity id {}", p.id); return; }; |
