azalea_client/plugins/
auto_reconnect.rs1use std::time::{Duration, Instant};
6
7use bevy_app::prelude::*;
8use bevy_ecs::prelude::*;
9
10use super::{
11 disconnect::DisconnectEvent,
12 events::LocalPlayerEvents,
13 join::{ConnectOpts, ConnectionFailedEvent, StartJoinServerEvent},
14};
15use crate::Account;
16
17pub const DEFAULT_RECONNECT_DELAY: Duration = Duration::from_secs(5);
21
22pub struct AutoReconnectPlugin;
31impl Plugin for AutoReconnectPlugin {
32 fn build(&self, app: &mut App) {
33 app.insert_resource(AutoReconnectDelay::new(DEFAULT_RECONNECT_DELAY))
34 .add_systems(
35 Update,
36 (start_rejoin_on_disconnect, rejoin_after_delay)
37 .chain()
38 .before(super::join::handle_start_join_server_event),
39 );
40 }
41}
42
43pub fn start_rejoin_on_disconnect(
44 mut commands: Commands,
45 mut disconnect_events: MessageReader<DisconnectEvent>,
46 mut connection_failed_events: MessageReader<ConnectionFailedEvent>,
47 auto_reconnect_delay_res: Option<Res<AutoReconnectDelay>>,
48 auto_reconnect_delay_query: Query<&AutoReconnectDelay>,
49) {
50 for entity in disconnect_events
51 .read()
52 .map(|e| e.entity)
53 .chain(connection_failed_events.read().map(|e| e.entity))
54 {
55 let Some(delay) = get_delay(
56 &auto_reconnect_delay_res,
57 auto_reconnect_delay_query,
58 entity,
59 ) else {
60 continue;
62 };
63
64 let reconnect_after = Instant::now() + delay;
65 commands.entity(entity).insert(InternalReconnectAfter {
66 instant: reconnect_after,
67 });
68 }
69}
70
71fn get_delay(
72 auto_reconnect_delay_res: &Option<Res<AutoReconnectDelay>>,
73 auto_reconnect_delay_query: Query<&AutoReconnectDelay>,
74 entity: Entity,
75) -> Option<Duration> {
76 let delay = if let Ok(c) = auto_reconnect_delay_query.get(entity) {
77 Some(c.delay)
78 } else {
79 auto_reconnect_delay_res.as_ref().map(|r| r.delay)
80 };
81
82 if delay == Some(Duration::MAX) {
83 return None;
85 }
86 delay
87}
88
89pub fn rejoin_after_delay(
90 mut commands: Commands,
91 mut join_events: MessageWriter<StartJoinServerEvent>,
92 query: Query<(
93 Entity,
94 &InternalReconnectAfter,
95 &Account,
96 &ConnectOpts,
97 Option<&LocalPlayerEvents>,
98 )>,
99) {
100 for (entity, reconnect_after, account, connect_opts, local_player_events) in query.iter() {
101 if Instant::now() >= reconnect_after.instant {
102 commands.entity(entity).remove::<InternalReconnectAfter>();
104
105 join_events.write(StartJoinServerEvent {
107 account: account.clone(),
108 connect_opts: connect_opts.clone(),
109 event_sender: local_player_events.map(|e| e.0.clone()),
113 start_join_callback_tx: None,
114 });
115 }
116 }
117}
118
119#[derive(Resource, Component, Debug, Clone)]
130pub struct AutoReconnectDelay {
131 pub delay: Duration,
132}
133impl AutoReconnectDelay {
134 pub fn new(delay: Duration) -> Self {
135 Self { delay }
136 }
137}
138
139#[derive(Component, Debug, Clone)]
143pub struct InternalReconnectAfter {
144 pub instant: Instant,
145}