azalea_client/plugins/packet/login/
mod.rs1mod events;
5
6use azalea_protocol::packets::{
7 ConnectionProtocol,
8 login::{
9 ClientboundCookieRequest, ClientboundCustomQuery, ClientboundHello,
10 ClientboundLoginCompression, ClientboundLoginDisconnect, ClientboundLoginFinished,
11 ClientboundLoginPacket, ServerboundCookieResponse, ServerboundLoginAcknowledged,
12 },
13};
14use bevy_ecs::prelude::*;
15pub use events::*;
16use tracing::{debug, error};
17
18use super::as_system;
19use crate::{
20 Account, InConfigState, connection::RawConnection, disconnect::DisconnectEvent,
21 packet::declare_packet_handlers, player::GameProfileComponent,
22};
23
24pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundLoginPacket) {
25 let mut handler = LoginPacketHandler { player, ecs };
26
27 declare_packet_handlers!(
28 ClientboundLoginPacket,
29 packet,
30 handler,
31 [
32 hello,
33 login_disconnect,
34 login_finished,
35 login_compression,
36 custom_query,
37 cookie_request
38 ]
39 );
40}
41
42#[derive(Component, Clone, Debug)]
45pub struct InLoginState;
46
47pub struct LoginPacketHandler<'a> {
48 pub ecs: &'a mut World,
49 pub player: Entity,
50}
51impl LoginPacketHandler<'_> {
52 pub fn hello(&mut self, p: &ClientboundHello) {
53 debug!("Got encryption request {p:?}");
54
55 as_system::<(Commands, Query<&Account>)>(self.ecs, |(mut commands, query)| {
56 let Ok(account) = query.get(self.player) else {
57 error!(
58 "Expected Account component to be present on player when receiving hello packet."
59 );
60 return;
61 };
62 commands.trigger(ReceiveHelloEvent {
63 entity: self.player,
64 account: account.clone(),
65 packet: p.clone(),
66 });
67 });
68 }
69 pub fn login_disconnect(&mut self, p: &ClientboundLoginDisconnect) {
70 debug!("Got disconnect {:?}", p);
71
72 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
73 events.write(DisconnectEvent {
74 entity: self.player,
75 reason: Some(p.reason.clone()),
76 });
77 });
78 }
79 pub fn login_finished(&mut self, p: &ClientboundLoginFinished) {
80 debug!(
81 "Got profile {:?}. login is finished and we're now switching to the config state",
82 p.game_profile
83 );
84
85 as_system::<(Commands, Query<&mut RawConnection>)>(
86 self.ecs,
87 |(mut commands, mut query)| {
88 commands.trigger(SendLoginPacketEvent::new(
89 self.player,
90 ServerboundLoginAcknowledged,
91 ));
92
93 commands
94 .entity(self.player)
95 .remove::<InLoginState>()
96 .insert(InConfigState)
97 .insert(GameProfileComponent(p.game_profile.clone()));
98
99 let mut conn = query
100 .get_mut(self.player)
101 .expect("RawConnection component should be present when receiving packets");
102 conn.state = ConnectionProtocol::Configuration;
103 },
104 );
105 }
106 pub fn login_compression(&mut self, p: &ClientboundLoginCompression) {
107 debug!("Got compression request {p:?}");
108
109 as_system::<Query<&mut RawConnection>>(self.ecs, |mut query| {
110 let mut conn = query
111 .get_mut(self.player)
112 .expect("RawConnection component should be present when receiving packets");
113 if let Some(net_conn) = &mut conn.net_conn() {
114 net_conn.set_compression_threshold(Some(p.compression_threshold as u32));
115 }
116 })
117 }
118 pub fn custom_query(&mut self, p: &ClientboundCustomQuery) {
119 debug!("Got custom query {p:?}");
120
121 as_system::<MessageWriter<ReceiveCustomQueryEvent>>(self.ecs, |mut events| {
122 events.write(ReceiveCustomQueryEvent {
123 entity: self.player,
124 packet: p.clone(),
125 disabled: false,
126 });
127 });
128 }
129 pub fn cookie_request(&mut self, p: &ClientboundCookieRequest) {
130 debug!("Got cookie request {p:?}");
131
132 as_system::<Commands>(self.ecs, |mut commands| {
133 commands.trigger(SendLoginPacketEvent::new(
134 self.player,
135 ServerboundCookieResponse {
136 key: p.key.clone(),
137 payload: None,
139 },
140 ));
141 });
142 }
143}