From e5547477fc7a2b5df0faea6d29db4e7564e043d8 Mon Sep 17 00:00:00 2001 From: Nicholas Novak <34256932+NickyBoy89@users.noreply.github.com> Date: Mon, 2 Oct 2023 15:56:33 -0700 Subject: [PATCH] Got a simple retrieve to pass --- src/simple_server/server.rs | 84 ++++++++++++++++++++++++++----------- src/storage/world.rs | 39 +++++++++++++---- src/storage_server.rs | 6 +-- src/tests/insert_one.rs | 6 +-- 4 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/simple_server/server.rs b/src/simple_server/server.rs index de3589b..182cf35 100644 --- a/src/simple_server/server.rs +++ b/src/simple_server/server.rs @@ -1,20 +1,21 @@ use crate::storage::world::{BlockID, BlockPos, BlockRange, ChunkData, ChunkPos}; use crate::storage_server::StorageServer; -#[derive(Clone)] +#[derive(Debug, Clone)] struct SingleBlock { id: BlockID, position: BlockPos, } +#[derive(Debug)] struct MultipleBlocks { id: BlockID, range: BlockRange, } +#[derive(Debug)] pub struct SimpleServer { chunks: Vec, - single_blocks: Vec, block_ranges: Vec, } @@ -22,44 +23,79 @@ impl SimpleServer { pub fn new() -> Self { SimpleServer { chunks: Vec::new(), - single_blocks: Vec::new(), block_ranges: Vec::new(), } } + + fn chunk_at_block_mut(&mut self, block_pos: &BlockPos) -> Option<&mut ChunkData> { + // Find what chunk the block is in + let chunk_pos = ChunkPos::from(block_pos); + + // Find the chunk with the correct index + for chunk in self.chunks.iter_mut() { + if chunk.pos == chunk_pos { + return Some(chunk); + } + } + + None + } + + fn chunk_at(&self, block_pos: &BlockPos) -> Option<&ChunkData> { + let chunk_pos = ChunkPos::from(block_pos); + + for chunk in self.chunks.iter() { + if chunk.pos == chunk_pos { + return Some(chunk); + } + } + + None + } + + fn create_chunk_at(&mut self, chunk_pos: &ChunkPos) { + let new_chunk = ChunkData::new(chunk_pos); + + self.chunks.push(new_chunk); + } } impl StorageServer for SimpleServer { - fn change_block(&mut self, target_state: BlockID, world_position: BlockPos) { - let chunk_pos = ChunkPos::from(&world_position); + fn change_block(&mut self, target_state: BlockID, world_position: &BlockPos) { + let mut chunk = self.chunk_at_block_mut(world_position); - println!("Chunk position: {:?}", chunk_pos); - - for chunk in self.chunks.iter_mut() { - if chunk.pos.same_location(&chunk_pos) { - let current_section = &mut chunk.sections[world_position.y / 16]; - let chunk_array_index = current_section.index_of_block(&world_position); - current_section.update_block_at_index(&target_state, chunk_array_index); - } + // Test if there is a chunk that already exists + if chunk.is_none() { + self.create_chunk_at(&ChunkPos::from(world_position)); + chunk = self.chunk_at_block_mut(world_position); } - self.single_blocks.push(SingleBlock { - id: target_state, - position: world_position, - }); + let chunk = chunk.expect("Could not find chunk"); + + // Find the section that the block is located in + let current_section = &mut chunk.sections[world_position.y / 16]; + // Find the index that the block is at, and update its state + let chunk_array_index = current_section.index_of_block(&world_position); + current_section.update_block_at_index(&target_state, chunk_array_index); } - fn change_block_range(&mut self, target_stage: BlockID, start: BlockPos, end: BlockPos) { + fn change_block_range(&mut self, target_stage: BlockID, start: &BlockPos, end: &BlockPos) { self.block_ranges.push(MultipleBlocks { id: target_stage, - range: BlockRange { start, end }, + range: BlockRange { + start: start.clone(), + end: end.clone(), + }, }) } - fn read_block_at(&self, pos: BlockPos) -> BlockID { - for block in self.single_blocks.iter() { - if block.position == pos { - return block.id.clone(); - } + fn read_block_at(&self, pos: &BlockPos) -> BlockID { + let chunk = self.chunk_at(pos); + + if let Some(chunk) = chunk { + let chunk_section = chunk.section_for(pos); + + return chunk_section.get_block_at_index(pos).clone(); } for blocks in self.block_ranges.iter() { diff --git a/src/storage/world.rs b/src/storage/world.rs index f7cc714..f02e632 100644 --- a/src/storage/world.rs +++ b/src/storage/world.rs @@ -3,7 +3,7 @@ use std::cmp::{max, min}; const SECTIONS_PER_CHUNK: usize = 16; const SLICE_SIZE: usize = 16 * 16; -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq)] pub struct ChunkPos { pub x: isize, pub z: isize, @@ -18,18 +18,27 @@ impl From<&BlockPos> for ChunkPos { } } -impl ChunkPos { - pub fn same_location(&self, other: &ChunkPos) -> bool { - self.x == other.x && self.z == other.z - } -} - +#[derive(Debug)] pub struct ChunkData { pub pos: ChunkPos, pub sections: [ChunkSection; SECTIONS_PER_CHUNK], } +impl ChunkData { + pub fn new(pos: &ChunkPos) -> Self { + ChunkData { + pos: pos.clone(), + sections: [ChunkSection::new(); SECTIONS_PER_CHUNK], + } + } + + pub fn section_for(&self, block_pos: &BlockPos) -> &ChunkSection { + &self.sections[block_pos.y % 16] + } +} + // https://wiki.vg/Chunk_Format +#[derive(Debug, Clone, Copy)] pub struct ChunkSection { /// The number of non-empty blocks in the section. If completely full, the /// section contains a 16 x 16 x 16 cube of blocks = 4096 blocks @@ -42,6 +51,13 @@ pub struct ChunkSection { } impl ChunkSection { + pub fn new() -> Self { + ChunkSection { + block_count: 0, + block_states: [BlockID::Empty; 16 * 16 * 16], + } + } + pub fn index_of_block(&self, pos: &BlockPos) -> usize { let base_x = pos.x.rem_euclid(16) as usize; let base_y = pos.y.rem_euclid(16) as usize; @@ -74,6 +90,12 @@ impl ChunkSection { self.block_states[index] = id.clone(); } + + pub fn get_block_at_index(&self, pos: &BlockPos) -> &BlockID { + let array_index = self.index_of_block(pos); + + &self.block_states[array_index] + } } /// `BlockPos` represents the location of a block in world space @@ -91,6 +113,7 @@ impl BlockPos { } /// BlockRange represents a range of blocks that have been updated +#[derive(Debug)] pub struct BlockRange { pub start: BlockPos, pub end: BlockPos, @@ -131,7 +154,7 @@ impl BlockRange { /// BlockID represents the type of block stored #[repr(u8)] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum BlockID { Empty, Generic, diff --git a/src/storage_server.rs b/src/storage_server.rs index 948c966..6f60dae 100644 --- a/src/storage_server.rs +++ b/src/storage_server.rs @@ -4,12 +4,12 @@ use axum::{routing::get, Router}; pub trait StorageServer { /// `change_block` changes the block at the world position given by `world_position` to the /// target block id `BlockID` - fn change_block(&mut self, target_state: BlockID, world_position: BlockPos); - fn change_block_range(&mut self, target_stage: BlockID, start: BlockPos, end: BlockPos); + fn change_block(&mut self, target_state: BlockID, world_position: &BlockPos); + fn change_block_range(&mut self, target_stage: BlockID, start: &BlockPos, end: &BlockPos); /// `read_block_at` returns the id of the block at the location specified /// If no block is present, the returned id will be of the empty type - fn read_block_at(&self, pos: BlockPos) -> BlockID; + fn read_block_at(&self, pos: &BlockPos) -> BlockID; } #[tokio::main] diff --git a/src/tests/insert_one.rs b/src/tests/insert_one.rs index d252f8b..7a0c1b5 100644 --- a/src/tests/insert_one.rs +++ b/src/tests/insert_one.rs @@ -26,7 +26,7 @@ mod tests { assert!(range.within_range(&test4)); assert!(range.within_range(&test5)); - let test6 = BlockPos::new(-1, -1, 0); + let test6 = BlockPos::new(-1, 0, 0); assert!(!range.within_range(&test6)); } @@ -35,10 +35,10 @@ mod tests { fn test_simple_insert() { let mut server = SimpleServer::new(); - server.change_block(BlockID::Generic, BlockPos::new(0, 0, 0)); + server.change_block(BlockID::Generic, &BlockPos::new(0, 0, 0)); assert_eq!( - server.read_block_at(BlockPos::new(0, 0, 0)), + server.read_block_at(&BlockPos::new(0, 0, 0)), BlockID::Generic ); }