aboutsummaryrefslogtreecommitdiff
path: root/azalea
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-12-12 01:29:49 -0600
committerGitHub <noreply@github.com>2025-12-12 01:29:49 -0600
commitf4a3c53eee7d29bade0c074f402c4a45aa98eca8 (patch)
treef25ec1d1390c5e96aba858141206a05812135b95 /azalea
parent7f761df3e7b72ce75be21ab9b3a533d0a5a938a5 (diff)
downloadazalea-drasl-f4a3c53eee7d29bade0c074f402c4a45aa98eca8.tar.xz
Delete `StartError` and `JoinError` (#296)
* delete StartError and JoinError * update changelog
Diffstat (limited to 'azalea')
-rw-r--r--azalea/README.md3
-rw-r--r--azalea/examples/echo.rs3
-rw-r--r--azalea/examples/nearest_entity.rs4
-rw-r--r--azalea/examples/steal.rs3
-rw-r--r--azalea/examples/testbot/main.rs3
-rw-r--r--azalea/examples/todo/craft_dig_straight_down.rs3
-rw-r--r--azalea/examples/todo/mine_a_chunk.rs3
-rw-r--r--azalea/examples/todo/pvp.rs3
-rw-r--r--azalea/src/lib.rs67
-rw-r--r--azalea/src/prelude.rs1
-rw-r--r--azalea/src/swarm/mod.rs117
11 files changed, 107 insertions, 103 deletions
diff --git a/azalea/README.md b/azalea/README.md
index 3055b0c0..6b5c2601 100644
--- a/azalea/README.md
+++ b/azalea/README.md
@@ -43,7 +43,7 @@ use azalea::prelude::*;
use parking_lot::Mutex;
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let account = Account::offline("bot");
// or Account::microsoft("example@example.com").await.unwrap();
@@ -51,7 +51,6 @@ async fn main() {
.set_handler(handle)
.start(account, "localhost")
.await
- .unwrap();
}
#[derive(Default, Clone, Component)]
diff --git a/azalea/examples/echo.rs b/azalea/examples/echo.rs
index a2219008..ed013a66 100644
--- a/azalea/examples/echo.rs
+++ b/azalea/examples/echo.rs
@@ -3,7 +3,7 @@
use azalea::prelude::*;
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let account = Account::offline("bot");
// or let account = Account::microsoft("email").await.unwrap();
@@ -11,7 +11,6 @@ async fn main() {
.set_handler(handle)
.start(account, "localhost")
.await
- .unwrap();
}
#[derive(Default, Clone, Component)]
diff --git a/azalea/examples/nearest_entity.rs b/azalea/examples/nearest_entity.rs
index 19223589..a0385917 100644
--- a/azalea/examples/nearest_entity.rs
+++ b/azalea/examples/nearest_entity.rs
@@ -2,6 +2,7 @@ use azalea::{
ClientBuilder,
bot::{Bot, LookAtEvent},
nearest_entity::EntityFinder,
+ prelude::*,
};
use azalea_client::Account;
use azalea_core::tick::GameTick;
@@ -18,14 +19,13 @@ use bevy_ecs::{
};
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let account = Account::offline("bot");
ClientBuilder::new()
.add_plugins(LookAtStuffPlugin)
.start(account, "localhost")
.await
- .unwrap();
}
pub struct LookAtStuffPlugin;
diff --git a/azalea/examples/steal.rs b/azalea/examples/steal.rs
index c928545f..99254d51 100644
--- a/azalea/examples/steal.rs
+++ b/azalea/examples/steal.rs
@@ -8,7 +8,7 @@ use azalea_registry::builtin::{BlockKind, ItemKind};
use parking_lot::Mutex;
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let account = Account::offline("bot");
// or let bot = Account::microsoft("email").await.unwrap();
@@ -16,7 +16,6 @@ async fn main() {
.set_handler(handle)
.start(account, "localhost")
.await
- .unwrap();
}
#[derive(Default, Clone, Component)]
diff --git a/azalea/examples/testbot/main.rs b/azalea/examples/testbot/main.rs
index 6adb782c..2c282f07 100644
--- a/azalea/examples/testbot/main.rs
+++ b/azalea/examples/testbot/main.rs
@@ -33,7 +33,7 @@ use commands::{CommandSource, register_commands};
use parking_lot::Mutex;
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let args = parse_args();
thread::spawn(deadlock_detection_thread);
@@ -65,7 +65,6 @@ async fn main() {
})
.start(join_address)
.await
- .unwrap();
}
/// Runs a loop that checks for deadlocks every 10 seconds.
diff --git a/azalea/examples/todo/craft_dig_straight_down.rs b/azalea/examples/todo/craft_dig_straight_down.rs
index 0d9961d4..a76c1ffe 100644
--- a/azalea/examples/todo/craft_dig_straight_down.rs
+++ b/azalea/examples/todo/craft_dig_straight_down.rs
@@ -9,7 +9,7 @@ struct State {
}
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let account = Account::offline("bot");
// or let bot = Account::microsoft("email").await;
@@ -17,7 +17,6 @@ async fn main() {
.set_handler(handle)
.start(account, "localhost")
.await
- .unwrap();
}
async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
diff --git a/azalea/examples/todo/mine_a_chunk.rs b/azalea/examples/todo/mine_a_chunk.rs
index 0c439f26..6f6606f4 100644
--- a/azalea/examples/todo/mine_a_chunk.rs
+++ b/azalea/examples/todo/mine_a_chunk.rs
@@ -1,7 +1,7 @@
use azalea::{prelude::*, swarm::prelude::*};
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let mut accounts = Vec::new();
let mut states = Vec::new();
@@ -16,7 +16,6 @@ async fn main() {
.set_swarm_handler(swarm_handle)
.start("localhost")
.await
- .unwrap();
}
#[derive(Default, Clone, Component)]
diff --git a/azalea/examples/todo/pvp.rs b/azalea/examples/todo/pvp.rs
index d85278e8..9121444c 100644
--- a/azalea/examples/todo/pvp.rs
+++ b/azalea/examples/todo/pvp.rs
@@ -6,7 +6,7 @@ use azalea::{
};
#[tokio::main]
-async fn main() {
+async fn main() -> AppExit {
let mut accounts = Vec::new();
let mut states = Vec::new();
@@ -22,7 +22,6 @@ async fn main() {
.join_delay(Duration::from_millis(1000))
.start("localhost")
.await
- .unwrap();
}
#[derive(Component, Default, Clone)]
diff --git a/azalea/src/lib.rs b/azalea/src/lib.rs
index 8440e31f..45c0114d 100644
--- a/azalea/src/lib.rs
+++ b/azalea/src/lib.rs
@@ -37,6 +37,7 @@ pub use azalea_core::position::{BlockPos, Vec3};
pub use azalea_entity as entity;
pub use azalea_physics as physics;
pub use azalea_protocol as protocol;
+use azalea_protocol::address::{ResolvableAddr, ServerAddr};
pub use azalea_registry as registry;
#[doc(hidden)]
#[deprecated(note = "renamed to `Identifier`.")]
@@ -48,9 +49,8 @@ use bevy_app::AppExit;
pub use bevy_ecs as ecs;
use ecs::component::Component;
use futures::{Future, future::BoxFuture};
-use protocol::{ServerAddress, connect::Proxy, resolve::ResolveError};
+use protocol::connect::Proxy;
use swarm::SwarmBuilder;
-use thiserror::Error;
use crate::bot::DefaultBotPlugins;
@@ -58,15 +58,6 @@ pub type BoxHandleFn<S, R> =
Box<dyn Fn(Client, azalea_client::Event, S) -> BoxFuture<'static, R> + Send>;
pub type HandleFn<S, Fut> = fn(Client, azalea_client::Event, S) -> Fut;
-/// An error related to resolving the server address when starting a client.
-#[derive(Error, Debug)]
-pub enum StartError {
- #[error("Invalid address")]
- InvalidAddress,
- #[error(transparent)]
- ResolveAddress(#[from] ResolveError),
-}
-
/// A builder for creating new [`Client`]s. This is the recommended way of
/// making a bot.
///
@@ -217,20 +208,17 @@ where
///
/// If the client can't join, it'll keep retrying forever until it can.
///
- /// The `address` argument can be a `&str`, [`ServerAddress`], or anything
- /// that implements `TryInto<ServerAddress>`.
+ /// The `address` argument can be a `&str`, [`ServerAddr`],
+ /// [`ResolvedAddr`], or anything else that implements [`ResolvableAddr`].
///
/// # Errors
///
/// This will error if the given address is invalid or couldn't be resolved
/// to a Minecraft server.
///
- /// [`ServerAddress`]: azalea_protocol::ServerAddress
- pub async fn start(
- mut self,
- account: Account,
- address: impl TryInto<ServerAddress>,
- ) -> Result<AppExit, StartError> {
+ /// [`ServerAddr`]: azalea_protocol::address::ServerAddr
+ /// [`ResolvedAddr`]: azalea_protocol::address::ResolvedAddr
+ pub async fn start(mut self, account: Account, address: impl ResolvableAddr) -> AppExit {
self.swarm.accounts = vec![(account, JoinOpts::default())];
if self.swarm.states.is_empty() {
self.swarm.states = vec![S::default()];
@@ -243,14 +231,14 @@ where
pub async fn start_with_opts(
mut self,
account: Account,
- address: impl TryInto<ServerAddress>,
+ address: impl ResolvableAddr,
opts: JoinOpts,
- ) -> Result<AppExit, StartError> {
+ ) -> AppExit {
self.swarm.accounts = vec![(account, opts.clone())];
if self.swarm.states.is_empty() {
self.swarm.states = vec![S::default()];
}
- self.swarm.start_with_default_opts(address, opts).await
+ self.swarm.start_with_opts(address, opts).await
}
}
impl Default for ClientBuilder<NoState, ()> {
@@ -287,10 +275,12 @@ pub struct JoinOpts {
pub sessionserver_proxy: Option<Proxy>,
/// Override the server address that this specific bot will send in the
/// handshake packet.
- pub custom_address: Option<ServerAddress>,
- /// Override the socket address that this specific bot will use to connect
+ #[doc(alias = "custom_address")]
+ pub custom_server_addr: Option<ServerAddr>,
+ /// Override the IP and port that this specific bot will use to connect
/// to the server.
- pub custom_resolved_address: Option<SocketAddr>,
+ #[doc(alias = "custom_resolved_address")]
+ pub custom_socket_addr: Option<SocketAddr>,
}
impl JoinOpts {
@@ -305,11 +295,11 @@ impl JoinOpts {
if let Some(proxy) = other.sessionserver_proxy.clone() {
self.sessionserver_proxy = Some(proxy);
}
- if let Some(custom_address) = other.custom_address.clone() {
- self.custom_address = Some(custom_address);
+ if let Some(custom_server_addr) = other.custom_server_addr.clone() {
+ self.custom_server_addr = Some(custom_server_addr);
}
- if let Some(custom_resolved_address) = other.custom_resolved_address {
- self.custom_resolved_address = Some(custom_resolved_address);
+ if let Some(custom_socket_addr) = other.custom_socket_addr {
+ self.custom_socket_addr = Some(custom_socket_addr);
}
}
@@ -347,15 +337,26 @@ impl JoinOpts {
/// Set the custom address that this bot will send in the handshake packet.
#[must_use]
- pub fn custom_address(mut self, custom_address: ServerAddress) -> Self {
- self.custom_address = Some(custom_address);
+ pub fn custom_server_addr(mut self, server_addr: ServerAddr) -> Self {
+ self.custom_server_addr = Some(server_addr);
self
}
/// Set the custom resolved address that this bot will use to connect to the
/// server.
#[must_use]
- pub fn custom_resolved_address(mut self, custom_resolved_address: SocketAddr) -> Self {
- self.custom_resolved_address = Some(custom_resolved_address);
+ pub fn custom_socket_addr(mut self, socket_addr: SocketAddr) -> Self {
+ self.custom_socket_addr = Some(socket_addr);
self
}
+
+ #[doc(hidden)]
+ #[deprecated = "renamed to `custom_server_addr`."]
+ pub fn custom_address(self, server_addr: ServerAddr) -> Self {
+ self.custom_server_addr(server_addr)
+ }
+ #[doc(hidden)]
+ #[deprecated = "renamed to `custom_socket_addr`."]
+ pub fn custom_resolved_address(self, socket_addr: SocketAddr) -> Self {
+ self.custom_socket_addr(socket_addr)
+ }
}
diff --git a/azalea/src/prelude.rs b/azalea/src/prelude.rs
index 969b1e86..335244cc 100644
--- a/azalea/src/prelude.rs
+++ b/azalea/src/prelude.rs
@@ -3,6 +3,7 @@
pub use azalea_client::{Account, Client, Event};
pub use azalea_core::tick::GameTick;
+pub use bevy_app::AppExit;
// this is necessary to make the macros that reference bevy_ecs work
pub use crate::ecs as bevy_ecs;
diff --git a/azalea/src/swarm/mod.rs b/azalea/src/swarm/mod.rs
index feb3ff38..24e9c1b2 100644
--- a/azalea/src/swarm/mod.rs
+++ b/azalea/src/swarm/mod.rs
@@ -10,7 +10,6 @@ use std::{
collections::{HashMap, hash_map},
future::Future,
mem,
- net::SocketAddr,
sync::{
Arc,
atomic::{self, AtomicBool},
@@ -19,14 +18,14 @@ use std::{
};
use azalea_client::{
- Account, Client, DefaultPlugins, Event, JoinError, StartClientOpts,
+ Account, Client, DefaultPlugins, Event, StartClientOpts,
auto_reconnect::{AutoReconnectDelay, DEFAULT_RECONNECT_DELAY},
chat::ChatPacket,
join::ConnectOpts,
start_ecs_runner,
};
use azalea_entity::LocalEntity;
-use azalea_protocol::{ServerAddress, resolve};
+use azalea_protocol::address::{ResolvableAddr, ResolvedAddr};
use azalea_world::InstanceContainer;
use bevy_app::{App, AppExit, PluginGroup, PluginGroupBuilder, Plugins, SubApp};
use bevy_ecs::prelude::*;
@@ -35,7 +34,7 @@ use parking_lot::{Mutex, RwLock};
use tokio::{sync::mpsc, task};
use tracing::{debug, error, warn};
-use crate::{BoxHandleFn, DefaultBotPlugins, HandleFn, JoinOpts, NoState, StartError};
+use crate::{BoxHandleFn, DefaultBotPlugins, HandleFn, JoinOpts, NoState};
/// A swarm is a way to conveniently control many bots at once, while also
/// being able to control bots at an individual level when desired.
@@ -51,8 +50,7 @@ pub struct Swarm {
pub ecs_lock: Arc<Mutex<World>>,
// the address is public and mutable so plugins can change it
- pub resolved_address: Arc<RwLock<SocketAddr>>,
- pub address: Arc<RwLock<ServerAddress>>,
+ pub address: Arc<RwLock<ResolvedAddr>>,
pub instance_container: Arc<RwLock<InstanceContainer>>,
@@ -405,28 +403,31 @@ where
/// Build this `SwarmBuilder` into an actual [`Swarm`] and join the given
/// server.
///
- /// The `address` argument can be a `&str`, [`ServerAddress`], or anything
- /// that implements `TryInto<ServerAddress>`.
+ /// The `address` argument can be a `&str`, [`ServerAddr`],
+ /// [`ResolvedAddr`], or anything else that implements [`ResolvableAddr`].
///
- /// [`ServerAddress`]: azalea_protocol::ServerAddress
- pub async fn start(self, address: impl TryInto<ServerAddress>) -> Result<AppExit, StartError> {
- // convert the TryInto<ServerAddress> into a ServerAddress
- let address: ServerAddress = match address.try_into() {
- Ok(address) => address,
- Err(_) => return Err(StartError::InvalidAddress),
- };
+ /// [`ServerAddr`]: azalea_protocol::address::ServerAddr
+ pub async fn start(self, address: impl ResolvableAddr) -> AppExit {
+ self.start_with_opts(address, JoinOpts::default()).await
+ }
- self.start_with_default_opts(address, JoinOpts::default())
- .await
+ #[doc(hidden)]
+ #[deprecated = "renamed to `start_with_opts`."]
+ pub async fn start_with_default_opts(
+ self,
+ address: impl ResolvableAddr,
+ default_join_opts: JoinOpts,
+ ) -> AppExit {
+ self.start_with_opts(address, default_join_opts).await
}
/// Do the same as [`Self::start`], but allow passing in default join
/// options for the bots.
- pub async fn start_with_default_opts(
+ pub async fn start_with_opts(
mut self,
- address: impl TryInto<ServerAddress>,
- default_join_opts: JoinOpts,
- ) -> Result<AppExit, StartError> {
+ address: impl ResolvableAddr,
+ join_opts: JoinOpts,
+ ) -> AppExit {
assert_eq!(
self.accounts.len(),
self.states.len(),
@@ -435,17 +436,32 @@ where
debug!("Starting Azalea {}", env!("CARGO_PKG_VERSION"));
- // convert the TryInto<ServerAddress> into a ServerAddress
- let address = match address.try_into() {
- Ok(address) => address,
- Err(_) => return Err(StartError::InvalidAddress),
- };
+ let address = if let Some(socket_addr) = join_opts.custom_socket_addr.clone() {
+ let server_addr = if let Some(server_addr) = join_opts
+ .custom_server_addr
+ .clone()
+ .or_else(|| address.clone().server_addr().ok())
+ {
+ server_addr
+ } else {
+ error!(
+ "Failed to parse address: {address:?}. If this was expected, consider passing in a `ServerAddr` instead."
+ );
+ return AppExit::error();
+ };
- let address: ServerAddress = default_join_opts.custom_address.clone().unwrap_or(address);
- let resolved_address = if let Some(a) = default_join_opts.custom_resolved_address {
- a
+ ResolvedAddr {
+ server: server_addr,
+ socket: socket_addr,
+ }
} else {
- resolve::resolve_address(&address).await?
+ let Ok(addr) = address.clone().resolve().await else {
+ error!(
+ "Failed to resolve address: {address:?}. If this was expected, consider resolving the address earlier with `ResolvableAddr::resolve`."
+ );
+ return AppExit::error();
+ };
+ addr
};
let instance_container = Arc::new(RwLock::new(InstanceContainer::default()));
@@ -460,14 +476,13 @@ where
let local_set = task::LocalSet::new();
- let appexit = local_set.run_until(async move {
+ let app_exit = local_set.run_until(async move {
// start_ecs_runner must be run inside of the LocalSet
let (ecs_lock, start_running_systems, appexit_rx) = start_ecs_runner(&mut self.app);
let swarm = Swarm {
ecs_lock: ecs_lock.clone(),
- resolved_address: Arc::new(RwLock::new(resolved_address)),
address: Arc::new(RwLock::new(address)),
instance_container,
@@ -507,7 +522,7 @@ where
if let Some(join_delay) = join_delay {
// if there's a join delay, then join one by one
for ((account, bot_join_opts), state) in accounts.iter().zip(states) {
- let mut join_opts = default_join_opts.clone();
+ let mut join_opts = join_opts.clone();
join_opts.update(bot_join_opts);
let _ = swarm_clone.add_with_opts(account, state, &join_opts).await;
tokio::time::sleep(join_delay).await;
@@ -517,7 +532,7 @@ where
let swarm_borrow = &swarm_clone;
join_all(accounts.iter().zip(states).map(
|((account, bot_join_opts), state)| async {
- let mut join_opts = default_join_opts.clone();
+ let mut join_opts = join_opts.clone();
join_opts.update(bot_join_opts);
let _ = swarm_borrow
.clone()
@@ -603,17 +618,17 @@ where
}
});
- let appexit = appexit_rx
+ let app_exit = appexit_rx
.await
.expect("appexit_tx shouldn't be dropped by the ECS runner before sending");
swarm_handler_task.abort();
client_handler_task.abort();
- appexit
+ app_exit
}).await;
- Ok(appexit)
+ app_exit
}
}
@@ -667,7 +682,7 @@ pub type BoxSwarmHandleFn<SS, R> =
/// struct SwarmState {}
///
/// #[tokio::main]
-/// async fn main() {
+/// async fn main() -> AppExit {
/// let mut accounts = Vec::new();
/// let mut states = Vec::new();
///
@@ -683,7 +698,6 @@ pub type BoxSwarmHandleFn<SS, R> =
/// .join_delay(Duration::from_millis(1000))
/// .start("localhost")
/// .await
-/// .unwrap();
/// }
///
/// async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()> {
@@ -714,11 +728,7 @@ impl Swarm {
/// # Errors
///
/// Returns an error if the server's address could not be resolved.
- pub async fn add<S: Component + Clone>(
- &self,
- account: &Account,
- state: S,
- ) -> Result<Client, JoinError> {
+ pub async fn add<S: Component + Clone>(&self, account: &Account, state: S) -> Client {
self.add_with_opts(account, state, &JoinOpts::default())
.await
}
@@ -735,19 +745,19 @@ impl Swarm {
account: &Account,
state: S,
join_opts: &JoinOpts,
- ) -> Result<Client, JoinError> {
+ ) -> Client {
debug!(
"add_with_opts called for account {} with opts {join_opts:?}",
account.username
);
- let address = join_opts
- .custom_address
- .clone()
- .unwrap_or_else(|| self.address.read().clone());
- let resolved_address = join_opts
- .custom_resolved_address
- .unwrap_or_else(|| *self.resolved_address.read());
+ let mut address = self.address.read().clone();
+ if let Some(custom_server_addr) = join_opts.custom_server_addr.clone() {
+ address.server = custom_server_addr;
+ }
+ if let Some(custom_socket_addr) = join_opts.custom_socket_addr.clone() {
+ address.socket = custom_socket_addr;
+ }
let server_proxy = join_opts.server_proxy.clone();
let sessionserver_proxy = join_opts.sessionserver_proxy.clone();
@@ -758,7 +768,6 @@ impl Swarm {
account: account.clone(),
connect_opts: ConnectOpts {
address,
- resolved_address,
server_proxy,
sessionserver_proxy,
},
@@ -780,7 +789,7 @@ impl Swarm {
rx, swarm_tx, bots_tx, cloned_bot, join_opts,
));
- Ok(client)
+ client
}
/// Copy the events from a client's receiver into bots_tx, until the bot is