azalea_client/plugins/packet/
login.rs

1// login packets aren't actually handled here because compression/encryption
2// would make packet handling a lot messier
3
4use std::{collections::HashSet, sync::Arc};
5
6use azalea_protocol::packets::{
7    Packet,
8    login::{
9        ClientboundLoginPacket, ServerboundLoginPacket,
10        s_custom_query_answer::ServerboundCustomQueryAnswer,
11    },
12};
13use bevy_ecs::{prelude::*, system::SystemState};
14use derive_more::{Deref, DerefMut};
15use tokio::sync::mpsc;
16use tracing::error;
17
18// this struct is defined here anyways though so it's consistent with the other
19// ones
20
21/// An event that's sent when we receive a login packet from the server. Note
22/// that if you want to handle this in a system, you must add
23/// `.before(azalea::packet::login::process_packet_events)` to it
24/// because that system clears the events.
25#[derive(Event, Debug, Clone)]
26pub struct LoginPacketEvent {
27    /// The client entity that received the packet.
28    pub entity: Entity,
29    /// The packet that was actually received.
30    pub packet: Arc<ClientboundLoginPacket>,
31}
32
33/// Event for sending a login packet to the server.
34#[derive(Event)]
35pub struct SendLoginPacketEvent {
36    pub entity: Entity,
37    pub packet: ServerboundLoginPacket,
38}
39impl SendLoginPacketEvent {
40    pub fn new(entity: Entity, packet: impl Packet<ServerboundLoginPacket>) -> Self {
41        let packet = packet.into_variant();
42        Self { entity, packet }
43    }
44}
45
46#[derive(Component)]
47pub struct LoginSendPacketQueue {
48    pub tx: mpsc::UnboundedSender<ServerboundLoginPacket>,
49}
50
51/// A marker component for local players that are currently in the
52/// `login` state.
53#[derive(Component, Clone, Debug)]
54pub struct InLoginState;
55
56pub fn handle_send_packet_event(
57    mut send_packet_events: EventReader<SendLoginPacketEvent>,
58    mut query: Query<&mut LoginSendPacketQueue>,
59) {
60    for event in send_packet_events.read() {
61        if let Ok(queue) = query.get_mut(event.entity) {
62            let _ = queue.tx.send(event.packet.clone());
63        } else {
64            error!("Sent SendPacketEvent for entity that doesn't have a LoginSendPacketQueue");
65        }
66    }
67}
68
69/// Plugins can add to this set if they want to handle a custom query packet
70/// themselves. This component removed after the login state ends.
71#[derive(Component, Default, Debug, Deref, DerefMut)]
72pub struct IgnoreQueryIds(HashSet<u32>);
73
74pub fn process_packet_events(ecs: &mut World) {
75    let mut events_owned = Vec::new();
76    let mut system_state: SystemState<ResMut<Events<LoginPacketEvent>>> = SystemState::new(ecs);
77    let mut events = system_state.get_mut(ecs);
78    for LoginPacketEvent {
79        entity: player_entity,
80        packet,
81    } in events.drain()
82    {
83        // we do this so `ecs` isn't borrowed for the whole loop
84        events_owned.push((player_entity, packet));
85    }
86    for (player_entity, packet) in events_owned {
87        #[allow(clippy::single_match)]
88        match packet.as_ref() {
89            ClientboundLoginPacket::CustomQuery(p) => {
90                let mut system_state: SystemState<(
91                    EventWriter<SendLoginPacketEvent>,
92                    Query<&IgnoreQueryIds>,
93                )> = SystemState::new(ecs);
94                let (mut send_packet_events, query) = system_state.get_mut(ecs);
95
96                let ignore_query_ids = query.get(player_entity).ok().map(|x| x.0.clone());
97                if let Some(ignore_query_ids) = ignore_query_ids {
98                    if ignore_query_ids.contains(&p.transaction_id) {
99                        continue;
100                    }
101                }
102
103                send_packet_events.send(SendLoginPacketEvent::new(
104                    player_entity,
105                    ServerboundCustomQueryAnswer {
106                        transaction_id: p.transaction_id,
107                        data: None,
108                    },
109                ));
110            }
111            _ => {}
112        }
113    }
114}