azalea_client/plugins/
client_information.rs

1use azalea_protocol::{
2    common::client_information::ClientInformation,
3    packets::{config::s_client_information::ServerboundClientInformation, game},
4};
5use bevy_app::prelude::*;
6use bevy_ecs::prelude::*;
7use tracing::{debug, warn};
8
9use super::packet::config::SendConfigPacketEvent;
10use crate::{Client, brand::send_brand, packet::login::InLoginState};
11
12/// Send [`ServerboundClientInformation`] on join.
13pub struct ClientInformationPlugin;
14impl Plugin for ClientInformationPlugin {
15    fn build(&self, app: &mut App) {
16        app.add_systems(Update, send_client_information.after(send_brand));
17    }
18}
19
20pub fn send_client_information(
21    mut commands: Commands,
22    mut removed: RemovedComponents<InLoginState>,
23    query: Query<&ClientInformation>,
24) {
25    for entity in removed.read() {
26        let client_information = match query.get(entity).ok() {
27            Some(i) => i,
28            None => {
29                warn!(
30                    "ClientInformation component was not set before leaving login state, using a default"
31                );
32                &ClientInformation::default()
33            }
34        };
35
36        debug!("Writing ClientInformation while in config state: {client_information:?}");
37        commands.trigger(SendConfigPacketEvent::new(
38            entity,
39            ServerboundClientInformation {
40                information: client_information.clone(),
41            },
42        ));
43    }
44}
45
46impl Client {
47    /// Tell the server we changed our game options (i.e. render distance, main
48    /// hand).
49    ///
50    /// If this is not set before the login packet, the default will be sent.
51    ///
52    /// ```rust,no_run
53    /// # use azalea_client::{Client, ClientInformation};
54    /// # async fn example(bot: Client) -> Result<(), Box<dyn std::error::Error>> {
55    /// bot.set_client_information(ClientInformation {
56    ///     view_distance: 2,
57    ///     ..Default::default()
58    /// });
59    /// # Ok(())
60    /// # }
61    /// ```
62    pub fn set_client_information(&self, client_information: ClientInformation) {
63        self.query_self::<&mut ClientInformation, _>(|mut ci| {
64            *ci = client_information.clone();
65        });
66
67        if self.logged_in() {
68            debug!(
69                "Sending client information (already logged in): {:?}",
70                client_information
71            );
72            self.write_packet(game::s_client_information::ServerboundClientInformation {
73                client_information,
74            });
75        }
76    }
77}