Skip to content

Commit

Permalink
Implement level.dat reading and use the seed in the world for chunk g…
Browse files Browse the repository at this point in the history
…eneration
  • Loading branch information
neeleshpoli committed Dec 21, 2024
1 parent cc0f308 commit dd36013
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 8 deletions.
55 changes: 53 additions & 2 deletions pumpkin-world/src/chunk/anvil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use std::{
};

use flate2::bufread::{GzDecoder, ZlibDecoder};
use serde::Deserialize;

use crate::level::SaveFile;
use crate::{chunk::ChunkParsingError, level::SaveFile};

use super::{ChunkData, ChunkReader, ChunkReadingError, CompressionError};
use super::{ChunkData, ChunkReader, ChunkReadingError, CompressionError, WorldInfo};

#[derive(Clone)]
pub struct AnvilChunkReader {}
Expand Down Expand Up @@ -158,6 +159,56 @@ impl ChunkReader for AnvilChunkReader {

ChunkData::from_bytes(&decompressed_chunk, *at).map_err(ChunkReadingError::ParsingError)
}

fn read_world_info(&self, save_file: &SaveFile) -> Result<WorldInfo, ChunkReadingError> {
let path = save_file.root_folder.join("level.dat");

let mut world_info_file = OpenOptions::new()
.read(true)
.open(path)
.map_err(|e| ChunkReadingError::IoError(e.kind()))?;

let mut buffer = Vec::new();
world_info_file
.read_to_end(&mut buffer)
.map_err(|e| ChunkReadingError::IoError(e.kind()))?;

let decompressed_data = Compression::GZip
.decompress_data(buffer)
.map_err(ChunkReadingError::Compression)?;
let info = fastnbt::from_bytes::<LevelDat>(&decompressed_data).map_err(|e| {
ChunkReadingError::ParsingError(ChunkParsingError::ErrorDeserializingChunk(
e.to_string(),
))
})?;

Ok(WorldInfo {
seed: info.data.world_gen_settings.seed,
})
}
}

#[derive(Deserialize)]
pub struct LevelDat {
// No idea why its formatted like this
#[serde(rename = "Data")]
pub data: WorldData,
}

#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct WorldData {
pub world_gen_settings: WorldGenSettings,
// TODO: Implement the rest of the fields
// Fields below this comment are being deserialized, but are not being used
pub spawn_x: i32,
pub spawn_y: i32,
pub spawn_z: i32,
}

#[derive(Deserialize)]
pub struct WorldGenSettings {
pub seed: i64,
}

#[cfg(test)]
Expand Down
6 changes: 6 additions & 0 deletions pumpkin-world/src/chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub trait ChunkReader: Sync + Send {
save_file: &SaveFile,
at: &Vector2<i32>,
) -> Result<ChunkData, ChunkReadingError>;
fn read_world_info(&self, save_file: &SaveFile) -> Result<WorldInfo, ChunkReadingError>;
}

#[derive(Error, Debug)]
Expand Down Expand Up @@ -326,3 +327,8 @@ pub enum ChunkParsingError {
#[error("Error deserializing chunk: {0}")]
ErrorDeserializingChunk(String),
}

pub struct WorldInfo {
pub seed: i64,
// TODO: Implement all fields
}
21 changes: 15 additions & 6 deletions pumpkin-world/src/level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use tokio::{
use crate::{
chunk::{
anvil::AnvilChunkReader, ChunkData, ChunkParsingError, ChunkReader, ChunkReadingError,
WorldInfo,
},
world_gen::{get_world_gen, Seed, WorldGenerator},
};
Expand All @@ -28,6 +29,7 @@ use crate::{
/// For more details on world generation, refer to the `WorldGenerator` module.
pub struct Level {
pub seed: Seed,
pub world_info: Option<WorldInfo>,
save_file: Option<SaveFile>,
loaded_chunks: Arc<DashMap<Vector2<i32>, Arc<RwLock<ChunkData>>>>,
chunk_watchers: Arc<DashMap<Vector2<i32>, usize>>,
Expand Down Expand Up @@ -55,20 +57,26 @@ impl Level {
region_folder.exists(),
"World region folder does not exist, despite there being a root folder."
);
// TODO: read seed from level.dat
let seed = get_or_create_seed();
let save_file = SaveFile {
root_folder,
region_folder,
};

let reader = AnvilChunkReader::new();
let info = reader
.read_world_info(&save_file)
.expect("Unable to get world info!");
let seed = Seed(info.seed as u64);
let world_gen = get_world_gen(seed).into(); // TODO Read Seed from config.

Self {
seed,
world_gen,
save_file: Some(SaveFile {
root_folder,
region_folder,
}),
save_file: Some(save_file),
chunk_reader: Arc::new(AnvilChunkReader::new()),
loaded_chunks: Arc::new(DashMap::new()),
chunk_watchers: Arc::new(DashMap::new()),
world_info: Some(info),
}
} else {
let seed = get_or_create_seed();
Expand All @@ -80,6 +88,7 @@ impl Level {
chunk_reader: Arc::new(AnvilChunkReader::new()),
loaded_chunks: Arc::new(DashMap::new()),
chunk_watchers: Arc::new(DashMap::new()),
world_info: None,
}
}
}
Expand Down

0 comments on commit dd36013

Please sign in to comment.