Pumpkin/pumpkin-world/src/world_info/mod.rs
Alexander Medvedev 82948f830e Update to 1.21.6
2025-06-17 19:53:33 +02:00

196 lines
6.1 KiB
Rust

use std::path::Path;
use pumpkin_config::BASIC_CONFIG;
use pumpkin_util::{Difficulty, serde_enum_as_integer};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::generation::Seed;
pub mod anvil;
// Constraint: disk biome palette serialization changed in 1.21.5
pub const MINIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4435; // 1.21.6
pub const MAXIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4435; // 1.21.6
pub trait WorldInfoReader {
fn read_world_info(&self, level_folder: &Path) -> Result<LevelData, WorldInfoError>;
}
pub trait WorldInfoWriter: Sync + Send {
fn write_world_info(&self, info: &LevelData, level_folder: &Path)
-> Result<(), WorldInfoError>;
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct LevelData {
// true if cheats are enabled.
#[serde(rename = "allowCommands")]
pub allow_commands: bool,
// Center of the world border on the X coordinate. Defaults to 0.
pub border_center_x: f64,
// Center of the world border on the Z coordinate. Defaults to 0.
pub border_center_z: f64,
// Defaults to 0.2.
pub border_damage_per_block: f64,
// Width and length of the border of the border. Defaults to 60000000.
pub border_size: f64,
// Defaults to 5.
pub border_safe_zone: f64,
// Defaults to 60000000.
pub border_size_lerp_target: f64,
// Defaults to 0.
pub border_size_lerp_time: i64,
// Defaults to 5.
pub border_warning_blocks: f64,
// Defaults to 15.
pub border_warning_time: f64,
// The number of ticks until "clear weather" has ended.
#[serde(rename = "clearWeatherTime")]
pub clear_weather_time: i32,
// TODO: Custom Boss Events
// Options for data packs.
pub data_packs: DataPacks,
// An integer displaying the data version.
pub data_version: i32,
// The time of day. 0 is sunrise, 6000 is mid day, 12000 is sunset, 18000 is mid night, 24000 is the next day's 0. This value keeps counting past 24000 and does not reset to 0.
pub day_time: i64,
// The current difficulty setting.
#[serde(with = "serde_enum_as_integer")]
pub difficulty: Difficulty,
// 1 or 0 (true/false) - True if the difficulty has been locked. Defaults to 0.
pub difficulty_locked: bool,
// TODO: DimensionData
// the generation settings for each dimension.
pub world_gen_settings: WorldGenSettings,
// The Unix time in milliseconds when the level was last loaded.
pub last_played: i64,
// The name of the level.
pub level_name: String,
// The X coordinate of the world spawn.
pub spawn_x: i32,
// The Y coordinate of the world spawn.
pub spawn_y: i32,
// The Z coordinate of the world spawn.
pub spawn_z: i32,
// The Yaw rotation of the world spawn.
pub spawn_angle: f32,
#[serde(rename = "version")]
// The NBT version of the level
pub nbt_version: i32,
#[serde(rename = "Version")]
pub version: WorldVersion,
// TODO: Implement the rest of the fields
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct WorldGenSettings {
// the numerical seed of the world
pub seed: i64,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct DataPacks {
// List of disabled data packs.
pub disabled: Vec<String>,
// List of enabled data packs. By default, this is populated with a single string "vanilla".
pub enabled: Vec<String>,
}
fn get_or_create_seed() -> Seed {
// TODO: if there is a seed in the config (!= "") use it. Otherwise make a random one
Seed::from(BASIC_CONFIG.seed.as_str())
}
impl Default for WorldGenSettings {
fn default() -> Self {
Self {
seed: get_or_create_seed().0 as i64,
}
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct WorldVersion {
// The version name as a string, e.g. "15w32b".
pub name: String,
// An integer displaying the data version.
pub id: i32,
// Whether the version is a snapshot or not.
pub snapshot: bool,
// Developing series. In 1.18 experimental snapshots, it was set to "ccpreview". In others, set to "main".
pub series: String,
}
impl Default for WorldVersion {
fn default() -> Self {
Self {
name: "1.24.4".to_string(),
id: -1,
snapshot: false,
series: "main".to_string(),
}
}
}
impl Default for LevelData {
fn default() -> Self {
Self {
allow_commands: true,
border_center_x: 0.0,
border_center_z: 0.0,
border_damage_per_block: 0.2,
border_size: 60_000_000.0,
border_safe_zone: 5.0,
border_size_lerp_target: 60_000_000.0,
border_size_lerp_time: 0,
border_warning_blocks: 5.0,
border_warning_time: 15.0,
clear_weather_time: -1,
data_packs: DataPacks {
disabled: vec![],
enabled: vec!["vanilla".to_string()],
},
data_version: MAXIMUM_SUPPORTED_WORLD_DATA_VERSION,
day_time: 0,
difficulty: Difficulty::Normal,
difficulty_locked: false,
world_gen_settings: Default::default(),
last_played: -1,
level_name: "world".to_string(),
spawn_x: 0,
spawn_y: 200,
spawn_z: 0,
spawn_angle: 0.0,
nbt_version: -1,
version: Default::default(),
}
}
}
#[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),
#[error("Unsupported world data version: {0}")]
UnsupportedVersion(i32),
}
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),
}
}
}