From 914290fe9e06b9daea08939d148dd678e2dc52da Mon Sep 17 00:00:00 2001 From: Nicholas Novak <34256932+NickyBoy89@users.noreply.github.com> Date: Sun, 1 Oct 2023 01:06:22 -0700 Subject: [PATCH] change: All the work from the coffee shops and started implementing the first server --- src/main.rs | 2 + src/simple_server/mod.rs | 1 + src/simple_server/server.rs | 73 +++++++++++++++++++++ src/storage/interface.rs | 11 ---- src/storage/mod.rs | 4 +- src/storage/world.rs | 123 +++++++++++++++++++++++++++++++++--- src/storage_server.rs | 12 ++++ src/tests/insert_one.rs | 42 +++++++++++- 8 files changed, 243 insertions(+), 25 deletions(-) create mode 100644 src/simple_server/mod.rs create mode 100644 src/simple_server/server.rs delete mode 100644 src/storage/interface.rs diff --git a/src/main.rs b/src/main.rs index fbb2b49..a6b47cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod simple_server; mod storage; mod storage_server; use clap::Parser; @@ -21,5 +22,6 @@ fn main() { println!("Proxy was enabled"); storage_server::main(); } + println!("Hello, world!"); } diff --git a/src/simple_server/mod.rs b/src/simple_server/mod.rs new file mode 100644 index 0000000..74f47ad --- /dev/null +++ b/src/simple_server/mod.rs @@ -0,0 +1 @@ +pub mod server; diff --git a/src/simple_server/server.rs b/src/simple_server/server.rs new file mode 100644 index 0000000..de3589b --- /dev/null +++ b/src/simple_server/server.rs @@ -0,0 +1,73 @@ +use crate::storage::world::{BlockID, BlockPos, BlockRange, ChunkData, ChunkPos}; +use crate::storage_server::StorageServer; + +#[derive(Clone)] +struct SingleBlock { + id: BlockID, + position: BlockPos, +} + +struct MultipleBlocks { + id: BlockID, + range: BlockRange, +} + +pub struct SimpleServer { + chunks: Vec, + single_blocks: Vec, + block_ranges: Vec, +} + +impl SimpleServer { + pub fn new() -> Self { + SimpleServer { + chunks: Vec::new(), + single_blocks: Vec::new(), + block_ranges: Vec::new(), + } + } +} + +impl StorageServer for SimpleServer { + fn change_block(&mut self, target_state: BlockID, world_position: BlockPos) { + let chunk_pos = ChunkPos::from(&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); + } + } + + self.single_blocks.push(SingleBlock { + id: target_state, + position: world_position, + }); + } + + 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 }, + }) + } + + fn read_block_at(&self, pos: BlockPos) -> BlockID { + for block in self.single_blocks.iter() { + if block.position == pos { + return block.id.clone(); + } + } + + for blocks in self.block_ranges.iter() { + if blocks.range.within_range(&pos) { + return blocks.id.clone(); + } + } + + BlockID::Empty + } +} diff --git a/src/storage/interface.rs b/src/storage/interface.rs deleted file mode 100644 index 4b9466c..0000000 --- a/src/storage/interface.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::storage::world::{BlockID, BlockPos}; - -enum StorageInterface { - /// `ChangeBlock` changes the block at the world position given by `world_position` to the - /// target block id `BlockID` - ChangeBlock { - target_state: BlockID, - world_position: BlockPos, - }, - ChangeBlockRange(BlockID, BlockPos, BlockPos), -} diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 52c3d3a..f2e43b5 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,2 +1,2 @@ -mod interface; -mod world; +pub mod world; + diff --git a/src/storage/world.rs b/src/storage/world.rs index bd5b411..f7cc714 100644 --- a/src/storage/world.rs +++ b/src/storage/world.rs @@ -1,15 +1,36 @@ -type ChunkCoordinate = isize; +use std::cmp::{max, min}; const SECTIONS_PER_CHUNK: usize = 16; +const SLICE_SIZE: usize = 16 * 16; -struct ChunkData { - x: ChunkCoordinate, - y: ChunkCoordinate, - sections: [ChunkSection; SECTIONS_PER_CHUNK], +#[derive(Debug)] +pub struct ChunkPos { + pub x: isize, + pub z: isize, +} + +impl From<&BlockPos> for ChunkPos { + fn from(value: &BlockPos) -> Self { + ChunkPos { + x: value.x / 16, + z: value.z / 16, + } + } +} + +impl ChunkPos { + pub fn same_location(&self, other: &ChunkPos) -> bool { + self.x == other.x && self.z == other.z + } +} + +pub struct ChunkData { + pub pos: ChunkPos, + pub sections: [ChunkSection; SECTIONS_PER_CHUNK], } // https://wiki.vg/Chunk_Format -struct ChunkSection { +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 /// If the section is empty, this is skipped @@ -17,18 +38,100 @@ struct ChunkSection { /// The data for all the blocks in the chunk /// The representation for this may be different based on the number of /// non-empty blocks - block_states: [BlockID; 4096], + block_states: [BlockID; 16 * 16 * 16], +} + +impl ChunkSection { + 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; + let base_z = pos.z.rem_euclid(16) as usize; + + (base_y * SLICE_SIZE) + (base_z * 16) + base_x + } + + pub fn update_block_at_index(&mut self, id: &BlockID, index: usize) { + let existing_block = &self.block_states[index]; + match existing_block { + BlockID::Empty => match id { + BlockID::Generic => { + // If the existing block is empty, and the block that we + // are inserting is non-empty, increment the number of blocks + self.block_count += 1; + } + _ => {} + }, + _ => match id { + BlockID::Empty => { + // If the existing block is non-empty, and the block that + // we are inserting is empty, then decrement the number of + // blocks + self.block_count -= 1; + } + _ => {} + }, + } + + self.block_states[index] = id.clone(); + } } /// `BlockPos` represents the location of a block in world space +#[derive(Debug, Clone, PartialEq)] pub struct BlockPos { - x: isize, - y: isize, - z: isize, + pub x: isize, + pub y: usize, + pub z: isize, +} + +impl BlockPos { + pub fn new(x: isize, y: usize, z: isize) -> Self { + BlockPos { x, y, z } + } +} + +/// BlockRange represents a range of blocks that have been updated +pub struct BlockRange { + pub start: BlockPos, + pub end: BlockPos, +} + +impl BlockRange { + pub fn new(start: &BlockPos, end: &BlockPos) -> Self { + BlockRange { + start: start.clone(), + end: end.clone(), + } + } + pub fn within_range(&self, pos: &BlockPos) -> bool { + let minx = min(self.start.x, self.end.x); + let maxx = max(self.start.x, self.end.x); + + if pos.x < minx || pos.x > maxx { + return false; + } + + let miny = min(self.start.y, self.end.y); + let maxy = max(self.start.y, self.end.y); + + if pos.y < miny || pos.y > maxy { + return false; + } + + let minz = min(self.start.z, self.end.z); + let maxz = max(self.start.z, self.end.z); + + if pos.z < minz || pos.z > maxz { + return false; + } + + true + } } /// BlockID represents the type of block stored #[repr(u8)] +#[derive(Debug, Clone, PartialEq)] pub enum BlockID { Empty, Generic, diff --git a/src/storage_server.rs b/src/storage_server.rs index eeea872..948c966 100644 --- a/src/storage_server.rs +++ b/src/storage_server.rs @@ -1,5 +1,17 @@ +use crate::storage::world::{BlockID, BlockPos}; 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); + + /// `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; +} + #[tokio::main] pub async fn main() { let app = Router::new().route("/", get(|| async { "Hello World" })); diff --git a/src/tests/insert_one.rs b/src/tests/insert_one.rs index 70912be..d252f8b 100644 --- a/src/tests/insert_one.rs +++ b/src/tests/insert_one.rs @@ -1,7 +1,45 @@ +use crate::simple_server::server::SimpleServer; +use crate::storage::world::{BlockPos, BlockRange}; + #[cfg(test)] mod tests { + use crate::{storage::world::BlockID, storage_server::StorageServer}; + + use super::*; #[test] - fn add_one_block() { - assert_eq!(1, 1); + fn within_two_dimensions() { + // Get two points on the same z axis + let first = BlockPos::new(0, 0, 0); + let second = BlockPos::new(4, 4, 0); + + let range = BlockRange::new(&first, &second); + + let test1 = BlockPos::new(1, 1, 0); + let test2 = BlockPos::new(0, 0, 0); + let test3 = BlockPos::new(0, 4, 0); + let test4 = BlockPos::new(4, 4, 0); + let test5 = BlockPos::new(4, 0, 0); + + assert!(range.within_range(&test1)); + assert!(range.within_range(&test2)); + assert!(range.within_range(&test3)); + assert!(range.within_range(&test4)); + assert!(range.within_range(&test5)); + + let test6 = BlockPos::new(-1, -1, 0); + + assert!(!range.within_range(&test6)); + } + + #[test] + fn test_simple_insert() { + let mut server = SimpleServer::new(); + + server.change_block(BlockID::Generic, BlockPos::new(0, 0, 0)); + + assert_eq!( + server.read_block_at(BlockPos::new(0, 0, 0)), + BlockID::Generic + ); } }