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}