diff --git a/Cargo.toml b/Cargo.toml index a55ffbf9..b77081da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ ferrumc-anvil = { path = "src/lib/adapters/anvil" } ferrumc-config = { path = "src/lib/utils/config" } ferrumc-core = { path = "src/lib/core" } ferrumc-ecs = { path = "src/lib/ecs" } -ferrumc-events = { path = "src/lib/events" } +ferrumc-events = { path = "src/lib/events"} ferrumc-general-purpose = { path = "src/lib/utils/general_purpose" } ferrumc-logging = { path = "src/lib/utils/logging" } ferrumc-macros = { path = "src/lib/derive_macros" } @@ -115,6 +115,7 @@ async-trait = "0.1.82" # Logging tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +tracing-appender = "0.2.3" log = "0.4.22" console-subscriber = "0.4.1" diff --git a/src/bin/Cargo.toml b/src/bin/Cargo.toml index 0c0aaaea..1451fff7 100644 --- a/src/bin/Cargo.toml +++ b/src/bin/Cargo.toml @@ -27,15 +27,14 @@ ferrumc-nbt = { workspace = true } ferrumc-general-purpose = { workspace = true } ferrumc-state = { workspace = true } -ctor = { workspace = true } parking_lot = { workspace = true, features = ["deadlock_detection"] } tracing = { workspace = true } tokio = { workspace = true } -rayon = { workspace = true } futures = { workspace = true } -serde_json = { workspace = true } async-trait = { workspace = true } clap = { workspace = true, features = ["derive"] } +flate2 = { workspace = true } +ctor = { workspace = true } [[bin]] diff --git a/src/bin/src/packet_handlers/player/see_other_players.rs b/src/bin/src/packet_handlers/player/head_rot.rs similarity index 70% rename from src/bin/src/packet_handlers/player/see_other_players.rs rename to src/bin/src/packet_handlers/player/head_rot.rs index 8aaaac69..a5b60f34 100644 --- a/src/bin/src/packet_handlers/player/see_other_players.rs +++ b/src/bin/src/packet_handlers/player/head_rot.rs @@ -1,10 +1,7 @@ -use ferrumc_core::transform::grounded::OnGround; -use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; use ferrumc_macros::event_handler; use ferrumc_net::errors::NetError; use ferrumc_net::packets::outgoing::set_head_rotation::SetHeadRotationPacket; -use ferrumc_net::packets::outgoing::teleport_entity::TeleportEntityPacket; use ferrumc_net::packets::packet_events::TransformEvent; use ferrumc_net::utils::broadcast::{broadcast, BroadcastOptions}; use ferrumc_net::utils::ecs_helpers::EntityExt; @@ -18,16 +15,16 @@ async fn handle_player_move( ) -> Result { let entity = event.conn_id; - let pos = entity.get::(&state)?; + // let pos = entity.get::(&state)?; let rot = entity.get::(&state)?; - let grounded = entity.get::(&state)?; + // let grounded = entity.get::(&state)?; - let teleport_packet = TeleportEntityPacket::new(entity, &pos, &rot, grounded.0); + // let teleport_packet = TeleportEntityPacket::new(entity, &pos, &rot, grounded.0); let head_rot_packet = SetHeadRotationPacket::new(entity as i32, NetAngle::from_degrees(rot.yaw as f64)); let start = std::time::Instant::now(); - broadcast(&teleport_packet, &state, BroadcastOptions::default().all()).await?; + // broadcast(&teleport_packet, &state, BroadcastOptions::default().all()).await?; broadcast(&head_rot_packet, &state, BroadcastOptions::default().all()).await?; tracing::trace!("broadcasting entity move took {:?}", start.elapsed()); diff --git a/src/bin/src/packet_handlers/player/mod.rs b/src/bin/src/packet_handlers/player/mod.rs index 4e2f924e..0b3c4247 100644 --- a/src/bin/src/packet_handlers/player/mod.rs +++ b/src/bin/src/packet_handlers/player/mod.rs @@ -1,3 +1,3 @@ pub mod do_action; -pub mod see_other_players; +pub mod head_rot; pub mod update_player_position; diff --git a/src/bin/src/packet_handlers/player/update_player_position.rs b/src/bin/src/packet_handlers/player/update_player_position.rs index cef18915..9fb4fe47 100644 --- a/src/bin/src/packet_handlers/player/update_player_position.rs +++ b/src/bin/src/packet_handlers/player/update_player_position.rs @@ -2,10 +2,17 @@ use ferrumc_core::chunks::chunk_receiver::ChunkReceiver; use ferrumc_core::transform::grounded::OnGround; use ferrumc_core::transform::position::Position; use ferrumc_core::transform::rotation::Rotation; -use ferrumc_macros::event_handler; +use ferrumc_ecs::entities::Entity; +use ferrumc_macros::{event_handler, NetEncode}; use ferrumc_net::errors::NetError; +use ferrumc_net::packets::outgoing::teleport_entity::TeleportEntityPacket; +use ferrumc_net::packets::outgoing::update_entity_position::UpdateEntityPositionPacket; +use ferrumc_net::packets::outgoing::update_entity_position_and_rotation::UpdateEntityPositionAndRotationPacket; +use ferrumc_net::packets::outgoing::update_entity_rotation::UpdateEntityRotationPacket; use ferrumc_net::packets::packet_events::TransformEvent; +use ferrumc_net::utils::broadcast::{broadcast, BroadcastOptions}; use ferrumc_net::utils::ecs_helpers::EntityExt; +use ferrumc_net::NetResult; use ferrumc_state::GlobalState; use tracing::trace; @@ -16,6 +23,9 @@ async fn handle_player_move( ) -> Result { let conn_id = event.conn_id; + let mut delta_pos = None::<(i16, i16, i16)>; + let mut new_rot = None::; + if let Some(ref new_position) = event.position { trace!("Getting chunk_recv 1 for player move"); { @@ -45,6 +55,12 @@ async fn handle_player_move( let mut position = conn_id.get_mut::(&state)?; trace!("Got position 1 for player move"); + delta_pos = Some(( + ((new_position.x * 4096.0) - (position.x * 4096.0)) as i16, + ((new_position.y * 4096.0) - (position.y * 4096.0)) as i16, + ((new_position.z * 4096.0) - (position.z * 4096.0)) as i16, + )); + *position = Position::new(new_position.x, new_position.y, new_position.z); } @@ -53,7 +69,10 @@ async fn handle_player_move( let mut rotation = conn_id.get_mut::(&state)?; trace!("Got rotation 1 for player move"); - *rotation = Rotation::new(new_rotation.yaw, new_rotation.pitch); + let new_rotation = Rotation::new(new_rotation.yaw, new_rotation.pitch); + new_rot = Some(new_rotation); + + *rotation = new_rotation; } if let Some(new_grounded) = event.on_ground { @@ -64,5 +83,71 @@ async fn handle_player_move( *on_ground = OnGround(new_grounded); } + update_pos_for_all(conn_id, delta_pos, new_rot, &state).await?; + Ok(event) } + +#[derive(NetEncode)] +enum BroadcastMovementPacket { + UpdateEntityPosition(UpdateEntityPositionPacket), + UpdateEntityPositionAndRotation(UpdateEntityPositionAndRotationPacket), + UpdateEntityRotation(UpdateEntityRotationPacket), + TeleportEntity(TeleportEntityPacket), +} + +async fn update_pos_for_all( + entity_id: Entity, + delta_pos: Option<(i16, i16, i16)>, + new_rot: Option, + state: &GlobalState, +) -> NetResult<()> { + let is_grounded = entity_id.get::(state)?.0; + + // If any delta of (x|y|z) exceeds 7.5, then it's "not recommended" to use this packet + // As docs say: "If the movement exceeds these limits, Teleport Entity should be sent instead." + // "should"???? + const MAX_DELTA: i16 = (7.5 * 4096f32) as i16; + let delta_exceeds_threshold = match delta_pos { + Some((delta_x, delta_y, delta_z)) => { + delta_x.abs() > MAX_DELTA || delta_y.abs() > MAX_DELTA || delta_z.abs() > MAX_DELTA + } + None => false, + }; + + let packet: BroadcastMovementPacket = if delta_exceeds_threshold { + let pos = entity_id.get::(state)?; + let rot = entity_id.get::(state)?; + let grounded = entity_id.get::(state)?.0; + + BroadcastMovementPacket::TeleportEntity(TeleportEntityPacket::new( + entity_id, &pos, &rot, grounded, + )) + } else { + match (delta_pos, new_rot) { + (Some(delta_pos), Some(new_rot)) => { + BroadcastMovementPacket::UpdateEntityPositionAndRotation( + UpdateEntityPositionAndRotationPacket::new( + entity_id, + delta_pos, + &new_rot, + is_grounded, + ), + ) + } + (Some(delta_pos), None) => BroadcastMovementPacket::UpdateEntityPosition( + UpdateEntityPositionPacket::new(entity_id, delta_pos, is_grounded), + ), + (None, Some(new_rot)) => BroadcastMovementPacket::UpdateEntityRotation( + UpdateEntityRotationPacket::new(entity_id, &new_rot, is_grounded), + ), + _ => { + return Ok(()); + } + } + }; + + broadcast(&packet, state, BroadcastOptions::default().all()).await?; + + Ok(()) +} diff --git a/src/lib/events/Cargo.toml b/src/lib/events/Cargo.toml index 2c1c7109..8461d9a3 100644 --- a/src/lib/events/Cargo.toml +++ b/src/lib/events/Cargo.toml @@ -10,3 +10,4 @@ ctor = { workspace = true} thiserror = { workspace = true } futures = { workspace = true } dashmap = { workspace = true } +tracing = { workspace = true } \ No newline at end of file diff --git a/src/lib/events/src/infrastructure.rs b/src/lib/events/src/infrastructure.rs index 5f3e09b5..16774b21 100644 --- a/src/lib/events/src/infrastructure.rs +++ b/src/lib/events/src/infrastructure.rs @@ -73,6 +73,9 @@ pub trait Event: Sized + Send + Sync + 'static { /// /// Returns `Ok(())` if the execution succeeded. `Err(EventsError)` ifa listener failed. async fn trigger(event: Self::Data, state: Self::State) -> Result<(), Self::Error> { + #[cfg(debug_assertions)] + let start = std::time::Instant::now(); + let listeners = EVENTS_LISTENERS .get(Self::name()) .expect("Failed to find event listeners. Impossible;"); @@ -96,6 +99,9 @@ pub trait Event: Sized + Send + Sync + 'static { }) .await?; + #[cfg(debug_assertions)] + tracing::trace!("Event {} took {:?}", Self::name(), start.elapsed()); + Ok(()) } diff --git a/src/lib/net/src/packets/outgoing/mod.rs b/src/lib/net/src/packets/outgoing/mod.rs index fb78750e..ce630555 100644 --- a/src/lib/net/src/packets/outgoing/mod.rs +++ b/src/lib/net/src/packets/outgoing/mod.rs @@ -24,5 +24,11 @@ pub mod spawn_entity; pub mod entity_animation; pub mod entity_metadata; pub mod player_info_update; + +// --------- Movement ---------- pub mod set_head_rotation; pub mod teleport_entity; +pub mod update_entity_position; +pub mod update_entity_position_and_rotation; +pub mod update_entity_rotation; +// ----------------------------- diff --git a/src/lib/net/src/packets/outgoing/update_entity_position.rs b/src/lib/net/src/packets/outgoing/update_entity_position.rs new file mode 100644 index 00000000..e7ab4320 --- /dev/null +++ b/src/lib/net/src/packets/outgoing/update_entity_position.rs @@ -0,0 +1,26 @@ +use ferrumc_ecs::entities::Entity; +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::net_types::var_int::VarInt; +use std::io::Write; + +#[derive(NetEncode)] +#[packet(packet_id = 0x2E)] +pub struct UpdateEntityPositionPacket { + pub entity_id: VarInt, + pub delta_x: i16, + pub delta_y: i16, + pub delta_z: i16, + pub on_ground: bool, +} + +impl UpdateEntityPositionPacket { + pub fn new(entity_id: Entity, delta_positions: (i16, i16, i16), on_ground: bool) -> Self { + Self { + entity_id: VarInt::new(entity_id as i32), + delta_x: delta_positions.0, + delta_y: delta_positions.1, + delta_z: delta_positions.2, + on_ground, + } + } +} diff --git a/src/lib/net/src/packets/outgoing/update_entity_position_and_rotation.rs b/src/lib/net/src/packets/outgoing/update_entity_position_and_rotation.rs new file mode 100644 index 00000000..f2a8c96d --- /dev/null +++ b/src/lib/net/src/packets/outgoing/update_entity_position_and_rotation.rs @@ -0,0 +1,37 @@ +use ferrumc_core::transform::rotation::Rotation; +use ferrumc_ecs::entities::Entity; +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::net_types::angle::NetAngle; +use ferrumc_net_codec::net_types::var_int::VarInt; +use std::io::Write; + +#[derive(NetEncode)] +#[packet(packet_id = 0x2F)] +pub struct UpdateEntityPositionAndRotationPacket { + pub entity_id: VarInt, + pub delta_x: i16, + pub delta_y: i16, + pub delta_z: i16, + pub yaw: NetAngle, + pub pitch: NetAngle, + pub on_ground: bool, +} + +impl UpdateEntityPositionAndRotationPacket { + pub fn new( + entity_id: Entity, + delta_positions: (i16, i16, i16), + new_rot: &Rotation, + on_ground: bool, + ) -> Self { + Self { + entity_id: VarInt::new(entity_id as i32), + delta_x: delta_positions.0, + delta_y: delta_positions.1, + delta_z: delta_positions.2, + yaw: NetAngle::from_degrees(new_rot.yaw as f64), + pitch: NetAngle::from_degrees(new_rot.pitch as f64), + on_ground, + } + } +} diff --git a/src/lib/net/src/packets/outgoing/update_entity_rotation.rs b/src/lib/net/src/packets/outgoing/update_entity_rotation.rs new file mode 100644 index 00000000..96b91916 --- /dev/null +++ b/src/lib/net/src/packets/outgoing/update_entity_rotation.rs @@ -0,0 +1,25 @@ +use ferrumc_core::transform::rotation::Rotation; +use ferrumc_ecs::entities::Entity; +use ferrumc_macros::{packet, NetEncode}; +use ferrumc_net_codec::net_types::angle::NetAngle; +use ferrumc_net_codec::net_types::var_int::VarInt; +use std::io::Write; + +#[derive(NetEncode)] +#[packet(packet_id = 0x30)] +pub struct UpdateEntityRotationPacket { + pub entity_id: VarInt, + pub yaw: NetAngle, + pub pitch: NetAngle, + pub on_ground: bool, +} +impl UpdateEntityRotationPacket { + pub fn new(entity_id: Entity, new_rot: &Rotation, on_ground: bool) -> Self { + Self { + entity_id: VarInt::new(entity_id as i32), + yaw: NetAngle::from_degrees(new_rot.yaw as f64), + pitch: NetAngle::from_degrees(new_rot.pitch as f64), + on_ground, + } + } +} diff --git a/src/lib/utils/logging/Cargo.toml b/src/lib/utils/logging/Cargo.toml index 5bc7a18d..2025125b 100644 --- a/src/lib/utils/logging/Cargo.toml +++ b/src/lib/utils/logging/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" [dependencies] tracing = { workspace = true } tracing-subscriber = { workspace = true } +tracing-appender = { workspace = true } tokio = { workspace = true } ferrumc-profiling = { workspace = true } +ferrumc-general-purpose = { workspace = true } thiserror = { workspace = true } console-subscriber = { workspace = true } diff --git a/src/lib/utils/logging/src/lib.rs b/src/lib/utils/logging/src/lib.rs index 85c5b55c..97fece40 100644 --- a/src/lib/utils/logging/src/lib.rs +++ b/src/lib/utils/logging/src/lib.rs @@ -1,8 +1,10 @@ pub mod errors; +use ferrumc_general_purpose::paths::get_root_path; use ferrumc_profiling::ProfilerTracingLayer; use tracing::Level; -use tracing_subscriber::fmt::Layer; +use tracing_appender::rolling::Rotation; +use tracing_subscriber::fmt::{layer, Layer}; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::EnvFilter; @@ -11,10 +13,33 @@ pub fn init_logging(trace_level: Level) { //let console = console_subscriber::spawn(); let env_filter = EnvFilter::from_default_env().add_directive(trace_level.into()); + let is_verbose = trace_level > Level::INFO; + + let file_layer = { + let file_appender = tracing_appender::rolling::Builder::new() + .rotation(Rotation::DAILY) + .filename_prefix("ferrumc") + .filename_suffix("log.txt") + .build(get_root_path().join("logs")) + .unwrap(); + + if is_verbose { + layer().with_writer(file_appender).with_ansi(false) + } else { + layer() + .with_ansi(false) + .with_writer(file_appender) + .with_target(false) + .with_thread_ids(false) + .with_line_number(false) + .with_file(false) + } + }; + let mut fmt_layer = Layer::default(); // remove path from logs if log level is INFO - if trace_level == Level::INFO { + if !is_verbose { fmt_layer = fmt_layer .with_target(false) .with_thread_ids(false) @@ -24,7 +49,7 @@ pub fn init_logging(trace_level: Level) { let profiler_layer = ProfilerTracingLayer; tracing_subscriber::registry() - // .with(console) + .with(file_layer) .with(env_filter) .with(profiler_layer) .with(fmt_layer)