aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-08-12 11:00:11 -1000
committermat <git@matdoes.dev>2025-08-12 11:00:11 -1000
commit7f4e3c583dd669561e8502822952fc9afe26e005 (patch)
tree831fbcb717493858c31ad58796e01494da276d76
parentc36c3c0ed02b3727ba61b45a6a7febf1a008a7dc (diff)
downloadazalea-drasl-7f4e3c583dd669561e8502822952fc9afe26e005.tar.xz
add nearest_entity_by and improve some docs
-rw-r--r--CHANGELOG.md4
-rw-r--r--azalea-chat/src/component.rs15
-rw-r--r--azalea-client/src/account.rs4
-rw-r--r--azalea-client/src/entity_query.rs58
-rw-r--r--azalea-client/src/plugins/movement.rs2
-rw-r--r--azalea-entity/src/lib.rs27
-rw-r--r--azalea-inventory/src/default_components/mod.rs3
-rw-r--r--azalea-inventory/src/operations.rs1
-rw-r--r--azalea/README.md7
-rw-r--r--azalea/examples/testbot/commands.rs7
-rw-r--r--azalea/src/container.rs4
-rw-r--r--azalea/src/pathfinder/goto_event.rs5
12 files changed, 101 insertions, 36 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 979a1ad5..5850f181 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ is breaking anyways, semantic versioning is not followed.
- Local clients now have a `TicksConnected` component. (@Kumpelinus)
- There is now a `azalea_inventory::default_components::get_default_component` function to get the default value of a component for a registry item.
- `ItemStack` now has a `get_component` function that supports default components.
+- Add `Client::nearest_entity_by`.
### Changed
@@ -24,18 +25,19 @@ is breaking anyways, semantic versioning is not followed.
- `Client::attack` now takes `Entity` instead of `MinecraftEntityId`.
- `ItemStackData::components` was renamed to `component_patch`.
- The fields in `LookDirection` have been replaced with getters.
+- Renamed `Client::entity_by` to `any_entity_by`, and `Client::entities_by` to `nearest_entities_by`.
### Fixed
- Fix packet order for loading (`PlayerLoaded`/`MovePlayerPos`) and sprinting (`PlayerInput`/`PlayerCommand`).
- Clients no longer send invalid look directions if the server teleports us with one.
+- Look directions are now rounded based on the default Minecraft sensitivity, which may help avoid flagging anticheats.
- Movement code was updated with the changes from 1.21.5, so it no longer flags Grim.
- `azalea-chat` now handles arrays of integers in the `with` field. (@qwqawawow)
- `azalea-chat` no longer incorrectly persists styles of components in the "extra" field.
- Inventories now use the correct max stack sizes.
- Clients now send the correct data component checksums when interacting with items.
- Fix parsing some metadata fields of Display entities.
-- Look directions are now rounded based on the default Minecraft sensitivity, which may help avoid flagging anticheats.
## [0.13.0+mc1.21.5] - 2025-06-15
diff --git a/azalea-chat/src/component.rs b/azalea-chat/src/component.rs
index bf064c8f..62e5e151 100644
--- a/azalea-chat/src/component.rs
+++ b/azalea-chat/src/component.rs
@@ -131,7 +131,6 @@ impl FormattedText {
&mut output,
&mut style_formatter,
&mut text_formatter,
- &mut cleanup_formatter,
&default_style.clone(),
&mut running_style,
);
@@ -140,18 +139,16 @@ impl FormattedText {
output
}
- fn to_custom_format_recursive<F, S, C>(
+ fn to_custom_format_recursive<F, S>(
&self,
output: &mut String,
style_formatter: &mut F,
text_formatter: &mut S,
- cleanup_formatter: &mut C,
parent_style: &Style,
running_style: &mut Style,
) where
F: FnMut(&Style, &Style) -> (String, String),
S: FnMut(&str) -> String,
- C: FnMut(&Style) -> String,
{
let component_text = match &self {
Self::Text(c) => c.text.to_string(),
@@ -166,7 +163,7 @@ impl FormattedText {
if !component_text.is_empty() {
let (formatted_style_prefix, formatted_style_suffix) =
- style_formatter(&running_style, &new_style);
+ style_formatter(running_style, &new_style);
let formatted_text = text_formatter(&component_text);
output.push_str(&formatted_style_prefix);
@@ -181,7 +178,6 @@ impl FormattedText {
output,
style_formatter,
text_formatter,
- cleanup_formatter,
&new_style,
running_style,
);
@@ -211,7 +207,7 @@ impl FormattedText {
/// colored white.
///
/// If you don't want the result to be styled at all, use
- /// [`Self::to_string`].
+ /// [`Self::to_string`](#method.fmt-1).
///
/// # Examples
///
@@ -230,6 +226,7 @@ impl FormattedText {
self.to_ansi_with_custom_style(&DEFAULT_STYLE)
}
+ /// Similar to [`Self::to_ansi`] but renders the result as HTML instead.
pub fn to_html(&self) -> String {
self.to_custom_format(
|running, new| {
@@ -664,6 +661,10 @@ impl From<TextComponent> for FormattedText {
}
impl Display for FormattedText {
+ /// Render the text in the component but without any formatting/styling.
+ ///
+ /// If you want the text to be styled, consider using [`Self::to_ansi`] or
+ /// [`Self::to_html`].
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FormattedText::Text(c) => c.fmt(f),
diff --git a/azalea-client/src/account.rs b/azalea-client/src/account.rs
index 7e3f917d..bda69558 100644
--- a/azalea-client/src/account.rs
+++ b/azalea-client/src/account.rs
@@ -22,8 +22,8 @@ use uuid::Uuid;
/// # Examples
///
/// ```rust,no_run
-/// use azalea_client::Account;
-///
+/// # use azalea_client::Account;
+/// #
/// # #[tokio::main]
/// # async fn main() {
/// let account = Account::microsoft("example@example.com").await;
diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs
index ee99d0f4..49119b98 100644
--- a/azalea-client/src/entity_query.rs
+++ b/azalea-client/src/entity_query.rs
@@ -36,15 +36,16 @@ impl Client {
})
}
- /// Return a lightweight [`Entity`] for an arbitrary entity that matches the
- /// given predicate function that is in the same [`Instance`] as the
- /// client.
+ /// Quickly returns a lightweight [`Entity`] for an arbitrary entity that
+ /// matches the given predicate function that is in the same
+ /// [`Instance`] as the client.
///
/// You can then use [`Self::entity_component`] to get components from this
/// entity.
///
- /// Also see [`Self::entities_by`] which will return all entities that match
- /// the predicate and sorts them by distance (unlike `entity_by`).
+ /// If you want to find the nearest entity, consider using
+ /// [`Self::nearest_entity_by`] instead. If you want to find all entities
+ /// that match the predicate, use [`Self::nearest_entities_by`].
///
/// # Example
/// ```
@@ -65,7 +66,7 @@ impl Client {
///
/// [`Entity`]: bevy_ecs::entity::Entity
/// [`Instance`]: azalea_world::Instance
- pub fn entity_by<F: QueryFilter, Q: QueryData>(
+ pub fn any_entity_by<F: QueryFilter, Q: QueryData>(
&self,
predicate: impl EntityPredicate<Q, F>,
) -> Option<Entity> {
@@ -73,12 +74,47 @@ impl Client {
predicate.find_any(self.ecs.clone(), &instance_name)
}
- /// Similar to [`Self::entity_by`] but returns a `Vec<Entity>` of all
- /// entities in our instance that match the predicate.
+ /// Return a lightweight [`Entity`] for the nearest entity that matches the
+ /// given predicate function.
///
- /// Unlike `entity_by`, the result is sorted by distance to our client's
- /// position, so the closest entity is first.
- pub fn entities_by<F: QueryFilter, Q: QueryData>(
+ /// You can then use [`Self::entity_component`] to get components from this
+ /// entity.
+ ///
+ /// If you don't need the entity to be the nearest one, it may be more
+ /// efficient to use [`Self::any_entity_by`] instead. You can also use
+ /// [`Self::nearest_entities_by`] to get all nearby entities.
+ ///
+ /// # Example
+ /// ```
+ /// use azalea_entity::{Position, metadata::Player, LocalEntity};
+ /// use bevy_ecs::query::With;
+ ///
+ /// # fn example(mut bot: azalea_client::Client, sender_name: String) {
+ /// // look at the nearest player
+ /// if let Some(closest_player) = bot
+ /// .entities_by::<(With<Player>, Without<LocalEntity>), ()>(|_: &()| true)
+ /// .first()
+ /// {
+ /// let closest_player_pos = *bot.entity_component::<Position>(*closest_player);
+ /// bot.look_at(closest_player_pos.up(1.62));
+ /// }
+ /// }
+ /// ```
+ ///
+ /// [`Entity`]: bevy_ecs::entity::Entity
+ /// [`Instance`]: azalea_world::Instance
+ pub fn nearest_entity_by<F: QueryFilter, Q: QueryData>(
+ &self,
+ predicate: impl EntityPredicate<Q, F>,
+ ) -> Option<Entity> {
+ self.nearest_entities_by(predicate).first().copied()
+ }
+
+ /// Similar to [`Self::nearest_entity_by`] but returns a `Vec<Entity>` of
+ /// all entities in our instance that match the predicate.
+ ///
+ /// The first entity is the nearest one.
+ pub fn nearest_entities_by<F: QueryFilter, Q: QueryData>(
&self,
predicate: impl EntityPredicate<Q, F>,
) -> Vec<Entity> {
diff --git a/azalea-client/src/plugins/movement.rs b/azalea-client/src/plugins/movement.rs
index c27a67ce..675796f6 100644
--- a/azalea-client/src/plugins/movement.rs
+++ b/azalea-client/src/plugins/movement.rs
@@ -452,7 +452,7 @@ impl Client {
}
/// Start sprinting in the given direction. To stop moving, call
- /// [`Client::walk(WalkDirection::None)`]
+ /// [`bot.walk(WalkDirection::None)`](Self::walk)
///
/// # Examples
///
diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs
index 8758c258..645a5534 100644
--- a/azalea-entity/src/lib.rs
+++ b/azalea-entity/src/lib.rs
@@ -230,8 +230,7 @@ pub struct LookDirection {
}
impl LookDirection {
- /// Create a new look direction, while clamping and wrapping the rotations
- /// to the allowed values.
+ /// Create a new look direction and clamp the `x_rot` to the allowed values.
pub fn new(y_rot: f32, x_rot: f32) -> Self {
apply_clamp_look_direction(Self { y_rot, x_rot })
}
@@ -255,12 +254,32 @@ impl LookDirection {
pub fn update(&mut self, new: LookDirection) {
self.update_with_sensitivity(new, 1.);
}
+ /// Update the `y_rot` to the given value, in degrees.
+ ///
+ /// This is a shortcut for [`Self::update`] while keeping the `x_rot` the
+ /// same.
+ pub fn update_y_rot(&mut self, new_y_rot: f32) {
+ self.update(LookDirection {
+ y_rot: new_y_rot,
+ x_rot: self.x_rot,
+ });
+ }
+ /// Update the `x_rot` to the given value, in degrees.
+ ///
+ /// This is a shortcut for [`Self::update`] while keeping the `y_rot` the
+ /// same.
+ pub fn update_x_rot(&mut self, new_x_rot: f32) {
+ self.update(LookDirection {
+ y_rot: self.y_rot,
+ x_rot: new_x_rot,
+ });
+ }
/// Update this look direction to the new value, using the given
/// sensitivity value.
///
- /// Consider using [`Self::set`] instead, which uses 1.0 as the sensitivity
- /// (equivalent to 100% sensitivity in Minecraft).
+ /// Consider using [`Self::update`] instead, which uses 1.0 as the
+ /// sensitivity (equivalent to 100% sensitivity in Minecraft).
pub fn update_with_sensitivity(&mut self, new: LookDirection, sensitivity: f32) {
let mut delta_y_rot = new.y_rot.rem_euclid(360.) - self.y_rot.rem_euclid(360.);
let delta_x_rot = new.x_rot - self.x_rot;
diff --git a/azalea-inventory/src/default_components/mod.rs b/azalea-inventory/src/default_components/mod.rs
index 7f9ef6fb..74b7248e 100644
--- a/azalea-inventory/src/default_components/mod.rs
+++ b/azalea-inventory/src/default_components/mod.rs
@@ -4,7 +4,8 @@ use azalea_registry::Item;
use crate::components::DataComponentTrait;
-/// A [`DataComponent`] that some [`Item`]s may have a default value for.
+/// A trait for data components that some [`Item`]s may have a default value
+/// for.
pub trait DefaultableComponent: DataComponentTrait {
fn default_for_item(item: Item) -> Option<Self>
where
diff --git a/azalea-inventory/src/operations.rs b/azalea-inventory/src/operations.rs
index e7668ab5..60bf9e64 100644
--- a/azalea-inventory/src/operations.rs
+++ b/azalea-inventory/src/operations.rs
@@ -13,6 +13,7 @@ use crate::{
StonecutterMenuLocation, item::MaxStackSizeExt,
};
+/// A type of click in a Minecraft inventory.
#[derive(Debug, Clone)]
pub enum ClickOperation {
Pickup(PickupClick),
diff --git a/azalea/README.md b/azalea/README.md
index 4f7506d1..3454ed2e 100644
--- a/azalea/README.md
+++ b/azalea/README.md
@@ -32,10 +32,6 @@ opt-level = 3
The documentation for the latest Azalea crates.io release is available at [docs.rs/azalea](https://docs.rs/azalea/latest/azalea/) and the docs for the latest bleeding-edge (git) version are at [azalea.matdoes.dev](https://azalea.matdoes.dev/azalea/).
-Note that the `azalea` crate is technically just a wrapper over [`azalea_client`] that adds some extra functions.
-Because of this, some of the documentation will refer to `azalea_client`.
-You can just replace these with `azalea` in your code since everything from `azalea_client` is re-exported in azalea.
-
# Examples
```rust,no_run
@@ -76,6 +72,9 @@ async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
}
```
+There are more examples in the [examples directory](https://github.com/azalea-rs/azalea/tree/main/azalea/examples).
+You may also find it helpful to read the code for [other people's Azalea bots](https://github.com/azalea-rs/azalea#real-world-bots-using-azalea).
+
# Swarms
Azalea lets you create "swarms", which are a group of bots in the same world that can perform actions together. See [testbot](https://github.com/azalea-rs/azalea/blob/main/azalea/examples/testbot/main.rs) for an example. Also, if you're using swarms, you should also `use` both `azalea::prelude::*` and `azalea::swarm::prelude::*`.
diff --git a/azalea/examples/testbot/commands.rs b/azalea/examples/testbot/commands.rs
index ecd68ade..7486780e 100644
--- a/azalea/examples/testbot/commands.rs
+++ b/azalea/examples/testbot/commands.rs
@@ -31,9 +31,10 @@ impl CommandSource {
pub fn entity(&mut self) -> Option<Entity> {
let username = self.chat.sender()?;
- self.bot.entity_by::<With<Player>, &GameProfileComponent>(
- |profile: &&GameProfileComponent| profile.name == username,
- )
+ self.bot
+ .any_entity_by::<With<Player>, &GameProfileComponent>(
+ |profile: &&GameProfileComponent| profile.name == username,
+ )
}
}
diff --git a/azalea/src/container.rs b/azalea/src/container.rs
index ee618df2..a7b496ea 100644
--- a/azalea/src/container.rs
+++ b/azalea/src/container.rs
@@ -174,7 +174,7 @@ impl ContainerHandleRef {
///
/// Note that any modifications you make to the `Menu` you're given will not
/// actually cause any packets to be sent. If you're trying to modify your
- /// inventory, use [`ContainerHandle::click`] instead
+ /// inventory, use [`Self::click`] instead
pub fn menu(&self) -> Option<Menu> {
let ecs = self.client.ecs.lock();
let inventory = ecs
@@ -224,6 +224,8 @@ impl ContainerHandleRef {
});
}
+ /// Simulate a click in the container and send the packet to perform the
+ /// action.
pub fn click(&self, operation: impl Into<ClickOperation>) {
let operation = operation.into();
self.client.ecs.lock().send_event(ContainerClickEvent {
diff --git a/azalea/src/pathfinder/goto_event.rs b/azalea/src/pathfinder/goto_event.rs
index dfd89122..d87d1586 100644
--- a/azalea/src/pathfinder/goto_event.rs
+++ b/azalea/src/pathfinder/goto_event.rs
@@ -12,7 +12,10 @@ use crate::pathfinder::{
///
/// Also see [`PathfinderClientExt::goto`].
///
-/// This event is read by [`goto_listener`].
+/// This event is read by [`goto_listener`]
+///
+/// [`goto_listener`]: crate::pathfinder::goto_listener
+/// [`PathfinderClientExt::goto`]: crate::pathfinder::PathfinderClientExt::goto
#[derive(Event)]
#[non_exhaustive]
pub struct GotoEvent {