azalea_client/plugins/packet/
mod.rs

1use azalea_entity::metadata::Health;
2use bevy_app::{App, First, Plugin, PreUpdate, Update};
3use bevy_ecs::{
4    prelude::*,
5    system::{SystemParam, SystemState},
6};
7
8use self::{
9    game::{
10        AddPlayerEvent, DeathEvent, InstanceLoadedEvent, KeepAliveEvent, RemovePlayerEvent,
11        ResourcePackEvent, UpdatePlayerEvent,
12    },
13    login::{LoginPacketEvent, SendLoginPacketEvent},
14};
15use crate::{chat::ChatReceivedEvent, events::death_listener};
16
17pub mod config;
18pub mod game;
19pub mod login;
20
21pub struct PacketPlugin;
22
23pub fn death_event_on_0_health(
24    query: Query<(Entity, &Health), Changed<Health>>,
25    mut death_events: EventWriter<DeathEvent>,
26) {
27    for (entity, health) in query.iter() {
28        if **health == 0. {
29            death_events.send(DeathEvent {
30                entity,
31                packet: None,
32            });
33        }
34    }
35}
36
37impl Plugin for PacketPlugin {
38    fn build(&self, app: &mut App) {
39        app.add_systems(
40            First,
41            (
42                game::emit_receive_packet_events,
43                config::emit_receive_config_packet_events,
44            ),
45        )
46        .add_systems(
47            PreUpdate,
48            (
49                game::process_packet_events,
50                config::process_packet_events,
51                login::handle_send_packet_event,
52                login::process_packet_events,
53            ),
54        )
55        .add_observer(game::handle_outgoing_packets_observer)
56        .add_observer(config::handle_outgoing_packets_observer)
57        .add_systems(
58            Update,
59            (
60                (
61                    config::handle_outgoing_packets,
62                    game::handle_outgoing_packets,
63                )
64                    .chain(),
65                death_event_on_0_health.before(death_listener),
66            ),
67        )
68        // we do this instead of add_event so we can handle the events ourselves
69        .init_resource::<Events<game::ReceivePacketEvent>>()
70        .init_resource::<Events<config::ReceiveConfigPacketEvent>>()
71        .add_event::<game::SendPacketEvent>()
72        .add_event::<config::SendConfigPacketEvent>()
73        .add_event::<AddPlayerEvent>()
74        .add_event::<RemovePlayerEvent>()
75        .add_event::<UpdatePlayerEvent>()
76        .add_event::<ChatReceivedEvent>()
77        .add_event::<DeathEvent>()
78        .add_event::<KeepAliveEvent>()
79        .add_event::<ResourcePackEvent>()
80        .add_event::<InstanceLoadedEvent>()
81        .add_event::<LoginPacketEvent>()
82        .add_event::<SendLoginPacketEvent>();
83    }
84}
85
86#[macro_export]
87macro_rules! declare_packet_handlers {
88    (
89        $packetenum:ident,
90        $packetvar:expr,
91        $handler:ident,
92        [$($packet:path),+ $(,)?]
93    ) => {
94        paste::paste! {
95           match $packetvar {
96                $(
97                    $packetenum::[< $packet:camel >](p) => $handler.$packet(p),
98                )+
99            }
100        }
101    };
102}
103
104pub(crate) fn as_system<T>(ecs: &mut World, f: impl FnOnce(T::Item<'_, '_>))
105where
106    T: SystemParam + 'static,
107{
108    let mut system_state = SystemState::<T>::new(ecs);
109    let values = system_state.get_mut(ecs);
110    f(values);
111    system_state.apply(ecs);
112}