using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; namespace MinecraftClient.Mapping.BlockPalettes { /// /// Generator for MCC Block Palette mappings /// /// /// Example for generating MaterialXXX.cs and PaletteXXX.cs from blocks.json: /// /// MinecraftClient.Mapping.BlockPalettes.BlockPaletteGenerator.JsonToClass( /// @"C:\Path\To\blocks.json", /// @"C:\Path\To\Output\PaletteXXX.cs", /// @"C:\Path\To\Output\MaterialXXX.cs" /// ); /// /// Place the above example inside the Main() method of Program.cs, adjust paths then compile and run. /// Do not forget to remove the temporay call to JsonToClass() from Main() once you are done. /// public static class BlockPaletteGenerator { /// /// Generate mapping from Minecraft blocks.json /// /// path to blocks.json /// java -cp minecraft_server.jar net.minecraft.data.Main --reports /// state => block name mappings public static void GenerateBlockPalette(string blocksJsonFile) { BlockPaletteGenerator.JsonToClass(blocksJsonFile, "Palette", "Material"); } /// /// Generate mapping from Minecraft blocks.json /// /// path to blocks.json /// output path for blocks.cs /// output path for material.cs /// java -cp minecraft_server.jar net.minecraft.data.Main --reports /// state => block name mappings public static void JsonToClass(string blocksJsonFile, string outputClass, string? outputEnum = null) { string outputPalettePath = Path.Combine(Path.GetDirectoryName(blocksJsonFile)!, outputClass + "XXX.cs"); string outputEnumPath = Path.Combine(Path.GetDirectoryName(blocksJsonFile)!, outputEnum + "XXX.cs"); HashSet knownStates = new(); Dictionary> blocks = new(); Json.JSONData palette = Json.ParseJson(File.ReadAllText(blocksJsonFile, Encoding.UTF8)); foreach (KeyValuePair item in palette.Properties) { //minecraft:item_name => ItemName string blockType = String.Concat( item.Key.Replace("minecraft:", "") .Split('_') .Select(word => char.ToUpper(word[0]) + word.Substring(1)) ); if (blocks.ContainsKey(blockType)) throw new InvalidDataException("Duplicate block type " + blockType + "!?"); blocks[blockType] = new HashSet(); foreach (Json.JSONData state in item.Value.Properties["states"].DataArray) { int id = int.Parse(state.Properties["id"].StringValue, NumberStyles.Any, CultureInfo.CurrentCulture); if (knownStates.Contains(id)) throw new InvalidDataException("Duplicate state id " + id + "!?"); knownStates.Add(id); blocks[blockType].Add(id); } } HashSet materials = new(); List outFile = new(); outFile.AddRange(new[] { "using System.Collections.Generic;", "", "namespace MinecraftClient.Mapping.BlockPalettes", "{", " public class PaletteXXX : BlockPalette", " {", " private static readonly Dictionary materials = new();", "", " static PaletteXXX()", " {", }); foreach (KeyValuePair> blockType in blocks) { if (blockType.Value.Count > 0) { List idList = blockType.Value.ToList(); string materialName = blockType.Key; materials.Add(materialName); if (idList.Count > 1) { idList.Sort(); Queue idQueue = new(idList); while (idQueue.Count > 0) { int startValue = idQueue.Dequeue(); int endValue = startValue; while (idQueue.Count > 0 && idQueue.Peek() == endValue + 1) endValue = idQueue.Dequeue(); if (endValue > startValue) { outFile.Add(" for (int i = " + startValue + "; i <= " + endValue + "; i++)"); outFile.Add(" materials[i] = Material." + materialName + ";"); } else outFile.Add(" materials[" + startValue + "] = Material." + materialName + ";"); } } else outFile.Add(" materials[" + idList[0] + "] = Material." + materialName + ";"); } else throw new InvalidDataException("No state id for block type " + blockType.Key + "!?"); } outFile.AddRange(new[] { " }", "", " protected override Dictionary GetDict()", " {", " return materials;", " }", " }", "}" }); File.WriteAllLines(outputPalettePath, outFile); if (outputEnum != null) { outFile = new List(); outFile.AddRange(new[] { "namespace MinecraftClient.Mapping", "{", " public enum Material", " {" }); foreach (string material in materials) outFile.Add(" " + material + ","); outFile.AddRange(new[] { " }", "}" }); File.WriteAllLines(outputEnumPath, outFile); } } } }