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 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
80pub fn rejoin_after_delay(
81 mut commands: Commands,
82 mut join_events: EventWriter<StartJoinServerEvent>,
83 query: Query<(
84 Entity,
85 &InternalReconnectAfter,
86 &Account,
87 &ConnectOpts,
88 Option<&LocalPlayerEvents>,
89 )>,
90) {
91 for (entity, reconnect_after, account, connect_opts, local_player_events) in query.iter() {
92 if Instant::now() >= reconnect_after.instant {
93 commands.entity(entity).remove::<InternalReconnectAfter>();
95
96 join_events.write(StartJoinServerEvent {
98 account: account.clone(),
99 connect_opts: connect_opts.clone(),
100 event_sender: local_player_events.map(|e| e.0.clone()),
104 start_join_callback_tx: None,
105 });
106 }
107 }
108}
109
110#[derive(Resource, Component, Debug, Clone)]
121pub struct AutoReconnectDelay {
122 pub delay: Duration,
123}
124impl AutoReconnectDelay {
125 pub fn new(delay: Duration) -> Self {
126 Self { delay }
127 }
128}
129
130#[derive(Component, Debug, Clone)]
134pub struct InternalReconnectAfter {
135 pub instant: Instant,
136}