add default value

This commit is contained in:
2025-08-21 17:34:53 +02:00
parent a55fe08a93
commit 7be6993735
4 changed files with 212 additions and 166 deletions

View File

@@ -4,10 +4,11 @@ version = "0.1.0"
edition = "2024"
[dependencies]
image = "0.25.6"
rand = "0.9.2"
rand_chacha = "0.9.0"
nbt = { git = "https://github.com/Cactus-minecraft-server/nbt.git" }
[lib]
name = "world"
path = "src/lib.rs"
[dev-dependencies]
image = "0.25.6"

View File

@@ -1,7 +1,104 @@
use nbt::{Tag, write_nbt};
use nbt::{Tag, Writer, write_nbt};
use std::collections::HashMap;
use std::fs::File;
pub struct CustomBossEvents {
boss: Vec<String>,
}
impl Default for CustomBossEvents {
fn default() -> Self {
Self {
boss: ["".into()].into(),
}
}
}
pub struct DataPacks {
pub disabled: Vec<String>,
pub enabled: Vec<String>,
}
impl Default for DataPacks {
fn default() -> Self {
Self {
disabled: [
"minecraft_improvement".into(),
"redstone_experiments".into(),
"trade_rebalance".into(),
]
.into(),
enabled: ["vanilla".into()].into(),
}
}
}
pub struct DragonFight {
pub gateways: Vec<i32>,
pub dragon_killed: bool,
pub needs_state_scanning: bool,
pub previously_killed: bool,
}
impl Default for DragonFight {
fn default() -> Self {
Self {
gateways: [].into(),
dragon_killed: false,
needs_state_scanning: true,
previously_killed: false,
}
}
}
pub type GameRules = HashMap<String, String>;
pub struct VersionInfo {
pub id: i32,
pub name: String,
pub series: String,
pub snapshot: bool,
}
impl Default for VersionInfo {
fn default() -> Self {
Self {
id: 4440,
name: "1.21.8".into(),
series: "main".into(),
snapshot: false,
}
}
}
pub enum Dimension {
Overworld,
End,
Nether,
}
pub struct WorldGenSettings {
pub dimensions: HashMap<String, Dimension>,
pub bonus_chest: bool,
pub generate_features: bool,
pub seed: i64,
}
impl Default for WorldGenSettings {
fn default() -> Self {
let mut dim: HashMap<String, Dimension> = HashMap::new();
dim.insert("Overworld".into(), Dimension::Overworld);
dim.insert("Nether".into(), Dimension::Nether);
dim.insert("The_End".into(), Dimension::End);
Self {
dimensions: dim,
bonus_chest: false,
generate_features: true,
seed: 42,
}
}
}
pub type ServerBrands = Vec<String>;
pub struct LevelDat {
pub custom_boss_events: CustomBossEvents,
pub data_packs: DataPacks,
@@ -9,7 +106,7 @@ pub struct LevelDat {
pub game_rules: GameRules,
pub version: VersionInfo,
pub world_gen_settings: WorldGenSettings,
pub scheduled_events: ScheduledEvents,
pub scheduled_events: Vec<String>,
pub server_brands: ServerBrands,
pub allow_commands: bool,
@@ -48,46 +145,53 @@ pub struct LevelDat {
pub wandering_trader_spawn_delay: i32,
pub was_modded: bool,
}
pub struct CustomBossEvents {}
pub struct DataPacks {
pub disabled: Vec<String>,
pub enabled: Vec<String>,
impl Default for LevelDat {
fn default() -> Self {
Self {
custom_boss_events: CustomBossEvents::default(),
data_packs: DataPacks::default(),
dragon_fight: DragonFight::default(),
game_rules: GameRules::default(),
version: VersionInfo::default(),
world_gen_settings: WorldGenSettings::default(),
scheduled_events: ["".into()].into(),
server_brands: ServerBrands::default(),
allow_commands: false,
border_center_x: 0.0,
border_center_z: 0.0,
border_damage_per_block: 0.2,
border_safe_zone: 5.0,
border_size: 59999968.0,
border_size_lerp_target: 59999968.0,
border_size_lerp_time: 0,
border_warning_blocks: 15,
border_warning_time: 15,
clear_weather_time: 0,
data_version: 4440,
day_time: 95,
difficulty: 1,
difficulty_locked: false,
game_type: 0,
hardcore: false,
initialized: true,
last_played: 0,
level_name: "World".into(),
raining: false,
rain_time: 0,
spawn_angle: 0.0,
spawn_x: 0,
spawn_y: 82,
spawn_z: 0,
thundering: false,
thunder_time: 0,
time: 95,
version_id: 19133,
wandering_trader_spawn_chance: 25,
wandering_trader_spawn_delay: 24000,
was_modded: false,
}
pub struct DragonFight {
pub gateways: Vec<i32>,
pub dragon_killed: bool,
pub needs_state_scanning: bool,
pub previously_killed: bool,
}
pub type GameRules = HashMap<String, String>;
pub struct VersionInfo {
pub id: i32,
pub name: String,
pub series: String,
pub snapshot: i8,
}
pub enum Dimension {
Overworld,
End,
Nether,
}
pub struct WorldGenSettings {
pub dimensions: HashMap<String, Dimension>,
pub bonus_chest: bool,
pub generate_features: bool,
pub seed: i64,
}
pub struct ScheduledEvents {}
pub type ServerBrands = Vec<String>;
fn dim_to_str(d: &Dimension) -> &'static str {
match d {
Dimension::Overworld => "overworld",
@@ -262,7 +366,7 @@ pub fn create_nbt(level: &LevelDat, path: &str) -> std::io::Result<()> {
);
ver.insert(
"Snapshot".to_string(),
Tag::new_byte("Snapshot", level.version.snapshot),
Tag::new_byte("Snapshot", i8::from(level.version.snapshot)),
);
root.insert("Version".to_string(), ver);
@@ -380,6 +484,7 @@ pub fn create_nbt(level: &LevelDat, path: &str) -> std::io::Result<()> {
// --- write ---
let file = File::create(format!("{path}/level.dat"))?;
write_nbt(&root, file)?;
let mut w = Writer::to_gzip(file);
w.write_tag(&root)?;
Ok(())
}

View File

@@ -1,5 +1,7 @@
use nbt::{Tag, write_nbt};
use nbt::{Tag, Writer, write_nbt};
use std::fs::File;
use crate::level::Dimension;
pub struct PlayerData {
pub inventory: Vec<Item>,
pub motion: [f64; 2],
@@ -10,7 +12,7 @@ pub struct PlayerData {
pub current_impulse_context_reset_grace_time: i32,
pub data_version: i32,
pub death_time: i16,
pub dimension: String,
pub dimension: Dimension,
pub fall_distance: f64,
pub fall_flying: bool,
pub fire: i16,
@@ -37,12 +39,61 @@ pub struct PlayerData {
pub xp_total: i32,
pub uuid: [i32; 4],
}
impl Default for PlayerData {
fn default() -> Self {
Self {
inventory: [].into(),
motion: [0.0, 0.0].into(),
position: [0.0, 0.0, 0.0].into(),
rotation: [0.0, 0.0].into(),
absorbtion_amount: 0.0,
air: 300,
current_impulse_context_reset_grace_time: 0,
data_version: 4440,
death_time: 0,
dimension: Dimension::Overworld,
fall_distance: 0.0,
fall_flying: false,
fire: -20,
food_exhaustion_level: 0.0,
food_level: 20,
food_saturation_level: 5.0,
food_tick_timer: 0,
health: 20.0,
hurt_by_timestamp: 0,
hurt_time: 0,
ignore_fall_damage_from_current_explosion: false,
invulnerable: false,
on_ground: true,
player_game_type: 0,
portal_cooldown: 0,
score: 0,
seen_credits: false,
selected_item_slot: 0,
sleep_timer: 0,
spawn_extra_particles_on_fall: false,
xp_level: 0,
xp_p: 0.0,
xp_seed: 0,
xp_total: 0,
uuid: [0, 0, 0, 0],
}
}
}
pub struct Item {
pub count: i8,
pub slot: i8,
pub metadata: i16,
pub id: String,
}
fn dim_to_str(d: &Dimension) -> &'static str {
match d {
Dimension::Overworld => "overworld",
Dimension::End => "the_end",
Dimension::Nether => "the_nether",
}
}
pub fn create_nbt(uuid: &String, player_data: PlayerData, path: String) -> std::io::Result<()> {
let mut root = Tag::new_compound(uuid);
let mut inventory = Tag::new_compound("inventory");
@@ -85,7 +136,7 @@ pub fn create_nbt(uuid: &String, player_data: PlayerData, path: String) -> std::
);
root.insert(
"Dimension".into(),
Tag::new_string("Dimension", player_data.dimension),
Tag::new_string("Dimension", dim_to_str(&player_data.dimension)),
);
root.insert(
"fall_distance".into(),
@@ -183,6 +234,7 @@ pub fn create_nbt(uuid: &String, player_data: PlayerData, path: String) -> std::
);
let file = File::create(format!("{path}/{uuid}.dat"))?;
write_nbt(&root, file)?;
let mut w = Writer::to_gzip(file);
w.write_tag(&root)?;
Ok(())
}

View File

@@ -48,83 +48,13 @@ mod perlin_test {
/// Test for level.rs
#[cfg(test)]
mod level_file_test {
use crate::level::{
CustomBossEvents, DataPacks, Dimension, DragonFight, LevelDat, ScheduledEvents,
ServerBrands, VersionInfo, WorldGenSettings, create_nbt,
};
use std::collections::HashMap;
use crate::level::{LevelDat, create_nbt};
#[test]
fn test_creation_of_file() {
let mut game_rules: HashMap<String, String> = HashMap::new();
game_rules.insert("doDaylightCycle".into(), "true".into());
let mut dimensions: HashMap<String, Dimension> = HashMap::new();
dimensions.insert("minecraft:overworld".into(), Dimension::Overworld);
let level = LevelDat {
custom_boss_events: CustomBossEvents {},
data_packs: DataPacks {
disabled: vec![],
enabled: vec![],
},
dragon_fight: DragonFight {
gateways: vec![0, 1, 2],
dragon_killed: false,
needs_state_scanning: false,
previously_killed: false,
},
game_rules,
version: VersionInfo {
id: 3465,
name: "1.20.1".into(),
series: "main".into(),
snapshot: 0,
},
world_gen_settings: WorldGenSettings {
dimensions,
bonus_chest: false,
generate_features: true,
seed: 1234,
},
scheduled_events: ScheduledEvents {},
server_brands: ServerBrands::from(vec!["vanilla".to_string()]),
allow_commands: true,
border_center_x: 0.0,
border_center_z: 0.0,
border_damage_per_block: 0.0,
border_safe_zone: 0.0,
border_size: 60_000_000.0,
border_size_lerp_target: 60_000_000.0,
border_size_lerp_time: 0,
border_warning_blocks: 5,
border_warning_time: 15,
clear_weather_time: 0,
data_version: 3465,
day_time: 0,
difficulty: 2,
difficulty_locked: false,
game_type: 0,
hardcore: false,
initialized: true,
last_played: 0,
level_name: "test".into(),
raining: false,
rain_time: 0,
spawn_angle: 0.0,
spawn_x: 0,
spawn_y: 64,
spawn_z: 0,
thundering: false,
thunder_time: 0,
time: 0,
version_id: 3465,
wandering_trader_spawn_chance: 25,
wandering_trader_spawn_delay: 1200,
was_modded: false,
..Default::default()
};
let result = create_nbt(&level, "target");
@@ -135,60 +65,18 @@ mod level_file_test {
/// Test for player.rs
#[cfg(test)]
mod player_data_test {
use crate::player::{Item, PlayerData, create_nbt};
use crate::player::{PlayerData, create_nbt};
#[test]
fn test_playerdata_creation() {
let item = Item {
count: 1,
slot: 0,
metadata: 0,
id: "minecraft:stone".to_string(),
};
let data = PlayerData {
inventory: vec![item],
motion: [0.0, 0.0],
position: [0.0, 64.0, 0.0],
rotation: [0.0, 0.0],
absorbtion_amount: 0.0,
air: 300,
current_impulse_context_reset_grace_time: 0,
data_version: 3465,
death_time: 0,
dimension: "minecraft:overworld".to_string(),
fall_distance: 0.0,
fall_flying: false,
fire: -20,
food_exhaustion_level: 0.0,
food_level: 20,
food_saturation_level: 5.0,
food_tick_timer: 0,
health: 20.0,
hurt_by_timestamp: 0,
hurt_time: 0,
ignore_fall_damage_from_current_explosion: false,
invulnerable: false,
on_ground: true,
player_game_type: 0,
portal_cooldown: 0,
score: 0,
seen_credits: false,
selected_item_slot: 0,
sleep_timer: 0,
spawn_extra_particles_on_fall: false,
xp_level: 0,
xp_p: 0.0,
xp_seed: 0,
xp_total: 0,
uuid: [0, 0, 0, 0],
..Default::default()
};
let result = create_nbt(
&"8c701aa5-e353-42dd-aa71-95d76b63a5d7".into(),
data,
"target/".into(),
);
assert_eq!(result.is_ok(), true);
assert!(result.is_ok());
}
}