This commit is contained in:
griffi-gh 2023-11-20 20:59:34 +01:00
parent e2bec4bf2e
commit 43ca458896
7 changed files with 122 additions and 23 deletions

2
.gitignore vendored
View file

@ -13,3 +13,5 @@ target/
_src _src
_visualizer.json _visualizer.json
*.kubi

27
Cargo.lock generated
View file

@ -1033,11 +1033,13 @@ dependencies = [
"glam", "glam",
"hashbrown 0.14.0", "hashbrown 0.14.0",
"nohash-hasher", "nohash-hasher",
"num_enum 0.7.1",
"postcard", "postcard",
"rand", "rand",
"rand_xoshiro", "rand_xoshiro",
"serde", "serde",
"shipyard", "shipyard",
"static_assertions",
"strum", "strum",
] ]
@ -1223,7 +1225,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"jni-sys", "jni-sys",
"ndk-sys", "ndk-sys",
"num_enum", "num_enum 0.5.11",
"raw-window-handle 0.5.2", "raw-window-handle 0.5.2",
"thiserror", "thiserror",
] ]
@ -1371,7 +1373,16 @@ version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
dependencies = [ dependencies = [
"num_enum_derive", "num_enum_derive 0.5.11",
]
[[package]]
name = "num_enum"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0"
dependencies = [
"num_enum_derive 0.7.1",
] ]
[[package]] [[package]]
@ -1386,6 +1397,18 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "num_enum_derive"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.23",
]
[[package]] [[package]]
name = "objc" name = "objc"
version = "0.2.7" version = "0.2.7"

View file

@ -8,6 +8,7 @@ publish = false
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math", "serde"] } glam = { version = "0.24", features = ["debug-glam-assert", "fast-math", "serde"] }
shipyard = { git = "https://github.com/leudz/shipyard", rev = "0934b426eb9a8", default-features = false, features = ["std"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "0934b426eb9a8", default-features = false, features = ["std"] }
strum = { version = "0.25", features = ["derive"] } strum = { version = "0.25", features = ["derive"] }
num_enum = "0.7"
postcard = { version = "1.0", features = ["alloc"] } postcard = { version = "1.0", features = ["alloc"] }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
bincode = "1.3" bincode = "1.3"
@ -17,9 +18,8 @@ rand = { version = "0.8", default_features = false, features = ["std", "min_cons
rand_xoshiro = "0.6" rand_xoshiro = "0.6"
hashbrown = { version = "0.14", features = ["serde"] } hashbrown = { version = "0.14", features = ["serde"] }
nohash-hasher = "0.2" nohash-hasher = "0.2"
#bytemuck = { version = "1.14", features = ["derive"] } #bytemuck = { version = "1.14", features = ["derive"] }
#static_assertions = "1.1" static_assertions = "1.1"
[features] [features]
default = [] default = []

View file

@ -1,5 +1,6 @@
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use strum::EnumIter; use strum::EnumIter;
use num_enum::TryFromPrimitive;
#[derive(Serialize, Deserialize, Clone, Copy, Debug, EnumIter)] #[derive(Serialize, Deserialize, Clone, Copy, Debug, EnumIter)]
#[repr(u8)] #[repr(u8)]
@ -22,7 +23,7 @@ pub enum BlockTexture {
WaterSolid, WaterSolid,
} }
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, EnumIter)] #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, EnumIter, TryFromPrimitive)]
#[repr(u8)] #[repr(u8)]
pub enum Block { pub enum Block {
Air, Air,

View file

@ -2,13 +2,20 @@ use std::{
fs::File, fs::File,
mem::size_of, mem::size_of,
io::{Read, Seek, SeekFrom, Write}, io::{Read, Seek, SeekFrom, Write},
borrow::Cow borrow::Cow,
sync::{Arc, RwLock}
}; };
use num_enum::TryFromPrimitive;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use glam::IVec2; use glam::IVec3;
use hashbrown::HashMap; use hashbrown::HashMap;
use anyhow::Result; use anyhow::Result;
use crate::{block::Block, chunk::{CHUNK_SIZE, BlockDataRef}}; use shipyard::Unique;
use static_assertions::const_assert_eq;
use crate::{
block::Block,
chunk::{CHUNK_SIZE, BlockDataRef, BlockData}
};
const SECTOR_SIZE: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * size_of::<Block>(); const SECTOR_SIZE: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * size_of::<Block>();
const RESERVED_SIZE: usize = 1048576; //~1mb (16 sectors assuming 32x32x32 world of 1byte blocks) const RESERVED_SIZE: usize = 1048576; //~1mb (16 sectors assuming 32x32x32 world of 1byte blocks)
@ -20,13 +27,13 @@ const HEADER_MAGIC_STR: [u8; 4] = *b"KUBI";
const HEADER_MAGIC_IDENTITY: u32 = 1; const HEADER_MAGIC_IDENTITY: u32 = 1;
// #[repr(transparent)] // #[repr(transparent)]
// struct IVec2Hash(IVec2); // struct IVec3Hash(IVec3);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct WorldSaveDataHeader { pub struct WorldSaveDataHeader {
pub name: Cow<'static, str>, pub name: Cow<'static, str>,
pub seed: u64, pub seed: u64,
sector_count: u32, sector_count: u32,
chunk_map: HashMap<IVec2, u32>, chunk_map: HashMap<IVec3, u32>,
} }
impl Default for WorldSaveDataHeader { impl Default for WorldSaveDataHeader {
@ -40,11 +47,14 @@ impl Default for WorldSaveDataHeader {
} }
} }
struct WorldSaveFile { #[derive(Unique)]
pub struct WorldSaveFile {
pub file: File, pub file: File,
pub header: WorldSaveDataHeader, pub header: WorldSaveDataHeader,
} }
pub type SharedSaveFile = Arc<RwLock<WorldSaveFile>>;
impl WorldSaveFile { impl WorldSaveFile {
pub fn new(file: File) -> Self { pub fn new(file: File) -> Self {
WorldSaveFile { WorldSaveFile {
@ -82,13 +92,23 @@ impl WorldSaveFile {
Ok(()) Ok(())
} }
pub fn initialize(&mut self) -> Result<()> {
self.write_header()?;
Ok(())
}
pub fn load_data(&mut self) -> Result<()> {
self.read_header()?;
Ok(())
}
fn allocate_sector(&mut self) -> u32 { fn allocate_sector(&mut self) -> u32 {
let value = self.header.sector_count + 1; let value = self.header.sector_count + 1;
self.header.sector_count += 1; self.header.sector_count += 1;
value value
} }
pub fn save_chunk(&mut self, position: IVec2, data: &BlockDataRef) -> Result<()> { pub fn save_chunk(&mut self, position: IVec3, data: &BlockDataRef) -> Result<()> {
let mut header_modified = false; let mut header_modified = false;
let sector = self.header.chunk_map.get(&position).copied().unwrap_or_else(|| { let sector = self.header.chunk_map.get(&position).copied().unwrap_or_else(|| {
header_modified = true; header_modified = true;
@ -96,7 +116,8 @@ impl WorldSaveFile {
}); });
let offset = sector as u64 * SECTOR_SIZE as u64; let offset = sector as u64 * SECTOR_SIZE as u64;
//SAFETY: *nuzzles* t-t-twust me pwease OwO
const_assert_eq!(size_of::<Block>(), 1);
let data: &[u8; SECTOR_SIZE] = unsafe { std::mem::transmute(data) }; let data: &[u8; SECTOR_SIZE] = unsafe { std::mem::transmute(data) };
self.file.seek(SeekFrom::Start(offset))?; self.file.seek(SeekFrom::Start(offset))?;
@ -108,4 +129,41 @@ impl WorldSaveFile {
self.file.sync_data()?; self.file.sync_data()?;
Ok(()) Ok(())
} }
///TODO partial chunk commit (No need to write whole 32kb for a single block change!)
pub fn chunk_set_block() {
todo!()
}
pub fn chunk_exists(&self, position: IVec3) -> bool {
self.header.chunk_map.contains_key(&position)
}
pub fn load_chunk(&mut self, position: IVec3) -> Result<Option<BlockData>> {
let Some(&sector) = self.header.chunk_map.get(&position) else {
return Ok(None);
};
let mut buffer = Box::new([0u8; CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * size_of::<Block>()]);
let offset = sector as u64 * SECTOR_SIZE as u64;
self.file.seek(SeekFrom::Start(offset))?;
self.file.read_exact(&mut buffer[..])?;
//should be safe under these conditions:
//Block is a single byte
//All block data bytes are in valid range
const_assert_eq!(size_of::<Block>(), 1);
for &byte in &buffer[..] {
let block = Block::try_from_primitive(byte);
match block {
//Sanity check, not actually required: (should NEVER happen)
Ok(block) => debug_assert_eq!(byte, block as u8),
Err(_) => anyhow::bail!("invalid block data"),
}
}
let data: BlockData = unsafe { std::mem::transmute(buffer) };
Ok(Some(data))
}
} }

View file

@ -1,9 +1,26 @@
use shipyard::{AllStoragesView, UniqueViewMut}; use shipyard::{AllStoragesView, UniqueViewMut};
use std::{env, net::SocketAddr}; use std::{env, net::SocketAddr, fs::OpenOptions, path::{Path, PathBuf}, str::FromStr, sync::{Arc, RwLock}};
use anyhow::Result;
use crate::{ use crate::{
networking::{GameType, ServerAddress}, networking::{GameType, ServerAddress},
state::{GameState, NextState} state::{GameState, NextState}
}; };
use kubi_shared::data::{WorldSaveFile, SharedSaveFile};
fn open_local_save_file(path: &Path) -> Result<WorldSaveFile> {
let mut save_file = WorldSaveFile::new({
OpenOptions::new()
.read(true)
.write(true)
.open("world.kbi")?
});
if save_file.file.metadata().unwrap().len() == 0 {
save_file.initialize()?;
} else {
save_file.load_data()?;
}
Ok(save_file)
}
pub fn initialize_from_args( pub fn initialize_from_args(
all_storages: AllStoragesView, all_storages: AllStoragesView,

View file

@ -6,11 +6,9 @@ use shipyard::{
NonSendSync, WorkloadModificator, NonSendSync, WorkloadModificator,
SystemModificator SystemModificator
}; };
use glium::{ use glium::glutin::{
glutin::{
event_loop::{EventLoop, ControlFlow}, event_loop::{EventLoop, ControlFlow},
event::{Event, WindowEvent} event::{Event, WindowEvent}
}
}; };
use glam::vec3; use glam::vec3;
use std::time::Instant; use std::time::Instant;