1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 23:44:38 +00:00

update config state to also use handler functions

This commit is contained in:
mat 2025-02-17 02:12:41 +00:00
commit e532511ba5
11 changed files with 420 additions and 378 deletions

View file

@ -786,7 +786,7 @@ pub struct LocalPlayerBundle {
/// A bundle for the components that are present on a local player that is
/// currently in the `game` protocol state. If you want to filter for this, just
/// use [`LocalEntity`].
#[derive(Bundle)]
#[derive(Bundle, Default)]
pub struct JoinedClientBundle {
// note that InstanceHolder isn't here because it's set slightly before we fully join the world
pub physics_state: PhysicsState,

View file

@ -10,28 +10,27 @@ use azalea_protocol::{
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use crate::{client::InConfigState, packet::configuration::SendConfigurationEvent};
use crate::{client::InConfigState, packet::config::SendConfigPacketEvent};
pub struct ConfigurationPlugin;
impl Plugin for ConfigurationPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,
handle_in_configuration_state
.before(crate::packet::configuration::handle_send_packet_event),
handle_in_configuration_state.before(crate::packet::config::handle_send_packet_event),
);
}
}
fn handle_in_configuration_state(
query: Query<(Entity, &ClientInformation), Added<InConfigState>>,
mut send_packet_events: EventWriter<SendConfigurationEvent>,
mut send_packet_events: EventWriter<SendConfigPacketEvent>,
) {
for (entity, client_information) in query.iter() {
let mut brand_data = Vec::new();
// they don't have to know :)
"vanilla".azalea_write(&mut brand_data).unwrap();
send_packet_events.send(SendConfigurationEvent::new(
send_packet_events.send(SendConfigPacketEvent::new(
entity,
ServerboundCustomPayload {
identifier: ResourceLocation::new("brand"),
@ -39,7 +38,7 @@ fn handle_in_configuration_state(
},
));
send_packet_events.send(SendConfigurationEvent::new(
send_packet_events.send(SendConfigPacketEvent::new(
entity,
ServerboundClientInformation {
information: client_information.clone(),

View file

@ -0,0 +1,90 @@
use std::io::Cursor;
use azalea_protocol::{
packets::{
config::{ClientboundConfigPacket, ServerboundConfigPacket},
Packet,
},
read::deserialize_packet,
};
use bevy_ecs::prelude::*;
use tracing::{debug, error};
use crate::{raw_connection::RawConnection, InConfigState};
#[derive(Event, Debug, Clone)]
pub struct ReceiveConfigPacketEvent {
/// The client entity that received the packet.
pub entity: Entity,
/// The packet that was actually received.
pub packet: ClientboundConfigPacket,
}
/// An event for sending a packet to the server while we're in the
/// `configuration` state.
#[derive(Event)]
pub struct SendConfigPacketEvent {
pub sent_by: Entity,
pub packet: ServerboundConfigPacket,
}
impl SendConfigPacketEvent {
pub fn new(sent_by: Entity, packet: impl Packet<ServerboundConfigPacket>) -> Self {
let packet = packet.into_variant();
Self { sent_by, packet }
}
}
pub fn handle_send_packet_event(
mut send_packet_events: EventReader<SendConfigPacketEvent>,
mut query: Query<(&mut RawConnection, Option<&InConfigState>)>,
) {
for event in send_packet_events.read() {
if let Ok((raw_conn, in_configuration_state)) = query.get_mut(event.sent_by) {
if in_configuration_state.is_none() {
error!(
"Tried to send a configuration packet {:?} while not in configuration state",
event.packet
);
continue;
}
debug!("Sending packet: {:?}", event.packet);
if let Err(e) = raw_conn.write_packet(event.packet.clone()) {
error!("Failed to send packet: {e}");
}
}
}
}
pub fn send_packet_events(
query: Query<(Entity, &RawConnection), With<InConfigState>>,
mut packet_events: ResMut<Events<ReceiveConfigPacketEvent>>,
) {
// we manually clear and send the events at the beginning of each update
// since otherwise it'd cause issues with events in process_packet_events
// running twice
packet_events.clear();
for (player_entity, raw_conn) in &query {
let packets_lock = raw_conn.incoming_packet_queue();
let mut packets = packets_lock.lock();
if !packets.is_empty() {
for raw_packet in packets.iter() {
let packet = match deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new(
raw_packet,
)) {
Ok(packet) => packet,
Err(err) => {
error!("failed to read packet: {err:?}");
debug!("packet bytes: {raw_packet:?}");
continue;
}
};
packet_events.send(ReceiveConfigPacketEvent {
entity: player_entity,
packet,
});
}
// clear the packets right after we read them
packets.clear();
}
}
}

View file

@ -0,0 +1,223 @@
mod events;
use azalea_protocol::packets::config::*;
use azalea_protocol::packets::ConnectionProtocol;
use bevy_ecs::prelude::*;
use bevy_ecs::system::SystemState;
pub use events::*;
use tracing::{debug, warn};
use super::as_system;
use crate::client::InConfigState;
use crate::disconnect::DisconnectEvent;
use crate::packet::game::KeepAliveEvent;
use crate::raw_connection::RawConnection;
use crate::{declare_packet_handlers, InstanceHolder};
pub fn process_packet_events(ecs: &mut World) {
let mut events_owned = Vec::new();
let mut system_state: SystemState<EventReader<ReceiveConfigPacketEvent>> =
SystemState::new(ecs);
let mut events = system_state.get_mut(ecs);
for ReceiveConfigPacketEvent {
entity: player_entity,
packet,
} in events.read()
{
// we do this so `ecs` isn't borrowed for the whole loop
events_owned.push((*player_entity, packet.clone()));
}
for (player_entity, packet) in events_owned {
let mut handler = ConfigPacketHandler {
player: player_entity,
ecs,
};
declare_packet_handlers!(
ClientboundConfigPacket,
packet,
handler,
[
cookie_request,
custom_payload,
disconnect,
finish_configuration,
keep_alive,
ping,
reset_chat,
registry_data,
resource_pack_pop,
resource_pack_push,
store_cookie,
transfer,
update_enabled_features,
update_tags,
select_known_packs,
custom_report_details,
server_links,
]
);
}
}
pub struct ConfigPacketHandler<'a> {
pub ecs: &'a mut World,
pub player: Entity,
}
impl ConfigPacketHandler<'_> {
pub fn registry_data(&mut self, p: ClientboundRegistryData) {
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
let instance_holder = query.get_mut(self.player).unwrap();
let mut instance = instance_holder.instance.write();
// add the new registry data
instance.registries.append(p.registry_id, p.entries);
});
}
pub fn custom_payload(&mut self, p: ClientboundCustomPayload) {
debug!("Got custom payload packet {p:?}");
}
pub fn disconnect(&mut self, p: ClientboundDisconnect) {
warn!("Got disconnect packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(DisconnectEvent {
entity: self.player,
reason: Some(p.reason),
});
});
}
pub fn finish_configuration(&mut self, p: ClientboundFinishConfiguration) {
debug!("got FinishConfiguration packet: {p:?}");
as_system::<(Commands, Query<&mut RawConnection>)>(
self.ecs,
|(mut commands, mut query)| {
let mut raw_conn = query.get_mut(self.player).unwrap();
raw_conn
.write_packet(ServerboundFinishConfiguration)
.expect(
"we should be in the right state and encoding this packet shouldn't fail",
);
raw_conn.set_state(ConnectionProtocol::Game);
// these components are added now that we're going to be in the Game state
commands
.entity(self.player)
.remove::<InConfigState>()
.insert(crate::JoinedClientBundle::default());
},
);
}
pub fn keep_alive(&mut self, p: ClientboundKeepAlive) {
debug!(
"Got keep alive packet (in configuration) {p:?} for {:?}",
self.player
);
as_system::<(Query<&RawConnection>, EventWriter<_>)>(self.ecs, |(query, mut events)| {
let raw_conn = query.get(self.player).unwrap();
events.send(KeepAliveEvent {
entity: self.player,
id: p.id,
});
raw_conn
.write_packet(ServerboundKeepAlive { id: p.id })
.unwrap();
});
}
pub fn ping(&mut self, p: ClientboundPing) {
debug!("Got ping packet (in configuration) {p:?}");
as_system::<Query<&RawConnection>>(self.ecs, |query| {
let raw_conn = query.get(self.player).unwrap();
raw_conn.write_packet(ServerboundPong { id: p.id }).unwrap();
});
}
pub fn resource_pack_push(&mut self, p: ClientboundResourcePackPush) {
debug!("Got resource pack push packet {p:?}");
as_system::<Query<&RawConnection>>(self.ecs, |query| {
let raw_conn = query.get(self.player).unwrap();
// always accept resource pack
raw_conn
.write_packet(ServerboundResourcePack {
id: p.id,
action: s_resource_pack::Action::Accepted,
})
.unwrap();
});
}
pub fn resource_pack_pop(&mut self, p: ClientboundResourcePackPop) {
debug!("Got resource pack pop packet {p:?}");
}
pub fn update_enabled_features(&mut self, p: ClientboundUpdateEnabledFeatures) {
debug!("Got update enabled features packet {p:?}");
}
pub fn update_tags(&mut self, _p: ClientboundUpdateTags) {
debug!("Got update tags packet");
}
pub fn cookie_request(&mut self, p: ClientboundCookieRequest) {
debug!("Got cookie request packet {p:?}");
as_system::<Query<&RawConnection>>(self.ecs, |query| {
let raw_conn = query.get(self.player).unwrap();
raw_conn
.write_packet(ServerboundCookieResponse {
key: p.key,
// cookies aren't implemented
payload: None,
})
.unwrap();
});
}
pub fn reset_chat(&mut self, p: ClientboundResetChat) {
debug!("Got reset chat packet {p:?}");
}
pub fn store_cookie(&mut self, p: ClientboundStoreCookie) {
debug!("Got store cookie packet {p:?}");
}
pub fn transfer(&mut self, p: ClientboundTransfer) {
debug!("Got transfer packet {p:?}");
}
pub fn select_known_packs(&mut self, p: ClientboundSelectKnownPacks) {
debug!("Got select known packs packet {p:?}");
as_system::<Query<&RawConnection>>(self.ecs, |query| {
let raw_conn = query.get(self.player).unwrap();
// resource pack management isn't implemented
raw_conn
.write_packet(ServerboundSelectKnownPacks {
known_packs: vec![],
})
.unwrap();
});
}
pub fn server_links(&mut self, p: ClientboundServerLinks) {
debug!("Got server links packet {p:?}");
}
pub fn custom_report_details(&mut self, p: ClientboundCustomReportDetails) {
debug!("Got custom report details packet {p:?}");
}
}

View file

@ -1,271 +0,0 @@
use std::io::Cursor;
use azalea_entity::indexing::EntityIdIndex;
use azalea_protocol::packets::config::s_finish_configuration::ServerboundFinishConfiguration;
use azalea_protocol::packets::config::s_keep_alive::ServerboundKeepAlive;
use azalea_protocol::packets::config::s_select_known_packs::ServerboundSelectKnownPacks;
use azalea_protocol::packets::config::{
self, ClientboundConfigPacket, ServerboundConfigPacket, ServerboundCookieResponse,
ServerboundResourcePack,
};
use azalea_protocol::packets::{ConnectionProtocol, Packet};
use azalea_protocol::read::deserialize_packet;
use bevy_ecs::prelude::*;
use bevy_ecs::system::SystemState;
use tracing::{debug, error, warn};
use crate::client::InConfigState;
use crate::disconnect::DisconnectEvent;
use crate::local_player::Hunger;
use crate::packet::game::KeepAliveEvent;
use crate::raw_connection::RawConnection;
use crate::InstanceHolder;
#[derive(Event, Debug, Clone)]
pub struct ConfigurationEvent {
/// The client entity that received the packet.
pub entity: Entity,
/// The packet that was actually received.
pub packet: ClientboundConfigPacket,
}
pub fn send_packet_events(
query: Query<(Entity, &RawConnection), With<InConfigState>>,
mut packet_events: ResMut<Events<ConfigurationEvent>>,
) {
// we manually clear and send the events at the beginning of each update
// since otherwise it'd cause issues with events in process_packet_events
// running twice
packet_events.clear();
for (player_entity, raw_conn) in &query {
let packets_lock = raw_conn.incoming_packet_queue();
let mut packets = packets_lock.lock();
if !packets.is_empty() {
for raw_packet in packets.iter() {
let packet = match deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new(
raw_packet,
)) {
Ok(packet) => packet,
Err(err) => {
error!("failed to read packet: {err:?}");
debug!("packet bytes: {raw_packet:?}");
continue;
}
};
packet_events.send(ConfigurationEvent {
entity: player_entity,
packet,
});
}
// clear the packets right after we read them
packets.clear();
}
}
}
pub fn process_packet_events(ecs: &mut World) {
let mut events_owned = Vec::new();
let mut system_state: SystemState<EventReader<ConfigurationEvent>> = SystemState::new(ecs);
let mut events = system_state.get_mut(ecs);
for ConfigurationEvent {
entity: player_entity,
packet,
} in events.read()
{
// we do this so `ecs` isn't borrowed for the whole loop
events_owned.push((*player_entity, packet.clone()));
}
for (player_entity, packet) in events_owned {
match packet {
ClientboundConfigPacket::RegistryData(p) => {
let mut system_state: SystemState<Query<&mut InstanceHolder>> =
SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
let instance_holder = query.get_mut(player_entity).unwrap();
let mut instance = instance_holder.instance.write();
// add the new registry data
instance.registries.append(p.registry_id, p.entries);
}
ClientboundConfigPacket::CustomPayload(p) => {
debug!("Got custom payload packet {p:?}");
}
ClientboundConfigPacket::Disconnect(p) => {
warn!("Got disconnect packet {p:?}");
let mut system_state: SystemState<EventWriter<DisconnectEvent>> =
SystemState::new(ecs);
let mut disconnect_events = system_state.get_mut(ecs);
disconnect_events.send(DisconnectEvent {
entity: player_entity,
reason: Some(p.reason.clone()),
});
}
ClientboundConfigPacket::FinishConfiguration(p) => {
debug!("got FinishConfiguration packet: {p:?}");
let mut system_state: SystemState<Query<&mut RawConnection>> =
SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
let mut raw_conn = query.get_mut(player_entity).unwrap();
raw_conn
.write_packet(ServerboundFinishConfiguration)
.expect(
"we should be in the right state and encoding this packet shouldn't fail",
);
raw_conn.set_state(ConnectionProtocol::Game);
// these components are added now that we're going to be in the Game state
ecs.entity_mut(player_entity)
.remove::<InConfigState>()
.insert(crate::JoinedClientBundle {
physics_state: crate::PhysicsState::default(),
inventory: crate::inventory::Inventory::default(),
tab_list: crate::local_player::TabList::default(),
current_sequence_number: crate::interact::CurrentSequenceNumber::default(),
last_sent_direction: crate::movement::LastSentLookDirection::default(),
abilities: crate::local_player::PlayerAbilities::default(),
permission_level: crate::local_player::PermissionLevel::default(),
hunger: Hunger::default(),
chunk_batch_info: crate::chunks::ChunkBatchInfo::default(),
entity_id_index: EntityIdIndex::default(),
mining: crate::mining::MineBundle::default(),
attack: crate::attack::AttackBundle::default(),
_local_entity: azalea_entity::LocalEntity,
});
}
ClientboundConfigPacket::KeepAlive(p) => {
debug!("Got keep alive packet (in configuration) {p:?} for {player_entity:?}");
let mut system_state: SystemState<(
Query<&RawConnection>,
EventWriter<KeepAliveEvent>,
)> = SystemState::new(ecs);
let (query, mut keepalive_events) = system_state.get_mut(ecs);
let raw_conn = query.get(player_entity).unwrap();
keepalive_events.send(KeepAliveEvent {
entity: player_entity,
id: p.id,
});
raw_conn
.write_packet(ServerboundKeepAlive { id: p.id })
.unwrap();
}
ClientboundConfigPacket::Ping(p) => {
debug!("Got ping packet {p:?}");
let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
let raw_conn = query.get_mut(player_entity).unwrap();
raw_conn
.write_packet(config::s_pong::ServerboundPong { id: p.id })
.unwrap();
}
ClientboundConfigPacket::ResourcePackPush(p) => {
debug!("Got resource pack packet {p:?}");
let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
let raw_conn = query.get_mut(player_entity).unwrap();
// always accept resource pack
raw_conn
.write_packet(ServerboundResourcePack {
id: p.id,
action: config::s_resource_pack::Action::Accepted,
})
.unwrap();
}
ClientboundConfigPacket::ResourcePackPop(_) => {
// we can ignore this
}
ClientboundConfigPacket::UpdateEnabledFeatures(p) => {
debug!("Got update enabled features packet {p:?}");
}
ClientboundConfigPacket::UpdateTags(_p) => {
debug!("Got update tags packet");
}
ClientboundConfigPacket::CookieRequest(p) => {
debug!("Got cookie request packet {p:?}");
let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
let raw_conn = query.get_mut(player_entity).unwrap();
raw_conn
.write_packet(ServerboundCookieResponse {
key: p.key,
// cookies aren't implemented
payload: None,
})
.unwrap();
}
ClientboundConfigPacket::ResetChat(p) => {
debug!("Got reset chat packet {p:?}");
}
ClientboundConfigPacket::StoreCookie(p) => {
debug!("Got store cookie packet {p:?}");
}
ClientboundConfigPacket::Transfer(p) => {
debug!("Got transfer packet {p:?}");
}
ClientboundConfigPacket::SelectKnownPacks(p) => {
debug!("Got select known packs packet {p:?}");
let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
let raw_conn = query.get_mut(player_entity).unwrap();
// resource pack management isn't implemented
raw_conn
.write_packet(ServerboundSelectKnownPacks {
known_packs: vec![],
})
.unwrap();
}
ClientboundConfigPacket::ServerLinks(_) => {}
ClientboundConfigPacket::CustomReportDetails(_) => {}
}
}
}
/// An event for sending a packet to the server while we're in the
/// `configuration` state.
#[derive(Event)]
pub struct SendConfigurationEvent {
pub sent_by: Entity,
pub packet: ServerboundConfigPacket,
}
impl SendConfigurationEvent {
pub fn new(sent_by: Entity, packet: impl Packet<ServerboundConfigPacket>) -> Self {
let packet = packet.into_variant();
Self { sent_by, packet }
}
}
pub fn handle_send_packet_event(
mut send_packet_events: EventReader<SendConfigurationEvent>,
mut query: Query<(&mut RawConnection, Option<&InConfigState>)>,
) {
for event in send_packet_events.read() {
if let Ok((raw_conn, in_configuration_state)) = query.get_mut(event.sent_by) {
if in_configuration_state.is_none() {
error!(
"Tried to send a configuration packet {:?} while not in configuration state",
event.packet
);
continue;
}
debug!("Sending packet: {:?}", event.packet);
if let Err(e) = raw_conn.write_packet(event.packet.clone()) {
error!("Failed to send packet: {e}");
}
}
}
}

View file

@ -1,17 +1,25 @@
use std::sync::{Arc, Weak};
use std::{
io::Cursor,
sync::{Arc, Weak},
};
use azalea_chat::FormattedText;
use azalea_core::resource_location::ResourceLocation;
use azalea_protocol::packets::{
game::{ClientboundGamePacket, ClientboundPlayerCombatKill, ServerboundGamePacket},
Packet,
use azalea_entity::LocalEntity;
use azalea_protocol::{
packets::{
game::{ClientboundGamePacket, ClientboundPlayerCombatKill, ServerboundGamePacket},
Packet,
},
read::deserialize_packet,
};
use azalea_world::Instance;
use bevy_ecs::{entity::Entity, event::Event};
use bevy_ecs::prelude::*;
use parking_lot::RwLock;
use tracing::{debug, error};
use uuid::Uuid;
use crate::PlayerInfo;
use crate::{raw_connection::RawConnection, PlayerInfo};
/// An event that's sent when we receive a packet.
/// ```
@ -54,6 +62,54 @@ impl SendPacketEvent {
}
}
pub fn handle_sendpacketevent(
mut send_packet_events: EventReader<SendPacketEvent>,
mut query: Query<&mut RawConnection>,
) {
for event in send_packet_events.read() {
if let Ok(raw_connection) = query.get_mut(event.sent_by) {
// debug!("Sending packet: {:?}", event.packet);
if let Err(e) = raw_connection.write_packet(event.packet.clone()) {
error!("Failed to send packet: {e}");
}
}
}
}
pub fn send_receivepacketevent(
query: Query<(Entity, &RawConnection), With<LocalEntity>>,
mut packet_events: ResMut<Events<ReceivePacketEvent>>,
) {
// we manually clear and send the events at the beginning of each update
// since otherwise it'd cause issues with events in process_packet_events
// running twice
packet_events.clear();
for (player_entity, raw_connection) in &query {
let packets_lock = raw_connection.incoming_packet_queue();
let mut packets = packets_lock.lock();
if !packets.is_empty() {
for raw_packet in packets.iter() {
let packet =
match deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(raw_packet))
{
Ok(packet) => packet,
Err(err) => {
error!("failed to read packet: {err:?}");
debug!("packet bytes: {raw_packet:?}");
continue;
}
};
packet_events.send(ReceivePacketEvent {
entity: player_entity,
packet: Arc::new(packet),
});
}
// clear the packets right after we read them
packets.clear();
}
}
}
/// A player joined the game (or more specifically, was added to the tab
/// list of a local player).
#[derive(Event, Debug, Clone)]

View file

@ -1,6 +1,6 @@
mod events;
use std::{collections::HashSet, io::Cursor, ops::Add, sync::Arc};
use std::{collections::HashSet, ops::Add, sync::Arc};
use azalea_core::{
game_type::GameMode,
@ -14,12 +14,9 @@ use azalea_entity::{
Dead, EntityBundle, EntityKind, LastSentPosition, LoadedBy, LocalEntity, LookDirection,
Physics, Position, RelativeEntityUpdate,
};
use azalea_protocol::{packets::game::*, read::deserialize_packet};
use azalea_protocol::packets::game::*;
use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance};
use bevy_ecs::{
prelude::*,
system::{SystemParam, SystemState},
};
use bevy_ecs::{prelude::*, system::SystemState};
pub use events::*;
use tracing::{debug, error, trace, warn};
@ -34,7 +31,7 @@ use crate::{
GameProfileComponent, Hunger, InstanceHolder, LocalGameMode, PlayerAbilities, TabList,
},
movement::{KnockbackEvent, KnockbackType},
raw_connection::RawConnection,
packet::as_system,
ClientInformation, PlayerInfo,
};
@ -62,7 +59,7 @@ pub fn process_packet_events(ecs: &mut World) {
declare_packet_handlers!(
ClientboundGamePacket,
packet,
packet.as_ref(),
handler,
[
login,
@ -201,6 +198,10 @@ pub fn process_packet_events(ecs: &mut World) {
}
}
pub struct GamePacketHandler<'a> {
pub ecs: &'a mut World,
pub player: Entity,
}
impl GamePacketHandler<'_> {
pub fn login(&mut self, p: &ClientboundLogin) {
debug!("Got login packet");
@ -811,9 +812,9 @@ impl GamePacketHandler<'_> {
// multiple times when in swarms
let knockback = KnockbackType::Set(Vec3 {
x: p.xa as f64 / 8000.,
y: p.ya as f64 / 8000.,
z: p.za as f64 / 8000.,
x: p.delta.xa as f64 / 8000.,
y: p.delta.ya as f64 / 8000.,
z: p.delta.za as f64 / 8000.,
});
commands.entity(entity).queue(RelativeEntityUpdate {
@ -1598,66 +1599,3 @@ impl GamePacketHandler<'_> {
pub fn recipe_book_remove(&mut self, _p: &ClientboundRecipeBookRemove) {}
pub fn recipe_book_settings(&mut self, _p: &ClientboundRecipeBookSettings) {}
}
pub struct GamePacketHandler<'a> {
pub ecs: &'a mut World,
pub player: Entity,
}
pub fn as_system<T>(ecs: &mut World, f: impl FnOnce(T::Item<'_, '_>))
where
T: SystemParam + 'static,
{
let mut system_state = SystemState::<T>::new(ecs);
let values = system_state.get_mut(ecs);
f(values);
system_state.apply(ecs);
}
pub fn handle_sendpacketevent(
mut send_packet_events: EventReader<SendPacketEvent>,
mut query: Query<&mut RawConnection>,
) {
for event in send_packet_events.read() {
if let Ok(raw_connection) = query.get_mut(event.sent_by) {
// debug!("Sending packet: {:?}", event.packet);
if let Err(e) = raw_connection.write_packet(event.packet.clone()) {
error!("Failed to send packet: {e}");
}
}
}
}
pub fn send_receivepacketevent(
query: Query<(Entity, &RawConnection), With<LocalEntity>>,
mut packet_events: ResMut<Events<ReceivePacketEvent>>,
) {
// we manually clear and send the events at the beginning of each update
// since otherwise it'd cause issues with events in process_packet_events
// running twice
packet_events.clear();
for (player_entity, raw_connection) in &query {
let packets_lock = raw_connection.incoming_packet_queue();
let mut packets = packets_lock.lock();
if !packets.is_empty() {
for raw_packet in packets.iter() {
let packet =
match deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(raw_packet))
{
Ok(packet) => packet,
Err(err) => {
error!("failed to read packet: {err:?}");
debug!("packet bytes: {raw_packet:?}");
continue;
}
};
packet_events.send(ReceivePacketEvent {
entity: player_entity,
packet: Arc::new(packet),
});
}
// clear the packets right after we read them
packets.clear();
}
}
}

View file

@ -1,6 +1,9 @@
use azalea_entity::{metadata::Health, EntityUpdateSet};
use bevy_app::{App, First, Plugin, PreUpdate, Update};
use bevy_ecs::prelude::*;
use bevy_ecs::{
prelude::*,
system::{SystemParam, SystemState},
};
use self::{
game::{
@ -11,7 +14,7 @@ use self::{
};
use crate::{chat::ChatReceivedEvent, events::death_listener};
pub mod configuration;
pub mod config;
pub mod game;
pub mod login;
@ -35,10 +38,7 @@ impl Plugin for PacketHandlerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
First,
(
game::send_receivepacketevent,
configuration::send_packet_events,
),
(game::send_receivepacketevent, config::send_packet_events),
)
.add_systems(
PreUpdate,
@ -46,7 +46,7 @@ impl Plugin for PacketHandlerPlugin {
game::process_packet_events
// we want to index and deindex right after
.before(EntityUpdateSet::Deindex),
configuration::process_packet_events,
config::process_packet_events,
login::handle_send_packet_event,
login::process_packet_events,
),
@ -55,7 +55,7 @@ impl Plugin for PacketHandlerPlugin {
Update,
(
(
configuration::handle_send_packet_event,
config::handle_send_packet_event,
game::handle_sendpacketevent,
)
.chain(),
@ -64,9 +64,9 @@ impl Plugin for PacketHandlerPlugin {
)
// we do this instead of add_event so we can handle the events ourselves
.init_resource::<Events<game::ReceivePacketEvent>>()
.init_resource::<Events<configuration::ConfigurationEvent>>()
.init_resource::<Events<config::ReceiveConfigPacketEvent>>()
.add_event::<game::SendPacketEvent>()
.add_event::<configuration::SendConfigurationEvent>()
.add_event::<config::SendConfigPacketEvent>()
.add_event::<AddPlayerEvent>()
.add_event::<RemovePlayerEvent>()
.add_event::<UpdatePlayerEvent>()
@ -84,12 +84,12 @@ impl Plugin for PacketHandlerPlugin {
macro_rules! declare_packet_handlers {
(
$packetenum:ident,
$packetvar:ident,
$packetvar:expr,
$handler:ident,
[$($packet:path),+ $(,)?]
) => {
paste::paste! {
match $packetvar.as_ref() {
match $packetvar {
$(
$packetenum::[< $packet:camel >](p) => $handler.$packet(p),
)+
@ -97,3 +97,13 @@ macro_rules! declare_packet_handlers {
}
};
}
pub(crate) fn as_system<T>(ecs: &mut World, f: impl FnOnce(T::Item<'_, '_>))
where
T: SystemParam + 'static,
{
let mut system_state = SystemState::<T>::new(ecs);
let values = system_state.get_mut(ecs);
f(values);
system_state.apply(ecs);
}

View file

@ -482,7 +482,7 @@ impl EntityBundle {
/// be updated by other clients.
///
/// If this is for a client then all of our clients will have this.
#[derive(Component, Clone, Debug)]
#[derive(Component, Clone, Debug, Default)]
pub struct LocalEntity;
#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]

View file

@ -1,5 +1,5 @@
use azalea_buf::AzBuf;
use azalea_core::{position::Vec3, resource_location::ResourceLocation};
use azalea_core::{delta::PositionDelta8, position::Vec3, resource_location::ResourceLocation};
use azalea_entity::{metadata::apply_default_metadata, EntityBundle};
use azalea_protocol_macros::ClientboundGamePacket;
use azalea_world::MinecraftEntityId;
@ -18,9 +18,7 @@ pub struct ClientboundAddEntity {
pub y_head_rot: i8,
#[var]
pub data: u32,
pub x_vel: i16,
pub y_vel: i16,
pub z_vel: i16,
pub velocity: PositionDelta8,
}
impl ClientboundAddEntity {

View file

@ -1,4 +1,5 @@
use azalea_buf::AzBuf;
use azalea_core::delta::PositionDelta8;
use azalea_protocol_macros::ClientboundGamePacket;
use azalea_world::MinecraftEntityId;
@ -6,7 +7,5 @@ use azalea_world::MinecraftEntityId;
pub struct ClientboundSetEntityMotion {
#[var]
pub id: MinecraftEntityId,
pub xa: i16,
pub ya: i16,
pub za: i16,
pub delta: PositionDelta8,
}