started the level.dat file creation and completion... I may need to continue the code of level.rs and make an update function to level.dat

This commit is contained in:
2025-08-19 17:52:47 +02:00
parent 36e01961fb
commit 5193283c70
8 changed files with 170 additions and 121 deletions

80
src/level.rs Normal file
View File

@@ -0,0 +1,80 @@
use std::fs::File;
use nbt::{Tag, write_nbt};
pub fn create_nbt(
name: String,
seed: i64,
is_hardcore: bool,
structures: bool,
raining: bool,
thundering: bool,
game_type: i32,
generator_version: i32,
raintime: i32,
spawnx: i32,
spawny: i32,
spawnz: i32,
thundertime: i32,
version: i32,
last_played: i64,
disk_size: i64,
time: i64,
generator_name: String,
level_name: String,
path: String,
) -> std::io::Result<()> {
let mut root = Tag::new_compound(name);
root.insert("RandomSeed".to_string(), Tag::new_long("RandomSeed", seed));
root.insert(
"hardcore".to_string(),
Tag::new_byte("hardcore", i8::from(is_hardcore)),
);
root.insert(
"MapFeatures".to_string(),
Tag::new_byte("MapFeatures", i8::from(structures)),
);
root.insert(
"raining".to_string(),
Tag::new_byte("raining", i8::from(raining)),
);
root.insert(
"thundering".to_string(),
Tag::new_byte("thundering", i8::from(thundering)),
);
root.insert("GameType".to_string(), Tag::new_int("GameType", game_type));
root.insert(
"GeneratorVersion".to_string(),
Tag::new_int("GeneratorVersion", generator_version),
);
root.insert("RainTime".to_string(), Tag::new_int("RainTime", raintime));
root.insert("SpawnX".to_string(), Tag::new_int("SpawnX", spawnx));
root.insert("SpawnY".to_string(), Tag::new_int("SpawnY", spawny));
root.insert("SpawnZ".to_string(), Tag::new_int("SpawnZ", spawnz));
root.insert(
"ThunderTime".to_string(),
Tag::new_int("ThunderTime", thundertime),
);
root.insert("Version".to_string(), Tag::new_int("Version", version));
root.insert(
"LastPlayed".to_string(),
Tag::new_long("LastPlayed", last_played),
); // Not sure if I should keep LastPlayed field because of the fact that this isn't for a
// client world but for a server world
root.insert(
"SizeOnDisk".to_string(),
Tag::new_long("SizeOnDisk", disk_size),
);
root.insert("Time".to_string(), Tag::new_long("Time", time));
root.insert(
"GeneratorName".to_string(),
Tag::new_string("GeneratorName", generator_name),
);
root.insert(
"LevelName".to_string(),
Tag::new_string("LevelName", level_name),
);
let file = File::create(path)?;
write_nbt(&root, file)?;
Ok(())
}

View File

@@ -1,2 +1,5 @@
mod level;
mod perlin;
mod superflat;
#[cfg(test)]
mod test;

View File

@@ -4,7 +4,7 @@ use rand::{
};
use rand_chacha::ChaCha8Rng;
const CHUNK_SIZE: usize = 16;
pub const CHUNK_SIZE: usize = 16;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Noise {
scale: f32,
@@ -18,9 +18,9 @@ pub struct Vector {
y: f32,
}
const MIN_Y: i32 = -64;
const MAX_Y: i32 = 320;
const SEA_LEVEL: i32 = 63;
pub const MIN_Y: i32 = -64;
pub const MAX_Y: i32 = 320;
pub const SEA_LEVEL: i32 = 63;
#[inline]
fn fbm_seeded(
@@ -211,13 +211,15 @@ fn linear_interpolation(a: f32, b: f32, t: f32) -> f32 {
#[cfg(test)]
mod tests {
use crate::perlin::{
Noise, Vector, calculate_norm, dot_product, fade, linear_interpolation, normalize,
};
fn deriv(f: fn(f32) -> f32, x: f32) -> f32 {
let h = 1e-3;
(f(x + h) - f(x - h)) / (2.0 * h)
}
use super::*;
fn approx_eq(a: f32, b: f32, eps: f32) -> bool {
(a - b).abs() <= eps
}
@@ -436,49 +438,3 @@ mod perlin_tests {
assert!((n.get(x, y + h) - c0).abs() < 0.1);
}
}
#[cfg(test)]
mod viz_chunk2 {
use super::*;
use image::{ImageBuffer, Luma};
#[test]
#[ignore]
fn dump_chunk_png() {
let seed: u64 = 42;
let chunks_x: usize = 32;
let chunks_z: usize = 32;
let w: u32 = (chunks_x * CHUNK_SIZE) as u32;
let h: u32 = (chunks_z * CHUNK_SIZE) as u32;
let mut field = vec![0i32; (w as usize) * (h as usize)];
for cz in 0..chunks_z {
for cx in 0..chunks_x {
let tile = generate_height_chunk(seed, cx as i32, cz as i32);
for lz in 0..CHUNK_SIZE {
for lx in 0..CHUNK_SIZE {
let x = cx * CHUNK_SIZE + lx;
let z = cz * CHUNK_SIZE + lz;
field[z * (w as usize) + x] = tile[lx][lz];
}
}
}
}
let mut img: ImageBuffer<Luma<u16>, Vec<u16>> = ImageBuffer::new(w, h);
let denom = (MAX_Y - MIN_Y) as f32;
for z in 0..h {
for x in 0..w {
let v = field[(z as usize) * (w as usize) + (x as usize)];
let n01 = ((v - MIN_Y) as f32 / denom).clamp(0.0, 1.0);
let p = (n01 * u16::MAX as f32).round() as u16;
img.put_pixel(x, z, Luma([p]));
}
}
std::fs::create_dir_all("target").ok();
img.save("target/heightmap16.png").unwrap();
}
}

0
src/player.rs Normal file
View File

0
src/region.rs Normal file
View File

78
src/test.rs Normal file
View File

@@ -0,0 +1,78 @@
/// Test for perlin.rs
#[cfg(test)]
mod perlin_test {
use crate::perlin::{CHUNK_SIZE, MAX_Y, MIN_Y, generate_height_chunk};
use image::{ImageBuffer, Luma};
#[test]
#[ignore]
fn dump_chunk_png() {
let seed: u64 = 42;
let chunks_x: usize = 32;
let chunks_z: usize = 32;
let w: u32 = (chunks_x * CHUNK_SIZE) as u32;
let h: u32 = (chunks_z * CHUNK_SIZE) as u32;
let mut field = vec![0i32; (w as usize) * (h as usize)];
for cz in 0..chunks_z {
for cx in 0..chunks_x {
let tile = generate_height_chunk(seed, cx as i32, cz as i32);
for lz in 0..CHUNK_SIZE {
for lx in 0..CHUNK_SIZE {
let x = cx * CHUNK_SIZE + lx;
let z = cz * CHUNK_SIZE + lz;
field[z * (w as usize) + x] = tile[lx][lz];
}
}
}
}
let mut img: ImageBuffer<Luma<u16>, Vec<u16>> = ImageBuffer::new(w, h);
let denom = (MAX_Y - MIN_Y) as f32;
for z in 0..h {
for x in 0..w {
let v = field[(z as usize) * (w as usize) + (x as usize)];
let n01 = ((v - MIN_Y) as f32 / denom).clamp(0.0, 1.0);
let p = (n01 * u16::MAX as f32).round() as u16;
img.put_pixel(x, z, Luma([p]));
}
}
std::fs::create_dir_all("target").ok();
img.save("target/heightmap16.png").unwrap();
}
}
/// Test for level.rs
#[cfg(test)]
mod level_file_test {
use crate::level::create_nbt;
#[test]
fn test_creation_of_file() -> () {
let result = create_nbt(
"test".to_string(),
1234,
true,
true,
true,
true,
1,
1,
1,
0,
0,
0,
213,
1235,
55555,
90000,
900,
"test".to_string(),
"test".to_string(),
"target/level.dat".to_string(),
);
assert_eq!(result.is_ok(), true);
}
}