Minecraft-Console-Client/tools/gen_block_palette.py
BruceChen 34671fdab2 feat: enhance palette generation and validation for MC 1.21.9
Updated the SKILL.md documentation to include critical steps for generating server reports and validating decompiled source against server data, emphasizing the importance of using server data since MC 1.21.9. Enhanced the diff_registries.py script to support cross-validation with server registries.json, allowing for accurate palette generation. Added new scripts for generating block and entity palettes from server data, ensuring completeness and correctness of entries.

This update improves the workflow for adapting to new Minecraft versions and ensures that palette generation reflects the latest changes in item and block registration.

Made-with: Cursor
2026-03-21 15:04:20 +08:00

119 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""
Generate an MCC BlockPalette C# file from server-generated blocks.json.
The blocks.json file is generated by running:
java -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports
Usage:
python3 tools/gen_block_palette.py <blocks.json> <suffix>
Example:
python3 tools/gen_block_palette.py /tmp/mc_reports/reports/blocks.json 1219
# Generates Palette1219.cs
"""
import json
import re
import sys
from pathlib import Path
OUTPUT_DIR = (Path(__file__).resolve().parent.parent /
"MinecraftClient" / "Mapping" / "BlockPalettes")
MATERIAL_CS = OUTPUT_DIR.parent / "Material.cs"
def mc_name_to_csharp(mc_name: str) -> str:
"""Convert minecraft:snake_case to PascalCase C# enum name."""
name = mc_name.removeprefix("minecraft:")
return "".join(word.capitalize() for word in name.split("_"))
def load_known_materials() -> set[str]:
known = set()
if MATERIAL_CS.exists():
with open(MATERIAL_CS) as f:
for line in f:
m = re.match(r'\s+(\w+),?\s*$', line)
if m:
known.add(m.group(1))
return known
def main():
if len(sys.argv) != 3:
print(__doc__)
sys.exit(1)
blocks_json = Path(sys.argv[1])
class_suffix = sys.argv[2]
if not blocks_json.exists():
print(f"Error: {blocks_json} not found")
sys.exit(1)
with open(blocks_json) as f:
data = json.load(f)
# Build (min_state, max_state, cs_name) for each block, sorted by min_state
block_ranges = []
for block_key, block_info in data.items():
cs_name = mc_name_to_csharp(block_key)
states = block_info.get("states", [])
state_ids = [s["id"] for s in states]
if state_ids:
block_ranges.append((min(state_ids), max(state_ids), cs_name))
block_ranges.sort(key=lambda x: x[0])
print(f"Loaded {len(block_ranges)} blocks from {blocks_json}")
max_state = max(r[1] for r in block_ranges)
print(f"State ID range: 0 - {max_state}")
known_materials = load_known_materials()
missing = [cs for _, _, cs in block_ranges if known_materials and cs not in known_materials]
if missing:
print(f"\nWARNING: {len(missing)} blocks not found in Material.cs enum:")
for cs_name in missing:
print(f" {cs_name}")
print("\nYou need to add these to Material.cs before the palette will compile.")
print("Insert them in alphabetical order within the enum.")
class_name = f"Palette{class_suffix}"
output_path = OUTPUT_DIR / f"{class_name}.cs"
lines = [
"using System.Collections.Generic;",
"",
"namespace MinecraftClient.Mapping.BlockPalettes",
"{",
f" public class {class_name} : BlockPalette",
" {",
" private static readonly Dictionary<int, Material> materials = new();",
"",
f" static {class_name}()",
" {",
]
for min_s, max_s, cs_name in block_ranges:
lines.append(f" for (int i = {min_s}; i <= {max_s}; i++)")
lines.append(f" materials[i] = Material.{cs_name};")
lines += [
" }",
"",
" protected override Dictionary<int, Material> GetDict()",
" {",
" return materials;",
" }",
" }",
"}",
"",
]
output_path.write_text("\n".join(lines))
print(f"Generated {output_path} with {len(block_ranges)} blocks ({max_state + 1} total states)")
if __name__ == "__main__":
main()