Skip to content

Commit

Permalink
Merge branch 'rewrite/v3' into fix/keep_alive
Browse files Browse the repository at this point in the history
  • Loading branch information
AnonymousBit0111 authored Nov 11, 2024
2 parents edffdf4 + 68ee9f5 commit 720d332
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 121 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ bzip2 = "0.4.1"
# CLI
clap = "4.5.20"
indicatif = "0.17.8"
colored = "2.1.0"

# Misc
deepsize = "0.2.0"
Expand Down
93 changes: 32 additions & 61 deletions src/bin/src/packet_handlers/login_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ use ferrumc_net::packets::incoming::login_acknowledged::LoginAcknowledgedEvent;
use ferrumc_net::packets::incoming::login_start::LoginStartEvent;
use ferrumc_net::packets::incoming::server_bound_known_packs::ServerBoundKnownPacksEvent;
use ferrumc_net::packets::outgoing::client_bound_known_packs::ClientBoundKnownPacksPacket;
use ferrumc_net::packets::outgoing::finish_configuration::FinishConfigurationPacket;
use ferrumc_net::packets::outgoing::game_event::GameEventPacket;
use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket;
use ferrumc_net::packets::outgoing::keep_alive::{KeepAlive, KeepAlivePacket};
use ferrumc_net::packets::outgoing::login_play::LoginPlayPacket;
use ferrumc_net::packets::outgoing::login_success::LoginSuccessPacket;
use ferrumc_net::packets::outgoing::registry_data::get_registry_packets;
Expand All @@ -19,6 +18,7 @@ use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlay
use ferrumc_net::GlobalState;
use ferrumc_net_codec::encode::NetEncodeOpts;
use tracing::{debug, trace};
use ferrumc_net::packets::outgoing::finish_configuration::FinishConfigurationPacket;

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


// Add the player identity component to the ECS for the entity.
state.universe.add_component::<PlayerIdentity>(
login_start_event.conn_id,
PlayerIdentity::new(username.to_string(), uuid),
)?;

//Send a Login Success Response to further the login sequence
let mut writer = state
.universe
.get_mut::<StreamWriter>(login_start_event.conn_id)?;

writer
.send_packet(
&LoginSuccessPacket::new(uuid, username),
&NetEncodeOpts::WithLength,
)
.await?;
writer.send_packet(&LoginSuccessPacket::new(uuid, username), &NetEncodeOpts::WithLength).await?;

Ok(login_start_event)
}
Expand All @@ -66,16 +62,15 @@ async fn handle_login_acknowledged(

*connection_state = ConnectionState::Configuration;


// Send packets packet
let client_bound_known_packs = ClientBoundKnownPacksPacket::new();

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

writer
.send_packet(&client_bound_known_packs, &NetEncodeOpts::WithLength)
.await?;
writer.send_packet(&client_bound_known_packs, &NetEncodeOpts::WithLength).await?;

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

let registry_packets = get_registry_packets();
writer
.send_packet(&registry_packets, &NetEncodeOpts::None)
.await?;

writer
.send_packet(
&FinishConfigurationPacket::new(),
&NetEncodeOpts::WithLength,
)
.await?;

writer.send_packet(&registry_packets, &NetEncodeOpts::None).await?;

writer.send_packet(&FinishConfigurationPacket::new(), &NetEncodeOpts::WithLength).await?;

Ok(server_bound_known_packs_event)
}

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

let conn_id = ack_finish_configuration_event.conn_id;

let mut conn_state = state.universe.get_mut::<ConnectionState>(conn_id)?;
let mut conn_state = state
.universe
.get_mut::<ConnectionState>(conn_id)?;

*conn_state = ConnectionState::Play;

let mut writer = state.universe.get_mut::<StreamWriter>(conn_id)?;

writer
.send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength)
.await?;
writer
.send_packet(
&SetDefaultSpawnPositionPacket::default(),
&NetEncodeOpts::WithLength,
)
.await?;
writer
.send_packet(
&SynchronizePlayerPositionPacket::default(),
&NetEncodeOpts::WithLength,
)
.await?;
writer
.send_packet(
&GameEventPacket::start_waiting_for_level_chunks(),
&NetEncodeOpts::WithLength,
)
.await?;
let mut writer = state
.universe
.get_mut::<StreamWriter>(conn_id)?;

writer.send_packet(&LoginPlayPacket::new(conn_id), &NetEncodeOpts::WithLength).await?;
writer.send_packet(&SetDefaultSpawnPositionPacket::default(), &NetEncodeOpts::WithLength).await?;
writer.send_packet(&SynchronizePlayerPositionPacket::default(), &NetEncodeOpts::WithLength).await?;
writer.send_packet(&GameEventPacket::start_waiting_for_level_chunks(), &NetEncodeOpts::WithLength).await?;

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


Ok(ack_finish_configuration_event)
}
async fn send_keep_alive(
conn_id: usize,
state: GlobalState,
writer: &mut ComponentRefMut<'_, StreamWriter>,
) -> Result<(), NetError> {
let keep_alive_packet = OutgoingKeepAlivePacket::default();
writer
.send_packet(&keep_alive_packet, &NetEncodeOpts::WithLength)
.await?;

state
.universe
.add_component::<OutgoingKeepAlivePacket>(conn_id, keep_alive_packet)?;
async fn send_keep_alive(conn_id: usize, state: GlobalState, writer: &mut ComponentRefMut<'_, StreamWriter>) -> Result<(), NetError> {
let keep_alive_packet = KeepAlivePacket::default();
writer.send_packet(&keep_alive_packet, &NetEncodeOpts::WithLength).await?;

let id = keep_alive_packet.id;

state.universe.add_component::<KeepAlive>(conn_id, id)?;


Ok(())
}
}
58 changes: 25 additions & 33 deletions src/bin/src/systems/keep_alive_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use crate::systems::definition::System;
use async_trait::async_trait;
use ferrumc_core::identity::player_identity::PlayerIdentity;
use ferrumc_net::connection::{ConnectionState, StreamWriter};
use ferrumc_net::packets::incoming::keep_alive::IncomingKeepAlivePacket;
use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket;
use ferrumc_net::packets::outgoing::keep_alive::{KeepAlive, KeepAlivePacket};
use ferrumc_net::utils::broadcast::{BroadcastOptions, BroadcastToAll};
use ferrumc_net::GlobalState;
use std::sync::atomic::{AtomicBool, Ordering};
Expand All @@ -21,7 +20,6 @@ impl KeepAliveSystem {
}
}
}
const FIFTEEN_SECONDS_MS: i64 = 15000; // 15 seconds in milliseconds

#[async_trait]
impl System for KeepAliveSystem {
Expand All @@ -31,7 +29,11 @@ impl System for KeepAliveSystem {
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as i64;
while !self.shutdown.load(Ordering::Relaxed) {
loop {
if self.shutdown.load(Ordering::Relaxed) {
break;
}

let online_players = state.universe.query::<&PlayerIdentity>();

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

let fifteen_seconds_ms = 15000; // 15 seconds in milliseconds

let entities = state
.universe
.query::<(
&mut StreamWriter,
&ConnectionState,
&IncomingKeepAlivePacket,
)>()
.query::<(&mut StreamWriter, &ConnectionState, &KeepAlive)>()
.into_entities()
.into_iter()
.filter_map(|entity| {
let conn_state = state.universe.get::<ConnectionState>(entity).ok()?;
let keep_alive = state
.universe
.get_mut::<IncomingKeepAlivePacket>(entity)
.ok()?;
let keep_alive = state.universe.get_mut::<KeepAlive>(entity).ok()?;

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

let packet = OutgoingKeepAlivePacket { id: current_time };
let packet = KeepAlivePacket::default();

let broadcast_opts = BroadcastOptions::default()
.only(entities)
.with_sync_callback(move |entity, state| {
let Ok(mut outgoing_keep_alive) =
state.universe.get_mut::<OutgoingKeepAlivePacket>(entity)
else {
warn!(
"Failed to get <OutgoingKeepAlive> component for entity {}",
entity
);
return;
};
let broadcast_opts = BroadcastOptions::default()
.only(entities)
.with_sync_callback(move |entity, state| {
let Ok(mut keep_alive) = state.universe.get_mut::<KeepAlive>(entity) else {
warn!("Failed to get <KeepAlive> component for entity {}", entity);
return;
};

*outgoing_keep_alive = OutgoingKeepAlivePacket { id: current_time };
});
*keep_alive = KeepAlive::from(current_time);
});

if let Err(e) = state.broadcast(&packet, broadcast_opts).await {
error!("Error sending keep alive packet: {}", e);
};
}
if let Err(e) = state.broadcast(&packet, broadcast_opts).await {
error!("Error sending keep alive packet: {}", e);
};
// 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
tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
}
Expand Down
5 changes: 5 additions & 0 deletions src/lib/derive_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ name = "ferrumc-macros"
version = "0.1.0"
edition = "2021"

[features]
default = ["colors"]
colors = []

[lib]
proc-macro = true

[dependencies]
colored = { workspace = true }
quote = { workspace = true }
syn = { workspace = true, features = ["full"] }
thiserror = { workspace = true }
Expand Down
32 changes: 24 additions & 8 deletions src/lib/derive_macros/src/net/packets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ use quote::quote;
use std::env;
use std::ops::Add;
use syn::{parse_macro_input, LitInt, LitStr};
use colored::Colorize;

/// Essentially, this just reads all the files in the directory and generates a match arm for each packet.
/// (packet_id, state) => { ... }
pub fn bake_registry(input: TokenStream) -> TokenStream {
#[cfg(feature = "colors")]
colored::control::set_override(true);

let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let module_path = parse_macro_input!(input as syn::LitStr).value();

Expand All @@ -18,7 +22,11 @@ pub fn bake_registry(input: TokenStream) -> TokenStream {
let base_path = module_path.split("\\").collect::<Vec<&str>>()[2..].join("::");
let base_path = format!("crate::{}", base_path);

println!("[FERRUMC_MACROS] Parsing packets in {}", dir_path.display());
println!(
" {} {}",
"[FERRUMC_MACROS]".blue().bold(),
format!("Parsing packets in {}", dir_path.display()).white().bold()
);

if !std::fs::metadata(dir_path).unwrap().is_dir() {
return TokenStream::from(quote! {
Expand Down Expand Up @@ -90,17 +98,20 @@ pub fn bake_registry(input: TokenStream) -> TokenStream {
let struct_name = &item_struct.ident;

println!(
"[FERRUMC_MACROS] Found Packet (ID: 0x{:02X}, State: {}, Struct Name: {})",
packet_id, state, struct_name
" {} {} (ID: {}, State: {}, Struct Name: {})",
"[FERRUMC_MACROS]".bold().blue(),
"Found Packet".white().bold(),
format!("0x{:02X}", packet_id).cyan(),
state.green(),
struct_name.to_string().yellow()
);

let path = format!(
// "crate::net::packets::incoming::{}",
"{}::{}",
base_path,
file_name.to_string_lossy().replace(".rs", "")
);

let struct_path = format!("{}::{}", path, struct_name);

let struct_path = syn::parse_str::<syn::Path>(&struct_path).expect("parse_str failed");
Expand All @@ -119,10 +130,15 @@ pub fn bake_registry(input: TokenStream) -> TokenStream {
}

let elapsed = start.elapsed();
println!("[FERRUMC_MACROS] Found {} packets", match_arms.len());
println!(
"[FERRUMC_MACROS] It took: {:?} to parse all the files and generate the packet registry",
elapsed
" {} {}",
"[FERRUMC_MACROS]".bold().blue(),
format!("Found {} packets", match_arms.len()).purple().bold()
);
println!(
" {} {}",
"[FERRUMC_MACROS]".bold().blue(),
format!("It took: {:?} to parse all the files and generate the packet registry", elapsed).red().bold()
);

let match_arms = match_arms.into_iter();
Expand Down
Loading

0 comments on commit 720d332

Please sign in to comment.