azalea_client/
disconnect.rs1use azalea_chat::FormattedText;
4use azalea_entity::LocalEntity;
5use bevy_app::{App, Plugin, PostUpdate};
6use bevy_ecs::{
7 component::Component,
8 entity::Entity,
9 event::{EventReader, EventWriter},
10 prelude::Event,
11 query::{Changed, With},
12 schedule::IntoSystemConfigs,
13 system::{Commands, Query},
14};
15use derive_more::Deref;
16use tracing::trace;
17
18use crate::{client::JoinedClientBundle, events::LocalPlayerEvents, raw_connection::RawConnection};
19
20pub struct DisconnectPlugin;
21impl Plugin for DisconnectPlugin {
22 fn build(&self, app: &mut App) {
23 app.add_event::<DisconnectEvent>().add_systems(
24 PostUpdate,
25 (
26 update_read_packets_task_running_component,
27 disconnect_on_connection_dead,
28 remove_components_from_disconnected_players,
29 )
30 .chain(),
31 );
32 }
33}
34
35#[derive(Event)]
37pub struct DisconnectEvent {
38 pub entity: Entity,
39 pub reason: Option<FormattedText>,
40}
41
42pub fn remove_components_from_disconnected_players(
45 mut commands: Commands,
46 mut events: EventReader<DisconnectEvent>,
47) {
48 for DisconnectEvent { entity, .. } in events.read() {
49 trace!("Got DisconnectEvent for {entity:?}");
50 commands
51 .entity(*entity)
52 .remove::<JoinedClientBundle>()
53 .remove::<RawConnection>()
55 .remove::<LocalPlayerEvents>();
57 }
60}
61
62#[derive(Component, Clone, Copy, Debug, Deref)]
63pub struct IsConnectionAlive(bool);
64
65fn update_read_packets_task_running_component(
66 query: Query<(Entity, &RawConnection)>,
67 mut commands: Commands,
68) {
69 for (entity, raw_connection) in &query {
70 let running = raw_connection.is_alive();
71 commands.entity(entity).insert(IsConnectionAlive(running));
72 }
73}
74
75#[allow(clippy::type_complexity)]
76fn disconnect_on_connection_dead(
77 query: Query<(Entity, &IsConnectionAlive), (Changed<IsConnectionAlive>, With<LocalEntity>)>,
78 mut disconnect_events: EventWriter<DisconnectEvent>,
79) {
80 for (entity, &is_connection_alive) in &query {
81 if !*is_connection_alive {
82 disconnect_events.send(DisconnectEvent {
83 entity,
84 reason: None,
85 });
86 }
87 }
88}