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