Skip to content

Commit c20941e

Browse files
authored
Merge pull request #223 from Sunnickel/fix/fix-disconnect
Fix: Disconnecting
2 parents 2632960 + ad5af47 commit c20941e

File tree

5 files changed

+167
-103
lines changed

5 files changed

+167
-103
lines changed

src/bin/src/systems/connection_killer.rs

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,52 @@ pub fn connection_killer(
1212
state: Res<GlobalStateResource>,
1313
) {
1414
while let Some((disconnecting_entity, reason)) = state.0.players.disconnection_queue.pop() {
15-
let entity_result = query.get(disconnecting_entity);
16-
match entity_result {
17-
Ok(disconnecting_player) => {
18-
for (entity, conn, player_identity) in query.iter() {
19-
if disconnecting_entity == entity {
20-
info!(
21-
"Player {} ({}) disconnected: {}",
22-
player_identity.username,
23-
player_identity.uuid,
24-
reason.as_deref().unwrap_or("No reason")
15+
let disconnecting_player_identity = query
16+
.get(disconnecting_entity)
17+
.ok()
18+
.map(|(_, _, identity)| identity.clone());
19+
20+
if disconnecting_player_identity.is_none() {
21+
warn!("Player's entity has already been removed");
22+
continue;
23+
}
24+
25+
let disconnecting_player_identity = disconnecting_player_identity.unwrap();
26+
27+
for (entity, conn, player_identity) in query.iter() {
28+
if disconnecting_entity == entity {
29+
info!(
30+
"Player {} ({}) disconnected: {}",
31+
player_identity.username,
32+
player_identity.uuid,
33+
reason.as_deref().unwrap_or("No reason")
34+
);
35+
if conn.running.load(std::sync::atomic::Ordering::Relaxed) {
36+
trace!(
37+
"Sending disconnect packet to player {}",
38+
player_identity.username
39+
);
40+
if let Err(e) = conn.send_packet_ref(
41+
&ferrumc_net::packets::outgoing::disconnect::DisconnectPacket {
42+
reason: TextComponent::from(
43+
reason.as_deref().unwrap_or("Disconnected"),
44+
),
45+
},
46+
) {
47+
warn!(
48+
"Failed to send disconnect packet to player {}: {:?}",
49+
player_identity.username, e
2550
);
26-
if conn.running.load(std::sync::atomic::Ordering::Relaxed) {
27-
trace!(
28-
"Sending disconnect packet to player {}",
29-
player_identity.username
30-
);
31-
if let Err(e) = conn.send_packet_ref(
32-
&ferrumc_net::packets::outgoing::disconnect::DisconnectPacket {
33-
reason: TextComponent::from(
34-
reason.as_deref().unwrap_or("Disconnected"),
35-
),
36-
},
37-
) {
38-
warn!(
39-
"Failed to send disconnect packet to player {}: {:?}",
40-
player_identity.username, e
41-
);
42-
}
43-
} else {
44-
trace!(
51+
}
52+
} else {
53+
trace!(
4554
"Connection for player {} is not running, skipping disconnect packet",
4655
player_identity.username
4756
);
48-
}
49-
} else {
50-
system_messages::player_leave::handle(disconnecting_player.2, entity);
51-
}
52-
cmd.entity(entity).despawn();
5357
}
54-
}
55-
Err(e) => {
56-
warn!("Player's entity has already been removed: {}", e);
58+
cmd.entity(entity).despawn();
59+
} else {
60+
system_messages::player_leave::handle(&disconnecting_player_identity, entity);
5761
}
5862
}
5963
}

src/bin/src/systems/keep_alive_system.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ pub fn keep_alive_system(
1919
.running
2020
.load(std::sync::atomic::Ordering::Relaxed)
2121
{
22+
if state.0.players.is_connected(entity) {
23+
state.0.players.disconnect(entity, None);
24+
}
2225
continue;
2326
}
2427

src/bin/src/systems/new_connections.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use ferrumc_core::transform::position::Position;
88
use ferrumc_core::transform::rotation::Rotation;
99
use ferrumc_inventories::hotbar::Hotbar;
1010
use ferrumc_inventories::inventory::Inventory;
11-
use ferrumc_net::connection::NewConnection;
11+
use ferrumc_net::connection::{DisconnectHandle, NewConnection};
1212
use ferrumc_state::GlobalStateResource;
1313
use std::time::Instant;
1414
use tracing::{error, trace};
@@ -28,6 +28,9 @@ pub fn accept_new_connections(
2828
let return_sender = new_connection.entity_return;
2929
let entity = cmd.spawn((
3030
new_connection.stream,
31+
DisconnectHandle {
32+
sender: Some(new_connection.disconnect_handle),
33+
},
3134
Position::default(),
3235
ChunkReceiver::default(),
3336
Rotation::default(),

src/lib/net/src/conn_init/login.rs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -210,21 +210,27 @@ pub(super) async fn login(
210210

211211
// =============================================================================================
212212
// 13 Await client's teleport acceptance
213-
let mut skel = PacketSkeleton::new(conn_read, compressed, Play).await?;
213+
// The client may send other packets (like client_tick_end) before accepting the teleport,
214+
// so we loop until we get the accept_teleportation packet
214215
let expected_id = lookup_packet!("play", "serverbound", "accept_teleportation");
215-
if skel.id != expected_id {
216-
return Err(NetError::Packet(PacketError::UnexpectedPacket {
217-
expected: expected_id,
218-
received: skel.id,
219-
state: Play,
220-
}));
221-
}
222-
223-
let confirm_player_teleport =
224-
crate::packets::incoming::confirm_player_teleport::ConfirmPlayerTeleport::decode(
225-
&mut skel.data,
226-
&NetDecodeOpts::None,
227-
)?;
216+
let confirm_player_teleport = loop {
217+
let mut skel = PacketSkeleton::new(conn_read, compressed, Play).await?;
218+
if skel.id == expected_id {
219+
// Got the teleport confirmation
220+
let confirm =
221+
crate::packets::incoming::confirm_player_teleport::ConfirmPlayerTeleport::decode(
222+
&mut skel.data,
223+
&NetDecodeOpts::None,
224+
)?;
225+
break confirm;
226+
} else {
227+
// Client sent another packet before confirming teleport - just ignore it
228+
trace!(
229+
"Ignoring packet 0x{:02X} while waiting for teleport confirmation",
230+
skel.id
231+
);
232+
}
233+
};
228234

229235
if confirm_player_teleport.teleport_id.0 != teleport_id_i32 {
230236
error!(
@@ -235,21 +241,25 @@ pub(super) async fn login(
235241

236242
// =============================================================================================
237243
// 14 Receive first movement packet from player
238-
let mut skel = PacketSkeleton::new(conn_read, compressed, Play).await?;
244+
// Similarly, the client may send other packets before the movement packet
239245
let expected_id = lookup_packet!("play", "serverbound", "move_player_pos_rot");
240-
if skel.id != expected_id {
241-
return Err(NetError::Packet(PacketError::UnexpectedPacket {
242-
expected: expected_id,
243-
received: skel.id,
244-
state: Play,
245-
}));
246-
}
247-
248-
let _player_pos_and_rot =
249-
crate::packets::incoming::set_player_position_and_rotation::SetPlayerPositionAndRotationPacket::decode(
250-
&mut skel.data,
251-
&NetDecodeOpts::None,
252-
)?;
246+
let _player_pos_and_rot = loop {
247+
let mut skel = PacketSkeleton::new(conn_read, compressed, Play).await?;
248+
249+
if skel.id == expected_id {
250+
let pos_rot = crate::packets::incoming::set_player_position_and_rotation::SetPlayerPositionAndRotationPacket::decode(
251+
&mut skel.data,
252+
&NetDecodeOpts::None,
253+
)?;
254+
break pos_rot;
255+
} else {
256+
// Client sent another packet before movement - ignore it
257+
trace!(
258+
"Ignoring packet 0x{:02X} while waiting for initial movement packet",
259+
skel.id
260+
);
261+
}
262+
};
253263

254264
// =============================================================================================
255265
// 15 Send initial game event (e.g., "change game mode")

0 commit comments

Comments
 (0)