mirror of
https://github.com/Noratrieb/game-wip-dontplay.git
synced 2026-01-14 19:55:02 +01:00
Rudimentary (buggy) world serialization/deserialization
This commit is contained in:
parent
6896698883
commit
83f35e51ee
3 changed files with 167 additions and 18 deletions
56
src/bitmanip.rs
Normal file
56
src/bitmanip.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use std::ops::{BitAndAssign, BitOrAssign};
|
||||
|
||||
use num_traits::PrimInt;
|
||||
|
||||
pub fn nth_bit_set<N: PrimInt>(number: N, n: usize) -> bool {
|
||||
(number & (N::one() << n)) != N::zero()
|
||||
}
|
||||
|
||||
pub fn set_nth_bit<N: PrimInt + BitOrAssign + BitAndAssign>(number: &mut N, n: usize, set: bool) {
|
||||
let mask = N::one() << n;
|
||||
if set {
|
||||
*number |= mask;
|
||||
} else {
|
||||
*number &= !mask;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nth_bit_set() {
|
||||
let number: u8 = 0b0100_0100;
|
||||
assert_eq!(nth_bit_set(number, 0), false);
|
||||
assert_eq!(nth_bit_set(number, 1), false);
|
||||
assert_eq!(nth_bit_set(number, 2), true);
|
||||
assert_eq!(nth_bit_set(number, 3), false);
|
||||
assert_eq!(nth_bit_set(number, 4), false);
|
||||
assert_eq!(nth_bit_set(number, 5), false);
|
||||
assert_eq!(nth_bit_set(number, 6), true);
|
||||
assert_eq!(nth_bit_set(number, 7), false);
|
||||
assert_eq!(nth_bit_set(0u64, 0), false);
|
||||
assert_eq!(nth_bit_set(u64::MAX, 63), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_nth_bit() {
|
||||
let mut number: u8 = 0b0000_0000;
|
||||
set_nth_bit(&mut number, 0, true);
|
||||
assert_eq!(number, 0b0000_0001);
|
||||
set_nth_bit(&mut number, 1, true);
|
||||
assert_eq!(number, 0b0000_0011);
|
||||
set_nth_bit(&mut number, 2, true);
|
||||
assert_eq!(number, 0b0000_0111);
|
||||
set_nth_bit(&mut number, 0, false);
|
||||
assert_eq!(number, 0b0000_0110);
|
||||
|
||||
let mut all_bits_set: u64 = 0;
|
||||
for i in 0..64 {
|
||||
set_nth_bit(&mut all_bits_set, i, true);
|
||||
assert_eq!(nth_bit_set(all_bits_set, i), true);
|
||||
}
|
||||
|
||||
let mut no_bits_set: u64 = u64::MAX;
|
||||
for i in 0..64 {
|
||||
set_nth_bit(&mut no_bits_set, i, false);
|
||||
assert_eq!(nth_bit_set(no_bits_set, i), false);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
mod app;
|
||||
mod bitmanip;
|
||||
mod debug;
|
||||
mod game;
|
||||
mod graphics;
|
||||
|
|
|
|||
128
src/world.rs
128
src/world.rs
|
|
@ -1,4 +1,8 @@
|
|||
use std::path::Path;
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use egui_inspect::derive::Inspect;
|
||||
use fnv::FnvHashMap;
|
||||
|
|
@ -70,21 +74,29 @@ impl World {
|
|||
}
|
||||
pub fn save_chunks(&self) {
|
||||
for (pos, chk) in self.chunks.iter() {
|
||||
let (reg_x, reg_y) = pos.region();
|
||||
let reg_file_name = format!("{reg_x}.{reg_y}.rgn");
|
||||
let reg_file_name = format_reg_file_name(pos.region());
|
||||
dbg!(®_file_name);
|
||||
if !Path::new(®_file_name).exists() {
|
||||
log::info!(
|
||||
"{:?}",
|
||||
std::fs::write(®_file_name, zstd::encode_all(&[][..], 0).unwrap())
|
||||
);
|
||||
log::warn!("Region file doesn't exist, creating.");
|
||||
let mut f = File::create(®_file_name).unwrap();
|
||||
// Write an empty existence bitset
|
||||
f.write_all(&[0; 8]).unwrap();
|
||||
log::info!("{:?}", f.write_all(&zstd::encode_all(&[][..], 0).unwrap()));
|
||||
}
|
||||
let mut decomp = zstd::decode_all(&std::fs::read(®_file_name).unwrap()[..]).unwrap();
|
||||
let mut f = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(®_file_name)
|
||||
.unwrap();
|
||||
let mut existence_bitset = read_existence_bitset_file(&mut f);
|
||||
dbg!(existence_bitset);
|
||||
dbg!(f.stream_position());
|
||||
let mut decomp = zstd::decode_all(&mut f).unwrap();
|
||||
let (loc_x, loc_y) = pos.local();
|
||||
dbg!(loc_x, loc_y);
|
||||
let loc_idx = (loc_y * REGION_CHUNK_EXTENT) + loc_x;
|
||||
dbg!(loc_idx);
|
||||
let byte_idx = loc_idx as usize * CHUNK_BYTES;
|
||||
let loc_idx = loc_idx(loc_y, loc_x);
|
||||
crate::bitmanip::set_nth_bit(&mut existence_bitset, loc_idx as usize, true);
|
||||
let byte_idx = loc_byte_idx(loc_idx);
|
||||
dbg!(byte_idx);
|
||||
let end_idx = byte_idx + CHUNK_BYTES;
|
||||
dbg!(end_idx);
|
||||
|
|
@ -97,14 +109,39 @@ impl World {
|
|||
decomp[off + 2..off + 4].copy_from_slice(&tile.mid.to_le_bytes());
|
||||
decomp[off + 4..off + 6].copy_from_slice(&tile.fg.to_le_bytes());
|
||||
}
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
f.write_all(&u64::to_le_bytes(existence_bitset)[..])
|
||||
.unwrap();
|
||||
log::info!(
|
||||
"{:?}",
|
||||
std::fs::write(®_file_name, zstd::encode_all(&decomp[..], 0).unwrap())
|
||||
f.write_all(&zstd::encode_all(&decomp[..], 0).unwrap())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_existence_bitset_file(f: &mut File) -> u64 {
|
||||
let mut buf = [0; 8];
|
||||
f.read_exact(&mut buf).unwrap();
|
||||
u64::from_le_bytes(buf)
|
||||
}
|
||||
|
||||
fn loc_byte_idx_xy(x: u8, y: u8) -> usize {
|
||||
loc_byte_idx(loc_idx(y, x))
|
||||
}
|
||||
|
||||
fn loc_byte_idx(loc_idx: u8) -> usize {
|
||||
loc_idx as usize * CHUNK_BYTES
|
||||
}
|
||||
|
||||
fn loc_idx(loc_y: u8, loc_x: u8) -> u8 {
|
||||
(loc_y * REGION_CHUNK_EXTENT) + loc_x
|
||||
}
|
||||
|
||||
fn format_reg_file_name((x, y): (u8, u8)) -> String {
|
||||
format!("{x}.{y}.rgn")
|
||||
}
|
||||
|
||||
const CHUNK_BYTES: usize = CHUNK_N_TILES * TILE_BYTES;
|
||||
const TILE_BYTES: usize = 3 * 2;
|
||||
|
||||
|
|
@ -123,7 +160,7 @@ impl World {
|
|||
let chk = self
|
||||
.chunks
|
||||
.entry(chk)
|
||||
.or_insert_with(|| Chunk::gen(chk, worldgen));
|
||||
.or_insert_with(|| Chunk::load_or_gen(chk, worldgen, &self.name));
|
||||
chk.at_mut(local)
|
||||
}
|
||||
}
|
||||
|
|
@ -202,6 +239,14 @@ const CHUNK_N_TILES: usize = CHUNK_EXTENT as usize * CHUNK_EXTENT as usize;
|
|||
|
||||
type ChunkTiles = [Tile; CHUNK_N_TILES];
|
||||
|
||||
fn default_chunk_tiles() -> ChunkTiles {
|
||||
[Tile {
|
||||
bg: 0,
|
||||
mid: 0,
|
||||
fg: 0,
|
||||
}; CHUNK_N_TILES]
|
||||
}
|
||||
|
||||
#[derive(Debug, Inspect)]
|
||||
pub struct Chunk {
|
||||
tiles: ChunkTiles,
|
||||
|
|
@ -209,11 +254,7 @@ pub struct Chunk {
|
|||
|
||||
impl Chunk {
|
||||
pub fn gen(pos: ChunkPos, worldgen: &Worldgen) -> Self {
|
||||
let mut tiles = [Tile {
|
||||
bg: 0,
|
||||
mid: 0,
|
||||
fg: 0,
|
||||
}; CHUNK_N_TILES];
|
||||
let mut tiles = default_chunk_tiles();
|
||||
let noise = worldgen.chunk_noise(pos);
|
||||
if pos.y >= 156 {
|
||||
for (i, t) in tiles.iter_mut().enumerate() {
|
||||
|
|
@ -232,9 +273,56 @@ impl Chunk {
|
|||
Self { tiles }
|
||||
}
|
||||
|
||||
pub fn load_or_gen(chk: ChunkPos, worldgen: &Worldgen, world_name: &str) -> Chunk {
|
||||
log::info!("Loading chunk {chk:?} (reg: {:?})", chk.region());
|
||||
let prev_dir = std::env::current_dir().unwrap();
|
||||
log::info!("{:?}", std::env::set_current_dir(world_name));
|
||||
let reg_filename = format_reg_file_name(chk.region());
|
||||
let chunk = if chunk_exists(®_filename, chk) {
|
||||
log::info!("Chunk exists, loading");
|
||||
let mut f = File::open(®_filename).unwrap();
|
||||
log::info!("Existence bitset: {:b}", read_existence_bitset_file(&mut f));
|
||||
let decomp_data = zstd::decode_all(f).unwrap();
|
||||
let local_pos = chk.local();
|
||||
Chunk::load_from_region(&decomp_data, local_pos.0, local_pos.1)
|
||||
} else {
|
||||
log::warn!("Chunk at {:?} doesn't exist, generating.", chk);
|
||||
Chunk::gen(chk, worldgen)
|
||||
};
|
||||
log::info!("{:?}", std::env::set_current_dir(prev_dir));
|
||||
chunk
|
||||
}
|
||||
|
||||
fn at_mut(&mut self, local: ChunkLocalTilePos) -> &mut Tile {
|
||||
&mut self.tiles[CHUNK_EXTENT as usize * local.y as usize + local.x as usize]
|
||||
}
|
||||
|
||||
fn load_from_region(data: &[u8], x: u8, y: u8) -> Self {
|
||||
let byte_idx = loc_byte_idx_xy(x, y);
|
||||
let mut tiles = default_chunk_tiles();
|
||||
for (i, t) in tiles.iter_mut().enumerate() {
|
||||
let off = byte_idx + (i * TILE_BYTES);
|
||||
t.bg = u16::from_le_bytes(data[off..off + 2].try_into().unwrap());
|
||||
t.mid = u16::from_le_bytes(data[off + 2..off + 4].try_into().unwrap());
|
||||
t.fg = u16::from_le_bytes(data[off + 4..off + 6].try_into().unwrap());
|
||||
}
|
||||
Self { tiles }
|
||||
}
|
||||
}
|
||||
|
||||
fn read_existence_bitset(reg_filename: &str) -> u64 {
|
||||
let mut f = File::open(reg_filename).unwrap();
|
||||
read_existence_bitset_file(&mut f)
|
||||
}
|
||||
|
||||
fn chunk_exists(reg_filename: &str, pos: ChunkPos) -> bool {
|
||||
if !Path::new(®_filename).exists() {
|
||||
return false;
|
||||
}
|
||||
let bitset = read_existence_bitset(reg_filename);
|
||||
let local = pos.local();
|
||||
let idx = loc_idx(local.1, local.0);
|
||||
crate::bitmanip::nth_bit_set(bitset, idx as usize)
|
||||
}
|
||||
|
||||
pub type TileId = u16;
|
||||
|
|
@ -255,3 +343,7 @@ impl Tile {
|
|||
}
|
||||
|
||||
pub const REGION_CHUNK_EXTENT: u8 = 8;
|
||||
const _: () = assert!(
|
||||
REGION_CHUNK_EXTENT * REGION_CHUNK_EXTENT <= 64,
|
||||
"A region file uses an existence bitset that's a 64 bit integer"
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue