Skip to content

Commit

Permalink
refactor(world): implement Chunk and Dimension improvements
Browse files Browse the repository at this point in the history
- Rewrite Chunk to use Section data structure for better organization
- Optimize Dimension to use DashMap for chunk storage
- Implement Item and BlockItem traits for future item system
- Update world and entity modules to accommodate new changes
  • Loading branch information
Liyze09 committed Oct 2, 2024
1 parent 7f2ae70 commit bd63fa5
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 58 deletions.
5 changes: 0 additions & 5 deletions crates/kernel/config.toml

This file was deleted.

8 changes: 0 additions & 8 deletions crates/kernel/logs/latest.log

This file was deleted.

1 change: 1 addition & 0 deletions crates/kernel/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub(crate) static BLOCKS_BY_ID: Lazy<DashMap<u32, Box<dyn Block>>> = Lazy::new(D
pub(crate) static BLOCKS_BY_NAME: Lazy<DashMap<String, u32>> = Lazy::new(DashMap::new);
pub(crate) static BLOCK_STATES_BY_ID: Lazy<DashMap<u32, Arc<(dyn BlockState)>>> =
Lazy::new(DashMap::new);
pub(crate) static BLOCK_ITEM_BY_ID: Lazy<DashMap<u32, u32>> = Lazy::new(DashMap::new);

pub fn register_block(id: &str, block: Box<dyn Block + 'static>) {
block.get_block_states().into_iter().for_each(|(k, v)| {
Expand Down
5 changes: 2 additions & 3 deletions crates/kernel/src/entity.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::world::dimension::Dimension;
use crate::WORLD;
use downcast_rs::{impl_downcast, DowncastSync};
use parking_lot::RwLock;
use std::sync::Arc;

pub mod entity_manager;
Expand All @@ -19,7 +18,7 @@ pub trait Entity: Send + Sync + DowncastSync {
self.get_data_mut().pos = (x, y, z);
}

fn get_dimension(&mut self) -> Arc<RwLock<Dimension>> {
fn get_dimension(&mut self) -> Arc<Dimension> {
unsafe {
WORLD
.read()
Expand All @@ -36,7 +35,7 @@ pub trait Entity: Send + Sync + DowncastSync {
.read()
.dimensions
.iter()
.position(|d| d.read().dimension_name == dimension)
.position(|d| d.dimension_name == dimension)
.unwrap();
}
}
Expand Down
59 changes: 59 additions & 0 deletions crates/kernel/src/item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::registry::protocol_id::get_protocol_id;
use downcast_rs::{impl_downcast, DowncastSync};

pub trait Item: Send + Sync + DowncastSync {
fn get_builder(&self) -> &ItemBuilder;
}
impl_downcast!(sync Item);

pub trait BlockItem: Item {
fn get_block() -> u32;
}

pub struct ItemBuilder {
pub protocol_id: u32,
pub item_settings: ItemSettings,
}

impl ItemBuilder {
fn new(id: &str, item_settings: ItemSettings) -> ItemBuilder {
ItemBuilder {
protocol_id: get_protocol_id("minecraft:item", &id).unwrap(),
item_settings,
}
}
}

pub struct ItemSettings {
pub max_count: u8,
pub max_damage: u16,
pub fireproof: bool,
}

impl ItemSettings {
pub fn new() -> ItemSettings {
ItemSettings {
max_count: 64,
max_damage: 0,
fireproof: false,
}
}
pub fn max_count(mut self, max_count: u8) -> ItemSettings {
self.max_count = max_count;
self
}
pub fn max_damage(mut self, max_damage: u16) -> ItemSettings {
self.max_damage = max_damage;
self
}
pub fn fireproof(mut self) -> ItemSettings {
self.fireproof = true;
self
}
}

impl Default for ItemSettings {
fn default() -> Self {
Self::new()
}
}
1 change: 1 addition & 0 deletions crates/kernel/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod block;
pub mod config;
pub mod entity;
pub mod item;
pub mod nbt;
pub(crate) mod network;
pub mod registry;
Expand Down
23 changes: 18 additions & 5 deletions crates/kernel/src/test/world_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ mod chunk {
#[test]
fn chunk() {
use crate::world::chunk::Chunk;
let mut chunk = Chunk::new(384);
use crate::world::dimension::Dimension;
let chunk = Chunk::new(
&Dimension::new(
crate::registry::dimension_type::DIMENSION_TYPES
.get("minecraft:overworld")
.unwrap()
.clone(),
"overworld".to_string(),
0,
),
0,
);
chunk.set_block(0, 0, 0, 9);
chunk.set_block(11, 45, 14, 9);
chunk.set_block(15, 383, 15, 9);
Expand All @@ -16,16 +27,18 @@ mod dimension {
#[test]
fn dimension() {
use crate::world::dimension::Dimension;
let mut dimension = Dimension::new(
let mut chunks = Vec::with_capacity(3);
let dimension = Dimension::new(
crate::registry::dimension_type::DIMENSION_TYPES
.get("minecraft:overworld")
.unwrap()
.clone(),
"overworld".to_string(),
0,
);
dimension.set_block(1144657482, 319, -138848321, 9);
dimension.set_block(1145, 14, 1919, 9);
dimension.set_block(0, -64, 0, 9);
chunks.push(dimension.set_block(1144657482, 319, -138848321, 9));
chunks.push(dimension.set_block(1145, 14, 1919, 9));
chunks.push(dimension.set_block(0, -64, 0, 9));
assert_eq!(dimension.get_block(1144657482, 319, -138848321), Some(9));
assert_eq!(dimension.get_block(1145, 14, 1919), Some(9));
assert_eq!(dimension.get_block(0, -64, 0), Some(9));
Expand Down
19 changes: 11 additions & 8 deletions crates/kernel/src/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::registry::DIMENSION_TYPES_INDEX;
use crate::world::block_update::{BlockUpdate, BlockUpdateType};
use crate::world::dimension::Dimension;
use dashmap::DashSet;
use parking_lot::RwLock;
use rayon::prelude::*;
use std::sync::Arc;
use std::thread;
Expand All @@ -15,7 +14,7 @@ pub mod dimension;

pub struct World {
default_dimension: usize,
pub dimensions: Vec<Arc<RwLock<Dimension>>>,
pub dimensions: Vec<Arc<Dimension>>,
pub(crate) entities: EntityManager,
block_updates_queue_1: Vec<BlockUpdate>,
block_updates_queue_2: Vec<BlockUpdate>,
Expand All @@ -24,16 +23,20 @@ pub struct World {
impl World {
pub fn new() -> World {
let mut dimensions = Vec::with_capacity(DIMENSION_TYPES_INDEX.len());
for dim in DIMENSION_TYPES_INDEX.iter() {
dimensions.push(Arc::new(RwLock::new(Dimension::new(
let mut idx = 0;
while idx < DIMENSION_TYPES_INDEX.len() {
let dim = DIMENSION_TYPES_INDEX.get(idx).unwrap();
dimensions.push(Arc::new(Dimension::new(
DIMENSION_TYPES.get(dim).unwrap().value().clone(),
dim.to_string(),
))));
idx as u32,
)));
idx += 1;
}
World {
default_dimension: dimensions
.iter()
.position(|it| it.read().dimension_name == "minecraft:overworld")
.position(|it| it.dimension_name == "minecraft:overworld")
.unwrap(),
dimensions,
entities: EntityManager::default(),
Expand Down Expand Up @@ -104,11 +107,11 @@ impl World {
}
self.swap_queues();
}
pub fn find_dimension(&self, name: &str) -> Option<Arc<RwLock<Dimension>>> {
pub fn find_dimension(&self, name: &str) -> Option<Arc<Dimension>> {
Some(
self.dimensions
.iter()
.find(|&dim| dim.read().dimension_name == name)?
.find(|&dim| dim.dimension_name == name)?
.clone(),
)
}
Expand Down
112 changes: 99 additions & 13 deletions crates/kernel/src/world/chunk.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
use crate::util::to_chunk_yzx;
use crate::world::dimension::Dimension;
use crate::WORLD;
use parking_lot::{Mutex, MutexGuard};

pub struct Chunk {
pub(crate) data: Vec<u32>,
pub(crate) data: Vec<Section>,
pub(crate) pos: u64,
pub(crate) height: i32,
pub(crate) idx: u32,
}

impl Chunk {
pub fn new(height: i32) -> Chunk {
let size = 16 * 16 * height as usize;
let data: Vec<u32> = vec![0; size];
Chunk { data, height }
pub fn new(dimension: &Dimension, pos: u64) -> Chunk {
let height = dimension.dimension_type.height;
let size = (height / 16) as usize;
let mut data = Vec::with_capacity(size);
while data.len() < size {
data.push(Section::new());
}
Chunk {
data,
height,
idx: dimension.dim_idx,
pos,
}
}
pub fn get_block(&self, x: i32, y: i32, z: i32) -> Option<u32> {
if y < 0 || y >= self.height {
Expand All @@ -18,21 +31,94 @@ impl Chunk {
if !(0..16).contains(&x) || !(0..16).contains(&z) {
return None;
}
let yzx = to_chunk_yzx(x, y, z);
Some(*self.data.get(yzx)?)
let idx = y as usize / 16;
let section = self.data.get(idx);
let sy = ((y as usize) - (16 * idx)) as u32;
Some(section?.get_state(x as u32, sy, z as u32))
}

pub fn set_block(&mut self, x: i32, y: i32, z: i32, block: u32) {
pub fn set_block(&self, x: i32, y: i32, z: i32, block: u32) {
if y < 0 || y >= self.height {
return;
}
if !(0..16).contains(&x) || !(0..16).contains(&z) {
return;
}
let yzx = to_chunk_yzx(x, y, z);
if yzx >= self.data.capacity() {
return;
let idx = y as usize / 16;
let section = match self.data.get(idx) {
Some(s) => s,
None => return,
};
let sy = ((y as usize) - (16 * idx)) as u32;
section.set_state(x as u32, sy, z as u32, block)
}

pub fn get_section(&self, y: usize) -> Option<SectionDataGuard> {
Some(self.data.get(y / 16)?.get_data_guard())
}
}

impl Drop for Chunk {
fn drop(&mut self) {
unsafe {
WORLD
.read()
.dimensions
.get(self.idx as usize)
.unwrap()
.chunks
.remove(&self.pos);
}
self.data.insert(yzx, block);
}
}

pub struct Section {
pub data: Mutex<[u32; 4096]>,
}

impl Section {
pub fn new() -> Section {
Section {
data: Mutex::new([0; 4096]),
}
}
#[inline]
pub fn get_state(&self, x: u32, y: u32, z: u32) -> u32 {
let index = (x + 16 * (y + 16 * z)) as usize;
self.data.lock()[index]
}
#[inline]
pub fn set_state(&self, x: u32, y: u32, z: u32, state: u32) {
let index = (x + 16 * (y + 16 * z)) as usize;
self.data.lock()[index] = state;
}

#[inline]
pub fn get_data_guard(&self) -> SectionDataGuard {
SectionDataGuard {
data: self.data.lock(),
}
}
}

impl Default for Section {
fn default() -> Self {
Self::new()
}
}

pub struct SectionDataGuard<'a> {
pub data: MutexGuard<'a, [u32; 4096]>,
}

impl SectionDataGuard<'_> {
pub fn get_state(&self, x: i32, y: i32, z: i32) -> u32 {
let index = (x + 16 * (y + 16 * z)) as usize;
self.data[index]
}

pub fn set_state(&mut self, x: i32, y: i32, z: i32, state: u32) {
let index = (x + 16 * (y + 16 * z)) as usize;
self.data[index] = state;
}
}
Loading

0 comments on commit bd63fa5

Please sign in to comment.