Skip to content
Draft
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
11 changes: 8 additions & 3 deletions src/bin/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
use clap::{Parser, Subcommand, ValueEnum};
use tracing::Level;

/// Parser for command arguments
#[derive(Parser)]
pub struct CLIArgs {
/// The Subcommands
#[command(subcommand)]
pub command: Option<Command>,
/// Customizable Logging level
#[clap(long)]
#[arg(value_enum)]
#[cfg_attr(debug_assertions, arg(default_value_t = LogLevel(Level::DEBUG)))]
#[cfg_attr(not(debug_assertions), arg(default_value_t = LogLevel(Level::INFO)))]
pub log: LogLevel,
}

/// The subcommands that could be given when executing the application from the binary.
#[derive(Subcommand, Clone)]
pub enum Command {
/// Sets up the config
Expand All @@ -22,6 +26,7 @@ pub enum Command {
Run,
}

/// Arguments that could be given if the subcommand used was [Command::Import]
#[derive(Debug, Clone, Parser)]
pub struct ImportArgs {
/// Path to world import folder
Expand All @@ -37,11 +42,11 @@ pub struct ImportArgs {
pub max_concurrent_tasks: usize,
}

// Wrapper struct for the Level enum
/// Wrapper struct for the Level enum
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LogLevel(Level);

// Implement `ValueEnum` for the wrapper
/// Implement [`ValueEnum`] for the wrapper
impl ValueEnum for LogLevel {
fn value_variants<'a>() -> &'a [Self] {
static VARIANTS: &[LogLevel] = &[
Expand All @@ -65,7 +70,7 @@ impl ValueEnum for LogLevel {
}
}

// Add a conversion method to make using the wrapper easier
/// Add a conversion method to make using the wrapper easier
impl From<LogLevel> for Level {
fn from(log_level: LogLevel) -> Self {
log_level.0
Expand Down
13 changes: 13 additions & 0 deletions src/bin/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,54 @@ use ferrumc_utils::errors::UtilsError;
use ferrumc_world::errors::WorldError;
use thiserror::Error;

/// Errors that could be thrown by the application.
#[derive(Debug, Error)]
pub enum BinaryError {
/// An error that gets thrown at the core level.
#[error("Core error: {0}")]
Core(#[from] CoreError),

/// An error that occurs when retrieving a specific Entity's query result from Query or QueryState.
#[error("QueryError error: {0}")]
QueryError(#[from] QueryEntityError),

/// An error that gets thrown for connection / networking errors.
#[error("Net error: {0}")]
Net(#[from] NetError),

/// An error if a plugin threw an error
#[error("Plugins error: {0}")]
Plugins(#[from] PluginsError),

/// An error if there was an IO error via the storage.
#[error("Storage error: {0}")]
Storage(#[from] StorageError),

/// An error that gets thrown when utils fail.
#[error("Utils error: {0}")]
Utils(#[from] UtilsError),

/// An error that gets thrown when the chunkloading or world files fails.
#[error("World error: {0}")]
World(#[from] WorldError),

/// An error that gets thrown when an Inventory error happens.
#[error("Inventory error: {0}")]
Inventory(#[from] InventoryError),

/// Custom errors, that are not handled in another error.
#[error("{0}")]
Custom(String),

/// Classic IO Error
#[error("IO error: {0}")]
Io(#[from] std::io::Error),

/// Error when the path given, cant be correctly handled.
#[error("Root Path error: {0}")]
RootPath(#[from] ferrumc_general_purpose::paths::RootPathError),

/// An error that gets thrown when world-generation fails.
#[error("WorldGen error: {0}")]
WorldGen(#[from] ferrumc_world_gen::errors::WorldGenError),
}
3 changes: 3 additions & 0 deletions src/bin/src/game_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::time::{Duration, Instant};
use tokio::time::sleep;
use tracing::{debug, error, info, info_span, trace, warn, Instrument};

/// Sets up important variables and values needed for the game to run properly.
pub fn start_game_loop(global_state: GlobalState) -> Result<(), BinaryError> {
// ECS world and schedules
let mut ecs_world = World::new();
Expand Down Expand Up @@ -144,6 +145,7 @@ pub fn start_game_loop(global_state: GlobalState) -> Result<(), BinaryError> {
Ok(())
}

/// Schedules events that should run at specific times.
fn build_timed_scheduler() -> Scheduler {
let mut timed = Scheduler::new();

Expand Down Expand Up @@ -202,6 +204,7 @@ fn build_timed_scheduler() -> Scheduler {
timed
}

/// Accepts the connection from new players and puts them in the bevy ecs app to handle them.
fn tcp_conn_acceptor(
state: GlobalState,
packet_sender: Arc<PacketSender>,
Expand Down
6 changes: 5 additions & 1 deletion src/bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod systems;
#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;

/// Main function, should be self-explanatory.
fn main() {
#[cfg(feature = "dhat")]
let _profiler = dhat::Profiler::new_heap();
Expand Down Expand Up @@ -71,6 +72,7 @@ fn main() {
}
}

/// Generates 12x12 Chunks on start around the world-spawn.
fn generate_chunks(state: GlobalState) -> Result<(), BinaryError> {
info!("No overworld spawn chunk found, generating spawn chunks...");
// Generate a 12x12 chunk area around the spawn point
Expand Down Expand Up @@ -105,6 +107,7 @@ fn generate_chunks(state: GlobalState) -> Result<(), BinaryError> {
Ok(())
}

/// Starts the gameloop and adds a hook for shutting down.
fn entry(start_time: Instant) -> Result<(), BinaryError> {
let state = create_state(start_time)?;
let global_state = Arc::new(state);
Expand Down Expand Up @@ -133,8 +136,8 @@ fn entry(start_time: Instant) -> Result<(), BinaryError> {
Ok(())
}

/// Handles the import of other worlds to the server.
fn handle_import(import_args: ImportArgs) -> Result<(), BinaryError> {
//! Handles the import of the world.
info!("Importing world...");

// let config = get_global_config();
Expand All @@ -154,6 +157,7 @@ fn handle_import(import_args: ImportArgs) -> Result<(), BinaryError> {
Ok(())
}

/// Creates the first ServerState.
fn create_state(start_time: Instant) -> Result<ServerState, BinaryError> {
Ok(ServerState {
world: World::new(&get_global_config().database.db_path),
Expand Down
3 changes: 3 additions & 0 deletions src/bin/src/packet_handlers/play_packets/chat_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use ferrumc_core::{identity::player_identity::PlayerIdentity, mq};
use ferrumc_net::ChatMessagePacketReceiver;
use ferrumc_text::TextComponent;

/// Handles the normal chat for the player,
/// so that if someone sends a message,
/// everyone that should get it, gets it.
pub fn handle(events: Res<ChatMessagePacketReceiver>, query: Query<&PlayerIdentity>) {
for (message, sender) in events.0.try_iter() {
let Ok(identity) = query.get(sender) else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ferrumc_net::ChunkBatchAckReceiver;
use ferrumc_state::GlobalStateResource;
use tracing::{error, warn};

/// Handles that every player gets the chunks they need currently.
pub fn handle(
events: Res<ChunkBatchAckReceiver>,
mut query: Query<(Entity, &mut ChunkReceiver)>,
Expand Down
11 changes: 11 additions & 0 deletions src/bin/src/packet_handlers/play_packets/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ use ferrumc_core::mq;
use ferrumc_net::ChatCommandPacketReceiver;
use ferrumc_text::{NamedColor, TextComponent, TextComponentBuilder};

/// Checks if the command sent is valid and exists.
///
/// # Arguments
///
/// * `input`: The command as a String.
/// * `sender`: The player that sent it.
///
/// returns: A Result with the information as a ['CommandContext'](ferrumc_commands::CommandContext)
///
/// throws: Error if the command does not exist, with a TextComponent.
fn resolve(
input: String,
sender: Sender,
Expand Down Expand Up @@ -37,6 +47,7 @@ fn resolve(
Ok((command, ctx))
}

/// Handles that players can execute commands while on the server.
pub fn handle(
events: Res<ChatCommandPacketReceiver>,
mut dispatch_events: EventWriter<CommandDispatchEvent>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use ferrumc_net_codec::net_types::{
use ferrumc_state::GlobalStateResource;
use tracing::error;

/// Tries to find possible (registered) commands via a given String.
fn find_command(input: String) -> Option<Arc<Command>> {
let mut input = input;
if input.starts_with("/") {
Expand Down Expand Up @@ -47,6 +48,7 @@ fn find_command(input: String) -> Option<Arc<Command>> {
None
}

/// Creates the needed Context for the Client to show suggestions.
fn create_ctx(input: String, command: Option<Arc<Command>>, sender: Sender) -> CommandContext {
let input = input
.strip_prefix(command.clone().map(|c| c.name).unwrap_or_default())
Expand All @@ -61,6 +63,9 @@ fn create_ctx(input: String, command: Option<Arc<Command>>, sender: Sender) -> C
}
}

/// Handles that while the player writes a command,
/// he gets recommendations about which commands
/// are possible / fitting with the parts he wrote already.
pub fn handle(
events: Res<CommandSuggestionRequestReceiver>,
query: Query<&StreamWriter>,
Expand Down
1 change: 1 addition & 0 deletions src/bin/src/packet_handlers/play_packets/keep_alive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ferrumc_state::GlobalStateResource;
use std::time::Instant;
use tracing::{error, warn};

/// Handles the keep-alive packets for the user, to keep connections up and alive.
pub fn handle(
events: Res<IncomingKeepAlivePacketReceiver>,
mut query: Query<&mut KeepAliveTracker>,
Expand Down
6 changes: 6 additions & 0 deletions src/bin/src/packet_handlers/play_packets/place_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::str::FromStr;

/// Givees the file where the items can be mapped to the corresponding blocks.
const ITEM_TO_BLOCK_MAPPING_FILE: &str =
include_str!("../../../../../assets/data/item_to_block_mapping.json");

/// Gives a parsed Mapping from the [ITEM_TO_BLOCK_MAPPING_FILE]
/// - returns hashmap with mapping.
/// - panics: if the mapping cant be parsed.
static ITEM_TO_BLOCK_MAPPING: Lazy<HashMap<i32, i32>> = Lazy::new(|| {
let str_form: HashMap<String, String> = serde_json::from_str(ITEM_TO_BLOCK_MAPPING_FILE)
.expect("Failed to parse item_to_block_mapping.json");
Expand All @@ -30,6 +35,7 @@ static ITEM_TO_BLOCK_MAPPING: Lazy<HashMap<i32, i32>> = Lazy::new(|| {
.collect()
});

/// Handles which block is getting places where, when the client wants to.
pub fn handle(
events: Res<PlaceBlockReceiver>,
state: Res<GlobalStateResource>,
Expand Down
4 changes: 3 additions & 1 deletion src/bin/src/packet_handlers/play_packets/player_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ use ferrumc_state::GlobalStateResource;
use ferrumc_world::block_id::BlockId;
use tracing::{debug, error, trace};

/// Handles the Action the player could do.
///
/// Documentation to look up possible events: [https://minecraft.wiki](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol?oldid=2773393#Player_Action)
pub fn handle(
events: Res<PlayerActionReceiver>,
state: Res<GlobalStateResource>,
query: Query<(Entity, &StreamWriter)>,
) {
// https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol?oldid=2773393#Player_Action
for (event, trigger_eid) in events.0.try_iter() {
let res: Result<(), BinaryError> = try {
match event.status.0 {
Expand Down
3 changes: 3 additions & 0 deletions src/bin/src/packet_handlers/play_packets/player_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use ferrumc_net::PlayerCommandPacketReceiver;
use ferrumc_state::GlobalStateResource;
use tracing::error;

/// Handles actions the player could do with movement. e.g. Sneaking, swimming.
///
/// Documentation to look up possible events: [https://minecraft.wiki](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol?oldid=2773393#Player_Action)
pub fn handle(
events: Res<PlayerCommandPacketReceiver>,
query: Query<(Entity, &StreamWriter)>,
Expand Down
1 change: 1 addition & 0 deletions src/bin/src/packet_handlers/play_packets/player_loaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use ferrumc_state::GlobalStateResource;
use ferrumc_world::block_id::BlockId;
use tracing::warn;

/// Handles where the player gets loaded in after joining.
pub fn handle(
ev: Res<PlayerLoadedReceiver>,
state: Res<GlobalStateResource>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use ferrumc_net::SetCreativeModeSlotReceiver;
use ferrumc_state::GlobalStateResource;
use tracing::{debug, error};

/// Handles that the player can get blocks from the creative inventory and add them to the player inventory.
pub fn handle(
events: Res<SetCreativeModeSlotReceiver>,
state: Res<GlobalStateResource>,
Expand Down
1 change: 1 addition & 0 deletions src/bin/src/packet_handlers/play_packets/set_held_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ferrumc_net::SetHeldItemReceiver;
use ferrumc_state::GlobalStateResource;
use tracing::{debug, error};

/// Handles that the player can have a item in the hand, later that others can see the item currently held.
pub fn handle(
events: Res<SetHeldItemReceiver>,
state: Res<GlobalStateResource>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use ferrumc_net::packets::outgoing::update_entity_position_and_rotation::UpdateE
use ferrumc_net::packets::outgoing::update_entity_rotation::UpdateEntityRotationPacket;
use ferrumc_state::{GlobalState, GlobalStateResource};

/// Handles when the player moves, where to and in which direction they look.
pub fn handle(
events: Res<SetPlayerPositionPacketReceiver>,
mut pos_query: Query<(&mut Position, &mut OnGround, &Rotation, &PlayerIdentity)>,
Expand Down Expand Up @@ -84,14 +85,20 @@ pub fn handle(
}
}

/// Enum to describe how the player just moved.
#[derive(NetEncode, Clone)]
enum BroadcastMovementPacket {
/// Value only for Movement.
UpdateEntityPosition(UpdateEntityPositionPacket),
/// Value for position and rotation.
UpdateEntityPositionAndRotation(UpdateEntityPositionAndRotationPacket),
/// Value for position.
UpdateEntityRotation(UpdateEntityRotationPacket),
/// Value for teleporting players.
TeleportEntity(TeleportEntityPacket),
}

/// Updates the position for all players to all players.
fn update_pos_for_all(
entity_id: Entity,
delta_pos: Option<(i16, i16, i16)>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bevy_ecs::prelude::{EventWriter, Res};
use ferrumc_net::packets::packet_events::TransformEvent;
use ferrumc_net::SetPlayerPositionAndRotationPacketReceiver;

/// Sets the Position & Rotation of the player.
pub fn handle(
events: Res<SetPlayerPositionAndRotationPacketReceiver>,
mut transform_event_writer: EventWriter<TransformEvent>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bevy_ecs::prelude::{EventWriter, Res};
use ferrumc_net::packets::packet_events::TransformEvent;
use ferrumc_net::SetPlayerRotationPacketReceiver;

/// Handles the rotation of the player.
pub fn handle(
events: Res<SetPlayerRotationPacketReceiver>,
mut event_writer: EventWriter<TransformEvent>,
Expand Down
1 change: 1 addition & 0 deletions src/bin/src/packet_handlers/play_packets/swing_arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use ferrumc_net_codec::net_types::var_int::VarInt;
use ferrumc_state::GlobalStateResource;
use tracing::error;

/// Makes the player swing their arm.
pub fn handle(
events: Res<SwingArmPacketReceiver>,
query: Query<&PlayerIdentity>,
Expand Down
1 change: 1 addition & 0 deletions src/bin/src/packet_handlers/player/head_rot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use ferrumc_net::packets::packet_events::TransformEvent;
use ferrumc_net_codec::net_types::angle::NetAngle;
use tracing::error;

/// Handles the player head rotation
pub fn handle_player_move(
mut events: EventReader<TransformEvent>,
query: Query<(&Rotation, &PlayerIdentity)>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use ferrumc_net_codec::net_types::var_int::VarInt;
use ferrumc_state::GlobalStateResource;
use tracing::{debug, error};

/// Handles the inventory for the player from the server.
pub fn handle_inventory_updates(state: Res<GlobalStateResource>, mut query: Query<&StreamWriter>) {
while let Some(update) = INVENTORY_UPDATES_QUEUE.pop() {
if state.0.players.is_connected(update.entity) {
Expand Down
1 change: 1 addition & 0 deletions src/bin/src/register_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ferrumc_core::conn::player_count_update_cooldown::PlayerCountUpdateCooldown;
use ferrumc_net::connection::NewConnection;
use ferrumc_state::GlobalStateResource;

/// Registers resources that will be needed later on
pub fn register_resources(
world: &mut World,
new_conn_recv: Receiver<NewConnection>,
Expand Down
Loading