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",
|
||||
"chrono",
|
||||
"env_logger",
|
||||
"md-5",
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"reqwest",
|
||||
|
@ -1637,6 +1638,16 @@ dependencies = [
|
|||
"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]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
|
@ -2878,6 +2889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"md-5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ serde = { version = "1.0.192", features = ["derive"] }
|
|||
serde_json = "1.0.108"
|
||||
thiserror = "1.0.50"
|
||||
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]
|
||||
env_logger = "0.10.1"
|
||||
|
|
|
@ -4,6 +4,7 @@ mod auth;
|
|||
pub mod cache;
|
||||
pub mod certs;
|
||||
pub mod game_profile;
|
||||
pub mod offline;
|
||||
pub mod sessionserver;
|
||||
|
||||
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)]
|
||||
|
@ -226,3 +233,5 @@ impl Account {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn uuid_from_username() {}
|
||||
|
|
|
@ -13,11 +13,8 @@ use bevy_ecs::prelude::*;
|
|||
use derive_more::{Deref, DerefMut};
|
||||
|
||||
use crate::{
|
||||
interact::SwingArmEvent,
|
||||
local_player::{LocalGameMode, SendPacketEvent},
|
||||
movement::MoveEventsSet,
|
||||
respawn::perform_respawn,
|
||||
Client,
|
||||
interact::SwingArmEvent, local_player::LocalGameMode, movement::MoveEventsSet,
|
||||
packet_handling::game::SendPacketEvent, respawn::perform_respawn, Client,
|
||||
};
|
||||
|
||||
pub struct AttackPlugin;
|
||||
|
|
|
@ -22,7 +22,7 @@ use uuid::Uuid;
|
|||
|
||||
use crate::{
|
||||
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.
|
||||
|
|
|
@ -21,7 +21,7 @@ use tracing::{error, trace};
|
|||
use crate::{
|
||||
interact::handle_block_interact_event,
|
||||
inventory::InventorySet,
|
||||
local_player::{handle_send_packet_event, SendPacketEvent},
|
||||
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||
respawn::perform_respawn,
|
||||
InstanceHolder,
|
||||
};
|
||||
|
|
|
@ -7,12 +7,16 @@ use crate::{
|
|||
interact::{CurrentSequenceNumber, InteractPlugin},
|
||||
inventory::{InventoryComponent, InventoryPlugin},
|
||||
local_player::{
|
||||
death_event, handle_send_packet_event, GameProfileComponent, Hunger, InstanceHolder,
|
||||
PermissionLevel, PlayerAbilities, SendPacketEvent, TabList,
|
||||
death_event, GameProfileComponent, Hunger, InstanceHolder, PermissionLevel,
|
||||
PlayerAbilities, TabList,
|
||||
},
|
||||
mining::{self, MinePlugin},
|
||||
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,
|
||||
raw_connection::RawConnection,
|
||||
respawn::RespawnPlugin,
|
||||
|
@ -35,6 +39,7 @@ use azalea_protocol::{
|
|||
packets::{
|
||||
configuration::{
|
||||
serverbound_client_information_packet::ClientInformation,
|
||||
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||
ClientboundConfigurationPacket, ServerboundConfigurationPacket,
|
||||
},
|
||||
game::ServerboundGamePacket,
|
||||
|
@ -208,8 +213,29 @@ impl Client {
|
|||
resolved_address: &SocketAddr,
|
||||
run_schedule_sender: mpsc::UnboundedSender<()>,
|
||||
) -> 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 (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
|
||||
|
@ -217,12 +243,13 @@ impl Client {
|
|||
// they don't have to know :)
|
||||
"vanilla".write_into(&mut brand_data).unwrap();
|
||||
conn.write(
|
||||
azalea_protocol::packets::configuration::serverbound_custom_payload_packet::ServerboundCustomPayloadPacket {
|
||||
ServerboundCustomPayloadPacket {
|
||||
identifier: ResourceLocation::new("brand"),
|
||||
data: brand_data.into(),
|
||||
}
|
||||
.get(),
|
||||
).await?;
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let (read_conn, write_conn) = conn.into_split();
|
||||
|
@ -234,22 +261,6 @@ impl Client {
|
|||
|
||||
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 :)
|
||||
let client = Client::new(
|
||||
game_profile.clone(),
|
||||
|
@ -284,6 +295,8 @@ impl Client {
|
|||
/// This will also automatically refresh the account's access token if
|
||||
/// it's expired.
|
||||
pub async fn handshake(
|
||||
ecs_lock: Arc<Mutex<World>>,
|
||||
entity: Entity,
|
||||
mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
|
||||
account: &Account,
|
||||
address: &ServerAddress,
|
||||
|
@ -307,6 +320,14 @@ impl Client {
|
|||
.await?;
|
||||
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
|
||||
conn.write(
|
||||
ServerboundHelloPacket {
|
||||
|
@ -320,7 +341,20 @@ impl Client {
|
|||
.await?;
|
||||
|
||||
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 {
|
||||
ClientboundLoginPacket::Hello(p) => {
|
||||
debug!("Got encryption request");
|
||||
|
@ -655,7 +689,7 @@ impl Plugin for AzaleaPlugin {
|
|||
/// [`DefaultPlugins`].
|
||||
#[doc(hidden)]
|
||||
pub fn start_ecs_runner(
|
||||
mut app: App,
|
||||
app: App,
|
||||
run_schedule_receiver: mpsc::UnboundedReceiver<()>,
|
||||
run_schedule_sender: mpsc::UnboundedSender<()>,
|
||||
) -> Arc<Mutex<World>> {
|
||||
|
|
|
@ -34,10 +34,9 @@ use tracing::warn;
|
|||
use crate::{
|
||||
attack::handle_attack_event,
|
||||
inventory::{InventoryComponent, InventorySet},
|
||||
local_player::{
|
||||
handle_send_packet_event, LocalGameMode, PermissionLevel, PlayerAbilities, SendPacketEvent,
|
||||
},
|
||||
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities},
|
||||
movement::MoveEventsSet,
|
||||
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||
respawn::perform_respawn,
|
||||
Client,
|
||||
};
|
||||
|
|
|
@ -26,7 +26,8 @@ use bevy_ecs::{
|
|||
use tracing::warn;
|
||||
|
||||
use crate::{
|
||||
local_player::{handle_send_packet_event, PlayerAbilities, SendPacketEvent},
|
||||
local_player::PlayerAbilities,
|
||||
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
|
||||
respawn::perform_respawn,
|
||||
Client,
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ pub use client::{
|
|||
start_ecs_runner, Client, DefaultPlugins, JoinError, JoinedClientBundle, TickBroadcast,
|
||||
};
|
||||
pub use events::Event;
|
||||
pub use local_player::{GameProfileComponent, InstanceHolder, SendPacketEvent, TabList};
|
||||
pub use local_player::{GameProfileComponent, InstanceHolder, TabList};
|
||||
pub use movement::{
|
||||
PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
|
||||
};
|
||||
|
|
|
@ -160,24 +160,3 @@ impl<T> From<std::sync::PoisonError<T>> for HandlePacketError {
|
|||
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,
|
||||
},
|
||||
inventory::{InventoryComponent, InventorySet},
|
||||
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities, SendPacketEvent},
|
||||
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities},
|
||||
movement::MoveEventsSet,
|
||||
packet_handling::game::SendPacketEvent,
|
||||
Client,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::client::Client;
|
||||
use crate::local_player::SendPacketEvent;
|
||||
use crate::packet_handling::game::SendPacketEvent;
|
||||
use azalea_core::position::Vec3;
|
||||
use azalea_entity::{metadata::Sprinting, Attributes, Jumping};
|
||||
use azalea_entity::{InLoadedChunk, LastSentPosition, LookDirection, Physics, Position};
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::packet_handling::game::KeepAliveEvent;
|
|||
use crate::raw_connection::RawConnection;
|
||||
|
||||
#[derive(Event, Debug, Clone)]
|
||||
pub struct PacketEvent {
|
||||
pub struct ConfigurationPacketEvent {
|
||||
/// The client entity that received the packet.
|
||||
pub entity: Entity,
|
||||
/// The packet that was actually received.
|
||||
|
@ -31,7 +31,7 @@ pub struct PacketEvent {
|
|||
|
||||
pub fn send_packet_events(
|
||||
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
|
||||
// since otherwise it'd cause issues with events in process_packet_events
|
||||
|
@ -51,7 +51,7 @@ pub fn send_packet_events(
|
|||
continue;
|
||||
}
|
||||
};
|
||||
packet_events.send(PacketEvent {
|
||||
packet_events.send(ConfigurationPacketEvent {
|
||||
entity: player_entity,
|
||||
packet,
|
||||
});
|
||||
|
@ -64,9 +64,10 @@ pub fn send_packet_events(
|
|||
|
||||
pub fn process_packet_events(ecs: &mut World) {
|
||||
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);
|
||||
for PacketEvent {
|
||||
for ConfigurationPacketEvent {
|
||||
entity: player_entity,
|
||||
packet,
|
||||
} in events.read()
|
||||
|
|
|
@ -23,6 +23,7 @@ use azalea_protocol::{
|
|||
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||
serverbound_pong_packet::ServerboundPongPacket, ClientboundGamePacket,
|
||||
ServerboundGamePacket,
|
||||
},
|
||||
read::deserialize_packet,
|
||||
};
|
||||
|
@ -40,8 +41,7 @@ use crate::{
|
|||
SetContainerContentEvent,
|
||||
},
|
||||
local_player::{
|
||||
GameProfileComponent, Hunger, InstanceHolder, LocalGameMode, PlayerAbilities,
|
||||
SendPacketEvent, TabList,
|
||||
GameProfileComponent, Hunger, InstanceHolder, LocalGameMode, PlayerAbilities, TabList,
|
||||
},
|
||||
movement::{KnockbackEvent, KnockbackType},
|
||||
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 self::game::{
|
||||
use self::{
|
||||
game::{
|
||||
AddPlayerEvent, DeathEvent, InstanceLoadedEvent, KeepAliveEvent, RemovePlayerEvent,
|
||||
ResourcePackEvent, UpdatePlayerEvent,
|
||||
},
|
||||
login::{LoginPacketEvent, SendLoginPacketEvent},
|
||||
};
|
||||
|
||||
pub mod configuration;
|
||||
pub mod game;
|
||||
pub mod login;
|
||||
|
||||
pub struct PacketHandlerPlugin;
|
||||
|
||||
|
@ -37,16 +41,17 @@ impl Plugin for PacketHandlerPlugin {
|
|||
.add_systems(
|
||||
PreUpdate,
|
||||
(
|
||||
game::process_packet_events,
|
||||
configuration::process_packet_events,
|
||||
)
|
||||
game::process_packet_events
|
||||
// we want to index and deindex right after
|
||||
.before(EntityUpdateSet::Deindex),
|
||||
configuration::process_packet_events,
|
||||
login::handle_send_packet_event,
|
||||
),
|
||||
)
|
||||
.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
|
||||
.init_resource::<Events<game::PacketEvent>>()
|
||||
.init_resource::<Events<configuration::PacketEvent>>()
|
||||
.init_resource::<Events<configuration::ConfigurationPacketEvent>>()
|
||||
.add_event::<AddPlayerEvent>()
|
||||
.add_event::<RemovePlayerEvent>()
|
||||
.add_event::<UpdatePlayerEvent>()
|
||||
|
@ -54,6 +59,8 @@ impl Plugin for PacketHandlerPlugin {
|
|||
.add_event::<DeathEvent>()
|
||||
.add_event::<KeepAliveEvent>()
|
||||
.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_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.
|
||||
#[derive(Event, Debug, Clone)]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::app::{App, Plugin};
|
||||
use azalea_client::chunks::handle_chunk_batch_finished_event;
|
||||
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::respawn::perform_respawn;
|
||||
use azalea_client::SendPacketEvent;
|
||||
use azalea_protocol::packets::game::serverbound_resource_pack_packet::{
|
||||
self, ServerboundResourcePackPacket,
|
||||
};
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
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_entity::{
|
||||
attributes::AttributeInstance, metadata::Sprinting, Attributes, EntityDimensions, Physics,
|
||||
|
@ -77,7 +79,7 @@ impl Simulation {
|
|||
.cloned()
|
||||
.collect(),
|
||||
})
|
||||
.add_event::<azalea_client::SendPacketEvent>();
|
||||
.add_event::<SendPacketEvent>();
|
||||
|
||||
app.edit_schedule(bevy_app::Main, |schedule| {
|
||||
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
|
||||
|
|
Loading…
Reference in a new issue