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:
parent
c3bbc9e563
commit
e532511ba5
11 changed files with 420 additions and 378 deletions
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
90
azalea-client/src/packet/config/events.rs
Normal file
90
azalea-client/src/packet/config/events.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
223
azalea-client/src/packet/config/mod.rs
Normal file
223
azalea-client/src/packet/config/mod.rs
Normal 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:?}");
|
||||
}
|
||||
}
|
|
@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)]
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue