From e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7 Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Sat, 22 Feb 2025 21:45:26 -0600 Subject: Refactor azalea-client (#205) * start organizing packet_handling more by moving packet handlers into their own functions * finish writing all the handler functions for packets * use macro for generating match statement for packet handler functions * fix set_entity_data * update config state to also use handler functions * organize az-client file structure by moving things into plugins directory * fix merge issues --- azalea-client/src/plugins/disconnect.rs | 103 ++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 azalea-client/src/plugins/disconnect.rs (limited to 'azalea-client/src/plugins/disconnect.rs') diff --git a/azalea-client/src/plugins/disconnect.rs b/azalea-client/src/plugins/disconnect.rs new file mode 100644 index 00000000..bd10ac75 --- /dev/null +++ b/azalea-client/src/plugins/disconnect.rs @@ -0,0 +1,103 @@ +//! Disconnect a client from the server. + +use azalea_chat::FormattedText; +use azalea_entity::{EntityBundle, InLoadedChunk, LocalEntity, metadata::PlayerMetadataBundle}; +use bevy_app::{App, Plugin, PostUpdate}; +use bevy_ecs::{ + component::Component, + entity::Entity, + event::{EventReader, EventWriter}, + prelude::Event, + query::{Changed, With}, + schedule::IntoSystemConfigs, + system::{Commands, Query}, +}; +use derive_more::Deref; +use tracing::trace; + +use crate::{ + InstanceHolder, client::JoinedClientBundle, events::LocalPlayerEvents, + raw_connection::RawConnection, +}; + +pub struct DisconnectPlugin; +impl Plugin for DisconnectPlugin { + fn build(&self, app: &mut App) { + app.add_event::().add_systems( + PostUpdate, + ( + update_read_packets_task_running_component, + disconnect_on_connection_dead, + remove_components_from_disconnected_players, + ) + .chain(), + ); + } +} + +/// An event sent when a client is getting disconnected. +#[derive(Event)] +pub struct DisconnectEvent { + pub entity: Entity, + pub reason: Option, +} + +/// A system that removes the several components from our clients when they get +/// a [`DisconnectEvent`]. +pub fn remove_components_from_disconnected_players( + mut commands: Commands, + mut events: EventReader, + mut loaded_by_query: Query<&mut azalea_entity::LoadedBy>, +) { + for DisconnectEvent { entity, .. } in events.read() { + trace!("Got DisconnectEvent for {entity:?}"); + commands + .entity(*entity) + .remove::() + .remove::() + .remove::() + .remove::() + .remove::() + // this makes it close the tcp connection + .remove::() + // swarm detects when this tx gets dropped to fire SwarmEvent::Disconnect + .remove::(); + // note that we don't remove the client from the ECS, so if they decide + // to reconnect they'll keep their state + + // now we have to remove ourselves from the LoadedBy for every entity. + // in theory this could be inefficient if we have massive swarms... but in + // practice this is fine. + for mut loaded_by in &mut loaded_by_query.iter_mut() { + loaded_by.remove(entity); + } + } +} + +#[derive(Component, Clone, Copy, Debug, Deref)] +pub struct IsConnectionAlive(bool); + +fn update_read_packets_task_running_component( + query: Query<(Entity, &RawConnection)>, + mut commands: Commands, +) { + for (entity, raw_connection) in &query { + let running = raw_connection.is_alive(); + commands.entity(entity).insert(IsConnectionAlive(running)); + } +} + +#[allow(clippy::type_complexity)] +fn disconnect_on_connection_dead( + query: Query<(Entity, &IsConnectionAlive), (Changed, With)>, + mut disconnect_events: EventWriter, +) { + for (entity, &is_connection_alive) in &query { + if !*is_connection_alive { + disconnect_events.send(DisconnectEvent { + entity, + reason: None, + }); + } + } +} -- cgit v1.2.3