Optimised sub-terrain chonk storage, fixed hash chunk bug, altered terrain base

This commit is contained in:
Joshua Barretto 2019-06-04 13:45:41 +01:00
parent 910eccee82
commit 92f2d36b0c
7 changed files with 141 additions and 60 deletions

1
Cargo.lock generated
View File

@ -2569,6 +2569,7 @@ dependencies = [
name = "veloren-client"
version = "0.2.0"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -7,6 +7,7 @@ edition = "2018"
[dependencies]
common = { package = "veloren-common", path = "../common" }
log = "0.4"
specs = "0.14"
vek = "0.9"
threadpool = "1.7"

View File

@ -12,18 +12,21 @@ use common::{
msg::{ClientMsg, ClientState, ServerInfo, ServerMsg},
net::PostBox,
state::State,
terrain::chonk::ChonkMetrics,
};
use std::{
collections::HashMap,
net::SocketAddr,
time::{Duration, Instant},
};
use threadpool::ThreadPool;
use log::info;
use vek::*;
const SERVER_TIMEOUT: Duration = Duration::from_secs(20);
const DEBUG_METRICS: bool = true;
pub enum Event {
Chat(String),
Disconnect,
@ -308,6 +311,15 @@ impl Client {
}
}
// Output debug metrics
if DEBUG_METRICS && self.tick % 600 == 0 {
let metrics = self.state
.terrain()
.iter()
.fold(ChonkMetrics::default(), |a, (_, c)| a + c.get_metrics());
info!("{:?}", metrics);
}
// 7) Finish the tick, pass control back to the frontend.
self.tick += 1;

View File

@ -4,7 +4,10 @@ use crate::{
volumes::chunk::{Chunk, ChunkErr},
};
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{
ops::Add,
collections::HashMap,
};
use vek::*;
#[derive(Debug)]
@ -43,6 +46,24 @@ impl Chonk {
self.z_offset + (self.sub_chunks.len() as u32 * SUB_CHUNK_HEIGHT) as i32
}
pub fn get_metrics(&self) -> ChonkMetrics {
ChonkMetrics {
chonks: 1,
homogeneous: self.sub_chunks
.iter()
.filter(|s| match s { SubChunk::Homogeneous(_) => true, _ => false })
.count(),
hash: self.sub_chunks
.iter()
.filter(|s| match s { SubChunk::Hash(_, _) => true, _ => false })
.count(),
heterogeneous: self.sub_chunks
.iter()
.filter(|s| match s { SubChunk::Heterogeneous(_) => true, _ => false })
.count(),
}
}
fn sub_chunk_idx(&self, z: i32) -> usize {
((z - self.z_offset) as u32 / SUB_CHUNK_HEIGHT as u32) as usize
}
@ -75,7 +96,7 @@ impl ReadVol for Chonk {
- Vec3::unit_z()
* (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32);
Ok(map.get(&rpos).unwrap_or(cblock))
Ok(map.get(&rpos.map(|e| e as u8)).unwrap_or(cblock))
}
SubChunk::Heterogeneous(chunk) => {
let rpos = pos
@ -92,59 +113,61 @@ impl ReadVol for Chonk {
impl WriteVol for Chonk {
#[inline(always)]
fn set(&mut self, pos: Vec3<i32>, block: Block) -> Result<(), ChonkError> {
if pos.z < self.z_offset {
Err(ChonkError::OutOfBounds)
} else {
let sub_chunk_idx = self.sub_chunk_idx(pos.z);
while pos.z < self.z_offset {
self.sub_chunks.insert(0, SubChunk::Homogeneous(self.below));
self.z_offset -= SUB_CHUNK_HEIGHT as i32;
}
while self.sub_chunks.get(sub_chunk_idx).is_none() {
self.sub_chunks.push(SubChunk::Homogeneous(self.above));
}
let rpos = pos
- Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32);
match &mut self.sub_chunks[sub_chunk_idx] {
// Can't fail
SubChunk::Homogeneous(cblock) if *cblock == block => Ok(()),
SubChunk::Homogeneous(cblock) => {
let mut map = HashMap::new();
map.insert(rpos, block);
self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map);
Ok(())
}
SubChunk::Hash(cblock, map) if map.len() < 1024 => {
map.insert(rpos, block);
Ok(())
}
SubChunk::Hash(cblock, map) => {
let mut new_chunk = Chunk::filled(*cblock, ());
new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope)
for (map_pos, map_block) in map {
new_chunk.set(*map_pos, *map_block).unwrap(); // Can't fail (I hope!)
}
self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk);
Ok(())
}
/*
SubChunk::Homogeneous(cblock) => {
let mut new_chunk = Chunk::filled(*cblock, ());
new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope!)
self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk);
Ok(())
}
*/
SubChunk::Heterogeneous(chunk) => chunk
.set(rpos, block)
.map_err(|err| ChonkError::ChunkError(err)),
//_ => unimplemented!(),
let sub_chunk_idx = self.sub_chunk_idx(pos.z);
while self.sub_chunks.get(sub_chunk_idx).is_none() {
self.sub_chunks.push(SubChunk::Homogeneous(self.above));
}
let rpos = pos
- Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32);
match &mut self.sub_chunks[sub_chunk_idx] {
// Can't fail
SubChunk::Homogeneous(cblock) if block == *cblock => Ok(()),
SubChunk::Homogeneous(cblock) => {
let mut map = HashMap::new();
map.insert(rpos.map(|e| e as u8), block);
self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map);
Ok(())
},
SubChunk::Hash(cblock, map) if block == *cblock => Ok(()),
SubChunk::Hash(cblock, map) if map.len() < 4096 => {
map.insert(rpos.map(|e| e as u8), block);
Ok(())
},
SubChunk::Hash(cblock, map) => {
let mut new_chunk = Chunk::filled(*cblock, ());
new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope)
for (map_pos, map_block) in map {
new_chunk.set(map_pos.map(|e| e as i32), *map_block).unwrap(); // Can't fail (I hope!)
}
self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk);
Ok(())
},
/*
SubChunk::Homogeneous(cblock) => {
let mut new_chunk = Chunk::filled(*cblock, ());
new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope!)
self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk);
Ok(())
}
*/
SubChunk::Heterogeneous(chunk) => chunk
.set(rpos, block)
.map_err(|err| ChonkError::ChunkError(err)),
//_ => unimplemented!(),
}
}
}
@ -152,7 +175,7 @@ impl WriteVol for Chonk {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SubChunk {
Homogeneous(Block),
Hash(Block, HashMap<Vec3<i32>, Block>),
Hash(Block, HashMap<Vec3<u8>, Block>),
Heterogeneous(Chunk<Block, TerrainChunkSize, ()>),
}
@ -161,3 +184,35 @@ impl SubChunk {
SubChunk::Homogeneous(block)
}
}
#[derive(Debug)]
pub struct ChonkMetrics {
chonks: usize,
homogeneous: usize,
hash: usize,
heterogeneous: usize,
}
impl Default for ChonkMetrics {
fn default() -> Self {
ChonkMetrics {
chonks: 0,
homogeneous: 0,
hash: 0,
heterogeneous: 0,
}
}
}
impl Add for ChonkMetrics {
type Output = Self;
fn add(self, other: Self::Output) -> Self {
Self::Output {
chonks: self.chonks + other.chonks,
homogeneous: self.homogeneous + other.homogeneous,
hash: self.hash + other.hash,
heterogeneous: self.heterogeneous + other.heterogeneous,
}
}
}

View File

@ -151,8 +151,8 @@ impl Terrain {
.fold(i32::MIN, |max, (_, chunk)| chunk.get_z_max().max(max));
let aabb = Aabb {
min: Vec3::from(aabr.min) + Vec3::unit_z() * z_min,
max: Vec3::from(aabr.max) + Vec3::unit_z() * z_max,
min: Vec3::from(aabr.min) + Vec3::unit_z() * (z_min - 1),
max: Vec3::from(aabr.max) + Vec3::unit_z() * (z_max + 1),
};
// Clone various things so that they can be moved into the thread.

View File

@ -49,7 +49,10 @@ impl World {
let warp_nz = BasicMulti::new().set_octaves(3).set_seed(self.sim.seed + 0);
let base_z = match self.sim.get_base_z(chunk_pos.map(|e| e as u32)) {
let base_z = match self.sim
.get(chunk_pos.map(|e| e as u32))
.map(|chunk| chunk.get_base_z())
{
Some(base_z) => base_z as i32,
None => return TerrainChunk::new(0, water, air, TerrainChunkMeta::void()),
};
@ -64,12 +67,17 @@ impl World {
+ Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32);
let wposf2d = wpos2d.map(|e| e as f64);
let min_z = self
.sim
.get_interpolated(wpos2d, |chunk| chunk.get_min_z())
.unwrap_or(0.0) as i32;
let max_z = self
.sim
.get_interpolated(wpos2d, |chunk| chunk.get_max_z())
.unwrap_or(0.0) as i32;
for z in base_z..max_z.max(sim::SEA_LEVEL as i32) {
for z in min_z..max_z {
let lpos = Vec3::new(x, y, z);
let wpos =
lpos + Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32);

View File

@ -746,10 +746,14 @@ impl SimChunk {
}
pub fn get_base_z(&self) -> f32 {
self.alt - 8.0
}
pub fn get_min_z(&self) -> f32 {
self.alt - Z_TOLERANCE.0 * (self.chaos + 0.3)
}
pub fn get_max_z(&self) -> f32 {
self.alt + Z_TOLERANCE.1
(self.alt + Z_TOLERANCE.1).max(SEA_LEVEL)
}
}