Method for shifting world nodes texture

This commit is contained in:
Piotrek
2021-05-13 11:59:22 +02:00
parent 57782a88ab
commit 98736c39a0
7 changed files with 136 additions and 81 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ impl Game {
Self { Self {
state: GameState::Paused, state: GameState::Paused,
player: Player::new(), player: Player::new(),
world: World::new("default".to_string()), world: World::init("hello".to_string()),
prev_pos: None prev_pos: None
} }
-2
View File
@@ -29,7 +29,6 @@ impl WorldChunk {
} }
} }
#[allow(unused)]
pub fn from_bytes(bytes: Vec<u8>) -> Self { pub fn from_bytes(bytes: Vec<u8>) -> Self {
let mut instance = Self::new(); let mut instance = Self::new();
@@ -61,7 +60,6 @@ impl WorldChunk {
instance instance
} }
#[allow(unused)]
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
// Header // Header
+16
View File
@@ -0,0 +1,16 @@
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct WorldData {
pub name: String,
pub display_name: String
}
impl Default for WorldData {
fn default() -> Self {
Self {
name: String::from("default"),
display_name: String::from("Default")
}
}
}
+60 -71
View File
@@ -1,4 +1,5 @@
mod generator; mod generator;
mod data;
pub mod chunk; pub mod chunk;
pub mod block; pub mod block;
use std::time::Instant; use std::time::Instant;
@@ -6,17 +7,12 @@ use std::path::PathBuf;
use std::io::Write; use std::io::Write;
use std::io::Read; use std::io::Read;
use std::fs; use std::fs;
use cgmath::{Point3, Vector3}; use cgmath::Vector3;
use std::collections::HashMap; use std::collections::HashMap;
use generator::WorldGen; use generator::WorldGen;
use chunk::WorldChunk; use chunk::WorldChunk;
use block::WorldBlock; use block::WorldBlock;
use data::WorldData;
#[derive(serde::Serialize, serde::Deserialize, Debug)]
struct WorldData {
#[serde(default)]
pub name: String
}
pub struct World { pub struct World {
data: WorldData, data: WorldData,
@@ -25,43 +21,56 @@ pub struct World {
impl World { impl World {
pub fn new(name: String) -> Self { pub fn init(name: String) -> Self {
Self { let mut instance = Self {
data: WorldData { name }, data: WorldData { name, ..Default::default() },
chunks: HashMap::new(), chunks: HashMap::new(),
};
instance.load_metadata();
instance.save_all();
instance
}
/*
* Loads metadata
*/
fn load_metadata(&mut self) -> bool {
let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").join(self.data.name.clone()).join("world.dat");
if let Ok(mut file) = fs::File::open(filepath) {
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
if let Ok(data) = toml::from_slice::<WorldData>(&buf[..]) {
self.data = data;
return true;
}
} }
return false;
} }
pub fn all_blocks(&self) -> Vec<(Vector3<i32>, &WorldBlock)> { /*
self.chunks.iter().map(|(chunk_pos, chunk)| { * Saves metadata and all loaded chunks
let off = chunk_pos * chunk::SIZE as i32; */
let result: Vec<(Vector3<i32>, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| { pub fn save_all(&self) {
(
Vector3{x: off.x+pos.x as i32, y: off.y+pos.y as i32, z: off.z+pos.z as i32},
*block
)
}).collect();
result
}).flatten().collect()
}
pub fn save(&self) {
// Get directory // Get directory
let dir = dirs::data_local_dir().unwrap().join("Voxelgame"); let dirpath = dirs::data_local_dir().unwrap().join("Voxelgame").join("saves").join(&self.data.name);
fs::create_dir_all(&dir).expect("Failed to create directory"); fs::create_dir_all(&dirpath).expect("Failed to create world directory");
// Save all chunks // Save all chunks
for (pos, chunk) in self.chunks.iter() { for (pos, chunk) in self.chunks.iter() {
let path = dir.with_file_name(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z)); let filepath = dirpath.join(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z));
let mut file = fs::File::create(path).expect("Failed to create file"); let mut file = fs::File::create(filepath).expect("Failed to create chunk file");
file.write(&chunk.to_bytes()).unwrap(); file.write(&chunk.to_bytes()).expect("Failed to write chunk file");
} }
// Save metadata // Save metadata
let data_str = toml::to_string(&self.data).unwrap(); let datastr = toml::to_string(&self.data).unwrap();
let data_path: PathBuf = [dir.to_str().unwrap(), "world.dat"].iter().collect(); let datapath: PathBuf = dirpath.join("world.dat");
let mut data_file = fs::File::create(data_path).unwrap(); let mut datafile = fs::File::create(datapath).expect("Failed to create world metadata file");
data_file.write_all(data_str.as_bytes()).expect("Failed to write world metadata"); datafile.write_all(datastr.as_bytes()).expect("Failed to write world metadata");
}
pub fn get_chunk(&mut self, chunk_wpos: &Vector3<i32>) -> Option<&mut WorldChunk> {
self.chunks.get_mut(chunk_wpos)
} }
/* /*
@@ -76,12 +85,13 @@ impl World {
// Try loading chunk from file // Try loading chunk from file
let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z); let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z);
let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").with_file_name(filename); let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").join("saves").join(&self.data.name).join(filename);
if filepath.is_file() { if filepath.is_file() {
let timer = Instant::now(); let timer = Instant::now();
let mut buff = Vec::new(); let mut buff = Vec::new();
let mut file = fs::File::open(filepath).expect("Failed to open file"); let mut file = fs::File::open(filepath).expect("Failed to open chunk file");
file.read_to_end(&mut buff).expect("Failed to read file"); file.read_to_end(&mut buff).expect("Failed to read chunk file");
let chunk = WorldChunk::from_bytes(buff); let chunk = WorldChunk::from_bytes(buff);
self.chunks.insert(pos, chunk); self.chunks.insert(pos, chunk);
println!("Chunk at {:?} loaded ({} ms)", pos, timer.elapsed().as_millis()); println!("Chunk at {:?} loaded ({} ms)", pos, timer.elapsed().as_millis());
@@ -99,13 +109,11 @@ impl World {
} }
} }
// Save // Save generated chunk to file
let timer1 = Instant::now(); let timer1 = Instant::now();
let dir = dirs::data_local_dir().unwrap().join("Voxelgame"); fs::create_dir_all(&filepath.parent().unwrap()).expect("Failed to create world directory");
fs::create_dir_all(&dir).expect("Failed to create directory"); let mut file = fs::File::create(filepath).expect("Failed to create chunk file");
let path = dir.with_file_name(format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z)); file.write(&chunk.to_bytes()).expect("Failed to write chunk file");
let mut file = fs::File::create(path).expect("Failed to create file");
file.write(&chunk.to_bytes()).unwrap();
// Add to list // Add to list
self.chunks.insert(pos, chunk); self.chunks.insert(pos, chunk);
@@ -117,33 +125,14 @@ impl World {
true true
} }
pub fn load(&mut self) -> bool { // pub fn get_block(&mut self, block_wpos: &Vector3<i32>) -> Option<&WorldBlock> {
// Load metadata // // Split world space to chunk and block space
let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").with_file_name("world.dat"); // let ch_pos = block_wpos / chunk::SIZE as i32;
if let Ok(mut file) = fs::File::open(filepath) { // let bl_pos = block_wpos % chunk::SIZE as i32;
let mut buf = Vec::new(); // // Return block if exists
file.read_to_end(&mut buf).unwrap(); // if let Some(chunk) = self.chunks.get_mut(&ch_pos) {
if let Ok(data) = toml::from_slice::<WorldData>(&buf[..]) { // return Some(chunk.get_block(&bl_pos));
self.data = data; // }
return true; // None
} // }
}
return false;
}
#[allow(unused)]
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 = 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)
}
} }
+23 -6
View File
@@ -1,3 +1,5 @@
use cgmath::Vector3;
use crate::renderer::renderer_view::RendererView;
use winit::{ use winit::{
event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, MouseButton}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, MouseButton},
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
@@ -43,13 +45,28 @@ fn main() {
match event { match event {
// Window closed (ALT+F4,) // Window closed (ALT+F4,)
WindowEvent::CloseRequested => { *c = ControlFlow::Exit; } WindowEvent::CloseRequested => { *c = ControlFlow::Exit; }
// Escape key // Key pressed
WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. }, .. } => { WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode, .. }, .. } => {
// Request pause if let Some(key) = virtual_keycode {
if let GameState::Paused = game.update_state(GameState::Paused) { match key {
window.set_cursor_grab(false).unwrap(); // Escape pressed
window.set_cursor_visible(true); VirtualKeyCode::Escape => {
if let GameState::Paused = game.update_state(GameState::Paused) {
window.set_cursor_grab(false).unwrap();
window.set_cursor_visible(true);
}
}
// Test key
VirtualKeyCode::T => {
let t = &mut renderer as &mut dyn RendererView;
t.shift(&Vector3::<i32>{ x:32, y:0, z:0 });
println!("shifted");
}
_ => ()
}
} }
} }
// Window clicked // Window clicked
WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => { WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => {
+31 -1
View File
@@ -101,7 +101,6 @@ impl Content {
ContentStats { node_tex_size, block_tex_size, block_tex_used, block_count, block_used } ContentStats { node_tex_size, block_tex_size, block_tex_used, block_count, block_used }
} }
#[allow(unused)]
pub fn write(&mut self, queue: &wgpu::Queue, block_pos: &Vector3<i32>, block: &WorldBlock) { pub fn write(&mut self, queue: &wgpu::Queue, block_pos: &Vector3<i32>, block: &WorldBlock) {
// Get node // Get node
@@ -139,6 +138,37 @@ impl Content {
); );
} }
pub fn shift(&mut self, offset: &Vector3<i32>) {
let timer = Instant::now();
let mut result = vec![0_u32; self.node_buffer.len()].into_boxed_slice();
let ox = offset.x as usize;
let oy = offset.y as usize;
let oz = offset.z as usize;
for x0 in 0..NODE_TEX_SIZE {
let x1 = x0+ox;
if x1 >= NODE_TEX_SIZE { continue; }
for y0 in 0..NODE_TEX_SIZE {
let y1 = y0+oy;
if y1 >= NODE_TEX_SIZE { continue; }
for z0 in 0..NODE_TEX_SIZE {
let z1 = z0+oz;
if z1 >= NODE_TEX_SIZE { continue; }
let idx0 = x0 + NODE_TEX_SIZE * (y0 + NODE_TEX_SIZE * z0);
let idx1 = x1 + NODE_TEX_SIZE * (y1 + NODE_TEX_SIZE * z1);
result[idx1] = self.node_buffer[idx0];
}
}
}
self.node_buffer = result;
self.node_dirty = true;
println!("Shifted in {} ms", timer.elapsed().as_millis());
}
fn write_nodes(&mut self, queue: &wgpu::Queue, z: usize) { fn write_nodes(&mut self, queue: &wgpu::Queue, z: usize) {
// Convert u32 node buffer to u8 // Convert u32 node buffer to u8
let node_origin = wgpu::Origin3d{ x:0, y: 0, z: z as u32 }; let node_origin = wgpu::Origin3d{ x:0, y: 0, z: z as u32 };
+5
View File
@@ -6,6 +6,7 @@ use cgmath::Vector3;
pub trait RendererView { pub trait RendererView {
fn write(&mut self, block_pos: &Vector3<i32>, block: &WorldBlock); fn write(&mut self, block_pos: &Vector3<i32>, block: &WorldBlock);
fn shift(&mut self, offset: &Vector3<i32>);
fn get_camera_transform(&mut self) -> &mut dyn CameraTransform; fn get_camera_transform(&mut self) -> &mut dyn CameraTransform;
fn get_ui(&mut self) -> &mut UserInterface; fn get_ui(&mut self) -> &mut UserInterface;
} }
@@ -16,6 +17,10 @@ impl RendererView for Renderer {
self.buffers.content.write(&self.queue, block_pos, block) self.buffers.content.write(&self.queue, block_pos, block)
} }
fn shift(&mut self, offset: &Vector3<i32>) {
self.buffers.content.shift(offset);
}
fn get_camera_transform(&mut self) -> &mut dyn CameraTransform { fn get_camera_transform(&mut self) -> &mut dyn CameraTransform {
&mut self.camera &mut self.camera
} }