Skip to content

Commit 1f46ef8

Browse files
committed
make it so plugins can send and receive packets during the login state
1 parent 0713223 commit 1f46ef8

File tree

22 files changed

+211
-80
lines changed

22 files changed

+211
-80
lines changed

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

azalea-auth/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ serde = { version = "1.0.192", features = ["derive"] }
2525
serde_json = "1.0.108"
2626
thiserror = "1.0.50"
2727
tokio = { version = "1.34.0", features = ["fs"] }
28-
uuid = { version = "1.5.0", features = ["serde"] }
28+
uuid = { version = "1.5.0", features = ["serde", "v3"] }
29+
md-5 = "0.10.6"
2930

3031
[dev-dependencies]
3132
env_logger = "0.10.1"

azalea-auth/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod auth;
44
pub mod cache;
55
pub mod certs;
66
pub mod game_profile;
7+
pub mod offline;
78
pub mod sessionserver;
89

910
pub use auth::*;

azalea-auth/src/offline.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use md5::{Digest, Md5};
2+
use uuid::Uuid;
3+
4+
pub fn generate_uuid(username: &str) -> Uuid {
5+
uuid::Builder::from_md5_bytes(hash(format!("OfflinePlayer:{username}").as_bytes())).into_uuid()
6+
}
7+
8+
fn hash(data: &[u8]) -> [u8; 16] {
9+
let mut hasher = Md5::new();
10+
11+
hasher.update(data);
12+
13+
let mut bytes = [0; 16];
14+
bytes.copy_from_slice(&hasher.finalize()[..16]);
15+
16+
bytes
17+
}

azalea-client/src/account.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ impl Account {
200200
}
201201
}
202202
}
203+
204+
/// Get the UUID of this account. This will generate an offline-mode UUID
205+
/// by making a hash with the username if the `uuid` field is None.
206+
pub fn uuid_or_offline(&self) -> Uuid {
207+
self.uuid
208+
.unwrap_or_else(|| azalea_auth::offline::generate_uuid(&self.username))
209+
}
203210
}
204211

205212
#[derive(Error, Debug)]
@@ -226,3 +233,5 @@ impl Account {
226233
Ok(())
227234
}
228235
}
236+
237+
fn uuid_from_username() {}

azalea-client/src/attack.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,8 @@ use bevy_ecs::prelude::*;
1313
use derive_more::{Deref, DerefMut};
1414

1515
use crate::{
16-
interact::SwingArmEvent,
17-
local_player::{LocalGameMode, SendPacketEvent},
18-
movement::MoveEventsSet,
19-
respawn::perform_respawn,
20-
Client,
16+
interact::SwingArmEvent, local_player::LocalGameMode, movement::MoveEventsSet,
17+
packet_handling::game::SendPacketEvent, respawn::perform_respawn, Client,
2118
};
2219

2320
pub struct AttackPlugin;

azalea-client/src/chat.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use uuid::Uuid;
2222

2323
use crate::{
2424
client::Client,
25-
local_player::{handle_send_packet_event, SendPacketEvent},
25+
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
2626
};
2727

2828
/// A chat packet, either a system message or a chat message.

azalea-client/src/chunks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tracing::{error, trace};
2121
use crate::{
2222
interact::handle_block_interact_event,
2323
inventory::InventorySet,
24-
local_player::{handle_send_packet_event, SendPacketEvent},
24+
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
2525
respawn::perform_respawn,
2626
InstanceHolder,
2727
};

azalea-client/src/client.rs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ use crate::{
77
interact::{CurrentSequenceNumber, InteractPlugin},
88
inventory::{InventoryComponent, InventoryPlugin},
99
local_player::{
10-
death_event, handle_send_packet_event, GameProfileComponent, Hunger, InstanceHolder,
11-
PermissionLevel, PlayerAbilities, SendPacketEvent, TabList,
10+
death_event, GameProfileComponent, Hunger, InstanceHolder, PermissionLevel,
11+
PlayerAbilities, TabList,
1212
},
1313
mining::{self, MinePlugin},
1414
movement::{LastSentLookDirection, PhysicsState, PlayerMovePlugin},
15-
packet_handling::PacketHandlerPlugin,
15+
packet_handling::{
16+
game::{handle_send_packet_event, SendPacketEvent},
17+
login::{self, LoginSendPacketQueue},
18+
PacketHandlerPlugin,
19+
},
1620
player::retroactively_add_game_profile_component,
1721
raw_connection::RawConnection,
1822
respawn::RespawnPlugin,
@@ -35,6 +39,7 @@ use azalea_protocol::{
3539
packets::{
3640
configuration::{
3741
serverbound_client_information_packet::ClientInformation,
42+
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
3843
ClientboundConfigurationPacket, ServerboundConfigurationPacket,
3944
},
4045
game::ServerboundGamePacket,
@@ -208,21 +213,43 @@ impl Client {
208213
resolved_address: &SocketAddr,
209214
run_schedule_sender: mpsc::UnboundedSender<()>,
210215
) -> Result<(Self, mpsc::UnboundedReceiver<Event>), JoinError> {
216+
// check if an entity with our uuid already exists in the ecs and if so then
217+
// just use that
218+
let entity = {
219+
let mut ecs = ecs_lock.lock();
220+
221+
let entity_uuid_index = ecs.resource::<EntityUuidIndex>();
222+
let uuid = account.uuid_or_offline();
223+
if let Some(entity) = entity_uuid_index.get(&account.uuid_or_offline()) {
224+
debug!("Reusing entity {entity:?} for client");
225+
entity
226+
} else {
227+
let entity = ecs.spawn_empty().id();
228+
debug!("Created new entity {entity:?} for client");
229+
// add to the uuid index
230+
let mut entity_uuid_index = ecs.resource_mut::<EntityUuidIndex>();
231+
entity_uuid_index.insert(uuid, entity);
232+
entity
233+
}
234+
};
235+
211236
let conn = Connection::new(resolved_address).await?;
212-
let (mut conn, game_profile) = Self::handshake(conn, account, address).await?;
237+
let (mut conn, game_profile) =
238+
Self::handshake(ecs_lock.clone(), entity, conn, account, address).await?;
213239

214240
{
215241
// quickly send the brand here
216242
let mut brand_data = Vec::new();
217243
// they don't have to know :)
218244
"vanilla".write_into(&mut brand_data).unwrap();
219245
conn.write(
220-
azalea_protocol::packets::configuration::serverbound_custom_payload_packet::ServerboundCustomPayloadPacket {
246+
ServerboundCustomPayloadPacket {
221247
identifier: ResourceLocation::new("brand"),
222248
data: brand_data.into(),
223249
}
224250
.get(),
225-
).await?;
251+
)
252+
.await?;
226253
}
227254

228255
let (read_conn, write_conn) = conn.into_split();
@@ -234,22 +261,6 @@ impl Client {
234261

235262
let mut ecs = ecs_lock.lock();
236263

237-
// check if an entity with our uuid already exists in the ecs and if so then
238-
// just use that
239-
let entity = {
240-
let entity_uuid_index = ecs.resource::<EntityUuidIndex>();
241-
if let Some(entity) = entity_uuid_index.get(&game_profile.uuid) {
242-
debug!("Reusing entity {entity:?} for client");
243-
entity
244-
} else {
245-
let entity = ecs.spawn_empty().id();
246-
debug!("Created new entity {entity:?} for client");
247-
// add to the uuid index
248-
let mut entity_uuid_index = ecs.resource_mut::<EntityUuidIndex>();
249-
entity_uuid_index.insert(game_profile.uuid, entity);
250-
entity
251-
}
252-
};
253264
// we got the ConfigurationConnection, so the client is now connected :)
254265
let client = Client::new(
255266
game_profile.clone(),
@@ -284,6 +295,8 @@ impl Client {
284295
/// This will also automatically refresh the account's access token if
285296
/// it's expired.
286297
pub async fn handshake(
298+
ecs_lock: Arc<Mutex<World>>,
299+
entity: Entity,
287300
mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
288301
account: &Account,
289302
address: &ServerAddress,
@@ -307,6 +320,14 @@ impl Client {
307320
.await?;
308321
let mut conn = conn.login();
309322

323+
// this makes it so plugins can send an `SendLoginPacketEvent` event to the ecs
324+
// and we'll send it to the server
325+
let (ecs_packets_tx, mut ecs_packets_rx) = mpsc::unbounded_channel();
326+
ecs_lock
327+
.lock()
328+
.entity_mut(entity)
329+
.insert(LoginSendPacketQueue { tx: ecs_packets_tx });
330+
310331
// login
311332
conn.write(
312333
ServerboundHelloPacket {
@@ -320,7 +341,20 @@ impl Client {
320341
.await?;
321342

322343
let (conn, profile) = loop {
323-
let packet = conn.read().await?;
344+
let packet = tokio::select! {
345+
packet = conn.read() => packet?,
346+
Some(packet) = ecs_packets_rx.recv() => {
347+
// write this packet to the server
348+
conn.write(packet).await?;
349+
continue;
350+
}
351+
};
352+
353+
ecs_lock.lock().send_event(login::LoginPacketEvent {
354+
entity,
355+
packet: Arc::new(packet.clone()),
356+
});
357+
324358
match packet {
325359
ClientboundLoginPacket::Hello(p) => {
326360
debug!("Got encryption request");
@@ -655,7 +689,7 @@ impl Plugin for AzaleaPlugin {
655689
/// [`DefaultPlugins`].
656690
#[doc(hidden)]
657691
pub fn start_ecs_runner(
658-
mut app: App,
692+
app: App,
659693
run_schedule_receiver: mpsc::UnboundedReceiver<()>,
660694
run_schedule_sender: mpsc::UnboundedSender<()>,
661695
) -> Arc<Mutex<World>> {

azalea-client/src/interact.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,9 @@ use tracing::warn;
3434
use crate::{
3535
attack::handle_attack_event,
3636
inventory::{InventoryComponent, InventorySet},
37-
local_player::{
38-
handle_send_packet_event, LocalGameMode, PermissionLevel, PlayerAbilities, SendPacketEvent,
39-
},
37+
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities},
4038
movement::MoveEventsSet,
39+
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
4140
respawn::perform_respawn,
4241
Client,
4342
};

azalea-client/src/inventory.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ use bevy_ecs::{
2626
use tracing::warn;
2727

2828
use crate::{
29-
local_player::{handle_send_packet_event, PlayerAbilities, SendPacketEvent},
29+
local_player::PlayerAbilities,
30+
packet_handling::game::{handle_send_packet_event, SendPacketEvent},
3031
respawn::perform_respawn,
3132
Client,
3233
};

azalea-client/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub use client::{
3636
start_ecs_runner, Client, DefaultPlugins, JoinError, JoinedClientBundle, TickBroadcast,
3737
};
3838
pub use events::Event;
39-
pub use local_player::{GameProfileComponent, InstanceHolder, SendPacketEvent, TabList};
39+
pub use local_player::{GameProfileComponent, InstanceHolder, TabList};
4040
pub use movement::{
4141
PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
4242
};

azalea-client/src/local_player.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -160,24 +160,3 @@ impl<T> From<std::sync::PoisonError<T>> for HandlePacketError {
160160
HandlePacketError::Poison(e.to_string())
161161
}
162162
}
163-
164-
/// Event for sending a packet to the server.
165-
#[derive(Event)]
166-
pub struct SendPacketEvent {
167-
pub entity: Entity,
168-
pub packet: ServerboundGamePacket,
169-
}
170-
171-
pub fn handle_send_packet_event(
172-
mut send_packet_events: EventReader<SendPacketEvent>,
173-
mut query: Query<&mut RawConnection>,
174-
) {
175-
for event in send_packet_events.read() {
176-
if let Ok(raw_connection) = query.get_mut(event.entity) {
177-
// debug!("Sending packet: {:?}", event.packet);
178-
if let Err(e) = raw_connection.write_packet(event.packet.clone()) {
179-
error!("Failed to send packet: {e}");
180-
}
181-
}
182-
}
183-
}

azalea-client/src/mining.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ use crate::{
1717
HitResultComponent, SwingArmEvent,
1818
},
1919
inventory::{InventoryComponent, InventorySet},
20-
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities, SendPacketEvent},
20+
local_player::{LocalGameMode, PermissionLevel, PlayerAbilities},
2121
movement::MoveEventsSet,
22+
packet_handling::game::SendPacketEvent,
2223
Client,
2324
};
2425

azalea-client/src/movement.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::client::Client;
2-
use crate::local_player::SendPacketEvent;
2+
use crate::packet_handling::game::SendPacketEvent;
33
use azalea_core::position::Vec3;
44
use azalea_entity::{metadata::Sprinting, Attributes, Jumping};
55
use azalea_entity::{InLoadedChunk, LastSentPosition, LookDirection, Physics, Position};

azalea-client/src/packet_handling/configuration.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::packet_handling::game::KeepAliveEvent;
2222
use crate::raw_connection::RawConnection;
2323

2424
#[derive(Event, Debug, Clone)]
25-
pub struct PacketEvent {
25+
pub struct ConfigurationPacketEvent {
2626
/// The client entity that received the packet.
2727
pub entity: Entity,
2828
/// The packet that was actually received.
@@ -31,7 +31,7 @@ pub struct PacketEvent {
3131

3232
pub fn send_packet_events(
3333
query: Query<(Entity, &RawConnection), With<InConfigurationState>>,
34-
mut packet_events: ResMut<Events<PacketEvent>>,
34+
mut packet_events: ResMut<Events<ConfigurationPacketEvent>>,
3535
) {
3636
// we manually clear and send the events at the beginning of each update
3737
// since otherwise it'd cause issues with events in process_packet_events
@@ -51,7 +51,7 @@ pub fn send_packet_events(
5151
continue;
5252
}
5353
};
54-
packet_events.send(PacketEvent {
54+
packet_events.send(ConfigurationPacketEvent {
5555
entity: player_entity,
5656
packet,
5757
});
@@ -64,9 +64,10 @@ pub fn send_packet_events(
6464

6565
pub fn process_packet_events(ecs: &mut World) {
6666
let mut events_owned = Vec::new();
67-
let mut system_state: SystemState<EventReader<PacketEvent>> = SystemState::new(ecs);
67+
let mut system_state: SystemState<EventReader<ConfigurationPacketEvent>> =
68+
SystemState::new(ecs);
6869
let mut events = system_state.get_mut(ecs);
69-
for PacketEvent {
70+
for ConfigurationPacketEvent {
7071
entity: player_entity,
7172
packet,
7273
} in events.read()

0 commit comments

Comments
 (0)