Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ec99110
Create new module for holding chunk code
MSKatKing Dec 26, 2025
88d3e20
Add various structs for holding positions
MSKatKing Dec 26, 2025
65af065
Implement BlockPalette struct
MSKatKing Dec 26, 2025
d5f8681
Add different chunk section types
MSKatKing Dec 26, 2025
679e4fa
Implement direct and uniform chunk section types
MSKatKing Dec 26, 2025
26b4c82
Implement turning SectionBlockPos into a linear index
MSKatKing Dec 27, 2025
992f956
Allow UniformSections to be initialized with a value
MSKatKing Dec 27, 2025
8310f82
Implement get and set block for paletted sections
MSKatKing Dec 27, 2025
8ceafc6
Implement ChunkSection and ChunkSectionType
MSKatKing Dec 27, 2025
3d66363
Finish, test, and bench initial chunk implementation
MSKatKing Dec 27, 2025
eb3adb5
Add network model structs and allow conversion from ChunkSection
MSKatKing Dec 27, 2025
546792a
Use Cow instead of custom data type
MSKatKing Dec 27, 2025
364f16c
Move light module to separate folder
MSKatKing Dec 27, 2025
88b4c06
Add light data to chunk sections
MSKatKing Dec 27, 2025
d6df1d8
Cleanup some code
MSKatKing Dec 27, 2025
4bcf443
Use existing position structs and fix pack/unpack functions
MSKatKing Dec 27, 2025
3aa11ca
Fix From<UniformSection> for PalettedSection
MSKatKing Dec 27, 2025
1d1ac65
Implement chunk heightmaps
MSKatKing Dec 28, 2025
6a1ab5f
Use heightmap data when sending to the client
MSKatKing Dec 29, 2025
401b067
Implement chunk section biome data
MSKatKing Dec 30, 2025
51cbf79
Formatting and clippy
MSKatKing Dec 30, 2025
30a720e
Merge remote-tracking branch 'origin/master' into feature/chunk-rewrite
MSKatKing Jan 8, 2026
f1a924f
Fix errors from merge
MSKatKing Jan 8, 2026
90153fb
Use existing BlockStateId struct
MSKatKing Jan 8, 2026
69ecd17
Remove old chunk format and replace usages with new format
MSKatKing Jan 8, 2026
f738a75
Fix benchmarks
MSKatKing Jan 8, 2026
4638a58
Improve code readability, introduce new NetworkArray struct for typed…
MSKatKing Jan 8, 2026
0894635
Ensure that Chunks can have a variable amount of ChunkSections based …
MSKatKing Jan 8, 2026
0f03cb5
Rough implementation of vanilla chunk loading
MSKatKing Jan 8, 2026
d35638b
Merge branch 'ferrumc-rs:master' into feature/chunk-rewrite
MSKatKing Jan 9, 2026
180cb12
Fix chunk importing and add some optimizations
MSKatKing Jan 9, 2026
a37465c
cargo fmt + clippy
MSKatKing Jan 9, 2026
376ce2e
Fix bugs and add PalettedSection memory optimization
MSKatKing Jan 9, 2026
2096c09
Tweak bench functions and add comments
MSKatKing Jan 9, 2026
f03d47d
Revert benchmark changes
MSKatKing Jan 9, 2026
6e2af74
Fix benchmark
ReCore-sys Jan 9, 2026
f290e2f
Clippy
ReCore-sys Jan 9, 2026
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
Binary file modified .etc/raw_chunk.dat
Binary file not shown.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ toml = "0.9.8"
craftflow-nbt = "2.1.0"
figment = { version = "0.10.19", features = ["toml", "env"] }
simd-json = "0.17.0"
bytemuck = { version = "1.24.0", features = ["extern_crate_alloc"] }

# Bit manipulation
byteorder = "1.5.0"
Expand Down
11 changes: 2 additions & 9 deletions src/bin/src/packet_handlers/play_packets/place_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ pub fn handle(
"overworld",
)
.expect("Failed to load or generate chunk");
let Ok(block_clicked) = chunk.get_block(pos.chunk_block_pos()) else {
debug!("Failed to get block at position: {}", pos);
continue 'ev_loop;
};
let block_clicked = chunk.get_block(pos.chunk_block_pos());
trace!("Block clicked: {:?}", block_clicked);
// Use the face to determine the offset of the block to place
let offset_pos = pos
Expand Down Expand Up @@ -126,11 +123,7 @@ pub fn handle(
continue 'ev_loop;
}

if let Err(err) = chunk.set_block(pos.chunk_block_pos(), *mapped_block_state_id)
{
error!("Failed to set block: {:?}", err);
continue 'ev_loop;
}
chunk.set_block(pos.chunk_block_pos(), *mapped_block_state_id);
let ack_packet = BlockChangeAck {
sequence: event.sequence,
};
Expand Down
4 changes: 1 addition & 3 deletions src/bin/src/packet_handlers/play_packets/player_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ pub fn handle(
"overworld",
)
.expect("Failed to load or generate chunk");
chunk
.set_block(pos.chunk_block_pos(), BlockStateId::default())
.map_err(BinaryError::World)?;
chunk.set_block(pos.chunk_block_pos(), BlockStateId::default());

// Send block broken event for un-grounding system
block_break_events.write(BlockBrokenEvent { position: pos });
Expand Down
4 changes: 1 addition & 3 deletions src/bin/src/systems/listeners/digging_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,7 @@ fn break_block(
let pos: BlockPos = position.clone().into();
let mut chunk = ferrumc_utils::world::load_or_generate_mut(&state.0, pos.chunk(), "overworld")
.expect("Failed to load or generate chunk");
chunk
.set_block(pos.chunk_block_pos(), BlockStateId::default())
.map_err(BinaryError::World)?;
chunk.set_block(pos.chunk_block_pos(), BlockStateId::default());

// Send block broken event for un-grounding system
debug!("Sending BlockBrokenEvent for block at {:?}", pos.pos);
Expand Down
17 changes: 8 additions & 9 deletions src/bin/src/systems/physics/collisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,12 @@ pub fn handle(

pub fn is_solid_block(state: &GlobalState, pos: IVec3) -> bool {
let chunk_coordinates = ChunkPos::from(pos.as_dvec3());
ferrumc_utils::world::load_or_generate_mut(state, chunk_coordinates, "overworld")
.expect("Failed to load or generate chunk")
.get_block(ChunkBlockPos::from(pos))
.map(|block_state| {
!match_block!("air", block_state)
&& !match_block!("void_air", block_state)
&& !match_block!("cave_air", block_state)
})
.unwrap_or(false)
let block_state =
ferrumc_utils::world::load_or_generate_mut(state, chunk_coordinates, "overworld")
.expect("Failed to load or generate chunk")
.get_block(ChunkBlockPos::from(pos));

!match_block!("air", block_state)
&& !match_block!("void_air", block_state)
&& !match_block!("air", block_state)
}
8 changes: 4 additions & 4 deletions src/bin/src/systems/physics/drag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ pub fn handle(
let chunk =
ferrumc_utils::world::load_or_generate_mut(&state.0, chunk_pos, "overworld")
.expect("Failed to load or generate chunk");
let is_in_water = chunk
.get_block(ChunkBlockPos::from(pos.coords.as_ivec3()))
.map(|block| match_block!("water", block))
.unwrap_or(false);
let is_in_water = match_block!(
"water",
chunk.get_block(ChunkBlockPos::from(pos.coords.as_ivec3()))
);
if is_in_water {
vel.y *= 0.98;
vel.x *= 0.91;
Expand Down
30 changes: 23 additions & 7 deletions src/lib/net/crates/codec/src/encode/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use crate::encode::errors::NetEncodeError;
use crate::encode::AsyncWrite;
use crate::encode::{NetEncode, NetEncodeOpts};
use crate::net_types::var_int::VarInt;
use std::borrow::Cow;
use std::collections::HashMap;
use std::io::Write;
use std::ops::Deref;
use tokio::io::AsyncWriteExt;

macro_rules! impl_for_primitives {
Expand Down Expand Up @@ -134,6 +136,7 @@ impl NetEncode for &[u8] {
}

writer.write_all(self)?;

Ok(())
}
async fn encode_async<W: AsyncWrite + Unpin>(
Expand All @@ -147,20 +150,20 @@ impl NetEncode for &[u8] {
}

writer.write_all(self).await?;

Ok(())
}
}

impl NetEncode for &[&str] {
impl NetEncode for [u8] {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> Result<(), NetEncodeError> {
if matches!(opts, NetEncodeOpts::SizePrefixed) {
let len: VarInt = VarInt::new(self.len() as i32);
len.encode(writer, opts)?;
}

for item in *self {
item.encode(writer, opts)?;
}
writer.write_all(self)?;

Ok(())
}
async fn encode_async<W: AsyncWrite + Unpin>(
Expand All @@ -173,13 +176,26 @@ impl NetEncode for &[&str] {
len.encode_async(writer, opts).await?;
}

for item in *self {
item.encode_async(writer, opts).await?;
}
writer.write_all(self).await?;

Ok(())
}
}

impl<T: NetEncode + ?Sized + ToOwned> NetEncode for Cow<'_, T> {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> Result<(), NetEncodeError> {
self.deref().encode(writer, opts)
}

async fn encode_async<W: AsyncWrite + Unpin>(
&self,
writer: &mut W,
opts: &NetEncodeOpts,
) -> Result<(), NetEncodeError> {
self.deref().encode_async(writer, opts).await
}
}

impl<T: NetEncode> NetEncode for Option<T> {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> Result<(), NetEncodeError> {
match self {
Expand Down
1 change: 1 addition & 0 deletions src/lib/net/crates/codec/src/net_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod angle;
pub mod bitset;
pub mod byte_array;
pub mod length_prefixed_vec;
pub mod net_array;
pub mod network_position;
pub mod prefixed_optional;
pub mod teleport_flags;
Expand Down
54 changes: 54 additions & 0 deletions src/lib/net/crates/codec/src/net_types/net_array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::encode::errors::NetEncodeError;
use crate::encode::{NetEncode, NetEncodeOpts};
use crate::net_types::var_int::VarInt;
use std::borrow::Cow;
use std::io::Write;
use tokio::io::AsyncWrite;

pub struct NetworkArray<'data, T: NetEncode + ToOwned + Clone>(Cow<'data, [T]>);

impl<'data, T: NetEncode + ToOwned + Clone> NetworkArray<'data, T> {
pub fn new_borrowed(data: &'data [T]) -> Self {
NetworkArray(Cow::Borrowed(data))
}

pub fn new_owned(data: <[T] as ToOwned>::Owned) -> Self {
NetworkArray(Cow::Owned(data))
}

pub fn into_inner(self) -> <[T] as ToOwned>::Owned {
self.0.into_owned()
}
}

impl<'data, T: NetEncode + ToOwned + Clone> NetEncode for NetworkArray<'data, T> {
fn encode<W: Write>(&self, writer: &mut W, opts: &NetEncodeOpts) -> Result<(), NetEncodeError> {
if matches!(opts, NetEncodeOpts::SizePrefixed) {
let len: VarInt = VarInt::new(self.0.len() as i32);
len.encode(writer, opts)?;
}

for item in self.0.iter() {
item.encode(writer, opts)?;
}

Ok(())
}

async fn encode_async<W: AsyncWrite + Unpin>(
&self,
writer: &mut W,
opts: &NetEncodeOpts,
) -> Result<(), NetEncodeError> {
if matches!(opts, NetEncodeOpts::SizePrefixed) {
let len: VarInt = VarInt::new(self.0.len() as i32);
len.encode_async(writer, opts).await?;
}

for item in self.0.iter() {
item.encode_async(writer, opts).await?;
}

Ok(())
}
}
Loading