diff --git a/server/src/blocks.rs b/server/src/blocks.rs index 4b05d91..b5579fb 100644 --- a/server/src/blocks.rs +++ b/server/src/blocks.rs @@ -1,3 +1,4 @@ +extern crate test; use std::{sync::Arc, ops::Sub, collections::HashMap}; use anyhow::{Ok, anyhow}; @@ -8,16 +9,24 @@ use tokio::sync::{RwLock, OwnedRwLockReadGuard}; use crate::{turtle::TurtleCommand, paths::{self, TRANSPARENT}}; -const CHUNK_SIZE: usize = 16; +const CHUNK_SIZE: usize = 4; const CHUNK_VOLUME: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; const CHUNK_VEC: Vec3 = Vec3::new(CHUNK_SIZE as i32, CHUNK_SIZE as i32, CHUNK_SIZE as i32); #[derive(Serialize, Deserialize)] -pub struct World(HashMap); // TODO: make r-trees faster than this, for my sanity +pub struct World { // TODO: make r-trees faster than this, for my sanity + index: HashMap, + data: Vec, + last: Option, +} impl World { pub fn new() -> Self { - World(HashMap::new()) + World{ + index: HashMap::new(), + data: Vec::new(), + last: None, + } } pub fn get(&self, block: Vec3) -> Option { let chunk = self.get_chunk(block)?; @@ -25,22 +34,36 @@ impl World { } pub fn set(&mut self, block: Block) { - let chunk = block.pos.map(|n| i32::div_floor(n,CHUNK_SIZE as i32)); - match self.0.get_mut(&chunk) { + let chunk_coords = block.pos.map(|n| i32::div_floor(n,CHUNK_SIZE as i32)); + + let chunk = self.last + .filter(|n| self.data[*n].contains(&block.pos)) + .or_else(|| { + self.index.get(&chunk_coords).map(|c| *c) + }) + .map(|n| *self.last.insert(n)); + + match chunk { Some(chunk) => { - chunk.set(block).unwrap(); + self.data[chunk].set(block).unwrap(); }, None => { - let mut new_chunk = Chunk::new(chunk); + let mut new_chunk = Chunk::new(chunk_coords); new_chunk.set(block).unwrap(); - self.0.insert(chunk, new_chunk); + self.data.push(new_chunk); + self.index.insert(chunk_coords, self.data.len() - 1); }, } } fn get_chunk(&self, block: Vec3) -> Option<&Chunk> { let block = block.map(|n| i32::div_floor(n,CHUNK_SIZE as i32)); - self.0.get(&block) + if let Some(last) = self.last { + if self.data[last].contains(&block) { + return Some(&self.data[last]) + } + } + self.index.get(&block).map(|i| &self.data[*i]) } } @@ -127,7 +150,7 @@ impl Chunk { fn contains(&self, pos:&Vec3) -> bool { let chunk = self.pos.component_mul(&CHUNK_VEC); let local = pos - chunk; - local >= Vec3::zeros() && local <= CHUNK_VEC + local >= Vec3::zeros() && local < CHUNK_VEC } } @@ -281,6 +304,10 @@ pub fn nearest(from: Vec3, to: Vec3) -> Position { #[cfg(test)] mod tests { + use test::Bencher; + + use crate::mine::fill; + use super::*; fn single_point(point: Vec3) { @@ -290,6 +317,19 @@ mod tests { assert_eq!("a", world.get(point).unwrap().name); } + fn many(point: Vec3, size: Vec3) { + let mut world = World::new(); + for i in 0..size.product() { + let block = fill(size, i) + point; + world.set(Block { name: i.to_string(), pos: block}); + } + + for i in 0..size.product() { + let block = fill(size, i) + point; + assert_eq!(i.to_string(), world.get(block).unwrap().name) + } + } + #[test] fn origin() { single_point(Vec3::zeros()) @@ -302,4 +342,24 @@ mod tests { fn small() { single_point(Vec3::new(-1212,100,-1292)) } + + #[test] + fn positive_many() { + many(Vec3::new(1212,100,1292), Vec3::new(100, 100, 100)) + } + + #[test] + fn negative_many() { + many(Vec3::new(-1212,100,-1292), Vec3::new(100, 100, 100)) + } + + #[bench] + fn positive_several(b: &mut Bencher) { + b.iter(||many(Vec3::new(1212,100,1292), Vec3::new(100, 1, 30))); + } + + #[bench] + fn positive_many_bench(b: &mut Bencher) { + b.iter(||many(Vec3::new(1212,100,1292), Vec3::new(50, 50, 50))); + } } diff --git a/server/src/main.rs b/server/src/main.rs index e2fa877..3e4deac 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,4 +1,4 @@ -#![feature(iter_map_windows, iter_collect_into, int_roundings)] +#![feature(iter_map_windows, iter_collect_into, int_roundings, test)] use std::{collections::VecDeque, io::ErrorKind, sync::Arc, env::args, path, borrow::BorrowMut, time::Duration}; diff --git a/server/src/turtle.rs b/server/src/turtle.rs index 94bc33b..8c9839b 100644 --- a/server/src/turtle.rs +++ b/server/src/turtle.rs @@ -198,7 +198,11 @@ impl TurtleCommander { // is left to read garbage }; - let resp = recv.await.unwrap(); + let resp = recv.await.unwrap_or_else(|_| { + error!("server dissapering"); + TurtleInfo::from_update(TurtleUpdate { fuel: self.fuel(), ahead: "".into(), above: "".into(), below: "".into(), ret: TurtleCommandResponse::Failure }, self.name(), Position::new(Vec3::zeros(), Direction::North)) + }); + let mut pos = self.pos.write().await; *pos = resp.pos; self.fuel.store(resp.fuel, std::sync::atomic::Ordering::SeqCst);