Skip to content

Commit e532511

Browse files
committed
update config state to also use handler functions
1 parent c3bbc9e commit e532511

File tree

11 files changed

+420
-378
lines changed

11 files changed

+420
-378
lines changed

azalea-client/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ pub struct LocalPlayerBundle {
786786
/// A bundle for the components that are present on a local player that is
787787
/// currently in the `game` protocol state. If you want to filter for this, just
788788
/// use [`LocalEntity`].
789-
#[derive(Bundle)]
789+
#[derive(Bundle, Default)]
790790
pub struct JoinedClientBundle {
791791
// note that InstanceHolder isn't here because it's set slightly before we fully join the world
792792
pub physics_state: PhysicsState,

azalea-client/src/configuration.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,35 @@ use azalea_protocol::{
1010
use bevy_app::prelude::*;
1111
use bevy_ecs::prelude::*;
1212

13-
use crate::{client::InConfigState, packet::configuration::SendConfigurationEvent};
13+
use crate::{client::InConfigState, packet::config::SendConfigPacketEvent};
1414

1515
pub struct ConfigurationPlugin;
1616
impl Plugin for ConfigurationPlugin {
1717
fn build(&self, app: &mut App) {
1818
app.add_systems(
1919
Update,
20-
handle_in_configuration_state
21-
.before(crate::packet::configuration::handle_send_packet_event),
20+
handle_in_configuration_state.before(crate::packet::config::handle_send_packet_event),
2221
);
2322
}
2423
}
2524

2625
fn handle_in_configuration_state(
2726
query: Query<(Entity, &ClientInformation), Added<InConfigState>>,
28-
mut send_packet_events: EventWriter<SendConfigurationEvent>,
27+
mut send_packet_events: EventWriter<SendConfigPacketEvent>,
2928
) {
3029
for (entity, client_information) in query.iter() {
3130
let mut brand_data = Vec::new();
3231
// they don't have to know :)
3332
"vanilla".azalea_write(&mut brand_data).unwrap();
34-
send_packet_events.send(SendConfigurationEvent::new(
33+
send_packet_events.send(SendConfigPacketEvent::new(
3534
entity,
3635
ServerboundCustomPayload {
3736
identifier: ResourceLocation::new("brand"),
3837
data: brand_data.into(),
3938
},
4039
));
4140

42-
send_packet_events.send(SendConfigurationEvent::new(
41+
send_packet_events.send(SendConfigPacketEvent::new(
4342
entity,
4443
ServerboundClientInformation {
4544
information: client_information.clone(),
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use std::io::Cursor;
2+
3+
use azalea_protocol::{
4+
packets::{
5+
config::{ClientboundConfigPacket, ServerboundConfigPacket},
6+
Packet,
7+
},
8+
read::deserialize_packet,
9+
};
10+
use bevy_ecs::prelude::*;
11+
use tracing::{debug, error};
12+
13+
use crate::{raw_connection::RawConnection, InConfigState};
14+
15+
#[derive(Event, Debug, Clone)]
16+
pub struct ReceiveConfigPacketEvent {
17+
/// The client entity that received the packet.
18+
pub entity: Entity,
19+
/// The packet that was actually received.
20+
pub packet: ClientboundConfigPacket,
21+
}
22+
23+
/// An event for sending a packet to the server while we're in the
24+
/// `configuration` state.
25+
#[derive(Event)]
26+
pub struct SendConfigPacketEvent {
27+
pub sent_by: Entity,
28+
pub packet: ServerboundConfigPacket,
29+
}
30+
impl SendConfigPacketEvent {
31+
pub fn new(sent_by: Entity, packet: impl Packet<ServerboundConfigPacket>) -> Self {
32+
let packet = packet.into_variant();
33+
Self { sent_by, packet }
34+
}
35+
}
36+
37+
pub fn handle_send_packet_event(
38+
mut send_packet_events: EventReader<SendConfigPacketEvent>,
39+
mut query: Query<(&mut RawConnection, Option<&InConfigState>)>,
40+
) {
41+
for event in send_packet_events.read() {
42+
if let Ok((raw_conn, in_configuration_state)) = query.get_mut(event.sent_by) {
43+
if in_configuration_state.is_none() {
44+
error!(
45+
"Tried to send a configuration packet {:?} while not in configuration state",
46+
event.packet
47+
);
48+
continue;
49+
}
50+
debug!("Sending packet: {:?}", event.packet);
51+
if let Err(e) = raw_conn.write_packet(event.packet.clone()) {
52+
error!("Failed to send packet: {e}");
53+
}
54+
}
55+
}
56+
}
57+
58+
pub fn send_packet_events(
59+
query: Query<(Entity, &RawConnection), With<InConfigState>>,
60+
mut packet_events: ResMut<Events<ReceiveConfigPacketEvent>>,
61+
) {
62+
// we manually clear and send the events at the beginning of each update
63+
// since otherwise it'd cause issues with events in process_packet_events
64+
// running twice
65+
packet_events.clear();
66+
for (player_entity, raw_conn) in &query {
67+
let packets_lock = raw_conn.incoming_packet_queue();
68+
let mut packets = packets_lock.lock();
69+
if !packets.is_empty() {
70+
for raw_packet in packets.iter() {
71+
let packet = match deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new(
72+
raw_packet,
73+
)) {
74+
Ok(packet) => packet,
75+
Err(err) => {
76+
error!("failed to read packet: {err:?}");
77+
debug!("packet bytes: {raw_packet:?}");
78+
continue;
79+
}
80+
};
81+
packet_events.send(ReceiveConfigPacketEvent {
82+
entity: player_entity,
83+
packet,
84+
});
85+
}
86+
// clear the packets right after we read them
87+
packets.clear();
88+
}
89+
}
90+
}
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
mod events;
2+
3+
use azalea_protocol::packets::config::*;
4+
use azalea_protocol::packets::ConnectionProtocol;
5+
use bevy_ecs::prelude::*;
6+
use bevy_ecs::system::SystemState;
7+
pub use events::*;
8+
use tracing::{debug, warn};
9+
10+
use super::as_system;
11+
use crate::client::InConfigState;
12+
use crate::disconnect::DisconnectEvent;
13+
use crate::packet::game::KeepAliveEvent;
14+
use crate::raw_connection::RawConnection;
15+
use crate::{declare_packet_handlers, InstanceHolder};
16+
17+
pub fn process_packet_events(ecs: &mut World) {
18+
let mut events_owned = Vec::new();
19+
let mut system_state: SystemState<EventReader<ReceiveConfigPacketEvent>> =
20+
SystemState::new(ecs);
21+
let mut events = system_state.get_mut(ecs);
22+
for ReceiveConfigPacketEvent {
23+
entity: player_entity,
24+
packet,
25+
} in events.read()
26+
{
27+
// we do this so `ecs` isn't borrowed for the whole loop
28+
events_owned.push((*player_entity, packet.clone()));
29+
}
30+
for (player_entity, packet) in events_owned {
31+
let mut handler = ConfigPacketHandler {
32+
player: player_entity,
33+
ecs,
34+
};
35+
36+
declare_packet_handlers!(
37+
ClientboundConfigPacket,
38+
packet,
39+
handler,
40+
[
41+
cookie_request,
42+
custom_payload,
43+
disconnect,
44+
finish_configuration,
45+
keep_alive,
46+
ping,
47+
reset_chat,
48+
registry_data,
49+
resource_pack_pop,
50+
resource_pack_push,
51+
store_cookie,
52+
transfer,
53+
update_enabled_features,
54+
update_tags,
55+
select_known_packs,
56+
custom_report_details,
57+
server_links,
58+
]
59+
);
60+
}
61+
}
62+
63+
pub struct ConfigPacketHandler<'a> {
64+
pub ecs: &'a mut World,
65+
pub player: Entity,
66+
}
67+
impl ConfigPacketHandler<'_> {
68+
pub fn registry_data(&mut self, p: ClientboundRegistryData) {
69+
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
70+
let instance_holder = query.get_mut(self.player).unwrap();
71+
let mut instance = instance_holder.instance.write();
72+
73+
// add the new registry data
74+
instance.registries.append(p.registry_id, p.entries);
75+
});
76+
}
77+
78+
pub fn custom_payload(&mut self, p: ClientboundCustomPayload) {
79+
debug!("Got custom payload packet {p:?}");
80+
}
81+
82+
pub fn disconnect(&mut self, p: ClientboundDisconnect) {
83+
warn!("Got disconnect packet {p:?}");
84+
as_system::<EventWriter<_>>(self.ecs, |mut events| {
85+
events.send(DisconnectEvent {
86+
entity: self.player,
87+
reason: Some(p.reason),
88+
});
89+
});
90+
}
91+
92+
pub fn finish_configuration(&mut self, p: ClientboundFinishConfiguration) {
93+
debug!("got FinishConfiguration packet: {p:?}");
94+
95+
as_system::<(Commands, Query<&mut RawConnection>)>(
96+
self.ecs,
97+
|(mut commands, mut query)| {
98+
let mut raw_conn = query.get_mut(self.player).unwrap();
99+
100+
raw_conn
101+
.write_packet(ServerboundFinishConfiguration)
102+
.expect(
103+
"we should be in the right state and encoding this packet shouldn't fail",
104+
);
105+
raw_conn.set_state(ConnectionProtocol::Game);
106+
107+
// these components are added now that we're going to be in the Game state
108+
commands
109+
.entity(self.player)
110+
.remove::<InConfigState>()
111+
.insert(crate::JoinedClientBundle::default());
112+
},
113+
);
114+
}
115+
116+
pub fn keep_alive(&mut self, p: ClientboundKeepAlive) {
117+
debug!(
118+
"Got keep alive packet (in configuration) {p:?} for {:?}",
119+
self.player
120+
);
121+
122+
as_system::<(Query<&RawConnection>, EventWriter<_>)>(self.ecs, |(query, mut events)| {
123+
let raw_conn = query.get(self.player).unwrap();
124+
125+
events.send(KeepAliveEvent {
126+
entity: self.player,
127+
id: p.id,
128+
});
129+
raw_conn
130+
.write_packet(ServerboundKeepAlive { id: p.id })
131+
.unwrap();
132+
});
133+
}
134+
135+
pub fn ping(&mut self, p: ClientboundPing) {
136+
debug!("Got ping packet (in configuration) {p:?}");
137+
138+
as_system::<Query<&RawConnection>>(self.ecs, |query| {
139+
let raw_conn = query.get(self.player).unwrap();
140+
141+
raw_conn.write_packet(ServerboundPong { id: p.id }).unwrap();
142+
});
143+
}
144+
145+
pub fn resource_pack_push(&mut self, p: ClientboundResourcePackPush) {
146+
debug!("Got resource pack push packet {p:?}");
147+
148+
as_system::<Query<&RawConnection>>(self.ecs, |query| {
149+
let raw_conn = query.get(self.player).unwrap();
150+
151+
// always accept resource pack
152+
raw_conn
153+
.write_packet(ServerboundResourcePack {
154+
id: p.id,
155+
action: s_resource_pack::Action::Accepted,
156+
})
157+
.unwrap();
158+
});
159+
}
160+
161+
pub fn resource_pack_pop(&mut self, p: ClientboundResourcePackPop) {
162+
debug!("Got resource pack pop packet {p:?}");
163+
}
164+
165+
pub fn update_enabled_features(&mut self, p: ClientboundUpdateEnabledFeatures) {
166+
debug!("Got update enabled features packet {p:?}");
167+
}
168+
169+
pub fn update_tags(&mut self, _p: ClientboundUpdateTags) {
170+
debug!("Got update tags packet");
171+
}
172+
173+
pub fn cookie_request(&mut self, p: ClientboundCookieRequest) {
174+
debug!("Got cookie request packet {p:?}");
175+
176+
as_system::<Query<&RawConnection>>(self.ecs, |query| {
177+
let raw_conn = query.get(self.player).unwrap();
178+
179+
raw_conn
180+
.write_packet(ServerboundCookieResponse {
181+
key: p.key,
182+
// cookies aren't implemented
183+
payload: None,
184+
})
185+
.unwrap();
186+
});
187+
}
188+
189+
pub fn reset_chat(&mut self, p: ClientboundResetChat) {
190+
debug!("Got reset chat packet {p:?}");
191+
}
192+
193+
pub fn store_cookie(&mut self, p: ClientboundStoreCookie) {
194+
debug!("Got store cookie packet {p:?}");
195+
}
196+
197+
pub fn transfer(&mut self, p: ClientboundTransfer) {
198+
debug!("Got transfer packet {p:?}");
199+
}
200+
201+
pub fn select_known_packs(&mut self, p: ClientboundSelectKnownPacks) {
202+
debug!("Got select known packs packet {p:?}");
203+
204+
as_system::<Query<&RawConnection>>(self.ecs, |query| {
205+
let raw_conn = query.get(self.player).unwrap();
206+
207+
// resource pack management isn't implemented
208+
raw_conn
209+
.write_packet(ServerboundSelectKnownPacks {
210+
known_packs: vec![],
211+
})
212+
.unwrap();
213+
});
214+
}
215+
216+
pub fn server_links(&mut self, p: ClientboundServerLinks) {
217+
debug!("Got server links packet {p:?}");
218+
}
219+
220+
pub fn custom_report_details(&mut self, p: ClientboundCustomReportDetails) {
221+
debug!("Got custom report details packet {p:?}");
222+
}
223+
}

0 commit comments

Comments
 (0)