1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 23:44:38 +00:00

organize az-client file structure by moving things into plugins directory

This commit is contained in:
mat 2025-02-17 02:45:22 +00:00
commit 9d0fcc671b
25 changed files with 162 additions and 157 deletions

View file

@ -62,28 +62,27 @@ use uuid::Uuid;
use crate::{
attack::{self, AttackPlugin},
brand::BrandPlugin,
chat::ChatPlugin,
chunks::{ChunkBatchInfo, ChunkPlugin},
configuration::ConfigurationPlugin,
chunks::{ChunkBatchInfo, ChunksPlugin},
disconnect::{DisconnectEvent, DisconnectPlugin},
events::{Event, EventPlugin, LocalPlayerEvents},
events::{Event, EventsPlugin, LocalPlayerEvents},
interact::{CurrentSequenceNumber, InteractPlugin},
inventory::{Inventory, InventoryPlugin},
local_player::{
death_event, GameProfileComponent, Hunger, InstanceHolder, PermissionLevel,
PlayerAbilities, TabList,
GameProfileComponent, Hunger, InstanceHolder, PermissionLevel, PlayerAbilities, TabList,
},
mining::{self, MinePlugin},
movement::{LastSentLookDirection, PhysicsState, PlayerMovePlugin},
mining::{self, MiningPlugin},
movement::{LastSentLookDirection, MovementPlugin, PhysicsState},
packet::{
login::{self, LoginSendPacketQueue},
PacketHandlerPlugin,
PacketPlugin,
},
player::retroactively_add_game_profile_component,
raw_connection::RawConnection,
respawn::RespawnPlugin,
send_client_end::TickEndPlugin,
task_pool::TaskPoolPlugin,
tick_end::TickEndPlugin,
Account, PlayerInfo,
};
@ -818,8 +817,6 @@ impl Plugin for AzaleaPlugin {
app.add_systems(
Update,
(
// fire the Death event when the player dies.
death_event,
// add GameProfileComponent when we get an AddPlayerEvent
retroactively_add_game_profile_component.after(EntityUpdateSet::Index),
),
@ -965,23 +962,23 @@ impl PluginGroup for DefaultPlugins {
let mut group = PluginGroupBuilder::start::<Self>()
.add(AmbiguityLoggerPlugin)
.add(TimePlugin)
.add(PacketHandlerPlugin)
.add(PacketPlugin)
.add(AzaleaPlugin)
.add(EntityPlugin)
.add(PhysicsPlugin)
.add(EventPlugin)
.add(EventsPlugin)
.add(TaskPoolPlugin::default())
.add(InventoryPlugin)
.add(ChatPlugin)
.add(DisconnectPlugin)
.add(PlayerMovePlugin)
.add(MovementPlugin)
.add(InteractPlugin)
.add(RespawnPlugin)
.add(MinePlugin)
.add(MiningPlugin)
.add(AttackPlugin)
.add(ChunkPlugin)
.add(ChunksPlugin)
.add(TickEndPlugin)
.add(ConfigurationPlugin)
.add(BrandPlugin)
.add(TickBroadcastPlugin);
#[cfg(feature = "log")]
{

View file

@ -8,26 +8,13 @@
#![feature(error_generic_member_access)]
mod account;
pub mod attack;
pub mod chat;
pub mod chunks;
mod client;
pub mod configuration;
pub mod disconnect;
mod entity_query;
pub mod events;
pub mod interact;
pub mod inventory;
mod local_player;
pub mod mining;
pub mod movement;
pub mod packet;
pub mod ping;
mod player;
mod plugins;
pub mod raw_connection;
pub mod respawn;
pub mod send_client_end;
pub mod task_pool;
pub use account::{Account, AccountOpts};
pub use azalea_protocol::common::client_information::ClientInformation;
@ -41,3 +28,4 @@ pub use movement::{
PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
};
pub use player::PlayerInfo;
pub use plugins::*;

View file

@ -2,7 +2,6 @@ use std::{collections::HashMap, io, sync::Arc};
use azalea_auth::game_profile::GameProfile;
use azalea_core::game_type::GameMode;
use azalea_entity::Dead;
use azalea_protocol::packets::game::c_player_abilities::ClientboundPlayerAbilities;
use azalea_world::{Instance, PartialInstance};
use bevy_ecs::{component::Component, prelude::*};
@ -13,10 +12,8 @@ use tokio::sync::mpsc;
use tracing::error;
use uuid::Uuid;
use crate::{
events::{Event as AzaleaEvent, LocalPlayerEvents},
ClientInformation, PlayerInfo,
};
use crate::Event as AzaleaEvent;
use crate::{ClientInformation, PlayerInfo};
/// A component that keeps strong references to our [`PartialInstance`] and
/// [`Instance`] for local players.
@ -143,13 +140,6 @@ impl InstanceHolder {
}
}
/// Send the "Death" event for [`LocalEntity`]s that died with no reason.
pub fn death_event(query: Query<&LocalPlayerEvents, Added<Dead>>) {
for local_player_events in &query {
local_player_events.send(AzaleaEvent::Death(None)).unwrap();
}
}
#[derive(Error, Debug)]
pub enum HandlePacketError {
#[error("{0}")]

View file

@ -12,8 +12,8 @@ use bevy_ecs::prelude::*;
use crate::{client::InConfigState, packet::config::SendConfigPacketEvent};
pub struct ConfigurationPlugin;
impl Plugin for ConfigurationPlugin {
pub struct BrandPlugin;
impl Plugin for BrandPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,
@ -22,13 +22,14 @@ impl Plugin for ConfigurationPlugin {
}
}
fn handle_in_configuration_state(
pub fn handle_in_configuration_state(
query: Query<(Entity, &ClientInformation), Added<InConfigState>>,
mut send_packet_events: EventWriter<SendConfigPacketEvent>,
) {
for (entity, client_information) in query.iter() {
let mut brand_data = Vec::new();
// they don't have to know :)
// azalea pretends to be vanilla everywhere else so it makes sense to lie here
// too
"vanilla".azalea_write(&mut brand_data).unwrap();
send_packet_events.send(SendConfigPacketEvent::new(
entity,

View file

@ -0,0 +1,61 @@
use std::time::{SystemTime, UNIX_EPOCH};
use azalea_protocol::packets::{
game::{s_chat::LastSeenMessagesUpdate, ServerboundChat, ServerboundChatCommand},
Packet,
};
use bevy_ecs::prelude::*;
use super::ChatKind;
use crate::packet::game::SendPacketEvent;
/// Send a chat packet to the server of a specific kind (chat message or
/// command). Usually you just want [`SendChatEvent`] instead.
///
/// Usually setting the kind to `Message` will make it send a chat message even
/// if it starts with a slash, but some server implementations will always do a
/// command if it starts with a slash.
///
/// If you're wondering why this isn't two separate events, it's so ordering is
/// preserved if multiple chat messages and commands are sent at the same time.
#[derive(Event)]
pub struct SendChatKindEvent {
pub entity: Entity,
pub content: String,
pub kind: ChatKind,
}
pub fn handle_send_chat_kind_event(
mut events: EventReader<SendChatKindEvent>,
mut send_packet_events: EventWriter<SendPacketEvent>,
) {
for event in events.read() {
let content = event
.content
.chars()
.filter(|c| !matches!(c, '\x00'..='\x1F' | '\x7F' | '§'))
.take(256)
.collect::<String>();
let packet = match event.kind {
ChatKind::Message => ServerboundChat {
message: content,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time shouldn't be before epoch")
.as_millis()
.try_into()
.expect("Instant should fit into a u64"),
salt: azalea_crypto::make_salt(),
signature: None,
last_seen_messages: LastSeenMessagesUpdate::default(),
}
.into_variant(),
ChatKind::Command => {
// TODO: chat signing
ServerboundChatCommand { command: content }.into_variant()
}
};
send_packet_events.send(SendPacketEvent::new(event.entity, packet));
}
}

View file

@ -1,20 +1,13 @@
//! Implementations of chat-related features.
use std::{
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};
pub mod handler;
use std::sync::Arc;
use azalea_chat::FormattedText;
use azalea_protocol::packets::{
game::{
c_disguised_chat::ClientboundDisguisedChat,
c_player_chat::ClientboundPlayerChat,
c_system_chat::ClientboundSystemChat,
s_chat::{LastSeenMessagesUpdate, ServerboundChat},
s_chat_command::ServerboundChatCommand,
},
Packet,
use azalea_protocol::packets::game::{
c_disguised_chat::ClientboundDisguisedChat, c_player_chat::ClientboundPlayerChat,
c_system_chat::ClientboundSystemChat,
};
use bevy_app::{App, Plugin, Update};
use bevy_ecs::{
@ -23,12 +16,27 @@ use bevy_ecs::{
prelude::Event,
schedule::IntoSystemConfigs,
};
use handler::{handle_send_chat_kind_event, SendChatKindEvent};
use uuid::Uuid;
use crate::{
client::Client,
packet::game::{handle_sendpacketevent, SendPacketEvent},
};
use crate::{client::Client, packet::game::handle_sendpacketevent};
pub struct ChatPlugin;
impl Plugin for ChatPlugin {
fn build(&self, app: &mut App) {
app.add_event::<SendChatEvent>()
.add_event::<SendChatKindEvent>()
.add_event::<ChatReceivedEvent>()
.add_systems(
Update,
(
handle_send_chat_event,
handle_send_chat_kind_event.after(handle_sendpacketevent),
)
.chain(),
);
}
}
/// A chat packet, either a system message or a chat message.
#[derive(Debug, Clone, PartialEq)]
@ -180,23 +188,6 @@ impl Client {
}
}
pub struct ChatPlugin;
impl Plugin for ChatPlugin {
fn build(&self, app: &mut App) {
app.add_event::<SendChatEvent>()
.add_event::<SendChatKindEvent>()
.add_event::<ChatReceivedEvent>()
.add_systems(
Update,
(
handle_send_chat_event,
handle_send_chat_kind_event.after(handle_sendpacketevent),
)
.chain(),
);
}
}
/// A client received a chat message packet.
#[derive(Event, Debug, Clone)]
pub struct ChatReceivedEvent {
@ -232,63 +223,12 @@ pub fn handle_send_chat_event(
}
}
/// Send a chat packet to the server of a specific kind (chat message or
/// command). Usually you just want [`SendChatEvent`] instead.
///
/// Usually setting the kind to `Message` will make it send a chat message even
/// if it starts with a slash, but some server implementations will always do a
/// command if it starts with a slash.
///
/// If you're wondering why this isn't two separate events, it's so ordering is
/// preserved if multiple chat messages and commands are sent at the same time.
#[derive(Event)]
pub struct SendChatKindEvent {
pub entity: Entity,
pub content: String,
pub kind: ChatKind,
}
/// A kind of chat packet, either a chat message or a command.
pub enum ChatKind {
Message,
Command,
}
pub fn handle_send_chat_kind_event(
mut events: EventReader<SendChatKindEvent>,
mut send_packet_events: EventWriter<SendPacketEvent>,
) {
for event in events.read() {
let content = event
.content
.chars()
.filter(|c| !matches!(c, '\x00'..='\x1F' | '\x7F' | '§'))
.take(256)
.collect::<String>();
let packet = match event.kind {
ChatKind::Message => ServerboundChat {
message: content,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time shouldn't be before epoch")
.as_millis()
.try_into()
.expect("Instant should fit into a u64"),
salt: azalea_crypto::make_salt(),
signature: None,
last_seen_messages: LastSeenMessagesUpdate::default(),
}
.into_variant(),
ChatKind::Command => {
// TODO: chat signing
ServerboundChatCommand { command: content }.into_variant()
}
};
send_packet_events.send(SendPacketEvent::new(event.entity, packet));
}
}
// TODO
// MessageSigner, ChatMessageContent, LastSeenMessages
// fn sign_message() -> MessageSignature {

View file

@ -26,8 +26,8 @@ use crate::{
InstanceHolder,
};
pub struct ChunkPlugin;
impl Plugin for ChunkPlugin {
pub struct ChunksPlugin;
impl Plugin for ChunksPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,

View file

@ -5,6 +5,7 @@ use std::sync::Arc;
use azalea_chat::FormattedText;
use azalea_core::tick::GameTick;
use azalea_entity::Dead;
use azalea_protocol::packets::game::{
c_player_combat_kill::ClientboundPlayerCombatKill, ClientboundGamePacket,
};
@ -32,20 +33,25 @@ use crate::{
// (for contributors):
// HOW TO ADD A NEW (packet based) EVENT:
// - make a struct that contains an entity field and a data field (look in
// packet_handling.rs for examples, also you should end the struct name with
// "Event")
// - the entity field is the local player entity that's receiving the event
// - in packet_handling, you always have a variable called player_entity that
// you can use
// - add the event struct in the `impl Plugin for PacketHandlerPlugin`
// - to get the event writer, you have to get an
// EventWriter<SomethingHappenedEvent> from the SystemState (the convention is
// to end your variable with the word "events", like "something_events")
// - 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 EventWriter<ThingEvent>.
// Look at other packets in packet/game/mod.rs for examples.
//
// - then here in this file, add it to the Event enum
// - and make an event listener system/function like the other ones and put the
// function in the `impl Plugin for EventPlugin`
// 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.
@ -111,8 +117,8 @@ pub enum Event {
#[derive(Component, Deref, DerefMut)]
pub struct LocalPlayerEvents(pub mpsc::UnboundedSender<Event>);
pub struct EventPlugin;
impl Plugin for EventPlugin {
pub struct EventsPlugin;
impl Plugin for EventsPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,
@ -222,6 +228,13 @@ pub fn death_listener(query: Query<&LocalPlayerEvents>, mut events: EventReader<
}
}
/// Send the "Death" event for [`LocalEntity`]s that died with no reason.
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: EventReader<KeepAliveEvent>,

View file

@ -22,8 +22,8 @@ use crate::{
};
/// A plugin that allows clients to break blocks in the world.
pub struct MinePlugin;
impl Plugin for MinePlugin {
pub struct MiningPlugin;
impl Plugin for MiningPlugin {
fn build(&self, app: &mut App) {
app.add_event::<StartMiningBlockEvent>()
.add_event::<StartMiningBlockWithDirectionEvent>()
@ -59,6 +59,7 @@ impl Plugin for MinePlugin {
}
}
/// The Bevy system set for things related to mining.
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub struct MiningSet;

View file

@ -0,0 +1,14 @@
pub mod attack;
pub mod brand;
pub mod chat;
pub mod chunks;
pub mod disconnect;
pub mod events;
pub mod interact;
pub mod inventory;
pub mod mining;
pub mod movement;
pub mod packet;
pub mod respawn;
pub mod task_pool;
pub mod tick_end;

View file

@ -47,9 +47,9 @@ impl From<MoveEntityError> for MovePlayerError {
}
}
pub struct PlayerMovePlugin;
pub struct MovementPlugin;
impl Plugin for PlayerMovePlugin {
impl Plugin for MovementPlugin {
fn build(&self, app: &mut App) {
app.add_event::<StartWalkEvent>()
.add_event::<StartSprintEvent>()

View file

@ -18,7 +18,7 @@ pub mod config;
pub mod game;
pub mod login;
pub struct PacketHandlerPlugin;
pub struct PacketPlugin;
pub fn death_event_on_0_health(
query: Query<(Entity, &Health), Changed<Health>>,
@ -34,7 +34,7 @@ pub fn death_event_on_0_health(
}
}
impl Plugin for PacketHandlerPlugin {
impl Plugin for PacketPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
First,

View file

@ -60,13 +60,13 @@ fn create_simulation_instance(chunks: ChunkStorage) -> (App, Arc<RwLock<Instance
app.add_plugins((
azalea_physics::PhysicsPlugin,
azalea_entity::EntityPlugin,
azalea_client::movement::PlayerMovePlugin,
azalea_client::movement::MovementPlugin,
super::PathfinderPlugin,
crate::BotPlugin,
azalea_client::task_pool::TaskPoolPlugin::default(),
// for mining
azalea_client::inventory::InventoryPlugin,
azalea_client::mining::MinePlugin,
azalea_client::mining::MiningPlugin,
azalea_client::interact::InteractPlugin,
))
.insert_resource(InstanceContainer {