probabilistic world. 32 bit keys instead of a string
This causes most of the big benchmarks to fail, and it makes the positive_many_set three times faster. More integration is required to create a actual performance benefit by adjusting the search code
This commit is contained in:
parent
0717f6f4f0
commit
191fee36e1
3 changed files with 50 additions and 13 deletions
|
@ -1,23 +1,24 @@
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use std::{sync::Arc, ops::Sub, collections::HashMap};
|
use std::{collections::HashMap, num::NonZero, ops::Sub, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{Ok, anyhow};
|
use anyhow::{anyhow, Context, Ok};
|
||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
use rstar::{PointDistance, RTree, RTreeObject, AABB, Envelope};
|
use rstar::{PointDistance, RTree, RTreeObject, AABB, Envelope};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{RwLock, OwnedRwLockReadGuard, OwnedRwLockWriteGuard};
|
use tokio::sync::{RwLock, OwnedRwLockReadGuard, OwnedRwLockWriteGuard};
|
||||||
|
|
||||||
use crate::{turtle::TurtleCommand, paths::{self, TRANSPARENT}};
|
use crate::{pallette::{self, Pallette}, paths::{self, TRANSPARENT}, turtle::TurtleCommand};
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 8;
|
const CHUNK_SIZE: usize = 8;
|
||||||
const CHUNK_VOLUME: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
|
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);
|
const CHUNK_VEC: Vec3 = Vec3::new(CHUNK_SIZE as i32, CHUNK_SIZE as i32, CHUNK_SIZE as i32);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct World { // TODO: make r-trees faster than this, for my sanity
|
pub struct World {
|
||||||
index: HashMap<Vec3, usize>,
|
index: HashMap<Vec3, usize>,
|
||||||
data: Vec<Chunk>,
|
data: Vec<Chunk>,
|
||||||
last: Option<usize>,
|
last: Option<usize>,
|
||||||
|
pallette: Pallette,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
|
@ -26,11 +27,12 @@ impl World {
|
||||||
index: HashMap::new(),
|
index: HashMap::new(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
last: None,
|
last: None,
|
||||||
|
pallette: Pallette::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get(&self, block: Vec3) -> Option<Block> {
|
pub fn get(&self, block: Vec3) -> Option<Block> {
|
||||||
let chunk = self.get_chunk(block)?;
|
let chunk = self.get_chunk(block)?;
|
||||||
Some(chunk.get(block)?)
|
Some(chunk.get(block, &self.pallette)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, block: Block) {
|
pub fn set(&mut self, block: Block) {
|
||||||
|
@ -45,11 +47,11 @@ impl World {
|
||||||
|
|
||||||
match chunk {
|
match chunk {
|
||||||
Some(chunk) => {
|
Some(chunk) => {
|
||||||
self.data[chunk].set(block).unwrap();
|
self.data[chunk].set(block, &mut self.pallette).unwrap();
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let mut new_chunk = Chunk::new(chunk_coords);
|
let mut new_chunk = Chunk::new(chunk_coords);
|
||||||
new_chunk.set(block).unwrap();
|
new_chunk.set(block, &mut self.pallette).unwrap();
|
||||||
self.data.push(new_chunk);
|
self.data.push(new_chunk);
|
||||||
self.index.insert(chunk_coords, self.data.len() - 1);
|
self.index.insert(chunk_coords, self.data.len() - 1);
|
||||||
},
|
},
|
||||||
|
@ -113,31 +115,33 @@ pub struct Block {
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
pos: Vec3, /// position in chunk coordinates (world/16)
|
pos: Vec3, /// position in chunk coordinates (world/16)
|
||||||
data: [[[Option<String>;CHUNK_SIZE];CHUNK_SIZE];CHUNK_SIZE]
|
data: [[[Option<NonZero<u32>>;CHUNK_SIZE];CHUNK_SIZE];CHUNK_SIZE]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
fn new(pos: Vec3) -> Self {
|
fn new(pos: Vec3) -> Self {
|
||||||
let data :[[[Option<String>;CHUNK_SIZE];CHUNK_SIZE];CHUNK_SIZE]= Default::default();
|
let data :[[[Option<NonZero<u32>>;CHUNK_SIZE];CHUNK_SIZE];CHUNK_SIZE]= Default::default();
|
||||||
Self {
|
Self {
|
||||||
pos,
|
pos,
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, pos: Block) -> anyhow::Result<()> {
|
fn set(&mut self, pos: Block, pallette: &mut Pallette) -> anyhow::Result<()> {
|
||||||
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
||||||
if !self.contains(&pos.pos) {
|
if !self.contains(&pos.pos) {
|
||||||
return Err(anyhow!("out of bounds"));
|
return Err(anyhow!("out of bounds"));
|
||||||
}
|
}
|
||||||
let local: Vector3<usize> = (pos.pos - chunk).map(|n| n as usize);
|
let local: Vector3<usize> = (pos.pos - chunk).map(|n| n as usize);
|
||||||
|
|
||||||
self.data[local.x][local.y][local.z] = Some(pos.name);
|
let idx = pallette.number(&pos.name);
|
||||||
|
|
||||||
|
self.data[local.x][local.y][local.z] = Some(idx);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, pos: Vec3) -> Option<Block> {
|
fn get(&self, pos: Vec3, pallette: &Pallette) -> Option<Block> {
|
||||||
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
let chunk = self.pos.component_mul(&CHUNK_VEC);
|
||||||
let local = pos - chunk;
|
let local = pos - chunk;
|
||||||
if !self.contains(&pos) {
|
if !self.contains(&pos) {
|
||||||
|
@ -145,8 +149,10 @@ impl Chunk {
|
||||||
}
|
}
|
||||||
let local = local.map(|n| n as usize);
|
let local = local.map(|n| n as usize);
|
||||||
|
|
||||||
|
let idx = self.data[local.x][local.y][local.z]?;
|
||||||
|
|
||||||
Some(Block {
|
Some(Block {
|
||||||
name: self.data[local.x][local.y][local.z].clone()?,
|
name: pallette.name(idx)?,
|
||||||
pos,
|
pos,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ use indoc::formatdoc;
|
||||||
use crate::blocks::Block;
|
use crate::blocks::Block;
|
||||||
|
|
||||||
mod blocks;
|
mod blocks;
|
||||||
|
mod pallette;
|
||||||
mod names;
|
mod names;
|
||||||
mod mine;
|
mod mine;
|
||||||
mod fell;
|
mod fell;
|
||||||
|
|
30
server/src/pallette.rs
Normal file
30
server/src/pallette.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use std::{collections::HashMap, hash::{DefaultHasher, Hasher, SipHasher}, num::NonZero};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Pallette {
|
||||||
|
names: HashMap<u32, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pallette {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let names = HashMap::new();
|
||||||
|
Self { names }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn number(&mut self, name: &str) -> NonZero<u32> {
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
hasher.write(name.as_bytes());
|
||||||
|
|
||||||
|
let mut key = hasher.finish() as u32;
|
||||||
|
if key == 0 {key += 1}; // double the collisions!
|
||||||
|
self.names.insert(key,name.to_owned());
|
||||||
|
let key = unsafe { NonZero::new_unchecked(key) }; // SAFETY: see
|
||||||
|
// two lines above
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self, number: NonZero<u32>) -> Option<String> {
|
||||||
|
self.names.get(&number.get()).map(|s| s.to_owned())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue