Dynamic loading, saving, generating chunks works

This commit is contained in:
Piotrek
2021-05-13 09:13:43 +02:00
parent ab9f4c83d0
commit 57782a88ab
7 changed files with 73 additions and 55 deletions
+40 -28
View File
@@ -1,11 +1,12 @@
mod generator;
pub mod chunk;
pub mod block;
use std::time::Instant;
use std::path::PathBuf;
use std::io::Write;
use std::io::Read;
use std::fs;
use cgmath::Point3;
use cgmath::{Point3, Vector3};
use std::collections::HashMap;
use generator::WorldGen;
use chunk::WorldChunk;
@@ -19,11 +20,7 @@ struct WorldData {
pub struct World {
data: WorldData,
chunks: HashMap<Point3<i32>, WorldChunk>,
}
fn point_abs(p: &Point3<i32>) -> Point3<u32> {
Point3 {x: p.x.abs() as u32, y: p.y.abs() as u32, z: p.z.abs() as u32 }
chunks: HashMap<Vector3<i32>, WorldChunk>,
}
impl World {
@@ -35,12 +32,12 @@ impl World {
}
}
pub fn all_blocks(&self) -> Vec<(Point3<i32>, &WorldBlock)> {
pub fn all_blocks(&self) -> Vec<(Vector3<i32>, &WorldBlock)> {
self.chunks.iter().map(|(chunk_pos, chunk)| {
let off = chunk_pos * chunk::SIZE as i32;
let result: Vec<(Point3<i32>, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| {
let result: Vec<(Vector3<i32>, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| {
(
Point3{x: off.x+pos.x as i32, y: off.y+pos.y as i32, z: off.z+pos.z as i32},
Vector3{x: off.x+pos.x as i32, y: off.y+pos.y as i32, z: off.z+pos.z as i32},
*block
)
}).collect();
@@ -50,18 +47,14 @@ impl World {
pub fn save(&self) {
// Get directory
let mut dir = dirs::data_local_dir().unwrap();
dir.push("Voxelgame");
let dir = dirs::data_local_dir().unwrap().join("Voxelgame");
fs::create_dir_all(&dir).expect("Failed to create directory");
// Save all chunks
for (pos, chunk) in self.chunks.iter() {
let bytes = chunk.to_bytes();
let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z);
let path: PathBuf = [dir.to_str().unwrap(), &filename].iter().collect();
let path = dir.with_file_name(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z));
let mut file = fs::File::create(path).expect("Failed to create file");
file.write(&bytes).unwrap();
file.write(&chunk.to_bytes()).unwrap();
}
// Save metadata
@@ -72,41 +65,56 @@ impl World {
}
/*
* Loads chunk and displays it in the world.
* Loads chunk into memory
* It will try to load the chunk from file, and if that fails it will generate the chunk and save it.
*/
pub fn load_chunk(&mut self, pos: Point3<i32>) -> Option<&WorldChunk> {
pub fn load_chunk(&mut self, pos: Vector3<i32>) ->bool {
// Abort if chunk is already loaded
if let Some(_) = self.chunks.get(&pos) {
return None;
return false;
}
// Try loading chunk from file
let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z);
let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").with_file_name(filename);
if filepath.is_file() {
let timer = Instant::now();
let mut buff = Vec::new();
let mut file = fs::File::open(filepath).expect("Failed to open file");
file.read_to_end(&mut buff).expect("Failed to read file");
let chunk = WorldChunk::from_bytes(buff);
self.chunks.insert(pos, chunk);
println!("Chunk at {:?} loaded", pos);
return Some(&chunk);
println!("Chunk at {:?} loaded ({} ms)", pos, timer.elapsed().as_millis());
return true;
}
// Try generating chunk
let timer0 = Instant::now();
let mut chunk = WorldChunk::new();
for x in 0..32 {
for z in 0..32 {
let bpos = &Point3::<u32>{x,y:0,z};
let bpos = Vector3::<i32>{x,y:0,z};
let block = chunk.get_block_mut(&bpos);
let wpos = &Point3::<i32>{ x: pos.x+bpos.x as i32, y: pos.y+bpos.y as i32, z: pos.z+bpos.z as i32};
WorldGen::generate(wpos, block);
WorldGen::generate(&(pos*32 + bpos), block);
}
}
// Save
let timer1 = Instant::now();
let dir = dirs::data_local_dir().unwrap().join("Voxelgame");
fs::create_dir_all(&dir).expect("Failed to create directory");
let path = dir.with_file_name(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z));
let mut file = fs::File::create(path).expect("Failed to create file");
file.write(&chunk.to_bytes()).unwrap();
// Add to list
self.chunks.insert(pos, chunk);
println!("Chunk at {:?} generated", pos);
Some(&chunk)
// Stats
let t1 = timer1.elapsed().as_millis();
let t0 = timer0.elapsed().as_millis() - t1;
println!("Chunk at {:?} generated ({} ms) and saved ({} ms)", pos, t0, t1);
true
}
pub fn load(&mut self) -> bool {
@@ -124,14 +132,18 @@ impl World {
}
#[allow(unused)]
pub fn get_block(&mut self, block_wpos: &Point3<i32>) -> Option<&WorldBlock> {
pub fn get_block(&mut self, block_wpos: &Vector3<i32>) -> Option<&WorldBlock> {
// Split world space to chunk and block space
let ch_pos = block_wpos / chunk::SIZE as i32;
let bl_pos = point_abs(block_wpos) % chunk::SIZE as u32;
let bl_pos = block_wpos % chunk::SIZE as i32;
// Return block if exists
if let Some(chunk) = self.chunks.get_mut(&ch_pos) {
return Some(chunk.get_block(&bl_pos));
}
None
}
pub fn get_chunk(&mut self, chunk_wpos: &Vector3<i32>) -> Option<&mut WorldChunk> {
self.chunks.get_mut(chunk_wpos)
}
}