diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-02-22 21:45:26 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-22 21:45:26 -0600 |
| commit | e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7 (patch) | |
| tree | add6f8bfce40d0c07845d8aa4c9945a0b918444c /azalea-client/src/plugins/disconnect.rs | |
| parent | f8130c3c92946d2293634ba4e252d6bc93026c3c (diff) | |
| download | azalea-drasl-e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7.tar.xz | |
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
Diffstat (limited to 'azalea-client/src/plugins/disconnect.rs')
| -rw-r--r-- | azalea-client/src/plugins/disconnect.rs | 103 |
1 files changed, 103 insertions, 0 deletions
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::<DisconnectEvent>().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<FormattedText>, +} + +/// 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<DisconnectEvent>, + mut loaded_by_query: Query<&mut azalea_entity::LoadedBy>, +) { + for DisconnectEvent { entity, .. } in events.read() { + trace!("Got DisconnectEvent for {entity:?}"); + commands + .entity(*entity) + .remove::<JoinedClientBundle>() + .remove::<EntityBundle>() + .remove::<InstanceHolder>() + .remove::<PlayerMetadataBundle>() + .remove::<InLoadedChunk>() + // this makes it close the tcp connection + .remove::<RawConnection>() + // swarm detects when this tx gets dropped to fire SwarmEvent::Disconnect + .remove::<LocalPlayerEvents>(); + // 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<IsConnectionAlive>, With<LocalEntity>)>, + mut disconnect_events: EventWriter<DisconnectEvent>, +) { + for (entity, &is_connection_alive) in &query { + if !*is_connection_alive { + disconnect_events.send(DisconnectEvent { + entity, + reason: None, + }); + } + } +} |
