feat: add block state data to all palettes

This commit is contained in:
Anon 2026-08-11 16:44:16 +02:00
parent f1d844afbe
commit cfb77088b6
21 changed files with 57289 additions and 26 deletions

View file

@ -17,23 +17,39 @@ import json
import math
import re
import sys
from collections.abc import Sequence
from pathlib import Path
OUTPUT_DIR = (Path(__file__).resolve().parent.parent /
"MinecraftClient" / "Mapping" / "BlockPalettes")
MATERIAL_CS = OUTPUT_DIR.parent / "Material.cs"
# Minecraft renamed these registry keys after the corresponding MCC Material
# names had already stabilized. Keep historical reports mapped to the current
# enum names instead of generating references to members that do not exist.
MATERIAL_NAME_ALIASES = {
"Grass": "ShortGrass",
"GrassPath": "DirtPath",
"Sign": "OakSign",
"WallSign": "OakWallSign",
}
OUTPUT_FILE_ALIASES = {
"120": "BlockPalette120.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("_"))
csharp_name = "".join(word.capitalize() for word in name.split("_"))
return MATERIAL_NAME_ALIASES.get(csharp_name, csharp_name)
def load_known_materials() -> set[str]:
known = set()
if MATERIAL_CS.exists():
with open(MATERIAL_CS) as f:
with MATERIAL_CS.open(encoding="utf-8-sig") as f:
for line in f:
m = re.match(r'\s+(\w+),?\s*$', line)
if m:
@ -89,6 +105,74 @@ def csharp_string(value: str) -> str:
return json.dumps(value, ensure_ascii=False)
def render_state_definitions(
block_ranges: Sequence[tuple[int, int, str, list[tuple[str, list[str], int]]]],
) -> tuple[list[str], int]:
"""Render the generated state-property section and return its definition count."""
lines = [
" // <auto-generated block-state-properties>",
" private static readonly BlockStateDefinition[] stateDefinitions =",
" [",
]
property_definition_count = 0
for min_s, max_s, _, properties in block_ranges:
if not properties:
continue
property_definition_count += 1
lines.append(f" new({min_s}, {max_s - min_s + 1},")
lines.append(" [")
for index, (name, values, stride) in enumerate(properties):
encoded_values = ", ".join(csharp_string(value) for value in values)
suffix = "," if index < len(properties) - 1 else ""
lines.append(f" new({csharp_string(name)}, [{encoded_values}], {stride}){suffix}")
lines.append(" ]),")
lines += [
" ];",
" // </auto-generated block-state-properties>",
]
return lines, property_definition_count
def update_existing_palette(output_path: Path, state_lines: list[str]) -> bool:
"""Replace only generated state metadata while preserving established material mappings."""
if not output_path.exists():
return False
source = output_path.read_text(encoding="utf-8")
dictionary_method = " protected override Dictionary<int, Material> GetDict()"
dictionary_index = source.find(dictionary_method)
if dictionary_index < 0:
raise ValueError(f"{output_path} does not contain the expected GetDict method")
generated_start = source.find(" // <auto-generated block-state-properties>")
legacy_start = source.find(" private static readonly BlockStateDefinition[] stateDefinitions =")
section_start = generated_start if generated_start >= 0 else legacy_start
if section_start < 0:
section_start = dictionary_index
prefix = source[:section_start].rstrip()
suffix = source[dictionary_index:]
state_override = """ protected override BlockStateDefinition[] GetStateDefinitions()
{
return stateDefinitions;
}
"""
suffix = suffix.replace("\n" + state_override, "", 1)
class_end = suffix.rfind("\n }\n}")
if class_end < 0:
raise ValueError(f"{output_path} does not contain the expected class terminator")
suffix = suffix[:class_end].rstrip() + "\n\n" + state_override.rstrip() + suffix[class_end:]
output_path.write_text(
prefix + "\n\n" + "\n".join(state_lines) + "\n\n" + suffix,
encoding="utf-8",
)
return True
def main():
if len(sys.argv) != 3:
print(__doc__)
@ -101,7 +185,7 @@ def main():
print(f"Error: {blocks_json} not found")
sys.exit(1)
with open(blocks_json) as f:
with blocks_json.open(encoding="utf-8") as f:
data = json.load(f)
# Build block ranges and compact state-property definitions, sorted by min state.
@ -130,7 +214,15 @@ def main():
print("Insert them in alphabetical order within the enum.")
class_name = f"Palette{class_suffix}"
output_path = OUTPUT_DIR / f"{class_name}.cs"
output_path = OUTPUT_DIR / OUTPUT_FILE_ALIASES.get(class_suffix, f"{class_name}.cs")
state_lines, property_definition_count = render_state_definitions(block_ranges)
if update_existing_palette(output_path, state_lines):
print(
f"Updated {output_path} with {property_definition_count} property definitions "
"while preserving material mappings"
)
return
lines = [
"using System.Collections.Generic;",
@ -152,28 +244,10 @@ def main():
lines += [
" }",
"",
" private static readonly BlockStateDefinition[] stateDefinitions =",
" [",
]
property_definition_count = 0
for min_s, max_s, _, properties in block_ranges:
if not properties:
continue
property_definition_count += 1
lines.append(f" new({min_s}, {max_s - min_s + 1},")
lines.append(" [")
property_items = properties
for index, (name, values, stride) in enumerate(property_items):
encoded_values = ", ".join(csharp_string(value) for value in values)
suffix = "," if index < len(property_items) - 1 else ""
lines.append(f" new({csharp_string(name)}, [{encoded_values}], {stride}){suffix}")
lines.append(" ]),")
lines += [
" ];",
*state_lines,
"",
]
lines += [
" protected override Dictionary<int, Material> GetDict()",
" {",
" return materials;",
@ -188,7 +262,7 @@ def main():
"",
]
output_path.write_text("\n".join(lines))
output_path.write_text("\n".join(lines), encoding="utf-8")
print(
f"Generated {output_path} with {len(block_ranges)} blocks, "
f"{max_state + 1} total states, and {property_definition_count} property definitions"