aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--azalea-auth/src/auth.rs2
-rw-r--r--azalea-buf/src/definitions.rs2
-rw-r--r--azalea-client/src/account.rs23
-rw-r--r--azalea-client/src/chat.rs32
-rw-r--r--azalea-client/src/client.rs24
-rwxr-xr-xazalea-client/src/lib.rs7
-rw-r--r--azalea-client/src/movement.rs2
-rwxr-xr-xazalea-client/src/ping.rs22
-rw-r--r--azalea-protocol/src/connect.rs2
-rw-r--r--azalea/README.md4
-rw-r--r--azalea/examples/craft_dig_straight_down.rs2
-rw-r--r--azalea/examples/echo.rs13
-rw-r--r--azalea/examples/pvp.rs3
-rw-r--r--azalea/src/lib.rs67
-rw-r--r--azalea/src/prelude.rs3
15 files changed, 167 insertions, 41 deletions
diff --git a/azalea-auth/src/auth.rs b/azalea-auth/src/auth.rs
index 98ea4952..3e5f82d8 100644
--- a/azalea-auth/src/auth.rs
+++ b/azalea-auth/src/auth.rs
@@ -48,7 +48,7 @@ pub enum AuthError {
GetXboxLiveAuth(#[from] XboxLiveAuthError),
}
-/// Authenticate with authenticate with Microsoft. If the data isn't cached,
+/// Authenticate with Microsoft. If the data isn't cached,
/// they'll be asked to go to log into Microsoft in a web page.
///
/// The email is technically only used as a cache key, so it *could* be
diff --git a/azalea-buf/src/definitions.rs b/azalea-buf/src/definitions.rs
index 77309c46..18581aa0 100644
--- a/azalea-buf/src/definitions.rs
+++ b/azalea-buf/src/definitions.rs
@@ -1,6 +1,6 @@
use std::ops::Deref;
-/// A Vec<u8> that isn't prefixed by a VarInt with the size.
+/// A `Vec<u8>` that isn't prefixed by a VarInt with the size.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnsizedByteArray(pub Vec<u8>);
diff --git a/azalea-client/src/account.rs b/azalea-client/src/account.rs
index fc34d6c4..f63d342e 100644
--- a/azalea-client/src/account.rs
+++ b/azalea-client/src/account.rs
@@ -1,13 +1,14 @@
//! Connect to Minecraft servers.
-use crate::{client::JoinError, get_mc_dir, Client, Event};
-use azalea_protocol::ServerAddress;
-use tokio::sync::mpsc::UnboundedReceiver;
+use crate::get_mc_dir;
use uuid::Uuid;
/// Something that can join Minecraft servers.
+///
+/// To join a server using this account, use [`crate::Client::join`].
#[derive(Clone, Debug)]
pub struct Account {
+ /// The Minecraft username of the account.
pub username: String,
/// The access token for authentication. You can obtain one of these
/// manually from azalea-auth.
@@ -15,7 +16,11 @@ pub struct Account {
/// Only required for online-mode accounts.
pub uuid: Option<uuid::Uuid>,
}
+
impl Account {
+ /// An offline account does not authenticate with Microsoft's servers, and
+ /// as such can only join offline mode servers. This is useful for testing
+ /// in LAN worlds.
pub fn offline(username: &str) -> Self {
Self {
username: username.to_string(),
@@ -24,6 +29,10 @@ impl Account {
}
}
+ /// This will create an online-mode account by authenticating with
+ /// Microsoft's servers. Note that the email given is actually only used as
+ /// a key for the cache, but it's recommended to use the real email to
+ /// avoid confusion.
pub async fn microsoft(email: &str) -> Result<Self, azalea_auth::AuthError> {
let minecraft_dir = get_mc_dir::minecraft_dir().unwrap();
let auth_result = azalea_auth::auth(
@@ -40,12 +49,4 @@ impl Account {
uuid: Some(Uuid::parse_str(&auth_result.profile.id).expect("Invalid UUID")),
})
}
-
- /// Joins the Minecraft server on the given address using this account.
- pub async fn join(
- &self,
- address: &ServerAddress,
- ) -> Result<(Client, UnboundedReceiver<Event>), JoinError> {
- Client::join(self, address).await
- }
}
diff --git a/azalea-client/src/chat.rs b/azalea-client/src/chat.rs
index 6176357f..9e3d58a0 100644
--- a/azalea-client/src/chat.rs
+++ b/azalea-client/src/chat.rs
@@ -11,8 +11,9 @@ use crate::Client;
impl Client {
/// Sends chat message to the server. This only sends the chat packet and
- /// not the command packet. The `chat` function handles checking whether
- /// the message is a command and using the proper packet for you.
+ /// not the command packet. The [`Client::chat`] function handles checking whether
+ /// the message is a command and using the proper packet for you, so you
+ /// should use that instead.
pub async fn send_chat_packet(&self, message: &str) -> Result<(), std::io::Error> {
// TODO: chat signing
let signature = sign_message();
@@ -54,6 +55,33 @@ impl Client {
self.write_packet(packet).await
}
+ /// Send a message in chat.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,no_run
+ /// # use azalea::prelude::*;
+ /// # use parking_lot::Mutex;
+ /// # use std::sync::Arc;
+ /// # #[tokio::main]
+ /// # async fn main() {
+ /// # let account = Account::offline("bot");
+ /// # azalea::start(azalea::Options {
+ /// # account,
+ /// # address: "localhost",
+ /// # state: Arc::new(Mutex::new(State::default())),
+ /// # plugins: vec![],
+ /// # handle,
+ /// # })
+ /// # .await
+ /// # .unwrap();
+ /// # }
+ /// # pub struct State {}
+ /// # async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
+ /// bot.chat("Hello, world!").await.unwrap();
+ /// # Ok(())
+ /// # }
+ /// ```
pub async fn chat(&self, message: &str) -> Result<(), std::io::Error> {
if message.chars().next() == Some('/') {
self.send_command_packet(&message[1..]).await
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs
index a59c340b..fc4ff477 100644
--- a/azalea-client/src/client.rs
+++ b/azalea-client/src/client.rs
@@ -69,7 +69,7 @@ impl ChatPacket {
}
}
-/// A player that you can control that is currently in a Minecraft server.
+/// A player that you control that is currently in a Minecraft server.
#[derive(Clone)]
pub struct Client {
game_profile: GameProfile,
@@ -106,6 +106,8 @@ pub enum JoinError {
Io(#[from] io::Error),
#[error("{0}")]
SessionServer(#[from] azalea_auth::sessionserver::SessionServerError),
+ #[error("The given address could not be parsed into a ServerAddress")]
+ InvalidAddress,
}
#[derive(Error, Debug)]
@@ -119,12 +121,26 @@ pub enum HandleError {
}
impl Client {
- /// Connect to a Minecraft server with an account.
+ /// Connect to a Minecraft server.
+ ///
+ /// ```rust,no_run
+ /// use azalea_client::Client;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> Box<dyn std::error::Error> {
+ /// let account = Account::offline("bot");
+ /// let client = Client::join(&account, "localhost").await?;
+ /// client.chat("Hello, world!").await?;
+ /// client.shutdown().await?;
+ /// }
+ /// ```
pub async fn join(
account: &Account,
- address: &ServerAddress,
+ address: impl TryInto<ServerAddress>,
) -> Result<(Self, UnboundedReceiver<Event>), JoinError> {
- let resolved_address = resolver::resolve_address(address).await?;
+ let address: ServerAddress = address.try_into().map_err(|_| JoinError::InvalidAddress)?;
+
+ let resolved_address = resolver::resolve_address(&address).await?;
let mut conn = Connection::new(&resolved_address).await?;
diff --git a/azalea-client/src/lib.rs b/azalea-client/src/lib.rs
index 1ed30394..61d2d9ee 100755
--- a/azalea-client/src/lib.rs
+++ b/azalea-client/src/lib.rs
@@ -1,4 +1,9 @@
-//! Significantly abstract azalea-protocol so it's actually useable for bots.
+//! Significantly abstract [`azalea_protocol`] so it's actually useable for
+//! real clients. If you want to make bots, however, you should use the
+//! [`azalea`] crate instead.
+//!
+//! [`azalea_protocol`]: https://crates.io/crates/azalea-protocol
+//! [`azalea`]: https://crates.io/crates/azalea
mod account;
mod chat;
diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs
index 85cf6bdd..93acf36f 100644
--- a/azalea-client/src/movement.rs
+++ b/azalea-client/src/movement.rs
@@ -155,6 +155,8 @@ impl Client {
Ok(())
}
+ /// Makes the bot do one physics tick. Note that this is already handled
+ /// automatically by the client.
pub fn ai_step(&mut self) {
self.tick_controls(None);
diff --git a/azalea-client/src/ping.rs b/azalea-client/src/ping.rs
index c59fb3ac..6817677e 100755
--- a/azalea-client/src/ping.rs
+++ b/azalea-client/src/ping.rs
@@ -1,4 +1,5 @@
-///! Ping Minecraft servers.
+//! Ping Minecraft servers.
+
use azalea_protocol::{
connect::{Connection, ConnectionError},
packets::{
@@ -25,12 +26,27 @@ pub enum PingError {
ReadPacket(#[from] azalea_protocol::read::ReadPacketError),
#[error("{0}")]
WritePacket(#[from] io::Error),
+ #[error("The given address could not be parsed into a ServerAddress")]
+ InvalidAddress,
}
+/// Ping a Minecraft server.
+///
+/// ```
+/// use azalea_client::ping;
+///
+/// #[tokio::main]
+/// async fn main() {
+/// let response = ping::ping_server("play.hypixel.net").await.unwrap();
+/// println!("{}", response.description.to_ansi(None));
+/// }
+/// ```
pub async fn ping_server(
- address: &ServerAddress,
+ address: impl TryInto<ServerAddress>,
) -> Result<ClientboundStatusResponsePacket, PingError> {
- let resolved_address = resolver::resolve_address(address).await?;
+ let address: ServerAddress = address.try_into().map_err(|_| PingError::InvalidAddress)?;
+
+ let resolved_address = resolver::resolve_address(&address).await?;
let mut conn = Connection::new(&resolved_address).await?;
diff --git a/azalea-protocol/src/connect.rs b/azalea-protocol/src/connect.rs
index 03c56471..c996001d 100644
--- a/azalea-protocol/src/connect.rs
+++ b/azalea-protocol/src/connect.rs
@@ -165,7 +165,7 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
/// online-mode servers. This must happen when you get a
/// `ClientboundLoginPacket::Hello` packet.
///
- /// ```no_run
+ /// ```rust,no_run
/// let token = azalea_auth::auth(azalea_auth::AuthOpts {
/// ..Default::default()
/// })
diff --git a/azalea/README.md b/azalea/README.md
index 2ea99de0..d9aa1574 100644
--- a/azalea/README.md
+++ b/azalea/README.md
@@ -1,3 +1,3 @@
-A framework for creating Minecraft bots.
+Azalea is a framework for creating Minecraft bots.
-Interally, it's just a wrapper over azalea-client, adding useful functions for making bots.
+Internally, it's just a wrapper over azalea-client, adding useful functions for making bots.
diff --git a/azalea/examples/craft_dig_straight_down.rs b/azalea/examples/craft_dig_straight_down.rs
index 89b11021..48e1fd22 100644
--- a/azalea/examples/craft_dig_straight_down.rs
+++ b/azalea/examples/craft_dig_straight_down.rs
@@ -11,7 +11,7 @@ struct State {
#[tokio::main]
async fn main() {
let account = Account::offline("bot");
- // or let bot = Account::microsoft("access token").await;
+ // or let bot = Account::microsoft("email").await;
azalea::start(azalea::Options {
account,
diff --git a/azalea/examples/echo.rs b/azalea/examples/echo.rs
index a5e27d56..a5280d8b 100644
--- a/azalea/examples/echo.rs
+++ b/azalea/examples/echo.rs
@@ -1,12 +1,13 @@
-use std::sync::Arc;
+//! A simple bot that repeats chat messages sent by other players.
use azalea::{Account, Client, Event};
use parking_lot::Mutex;
+use std::sync::Arc;
#[tokio::main]
async fn main() {
let account = Account::offline("bot");
- // or let account = Account::microsoft("access token").await;
+ // or let account = Account::microsoft("email").await;
azalea::start(azalea::Options {
account,
@@ -22,7 +23,7 @@ async fn main() {
pub struct State {}
async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
- match event {
+ match *event {
Event::Chat(m) => {
if m.username == bot.username {
return Ok(()); // ignore our own messages
@@ -33,12 +34,6 @@ async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> any
println!(m);
bot.reconnect().await.unwrap();
}
- Event::HungerUpdate(h) => {
- if !h.using_held_item() && h.hunger <= 17 {
- bot.hold(azalea::ItemGroup::Food).await?;
- bot.use_held_item().await?;
- }
- }
_ => {}
}
diff --git a/azalea/examples/pvp.rs b/azalea/examples/pvp.rs
index 9405cb6f..a2f070f0 100644
--- a/azalea/examples/pvp.rs
+++ b/azalea/examples/pvp.rs
@@ -1,7 +1,6 @@
-use std::sync::Arc;
-
use azalea::{pathfinder, Account, Accounts, Client, Event};
use parking_lot::Mutex;
+use std::sync::Arc;
#[tokio::main]
async fn main() {
diff --git a/azalea/src/lib.rs b/azalea/src/lib.rs
index 493745cb..19384761 100644
--- a/azalea/src/lib.rs
+++ b/azalea/src/lib.rs
@@ -1,3 +1,51 @@
+//! Azalea is a framework for creating Minecraft bots.
+//!
+//! Internally, it's just a wrapper over [`azalea_client`], adding useful
+//! functions for making bots. Because of this, lots 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
+//! //! A bot that logs chat messages sent in the server to the console.
+//!
+//! use azalea::prelude::*;
+//! use parking_lot::Mutex;
+//! use std::sync::Arc;
+//!
+//! #[tokio::main]
+//! async fn main() {
+//! let account = Account::offline("bot");
+//! // or Account::microsoft("example@example.com").await.unwrap();
+//!
+//! azalea::start(azalea::Options {
+//! account,
+//! address: "localhost",
+//! state: Arc::new(Mutex::new(State::default())),
+//! plugins: vec![],
+//! handle,
+//! })
+//! .await
+//! .unwrap();
+//! }
+//!
+//! pub struct State {}
+//!
+//! async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
+//! match *event {
+//! Event::Chat(m) => {
+//! println!(m.message().to_ansi(None));
+//! }
+//! _ => {}
+//! }
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`azalea_client`]: https://crates.io/crates/azalea-client
+
mod bot;
pub mod prelude;
@@ -16,15 +64,27 @@ pub trait Plugin: Send + Sync {
pub type HandleFn<Fut, S> = fn(Client, Arc<Event>, Arc<Mutex<S>>) -> Fut;
+/// The options that are passed to [`azalea::start`].
+///
+/// [`azalea::start`]: fn.start.html
pub struct Options<S, A, Fut>
where
A: TryInto<ServerAddress>,
Fut: Future<Output = Result<(), anyhow::Error>>,
{
+ /// The address of the server that we're connecting to. This can be a
+ /// `&str`, [`ServerAddress`], or anything that implements
+ /// `TryInto<ServerAddress>`.
pub address: A,
+ /// The account that's going to join the server,
pub account: Account,
+ /// A list of plugins that are going to be used. Plugins are external
+ /// crates that add extra functionality to Azalea.
pub plugins: Vec<Arc<dyn Plugin>>,
+ /// A struct that contains the data that you want your bot to remember
+ /// across events.
pub state: Arc<Mutex<S>>,
+ /// The function that's called whenever we get an event.
pub handle: HandleFn<Fut, S>,
}
@@ -34,9 +94,10 @@ pub enum Error {
InvalidAddress,
}
-/// Join a Minecraft server.
+/// Join a server and start handling events. This function will run forever until
+/// it gets disconnected from the server.
///
-/// ```no_run
+/// ```rust,no_run
/// azalea::start(azalea::Options {
/// account,
/// address: "localhost",
@@ -57,7 +118,7 @@ pub async fn start<
Err(_) => return Err(Error::InvalidAddress),
};
- let (bot, mut rx) = options.account.join(&address).await.unwrap();
+ let (bot, mut rx) = Client::join(&options.account, address).await.unwrap();
let state = options.state;
let bot_plugin = Arc::new(bot::Plugin::default());
diff --git a/azalea/src/prelude.rs b/azalea/src/prelude.rs
index 7b3345b0..0ffb60b8 100644
--- a/azalea/src/prelude.rs
+++ b/azalea/src/prelude.rs
@@ -1 +1,4 @@
+//! The Azalea prelude.
+
pub use crate::bot::BotTrait;
+pub use azalea_client::{Account, Client, Event};