Skip to content

Commit 6399270

Browse files
the server can now handle client timeouts
1 parent f16adf0 commit 6399270

File tree

4 files changed

+132
-87
lines changed

4 files changed

+132
-87
lines changed

src/bin/src/packet_handlers/login_process.rs

+61-32
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use ferrumc_net::packets::incoming::login_acknowledged::LoginAcknowledgedEvent;
88
use ferrumc_net::packets::incoming::login_start::LoginStartEvent;
99
use ferrumc_net::packets::incoming::server_bound_known_packs::ServerBoundKnownPacksEvent;
1010
use ferrumc_net::packets::outgoing::client_bound_known_packs::ClientBoundKnownPacksPacket;
11+
use ferrumc_net::packets::outgoing::finish_configuration::FinishConfigurationPacket;
1112
use ferrumc_net::packets::outgoing::game_event::GameEventPacket;
12-
use ferrumc_net::packets::outgoing::keep_alive::{KeepAlive, KeepAlivePacket};
13+
use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket;
1314
use ferrumc_net::packets::outgoing::login_play::LoginPlayPacket;
1415
use ferrumc_net::packets::outgoing::login_success::LoginSuccessPacket;
1516
use ferrumc_net::packets::outgoing::registry_data::get_registry_packets;
@@ -18,7 +19,6 @@ use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlay
1819
use ferrumc_net::GlobalState;
1920
use ferrumc_net_codec::encode::NetEncodeOpts;
2021
use tracing::{debug, trace};
21-
use ferrumc_net::packets::outgoing::finish_configuration::FinishConfigurationPacket;
2222

2323
#[event_handler]
2424
async fn handle_login_start(
@@ -31,19 +31,23 @@ async fn handle_login_start(
3131
let username = login_start_event.login_start_packet.username.as_str();
3232
debug!("Received login start from user with username {}", username);
3333

34-
3534
// Add the player identity component to the ECS for the entity.
3635
state.universe.add_component::<PlayerIdentity>(
3736
login_start_event.conn_id,
3837
PlayerIdentity::new(username.to_string(), uuid),
3938
)?;
40-
39+
4140
//Send a Login Success Response to further the login sequence
4241
let mut writer = state
4342
.universe
4443
.get_mut::<StreamWriter>(login_start_event.conn_id)?;
4544

46-
writer.send_packet(&LoginSuccessPacket::new(uuid, username), &NetEncodeOpts::WithLength).await?;
45+
writer
46+
.send_packet(
47+
&LoginSuccessPacket::new(uuid, username),
48+
&NetEncodeOpts::WithLength,
49+
)
50+
.await?;
4751

4852
Ok(login_start_event)
4953
}
@@ -62,15 +66,16 @@ async fn handle_login_acknowledged(
6266

6367
*connection_state = ConnectionState::Configuration;
6468

65-
6669
// Send packets packet
6770
let client_bound_known_packs = ClientBoundKnownPacksPacket::new();
6871

6972
let mut writer = state
7073
.universe
7174
.get_mut::<StreamWriter>(login_acknowledged_event.conn_id)?;
7275

73-
writer.send_packet(&client_bound_known_packs, &NetEncodeOpts::WithLength).await?;
76+
writer
77+
.send_packet(&client_bound_known_packs, &NetEncodeOpts::WithLength)
78+
.await?;
7479

7580
Ok(login_acknowledged_event)
7681
}
@@ -87,10 +92,17 @@ async fn handle_server_bound_known_packs(
8792
.get_mut::<StreamWriter>(server_bound_known_packs_event.conn_id)?;
8893

8994
let registry_packets = get_registry_packets();
90-
writer.send_packet(&registry_packets, &NetEncodeOpts::None).await?;
91-
92-
writer.send_packet(&FinishConfigurationPacket::new(), &NetEncodeOpts::WithLength).await?;
93-
95+
writer
96+
.send_packet(&registry_packets, &NetEncodeOpts::None)
97+
.await?;
98+
99+
writer
100+
.send_packet(
101+
&FinishConfigurationPacket::new(),
102+
&NetEncodeOpts::WithLength,
103+
)
104+
.await?;
105+
94106
Ok(server_bound_known_packs_event)
95107
}
96108

@@ -103,34 +115,51 @@ async fn handle_ack_finish_configuration(
103115

104116
let conn_id = ack_finish_configuration_event.conn_id;
105117

106-
let mut conn_state = state
107-
.universe
108-
.get_mut::<ConnectionState>(conn_id)?;
118+
let mut conn_state = state.universe.get_mut::<ConnectionState>(conn_id)?;
109119

110120
*conn_state = ConnectionState::Play;
111121

112-
let mut writer = state
113-
.universe
114-
.get_mut::<StreamWriter>(conn_id)?;
115-
116-
writer.send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength).await?;
117-
writer.send_packet(&SetDefaultSpawnPositionPacket::default(), &NetEncodeOpts::WithLength).await?;
118-
writer.send_packet(&SynchronizePlayerPositionPacket::default(), &NetEncodeOpts::WithLength).await?;
119-
writer.send_packet(&GameEventPacket::start_waiting_for_level_chunks(), &NetEncodeOpts::WithLength).await?;
122+
let mut writer = state.universe.get_mut::<StreamWriter>(conn_id)?;
123+
124+
writer
125+
.send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength)
126+
.await?;
127+
writer
128+
.send_packet(
129+
&SetDefaultSpawnPositionPacket::default(),
130+
&NetEncodeOpts::WithLength,
131+
)
132+
.await?;
133+
writer
134+
.send_packet(
135+
&SynchronizePlayerPositionPacket::default(),
136+
&NetEncodeOpts::WithLength,
137+
)
138+
.await?;
139+
writer
140+
.send_packet(
141+
&GameEventPacket::start_waiting_for_level_chunks(),
142+
&NetEncodeOpts::WithLength,
143+
)
144+
.await?;
120145

121146
send_keep_alive(conn_id, state, &mut writer).await?;
122147

123-
124148
Ok(ack_finish_configuration_event)
125149
}
126-
async fn send_keep_alive(conn_id: usize, state: GlobalState, writer: &mut ComponentRefMut<'_, StreamWriter>) -> Result<(), NetError> {
127-
let keep_alive_packet = KeepAlivePacket::default();
128-
writer.send_packet(&keep_alive_packet, &NetEncodeOpts::WithLength).await?;
129-
130-
let id = keep_alive_packet.id;
131-
132-
state.universe.add_component::<KeepAlive>(conn_id, id)?;
133-
150+
async fn send_keep_alive(
151+
conn_id: usize,
152+
state: GlobalState,
153+
writer: &mut ComponentRefMut<'_, StreamWriter>,
154+
) -> Result<(), NetError> {
155+
let keep_alive_packet = OutgoingKeepAlivePacket::default();
156+
writer
157+
.send_packet(&keep_alive_packet, &NetEncodeOpts::WithLength)
158+
.await?;
159+
160+
state
161+
.universe
162+
.add_component::<OutgoingKeepAlivePacket>(conn_id, keep_alive_packet)?;
134163

135164
Ok(())
136-
}
165+
}

src/bin/src/systems/keep_alive_system.rs

+33-25
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::systems::definition::System;
22
use async_trait::async_trait;
33
use ferrumc_core::identity::player_identity::PlayerIdentity;
44
use ferrumc_net::connection::{ConnectionState, StreamWriter};
5-
use ferrumc_net::packets::outgoing::keep_alive::{KeepAlive, KeepAlivePacket};
5+
use ferrumc_net::packets::incoming::keep_alive::IncomingKeepAlivePacket;
6+
use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket;
67
use ferrumc_net::utils::broadcast::{BroadcastOptions, BroadcastToAll};
78
use ferrumc_net::GlobalState;
89
use std::sync::atomic::{AtomicBool, Ordering};
@@ -20,6 +21,7 @@ impl KeepAliveSystem {
2021
}
2122
}
2223
}
24+
const FIFTEEN_SECONDS_MS: i64 = 15000; // 15 seconds in milliseconds
2325

2426
#[async_trait]
2527
impl System for KeepAliveSystem {
@@ -29,11 +31,7 @@ impl System for KeepAliveSystem {
2931
.duration_since(std::time::UNIX_EPOCH)
3032
.expect("Time went backwards")
3133
.as_millis() as i64;
32-
loop {
33-
if self.shutdown.load(Ordering::Relaxed) {
34-
break;
35-
}
36-
34+
while !self.shutdown.load(Ordering::Relaxed) {
3735
let online_players = state.universe.query::<&PlayerIdentity>();
3836

3937
let current_time = std::time::SystemTime::now()
@@ -46,19 +44,24 @@ impl System for KeepAliveSystem {
4644
last_time = current_time;
4745
}
4846

49-
let fifteen_seconds_ms = 15000; // 15 seconds in milliseconds
50-
5147
let entities = state
5248
.universe
53-
.query::<(&mut StreamWriter, &ConnectionState, &KeepAlive)>()
49+
.query::<(
50+
&mut StreamWriter,
51+
&ConnectionState,
52+
&IncomingKeepAlivePacket,
53+
)>()
5454
.into_entities()
5555
.into_iter()
5656
.filter_map(|entity| {
5757
let conn_state = state.universe.get::<ConnectionState>(entity).ok()?;
58-
let keep_alive = state.universe.get_mut::<KeepAlive>(entity).ok()?;
58+
let keep_alive = state
59+
.universe
60+
.get_mut::<IncomingKeepAlivePacket>(entity)
61+
.ok()?;
5962

6063
if matches!(*conn_state, ConnectionState::Play)
61-
&& (current_time - keep_alive.id) >= fifteen_seconds_ms
64+
&& (current_time - keep_alive.id) >= FIFTEEN_SECONDS_MS
6265
{
6366
Some(entity)
6467
} else {
@@ -68,24 +71,29 @@ impl System for KeepAliveSystem {
6871
.collect::<Vec<_>>();
6972
if !entities.is_empty() {
7073
trace!("there are {:?} players to keep alive", entities.len());
71-
}
7274

73-
let packet = KeepAlivePacket::default();
75+
let packet = OutgoingKeepAlivePacket { id: current_time };
7476

75-
let broadcast_opts = BroadcastOptions::default()
76-
.only(entities)
77-
.with_sync_callback(move |entity, state| {
78-
let Ok(mut keep_alive) = state.universe.get_mut::<KeepAlive>(entity) else {
79-
warn!("Failed to get <KeepAlive> component for entity {}", entity);
80-
return;
81-
};
77+
let broadcast_opts = BroadcastOptions::default()
78+
.only(entities)
79+
.with_sync_callback(move |entity, state| {
80+
let Ok(mut outgoing_keep_alive) =
81+
state.universe.get_mut::<OutgoingKeepAlivePacket>(entity)
82+
else {
83+
warn!(
84+
"Failed to get <OutgoingKeepAlive> component for entity {}",
85+
entity
86+
);
87+
return;
88+
};
8289

83-
*keep_alive = KeepAlive::from(current_time);
84-
});
90+
*outgoing_keep_alive = OutgoingKeepAlivePacket { id: current_time };
91+
});
8592

86-
if let Err(e) = state.broadcast(&packet, broadcast_opts).await {
87-
error!("Error sending keep alive packet: {}", e);
88-
};
93+
if let Err(e) = state.broadcast(&packet, broadcast_opts).await {
94+
error!("Error sending keep alive packet: {}", e);
95+
};
96+
}
8997
// TODO, this should be configurable as some people may have bad network so the clients may end up disconnecting from the server moments before the keep alive is sent
9098
tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
9199
}

src/lib/net/src/packets/incoming/keep_alive.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use crate::packets::outgoing::keep_alive::KeepAlive;
1+
use crate::packets::outgoing::keep_alive::OutgoingKeepAlivePacket;
22
use crate::packets::IncomingPacket;
33
use crate::{NetResult, ServerState};
4+
use ferrumc_ecs::components::storage::ComponentRefMut;
5+
use ferrumc_ecs::errors::ECSError;
46
use ferrumc_macros::{packet, NetDecode};
57
use std::sync::Arc;
6-
use tracing::debug;
8+
use tracing::{debug, warn};
79

810
#[derive(NetDecode)]
911
#[packet(packet_id = 0x18, state = "play")]
@@ -13,15 +15,42 @@ pub struct IncomingKeepAlivePacket {
1315

1416
impl IncomingPacket for IncomingKeepAlivePacket {
1517
async fn handle(self, conn_id: usize, state: Arc<ServerState>) -> NetResult<()> {
16-
let mut last_keep_alive = state.universe.get_mut::<KeepAlive>(conn_id)?;
18+
// TODO handle errors.
19+
let last_keep_alive = state.universe.get_mut::<OutgoingKeepAlivePacket>(conn_id)?;
20+
1721
if self.id != last_keep_alive.id {
1822
debug!(
19-
"Invalid keep alive packet received from {:?} with id {:?} (expected {:?})",
23+
"Invalid keep alive packet received from entity {:?} with id {:?} (expected {:?})",
2024
conn_id, self.id, last_keep_alive.id
2125
);
26+
return NetResult::Err(crate::errors::NetError::Packet(
27+
crate::errors::PacketError::InvalidState(0x18),
28+
));
2229
// TODO Kick player
30+
}
31+
32+
let result = state.universe.get_mut::<IncomingKeepAlivePacket>(conn_id);
33+
34+
if result.is_err() {
35+
let err = result.as_ref().err().unwrap();
36+
if matches!(err, ECSError::ComponentTypeNotFound) {
37+
state
38+
.universe
39+
.add_component(conn_id, IncomingKeepAlivePacket { id: self.id })?;
40+
let mut last_received_keep_alive = state.universe.get_mut(conn_id)?;
41+
*last_received_keep_alive = self;
42+
} else {
43+
warn!(
44+
"Failed to get or create <IncomingKeepAlive> component: {:?}",
45+
err
46+
);
47+
return Err(crate::errors::NetError::ECSError(result.err().unwrap()));
48+
}
2349
} else {
24-
*last_keep_alive = KeepAlive::from(self.id);
50+
let mut last_received_keep_alive: ComponentRefMut<'_, IncomingKeepAlivePacket> =
51+
result.unwrap();
52+
53+
*last_received_keep_alive = self;
2554
}
2655

2756
Ok(())
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,18 @@
11
use ferrumc_macros::{packet, NetEncode};
22
use std::io::Write;
33

4-
#[derive(Debug, NetEncode)]
5-
pub struct KeepAlive {
6-
pub id: i64,
7-
}
8-
9-
mod adapters {
10-
impl From<i64> for super::KeepAlive {
11-
fn from(id: i64) -> Self {
12-
Self { id }
13-
}
14-
}
15-
}
16-
174
#[derive(NetEncode)]
185
#[packet(packet_id = 0x26)]
19-
pub struct KeepAlivePacket {
20-
pub id: KeepAlive,
6+
pub struct OutgoingKeepAlivePacket {
7+
pub id: i64,
218
}
229

23-
impl Default for KeepAlivePacket {
10+
impl Default for OutgoingKeepAlivePacket {
2411
fn default() -> Self {
2512
let current_ms = std::time::SystemTime::now()
2613
.duration_since(std::time::UNIX_EPOCH)
2714
.expect("Time went backwards?? LMAO")
2815
.as_millis() as i64;
29-
Self::new(current_ms)
30-
}
31-
}
32-
33-
impl KeepAlivePacket {
34-
pub fn new(id: i64) -> Self {
35-
Self {
36-
id: KeepAlive::from(id),
37-
}
16+
Self { id: current_ms }
3817
}
3918
}

0 commit comments

Comments
 (0)