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);
20
21pub struct AutoReconnectPlugin;
28impl Plugin for AutoReconnectPlugin {
29 fn build(&self, app: &mut App) {
30 app.insert_resource(AutoReconnectDelay::new(DEFAULT_RECONNECT_DELAY))
31 .add_systems(
32 Update,
33 (start_rejoin_on_disconnect, rejoin_after_delay)
34 .chain()
35 .before(super::join::handle_start_join_server_event),
36 );
37 }
38}
39
40pub fn start_rejoin_on_disconnect(
41 mut commands: Commands,
42 mut disconnect_events: EventReader<DisconnectEvent>,
43 mut connection_failed_events: EventReader<ConnectionFailedEvent>,
44 auto_reconnect_delay_res: Option<Res<AutoReconnectDelay>>,
45 auto_reconnect_delay_query: Query<&AutoReconnectDelay>,
46) {
47 for entity in disconnect_events
48 .read()
49 .map(|e| e.entity)
50 .chain(connection_failed_events.read().map(|e| e.entity))
51 {
52 let Some(delay) = get_delay(
53 &auto_reconnect_delay_res,
54 auto_reconnect_delay_query,
55 entity,
56 ) else {
57 continue;
59 };
60
61 let reconnect_after = Instant::now() + delay;
62 commands.entity(entity).insert(InternalReconnectAfter {
63 instant: reconnect_after,
64 });
65 }
66}
67
68fn get_delay(
69 auto_reconnect_delay_res: &Option<Res<AutoReconnectDelay>>,
70 auto_reconnect_delay_query: Query<&AutoReconnectDelay>,
71 entity: Entity,
72) -> Option<Duration> {
73 let delay = if let Ok(c) = auto_reconnect_delay_query.get(entity) {
74 Some(c.delay)
75 } else {
76 auto_reconnect_delay_res.as_ref().map(|r| r.delay)
77 };
78
79 if delay == Some(Duration::MAX) {
80 return None;
82 }
83 delay
84}
85
86pub fn rejoin_after_delay(
87 mut commands: Commands,
88 mut join_events: EventWriter<StartJoinServerEvent>,
89 query: Query<(
90 Entity,
91 &InternalReconnectAfter,
92 &Account,
93 &ConnectOpts,
94 Option<&LocalPlayerEvents>,
95 )>,
96) {
97 for (entity, reconnect_after, account, connect_opts, local_player_events) in query.iter() {
98 if Instant::now() >= reconnect_after.instant {
99 commands.entity(entity).remove::<InternalReconnectAfter>();
101
102 join_events.write(StartJoinServerEvent {
104 account: account.clone(),
105 connect_opts: connect_opts.clone(),
106 event_sender: local_player_events.map(|e| e.0.clone()),
110 start_join_callback_tx: None,
111 });
112 }
113 }
114}
115
116#[derive(Resource, Component, Debug, Clone)]
127pub struct AutoReconnectDelay {
128 pub delay: Duration,
129}
130impl AutoReconnectDelay {
131 pub fn new(delay: Duration) -> Self {
132 Self { delay }
133 }
134}
135
136#[derive(Component, Debug, Clone)]
140pub struct InternalReconnectAfter {
141 pub instant: Instant,
142}