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
2 changes: 2 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[profile.default]
slow-timeout = { period = "15s", terminate-after = 3 }
Binary file modified .etc/raw_chunk.dat
Binary file not shown.
52 changes: 26 additions & 26 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ members = [
[workspace.lints.rust]
unsafe_code = "allow"
unused_unsafe = "deny"
#unsafe_op_in_unsafe_fn = "deny"
#unused_crate_dependencies = "deny"
unused_import_braces = "deny"
unused_lifetimes = "deny"
keyword_idents_2018 = "deny"
Expand Down Expand Up @@ -119,9 +117,9 @@ tokio = { version = "1.47.1", features = ["macros", "net", "rt", "sync", "time",

# Logging
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
tracing-appender = "0.2.3"
log = "0.4.27"
log = "0.4.28"
console-subscriber = "0.4.1"

# Concurrency/Parallelism
Expand All @@ -132,52 +130,51 @@ rusty_pool = "0.7.0"
crossbeam-queue = "0.3.12"

# Network
reqwest = { version = "0.12.22", features = ["json"] }
ureq = "3.1.0"
reqwest = { version = "0.12.23", features = ["json"] }
ureq = "3.1.2"

# Error handling
thiserror = "2.0.15"
thiserror = "2.0.16"

# Cryptography
rand = "0.9.2"
rand = "0.10.0-rc.0"
fnv = "1.0.7"
wyhash = "0.6.0"
ahash = "0.8.12"
simplehash = "0.1.3"

# Encoding/Serialization
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.142"
serde_derive = "1.0.219"
serde_yaml_ng = "0.9.36"
serde = { version = "1.0.226", features = ["derive"] }
serde_json = "1.0.145"
serde_derive = "1.0.226"
base64 = "0.22.1"
bitcode = "0.6.7"
bitcode_derive = "0.6.7"
toml = "0.9.5"
toml = "0.9.7"
craftflow-nbt = "2.1.0"
figment = { version = "0.10.19", features = ["toml", "env"] }
simd-json = "0.15.1"
simd-json = "0.16.0"

# Bit manipulation
byteorder = "1.5.0"

# Data types
dashmap = "7.0.0-rc2"
uuid = { version = "1.18.0", features = ["v4", "v3", "serde"] }
indexmap = { version = "2.10.0", features = ["serde"] }
uuid = { version = "1.18.1", features = ["v4", "v3", "serde"] }
indexmap = { version = "2.11.4", features = ["serde"] }

# Macros
lazy_static = "1.5.0"
quote = "1.0.40"
syn = "2.0.106"
proc-macro2 = "1.0.101"
proc-macro-crate = "3.3.0"
proc-macro-crate = "3.4.0"
paste = "1.0.15"
maplit = "1.0.2"
macro_rules_attribute = "0.2.2"

# Magic
dhat = "0.3.3"
ctor = "0.4.2"
ctor = "0.5.0"

# Compression/Decompression
flate2 = { version = "1.1.2", features = ["zlib"], default-features = false }
Expand All @@ -188,28 +185,31 @@ lz4_flex = "0.11.5"

# Database
heed = "0.22.0"
moka = "0.12.10"
moka = "0.12.11"

# CLI
clap = "4.5.45"
clap = "4.5.48"
indicatif = "0.18.0"
colored = "3.0.0"

# Misc
deepsize = "0.2.0"
page_size = "0.6.0"
enum-ordinalize = "4.3.0"
regex = "1.11.1"
regex = "1.11.3"
noise = "0.9.0"
ctrlc = "3.4.7"
ctrlc = "3.5.0"
num_cpus = "1.17.0"
typename = "0.1.2"
bevy_ecs = { version = "0.16.1", features = ["multi_threaded", "trace"] }
once_cell = "1.21.3"

# Bevy
bevy_math = "0.16.1"
bevy_ecs = { version = "0.16.1", features = ["multi_threaded", "trace"] }

# I/O
memmap2 = "0.9.7"
tempfile = "3.20.0"
memmap2 = "0.9.8"
tempfile = "3.23.0"

# Benchmarking
criterion = { version = "0.7.0", features = ["html_reports"] }
1 change: 1 addition & 0 deletions src/bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ferrumc-threadpool = { workspace = true }
ferrumc-inventories = { workspace = true }
once_cell = { workspace = true }
serde_json = { workspace = true }
bevy_math = { workspace = true }

tracing = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
Expand Down
16 changes: 10 additions & 6 deletions src/bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(try_blocks)]

use crate::errors::BinaryError;
use bevy_math::IVec2;
use clap::Parser;
use ferrumc_config::server_config::get_global_config;
use ferrumc_config::whitelist::create_whitelist;
Expand Down Expand Up @@ -79,23 +80,23 @@ fn generate_chunks(state: GlobalState) -> Result<(), BinaryError> {
let radius = get_global_config().chunk_render_distance as i32;
for x in -radius..=radius {
for z in -radius..=radius {
chunks.push((x, z));
chunks.push(IVec2::new(x, z));
}
}
let mut batch = state.thread_pool.batch();
for (x, z) in chunks {
for chunk_pos in chunks {
let state_clone = state.clone();
batch.execute(move || {
let chunk = state_clone
.terrain_generator
.generate_chunk(x, z)
.generate_chunk(chunk_pos)
.map(Arc::new);
if let Err(e) = chunk {
error!("Error generating chunk ({}, {}): {:?}", x, z, e);
error!("Error generating chunk ({}): {:?}", chunk_pos, e);
} else {
let chunk = chunk.unwrap();
if let Err(e) = state_clone.world.save_chunk(chunk) {
error!("Error saving chunk ({}, {}): {:?}", x, z, e);
error!("Error saving chunk ({}): {:?}", chunk_pos, e);
}
}
});
Expand All @@ -109,7 +110,10 @@ fn entry(start_time: Instant) -> Result<(), BinaryError> {
let state = create_state(start_time)?;
let global_state = Arc::new(state);
create_whitelist();
if !global_state.world.chunk_exists(0, 0, "overworld")? {
if !global_state
.world
.chunk_exists(IVec2::new(0, 0), "overworld")?
{
generate_chunks(global_state.clone())?;
}

Expand Down
19 changes: 9 additions & 10 deletions src/bin/src/packet_handlers/play_packets/place_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ use ferrumc_net_codec::net_types::var_int::VarInt;
use ferrumc_state::GlobalStateResource;
use tracing::{debug, error, trace};

use bevy_math::{IVec2, IVec3};
use ferrumc_inventories::hotbar::Hotbar;
use ferrumc_inventories::inventory::Inventory;
use ferrumc_world::block_id::BlockId;
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::str::FromStr;
Expand Down Expand Up @@ -65,8 +67,7 @@ pub fn handle(
item_id.0, mapped_block_id
);
let mut chunk = match state.0.world.load_chunk_owned(
event.position.x >> 4,
event.position.z >> 4,
IVec2::new(event.position.x >> 4, event.position.z >> 4),
"overworld",
) {
Ok(chunk) => chunk,
Expand All @@ -75,14 +76,11 @@ pub fn handle(
continue 'ev_loop;
}
};
let Ok(block_clicked) = chunk.get_block(
let block_clicked = chunk.get_block(IVec3::new(
event.position.x,
event.position.y as i32,
event.position.z,
) else {
debug!("Failed to get block at position: {:?}", event.position);
continue 'ev_loop;
};
));
trace!("Block clicked: {:?}", block_clicked);
// Use the face to determine the offset of the block to place
let (x_block_offset, y_block_offset, z_block_offset) = match event.face.0 {
Expand Down Expand Up @@ -128,9 +126,10 @@ pub fn handle(
continue 'ev_loop;
}

if let Err(err) =
chunk.set_block(x & 0xF, y as i32, z & 0xF, VarInt::new(*mapped_block_id))
{
if let Err(err) = chunk.set_block(
IVec3::new(x & 0xF, y as i32, z & 0xF),
BlockId::from(VarInt::new(*mapped_block_id)),
) {
error!("Failed to set block: {:?}", err);
continue 'ev_loop;
}
Expand Down
15 changes: 10 additions & 5 deletions src/bin/src/packet_handlers/play_packets/player_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use std::sync::Arc;

use crate::errors::BinaryError;
use bevy_ecs::prelude::{Entity, Query, Res};
use bevy_math::{IVec2, IVec3};
use ferrumc_net::connection::StreamWriter;
use ferrumc_net::packets::outgoing::block_change_ack::BlockChangeAck;
use ferrumc_net::packets::outgoing::block_update::BlockUpdate;
use ferrumc_net::PlayerActionReceiver;
use ferrumc_net_codec::net_types::var_int::VarInt;
use ferrumc_state::GlobalStateResource;
use ferrumc_world::block_id::BlockId;
use ferrumc_world::vanilla_chunk_format::BlockData;
use tracing::{debug, error, trace};

pub fn handle(
Expand All @@ -23,8 +23,7 @@ pub fn handle(
match event.status.0 {
0 => {
let mut chunk = match state.0.clone().world.load_chunk_owned(
event.location.x >> 4,
event.location.z >> 4,
IVec2::new(event.location.x >> 4, event.location.z >> 4),
"overworld",
) {
Ok(chunk) => chunk,
Expand All @@ -34,15 +33,21 @@ pub fn handle(
.0
.clone()
.terrain_generator
.generate_chunk(event.location.x >> 4, event.location.z >> 4)?
.generate_chunk(IVec2::new(
event.location.x >> 4,
event.location.z >> 4,
))?
}
};
let (relative_x, relative_y, relative_z) = (
event.location.x.abs() % 16,
event.location.y as i32,
event.location.z.abs() % 16,
);
chunk.set_block(relative_x, relative_y, relative_z, BlockData::default())?;
chunk.set_block(
IVec3::new(relative_x, relative_y, relative_z),
BlockId::default(),
)?;
// Save the chunk to disk
state.0.world.save_chunk(Arc::new(chunk))?;
for (eid, conn) in query {
Expand Down
14 changes: 7 additions & 7 deletions src/bin/src/packet_handlers/play_packets/player_loaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ pub fn handle(
);
continue;
}
let head_block = state.0.world.get_block_and_fetch(
player_pos.x as i32,
player_pos.y as i32,
player_pos.z as i32,
"overworld",
);
if let Ok(head_block) = head_block {
let chunk_coords = ferrumc_world::get_chunk_coordinates(player_pos.as_vec3());
let head_block =
state
.0
.world
.get_block_and_fetch(chunk_coords, player_pos.as_vec3(), "overworld");
if let Some(head_block) = head_block {
if head_block == BlockId(0) {
tracing::info!(
"Player {} loaded at position: ({}, {}, {})",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bevy_ecs::prelude::{Entity, EventWriter, Query, Res};
use bevy_math::IVec2;
use ferrumc_core::chunks::cross_chunk_boundary_event::CrossChunkBoundaryEvent;
use ferrumc_core::identity::player_identity::PlayerIdentity;
use ferrumc_net::SetPlayerPositionPacketReceiver;
Expand Down Expand Up @@ -46,9 +47,9 @@ pub fn handle(
((new_position.z * 4096.0) - (position.z * 4096.0)) as i16,
));

let old_chunk = (position.x as i32 >> 4, position.z as i32 >> 4);
let old_chunk = IVec2::new(position.x as i32 >> 4, position.z as i32 >> 4);
Copy link

Choose a reason for hiding this comment

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

i have been using the position of the chunkcolumn in the chunk that is closest to (-inf, -inf) for easier and faster conversion. also, i don't know if bitshifting on an i32 is rounding towards -inf or 0. if it rounds to 0, it is wrong (because the pos (-7, -9) and (5, 8) for example, would be rounded to (0, 0) even though they are in different chunks)


let new_chunk = (new_position.x as i32 >> 4, new_position.z as i32 >> 4);
let new_chunk = IVec2::new(new_position.x as i32 >> 4, new_position.z as i32 >> 4);

if old_chunk != new_chunk {
cross_chunk_events.write(CrossChunkBoundaryEvent {
Expand Down
21 changes: 9 additions & 12 deletions src/bin/src/systems/cross_chunk_boundary.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::systems::send_chunks::send_chunks;
use bevy_ecs::prelude::{EventReader, Query, Res};
use bevy_math::IVec2;
use ferrumc_config::server_config::get_global_config;
use ferrumc_core::chunks::cross_chunk_boundary_event::CrossChunkBoundaryEvent;
use ferrumc_net::connection::StreamWriter;
Expand All @@ -21,28 +22,24 @@ pub fn cross_chunk_boundary(
let radius = get_global_config().chunk_render_distance as i32;

let mut old_chunk_seen = HashSet::new();
for x in event.old_chunk.0 - radius..event.old_chunk.0 + radius {
for z in event.old_chunk.1 - radius..event.old_chunk.1 + radius {
old_chunk_seen.insert((x, z));
for x in event.old_chunk.x - radius..event.old_chunk.x + radius {
for z in event.old_chunk.y - radius..event.old_chunk.y + radius {
old_chunk_seen.insert(IVec2::new(x, z));
}
}
let mut new_chunk_seen = HashSet::new();
for x in event.new_chunk.0 - radius..event.new_chunk.0 + radius {
for z in event.new_chunk.1 - radius..event.new_chunk.1 + radius {
new_chunk_seen.insert((x, z));
for x in event.new_chunk.x - radius..event.new_chunk.x + radius {
for z in event.new_chunk.y - radius..event.new_chunk.y + radius {
new_chunk_seen.insert(IVec2::new(x, z));
}
}
let needed_chunks: Vec<_> = new_chunk_seen
.iter()
.filter(|chunk| !old_chunk_seen.contains(chunk))
.map(|chunk| {
let (x, z) = *chunk;
(x, z, "overworld".to_string())
})
.map(|chunk| (*chunk, "overworld".to_string()))
.collect();
let center_chunk = (event.new_chunk.0, event.new_chunk.1);
let mut conn = query.get_mut(event.player).expect("Player does not exist");
send_chunks(state.0.clone(), needed_chunks, &mut conn, center_chunk)
send_chunks(state.0.clone(), needed_chunks, &mut conn, event.new_chunk)
.expect("Failed to send chunks")
}
}
Loading