Implement chunk loading and saving
Some checks reported errors
continuous-integration/drone/push Build was killed

This commit is contained in:
Sijmen 2021-06-03 00:08:49 +02:00
parent 15247d12d4
commit 11b6abb0d4
Signed by: vijfhoek
GPG key ID: 82D05C89B28B0DAE
5 changed files with 209 additions and 18 deletions

4
.gitignore vendored
View file

@ -2,3 +2,7 @@
/generated/
/flamegraph.svg
/perf.data*
/chunks/
profile.txt
callgrind.out.*

68
Cargo.lock generated
View file

@ -1128,8 +1128,12 @@ dependencies = [
"log",
"noise",
"rayon",
"rmp-serde",
"serde",
"serde_repr",
"wgpu",
"winit",
"zstd",
]
[[package]]
@ -1603,6 +1607,27 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rmp"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6"
dependencies = [
"byteorder",
"num-traits",
]
[[package]]
name = "rmp-serde"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "839395ef53057db96b84c9238ab29e1a13f2e5c8ec9f66bef853ab4197303924"
dependencies = [
"byteorder",
"rmp",
"serde",
]
[[package]]
name = "ryu"
version = "1.0.5"
@ -1626,6 +1651,9 @@ name = "serde"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
@ -1649,6 +1677,17 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "slab"
version = "0.4.3"
@ -2023,3 +2062,32 @@ dependencies = [
"maybe-uninit",
"pkg-config",
]
[[package]]
name = "zstd"
version = "0.8.2+zstd.1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c83508bcbbdc9c3abcf77e8e56773d3ffcd2479e0933caab2e7d6b5a9e183aae"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "4.1.0+zstd.1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d30375f78e185ca4c91930f42ea2c0162f9aa29737032501f93b79266d985ae7"
dependencies = [
"libc",
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "1.6.0+zstd.1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2141bed8922b427761470e6bbfeff255da94fa20b0bbeab0d9297fcaf71e3aa7"
dependencies = [
"cc",
"libc",
]

View file

@ -19,7 +19,11 @@ noise = "0.7.0"
rayon = "1.5.1"
wgpu = "0.8.1"
winit = { version = "0.25.0", default_features = false, features = ["x11", "web-sys"] }
serde_repr = "0.1.7"
rmp-serde = "0.15.4"
itertools = "0.10.0"
serde = { version = "1.0.126", features = ["derive"] }
zstd = "0.8.2"
[profile.release]
debug = true

View file

@ -1,4 +1,8 @@
use std::{collections::VecDeque, usize};
use std::{
collections::VecDeque,
io::{Read, Write},
usize,
};
use crate::{geometry::Geometry, quad::Quad, vertex::BlockVertex};
use ahash::{AHashMap, AHashSet};
@ -6,17 +10,26 @@ use cgmath::{Point3, Vector3};
use noise::utils::{NoiseMapBuilder, PlaneMapBuilder};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::Serialize;
use serde::{
de::{SeqAccess, Visitor},
ser::{SerializeSeq, Serializer},
Deserialize,
};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum BlockType {
Cobblestone,
Dirt,
Stone,
Grass,
Bedrock,
Sand,
Gravel,
Water,
Cobblestone = 1,
Dirt = 2,
Stone = 3,
Grass = 4,
Bedrock = 5,
Sand = 6,
Gravel = 7,
Water = 8,
}
impl BlockType {
@ -50,7 +63,7 @@ pub const FACE_FRONT: FaceFlags = 32;
pub const FACE_ALL: FaceFlags =
FACE_LEFT | FACE_RIGHT | FACE_BOTTOM | FACE_TOP | FACE_BACK | FACE_FRONT;
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Block {
pub block_type: BlockType,
}
@ -60,10 +73,63 @@ pub const CHUNK_ISIZE: isize = CHUNK_SIZE as isize;
type ChunkBlocks = [[[Option<Block>; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE];
#[derive(Clone, Default)]
pub struct Chunk {
pub blocks: ChunkBlocks,
}
impl Serialize for Chunk {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(CHUNK_SIZE.pow(3)))?;
for layer in self.blocks.iter() {
for row in layer {
for block in row {
seq.serialize_element(block)?;
}
}
}
seq.end()
}
}
struct ChunkVisitor;
impl<'de> Visitor<'de> for ChunkVisitor {
type Value = Chunk;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a chunk")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut chunk = Chunk::default();
for layer in chunk.blocks.iter_mut() {
for row in layer {
for block in row {
*block = seq.next_element()?.unwrap();
}
}
}
Ok(chunk)
}
}
impl<'de> Deserialize<'de> for Chunk {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(ChunkVisitor)
}
}
impl Chunk {
pub fn generate(chunk_x: i32, chunk_y: i32, chunk_z: i32) -> Self {
let fbm = noise::Fbm::new();
@ -333,4 +399,27 @@ impl Chunk {
Self::quads_to_geometry(quads)
}
pub fn save(&self, position: Point3<isize>) -> anyhow::Result<()> {
let data = rmp_serde::encode::to_vec_named(self)?;
let compressed = zstd::block::compress(&data, 0)?;
let path = format!("chunks/{}_{}_{}.bin", position.x, position.y, position.z);
let mut file = std::fs::File::create(&path)?;
file.write(&compressed)?;
Ok(())
}
pub fn load(&mut self, position: Point3<isize>) -> anyhow::Result<()> {
let path = format!("chunks/{}_{}_{}.bin", position.x, position.y, position.z);
let mut file = std::fs::File::open(&path)?;
let mut compressed = Vec::new();
file.read_to_end(&mut compressed)?;
let data = zstd::block::decompress(&compressed, 1024 * 1024)?;
*self = rmp_serde::decode::from_slice(&data)?;
Ok(())
}
}

View file

@ -1,4 +1,7 @@
use std::time::{Duration, Instant};
use std::{
collections::VecDeque,
time::{Duration, Instant},
};
use ahash::AHashMap;
use cgmath::{EuclideanSpace, InnerSpace, Point3, Rad, Vector2, Vector3};
@ -36,6 +39,8 @@ pub struct WorldState {
pub world: World,
pub chunk_buffers: AHashMap<Point3<isize>, GeometryBuffers>,
pub chunk_save_queue: VecDeque<Point3<isize>>,
pub chunk_load_queue: VecDeque<Point3<isize>>,
time: Time,
time_buffer: wgpu::Buffer,
wireframe: bool,
@ -336,6 +341,8 @@ impl WorldState {
world,
chunk_buffers: AHashMap::new(),
chunk_load_queue: VecDeque::new(),
chunk_save_queue: VecDeque::new(),
wireframe: false,
highlighted: None,
@ -487,21 +494,23 @@ impl WorldState {
VirtualKeyCode::A => self.left_pressed = pressed,
VirtualKeyCode::D => self.right_pressed = pressed,
VirtualKeyCode::F2 if pressed => self.creative = !self.creative,
VirtualKeyCode::F3 if pressed => self.chunk_save_queue.extend(self.world.chunks.keys()),
VirtualKeyCode::F4 if pressed => self.chunk_load_queue.extend(self.world.chunks.keys()),
VirtualKeyCode::Space => {
self.up_speed = if self.creative {
if pressed {
self.up_speed = if pressed {
if self.creative {
1.0
} else {
0.0
0.6
}
} else {
0.6
0.0
}
}
VirtualKeyCode::LShift if self.creative => {
self.up_speed = if pressed { -1.0 } else { 0.0 }
}
VirtualKeyCode::LControl => self.sprinting = state == ElementState::Pressed,
VirtualKeyCode::LControl => self.sprinting = pressed,
_ => (),
}
}
@ -510,7 +519,7 @@ impl WorldState {
self.world
.get_block(
position.x as isize,
(position.y - 1.62) as isize,
(position.y - 1.8) as isize,
position.z as isize,
)
.is_some()
@ -556,6 +565,23 @@ impl WorldState {
}
pub fn update(&mut self, dt: Duration, render_context: &RenderContext) {
if let Some(position) = self.chunk_load_queue.pop_front() {
let chunk = self.world.chunks.entry(position).or_default();
if let Err(err) = chunk.load(position) {
eprintln!("Failed to load chunk {:?}: {:?}", position, err);
} else {
self.update_chunk_geometry(render_context, position);
println!("Loaded chunk {:?}", position);
}
} else if let Some(position) = self.chunk_save_queue.pop_front() {
let chunk = self.world.chunks.get(&position).unwrap();
if let Err(err) = chunk.save(position) {
eprintln!("Failed to save chunk {:?}: {:?}", position, err);
} else {
println!("Saved chunk {:?}", position);
}
}
self.update_position(dt);
self.update_aim(render_context);