Got a simple retrieve to pass
This commit is contained in:
parent
914290fe9e
commit
e5547477fc
@ -1,20 +1,21 @@
|
|||||||
use crate::storage::world::{BlockID, BlockPos, BlockRange, ChunkData, ChunkPos};
|
use crate::storage::world::{BlockID, BlockPos, BlockRange, ChunkData, ChunkPos};
|
||||||
use crate::storage_server::StorageServer;
|
use crate::storage_server::StorageServer;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct SingleBlock {
|
struct SingleBlock {
|
||||||
id: BlockID,
|
id: BlockID,
|
||||||
position: BlockPos,
|
position: BlockPos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct MultipleBlocks {
|
struct MultipleBlocks {
|
||||||
id: BlockID,
|
id: BlockID,
|
||||||
range: BlockRange,
|
range: BlockRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct SimpleServer {
|
pub struct SimpleServer {
|
||||||
chunks: Vec<ChunkData>,
|
chunks: Vec<ChunkData>,
|
||||||
single_blocks: Vec<SingleBlock>,
|
|
||||||
block_ranges: Vec<MultipleBlocks>,
|
block_ranges: Vec<MultipleBlocks>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,44 +23,79 @@ impl SimpleServer {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SimpleServer {
|
SimpleServer {
|
||||||
chunks: Vec::new(),
|
chunks: Vec::new(),
|
||||||
single_blocks: Vec::new(),
|
|
||||||
block_ranges: 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 {
|
impl StorageServer for SimpleServer {
|
||||||
fn change_block(&mut self, target_state: BlockID, world_position: BlockPos) {
|
fn change_block(&mut self, target_state: BlockID, world_position: &BlockPos) {
|
||||||
let chunk_pos = ChunkPos::from(&world_position);
|
let mut chunk = self.chunk_at_block_mut(world_position);
|
||||||
|
|
||||||
println!("Chunk position: {:?}", chunk_pos);
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
for chunk in self.chunks.iter_mut() {
|
let chunk = chunk.expect("Could not find chunk");
|
||||||
if chunk.pos.same_location(&chunk_pos) {
|
|
||||||
|
// Find the section that the block is located in
|
||||||
let current_section = &mut chunk.sections[world_position.y / 16];
|
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);
|
let chunk_array_index = current_section.index_of_block(&world_position);
|
||||||
current_section.update_block_at_index(&target_state, chunk_array_index);
|
current_section.update_block_at_index(&target_state, chunk_array_index);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.single_blocks.push(SingleBlock {
|
fn change_block_range(&mut self, target_stage: BlockID, start: &BlockPos, end: &BlockPos) {
|
||||||
id: target_state,
|
|
||||||
position: world_position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change_block_range(&mut self, target_stage: BlockID, start: BlockPos, end: BlockPos) {
|
|
||||||
self.block_ranges.push(MultipleBlocks {
|
self.block_ranges.push(MultipleBlocks {
|
||||||
id: target_stage,
|
id: target_stage,
|
||||||
range: BlockRange { start, end },
|
range: BlockRange {
|
||||||
|
start: start.clone(),
|
||||||
|
end: end.clone(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_block_at(&self, pos: BlockPos) -> BlockID {
|
fn read_block_at(&self, pos: &BlockPos) -> BlockID {
|
||||||
for block in self.single_blocks.iter() {
|
let chunk = self.chunk_at(pos);
|
||||||
if block.position == pos {
|
|
||||||
return block.id.clone();
|
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() {
|
for blocks in self.block_ranges.iter() {
|
||||||
|
@ -3,7 +3,7 @@ use std::cmp::{max, min};
|
|||||||
const SECTIONS_PER_CHUNK: usize = 16;
|
const SECTIONS_PER_CHUNK: usize = 16;
|
||||||
const SLICE_SIZE: usize = 16 * 16;
|
const SLICE_SIZE: usize = 16 * 16;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ChunkPos {
|
pub struct ChunkPos {
|
||||||
pub x: isize,
|
pub x: isize,
|
||||||
pub z: isize,
|
pub z: isize,
|
||||||
@ -18,18 +18,27 @@ impl From<&BlockPos> for ChunkPos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChunkPos {
|
#[derive(Debug)]
|
||||||
pub fn same_location(&self, other: &ChunkPos) -> bool {
|
|
||||||
self.x == other.x && self.z == other.z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ChunkData {
|
pub struct ChunkData {
|
||||||
pub pos: ChunkPos,
|
pub pos: ChunkPos,
|
||||||
pub sections: [ChunkSection; SECTIONS_PER_CHUNK],
|
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
|
// https://wiki.vg/Chunk_Format
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ChunkSection {
|
pub struct ChunkSection {
|
||||||
/// The number of non-empty blocks in the section. If completely full, the
|
/// 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
|
/// section contains a 16 x 16 x 16 cube of blocks = 4096 blocks
|
||||||
@ -42,6 +51,13 @@ pub struct ChunkSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn index_of_block(&self, pos: &BlockPos) -> usize {
|
||||||
let base_x = pos.x.rem_euclid(16) as usize;
|
let base_x = pos.x.rem_euclid(16) as usize;
|
||||||
let base_y = pos.y.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();
|
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
|
/// `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
|
/// BlockRange represents a range of blocks that have been updated
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BlockRange {
|
pub struct BlockRange {
|
||||||
pub start: BlockPos,
|
pub start: BlockPos,
|
||||||
pub end: BlockPos,
|
pub end: BlockPos,
|
||||||
@ -131,7 +154,7 @@ impl BlockRange {
|
|||||||
|
|
||||||
/// BlockID represents the type of block stored
|
/// BlockID represents the type of block stored
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum BlockID {
|
pub enum BlockID {
|
||||||
Empty,
|
Empty,
|
||||||
Generic,
|
Generic,
|
||||||
|
@ -4,12 +4,12 @@ use axum::{routing::get, Router};
|
|||||||
pub trait StorageServer {
|
pub trait StorageServer {
|
||||||
/// `change_block` changes the block at the world position given by `world_position` to the
|
/// `change_block` changes the block at the world position given by `world_position` to the
|
||||||
/// target block id `BlockID`
|
/// target block id `BlockID`
|
||||||
fn change_block(&mut self, target_state: BlockID, world_position: 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);
|
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
|
/// `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
|
/// 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]
|
#[tokio::main]
|
||||||
|
@ -26,7 +26,7 @@ mod tests {
|
|||||||
assert!(range.within_range(&test4));
|
assert!(range.within_range(&test4));
|
||||||
assert!(range.within_range(&test5));
|
assert!(range.within_range(&test5));
|
||||||
|
|
||||||
let test6 = BlockPos::new(-1, -1, 0);
|
let test6 = BlockPos::new(-1, 0, 0);
|
||||||
|
|
||||||
assert!(!range.within_range(&test6));
|
assert!(!range.within_range(&test6));
|
||||||
}
|
}
|
||||||
@ -35,10 +35,10 @@ mod tests {
|
|||||||
fn test_simple_insert() {
|
fn test_simple_insert() {
|
||||||
let mut server = SimpleServer::new();
|
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!(
|
assert_eq!(
|
||||||
server.read_block_at(BlockPos::new(0, 0, 0)),
|
server.read_block_at(&BlockPos::new(0, 0, 0)),
|
||||||
BlockID::Generic
|
BlockID::Generic
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user