mirror of
https://github.com/mat-1/azalea.git
synced 2024-09-19 22:52:32 +00:00
make it so plugins can send and receive packets during the login state
This commit is contained in:
parent
0713223e12
commit
1f46ef8c11
22 changed files with 211 additions and 80 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -196,6 +196,7 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"md-5",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
@ -1637,6 +1638,16 @@ dependencies = [
|
||||||
"regex-automata 0.1.10",
|
"regex-automata 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md-5"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.6.4"
|
version = "2.6.4"
|
||||||
|
@ -2878,6 +2889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
|
"md-5",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ serde = { version = "1.0.192", features = ["derive"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
thiserror = "1.0.50"
|
thiserror = "1.0.50"
|
||||||
tokio = { version = "1.34.0", features = ["fs"] }
|
tokio = { version = "1.34.0", features = ["fs"] }
|
||||||
uuid = { version = "1.5.0", features = ["serde"] }
|
uuid = { version = "1.5.0", features = ["serde", "v3"] }
|
||||||
|
md-5 = "0.10.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.10.1"
|
env_logger = "0.10.1"
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod auth;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod certs;
|
pub mod certs;
|
||||||
pub mod game_profile;
|
pub mod game_profile;
|
||||||
|
pub mod offline;
|
||||||
pub mod sessionserver;
|
pub mod sessionserver;
|
||||||
|
|
||||||
pub use auth::*;
|
pub use auth::*;
|
||||||
|
|
17
azalea-auth/src/offline.rs
Normal file
17
azalea-auth/src/offline.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use md5::{Digest, Md5};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub fn generate_uuid(username: &str) -> Uuid {
|
||||||
|
uuid::Builder::from_md5_bytes(hash(format!("OfflinePlayer:{username}").as_bytes())).into_uuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(data: &[u8]) -> [u8; 16] {
|
||||||
|
let mut hasher = Md5::new();
|
||||||
|
|
||||||
|
hasher.update(data);
|
||||||
|
|
||||||
|
let mut bytes = [0; 16];
|
||||||
|
bytes.copy_from_slice(&hasher.finalize()[..16]);
|
||||||
|
|
||||||
|
bytes
|
||||||
|
}
|
|
@ -200,6 +200,13 @@ impl Account {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the UUID of this account. This will generate an offline-mode UUID
|
||||||
|
/// by making a hash with the username if the `uuid` field is None.
|
||||||
|
pub fn uuid_or_offline(&self) -> Uuid {
|
||||||
|
self.uuid
|
||||||
|
.unwrap_or_else(|| azalea_auth::offline::generate_uuid(&self.username))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -226,3 +233,5 @@ impl Account {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uuid_from_username() {}
|
||||||
|
|
|
@ -13,11 +13,8 @@ use bevy_ecs::prelude::*;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
interact::SwingArmEvent,
|
interact::SwingArmEvent, local_player::LocalGameMode, movement::MoveEventsSet,
|
||||||
local_player::{LocalGameMode, SendPacketEvent},
|
packet_handling::game::SendPacketEvent, respawn::perform_respawn, Client,
|
||||||
movement::MoveEventsSet,
|
|
||||||
respawn::perform_respawn,
|
|
||||||
Client,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct AttackPlugin;
|
pub struct AttackPlugin;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::Client,
|
client::Client,
|
||||||
local_player::{handle_send_packet_event, SendPacketEvent},
|
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A chat packet, either a system message or a chat message.
|
/// A chat packet, either a system message or a chat message.
|
||||||
|
|
|
@ -21,7 +21,7 @@ use tracing::{error, trace};
|
||||||
use crate::{
|
use crate::{
|
||||||
interact::handle_block_interact_event,
|
interact::handle_block_interact_event,
|
||||||
inventory::InventorySet,
|
inventory::InventorySet,
|
||||||
local_player::{handle_send_packet_event, SendPacketEvent},
|
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||||
respawn::perform_respawn,
|
respawn::perform_respawn,
|
||||||
InstanceHolder,
|
InstanceHolder,
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,12 +7,16 @@ use crate::{
|
||||||
interact::{CurrentSequenceNumber, InteractPlugin},
|
interact::{CurrentSequenceNumber, InteractPlugin},
|
||||||
inventory::{InventoryComponent, InventoryPlugin},
|
inventory::{InventoryComponent, InventoryPlugin},
|
||||||
local_player::{
|
local_player::{
|
||||||
death_event, handle_send_packet_event, GameProfileComponent, Hunger, InstanceHolder,
|
death_event, GameProfileComponent, Hunger, InstanceHolder, PermissionLevel,
|
||||||
PermissionLevel, PlayerAbilities, SendPacketEvent, TabList,
|
PlayerAbilities, TabList,
|
||||||
},
|
},
|
||||||
mining::{self, MinePlugin},
|
mining::{self, MinePlugin},
|
||||||
movement::{LastSentLookDirection, PhysicsState, PlayerMovePlugin},
|
movement::{LastSentLookDirection, PhysicsState, PlayerMovePlugin},
|
||||||
packet_handling::PacketHandlerPlugin,
|
packet_handling::{
|
||||||
|
game::{handle_send_packet_event, SendPacketEvent},
|
||||||
|
login::{self, LoginSendPacketQueue},
|
||||||
|
PacketHandlerPlugin,
|
||||||
|
},
|
||||||
player::retroactively_add_game_profile_component,
|
player::retroactively_add_game_profile_component,
|
||||||
raw_connection::RawConnection,
|
raw_connection::RawConnection,
|
||||||
respawn::RespawnPlugin,
|
respawn::RespawnPlugin,
|
||||||
|
@ -35,6 +39,7 @@ use azalea_protocol::{
|
||||||
packets::{
|
packets::{
|
||||||
configuration::{
|
configuration::{
|
||||||
serverbound_client_information_packet::ClientInformation,
|
serverbound_client_information_packet::ClientInformation,
|
||||||
|
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||||
ClientboundConfigurationPacket, ServerboundConfigurationPacket,
|
ClientboundConfigurationPacket, ServerboundConfigurationPacket,
|
||||||
},
|
},
|
||||||
game::ServerboundGamePacket,
|
game::ServerboundGamePacket,
|
||||||
|
@ -208,8 +213,29 @@ impl Client {
|
||||||
resolved_address: &SocketAddr,
|
resolved_address: &SocketAddr,
|
||||||
run_schedule_sender: mpsc::UnboundedSender<()>,
|
run_schedule_sender: mpsc::UnboundedSender<()>,
|
||||||
) -> Result<(Self, mpsc::UnboundedReceiver<Event>), JoinError> {
|
) -> Result<(Self, mpsc::UnboundedReceiver<Event>), JoinError> {
|
||||||
|
// check if an entity with our uuid already exists in the ecs and if so then
|
||||||
|
// just use that
|
||||||
|
let entity = {
|
||||||
|
let mut ecs = ecs_lock.lock();
|
||||||
|
|
||||||
|
let entity_uuid_index = ecs.resource::<EntityUuidIndex>();
|
||||||
|
let uuid = account.uuid_or_offline();
|
||||||
|
if let Some(entity) = entity_uuid_index.get(&account.uuid_or_offline()) {
|
||||||
|
debug!("Reusing entity {entity:?} for client");
|
||||||
|
entity
|
||||||
|
} else {
|
||||||
|
let entity = ecs.spawn_empty().id();
|
||||||
|
debug!("Created new entity {entity:?} for client");
|
||||||
|
// add to the uuid index
|
||||||
|
let mut entity_uuid_index = ecs.resource_mut::<EntityUuidIndex>();
|
||||||
|
entity_uuid_index.insert(uuid, entity);
|
||||||
|
entity
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let conn = Connection::new(resolved_address).await?;
|
let conn = Connection::new(resolved_address).await?;
|
||||||
let (mut conn, game_profile) = Self::handshake(conn, account, address).await?;
|
let (mut conn, game_profile) =
|
||||||
|
Self::handshake(ecs_lock.clone(), entity, conn, account, address).await?;
|
||||||
|
|
||||||
{
|
{
|
||||||
// quickly send the brand here
|
// quickly send the brand here
|
||||||
|
@ -217,12 +243,13 @@ impl Client {
|
||||||
// they don't have to know :)
|
// they don't have to know :)
|
||||||
"vanilla".write_into(&mut brand_data).unwrap();
|
"vanilla".write_into(&mut brand_data).unwrap();
|
||||||
conn.write(
|
conn.write(
|
||||||
azalea_protocol::packets::configuration::serverbound_custom_payload_packet::ServerboundCustomPayloadPacket {
|
ServerboundCustomPayloadPacket {
|
||||||
identifier: ResourceLocation::new("brand"),
|
identifier: ResourceLocation::new("brand"),
|
||||||
data: brand_data.into(),
|
data: brand_data.into(),
|
||||||
}
|
}
|
||||||
.get(),
|
.get(),
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (read_conn, write_conn) = conn.into_split();
|
let (read_conn, write_conn) = conn.into_split();
|
||||||
|
@ -234,22 +261,6 @@ impl Client {
|
||||||
|
|
||||||
let mut ecs = ecs_lock.lock();
|
let mut ecs = ecs_lock.lock();
|
||||||
|
|
||||||
// check if an entity with our uuid already exists in the ecs and if so then
|
|
||||||
// just use that
|
|
||||||
let entity = {
|
|
||||||
let entity_uuid_index = ecs.resource::<EntityUuidIndex>();
|
|
||||||
if let Some(entity) = entity_uuid_index.get(&game_profile.uuid) {
|
|
||||||
debug!("Reusing entity {entity:?} for client");
|
|
||||||
entity
|
|
||||||
} else {
|
|
||||||
let entity = ecs.spawn_empty().id();
|
|
||||||
debug!("Created new entity {entity:?} for client");
|
|
||||||
// add to the uuid index
|
|
||||||
let mut entity_uuid_index = ecs.resource_mut::<EntityUuidIndex>();
|
|
||||||
entity_uuid_index.insert(game_profile.uuid, entity);
|
|
||||||
entity
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// we got the ConfigurationConnection, so the client is now connected :)
|
// we got the ConfigurationConnection, so the client is now connected :)
|
||||||
let client = Client::new(
|
let client = Client::new(
|
||||||
game_profile.clone(),
|
game_profile.clone(),
|
||||||
|
@ -284,6 +295,8 @@ impl Client {
|
||||||
/// This will also automatically refresh the account's access token if
|
/// This will also automatically refresh the account's access token if
|
||||||
/// it's expired.
|
/// it's expired.
|
||||||
pub async fn handshake(
|
pub async fn handshake(
|
||||||
|
ecs_lock: Arc<Mutex<World>>,
|
||||||
|
entity: Entity,
|
||||||
mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
|
mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
|
||||||
account: &Account,
|
account: &Account,
|
||||||
address: &ServerAddress,
|
address: &ServerAddress,
|
||||||
|
@ -307,6 +320,14 @@ impl Client {
|
||||||
.await?;
|
.await?;
|
||||||
let mut conn = conn.login();
|
let mut conn = conn.login();
|
||||||
|
|
||||||
|
// this makes it so plugins can send an `SendLoginPacketEvent` event to the ecs
|
||||||
|
// and we'll send it to the server
|
||||||
|
let (ecs_packets_tx, mut ecs_packets_rx) = mpsc::unbounded_channel();
|
||||||
|
ecs_lock
|
||||||
|
.lock()
|
||||||
|
.entity_mut(entity)
|
||||||
|
.insert(LoginSendPacketQueue { tx: ecs_packets_tx });
|
||||||
|
|
||||||
// login
|
// login
|
||||||
conn.write(
|
conn.write(
|
||||||
ServerboundHelloPacket {
|
ServerboundHelloPacket {
|
||||||
|
@ -320,7 +341,20 @@ impl Client {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let (conn, profile) = loop {
|
let (conn, profile) = loop {
|
||||||
let packet = conn.read().await?;
|
let packet = tokio::select! {
|
||||||
|
packet = conn.read() => packet?,
|
||||||
|
Some(packet) = ecs_packets_rx.recv() => {
|
||||||
|
// write this packet to the server
|
||||||
|
conn.write(packet).await?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ecs_lock.lock().send_event(login::LoginPacketEvent {
|
||||||
|
entity,
|
||||||
|
packet: Arc::new(packet.clone()),
|
||||||
|
});
|
||||||
|
|
||||||
match packet {
|
match packet {
|
||||||
ClientboundLoginPacket::Hello(p) => {
|
ClientboundLoginPacket::Hello(p) => {
|
||||||
debug!("Got encryption request");
|
debug!("Got encryption request");
|
||||||
|
@ -655,7 +689,7 @@ impl Plugin for AzaleaPlugin {
|
||||||
/// [`DefaultPlugins`].
|
/// [`DefaultPlugins`].
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn start_ecs_runner(
|
pub fn start_ecs_runner(
|
||||||
mut app: App,
|
app: App,
|
||||||
run_schedule_receiver: mpsc::UnboundedReceiver<()>,
|
run_schedule_receiver: mpsc::UnboundedReceiver<()>,
|
||||||
run_schedule_sender: mpsc::UnboundedSender<()>,
|
run_schedule_sender: mpsc::UnboundedSender<()>,
|
||||||
) -> Arc<Mutex<World>> {
|
) -> Arc<Mutex<World>> {
|
||||||
|
|
|
@ -34,10 +34,9 @@ use tracing::warn;
|
||||||
use crate::{
|
use crate::{
|
||||||
attack::handle_attack_event,
|
attack::handle_attack_event,
|
||||||
inventory::{InventoryComponent, InventorySet},
|
inventory::{InventoryComponent, InventorySet},
|
||||||
local_player::{
|
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities},
|
||||||
handle_send_packet_event, LocalGameMode, PermissionLevel, PlayerAbilities, SendPacketEvent,
|
|
||||||
},
|
|
||||||
movement::MoveEventsSet,
|
movement::MoveEventsSet,
|
||||||
|
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||||
respawn::perform_respawn,
|
respawn::perform_respawn,
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,7 +26,8 @@ use bevy_ecs::{
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
local_player::{handle_send_packet_event, PlayerAbilities, SendPacketEvent},
|
local_player::PlayerAbilities,
|
||||||
|
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||||
respawn::perform_respawn,
|
respawn::perform_respawn,
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub use client::{
|
||||||
start_ecs_runner, Client, DefaultPlugins, JoinError, JoinedClientBundle, TickBroadcast,
|
start_ecs_runner, Client, DefaultPlugins, JoinError, JoinedClientBundle, TickBroadcast,
|
||||||
};
|
};
|
||||||
pub use events::Event;
|
pub use events::Event;
|
||||||
pub use local_player::{GameProfileComponent, InstanceHolder, SendPacketEvent, TabList};
|
pub use local_player::{GameProfileComponent, InstanceHolder, TabList};
|
||||||
pub use movement::{
|
pub use movement::{
|
||||||
PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
|
PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
|
||||||
};
|
};
|
||||||
|
|
|
@ -160,24 +160,3 @@ impl<T> From<std::sync::PoisonError<T>> for HandlePacketError {
|
||||||
HandlePacketError::Poison(e.to_string())
|
HandlePacketError::Poison(e.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event for sending a packet to the server.
|
|
||||||
#[derive(Event)]
|
|
||||||
pub struct SendPacketEvent {
|
|
||||||
pub entity: Entity,
|
|
||||||
pub packet: ServerboundGamePacket,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_send_packet_event(
|
|
||||||
mut send_packet_events: EventReader<SendPacketEvent>,
|
|
||||||
mut query: Query<&mut RawConnection>,
|
|
||||||
) {
|
|
||||||
for event in send_packet_events.read() {
|
|
||||||
if let Ok(raw_connection) = query.get_mut(event.entity) {
|
|
||||||
// debug!("Sending packet: {:?}", event.packet);
|
|
||||||
if let Err(e) = raw_connection.write_packet(event.packet.clone()) {
|
|
||||||
error!("Failed to send packet: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,8 +17,9 @@ use crate::{
|
||||||
HitResultComponent, SwingArmEvent,
|
HitResultComponent, SwingArmEvent,
|
||||||
},
|
},
|
||||||
inventory::{InventoryComponent, InventorySet},
|
inventory::{InventoryComponent, InventorySet},
|
||||||
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities, SendPacketEvent},
|
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities},
|
||||||
movement::MoveEventsSet,
|
movement::MoveEventsSet,
|
||||||
|
packet_handling::game::SendPacketEvent,
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::client::Client;
|
use crate::client::Client;
|
||||||
use crate::local_player::SendPacketEvent;
|
use crate::packet_handling::game::SendPacketEvent;
|
||||||
use azalea_core::position::Vec3;
|
use azalea_core::position::Vec3;
|
||||||
use azalea_entity::{metadata::Sprinting, Attributes, Jumping};
|
use azalea_entity::{metadata::Sprinting, Attributes, Jumping};
|
||||||
use azalea_entity::{InLoadedChunk, LastSentPosition, LookDirection, Physics, Position};
|
use azalea_entity::{InLoadedChunk, LastSentPosition, LookDirection, Physics, Position};
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::packet_handling::game::KeepAliveEvent;
|
||||||
use crate::raw_connection::RawConnection;
|
use crate::raw_connection::RawConnection;
|
||||||
|
|
||||||
#[derive(Event, Debug, Clone)]
|
#[derive(Event, Debug, Clone)]
|
||||||
pub struct PacketEvent {
|
pub struct ConfigurationPacketEvent {
|
||||||
/// The client entity that received the packet.
|
/// The client entity that received the packet.
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
/// The packet that was actually received.
|
/// The packet that was actually received.
|
||||||
|
@ -31,7 +31,7 @@ pub struct PacketEvent {
|
||||||
|
|
||||||
pub fn send_packet_events(
|
pub fn send_packet_events(
|
||||||
query: Query<(Entity, &RawConnection), With<InConfigurationState>>,
|
query: Query<(Entity, &RawConnection), With<InConfigurationState>>,
|
||||||
mut packet_events: ResMut<Events<PacketEvent>>,
|
mut packet_events: ResMut<Events<ConfigurationPacketEvent>>,
|
||||||
) {
|
) {
|
||||||
// we manually clear and send the events at the beginning of each update
|
// we manually clear and send the events at the beginning of each update
|
||||||
// since otherwise it'd cause issues with events in process_packet_events
|
// since otherwise it'd cause issues with events in process_packet_events
|
||||||
|
@ -51,7 +51,7 @@ pub fn send_packet_events(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
packet_events.send(PacketEvent {
|
packet_events.send(ConfigurationPacketEvent {
|
||||||
entity: player_entity,
|
entity: player_entity,
|
||||||
packet,
|
packet,
|
||||||
});
|
});
|
||||||
|
@ -64,9 +64,10 @@ pub fn send_packet_events(
|
||||||
|
|
||||||
pub fn process_packet_events(ecs: &mut World) {
|
pub fn process_packet_events(ecs: &mut World) {
|
||||||
let mut events_owned = Vec::new();
|
let mut events_owned = Vec::new();
|
||||||
let mut system_state: SystemState<EventReader<PacketEvent>> = SystemState::new(ecs);
|
let mut system_state: SystemState<EventReader<ConfigurationPacketEvent>> =
|
||||||
|
SystemState::new(ecs);
|
||||||
let mut events = system_state.get_mut(ecs);
|
let mut events = system_state.get_mut(ecs);
|
||||||
for PacketEvent {
|
for ConfigurationPacketEvent {
|
||||||
entity: player_entity,
|
entity: player_entity,
|
||||||
packet,
|
packet,
|
||||||
} in events.read()
|
} in events.read()
|
||||||
|
|
|
@ -23,6 +23,7 @@ use azalea_protocol::{
|
||||||
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||||
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||||
serverbound_pong_packet::ServerboundPongPacket, ClientboundGamePacket,
|
serverbound_pong_packet::ServerboundPongPacket, ClientboundGamePacket,
|
||||||
|
ServerboundGamePacket,
|
||||||
},
|
},
|
||||||
read::deserialize_packet,
|
read::deserialize_packet,
|
||||||
};
|
};
|
||||||
|
@ -40,8 +41,7 @@ use crate::{
|
||||||
SetContainerContentEvent,
|
SetContainerContentEvent,
|
||||||
},
|
},
|
||||||
local_player::{
|
local_player::{
|
||||||
GameProfileComponent, Hunger, InstanceHolder, LocalGameMode, PlayerAbilities,
|
GameProfileComponent, Hunger, InstanceHolder, LocalGameMode, PlayerAbilities, TabList,
|
||||||
SendPacketEvent, TabList,
|
|
||||||
},
|
},
|
||||||
movement::{KnockbackEvent, KnockbackType},
|
movement::{KnockbackEvent, KnockbackType},
|
||||||
raw_connection::RawConnection,
|
raw_connection::RawConnection,
|
||||||
|
@ -1391,3 +1391,24 @@ pub fn process_packet_events(ecs: &mut World) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An event for sending a packet to the server while we're in the `game` state.
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct SendPacketEvent {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub packet: ServerboundGamePacket,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_send_packet_event(
|
||||||
|
mut send_packet_events: EventReader<SendPacketEvent>,
|
||||||
|
mut query: Query<&mut RawConnection>,
|
||||||
|
) {
|
||||||
|
for event in send_packet_events.read() {
|
||||||
|
if let Ok(raw_connection) = query.get_mut(event.entity) {
|
||||||
|
// debug!("Sending packet: {:?}", event.packet);
|
||||||
|
if let Err(e) = raw_connection.write_packet(event.packet.clone()) {
|
||||||
|
error!("Failed to send packet: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
49
azalea-client/src/packet_handling/login.rs
Normal file
49
azalea-client/src/packet_handling/login.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// login packets aren't actually handled here because compression/encryption
|
||||||
|
// would make packet handling a lot messier
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use azalea_protocol::packets::login::{ClientboundLoginPacket, ServerboundLoginPacket};
|
||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use crate::raw_connection::RawConnection;
|
||||||
|
|
||||||
|
use super::game::SendPacketEvent;
|
||||||
|
|
||||||
|
// this struct is defined here anyways though so it's consistent with the other
|
||||||
|
// ones
|
||||||
|
|
||||||
|
#[derive(Event, Debug, Clone)]
|
||||||
|
pub struct LoginPacketEvent {
|
||||||
|
/// The client entity that received the packet.
|
||||||
|
pub entity: Entity,
|
||||||
|
/// The packet that was actually received.
|
||||||
|
pub packet: Arc<ClientboundLoginPacket>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event for sending a login packet to the server.
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct SendLoginPacketEvent {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub packet: ServerboundLoginPacket,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct LoginSendPacketQueue {
|
||||||
|
pub tx: mpsc::UnboundedSender<ServerboundLoginPacket>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_send_packet_event(
|
||||||
|
mut send_packet_events: EventReader<SendLoginPacketEvent>,
|
||||||
|
mut query: Query<&mut LoginSendPacketQueue>,
|
||||||
|
) {
|
||||||
|
for event in send_packet_events.read() {
|
||||||
|
if let Ok(queue) = query.get_mut(event.entity) {
|
||||||
|
let _ = queue.tx.send(event.packet.clone());
|
||||||
|
} else {
|
||||||
|
error!("Sent SendPacketEvent for entity that doesn't have a LoginSendPacketQueue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,13 +4,17 @@ use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
use crate::{chat::ChatReceivedEvent, events::death_listener};
|
use crate::{chat::ChatReceivedEvent, events::death_listener};
|
||||||
|
|
||||||
use self::game::{
|
use self::{
|
||||||
|
game::{
|
||||||
AddPlayerEvent, DeathEvent, InstanceLoadedEvent, KeepAliveEvent, RemovePlayerEvent,
|
AddPlayerEvent, DeathEvent, InstanceLoadedEvent, KeepAliveEvent, RemovePlayerEvent,
|
||||||
ResourcePackEvent, UpdatePlayerEvent,
|
ResourcePackEvent, UpdatePlayerEvent,
|
||||||
|
},
|
||||||
|
login::{LoginPacketEvent, SendLoginPacketEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod configuration;
|
pub mod configuration;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
|
pub mod login;
|
||||||
|
|
||||||
pub struct PacketHandlerPlugin;
|
pub struct PacketHandlerPlugin;
|
||||||
|
|
||||||
|
@ -37,16 +41,17 @@ impl Plugin for PacketHandlerPlugin {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
(
|
(
|
||||||
game::process_packet_events,
|
game::process_packet_events
|
||||||
configuration::process_packet_events,
|
|
||||||
)
|
|
||||||
// we want to index and deindex right after
|
// we want to index and deindex right after
|
||||||
.before(EntityUpdateSet::Deindex),
|
.before(EntityUpdateSet::Deindex),
|
||||||
|
configuration::process_packet_events,
|
||||||
|
login::handle_send_packet_event,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.add_systems(Update, death_event_on_0_health.before(death_listener))
|
.add_systems(Update, death_event_on_0_health.before(death_listener))
|
||||||
// we do this instead of add_event so we can handle the events ourselves
|
// we do this instead of add_event so we can handle the events ourselves
|
||||||
.init_resource::<Events<game::PacketEvent>>()
|
.init_resource::<Events<game::PacketEvent>>()
|
||||||
.init_resource::<Events<configuration::PacketEvent>>()
|
.init_resource::<Events<configuration::ConfigurationPacketEvent>>()
|
||||||
.add_event::<AddPlayerEvent>()
|
.add_event::<AddPlayerEvent>()
|
||||||
.add_event::<RemovePlayerEvent>()
|
.add_event::<RemovePlayerEvent>()
|
||||||
.add_event::<UpdatePlayerEvent>()
|
.add_event::<UpdatePlayerEvent>()
|
||||||
|
@ -54,6 +59,8 @@ impl Plugin for PacketHandlerPlugin {
|
||||||
.add_event::<DeathEvent>()
|
.add_event::<DeathEvent>()
|
||||||
.add_event::<KeepAliveEvent>()
|
.add_event::<KeepAliveEvent>()
|
||||||
.add_event::<ResourcePackEvent>()
|
.add_event::<ResourcePackEvent>()
|
||||||
.add_event::<InstanceLoadedEvent>();
|
.add_event::<InstanceLoadedEvent>()
|
||||||
|
.add_event::<LoginPacketEvent>()
|
||||||
|
.add_event::<SendLoginPacketEvent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use azalea_protocol::packets::game::serverbound_client_command_packet::{
|
||||||
use bevy_app::{App, Plugin, Update};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
use crate::local_player::{handle_send_packet_event, SendPacketEvent};
|
use crate::packet_handling::game::{handle_send_packet_event, SendPacketEvent};
|
||||||
|
|
||||||
/// Tell the server that we're respawning.
|
/// Tell the server that we're respawning.
|
||||||
#[derive(Event, Debug, Clone)]
|
#[derive(Event, Debug, Clone)]
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::app::{App, Plugin};
|
use crate::app::{App, Plugin};
|
||||||
use azalea_client::chunks::handle_chunk_batch_finished_event;
|
use azalea_client::chunks::handle_chunk_batch_finished_event;
|
||||||
use azalea_client::inventory::InventorySet;
|
use azalea_client::inventory::InventorySet;
|
||||||
|
use azalea_client::packet_handling::game::SendPacketEvent;
|
||||||
use azalea_client::packet_handling::{death_event_on_0_health, game::ResourcePackEvent};
|
use azalea_client::packet_handling::{death_event_on_0_health, game::ResourcePackEvent};
|
||||||
use azalea_client::respawn::perform_respawn;
|
use azalea_client::respawn::perform_respawn;
|
||||||
use azalea_client::SendPacketEvent;
|
|
||||||
use azalea_protocol::packets::game::serverbound_resource_pack_packet::{
|
use azalea_protocol::packets::game::serverbound_resource_pack_packet::{
|
||||||
self, ServerboundResourcePackPacket,
|
self, ServerboundResourcePackPacket,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
use azalea_client::{inventory::InventoryComponent, PhysicsState};
|
use azalea_client::{
|
||||||
|
inventory::InventoryComponent, packet_handling::game::SendPacketEvent, PhysicsState,
|
||||||
|
};
|
||||||
use azalea_core::{position::Vec3, resource_location::ResourceLocation};
|
use azalea_core::{position::Vec3, resource_location::ResourceLocation};
|
||||||
use azalea_entity::{
|
use azalea_entity::{
|
||||||
attributes::AttributeInstance, metadata::Sprinting, Attributes, EntityDimensions, Physics,
|
attributes::AttributeInstance, metadata::Sprinting, Attributes, EntityDimensions, Physics,
|
||||||
|
@ -77,7 +79,7 @@ impl Simulation {
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
.add_event::<azalea_client::SendPacketEvent>();
|
.add_event::<SendPacketEvent>();
|
||||||
|
|
||||||
app.edit_schedule(bevy_app::Main, |schedule| {
|
app.edit_schedule(bevy_app::Main, |schedule| {
|
||||||
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
|
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
|
||||||
|
|
Loading…
Reference in a new issue