aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/plugins/events.rs
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-12-28 14:31:41 +0500
committermat <git@matdoes.dev>2025-12-28 14:31:41 +0500
commit7ab3b8924f64f7eadb6b8928b6fae73cb06e4c2f (patch)
tree5add5d27fd7c2638ebe6fab9bd7adcdae28a358d /azalea-client/src/plugins/events.rs
parent9513f42e87f64c409cdb2a100500a50e5a713bac (diff)
downloadazalea-drasl-7ab3b8924f64f7eadb6b8928b6fae73cb06e4c2f.tar.xz
move Event and auto_reconnect to the azalea crate
Diffstat (limited to 'azalea-client/src/plugins/events.rs')
-rw-r--r--azalea-client/src/plugins/events.rs317
1 files changed, 0 insertions, 317 deletions
diff --git a/azalea-client/src/plugins/events.rs b/azalea-client/src/plugins/events.rs
deleted file mode 100644
index bd0419cb..00000000
--- a/azalea-client/src/plugins/events.rs
+++ /dev/null
@@ -1,317 +0,0 @@
-//! Defines the [`enum@Event`] enum and makes those events trigger when they're
-//! sent in the ECS.
-
-use std::sync::Arc;
-
-use azalea_chat::FormattedText;
-use azalea_core::{position::ChunkPos, tick::GameTick};
-use azalea_entity::{Dead, InLoadedChunk};
-use azalea_protocol::packets::game::c_player_combat_kill::ClientboundPlayerCombatKill;
-use azalea_world::{InstanceName, MinecraftEntityId};
-use bevy_app::{App, Plugin, PreUpdate, Update};
-use bevy_ecs::prelude::*;
-use derive_more::{Deref, DerefMut};
-use tokio::sync::mpsc;
-
-use crate::{
- chat::{ChatPacket, ChatReceivedEvent},
- chunks::ReceiveChunkEvent,
- disconnect::DisconnectEvent,
- packet::game::{
- AddPlayerEvent, DeathEvent, KeepAliveEvent, RemovePlayerEvent, UpdatePlayerEvent,
- },
- player::PlayerInfo,
-};
-
-// (for contributors):
-// HOW TO ADD A NEW (packet based) EVENT:
-// - Add it as an ECS event first:
-// - Make a struct that contains an entity field and some data fields (look
-// in packet/game/events.rs for examples. These structs should always have
-// their names end with "Event".
-// - (the `entity` field is the local player entity that's receiving the
-// event)
-// - In the GamePacketHandler, you always have a `player` field that you can
-// use.
-// - Add the event struct in PacketPlugin::build
-// - (in the `impl Plugin for PacketPlugin`)
-// - To get the event writer, you have to get an MessageWriter<ThingEvent>.
-// Look at other packets in packet/game/mod.rs for examples.
-//
-// At this point, you've created a new ECS event. That's annoying for bots to
-// use though, so you might wanna add it to the Event enum too:
-// - In this file, add a new variant to that Event enum with the same name
-// as your event (without the "Event" suffix).
-// - Create a new system function like the other ones here, and put that
-// system function in the `impl Plugin for EventsPlugin`
-
-/// Something that happened in-game, such as a tick passing or chat message
-/// being sent.
-///
-/// Note: Events are sent before they're processed, so for example game ticks
-/// happen at the beginning of a tick before anything has happened.
-#[derive(Clone, Debug)]
-#[non_exhaustive]
-pub enum Event {
- /// Happens right after the bot switches into the Game state, but before
- /// it's actually spawned.
- ///
- /// This can be useful for setting the client information with
- /// [`Client::set_client_information`], so the packet doesn't have to be
- /// sent twice.
- ///
- /// You may want to use [`Event::Spawn`] instead to wait for the bot to be
- /// in the world.
- ///
- /// [`Client::set_client_information`]: crate::Client::set_client_information
- Init,
- /// Fired when we receive a login packet, which is after [`Event::Init`] but
- /// before [`Event::Spawn`]. You usually want [`Event::Spawn`] instead.
- ///
- /// Your position may be [`Vec3::ZERO`] immediately after you receive this
- /// event, but it'll be ready by the time you get [`Event::Spawn`].
- ///
- /// It's possible for this event to be sent multiple times per client if a
- /// server sends multiple login packets (like when switching worlds).
- ///
- /// [`Vec3::ZERO`]: azalea_core::position::Vec3::ZERO
- Login,
- /// Fired when the player fully spawns into the world (is in a loaded chunk)
- /// and is ready to interact with it.
- ///
- /// This is usually the event you should listen for when waiting for the bot
- /// to be ready.
- ///
- /// This event will be sent every time the client respawns or switches
- /// worlds, as long as the server sends chunks to the client.
- Spawn,
- /// A chat message was sent in the game chat.
- Chat(ChatPacket),
- /// Happens 20 times per second, but only when the world is loaded.
- Tick,
- #[cfg(feature = "packet-event")]
- /// We received a packet from the server.
- ///
- /// ```
- /// # use azalea_client::Event;
- /// # use azalea_protocol::packets::game::ClientboundGamePacket;
- /// # async fn example(event: Event) {
- /// # match event {
- /// Event::Packet(packet) => match &*packet {
- /// ClientboundGamePacket::Login(_) => {
- /// println!("login packet");
- /// }
- /// _ => {}
- /// },
- /// # _ => {}
- /// # }
- /// # }
- /// ```
- Packet(Arc<azalea_protocol::packets::game::ClientboundGamePacket>),
- /// A player joined the game (or more specifically, was added to the tab
- /// list).
- AddPlayer(PlayerInfo),
- /// A player left the game (or maybe is still in the game and was just
- /// removed from the tab list).
- RemovePlayer(PlayerInfo),
- /// A player was updated in the tab list (gamemode, display
- /// name, or latency changed).
- UpdatePlayer(PlayerInfo),
- /// The client player died in-game.
- Death(Option<Arc<ClientboundPlayerCombatKill>>),
- /// A `KeepAlive` packet was sent by the server.
- KeepAlive(u64),
- /// The client disconnected from the server.
- Disconnect(Option<FormattedText>),
- ReceiveChunk(ChunkPos),
-}
-
-/// A component that contains an event sender for events that are only
-/// received by local players.
-///
-/// The receiver for this is returned by [`Client::start_client`].
-///
-/// [`Client::start_client`]: crate::Client::start_client
-#[derive(Component, Deref, DerefMut)]
-pub struct LocalPlayerEvents(pub mpsc::UnboundedSender<Event>);
-
-pub struct EventsPlugin;
-impl Plugin for EventsPlugin {
- fn build(&self, app: &mut App) {
- app.add_systems(
- Update,
- (
- chat_listener,
- login_listener,
- spawn_listener,
- #[cfg(feature = "packet-event")]
- packet_listener,
- add_player_listener,
- update_player_listener,
- remove_player_listener,
- keepalive_listener,
- death_listener,
- disconnect_listener,
- receive_chunk_listener,
- ),
- )
- .add_systems(
- PreUpdate,
- init_listener.before(super::connection::read_packets),
- )
- .add_systems(GameTick, tick_listener);
- }
-}
-
-// when LocalPlayerEvents is added, it means the client just started
-pub fn init_listener(query: Query<&LocalPlayerEvents, Added<LocalPlayerEvents>>) {
- for local_player_events in &query {
- let _ = local_player_events.send(Event::Init);
- }
-}
-
-// when MinecraftEntityId is added, it means the player is now in the world
-pub fn login_listener(
- query: Query<(Entity, &LocalPlayerEvents), Added<MinecraftEntityId>>,
- mut commands: Commands,
-) {
- for (entity, local_player_events) in &query {
- let _ = local_player_events.send(Event::Login);
- commands.entity(entity).remove::<SentSpawnEvent>();
- }
-}
-
-/// A unit struct component that indicates that the entity has sent
-/// [`Event::Spawn`].
-///
-/// This is just used internally by the [`spawn_listener`] system to avoid
-/// sending the event twice if we stop being in an unloaded chunk. It's removed
-/// when we receive a login packet.
-#[derive(Component)]
-pub struct SentSpawnEvent;
-#[allow(clippy::type_complexity)]
-pub fn spawn_listener(
- query: Query<(Entity, &LocalPlayerEvents), (Added<InLoadedChunk>, Without<SentSpawnEvent>)>,
- mut commands: Commands,
-) {
- for (entity, local_player_events) in &query {
- let _ = local_player_events.send(Event::Spawn);
- commands.entity(entity).insert(SentSpawnEvent);
- }
-}
-
-pub fn chat_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<ChatReceivedEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::Chat(event.packet.clone()));
- }
- }
-}
-
-// only tick if we're in a world
-pub fn tick_listener(query: Query<&LocalPlayerEvents, With<InstanceName>>) {
- for local_player_events in &query {
- let _ = local_player_events.send(Event::Tick);
- }
-}
-
-#[cfg(feature = "packet-event")]
-pub fn packet_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<super::packet::game::ReceiveGamePacketEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::Packet(event.packet.clone()));
- }
- }
-}
-
-pub fn add_player_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<AddPlayerEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::AddPlayer(event.info.clone()));
- }
- }
-}
-
-pub fn update_player_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<UpdatePlayerEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::UpdatePlayer(event.info.clone()));
- }
- }
-}
-
-pub fn remove_player_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<RemovePlayerEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::RemovePlayer(event.info.clone()));
- }
- }
-}
-
-pub fn death_listener(query: Query<&LocalPlayerEvents>, mut events: MessageReader<DeathEvent>) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::Death(event.packet.clone().map(|p| p.into())));
- }
- }
-}
-
-/// Send the "Death" event for [`LocalEntity`]s that died with no reason.
-///
-/// [`LocalEntity`]: azalea_entity::LocalEntity
-pub fn dead_component_listener(query: Query<&LocalPlayerEvents, Added<Dead>>) {
- for local_player_events in &query {
- local_player_events.send(Event::Death(None)).unwrap();
- }
-}
-
-pub fn keepalive_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<KeepAliveEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::KeepAlive(event.id));
- }
- }
-}
-
-pub fn disconnect_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<DisconnectEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::Disconnect(event.reason.clone()));
- }
- }
-}
-
-pub fn receive_chunk_listener(
- query: Query<&LocalPlayerEvents>,
- mut events: MessageReader<ReceiveChunkEvent>,
-) {
- for event in events.read() {
- if let Ok(local_player_events) = query.get(event.entity) {
- let _ = local_player_events.send(Event::ReceiveChunk(ChunkPos::new(
- event.packet.x,
- event.packet.z,
- )));
- }
- }
-}