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). If this is not set before the login packet, the default will
49    /// be sent.
50    ///
51    /// ```rust,no_run
52    /// # use azalea_client::{Client, ClientInformation};
53    /// # async fn example(bot: Client) -> Result<(), Box<dyn std::error::Error>> {
54    /// bot.set_client_information(ClientInformation {
55    ///     view_distance: 2,
56    ///     ..Default::default()
57    /// })
58    /// .await;
59    /// # Ok(())
60    /// # }
61    /// ```
62    pub async fn set_client_information(&self, client_information: ClientInformation) {
63        {
64            let mut ecs = self.ecs.lock();
65            let mut client_information_mut = self.query::<&mut ClientInformation>(&mut ecs);
66            *client_information_mut = client_information.clone();
67        }
68
69        if self.logged_in() {
70            debug!(
71                "Sending client information (already logged in): {:?}",
72                client_information
73            );
74            self.write_packet(game::s_client_information::ServerboundClientInformation {
75                client_information,
76            });
77        }
78    }
79}