1#![doc = include_str!("../README.md")]
2#![feature(type_changing_struct_update)]
3#![feature(let_chains)]
4#![feature(never_type)]
5
6pub mod accept_resource_packs;
7pub mod auto_respawn;
8pub mod auto_tool;
9mod bot;
10pub mod container;
11pub mod nearest_entity;
12pub mod pathfinder;
13pub mod prelude;
14pub mod swarm;
15
16use std::net::SocketAddr;
17
18use app::Plugins;
19pub use azalea_auth as auth;
20pub use azalea_block as blocks;
21pub use azalea_brigadier as brigadier;
22pub use azalea_buf as buf;
23pub use azalea_chat::FormattedText;
24pub use azalea_client::*;
25pub use azalea_core as core;
26pub use azalea_core::{
28 position::{BlockPos, Vec3},
29 resource_location::ResourceLocation,
30};
31pub use azalea_entity as entity;
32pub use azalea_physics as physics;
33pub use azalea_protocol as protocol;
34pub use azalea_registry as registry;
35pub use azalea_world as world;
36pub use bevy_app as app;
37pub use bevy_ecs as ecs;
38pub use bot::*;
39use ecs::component::Component;
40use futures::{future::BoxFuture, Future};
41use protocol::connect::Proxy;
42use protocol::{resolver::ResolverError, ServerAddress};
43use swarm::SwarmBuilder;
44use thiserror::Error;
45
46pub type BoxHandleFn<S, R> = Box<dyn Fn(Client, azalea_client::Event, S) -> BoxFuture<'static, R>>;
47pub type HandleFn<S, Fut> = fn(Client, azalea_client::Event, S) -> Fut;
48
49#[derive(Error, Debug)]
50pub enum StartError {
51 #[error("Invalid address")]
52 InvalidAddress,
53 #[error(transparent)]
54 ResolveAddress(#[from] ResolverError),
55}
56
57pub struct ClientBuilder<S, R>
76where
77 S: Default + Send + Sync + Clone + Component + 'static,
78 R: Send + 'static,
79{
80 swarm: SwarmBuilder<S, swarm::NoSwarmState, R, ()>,
84}
85impl ClientBuilder<NoState, ()> {
86 #[must_use]
88 pub fn new() -> Self {
89 Self::new_without_plugins()
90 .add_plugins(DefaultPlugins)
91 .add_plugins(DefaultBotPlugins)
92 }
93
94 #[must_use]
118 pub fn new_without_plugins() -> Self {
119 Self {
120 swarm: SwarmBuilder::new_without_plugins(),
121 }
122 }
123
124 #[must_use]
141 pub fn set_handler<S, Fut, R>(self, handler: HandleFn<S, Fut>) -> ClientBuilder<S, R>
142 where
143 S: Default + Send + Sync + Clone + Component + 'static,
144 Fut: Future<Output = R> + Send + 'static,
145 R: Send + 'static,
146 {
147 ClientBuilder {
148 swarm: self.swarm.set_handler(handler),
149 }
150 }
151}
152impl<S, R> ClientBuilder<S, R>
153where
154 S: Default + Send + Sync + Clone + Component + 'static,
155 R: Send + 'static,
156{
157 #[must_use]
159 pub fn set_state(mut self, state: S) -> Self {
160 self.swarm.states = vec![state];
161 self
162 }
163 #[must_use]
165 pub fn add_plugins<M>(mut self, plugins: impl Plugins<M>) -> Self {
166 self.swarm = self.swarm.add_plugins(plugins);
167 self
168 }
169
170 pub async fn start(
184 mut self,
185 account: Account,
186 address: impl TryInto<ServerAddress>,
187 ) -> Result<!, StartError> {
188 self.swarm.accounts = vec![(account, JoinOpts::default())];
189 if self.swarm.states.is_empty() {
190 self.swarm.states = vec![S::default()];
191 }
192 self.swarm.start(address).await
193 }
194
195 pub async fn start_with_opts(
198 mut self,
199 account: Account,
200 address: impl TryInto<ServerAddress>,
201 opts: JoinOpts,
202 ) -> Result<!, StartError> {
203 self.swarm.accounts = vec![(account, opts.clone())];
204 if self.swarm.states.is_empty() {
205 self.swarm.states = vec![S::default()];
206 }
207 self.swarm.start_with_default_opts(address, opts).await
208 }
209}
210impl Default for ClientBuilder<NoState, ()> {
211 fn default() -> Self {
212 Self::new()
213 }
214}
215
216#[derive(Component, Clone, Default)]
222pub struct NoState;
223
224#[derive(Clone, Debug, Default)]
226#[non_exhaustive]
227pub struct JoinOpts {
228 pub proxy: Option<Proxy>,
230 pub custom_address: Option<ServerAddress>,
233 pub custom_resolved_address: Option<SocketAddr>,
236}
237
238impl JoinOpts {
239 pub fn new() -> Self {
240 Self::default()
241 }
242
243 pub fn update(&mut self, other: &Self) {
244 if let Some(proxy) = other.proxy.clone() {
245 self.proxy = Some(proxy);
246 }
247 if let Some(custom_address) = other.custom_address.clone() {
248 self.custom_address = Some(custom_address);
249 }
250 if let Some(custom_resolved_address) = other.custom_resolved_address {
251 self.custom_resolved_address = Some(custom_resolved_address);
252 }
253 }
254
255 #[must_use]
257 pub fn proxy(mut self, proxy: Proxy) -> Self {
258 self.proxy = Some(proxy);
259 self
260 }
261 #[must_use]
263 pub fn custom_address(mut self, custom_address: ServerAddress) -> Self {
264 self.custom_address = Some(custom_address);
265 self
266 }
267 #[must_use]
270 pub fn custom_resolved_address(mut self, custom_resolved_address: SocketAddr) -> Self {
271 self.custom_resolved_address = Some(custom_resolved_address);
272 self
273 }
274}