-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement level.dat reading and load the seed for use in world genera…
…tion (#402) * Implement level.dat reading and use the seed in the world for chunk generation * Add tests * Seperate world info loading from chunk reading * Fix cargo fmt --------- Co-authored-by: Alexander Medvedev <[email protected]>
- Loading branch information
1 parent
5394910
commit cc83e09
Showing
5 changed files
with
144 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use std::{fs::OpenOptions, io::Read}; | ||
|
||
use flate2::read::GzDecoder; | ||
use serde::Deserialize; | ||
|
||
use crate::level::SaveFile; | ||
|
||
use super::{WorldInfo, WorldInfoError, WorldInfoReader}; | ||
|
||
pub struct AnvilInfoReader {} | ||
|
||
impl AnvilInfoReader { | ||
pub fn new() -> Self { | ||
Self {} | ||
} | ||
} | ||
|
||
impl WorldInfoReader for AnvilInfoReader { | ||
fn read_world_info(&self, save_file: &SaveFile) -> Result<WorldInfo, WorldInfoError> { | ||
let path = save_file.root_folder.join("level.dat"); | ||
|
||
let mut world_info_file = OpenOptions::new().read(true).open(path)?; | ||
|
||
let mut buffer = Vec::new(); | ||
world_info_file.read_to_end(&mut buffer)?; | ||
|
||
let mut decoder = GzDecoder::new(&buffer[..]); | ||
let mut decompressed_data = Vec::new(); | ||
decoder.read_to_end(&mut decompressed_data)?; | ||
|
||
let info = fastnbt::from_bytes::<LevelDat>(&decompressed_data) | ||
.map_err(|e| WorldInfoError::DeserializationError(e.to_string()))?; | ||
|
||
Ok(WorldInfo { | ||
seed: info.data.world_gen_settings.seed, | ||
}) | ||
} | ||
} | ||
|
||
impl Default for AnvilInfoReader { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
#[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)] | ||
mod tests { | ||
use std::path::PathBuf; | ||
|
||
use crate::{ | ||
level::SaveFile, | ||
world_info::{anvil::AnvilInfoReader, WorldInfo, WorldInfoReader}, | ||
}; | ||
|
||
#[test] | ||
fn test_level_dat_reading() { | ||
let world_info = AnvilInfoReader::new(); | ||
let root_folder = PathBuf::from("test-files").join("sample-1"); | ||
let save_file = SaveFile { | ||
root_folder: root_folder.clone(), | ||
region_folder: root_folder, | ||
}; | ||
let expected = WorldInfo { | ||
seed: -79717552349559436, | ||
}; | ||
let info = world_info.read_world_info(&save_file).unwrap(); | ||
|
||
assert_eq!(info, expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use thiserror::Error; | ||
|
||
use crate::level::SaveFile; | ||
|
||
pub mod anvil; | ||
|
||
pub(crate) trait WorldInfoReader { | ||
fn read_world_info(&self, save_file: &SaveFile) -> Result<WorldInfo, WorldInfoError>; | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub struct WorldInfo { | ||
pub seed: i64, | ||
// TODO: Implement all fields | ||
} | ||
|
||
#[derive(Error, Debug)] | ||
pub enum WorldInfoError { | ||
#[error("Io error: {0}")] | ||
IoError(std::io::ErrorKind), | ||
#[error("Info not found!")] | ||
InfoNotFound, | ||
#[error("Deserialization error: {0}")] | ||
DeserializationError(String), | ||
} | ||
|
||
impl From<std::io::Error> for WorldInfoError { | ||
fn from(value: std::io::Error) -> Self { | ||
match value.kind() { | ||
std::io::ErrorKind::NotFound => Self::InfoNotFound, | ||
value => Self::IoError(value), | ||
} | ||
} | ||
} |
Binary file not shown.