azalea_client/account/mod.rs
1//! Connect to Minecraft servers.
2
3#[cfg(feature = "online-mode")]
4pub mod microsoft;
5pub mod offline;
6
7use std::{fmt::Debug, ops::Deref, pin::Pin, sync::Arc};
8
9#[cfg(feature = "online-mode")]
10use azalea_auth::sessionserver::ClientSessionServerError;
11use bevy_ecs::component::Component;
12use uuid::Uuid;
13
14/// Something that can join Minecraft servers.
15///
16/// By default, Azalea only supports either authentication with Microsoft
17/// (online-mode), or no authentication at all (offline-mode). If you'd like to
18/// do authentication in some other way, consider looking at [`AccountTrait`].
19///
20/// To join a server using this account, you can either use
21/// [`StartJoinServerEvent`] or `azalea::ClientBuilder`.
22///
23/// Note that `Account` is also an ECS component that's present on our client
24/// entities.
25///
26/// # Examples
27///
28/// ```rust,no_run
29/// # use azalea_client::Account;
30/// #
31/// # #[tokio::main]
32/// # async fn main() {
33/// let account = Account::microsoft("[email protected]").await;
34/// // or Account::offline("example");
35/// # }
36/// ```
37///
38/// [`StartJoinServerEvent`]: crate::join::StartJoinServerEvent
39/// [`azalea::ClientBuilder`]: https://docs.rs/azalea/latest/azalea/struct.ClientBuilder.html
40#[derive(Clone, Component, Debug)]
41pub struct Account(Arc<dyn AccountTrait>);
42
43impl Account {
44 #[deprecated = "moved to `uuid()`."]
45 pub fn uuid_or_offline(&self) -> Uuid {
46 self.uuid()
47 }
48}
49
50pub(crate) type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
51
52/// A trait that all types of accounts implement.
53///
54/// This can be used, for example, to join servers with a custom authentication
55/// server.
56///
57/// Anything that implements [`AccountTrait`] can be converted to an [`Account`]
58/// with `.into()`.
59///
60/// Consider reading the source code of
61/// [`MicrosoftAccount`](microsoft::MicrosoftAccount) for an example of how to
62/// implement this.
63pub trait AccountTrait: Send + Sync + Debug {
64 /// Returns the Minecraft username of the account.
65 fn username(&self) -> &str;
66 /// Returns the unique identifier for this player.
67 ///
68 /// For offline-mode accounts, this UUID is generated by calling
69 /// [`azalea_crypto::offline::generate_uuid`].
70 fn uuid(&self) -> Uuid;
71
72 /// The access token for authentication.
73 ///
74 /// You can obtain one of these manually from `azalea-auth`.
75 fn access_token(&self) -> Option<String>;
76
77 /// Refreshes the access token for this account.
78 #[cfg(feature = "online-mode")]
79 fn refresh(&self) -> BoxFuture<'_, Result<(), azalea_auth::AuthError>> {
80 Box::pin(async { Ok(()) })
81 }
82 /// Refreshes the access token for this account.
83 ///
84 /// The `online-mode` feature is disabled, so this won't do anything.
85 #[cfg(not(feature = "online-mode"))]
86 fn refresh(&self) -> BoxFuture<'_, Result<(), ()>> {
87 Box::pin(async { Ok(()) })
88 }
89
90 #[cfg(feature = "online-mode")]
91 fn certs(&self) -> Option<azalea_auth::certs::Certificates> {
92 None
93 }
94 /// Override the chat signing certificates for this account.
95 ///
96 /// You can get the certificates needed for this from
97 /// [`azalea_auth::certs::fetch_certificates`]. You typically don't need to
98 /// call this yourself, as Azalea will do it for you.
99 ///
100 /// For accounts that don't support signing (i.e. offline-mode), this won't
101 /// do anything.
102 #[cfg(feature = "online-mode")]
103 fn set_certs(&self, certs: azalea_auth::certs::Certificates) {
104 let _ = certs;
105 }
106
107 /// Typically used to tell Mojang's sessionserver that we are going to join
108 /// a server.
109 ///
110 /// This must be implemented for accounts that can join online-mode servers.
111 ///
112 /// This function is called internally by Azalea when the account tries to
113 /// join a server, but only if [`AccountTrait::access_token`] is `Some`.
114 #[cfg(feature = "online-mode")]
115 fn join<'a>(
116 &'a self,
117 public_key: &'a [u8],
118 private_key: &'a [u8; 16],
119 server_id: &'a str,
120 proxy: Option<reqwest::Proxy>,
121 ) -> BoxFuture<'a, Result<(), ClientSessionServerError>> {
122 let _ = (public_key, private_key, server_id, proxy);
123 Box::pin(async { Ok(()) })
124 }
125 /// Typically used to tell Mojang's sessionserver that we are going to join
126 /// a server.
127 ///
128 /// The `online-mode` feature is disabled, so this won't do anything.
129 #[cfg(not(feature = "online-mode"))]
130 fn join(
131 &self,
132 public_key: &[u8],
133 private_key: &[u8; 16],
134 server_id: &str,
135 proxy: Option<()>,
136 ) -> BoxFuture<'_, Result<(), ()>> {
137 let _ = (public_key, private_key, server_id, proxy);
138 Box::pin(async { Ok(()) })
139 }
140}
141impl<T: AccountTrait + 'static> From<T> for Account {
142 fn from(value: T) -> Self {
143 Account(Arc::new(value))
144 }
145}
146impl Deref for Account {
147 type Target = dyn AccountTrait;
148
149 fn deref(&self) -> &Self::Target {
150 &*self.0
151 }
152}