From f311ac27d47c43eb4c33d760f3e1d1f2b8008a4f Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 3 Jun 2025 22:01:50 +0330 Subject: [PATCH] send ServerboundPlayerLoaded on join and respawn --- azalea-client/src/plugins/disconnect.rs | 4 +- azalea-client/src/plugins/loading.rs | 40 +++++++++++++++++++ azalea-client/src/plugins/mod.rs | 2 + .../src/plugins/packet/game/events.rs | 5 ++- azalea-client/src/plugins/packet/game/mod.rs | 6 ++- 5 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 azalea-client/src/plugins/loading.rs diff --git a/azalea-client/src/plugins/disconnect.rs b/azalea-client/src/plugins/disconnect.rs index c6c01e35..8dddff09 100644 --- a/azalea-client/src/plugins/disconnect.rs +++ b/azalea-client/src/plugins/disconnect.rs @@ -10,7 +10,7 @@ use tracing::info; use super::login::IsAuthenticated; use crate::{ - chat_signing, client::JoinedClientBundle, connection::RawConnection, + chat_signing, client::JoinedClientBundle, connection::RawConnection, loading::HasClientLoaded, local_player::InstanceHolder, }; @@ -69,6 +69,8 @@ pub struct RemoveOnDisconnectBundle { pub chat_signing_session: chat_signing::ChatSigningSession, /// They're not authenticated anymore if they disconnected. pub is_authenticated: IsAuthenticated, + // send ServerboundPlayerLoaded next time we join + pub has_client_loaded: HasClientLoaded, } /// A system that removes the several components from our clients when they get diff --git a/azalea-client/src/plugins/loading.rs b/azalea-client/src/plugins/loading.rs new file mode 100644 index 00000000..33290f39 --- /dev/null +++ b/azalea-client/src/plugins/loading.rs @@ -0,0 +1,40 @@ +use azalea_core::tick::GameTick; +use azalea_entity::InLoadedChunk; +use azalea_physics::PhysicsSet; +use azalea_protocol::packets::game::ServerboundPlayerLoaded; +use bevy_app::{App, Plugin}; +use bevy_ecs::prelude::*; + +use crate::{mining::MiningSet, packet::game::SendPacketEvent}; + +pub struct PlayerLoadedPlugin; +impl Plugin for PlayerLoadedPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + GameTick, + player_loaded_packet + .after(PhysicsSet) + .after(MiningSet) + .after(crate::movement::send_position), + ); + } +} + +// this component is removed on respawn or disconnect +// (notably, it's not removed on login) + +// mojmap interchangably calls it 'has client loaded' and 'has player loaded', i +// prefer the client one because it makes it clear that the component is only +// present on our own clients + +#[derive(Component)] +pub struct HasClientLoaded; +pub fn player_loaded_packet( + mut commands: Commands, + query: Query, Without)>, +) { + for entity in query.iter() { + commands.trigger(SendPacketEvent::new(entity, ServerboundPlayerLoaded)); + commands.entity(entity).insert(HasClientLoaded); + } +} diff --git a/azalea-client/src/plugins/mod.rs b/azalea-client/src/plugins/mod.rs index dea2fdb8..6f003b01 100644 --- a/azalea-client/src/plugins/mod.rs +++ b/azalea-client/src/plugins/mod.rs @@ -12,6 +12,7 @@ pub mod events; pub mod interact; pub mod inventory; pub mod join; +pub mod loading; pub mod login; pub mod mining; pub mod movement; @@ -48,6 +49,7 @@ impl PluginGroup for DefaultPlugins { .add(attack::AttackPlugin) .add(chunks::ChunksPlugin) .add(tick_end::TickEndPlugin) + .add(loading::PlayerLoadedPlugin) .add(brand::BrandPlugin) .add(tick_broadcast::TickBroadcastPlugin) .add(pong::PongPlugin) diff --git a/azalea-client/src/plugins/packet/game/events.rs b/azalea-client/src/plugins/packet/game/events.rs index 7134a2f2..e341db3e 100644 --- a/azalea-client/src/plugins/packet/game/events.rs +++ b/azalea-client/src/plugins/packet/game/events.rs @@ -57,7 +57,6 @@ pub fn handle_outgoing_packets_observer( mut query: Query<(&mut RawConnection, Option<&InGameState>)>, ) { let event = trigger.event(); - trace!("Sending game packet: {:?}", event.packet); if let Ok((mut raw_connection, in_game_state)) = query.get_mut(event.sent_by) { if in_game_state.is_none() { @@ -68,10 +67,12 @@ pub fn handle_outgoing_packets_observer( return; } - // debug!("Sending game packet: {:?}", event.packet); + trace!("Sending game packet: {:?}", event.packet); if let Err(e) = raw_connection.write(event.packet.clone()) { error!("Failed to send packet: {e}"); } + } else { + trace!("Not sending game packet: {:?}", event.packet); } } diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs index 63c1bafa..670058c3 100644 --- a/azalea-client/src/plugins/packet/game/mod.rs +++ b/azalea-client/src/plugins/packet/game/mod.rs @@ -29,6 +29,7 @@ use crate::{ inventory::{ ClientSideCloseContainerEvent, Inventory, MenuOpenedEvent, SetContainerContentEvent, }, + loading::HasClientLoaded, local_player::{Hunger, InstanceHolder, LocalGameMode, PlayerAbilities, TabList}, movement::{KnockbackEvent, KnockbackType}, packet::as_system, @@ -1490,8 +1491,9 @@ impl GamePacketHandler<'_> { entity_bundle, )); - // Remove the Dead marker component from the player. - commands.entity(self.player).remove::(); + commands + .entity(self.player) + .remove::<(Dead, HasClientLoaded)>(); }, ) }