azalea/tick_broadcast.rs
1use azalea_core::tick::GameTick;
2use bevy_app::prelude::*;
3use bevy_ecs::prelude::*;
4use derive_more::Deref;
5use tokio::sync::broadcast;
6
7use crate::Client;
8
9/// A plugin that makes the [`UpdateBroadcast`] and [`TickBroadcast`] resources
10/// available.
11pub struct TickBroadcastPlugin;
12impl Plugin for TickBroadcastPlugin {
13 fn build(&self, app: &mut App) {
14 app.insert_resource(TickBroadcast(broadcast::channel(1).0))
15 .insert_resource(UpdateBroadcast(broadcast::channel(1).0))
16 .add_systems(
17 GameTick,
18 send_tick_broadcast.after(azalea_client::tick_counter::increment_counter),
19 )
20 .add_systems(Update, send_update_broadcast);
21 }
22}
23
24/// A resource that contains a [`broadcast::Sender`] that will be sent every
25/// Minecraft tick (see [`GameTick`]).
26///
27/// Also see [`Client::wait_ticks`] and [`Client::get_tick_broadcaster`].
28///
29/// ```
30/// use azalea::tick_broadcast::TickBroadcast;
31/// async fn example(tick_broadcast: &TickBroadcast) {
32/// let mut receiver = tick_broadcast.subscribe();
33///
34/// while receiver.recv().await.is_ok() {
35/// // do something
36/// }
37/// }
38/// ```
39#[derive(Deref, Resource)]
40pub struct TickBroadcast(broadcast::Sender<()>);
41
42/// A resource that contains a [`broadcast::Sender`] that will be sent every
43/// Azalea ECS `Update`.
44///
45/// Also see [`TickBroadcast`].
46#[derive(Deref, Resource)]
47pub struct UpdateBroadcast(broadcast::Sender<()>);
48
49pub fn send_tick_broadcast(tick_broadcast: ResMut<TickBroadcast>) {
50 let _ = tick_broadcast.0.send(());
51}
52pub fn send_update_broadcast(update_broadcast: ResMut<UpdateBroadcast>) {
53 let _ = update_broadcast.0.send(());
54}
55
56impl Client {
57 /// Returns a Receiver that receives a message every game tick.
58 ///
59 /// This is useful if you want to efficiently loop until a certain condition
60 /// is met.
61 ///
62 /// ```
63 /// # use azalea::prelude::*;
64 /// # use azalea::container::WaitingForInventoryOpen;
65 /// # async fn example(bot: &mut azalea::Client) {
66 /// let mut ticks = bot.get_tick_broadcaster();
67 /// while ticks.recv().await.is_ok() {
68 /// let ecs = bot.ecs.read();
69 /// if ecs.get::<WaitingForInventoryOpen>(bot.entity).is_none() {
70 /// break;
71 /// }
72 /// }
73 /// # }
74 /// ```
75 pub fn get_tick_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()> {
76 let ecs = self.ecs.read();
77 let tick_broadcast = ecs.resource::<TickBroadcast>();
78 tick_broadcast.subscribe()
79 }
80
81 /// Returns a Receiver that receives a message every ECS Update.
82 ///
83 /// ECS Updates happen at least at the frequency of game ticks, usually
84 /// faster.
85 ///
86 /// This is useful if you're sending an ECS event and want to make sure it's
87 /// been handled before continuing.
88 pub fn get_update_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()> {
89 let ecs = self.ecs.read();
90 let update_broadcast = ecs.resource::<UpdateBroadcast>();
91 update_broadcast.subscribe()
92 }
93}