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 if let Some(r) = &auto_reconnect_delay_res {
76 Some(r.delay)
77 } else {
78 None
79 }
80}
81
82pub fn rejoin_after_delay(
83 mut commands: Commands,
84 mut join_events: EventWriter<StartJoinServerEvent>,
85 query: Query<(
86 Entity,
87 &InternalReconnectAfter,
88 &Account,
89 &ConnectOpts,
90 Option<&LocalPlayerEvents>,
91 )>,
92) {
93 for (entity, reconnect_after, account, connect_opts, local_player_events) in query.iter() {
94 if Instant::now() >= reconnect_after.instant {
95 commands.entity(entity).remove::<InternalReconnectAfter>();
97
98 join_events.write(StartJoinServerEvent {
100 account: account.clone(),
101 connect_opts: connect_opts.clone(),
102 event_sender: local_player_events.map(|e| e.0.clone()),
106 start_join_callback_tx: None,
107 });
108 }
109 }
110}
111
112#[derive(Resource, Component, Debug, Clone)]
123pub struct AutoReconnectDelay {
124 pub delay: Duration,
125}
126impl AutoReconnectDelay {
127 pub fn new(delay: Duration) -> Self {
128 Self { delay }
129 }
130}
131
132#[derive(Component, Debug, Clone)]
136pub struct InternalReconnectAfter {
137 pub instant: Instant,
138}