Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ fn main() {
fn entry(start_time: Instant) -> Result<(), BinaryError> {
let state = launch::create_state(start_time)?;
let global_state = Arc::new(state);

create_whitelist();
if !global_state
.world
Expand Down
6 changes: 5 additions & 1 deletion src/bin/src/packet_handlers/play_packets/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ use ferrumc_commands::{
};
use ferrumc_core::mq;
use ferrumc_net::ChatCommandPacketReceiver;
use ferrumc_state::{GlobalState, GlobalStateResource};
use ferrumc_text::{NamedColor, TextComponent, TextComponentBuilder};

fn resolve(
input: String,
sender: Sender,
state: GlobalState,
) -> Result<(Arc<Command>, CommandContext), Box<TextComponent>> {
let command = infrastructure::find_command(&input);
if command.is_none() {
Expand All @@ -33,6 +35,7 @@ fn resolve(
input: input.clone(),
command: command.clone(),
sender,
state,
};

Ok((command, ctx))
Expand All @@ -42,6 +45,7 @@ pub fn handle(
receiver: Res<ChatCommandPacketReceiver>,
mut dispatch_msgs: MessageWriter<CommandDispatched>,
mut resolved_dispatch_msgs: MessageWriter<ResolvedCommandDispatched>,
state: Res<GlobalStateResource>,
) {
for (event, entity) in receiver.0.try_iter() {
let sender = Sender::Player(entity);
Expand All @@ -50,7 +54,7 @@ pub fn handle(
sender,
});

let resolved = resolve(event.command, sender);
let resolved = resolve(event.command, sender, state.0.clone());
match resolved {
Err(err) => {
mq::queue(*err, false, entity);
Expand Down
17 changes: 14 additions & 3 deletions src/bin/src/packet_handlers/play_packets/command_suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ferrumc_net::{
use ferrumc_net_codec::net_types::{
length_prefixed_vec::LengthPrefixedVec, prefixed_optional::PrefixedOptional, var_int::VarInt,
};
use ferrumc_state::GlobalStateResource;
use ferrumc_state::{GlobalState, GlobalStateResource};
use tracing::error;

fn find_command(input: String) -> Option<Arc<Command>> {
Expand Down Expand Up @@ -47,7 +47,12 @@ fn find_command(input: String) -> Option<Arc<Command>> {
None
}

fn create_ctx(input: String, command: Option<Arc<Command>>, sender: Sender) -> CommandContext {
fn create_ctx(
input: String,
command: Option<Arc<Command>>,
sender: Sender,
state: GlobalState,
) -> CommandContext {
let input = input
.strip_prefix(command.clone().map(|c| c.name).unwrap_or_default())
.unwrap_or(&input)
Expand All @@ -58,6 +63,7 @@ fn create_ctx(input: String, command: Option<Arc<Command>>, sender: Sender) -> C
input: input.clone(),
command: command.unwrap_or(ROOT_COMMAND.clone()),
sender,
state,
}
}

Expand All @@ -82,7 +88,12 @@ pub fn handle(
))
.unwrap_or(&input)
.to_string();
let mut ctx = create_ctx(command_arg.clone(), command.clone(), Sender::Player(entity));
let mut ctx = create_ctx(
command_arg.clone(),
command.clone(),
Sender::Player(entity),
state.0.clone(),
);
let command_arg = command_arg.clone(); // ok borrow checker
let tokens = command_arg.split(" ").collect::<Vec<&str>>();
let Some(current_token) = tokens.last() else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
pub fn handle() {
// TODO
use bevy_ecs::prelude::{Query, Res};
use ferrumc_components::player::teleport_tracker::TeleportTracker;
use ferrumc_net::ConfirmPlayerTeleportReceiver;

pub fn handle(
receiver: Res<ConfirmPlayerTeleportReceiver>,
mut query: Query<&mut TeleportTracker>,
) {
for (_, eid) in receiver.0.try_iter() {
let Ok(mut tracker) = query.get_mut(eid) else {
continue;
};
tracker.waiting_for_confirm = false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ignore teleport_id from client? Malicious client could send fake confirmations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sending malicious confirmations doesn't really do anything, the vanilla server doesn't even handle them.

}
}
4 changes: 2 additions & 2 deletions src/bin/src/packet_handlers/play_packets/player_abilities.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy_ecs::prelude::{Entity, Query, Res};
use ferrumc_net::connection::StreamWriter;
use tracing::{debug, error, warn};
use tracing::{error, trace, warn};

use ferrumc_net::PlayerAbilitiesReceiver;

Expand Down Expand Up @@ -42,7 +42,7 @@ pub fn handle(
// --- Validation ---
if abilities.may_fly {
// Player is allowed to fly. Update the server's state.
debug!(
trace!(
"Player {} toggled flying to: {}",
trigger_eid.index(),
client_is_flying
Expand Down
8 changes: 5 additions & 3 deletions src/bin/src/packet_handlers/play_packets/player_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ferrumc_net::packets::incoming::player_command::PlayerCommandAction;
use ferrumc_net::packets::outgoing::entity_metadata::{EntityMetadata, EntityMetadataPacket};
use ferrumc_net::PlayerCommandPacketReceiver;
use ferrumc_net_codec::net_types::var_int::VarInt;
use tracing::debug;
use tracing::log::trace;

/// Handles PlayerCommand packets (sprinting, leave bed, etc.)
/// Note: Sneaking is handled via PlayerInput packet, NOT here
Expand All @@ -23,9 +23,11 @@ pub fn handle(

let entity_id = VarInt::new(identity.short_uuid);

debug!(
trace!(
"PlayerCommand: {:?} from {} (entity_id={})",
event.action, identity.username, identity.short_uuid
event.action,
identity.username,
identity.short_uuid
);

match event.action {
Expand Down
7 changes: 4 additions & 3 deletions src/bin/src/packet_handlers/play_packets/set_held_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy_ecs::prelude::{Query, Res};
use ferrumc_inventories::hotbar::Hotbar;
use ferrumc_net::SetHeldItemReceiver;
use ferrumc_state::GlobalStateResource;
use tracing::{debug, error};
use tracing::{error, trace};

pub fn handle(
receiver: Res<SetHeldItemReceiver>,
Expand All @@ -14,9 +14,10 @@ pub fn handle(
if 0 <= event.slot_index && event.slot_index < 9 {
if let Ok(mut hotbar) = query.get_mut(entity) {
hotbar.selected_slot = event.slot_index as u8;
debug!(
trace!(
"Set held item for player {} to slot {}",
entity, event.slot_index
entity,
event.slot_index
);
} else {
error!("Could not find hotbar for player {}", entity);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use bevy_ecs::prelude::{MessageWriter, Query, Res};

use ferrumc_components::player::teleport_tracker::TeleportTracker;
use ferrumc_core::transform::grounded::OnGround;
use ferrumc_core::transform::position::Position;
use ferrumc_messages::chunk_calc::ChunkCalc;
Expand All @@ -9,12 +10,16 @@ use tracing::trace;

pub fn handle(
receiver: Res<SetPlayerPositionPacketReceiver>,
mut query: Query<(&mut Position, &mut OnGround)>,
mut query: Query<(&mut Position, &mut OnGround, &TeleportTracker)>,
mut movement_messages: MessageWriter<Movement>,
mut chunk_calc_messages: MessageWriter<ChunkCalc>,
) {
for (event, eid) in receiver.0.try_iter() {
if let Ok((mut pos, mut ground)) = query.get_mut(eid) {
if let Ok((mut pos, mut ground, tracker)) = query.get_mut(eid) {
if tracker.waiting_for_confirm {
// Ignore position updates while waiting for teleport confirmation
continue;
}
let new_pos = Position::new(event.x, event.feet_y, event.z);

// Check if chunk changed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use bevy_ecs::prelude::Query;
use bevy_ecs::prelude::{MessageWriter, Res};
use ferrumc_components::player::teleport_tracker::TeleportTracker;
use ferrumc_core::transform::grounded::OnGround;
use ferrumc_core::transform::position::Position;
use ferrumc_core::transform::rotation::Rotation;
Expand All @@ -11,10 +12,19 @@ pub fn handle(
receiver: Res<SetPlayerPositionAndRotationPacketReceiver>,
mut movement_messages: MessageWriter<Movement>,
mut chunk_calc_messages: MessageWriter<ChunkCalc>,
mut query: Query<(&mut Position, &mut Rotation, &mut OnGround)>,
mut query: Query<(
&mut Position,
&mut Rotation,
&mut OnGround,
&mut TeleportTracker,
)>,
) {
for (event, eid) in receiver.0.try_iter() {
if let Ok((mut pos, mut rot, mut ground)) = query.get_mut(eid) {
if let Ok((mut pos, mut rot, mut ground, tracker)) = query.get_mut(eid) {
if tracker.waiting_for_confirm {
// Ignore position updates while waiting for teleport confirmation
continue;
}
let new_pos = Position::new(event.x, event.feet_y, event.z);
let new_rot = Rotation::new(event.yaw, event.pitch);
let on_ground = event.flags & 0x01 != 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bevy_ecs::prelude::{MessageWriter, Query, Res};
use ferrumc_components::player::teleport_tracker::TeleportTracker;
use ferrumc_core::transform::grounded::OnGround;
use ferrumc_core::transform::rotation::Rotation;
use ferrumc_net::packets::packet_messages::Movement;
Expand All @@ -7,10 +8,14 @@ use ferrumc_net::SetPlayerRotationPacketReceiver;
pub fn handle(
receiver: Res<SetPlayerRotationPacketReceiver>,
mut movement_messages: MessageWriter<Movement>,
mut query: Query<(&mut Rotation, &mut OnGround)>,
mut query: Query<(&mut Rotation, &mut OnGround, &mut TeleportTracker)>,
) {
for (event, eid) in receiver.0.try_iter() {
if let Ok((mut rot, mut ground)) = query.get_mut(eid) {
if let Ok((mut rot, mut ground, tracker)) = query.get_mut(eid) {
if tracker.waiting_for_confirm {
// Ignore rotation updates while waiting for teleport confirmation
continue;
}
let new_rot = Rotation::new(event.yaw, event.pitch);
let on_ground = event.flags & 0x01 != 0;

Expand Down
9 changes: 6 additions & 3 deletions src/bin/src/systems/chunk_calculator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use bevy_ecs::prelude::{MessageReader, Query};
use bevy_math::IVec2;
use ferrumc_components::player::client_information::ClientInformation;
use ferrumc_config::server_config::get_global_config;
use ferrumc_core::chunks::chunk_receiver::ChunkReceiver;
use ferrumc_core::transform::position::Position;
Expand All @@ -8,15 +9,17 @@ use ferrumc_world::pos::ChunkPos;

pub fn handle(
mut messages: MessageReader<ChunkCalc>,
mut query: Query<(&Position, &mut ChunkReceiver)>,
mut query: Query<(&Position, &mut ChunkReceiver, &ClientInformation)>,
) {
for message in messages.read() {
let (position, mut chunk_receiver) = match query.get_mut(message.0) {
let (position, mut chunk_receiver, client_info) = match query.get_mut(message.0) {
Ok(data) => data,
Err(_) => continue, // Skip if the player does not exist
};

let radius = get_global_config().chunk_render_distance as i32;
let server_render_distance = get_global_config().chunk_render_distance as i32;
let client_view_distance = client_info.view_distance as i32;
let radius = server_render_distance.min(client_view_distance);
let player_chunk = ChunkPos::from(position.coords);

let mut queued_chunks = Vec::new();
Expand Down
93 changes: 64 additions & 29 deletions src/bin/src/systems/listeners/player_tp.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,82 @@
use bevy_ecs::prelude::{MessageReader, MessageWriter, Query};
use bevy_ecs::prelude::{Entity, MessageReader, MessageWriter, Query};
use ferrumc_components::player::teleport_tracker::TeleportTracker;
use ferrumc_core::identity::player_identity::PlayerIdentity;
use ferrumc_core::transform::position::Position;
use ferrumc_core::transform::rotation::Rotation;
use ferrumc_messages::chunk_calc::ChunkCalc;
use ferrumc_messages::entity_update::SendEntityUpdate;
use ferrumc_messages::teleport_player::TeleportPlayer;
use ferrumc_net::connection::StreamWriter;
use ferrumc_net::packets::outgoing::entity_position_sync::TeleportEntityPacket;
use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket;
use tracing::error;

pub fn teleport_player(
mut query: Query<(&StreamWriter, &mut Position, &Rotation)>,
mut query: Query<(Entity, &StreamWriter, &mut Position, &mut TeleportTracker)>,
id_query: Query<&PlayerIdentity>,
mut message_reader: MessageReader<TeleportPlayer>,
mut chunk_calc_msg: MessageWriter<ChunkCalc>,
mut player_update_msg: MessageWriter<SendEntityUpdate>,
) {
for message in message_reader.read() {
let entity = message.entity;

// Notify the chunk calculation system to recalculate chunks for this player
chunk_calc_msg.write(ChunkCalc(entity));

// Notify the player update system to send the new position to the client
player_update_msg.write(SendEntityUpdate(entity));
let Ok((conn, mut pos, rot)) = query.get_mut(entity) else {
continue;
let message_entity = message.entity;
let id = match id_query.get(message_entity) {
Ok(id) => id,
Err(err) => {
error!(
"Failed to get PlayerIdentity for entity {:?}: {}",
message_entity, err
);
continue;
}
};
pos.x = message.x;
pos.y = message.y;
pos.z = message.z;
if let Err(err) = conn.send_packet(SynchronizePlayerPositionPacket {
teleport_id: rand::random::<i32>().into(),
x: message.x,
y: message.y,
z: message.z,
vel_x: message.vel_x,
vel_y: message.vel_y,
vel_z: message.vel_z,
yaw: rot.yaw,
pitch: rot.pitch,
flags: 0,
}) {
error!("Failed to send teleport packet: {}", err);
continue;
for (entity, conn, mut pos, mut tracker) in query.iter_mut() {
if entity == message_entity {
// Block movement tracking until the player has been teleported
tracker.waiting_for_confirm = true;
pos.x = message.x;
pos.y = message.y;
pos.z = message.z;
// If it's the entity we are trying to teleport, send the sync player pos packet
if let Err(err) = conn.send_packet(SynchronizePlayerPositionPacket {
teleport_id: rand::random::<i32>().into(),
x: message.x,
y: message.y,
z: message.z,
vel_x: message.vel_x,
vel_y: message.vel_y,
vel_z: message.vel_z,
yaw: message.yaw,
pitch: message.pitch,
flags: 0,
}) {
error!("Failed to send teleport packet: {}", err);
continue;
}
} else {
// Otherwise send teleport entity packet. This ideally should be handled by the send
// entity updates system, but it seems to be a bit buggy
if let Err(err) = conn.send_packet(TeleportEntityPacket {
entity_id: id.short_uuid.into(),
x: message.x,
y: message.y,
z: message.z,
vel_x: 0.0,
vel_y: 0.0,
vel_z: 0.0,
yaw: message.yaw,
pitch: message.pitch,
on_ground: false,
}) {
error!("Failed to send teleport packet: {}", err);
continue;
}
}
}

// Notify the player update system to send the new position to the client
player_update_msg.write(SendEntityUpdate(message_entity));

// Notify the chunk calculation system to recalculate chunks for this player
chunk_calc_msg.write(ChunkCalc(message_entity));
}
}
Loading