Parse Registries from JSON

This commit is contained in:
Snowiiii
2024-11-02 16:34:35 +01:00
parent b090c34228
commit 9e7adec16b
32 changed files with 5771 additions and 418 deletions

View File

@@ -49,5 +49,6 @@ crossbeam = "0.8.4"
uuid = { version = "1.11.0", features = ["serde", "v3", "v4"] }
derive_more = { version = "1.0.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
itertools = "0.13.0"

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ import com.google.gson.JsonElement
import de.snowii.extractor.extractors.*
import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.server.MinecraftServer
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -27,6 +26,7 @@ class Extractor : ModInitializer {
Sounds(),
Recipes(),
Particles(),
SyncedRegistries(),
Packet(),
Items(),
Blocks(),

View File

@@ -9,7 +9,6 @@ import net.minecraft.network.NetworkState
import net.minecraft.network.listener.PacketListener
import net.minecraft.network.packet.PacketType
import net.minecraft.network.state.*
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.server.MinecraftServer

View File

@@ -4,9 +4,8 @@ import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.snowii.extractor.Extractor
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.network.packet.s2c.play.InventoryS2CPacket
import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKeys
import net.minecraft.server.MinecraftServer
@@ -17,7 +16,6 @@ class Particles : Extractor.Extractor {
override fun extract(server: MinecraftServer): JsonElement {
val particlesJson = JsonArray()
for (particle in Registries.PARTICLE_TYPE) {
val particleJson = JsonObject()
particleJson.addProperty("id", Registries.PARTICLE_TYPE.getRawId(particle))

View File

@@ -6,8 +6,6 @@ import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.snowii.extractor.Extractor
import net.minecraft.recipe.Recipe
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.registry.RegistryKeys
import net.minecraft.server.MinecraftServer
class Recipes : Extractor.Extractor {
@@ -32,22 +30,22 @@ class Recipes : Extractor.Extractor {
if (slot.isPresent) {
placementJson.addProperty("position", slot.orElseThrow().placerOutputPosition)
}
placementArray.add(placementJson);
placementArray.add(placementJson)
}
recipeJson.add("placementSlots", placementArray);
recipeJson.add("placementSlots", placementArray)
val ingredientArray = JsonArray()
for (ingredient in recipe.ingredientPlacement.ingredients) {
if (ingredient != null) {
val items = ingredient.matchingItems;
val items = ingredient.matchingItems
val ingredientJson = JsonObject()
for (item in items) {
ingredientJson.addProperty("id", item.idAsString)
}
ingredientArray.add(ingredientJson);
ingredientArray.add(ingredientJson)
}
}
recipeJson.add("ingredients", ingredientArray);
recipeJson.add("ingredients", ingredientArray)
// recipeJson.addProperty("placementSlots", gson.toJson(recipe.ingredientPlacement.placementSlots))
recipesJson.add(recipeJson)

View File

@@ -4,7 +4,6 @@ import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.snowii.extractor.Extractor
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.registry.Registries
import net.minecraft.server.MinecraftServer

View File

@@ -0,0 +1,50 @@
package de.snowii.extractor.extractors
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.mojang.serialization.Codec
import com.mojang.serialization.JsonOps
import de.snowii.extractor.Extractor
import net.minecraft.registry.*
import net.minecraft.server.MinecraftServer
import java.util.stream.Stream
class SyncedRegistries : Extractor.Extractor {
override fun fileName(): String {
return "synced_registries.json"
}
override fun extract(server: MinecraftServer): JsonElement {
val registries: Stream<RegistryLoader.Entry<*>> = RegistryLoader.SYNCED_REGISTRIES.stream()
val json = JsonObject()
registries.forEach { entry ->
json.add(
entry.key().value.toString(),
mapJson(entry, server.registryManager, server.combinedDynamicRegistries)
)
}
return json
}
private fun <T> mapJson(
registryEntry: RegistryLoader.Entry<T>,
registryManager: DynamicRegistryManager.Immutable,
combinedRegistries: CombinedDynamicRegistries<ServerDynamicRegistryType?>
): JsonObject {
val codec: Codec<T> = registryEntry.elementCodec()
val registry: Registry<T> = registryManager.getOrThrow(registryEntry.key())
val json = JsonObject()
registry.streamEntries().forEach { entry ->
json.add(
entry.key.orElseThrow().value.toString(),
codec.encodeStart(
combinedRegistries.combinedRegistryManager.getOps(JsonOps.INSTANCE),
entry.value()
).getOrThrow()
)
}
return json
}
}

View File

@@ -1,22 +1,22 @@
{
"schemaVersion": 1,
"id": "extractor",
"version": "${version}",
"name": "pumpkin-extractor",
"description": "",
"authors": [],
"contact": {},
"license": "MIT",
"environment": "*",
"entrypoints": {
"main": [
"de.snowii.extractor.Extractor"
]
},
"depends": {
"fabricloader": ">=${loader_version}",
"fabric-language-kotlin": ">=${kotlin_loader_version}",
"fabric": "*",
"minecraft": "${minecraft_version}"
}
"schemaVersion": 1,
"id": "extractor",
"version": "${version}",
"name": "pumpkin-extractor",
"description": "",
"authors": [],
"contact": {},
"license": "MIT",
"environment": "*",
"entrypoints": {
"main": [
"de.snowii.extractor.Extractor"
]
},
"depends": {
"fabricloader": ">=${loader_version}",
"fabric-language-kotlin": ">=${kotlin_loader_version}",
"fabric": "*",
"minecraft": "${minecraft_version}"
}
}

View File

@@ -1,8 +1,8 @@
use colored::{ColoredString, Colorize};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};
/// Text color
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
#[derive(Default, Debug, Clone, Copy, Serialize)]
#[serde(untagged)]
pub enum Color {
/// The default color for the text will be used, which varies by context
@@ -10,10 +10,33 @@ pub enum Color {
/// is a shade of gray that isn't normally used on text).
#[default]
Reset,
/// RGB Color
Rgb(u32),
/// One of the 16 named Minecraft colors
Named(NamedColor),
}
impl<'de> Deserialize<'de> for Color {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
if s == "reset" {
Ok(Color::Reset)
} else if s.starts_with('#') {
let rgb = u32::from_str_radix(&s.replace("#", ""), 16)
.map_err(|_| serde::de::Error::custom("Invalid hex color"))?;
Ok(Color::Rgb(rgb))
} else {
Ok(Color::Named(NamedColor::try_from(s.as_str()).map_err(
|_| serde::de::Error::custom("Invalid named color"),
)?))
}
}
}
impl Color {
pub fn console_color(&self, text: &str) -> ColoredString {
match self {
@@ -36,6 +59,7 @@ impl Color {
NamedColor::Yellow => text.bright_yellow(),
NamedColor::White => text.white(),
},
Color::Rgb(_) => todo!(),
}
}
}
@@ -61,3 +85,29 @@ pub enum NamedColor {
Yellow,
White,
}
impl TryFrom<&str> for NamedColor {
type Error = ();
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"black" => Ok(NamedColor::Black),
"dark_blue" => Ok(NamedColor::DarkBlue),
"dark_green" => Ok(NamedColor::DarkGreen),
"dark_aqua" => Ok(NamedColor::DarkAqua),
"dark_red" => Ok(NamedColor::DarkRed),
"dark_purple" => Ok(NamedColor::DarkPurple),
"gold" => Ok(NamedColor::Gold),
"gray" => Ok(NamedColor::Gray),
"dark_gray" => Ok(NamedColor::DarkGray),
"blue" => Ok(NamedColor::Blue),
"green" => Ok(NamedColor::Green),
"aqua" => Ok(NamedColor::Aqua),
"red" => Ok(NamedColor::Red),
"light_purple" => Ok(NamedColor::LightPurple),
"yellow" => Ok(NamedColor::Yellow),
"white" => Ok(NamedColor::White),
_ => Err(()),
}
}
}

View File

@@ -9,6 +9,7 @@ use super::{
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Style<'a> {
/// Changes the color to render the content
#[serde(default, skip_serializing_if = "Option::is_none")]
pub color: Option<Color>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub bold: Option<u8>,

View File

@@ -8,9 +8,9 @@ proc-macro = true
[dependencies]
serde.workspace = true
serde_json.workspace = true
itertools.workspace = true
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0"
serde_json = "1.0.132"

View File

@@ -98,7 +98,8 @@ impl<'a> ClientPacket for CChunkData<'a> {
//// Biomes
// TODO: make biomes work
data_buf.put_u8(0);
data_buf.put_var_int(&VarInt(0));
// This seems to be the biome
data_buf.put_var_int(&VarInt(10));
data_buf.put_var_int(&VarInt(0));
});

View File

@@ -8,6 +8,7 @@ pumpkin-protocol = { path = "../pumpkin-protocol" }
pumpkin-core = { path = "../pumpkin-core" }
serde.workspace = true
serde_json.workspace = true
# nbt
fastnbt = { git = "https://github.com/owengage/fastnbt.git" }

View File

@@ -0,0 +1,7 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BannerPattern {
asset_id: String,
translation_key: String,
}

View File

@@ -0,0 +1,71 @@
use pumpkin_protocol::VarInt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Biome {
has_precipitation: i8,
temperature: f32,
#[serde(skip_serializing_if = "Option::is_none")]
temperature_modifier: Option<String>,
downfall: f32,
effects: BiomeEffects,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct BiomeEffects {
fog_color: i32,
water_color: i32,
water_fog_color: i32,
sky_color: i32,
#[serde(skip_serializing_if = "Option::is_none")]
foliage_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
grass_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
grass_color_modifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
particle: Option<Particle>,
#[serde(skip_serializing_if = "Option::is_none")]
ambient_sound: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
mood_sound: Option<MoodSound>,
#[serde(skip_serializing_if = "Option::is_none")]
additions_sound: Option<AdditionsSound>,
#[serde(skip_serializing_if = "Option::is_none")]
music: Option<Music>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Particle {
options: ParticleOptions,
probability: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct ParticleOptions {
#[serde(rename = "type")]
typee: String,
#[serde(skip_serializing_if = "Option::is_none")]
value: Option<VarInt>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct MoodSound {
block_search_extent: i32,
offset: f64,
sound: String,
tick_delay: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct AdditionsSound {
sound: String,
tick_chance: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Music {
sound: String,
min_delay: i32,
max_delay: i32,
replace_current_music: i8,
}

View File

@@ -1,118 +0,0 @@
use pumpkin_protocol::VarInt;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct BiomeCodec {
name: String,
id: i32,
element: Biome,
}
impl Default for BiomeCodec {
fn default() -> Self {
Self {
name: "minecraft:plains".to_string(),
id: 0,
element: Biome::default(),
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct Biome {
has_precipitation: i8,
temperature: f32,
#[serde(skip_serializing_if = "Option::is_none")]
temperature_modifier: Option<String>,
downfall: f32,
effects: BiomeEffects,
}
#[derive(Debug, Clone, Serialize)]
struct BiomeEffects {
fog_color: i32,
water_color: i32,
water_fog_color: i32,
sky_color: i32,
#[serde(skip_serializing_if = "Option::is_none")]
foliage_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
grass_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
grass_color_modifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
particle: Option<Particle>,
#[serde(skip_serializing_if = "Option::is_none")]
ambient_sound: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
mood_sound: Option<MoodSound>,
#[serde(skip_serializing_if = "Option::is_none")]
additions_sound: Option<AdditionsSound>,
#[serde(skip_serializing_if = "Option::is_none")]
music: Option<Music>,
}
#[derive(Debug, Clone, Serialize)]
struct Particle {
options: ParticleOptions,
probability: f32,
}
#[derive(Debug, Clone, Serialize)]
struct ParticleOptions {
typee: String,
#[serde(skip_serializing_if = "Option::is_none")]
value: Option<VarInt>,
}
#[derive(Debug, Clone, Serialize)]
struct MoodSound {
block_search_extent: i32,
offset: f64,
sound: String,
tick_delay: i32,
}
#[derive(Debug, Clone, Serialize)]
struct AdditionsSound {
sound: String,
tick_chance: f64,
}
#[derive(Debug, Clone, Serialize)]
struct Music {
sound: String,
min_delay: i32,
max_delay: i32,
replace_current_music: i8,
}
// 1.20.6 default https://gist.github.com/WinX64/ab8c7a8df797c273b32d3a3b66522906
impl Default for Biome {
fn default() -> Self {
Self {
has_precipitation: 0,
temperature: 1.0,
temperature_modifier: None,
downfall: 0.0,
effects: BiomeEffects {
fog_color: 12638463,
water_color: 4159204,
water_fog_color: 329011,
sky_color: 7907327,
foliage_color: None,
grass_color: None,
grass_color_modifier: None,
particle: None,
ambient_sound: None,
mood_sound: Some(MoodSound {
block_search_extent: 8,
offset: 2.0,
sound: "minecraft:ambient.cave".into(),
tick_delay: 6000,
}),
additions_sound: None,
music: None,
},
}
}
}

View File

@@ -1,33 +1,16 @@
use pumpkin_core::text::style::Style;
use serde::Serialize;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatType {
chat: Decoration,
narration: Decoration,
}
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Decoration {
translation_key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
style: Option<Style<'static>>,
parameters: Vec<String>,
}
impl Default for ChatType {
fn default() -> Self {
Self {
chat: Decoration {
style: None,
parameters: vec!["sender".into(), "content".into()],
translation_key: "chat.type.text".into(),
},
narration: Decoration {
style: None,
parameters: vec!["sender".into(), "content".into()],
translation_key: "chat.type.text.narrate".into(),
},
}
}
}

View File

@@ -1,88 +1,12 @@
use fastnbt::SerOpts;
use pumpkin_protocol::client::config::RegistryEntry;
use serde::Serialize;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DamageType {
exhaustion: f32,
#[serde(skip_serializing_if = "Option::is_none")]
death_message_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
effects: Option<String>,
exhaustion: f32,
message_id: String,
scaling: String,
}
const NAMES: &[&str] = &[
"arrow",
"bad_respawn_point",
"cactus",
"campfire",
"cramming",
"dragon_breath",
"drown",
"dry_out",
"ender_pearl",
"explosion",
"fall",
"falling_anvil",
"falling_block",
"falling_stalactite",
"fireball",
"fireworks",
"fly_into_wall",
"freeze",
"generic",
"generic_kill",
"hot_floor",
"in_fire",
"in_wall",
"indirect_magic",
"lava",
"lightning_bolt",
"mace_smash",
"magic",
"mob_attack",
"mob_attack_no_aggro",
"mob_projectile",
"on_fire",
"out_of_world",
"outside_border",
"player_attack",
"player_explosion",
"sonic_boom",
"spit",
"stalagmite",
"starve",
"sting",
"sweet_berry_bush",
"thorns",
"thrown",
"trident",
"unattributed_fireball",
"wind_charge",
"wither",
"wither_skull",
];
pub(super) fn entries() -> Vec<RegistryEntry<'static>> {
let items: Vec<_> = NAMES
.iter()
.map(|name| RegistryEntry {
entry_id: name,
data: fastnbt::to_bytes_with_opts(
&DamageType {
exhaustion: 0.1,
message_id: "inFire".into(),
scaling: "when_caused_by_living_non_player".into(),
death_message_type: None,
effects: None,
},
SerOpts::network_nbt(),
)
.unwrap(),
})
.collect();
items
}

View File

@@ -0,0 +1,56 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dimension {
ambient_light: f32,
bed_works: u8,
coordinate_scale: f64,
effects: DimensionEffects,
#[serde(skip_serializing_if = "Option::is_none")]
fixed_time: Option<i64>,
has_ceiling: u8,
has_raids: u8,
has_skylight: u8,
height: i32,
infiniburn: String,
logical_height: i32,
min_y: i32,
monster_spawn_block_light_limit: i32,
monster_spawn_light_level: MonsterSpawnLightLevel,
natural: u8,
piglin_safe: u8,
respawn_anchor_works: u8,
ultrawarm: u8,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Default, Debug)]
pub enum DimensionEffects {
#[serde(rename = "minecraft:overworld")]
#[default]
Overworld,
#[serde(rename = "minecraft:the_nether")]
TheNether,
#[serde(rename = "minecraft:the_end")]
TheEnd,
}
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum MonsterSpawnLightLevel {
Int(i32),
Tagged(MonsterSpawnLightLevelTagged),
}
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct MonsterSpawnLightLevelTagged {
min_inclusive: i32,
max_inclusive: i32,
#[serde(rename = "type")]
typee: String,
}
impl From<i32> for MonsterSpawnLightLevel {
fn from(value: i32) -> Self {
Self::Int(value)
}
}

View File

@@ -1,83 +0,0 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dimension {
ambient_light: f32,
bed_works: u8,
coordinate_scale: f64,
effects: DimensionEffects,
#[serde(skip_serializing_if = "Option::is_none")]
fixed_time: Option<i64>,
has_ceiling: u8,
has_raids: u8,
has_skylight: u8,
height: i32,
infiniburn: String,
logical_height: i32,
min_y: i32,
monster_spawn_block_light_limit: i32,
monster_spawn_light_level: MonsterSpawnLightLevel,
natural: u8,
piglin_safe: u8,
respawn_anchor_works: u8,
ultrawarm: u8,
}
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Debug)]
pub enum DimensionEffects {
#[serde(rename = "minecraft:overworld")]
#[default]
Overworld,
#[serde(rename = "minecraft:the_nether")]
TheNether,
#[serde(rename = "minecraft:the_end")]
TheEnd,
}
impl Default for Dimension {
fn default() -> Self {
Self {
ambient_light: 0.0,
bed_works: 1,
coordinate_scale: 1.0,
effects: DimensionEffects::default(),
fixed_time: None,
has_ceiling: 0,
has_raids: 1,
has_skylight: 1,
height: 384,
infiniburn: "#minecraft:infiniburn_overworld".into(),
logical_height: 384,
min_y: -64,
monster_spawn_block_light_limit: 15,
monster_spawn_light_level: MonsterSpawnLightLevel::Int(7),
natural: 1,
piglin_safe: 0,
respawn_anchor_works: 0,
ultrawarm: 0,
}
}
}
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum MonsterSpawnLightLevel {
Int(i32),
Tagged(MonsterSpawnLightLevelTagged),
}
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(tag = "type", content = "value")]
pub enum MonsterSpawnLightLevelTagged {
#[serde(rename = "minecraft:uniform")]
Uniform {
min_inclusive: i32,
max_inclusive: i32,
},
}
impl From<i32> for MonsterSpawnLightLevel {
fn from(value: i32) -> Self {
Self::Int(value)
}
}

View File

@@ -0,0 +1,7 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Enchantment {
// TODO: Add things :D
// description: Text<'static>,
}

View File

@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Instrument {
sound_event: String,
use_duration: f32,
range: f32,
// description: TextComponent<'static>,
}

View File

@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JukeboxSong {
sound_event: String,
// description: TextComponent<'static>,
length_in_seconds: f32,
comparator_output: u32,
}

View File

@@ -1,86 +1,248 @@
use biomes::Biome;
use std::{collections::HashMap, sync::LazyLock};
use banner_pattern::BannerPattern;
use biome::Biome;
use chat_type::ChatType;
use dimensions::Dimension;
use damage_type::DamageType;
use dimension::Dimension;
use enchantment::Enchantment;
use fastnbt::SerOpts;
use instrument::Instrument;
use jukebox_song::JukeboxSong;
use paint::Painting;
use pumpkin_protocol::client::config::RegistryEntry;
use serde::{Deserialize, Serialize};
use trim_material::TrimMaterial;
use trim_pattern::TrimPattern;
use wolf::WolfVariant;
mod biomes;
mod banner_pattern;
mod biome;
mod chat_type;
mod damage_type;
mod dimensions;
mod dimension;
mod enchantment;
mod instrument;
mod jukebox_song;
mod paint;
mod trim_material;
mod trim_pattern;
mod wolf;
pub static SYNCED_REGISTRIES: LazyLock<SyncedRegistry> = LazyLock::new(|| {
serde_json::from_str(include_str!("../../assets/synced_registries.json"))
.expect("Could not parse synced_registries.json registry.")
});
pub struct Registry {
pub registry_id: String,
pub registry_entries: Vec<RegistryEntry<'static>>,
}
#[derive(Serialize, Deserialize)]
pub struct SyncedRegistry {
#[serde(rename = "minecraft:worldgen/biome")]
biome: HashMap<String, Biome>,
#[serde(rename = "minecraft:chat_type")]
chat_type: HashMap<String, ChatType>,
#[serde(rename = "minecraft:trim_pattern")]
trim_pattern: HashMap<String, TrimPattern>,
#[serde(rename = "minecraft:trim_material")]
trim_material: HashMap<String, TrimMaterial>,
#[serde(rename = "minecraft:wolf_variant")]
wolf_variant: HashMap<String, WolfVariant>,
#[serde(rename = "minecraft:painting_variant")]
painting_variant: HashMap<String, Painting>,
#[serde(rename = "minecraft:dimension_type")]
dimension_type: HashMap<String, Dimension>,
#[serde(rename = "minecraft:damage_type")]
damage_type: HashMap<String, DamageType>,
#[serde(rename = "minecraft:banner_pattern")]
banner_pattern: HashMap<String, BannerPattern>,
#[serde(rename = "minecraft:enchantment")]
enchantment: HashMap<String, Enchantment>,
#[serde(rename = "minecraft:jukebox_song")]
jukebox_song: HashMap<String, JukeboxSong>,
#[serde(rename = "minecraft:instrument")]
instrument: HashMap<String, Instrument>,
}
impl Registry {
/// We should parse this from a JSON in the future
pub fn get_static() -> Vec<Self> {
let dimensions = Registry {
registry_id: "minecraft:dimension_type".to_string(),
registry_entries: vec![RegistryEntry {
entry_id: "minecraft:overworld",
data: fastnbt::to_bytes_with_opts(&Dimension::default(), SerOpts::network_nbt())
.unwrap(),
}],
};
let biomes = Registry {
pub fn get_synced() -> Vec<Self> {
let registry_entries = SYNCED_REGISTRIES
.biome
.iter()
.map(|s| RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
})
.collect();
let biome = Registry {
registry_id: "minecraft:worldgen/biome".to_string(),
registry_entries: vec![
RegistryEntry {
entry_id: "minecraft:plains",
data: fastnbt::to_bytes_with_opts(&Biome::default(), SerOpts::network_nbt())
.unwrap(),
},
RegistryEntry {
entry_id: "minecraft:snowy_taiga",
data: fastnbt::to_bytes_with_opts(&Biome::default(), SerOpts::network_nbt())
.unwrap(),
},
],
};
let wolf_variants = Registry {
registry_id: "minecraft:wolf_variant".to_string(),
registry_entries: vec![RegistryEntry {
entry_id: "minecraft:wolf_variant",
data: fastnbt::to_bytes_with_opts(&WolfVariant::default(), SerOpts::network_nbt())
.unwrap(),
}],
registry_entries,
};
let chat_types = Registry {
let registry_entries = SYNCED_REGISTRIES
.chat_type
.iter()
.map(|s| RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
})
.collect();
let chat_type = Registry {
registry_id: "minecraft:chat_type".to_string(),
registry_entries: vec![RegistryEntry {
entry_id: "minecraft:chat",
data: fastnbt::to_bytes_with_opts(&ChatType::default(), SerOpts::network_nbt())
.unwrap(),
}],
registry_entries,
};
let damage_types = Registry {
registry_id: "minecraft:damage_type".to_string(),
registry_entries: damage_type::entries(),
// let registry_entries = SYNCED_REGISTRIES
// .trim_pattern
// .iter()
// .map(|s| RegistryEntry {
// entry_id: s.0,
// data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
// })
// .collect();
// let trim_pattern = Registry {
// registry_id: "minecraft:trim_pattern".to_string(),
// registry_entries,
// };
// let registry_entries = SYNCED_REGISTRIES
// .trim_material
// .iter()
// .map(|s| RegistryEntry {
// entry_id: s.0,
// data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
// })
// .collect();
// let trim_material = Registry {
// registry_id: "minecraft:trim_material".to_string(),
// registry_entries,
// };
let registry_entries = SYNCED_REGISTRIES
.wolf_variant
.iter()
.map(|s| {
// I present to you, A ugly hack which is done because Mojang developers decited to put is_<biome> instead of just <biome> on 3 wolf varients while all others have just the biome, this causes the client to not find the biome and disconnect
let varient = s.1.clone();
RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&varient, SerOpts::network_nbt()).unwrap(),
}
})
.collect();
let wolf_variant = Registry {
registry_id: "minecraft:wolf_variant".to_string(),
registry_entries,
};
let paintings = Registry {
let registry_entries = SYNCED_REGISTRIES
.painting_variant
.iter()
.map(|s| RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
})
.collect();
let painting_variant = Registry {
registry_id: "minecraft:painting_variant".to_string(),
registry_entries: vec![RegistryEntry {
entry_id: "minecraft:painting_variant",
data: fastnbt::to_bytes_with_opts(&Painting::default(), SerOpts::network_nbt())
.unwrap(),
}],
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
.dimension_type
.iter()
.map(|s| RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
})
.collect();
let dimension_type = Registry {
registry_id: "minecraft:dimension_type".to_string(),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
.damage_type
.iter()
.map(|s| RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
})
.collect();
let damage_type = Registry {
registry_id: "minecraft:damage_type".to_string(),
registry_entries,
};
let registry_entries = SYNCED_REGISTRIES
.banner_pattern
.iter()
.map(|s| RegistryEntry {
entry_id: s.0,
data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
})
.collect();
let banner_pattern = Registry {
registry_id: "minecraft:banner_pattern".to_string(),
registry_entries,
};
// TODO
// let registry_entries = SYNCED_REGISTRIES
// .enchantment
// .iter()
// .map(|s| RegistryEntry {
// entry_id: s.0,
// data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
// })
// .collect();
// let enchantment = Registry {
// registry_id: "minecraft:enchantment".to_string(),
// registry_entries,
// };
// let registry_entries = SYNCED_REGISTRIES
// .jukebox_song
// .iter()
// .map(|s| RegistryEntry {
// entry_id: s.0,
// data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
// })
// .collect();
// let jukebox_song = Registry {
// registry_id: "minecraft:jukebox_song".to_string(),
// registry_entries,
// };
// let registry_entries = SYNCED_REGISTRIES
// .instrument
// .iter()
// .map(|s| RegistryEntry {
// entry_id: s.0,
// data: fastnbt::to_bytes_with_opts(&s.1, SerOpts::network_nbt()).unwrap(),
// })
// .collect();
// let instrument = Registry {
// registry_id: "minecraft:instrument".to_string(),
// registry_entries,
// };
vec![
dimensions,
damage_types,
biomes,
wolf_variants,
paintings,
chat_types,
biome,
chat_type,
// trim_pattern,
// trim_material,
wolf_variant,
painting_variant,
dimension_type,
damage_type,
banner_pattern,
// enchantment,
// jukebox_song,
// instrument,
]
}
}

View File

@@ -3,16 +3,10 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Painting {
asset_id: String,
// #[serde(skip_serializing_if = "Option::is_none")]
// title: Option<TextComponent<'static>>,
// #[serde(skip_serializing_if = "Option::is_none")]
// author: Option<TextComponent<'static>>,
height: i32,
width: i32,
}
impl Default for Painting {
fn default() -> Self {
Self {
asset_id: "minecraft:backyard".into(),
height: 2,
width: 2,
}
}
}

View File

@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrimMaterial {
asset_name: String,
ingredient: String,
item_model_index: f32,
// description: TextComponent<'static>,
}

View File

@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrimPattern {
asset_id: String,
template_item: String,
// description: TextComponent<'static>,
decal: u8,
}

View File

@@ -5,16 +5,5 @@ pub struct WolfVariant {
wild_texture: String,
tame_texture: String,
angry_texture: String,
biomes: String,
}
impl Default for WolfVariant {
fn default() -> Self {
Self {
wild_texture: "minecraft:entity/wolf/wolf_ashen".to_string(),
tame_texture: "minecraft:entity/wolf/wolf_ashen_tame".to_string(),
angry_texture: "minecraft:entity/wolf/wolf_ashen_angry".to_string(),
biomes: "minecraft:snowy_taiga".to_string(),
}
}
pub biomes: String,
}

View File

@@ -13,6 +13,7 @@ derive_more.workspace = true
itertools.workspace = true
thiserror.workspace = true
serde.workspace = true
serde_json.workspace = true
log.workspace = true
parking_lot.workspace = true
@@ -25,7 +26,6 @@ dashmap = "6.1.0"
flate2 = "1.0"
lz4 = "1.28.0"
serde_json = "1.0"
enum_dispatch = "0.3.13"
derive-getters = "0.5.0"

View File

@@ -29,7 +29,7 @@ parking_lot.workspace = true
# config
serde.workspace = true
serde_json = "1.0"
serde_json.workspace = true
bytes = "1.8"

View File

@@ -82,7 +82,7 @@ impl Server {
"./world".parse().unwrap(),
));
Self {
cached_registry: Registry::get_static(),
cached_registry: Registry::get_synced(),
open_containers: RwLock::new(HashMap::new()),
drag_handler: DragHandler::new(),
// 0 is invalid