mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
feat: Refactor MapColors class to load color palette from JSON resource
This commit is contained in:
parent
76c3403700
commit
6e86edc632
3 changed files with 383 additions and 93 deletions
|
|
@ -447,109 +447,62 @@ namespace MinecraftClient.ChatBots
|
||||||
public DateTime LastUpdated { get; set; }
|
public DateTime LastUpdated { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MapColors
|
/// <summary>
|
||||||
|
/// Map packet base color palette. Colors are loaded from the embedded
|
||||||
|
/// MinimapBlockColors.json resource (map_palette section) generated by
|
||||||
|
/// tools/gen_block_color_map.py, which parses MapColor.java.
|
||||||
|
/// </summary>
|
||||||
|
internal static class MapColors
|
||||||
{
|
{
|
||||||
// When colors are updated in a new update, you can get them using the game code: net\minecraft\world\level\material\MaterialColor.java
|
private static readonly Dictionary<byte, byte[]> Colors;
|
||||||
public static Dictionary<byte, byte[]> Colors = new()
|
|
||||||
|
private static readonly byte[] ShadeMultipliers = [180, 220, 255, 135];
|
||||||
|
|
||||||
|
static MapColors()
|
||||||
{
|
{
|
||||||
//Color ID R G B
|
Colors = new Dictionary<byte, byte[]>();
|
||||||
{0, new byte[]{0, 0, 0}},
|
try
|
||||||
{1, new byte[]{127, 178, 56}},
|
{
|
||||||
{2, new byte[]{247, 233, 163}},
|
using var stream = System.Reflection.Assembly.GetExecutingAssembly()
|
||||||
{3, new byte[]{199, 199, 199}},
|
.GetManifestResourceStream("MinimapBlockColors.json");
|
||||||
{4, new byte[]{255, 0, 0}},
|
if (stream is not null)
|
||||||
{5, new byte[]{160, 160, 255}},
|
{
|
||||||
{6, new byte[]{167, 167, 167}},
|
using var doc = System.Text.Json.JsonDocument.Parse(stream);
|
||||||
{7, new byte[]{0, 124, 0}},
|
if (doc.RootElement.TryGetProperty("map_palette", out var palette))
|
||||||
{8, new byte[]{255, 255, 255}},
|
{
|
||||||
{9, new byte[]{164, 168, 184}},
|
foreach (var prop in palette.EnumerateObject())
|
||||||
{10, new byte[]{151, 109, 77}},
|
{
|
||||||
{11, new byte[]{112, 112, 112}},
|
if (!byte.TryParse(prop.Name, out byte id))
|
||||||
{12, new byte[]{64, 64, 255}},
|
continue;
|
||||||
{13, new byte[]{143, 119, 72}},
|
var arr = prop.Value;
|
||||||
{14, new byte[]{255, 252, 245}},
|
Colors[id] = [
|
||||||
{15, new byte[]{216, 127, 51}},
|
arr[0].GetByte(),
|
||||||
{16, new byte[]{178, 76, 216}},
|
arr[1].GetByte(),
|
||||||
{17, new byte[]{102, 153, 216}},
|
arr[2].GetByte()
|
||||||
{18, new byte[]{229, 229, 51}},
|
];
|
||||||
{19, new byte[]{127, 204, 25}},
|
}
|
||||||
{20, new byte[]{242, 127, 165}},
|
}
|
||||||
{21, new byte[]{76, 76, 76}},
|
}
|
||||||
{22, new byte[]{153, 153, 153}},
|
}
|
||||||
{23, new byte[]{76, 127, 153}},
|
catch (Exception ex)
|
||||||
{24, new byte[]{127, 63, 178}},
|
{
|
||||||
{25, new byte[]{51, 76, 178}},
|
ConsoleIO.WriteLogLine($"[Map] Failed to load map palette: {ex.Message}");
|
||||||
{26, new byte[]{102, 76, 51}},
|
}
|
||||||
{27, new byte[]{102, 127, 51}},
|
}
|
||||||
{28, new byte[]{153, 51, 51}},
|
|
||||||
{29, new byte[]{25, 25, 25}},
|
|
||||||
{30, new byte[]{250, 238, 77}},
|
|
||||||
{31, new byte[]{92, 219, 213}},
|
|
||||||
{32, new byte[]{74, 128, 255}},
|
|
||||||
{33, new byte[]{0, 217, 58}},
|
|
||||||
{34, new byte[]{129, 86, 49}},
|
|
||||||
{35, new byte[]{112, 2, 0}},
|
|
||||||
{36, new byte[]{209, 177, 161}},
|
|
||||||
{37, new byte[]{159, 82, 36}},
|
|
||||||
{38, new byte[]{149, 87, 108}},
|
|
||||||
{39, new byte[]{112, 108, 138}},
|
|
||||||
{40, new byte[]{186, 133, 36}},
|
|
||||||
{41, new byte[]{103, 117, 53}},
|
|
||||||
{42, new byte[]{160, 77, 78}},
|
|
||||||
{43, new byte[]{57, 41, 35}},
|
|
||||||
{44, new byte[]{135, 107, 98}},
|
|
||||||
{45, new byte[]{87, 92, 92}},
|
|
||||||
{46, new byte[]{122, 73, 88}},
|
|
||||||
{47, new byte[]{76, 62, 92}},
|
|
||||||
{48, new byte[]{76, 50, 35}},
|
|
||||||
{49, new byte[]{76, 82, 42}},
|
|
||||||
{50, new byte[]{142, 60, 46}},
|
|
||||||
{51, new byte[]{37, 22, 16}},
|
|
||||||
{52, new byte[]{189, 48, 49}},
|
|
||||||
{53, new byte[]{148, 63, 97}},
|
|
||||||
{54, new byte[]{92, 25, 29}},
|
|
||||||
{55, new byte[]{22, 126, 134}},
|
|
||||||
{56, new byte[]{58, 142, 140}},
|
|
||||||
{57, new byte[]{86, 44, 62}},
|
|
||||||
{58, new byte[]{20, 180, 133}},
|
|
||||||
{59, new byte[]{100, 100, 100}},
|
|
||||||
{60, new byte[]{216, 175, 147}},
|
|
||||||
{61, new byte[]{127, 167, 150}}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static ColorRGBA ColorByteToRGBA(byte receivedColorId)
|
public static ColorRGBA ColorByteToRGBA(byte receivedColorId)
|
||||||
{
|
{
|
||||||
// Divide received color id by 4 to get the base color id
|
|
||||||
// Much thanks to DevBobcorn
|
|
||||||
byte baseColorId = (byte)(receivedColorId >> 2);
|
byte baseColorId = (byte)(receivedColorId >> 2);
|
||||||
|
|
||||||
// Any new colors that we haven't added will be purple like in the missing CS: Source Texture
|
if (!Colors.TryGetValue(baseColorId, out byte[]? rgb))
|
||||||
if (!Colors.ContainsKey(baseColorId))
|
|
||||||
return new(248, 0, 248, 255, true);
|
return new(248, 0, 248, 255, true);
|
||||||
|
|
||||||
byte shadeId = (byte)(receivedColorId % 4);
|
byte multiplier = ShadeMultipliers[receivedColorId & 3];
|
||||||
byte shadeMultiplier = 255;
|
|
||||||
|
|
||||||
switch (shadeId)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
shadeMultiplier = 180;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
shadeMultiplier = 220;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
// NOTE: If we ever add map support below 1.8, this needs to be 220 before 1.8
|
|
||||||
shadeMultiplier = 135;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new(
|
return new(
|
||||||
r: (byte)((Colors[baseColorId][0] * shadeMultiplier) / 255),
|
r: (byte)(rgb[0] * multiplier / 255),
|
||||||
g: (byte)((Colors[baseColorId][1] * shadeMultiplier) / 255),
|
g: (byte)(rgb[1] * multiplier / 255),
|
||||||
b: (byte)((Colors[baseColorId][2] * shadeMultiplier) / 255),
|
b: (byte)(rgb[2] * multiplier / 255),
|
||||||
a: 255
|
a: 255
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3548,5 +3548,317 @@
|
||||||
"PackedIce",
|
"PackedIce",
|
||||||
"BlueIce",
|
"BlueIce",
|
||||||
"FrostedIce"
|
"FrostedIce"
|
||||||
|
],
|
||||||
|
"map_palette": {
|
||||||
|
"0": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
127,
|
||||||
|
178,
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
247,
|
||||||
|
233,
|
||||||
|
163
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
199,
|
||||||
|
199,
|
||||||
|
199
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
255,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
160,
|
||||||
|
160,
|
||||||
|
255
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
167,
|
||||||
|
167,
|
||||||
|
167
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
0,
|
||||||
|
124,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
164,
|
||||||
|
168,
|
||||||
|
184
|
||||||
|
],
|
||||||
|
"10": [
|
||||||
|
151,
|
||||||
|
109,
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"11": [
|
||||||
|
112,
|
||||||
|
112,
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"12": [
|
||||||
|
64,
|
||||||
|
64,
|
||||||
|
255
|
||||||
|
],
|
||||||
|
"13": [
|
||||||
|
143,
|
||||||
|
119,
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"14": [
|
||||||
|
255,
|
||||||
|
252,
|
||||||
|
245
|
||||||
|
],
|
||||||
|
"15": [
|
||||||
|
216,
|
||||||
|
127,
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"16": [
|
||||||
|
178,
|
||||||
|
76,
|
||||||
|
216
|
||||||
|
],
|
||||||
|
"17": [
|
||||||
|
102,
|
||||||
|
153,
|
||||||
|
216
|
||||||
|
],
|
||||||
|
"18": [
|
||||||
|
229,
|
||||||
|
229,
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"19": [
|
||||||
|
127,
|
||||||
|
204,
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"20": [
|
||||||
|
242,
|
||||||
|
127,
|
||||||
|
165
|
||||||
|
],
|
||||||
|
"21": [
|
||||||
|
76,
|
||||||
|
76,
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"22": [
|
||||||
|
153,
|
||||||
|
153,
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"23": [
|
||||||
|
76,
|
||||||
|
127,
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"24": [
|
||||||
|
127,
|
||||||
|
63,
|
||||||
|
178
|
||||||
|
],
|
||||||
|
"25": [
|
||||||
|
51,
|
||||||
|
76,
|
||||||
|
178
|
||||||
|
],
|
||||||
|
"26": [
|
||||||
|
102,
|
||||||
|
76,
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"27": [
|
||||||
|
102,
|
||||||
|
127,
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"28": [
|
||||||
|
153,
|
||||||
|
51,
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"29": [
|
||||||
|
25,
|
||||||
|
25,
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"30": [
|
||||||
|
250,
|
||||||
|
238,
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"31": [
|
||||||
|
92,
|
||||||
|
219,
|
||||||
|
213
|
||||||
|
],
|
||||||
|
"32": [
|
||||||
|
74,
|
||||||
|
128,
|
||||||
|
255
|
||||||
|
],
|
||||||
|
"33": [
|
||||||
|
0,
|
||||||
|
217,
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"34": [
|
||||||
|
129,
|
||||||
|
86,
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"35": [
|
||||||
|
112,
|
||||||
|
2,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"36": [
|
||||||
|
209,
|
||||||
|
177,
|
||||||
|
161
|
||||||
|
],
|
||||||
|
"37": [
|
||||||
|
159,
|
||||||
|
82,
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"38": [
|
||||||
|
149,
|
||||||
|
87,
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"39": [
|
||||||
|
112,
|
||||||
|
108,
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"40": [
|
||||||
|
186,
|
||||||
|
133,
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"41": [
|
||||||
|
103,
|
||||||
|
117,
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"42": [
|
||||||
|
160,
|
||||||
|
77,
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"43": [
|
||||||
|
57,
|
||||||
|
41,
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"44": [
|
||||||
|
135,
|
||||||
|
107,
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"45": [
|
||||||
|
87,
|
||||||
|
92,
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"46": [
|
||||||
|
122,
|
||||||
|
73,
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"47": [
|
||||||
|
76,
|
||||||
|
62,
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"48": [
|
||||||
|
76,
|
||||||
|
50,
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"49": [
|
||||||
|
76,
|
||||||
|
82,
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"50": [
|
||||||
|
142,
|
||||||
|
60,
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"51": [
|
||||||
|
37,
|
||||||
|
22,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"52": [
|
||||||
|
189,
|
||||||
|
48,
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"53": [
|
||||||
|
148,
|
||||||
|
63,
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"54": [
|
||||||
|
92,
|
||||||
|
25,
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"55": [
|
||||||
|
22,
|
||||||
|
126,
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"56": [
|
||||||
|
58,
|
||||||
|
142,
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"57": [
|
||||||
|
86,
|
||||||
|
44,
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"58": [
|
||||||
|
20,
|
||||||
|
180,
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"59": [
|
||||||
|
100,
|
||||||
|
100,
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"60": [
|
||||||
|
216,
|
||||||
|
175,
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"61": [
|
||||||
|
127,
|
||||||
|
167,
|
||||||
|
150
|
||||||
]
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -205,6 +205,28 @@ WATER_BLOCKS = ["Water"]
|
||||||
ICE_BLOCKS = ["Ice", "PackedIce", "BlueIce", "FrostedIce"]
|
ICE_BLOCKS = ["Ice", "PackedIce", "BlueIce", "FrostedIce"]
|
||||||
|
|
||||||
|
|
||||||
|
def build_map_palette(map_color_java: Path) -> dict[str, list[int]]:
|
||||||
|
"""Build MapColor ID -> [R, G, B] palette for the Map bot (map packet rendering).
|
||||||
|
|
||||||
|
Returns a dict keyed by string IDs ("0", "1", ...) to keep JSON simple.
|
||||||
|
"""
|
||||||
|
text = map_color_java.read_text()
|
||||||
|
palette: dict[str, list[int]] = {}
|
||||||
|
|
||||||
|
pattern = re.compile(
|
||||||
|
r'new\s+MapColor\(\s*(\d+)\s*,\s*(\d+)\s*\)')
|
||||||
|
for m in pattern.finditer(text):
|
||||||
|
cid = int(m.group(1))
|
||||||
|
raw = int(m.group(2))
|
||||||
|
r = (raw >> 16) & 0xFF
|
||||||
|
g = (raw >> 8) & 0xFF
|
||||||
|
b = raw & 0xFF
|
||||||
|
palette[str(cid)] = [r, g, b]
|
||||||
|
|
||||||
|
print(f" Built map_palette with {len(palette)} base color entries")
|
||||||
|
return dict(sorted(palette.items(), key=lambda x: int(x[0])))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print(__doc__)
|
print(__doc__)
|
||||||
|
|
@ -249,12 +271,15 @@ def main():
|
||||||
block_colors = matched
|
block_colors = matched
|
||||||
print(f" {len(block_colors)} blocks matched to Material.cs entries")
|
print(f" {len(block_colors)} blocks matched to Material.cs entries")
|
||||||
|
|
||||||
|
map_palette = build_map_palette(map_color_java)
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
"version": root.name.replace("-decompiled", "").replace("-client", ""),
|
"version": root.name.replace("-decompiled", "").replace("-client", ""),
|
||||||
"colors": {k: list(v) for k, v in sorted(block_colors.items())},
|
"colors": {k: list(v) for k, v in sorted(block_colors.items())},
|
||||||
"transparent": sorted(TRANSPARENT_BLOCKS),
|
"transparent": sorted(TRANSPARENT_BLOCKS),
|
||||||
"water": WATER_BLOCKS,
|
"water": WATER_BLOCKS,
|
||||||
"ice": ICE_BLOCKS,
|
"ice": ICE_BLOCKS,
|
||||||
|
"map_palette": map_palette,
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
|
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue