feat: Refactor MapColors class to load color palette from JSON resource

This commit is contained in:
BruceChen 2026-04-05 01:17:57 +08:00
parent 76c3403700
commit 6e86edc632
3 changed files with 383 additions and 93 deletions

View file

@ -447,109 +447,62 @@ namespace MinecraftClient.ChatBots
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
public static Dictionary<byte, byte[]> Colors = new()
private static readonly Dictionary<byte, byte[]> Colors;
private static readonly byte[] ShadeMultipliers = [180, 220, 255, 135];
static MapColors()
{
//Color ID R G B
{0, new byte[]{0, 0, 0}},
{1, new byte[]{127, 178, 56}},
{2, new byte[]{247, 233, 163}},
{3, new byte[]{199, 199, 199}},
{4, new byte[]{255, 0, 0}},
{5, new byte[]{160, 160, 255}},
{6, new byte[]{167, 167, 167}},
{7, new byte[]{0, 124, 0}},
{8, new byte[]{255, 255, 255}},
{9, new byte[]{164, 168, 184}},
{10, new byte[]{151, 109, 77}},
{11, new byte[]{112, 112, 112}},
{12, new byte[]{64, 64, 255}},
{13, new byte[]{143, 119, 72}},
{14, new byte[]{255, 252, 245}},
{15, new byte[]{216, 127, 51}},
{16, new byte[]{178, 76, 216}},
{17, new byte[]{102, 153, 216}},
{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}},
{24, new byte[]{127, 63, 178}},
{25, new byte[]{51, 76, 178}},
{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}}
};
Colors = new Dictionary<byte, byte[]>();
try
{
using var stream = System.Reflection.Assembly.GetExecutingAssembly()
.GetManifestResourceStream("MinimapBlockColors.json");
if (stream is not null)
{
using var doc = System.Text.Json.JsonDocument.Parse(stream);
if (doc.RootElement.TryGetProperty("map_palette", out var palette))
{
foreach (var prop in palette.EnumerateObject())
{
if (!byte.TryParse(prop.Name, out byte id))
continue;
var arr = prop.Value;
Colors[id] = [
arr[0].GetByte(),
arr[1].GetByte(),
arr[2].GetByte()
];
}
}
}
}
catch (Exception ex)
{
ConsoleIO.WriteLogLine($"[Map] Failed to load map palette: {ex.Message}");
}
}
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);
// Any new colors that we haven't added will be purple like in the missing CS: Source Texture
if (!Colors.ContainsKey(baseColorId))
if (!Colors.TryGetValue(baseColorId, out byte[]? rgb))
return new(248, 0, 248, 255, true);
byte shadeId = (byte)(receivedColorId % 4);
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;
}
byte multiplier = ShadeMultipliers[receivedColorId & 3];
return new(
r: (byte)((Colors[baseColorId][0] * shadeMultiplier) / 255),
g: (byte)((Colors[baseColorId][1] * shadeMultiplier) / 255),
b: (byte)((Colors[baseColorId][2] * shadeMultiplier) / 255),
r: (byte)(rgb[0] * multiplier / 255),
g: (byte)(rgb[1] * multiplier / 255),
b: (byte)(rgb[2] * multiplier / 255),
a: 255
);
}

View file

@ -3548,5 +3548,317 @@
"PackedIce",
"BlueIce",
"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
]
}
}