diff --git a/Cargo.lock b/Cargo.lock index 79c46e4..56111a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,15 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -170,9 +179,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "byteorder" @@ -826,6 +835,7 @@ checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ "ahash 0.8.3", "allocator-api2", + "serde", ] [[package]] @@ -1015,6 +1025,7 @@ name = "kubi-shared" version = "0.0.0" dependencies = [ "anyhow", + "bincode", "bracket-noise", "glam", "hashbrown 0.14.0", diff --git a/kubi-shared/Cargo.toml b/kubi-shared/Cargo.toml index eb023fe..61c2cc6 100644 --- a/kubi-shared/Cargo.toml +++ b/kubi-shared/Cargo.toml @@ -10,13 +10,17 @@ shipyard = { git = "https://github.com/leudz/shipyard", rev = "0934b426eb9a8", d strum = { version = "0.25", features = ["derive"] } postcard = { version = "1.0", features = ["alloc"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +bincode = "1.3" anyhow = "1.0" bracket-noise = "0.8" rand = { version = "0.8", default_features = false, features = ["std", "min_const_gen"] } rand_xoshiro = "0.6" -hashbrown = "0.14" +hashbrown = { version = "0.14", features = ["serde"] } nohash-hasher = "0.2" +#bytemuck = { version = "1.14", features = ["derive"] } +#static_assertions = "1.1" + [features] default = [] nightly = ["hashbrown/nightly", "rand/nightly", "rand/simd_support", "glam/core-simd"] diff --git a/kubi-shared/src/chunk.rs b/kubi-shared/src/chunk.rs index 3456db5..70785b0 100644 --- a/kubi-shared/src/chunk.rs +++ b/kubi-shared/src/chunk.rs @@ -2,3 +2,4 @@ use crate::block::Block; pub const CHUNK_SIZE: usize = 32; pub type BlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>; +pub type BlockDataRef = [[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]; diff --git a/kubi-shared/src/data.rs b/kubi-shared/src/data.rs new file mode 100644 index 0000000..45c41e9 --- /dev/null +++ b/kubi-shared/src/data.rs @@ -0,0 +1,91 @@ +use std::{ + fs::File, + mem::size_of, + io::{Read, Seek, SeekFrom, Write}, + borrow::Cow +}; +use serde::{Serialize, Deserialize}; +use glam::IVec2; +use hashbrown::HashMap; +use anyhow::Result; +use crate::{block::Block, chunk::{CHUNK_SIZE, BlockDataRef}}; + +const SECTOR_SIZE: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * size_of::(); +const RESERVED_SIZE: usize = 524288; //512kb (16 sectors assuming 32x32x32 world of 1byte blocks) +const RESERVED_SECTOR_COUNT: usize = RESERVED_SIZE / SECTOR_SIZE; + + +// #[repr(transparent)] +// struct IVec2Hash(IVec2); +#[derive(Serialize, Deserialize)] +struct WorldSaveDataHeader { + pub name: Cow<'static, str>, + pub seed: u64, + sector_count: u32, + chunk_map: HashMap +} + +impl Default for WorldSaveDataHeader { + fn default() -> Self { + Self { + name: "World".into(), + seed: 0, + sector_count: RESERVED_SECTOR_COUNT as u32, + chunk_map: HashMap::new() + } + } +} + +struct WorldSaveFile { + pub file: File, + pub header: WorldSaveDataHeader, +} + +impl WorldSaveFile { + pub fn new(file: File) -> Self { + WorldSaveFile { + file, + header: WorldSaveDataHeader::default() + } + } + + fn read_header(&mut self) -> Result<()> { + self.file.rewind()?; + self.header = bincode::deserialize_from((&self.file).take(RESERVED_SIZE as u64))?; + Ok(()) + } + + fn write_header(&mut self) -> Result<()> { + self.file.rewind()?; + ///XXX: this can cause the header to destroy chunk data (if it's WAY too long) + bincode::serialize_into(&self.file, &self.header)?; + Ok(()) + } + + fn allocate_sector(&mut self) -> u32 { + let value = self.header.sector_count + 1; + self.header.sector_count += 1; + value + } + + pub fn save_chunk(&mut self, position: IVec2, data: &BlockDataRef) -> Result<()> { + let mut header_modified = false; + let sector = self.header.chunk_map.get(&position).copied().unwrap_or_else(|| { + header_modified = true; + self.allocate_sector() + }); + + let offset = sector as u64 * SECTOR_SIZE as u64; + //SAFETY: *nuzzles* t-t-twust me pwease OwO + let data: &[u8; SECTOR_SIZE] = unsafe { std::mem::transmute(data) }; + + self.file.seek(SeekFrom::Start(offset))?; + self.file.write_all(data)?; + + if header_modified { + self.write_header()?; + } + self.file.sync_data()?; + Ok(()) + } +} diff --git a/kubi-shared/src/lib.rs b/kubi-shared/src/lib.rs index 10ea49c..d1c2c0a 100644 --- a/kubi-shared/src/lib.rs +++ b/kubi-shared/src/lib.rs @@ -6,3 +6,4 @@ pub mod transform; pub mod entity; pub mod player; pub mod queue; +pub mod data;