aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--azalea-client/src/client.rs47
-rw-r--r--azalea-client/src/plugins/attack.rs2
-rw-r--r--azalea-client/src/plugins/packet/game/mod.rs16
-rw-r--r--azalea-entity/src/plugin/indexing.rs9
4 files changed, 61 insertions, 13 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;
};
diff --git a/azalea-entity/src/plugin/indexing.rs b/azalea-entity/src/plugin/indexing.rs
index 85f0f76c..2a7643b0 100644
--- a/azalea-entity/src/plugin/indexing.rs
+++ b/azalea-entity/src/plugin/indexing.rs
@@ -64,11 +64,14 @@ pub struct EntityIdIndex {
}
impl EntityIdIndex {
- pub fn get(&self, id: MinecraftEntityId) -> Option<Entity> {
+ pub fn get_by_minecraft_entity(&self, id: MinecraftEntityId) -> Option<Entity> {
self.entity_by_id.get(&id).copied()
}
+ pub fn get_by_ecs_entity(&self, entity: Entity) -> Option<MinecraftEntityId> {
+ self.id_by_entity.get(&entity).copied()
+ }
- pub fn contains_key(&self, id: MinecraftEntityId) -> bool {
+ pub fn contains_minecraft_entity(&self, id: MinecraftEntityId) -> bool {
self.entity_by_id.contains_key(&id)
}
pub fn contains_ecs_entity(&self, id: Entity) -> bool {
@@ -81,7 +84,7 @@ impl EntityIdIndex {
trace!("Inserted {id} -> {entity:?} into a client's EntityIdIndex");
}
- pub fn remove(&mut self, id: MinecraftEntityId) -> Option<Entity> {
+ pub fn remove_by_minecraft_entity(&mut self, id: MinecraftEntityId) -> Option<Entity> {
if let Some(entity) = self.entity_by_id.remove(&id) {
trace!(
"Removed {id} -> {entity:?} from a client's EntityIdIndex (using EntityIdIndex::remove)"