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
6 changes: 4 additions & 2 deletions src/bin/src/launch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use ferrumc_state::player_cache::PlayerCache;
use ferrumc_state::player_list::PlayerList;
use ferrumc_state::{GlobalState, ServerState};
use ferrumc_threadpool::ThreadPool;
use ferrumc_world::pos::ChunkPos;
use ferrumc_world::World;
use ferrumc_world_gen::WorldGenerator;
use std::sync::Arc;
Expand Down Expand Up @@ -44,14 +45,15 @@ pub fn generate_spawn_chunks(state: GlobalState) -> Result<(), BinaryError> {
for (x, z) in chunks {
let state_clone = state.clone();
batch.execute(move || {
let pos = ChunkPos::new(x, z);
let chunk = state_clone
.terrain_generator
.generate_chunk(x, z)
.generate_chunk(pos)
.map(Arc::new);

match chunk {
Ok(chunk) => {
if let Err(e) = state_clone.world.save_chunk(chunk) {
if let Err(e) = state_clone.world.save_chunk(pos, "overworld", chunk) {
error!("Error saving chunk ({}, {}): {:?}", x, z, e);
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::cli::{CLIArgs, Command};
use crate::errors::BinaryError;
use clap::Parser;
use ferrumc_config::whitelist::create_whitelist;
use ferrumc_world::pos::ChunkPos;
use std::sync::Arc;
use std::time::Instant;
use tracing::{error, info};
Expand Down Expand Up @@ -72,8 +73,10 @@ fn entry(start_time: Instant) -> Result<(), BinaryError> {
let global_state = Arc::new(state);

create_whitelist();

if !global_state.world.chunk_exists(0, 0, "overworld")? {
if !global_state
.world
.chunk_exists(ChunkPos::new(0, 0), "overworld")?
{
launch::generate_spawn_chunks(global_state.clone())?;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ pub fn handle(
);

// 2. Get block from world
let pos = packet.location.clone().into();
let block_state_id = match state.0.world.get_block_and_fetch(
packet.location.x,
packet.location.y as i32,
packet.location.z,
pos,
"overworld", // TODO: Remove overworld hard coding for the dimension
) {
Ok(id) => id,
Expand Down
79 changes: 42 additions & 37 deletions src/bin/src/packet_handlers/play_packets/place_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use ferrumc_net::PlaceBlockReceiver;
use ferrumc_net_codec::net_types::network_position::NetworkPosition;
use ferrumc_net_codec::net_types::var_int::VarInt;
use ferrumc_state::GlobalStateResource;
use ferrumc_world::pos::BlockPos;
use tracing::{debug, error, trace};

use ferrumc_inventories::hotbar::Hotbar;
Expand All @@ -21,12 +22,17 @@ use std::str::FromStr;

const ITEM_TO_BLOCK_MAPPING_FILE: &str =
include_str!("../../../../../assets/data/item_to_block_mapping.json");
static ITEM_TO_BLOCK_MAPPING: Lazy<HashMap<i32, i32>> = Lazy::new(|| {
static ITEM_TO_BLOCK_MAPPING: Lazy<HashMap<i32, BlockStateId>> = 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");
str_form
.into_iter()
.map(|(k, v)| (i32::from_str(&k).unwrap(), i32::from_str(&v).unwrap()))
.map(|(k, v)| {
(
i32::from_str(&k).unwrap(),
BlockStateId::new(u32::from_str(&v).unwrap()),
)
})
.collect()
});

Expand Down Expand Up @@ -65,41 +71,31 @@ pub fn handle(
"Placing block with item ID: {}, mapped to block state ID: {}",
item_id.0, mapped_block_state_id
);
let mut chunk = match state.0.world.load_chunk_owned(
event.position.x >> 4,
event.position.z >> 4,
"overworld",
) {
let pos: BlockPos = event.position.into();
let mut chunk = match state.0.world.load_chunk_owned(pos.chunk(), "overworld") {
Ok(chunk) => chunk,
Err(e) => {
debug!("Failed to load chunk: {:?}", e);
continue 'ev_loop;
}
};
let Ok(block_clicked) = chunk.get_block(
event.position.x,
event.position.y as i32,
event.position.z,
) else {
debug!("Failed to get block at position: {:?}", event.position);
let Ok(block_clicked) = chunk.get_block(pos.chunk_block_pos()) else {
debug!("Failed to get block at position: {}", pos);
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 {
0 => (0, -1, 0),
1 => (0, 1, 0),
2 => (0, 0, -1),
3 => (0, 0, 1),
4 => (-1, 0, 0),
5 => (1, 0, 0),
_ => (0, 0, 0),
};
let (x, y, z) = (
event.position.x + x_block_offset,
event.position.y + y_block_offset,
event.position.z + z_block_offset,
);
let offset_pos = pos
+ match event.face.0 {
0 => (0, -1, 0),
1 => (0, 1, 0),
2 => (0, 0, -1),
3 => (0, 0, 1),
4 => (-1, 0, 0),
5 => (1, 0, 0),
_ => (0, 0, 0),
};

// Check if the block collides with any entities
let does_collide = {
pos_q.into_iter().any(|(pos, bounds)| {
Expand All @@ -113,7 +109,11 @@ pub fn handle(
z_offset_start: 0.0,
z_offset_end: 1.0,
},
(x as f64, y as f64, z as f64),
(
offset_pos.pos.x as f64,
offset_pos.pos.y as f64,
offset_pos.pos.z as f64,
),
)
})
};
Expand All @@ -129,12 +129,8 @@ pub fn handle(
continue 'ev_loop;
}

if let Err(err) = chunk.set_block(
x & 0xF,
y as i32,
z & 0xF,
BlockStateId(*mapped_block_state_id as u32),
) {
if let Err(err) = chunk.set_block(pos.chunk_block_pos(), *mapped_block_state_id)
{
error!("Failed to set block: {:?}", err);
continue 'ev_loop;
}
Expand All @@ -143,7 +139,11 @@ pub fn handle(
};

let chunk_packet = BlockUpdate {
location: NetworkPosition { x, y, z },
location: NetworkPosition {
x: offset_pos.pos.x,
y: offset_pos.pos.y as i16,
z: offset_pos.pos.z,
},
block_state_id: VarInt::from(*mapped_block_state_id),
};
if let Err(err) = conn.send_packet_ref(&chunk_packet) {
Expand All @@ -155,10 +155,15 @@ pub fn handle(
continue 'ev_loop;
}

if let Err(err) = state.0.world.save_chunk(Arc::from(chunk)) {
if let Err(err) =
state
.0
.world
.save_chunk(pos.chunk(), "overworld", Arc::from(chunk))
{
error!("Failed to save chunk after block placement: {:?}", err);
} else {
trace!("Block placed at ({}, {}, {})", x, y, z);
trace!("Block placed at {}", offset_pos);
}
}
}
Expand Down
25 changes: 11 additions & 14 deletions src/bin/src/packet_handlers/play_packets/player_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ 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_state_id::BlockStateId;
use ferrumc_world::{block_state_id::BlockStateId, pos::BlockPos};
use tracing::{error, trace, warn};

pub fn handle(
Expand All @@ -34,40 +34,37 @@ pub fn handle(
continue;
};

let pos: BlockPos = event.location.clone().into();
if abilities.creative_mode {
// --- CREATIVE MODE LOGIC ---
// Only instabreak (status 0) is relevant in creative.
if event.status.0 == 0 {
let res: Result<(), BinaryError> = try {
let mut chunk = match state.0.clone().world.load_chunk_owned(
event.location.x >> 4,
event.location.z >> 4,
"overworld",
) {
let mut chunk = match state
.0
.clone()
.world
.load_chunk_owned(pos.chunk(), "overworld")
{
Ok(chunk) => chunk,
Err(e) => {
trace!("Chunk not found, generating new chunk: {:?}", e);
state
.0
.clone()
.terrain_generator
.generate_chunk(event.location.x >> 4, event.location.z >> 4)
.generate_chunk(pos.chunk())
.map_err(BinaryError::WorldGen)?
}
};
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, BlockStateId::default())
.set_block(pos.chunk_block_pos(), BlockStateId::default())
.map_err(BinaryError::World)?;

state
.0
.world
.save_chunk(Arc::new(chunk))
.save_chunk(pos.chunk(), "overworld", Arc::new(chunk))
.map_err(BinaryError::World)?;

// Broadcast the change
Expand Down
8 changes: 5 additions & 3 deletions src/bin/src/packet_handlers/play_packets/player_loaded.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use bevy_ecs::prelude::{Entity, Query, Res};
use ferrumc_core::transform::position::Position;
use ferrumc_macros::block;
use ferrumc_net::connection::StreamWriter;
use ferrumc_net::packets::outgoing::synchronize_player_position::SynchronizePlayerPositionPacket;
use ferrumc_net::PlayerLoadedReceiver;
use ferrumc_state::GlobalStateResource;
use ferrumc_world::block_state_id::BlockStateId;
use ferrumc_world::pos::BlockPos;
use tracing::warn;

pub fn handle(
Expand All @@ -24,14 +26,14 @@ pub fn handle(
);
continue;
}
let head_block = state.0.world.get_block_and_fetch(
let pos = BlockPos::of(
player_pos.x as i32,
player_pos.y as i32,
player_pos.z as i32,
"overworld",
);
let head_block = state.0.world.get_block_and_fetch(pos, "overworld");
if let Ok(head_block) = head_block {
if head_block == BlockStateId(0) {
if head_block == block!("air") {
tracing::info!(
"Player {} loaded at position: ({}, {}, {})",
player,
Expand Down
9 changes: 5 additions & 4 deletions src/bin/src/systems/chunk_sending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use ferrumc_net::packets::outgoing::chunk_batch_start::ChunkBatchStart;
use ferrumc_net::packets::outgoing::set_center_chunk::SetCenterChunk;
use ferrumc_net_codec::encode::NetEncodeOpts;
use ferrumc_state::GlobalStateResource;
use ferrumc_world::pos::ChunkPos;
use std::sync::atomic::Ordering;

// Just take the needed chunks from the ChunkReceiver and send them
Expand Down Expand Up @@ -68,24 +69,24 @@ pub fn handle(
})
.expect("Failed to send SetCenterChunk");

for coordinates in needed_chunks {
for coordinates in needed_chunks.into_iter().map(|c| ChunkPos::new(c.0, c.1)) {
let state = state.clone();
let is_compressed = conn.compress.load(Ordering::Relaxed);
batch.execute({
move || {
let chunk = state
.0
.world
.load_chunk(coordinates.0, coordinates.1, "overworld")
.load_chunk(coordinates, "overworld")
.unwrap_or(
state
.0
.terrain_generator
.generate_chunk(coordinates.0, coordinates.1)
.generate_chunk(coordinates)
.expect("Could not generate chunk")
.into(),
);
let packet = ChunkAndLightData::from_chunk(&chunk)
let packet = ChunkAndLightData::from_chunk(coordinates, &chunk)
.expect("Failed to create ChunkAndLightData");
compress_packet(
&packet,
Expand Down
Loading