aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/plugins/packet/login/mod.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-04-17 16:16:51 -0500
committerGitHub <noreply@github.com>2025-04-17 16:16:51 -0500
commit3f60bdadac1a02e1109148bbbe5a8a3545f13849 (patch)
tree6c0460be61e715c1b789f81b16ce4c0fb986c3b4 /azalea-client/src/plugins/packet/login/mod.rs
parent1989f4ec979c138f8f466ccebadca335eb2917d6 (diff)
downloadazalea-drasl-3f60bdadac1a02e1109148bbbe5a8a3545f13849.tar.xz
Move login state to the ECS (#213)
* use packet handlers code for login custom_query * initial broken implementation for ecs-only login * fixes * run Update schedule 60 times per second and delete code related to run_schedule_sender * fix tests * fix online-mode * reply to query packets in a separate system and make it easier for plugins to disable individual replies * remove unused imports
Diffstat (limited to 'azalea-client/src/plugins/packet/login/mod.rs')
-rw-r--r--azalea-client/src/plugins/packet/login/mod.rs145
1 files changed, 145 insertions, 0 deletions
diff --git a/azalea-client/src/plugins/packet/login/mod.rs b/azalea-client/src/plugins/packet/login/mod.rs
new file mode 100644
index 00000000..d313a767
--- /dev/null
+++ b/azalea-client/src/plugins/packet/login/mod.rs
@@ -0,0 +1,145 @@
+// login packets aren't actually handled here because compression/encryption
+// would make packet handling a lot messier
+
+mod events;
+
+use azalea_protocol::packets::{
+ ConnectionProtocol,
+ login::{
+ ClientboundCookieRequest, ClientboundCustomQuery, ClientboundHello,
+ ClientboundLoginCompression, ClientboundLoginDisconnect, ClientboundLoginFinished,
+ ClientboundLoginPacket, ServerboundCookieResponse, ServerboundLoginAcknowledged,
+ },
+};
+use bevy_ecs::prelude::*;
+pub use events::*;
+use tracing::{debug, error};
+
+use super::as_system;
+use crate::{
+ Account, GameProfileComponent, InConfigState, connection::RawConnection,
+ declare_packet_handlers, disconnect::DisconnectEvent,
+};
+
+pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundLoginPacket) {
+ let mut handler = LoginPacketHandler { player, ecs };
+
+ declare_packet_handlers!(
+ ClientboundLoginPacket,
+ packet,
+ handler,
+ [
+ hello,
+ login_disconnect,
+ login_finished,
+ login_compression,
+ custom_query,
+ cookie_request
+ ]
+ );
+}
+
+/// A marker component for local players that are currently in the
+/// `login` state.
+#[derive(Component, Clone, Debug)]
+pub struct InLoginState;
+
+pub struct LoginPacketHandler<'a> {
+ pub ecs: &'a mut World,
+ pub player: Entity,
+}
+impl LoginPacketHandler<'_> {
+ pub fn hello(&mut self, p: &ClientboundHello) {
+ debug!("Got encryption request {p:?}");
+
+ as_system::<(Commands, Query<&Account>)>(self.ecs, |(mut commands, query)| {
+ let Ok(account) = query.get(self.player) else {
+ error!(
+ "Expected Account component to be present on player when receiving hello packet."
+ );
+ return;
+ };
+ commands.trigger_targets(
+ ReceiveHelloEvent {
+ account: account.clone(),
+ packet: p.clone(),
+ },
+ self.player,
+ );
+ });
+ }
+ pub fn login_disconnect(&mut self, p: &ClientboundLoginDisconnect) {
+ debug!("Got disconnect {:?}", p);
+
+ as_system::<EventWriter<_>>(self.ecs, |mut events| {
+ events.send(DisconnectEvent {
+ entity: self.player,
+ reason: Some(p.reason.clone()),
+ });
+ });
+ }
+ pub fn login_finished(&mut self, p: &ClientboundLoginFinished) {
+ debug!(
+ "Got profile {:?}. login is finished and we're now switching to the config state",
+ p.game_profile
+ );
+
+ as_system::<(Commands, Query<&mut RawConnection>)>(
+ self.ecs,
+ |(mut commands, mut query)| {
+ commands.trigger(SendLoginPacketEvent::new(
+ self.player,
+ ServerboundLoginAcknowledged,
+ ));
+
+ commands
+ .entity(self.player)
+ .remove::<InLoginState>()
+ .insert(InConfigState)
+ .insert(GameProfileComponent(p.game_profile.clone()));
+
+ let mut conn = query
+ .get_mut(self.player)
+ .expect("RawConnection component should be present when receiving packets");
+ conn.state = ConnectionProtocol::Configuration;
+ },
+ );
+ }
+ pub fn login_compression(&mut self, p: &ClientboundLoginCompression) {
+ debug!("Got compression request {p:?}");
+
+ as_system::<Query<&mut RawConnection>>(self.ecs, |mut query| {
+ let mut conn = query
+ .get_mut(self.player)
+ .expect("RawConnection component should be present when receiving packets");
+ if let Some(net_conn) = &mut conn.net_conn() {
+ net_conn.set_compression_threshold(Some(p.compression_threshold as u32));
+ }
+ })
+ }
+ pub fn custom_query(&mut self, p: &ClientboundCustomQuery) {
+ debug!("Got custom query {p:?}");
+
+ as_system::<EventWriter<ReceiveCustomQueryEvent>>(self.ecs, |mut events| {
+ events.send(ReceiveCustomQueryEvent {
+ entity: self.player,
+ packet: p.clone(),
+ disabled: false,
+ });
+ });
+ }
+ pub fn cookie_request(&mut self, p: &ClientboundCookieRequest) {
+ debug!("Got cookie request {p:?}");
+
+ as_system::<Commands>(self.ecs, |mut commands| {
+ commands.trigger(SendLoginPacketEvent::new(
+ self.player,
+ ServerboundCookieResponse {
+ key: p.key.clone(),
+ // cookies aren't implemented
+ payload: None,
+ },
+ ));
+ });
+ }
+}