Map: block colours from real block textures; palette-limited PNG tiles

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DjMbLQujBHunCCu5GpsHaT
This commit is contained in:
Claude committed 2026-10-01 00:34:21 +00:00
1 parent 30b1d92437
commit ead4a706c7
7 files changed
+561 -34

No files matched your search

@@ -35,13 +35,71 @@ public final class BlockColors {
private static final int[] UNKNOWN = {STONE, DIRT, WOOD, GRAY, BROWN, LIGHT_GRAY, DEEPSLATE}; private static final int[] UNKNOWN = {STONE, DIRT, WOOD, GRAY, BROWN, LIGHT_GRAY, DEEPSLATE};
/** 0 for blocks a map looks straight through (air, glass, rails, torches). */ /** Water is special-cased by the renderer, which shades it by depth. */
public static final int WATER_COLOR = 0xFF3F76E4;
private static final Map<String, Integer> TEXTURES = loadTextures();
private static final Map<String, Integer> COLORS = new ConcurrentHashMap<>();
/**
* The colour this block shows as on the map (opaque ARGB), or 0 for blocks a map looks straight through (air, glass, rails).
* Vanilla blocks use the average colour of their real top texture; anything without one falls back to the map colour table.
*/
public static int of(String blockName) { public static int of(String blockName) {
return COLORS.computeIfAbsent(blockName, BlockColors::resolve);
}
/** The nearest vanilla map colour id for a block (0 = see-through); also what the fallback palette uses. */
public static int mapColor(String blockName) {
return CACHE.computeIfAbsent(blockName, BlockColors::classify); return CACHE.computeIfAbsent(blockName, BlockColors::classify);
} }
private static int resolve(String full) {
int id = mapColor(full);
if (id == 0) return 0;
if (id == WATER) return WATER_COLOR;
String n = plain(full);
Integer exact = TEXTURES.get(n);
if (exact != null) return exact;
String s = n;
for (boolean changed = true; changed; ) {
changed = false;
for (String p : STRIP_PREFIX) if (s.startsWith(p) && s.length() > p.length()) { s = s.substring(p.length()); changed = true; }
for (String p : STRIP_SUFFIX) if (s.endsWith(p) && s.length() > p.length()) { s = s.substring(0, s.length() - p.length()); changed = true; }
if (!changed) break;
for (String candidate : new String[]{s, s + "s", s + "_planks", s + "_block"}) {
Integer hit = TEXTURES.get(candidate);
if (hit != null) return hit;
}
}
return MapColors.base(id);
}
private static String plain(String full) {
return full.startsWith("minecraft:") ? full.substring(10) : full.substring(full.indexOf(':') + 1);
}
private static Map<String, Integer> loadTextures() {
Map<String, Integer> out = new java.util.HashMap<>();
try (java.io.InputStream in = BlockColors.class.getResourceAsStream("block_colors.csv")) {
if (in == null) return out;
for (String line : new String(in.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8).split("\n")) {
int comma = line.indexOf(',');
if (comma <= 0 || comma + 7 > line.length()) continue;
try {
out.put(line.substring(0, comma), 0xFF000000 | Integer.parseInt(line.substring(comma + 1, comma + 7).trim(), 16));
} catch (NumberFormatException ignored) {
// a malformed row just falls back to the map colour table
}
}
} catch (java.io.IOException ignored) {
// no texture table: the map colour table covers everything
}
return out;
}
private static int classify(String full) { private static int classify(String full) {
String n = full.startsWith("minecraft:") ? full.substring(10) : full.substring(full.indexOf(':') + 1); String n = plain(full);
int c = lookup(n); int c = lookup(n);
if (c >= 0) return c; if (c >= 0) return c;
// Peel shape and finish words (cut_sandstone_stairs -> sandstone) and try again. // Peel shape and finish words (cut_sandstone_stairs -> sandstone) and try again.
@@ -150,5 +208,5 @@ public final class BlockColors {
return -1; return -1;
} }
public static boolean isWater(int colour) { return colour == WATER; } public static boolean isWater(int colour) { return colour == WATER_COLOR; }
} }
@@ -82,7 +82,7 @@ public final class ChunkSampler {
if (c == 0) continue; if (c == 0) continue;
out.color[i] = c; out.color[i] = c;
out.height[i] = worldY; out.height[i] = worldY;
if (c == MapColors.WATER) out.depth[i] = waterDepth(sections, si, ly, x, z); if (c == BlockColors.WATER_COLOR) out.depth[i] = waterDepth(sections, si, ly, x, z);
return; return;
} }
} }
@@ -97,7 +97,7 @@ public final class ChunkSampler {
for (int s = si; s < sections.size(); s++) { for (int s = si; s < sections.size(); s++) {
Section sec = sections.get(s); Section sec = sections.get(s);
for (int y = s == si ? ly - 1 : 15; y >= 0; y--) { for (int y = s == si ? ly - 1 : 15; y >= 0; y--) {
if (sec.colorAt(x, y, z) != MapColors.WATER) return depth; if (sec.colorAt(x, y, z) != BlockColors.WATER_COLOR) return depth;
if (++depth >= 64) return depth; if (++depth >= 64) return depth;
} }
} }
@@ -25,6 +25,9 @@ public final class MapColors {
/** Brightness factors for the four shades: darkest .. brightest, as a map shows low, normal, high and lowest ground. */ /** Brightness factors for the four shades: darkest .. brightest, as a map shows low, normal, high and lowest ground. */
private static final int[] SHADE = {180, 220, 255, 135}; private static final int[] SHADE = {180, 220, 255, 135};
/** The colour's base RGB (opaque ARGB), or 0 for none. */
public static int base(int id) { return id <= 0 || id >= COUNT ? 0 : 0xFF000000 | RGB[id]; }
/** Opaque ARGB for a colour id at a shade (0 = low, 1 = normal, 2 = high, 3 = lowest); 0 for no colour. */ /** Opaque ARGB for a colour id at a shade (0 = low, 1 = normal, 2 = high, 3 = lowest); 0 for no colour. */
public static int argb(int id, int shade) { public static int argb(int id, int shade) {
if (id <= 0 || id >= COUNT) return 0; if (id <= 0 || id >= COUNT) return 0;
@@ -3,6 +3,9 @@ package net.scopenet.worldmap;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -18,6 +21,7 @@ public final class Png {
* that fits (a typical tile is a few KB instead of tens); anything with more than 256 colours falls back to RGBA. * that fits (a typical tile is a few KB instead of tens); anything with more than 256 colours falls back to RGBA.
*/ */
public static byte[] encode(int[] argb, int width, int height) { public static byte[] encode(int[] argb, int width, int height) {
argb = limitColors(argb);
Map<Integer, Integer> palette = new LinkedHashMap<>(); Map<Integer, Integer> palette = new LinkedHashMap<>();
for (int c : argb) { for (int c : argb) {
int key = (c >>> 24) == 0 ? 0 : c; int key = (c >>> 24) == 0 ? 0 : c;
@@ -65,6 +69,36 @@ public final class Png {
return out.toByteArray(); return out.toByteArray();
} }
/**
* Keeps a tile within 256 colours: when it has more, the rarest colours are snapped to the nearest common one. Tiles
* rarely get there (blocks have few colours and shading adds only a handful of steps), and the change is hard to see.
*/
static int[] limitColors(int[] argb) {
Map<Integer, Integer> counts = new HashMap<>();
for (int c : argb) if ((c >>> 24) != 0) counts.merge(c, 1, Integer::sum);
if (counts.size() <= 255) return argb;
List<Integer> keep = new ArrayList<>(counts.keySet());
keep.sort((a, b) -> counts.get(b) - counts.get(a));
List<Integer> top = new ArrayList<>(keep.subList(0, 255));
Set<Integer> kept = new HashSet<>(top);
Map<Integer, Integer> remap = new HashMap<>();
int[] out = argb.clone();
for (int i = 0; i < out.length; i++) {
int c = out[i];
if ((c >>> 24) == 0 || kept.contains(c)) continue;
out[i] = remap.computeIfAbsent(c, k -> {
int best = top.get(0), bestD = Integer.MAX_VALUE;
for (int q : top) {
int dr = (k >> 16 & 0xFF) - (q >> 16 & 0xFF), dg = (k >> 8 & 0xFF) - (q >> 8 & 0xFF), db = (k & 0xFF) - (q & 0xFF);
int d = dr * dr * 2 + dg * dg * 4 + db * db * 3;
if (d < bestD) { bestD = d; best = q; }
}
return best;
});
}
return out;
}
private static final byte[] SIGNATURE = {(byte) 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n'}; private static final byte[] SIGNATURE = {(byte) 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n'};
private static byte[] deflate(byte[] raw) { private static byte[] deflate(byte[] raw) {
@@ -47,7 +47,10 @@ public final class RegionRenderer {
return tiles; return tiles;
} }
/** Shading as a vanilla map does it: slope against the block to the north, depth for water, plus a light dither. */ /**
* Shading: ground is lit by its slope against the block to the north (a gentle relief effect), water darkens with depth.
* Colours are the blocks' own, so they stay in few steps and compress well.
*/
static int[] shade(int[] colors, int[] heights, int[] depths) { static int[] shade(int[] colors, int[] heights, int[] depths) {
int[] out = new int[SIDE * SIDE]; int[] out = new int[SIDE * SIDE];
for (int z = 0; z < SIDE; z++) { for (int z = 0; z < SIDE; z++) {
@@ -55,18 +58,23 @@ public final class RegionRenderer {
int i = z * SIDE + x; int i = z * SIDE + x;
int c = colors[i]; int c = colors[i];
if (c == 0) continue; if (c == 0) continue;
int shade; int percent;
if (c == MapColors.WATER) { if (c == BlockColors.WATER_COLOR) {
double d = depths[i] * 0.1 + ((x + z) & 1) * 0.2; percent = 108 - Math.min(depths[i], 14) * 4;
shade = d < 0.5 ? 2 : d > 0.9 ? 0 : 1;
} else { } else {
int north = z > 0 && colors[i - SIDE] != 0 ? heights[i - SIDE] : heights[i]; int north = z > 0 && colors[i - SIDE] != 0 ? heights[i - SIDE] : heights[i];
double d = (heights[i] - north) * 4.0 / 5.0 + (((x + z) & 1) - 0.5) * 0.4; int diff = heights[i] - north;
shade = d > 0.6 ? 2 : d < -0.6 ? 0 : 1; percent = diff >= 2 ? 120 : diff == 1 ? 109 : diff == 0 ? 100 : diff == -1 ? 90 : 80;
} }
out[i] = MapColors.argb(c, shade); out[i] = scale(c, percent);
} }
} }
return out; return out;
} }
static int scale(int argb, int percent) {
int r = Math.min(255, (argb >> 16 & 0xFF) * percent / 100), g = Math.min(255, (argb >> 8 & 0xFF) * percent / 100),
b = Math.min(255, (argb & 0xFF) * percent / 100);
return 0xFF000000 | r << 16 | g << 8 | b;
}
} }
@@ -0,0 +1,418 @@
stone,989898
granite,B6775E
polished_granite,BC7A63
diorite,E5E5E5
polished_diorite,EAEBED
andesite,A6A6A6
polished_andesite,A1A3A2
grass_block,618149
dirt,A37048
coarse_dirt,91633F
podzol,6F4913
cobblestone,9B9B9B
oak_planks,C69A53
spruce_planks,8B6231
birch_planks,EAD389
jungle_planks,C38656
acacia_planks,CD622C
cherry_planks,FFC2BB
dark_oak_planks,513112
mangrove_planks,8F3930
bamboo_planks,EBD051
bamboo_mosaic,E8CC4F
bedrock,686868
sand,FFEFB6
red_sand,E87011
gravel,A09A99
gold_ore,B1A17C
deepslate_gold_ore,8C7B5A
iron_ore,A69C93
deepslate_iron_ore,817871
coal_ore,808080
deepslate_coal_ore,5A5A5D
nether_gold_ore,8C3929
oak_log,B88F4E
spruce_log,845E2F
birch_log,EBD89C
jungle_log,B67F4A
acacia_log,B76235
cherry_log,E2A6A0
dark_oak_log,523414
mangrove_log,7C332A
mangrove_roots,5A4629
muddy_mangrove_roots,554533
bamboo_block,A9AC40
stripped_spruce_log,805E2F
stripped_birch_log,E9CE83
stripped_jungle_log,C98F57
stripped_acacia_log,CB642D
stripped_cherry_log,FFB5AC
stripped_dark_oak_log,4F3315
stripped_oak_log,C39952
stripped_mangrove_log,852B2B
stripped_bamboo_block,D9BE48
oak_leaves,4D7515
spruce_leaves,355C35
jungle_leaves,557E14
cherry_leaves,FFB8D3
dark_oak_leaves,517B16
mangrove_leaves,456913
azalea_leaves,6A8B2B
flowering_azalea_leaves,778742
sponge,EEEA49
wet_sponge,CFDD45
lapis_ore,7E8BAC
deepslate_lapis_ore,5B6A8C
lapis_block,1447AB
dispenser,959393
sandstone,FFF3BB
chiseled_sandstone,FFECAE
cut_sandstone,FFF1B3
note_block,6B422A
powered_rail,A78151
detector_rail,967C69
piston,BB975E
white_wool,FBFFFF
orange_wool,FF7200
magenta_wool,E741D9
light_blue_wool,2EC8FF
yellow_wool,FFC40E
lime_wool,7EE207
pink_wool,FF8BB1
gray_wool,4A5357
light_gray_wool,ADADA2
cyan_wool,07A6B1
purple_wool,8C20D2
blue_wool,3137C0
brown_wool,8B5026
green_wool,638515
red_wool,C31E17
black_wool,18191E
gold_block,FFD328
iron_block,FFFFFF
bricks,B76F5B
tnt,AD4034
bookshelf,8F6F3F
chiseled_bookshelf,D9AB5E
mossy_cobblestone,85906F
obsidian,110A1D
spawner,28364C
diamond_ore,91ACAB
deepslate_diamond_ore,628181
diamond_block,57FFF4
crafting_table,915228
farmland,AE764B
furnace,868585
oak_door,AB8246
iron_door,EDEBEB
redstone_ore,AB8080
deepslate_redstone_ore,7F5556
snow,F9FFFF
ice,85B0FF
cactus,629B28
clay,C0C9DA
jukebox,714A33
netherrack,762626
soul_sand,634938
soul_soil,5C4334
basalt,616269
polished_basalt,79777A
glowstone,D19A5A
nether_portal,6400EA
carved_pumpkin,B75D01
jack_o_lantern,FFAC27
cake,FFE1D8
repeater,C3BFBE
oak_trapdoor,97753A
spruce_trapdoor,7E5D31
birch_trapdoor,FDEBB8
jungle_trapdoor,B98053
acacia_trapdoor,BE602F
cherry_trapdoor,FFC2BB
dark_oak_trapdoor,5C3814
mangrove_trapdoor,862F29
bamboo_trapdoor,F2D857
stone_bricks,959395
mossy_stone_bricks,8B947E
cracked_stone_bricks,908F90
chiseled_stone_bricks,919091
packed_mud,AD7C57
mud_bricks,A77958
brown_mushroom_block,B68259
red_mushroom_block,F42220
mushroom_stem,F8EEDF
pumpkin,F28404
melon,83B014
mycelium,87767A
nether_bricks,36161D
enchanting_table,9C5461
cauldron,59585A
end_portal_frame,6B9273
end_stone,FBFFAD
dragon_egg,0E0A12
redstone_lamp,743C1B
emerald_ore,80A689
deepslate_emerald_ore,5B7F68
emerald_block,1CF859
command_block,D89C78
beacon,79FFF9
anvil,585858
chipped_anvil,585858
damaged_anvil,585858
comparator,CBC4C1
daylight_detector,9F8B6D
redstone_block,D61800
nether_quartz_ore,8F4844
hopper,5C5A5C
quartz_block,FFF8EF
chiseled_quartz_block,FFF9EE
quartz_pillar,FFF8EF
activator_rail,8C6654
dropper,959393
white_terracotta,FFD5BD
orange_terracotta,C45A1B
magenta_terracotta,B6627E
light_blue_terracotta,8680A7
yellow_terracotta,E39B15
lime_terracotta,7C8F36
pink_terracotta,C45353
gray_terracotta,463127
light_gray_terracotta,A57D71
cyan_terracotta,686F6F
purple_terracotta,904E64
blue_terracotta,58436F
brown_terracotta,5E3A25
green_terracotta,5C652D
red_terracotta,AE3E2A
black_terracotta,2D1910
slime_block,7CEA60
iron_trapdoor,F6F6F6
prismarine,6EC6AE
prismarine_bricks,6ED1BF
dark_prismarine,386F59
sea_lantern,CEF4E6
hay_block,C9A700
terracotta,B96A45
coal_block,141212
packed_ice,82AFFF
red_sandstone,DD6A10
chiseled_red_sandstone,DF680A
cut_red_sandstone,E76E0F
smooth_stone_slab,CCCCCC
smooth_stone,C1C1C1
bamboo_fence_gate,FBDF57
bamboo_fence,FBE05B
spruce_door,815E32
birch_door,FFF1C6
jungle_door,C78B5B
acacia_door,CC693A
cherry_door,FFBBB3
dark_oak_door,5D3B17
mangrove_door,89312E
bamboo_door,E9CE53
chorus_plant,714071
chorus_flower,B88EB8
purpur_block,CE92CE
purpur_pillar,D196D1
end_stone_bricks,F7FFB0
dirt_path,B59043
repeating_command_block,967DCF
chain_command_block,9BC4B1
nether_wart_block,8B0000
red_nether_bricks,540003
bone_block,FFFBD6
observer,787878
shulker_box,AA6FAA
white_shulker_box,F7FEFF
orange_shulker_box,FF6F00
magenta_shulker_box,D330C5
light_blue_shulker_box,23BDFF
yellow_shulker_box,FFBA03
lime_shulker_box,6ED206
pink_shulker_box,FF78A4
gray_shulker_box,42464C
light_gray_shulker_box,97978B
cyan_shulker_box,0892A5
purple_shulker_box,7615BE
blue_shulker_box,2629AB
brown_shulker_box,814B20
green_shulker_box,5D7A1C
red_shulker_box,AB1614
black_shulker_box,1E1E23
white_glazed_terracotta,DFFFF2
orange_glazed_terracotta,BCB266
magenta_glazed_terracotta,FE6AE7
light_blue_glazed_terracotta,62C2FE
yellow_glazed_terracotta,FFCC4D
lime_glazed_terracotta,C1F02E
pink_glazed_terracotta,FF9DBD
gray_glazed_terracotta,646D71
light_gray_glazed_terracotta,ACCACC
cyan_glazed_terracotta,358F98
purple_glazed_terracotta,7F2AB9
blue_glazed_terracotta,2C43AA
brown_glazed_terracotta,917F63
green_glazed_terracotta,8BAD47
red_glazed_terracotta,DD362E
black_glazed_terracotta,521F22
white_concrete,F6FEFF
orange_concrete,FF6E00
magenta_concrete,CE29C1
light_blue_concrete,139EF2
yellow_concrete,FFB300
lime_concrete,68CD08
pink_concrete,FF69A0
gray_concrete,41454A
light_gray_concrete,98988B
cyan_concrete,098FA6
purple_concrete,7214BE
blue_concrete,272AAE
brown_concrete,75431C
green_concrete,566F24
red_concrete,AD1717
black_concrete,090B12
white_concrete_powder,FCFFFF
orange_concrete_powder,FF8608
magenta_concrete_powder,EA55DF
light_blue_concrete_powder,45D3FF
yellow_concrete_powder,FFD624
lime_concrete_powder,8FE71C
pink_concrete_powder,FFA1C4
gray_concrete_powder,5C6266
light_gray_concrete_powder,BCBCB4
cyan_concrete_powder,1AB2C0
purple_concrete_powder,9931D8
blue_concrete_powder,474BCB
brown_concrete_powder,986036
green_concrete_powder,73912B
red_concrete_powder,CD312C
black_concrete_powder,1E1F26
dead_tube_coral_block,9F9590
dead_brain_coral_block,978E8A
dead_bubble_coral_block,A0958F
dead_fire_coral_block,A0958F
dead_horn_coral_block,A29993
tube_coral_block,2559FB
brain_coral_block,FD5EBB
bubble_coral_block,C90BC5
fire_coral_block,C71827
horn_coral_block,FFE939
sea_pickle,6D7627
blue_ice,649EFF
bamboo,EBD051
scaffolding,CF9A4B
loom,AD8E68
barrel,A3753C
smoker,686562
blast_furnace,616163
cartography_table,7E684C
fletching_table,F0D999
lectern,D3A258
smithing_table,444555
stonecutter,968F86
warped_stem,388586
stripped_warped_stem,349C97
warped_nylium,2A8B79
warped_wart_block,0C9194
crimson_stem,89334F
stripped_crimson_stem,943B5E
crimson_nylium,9F1717
shroomlight,FF8F35
crimson_planks,7B3351
warped_planks,2C7F78
crimson_trapdoor,7E3553
warped_trapdoor,2F9186
crimson_door,8B395B
warped_door,2A9A92
structure_block,6B586E
jigsaw,615263
target,FFB8A8
bee_nest,F6BD48
beehive,C0954F
honey_block,FFB41D
honeycomb_block,FF9A06
netherite_block,514A4C
ancient_debris,734C41
crying_obsidian,230549
respawn_anchor,520BB6
lodestone,B3B5B9
blackstone,332B32
polished_blackstone,403944
polished_blackstone_bricks,3A323C
cracked_polished_blackstone_bricks,362C34
chiseled_polished_blackstone,403944
gilded_blackstone,43312C
chiseled_nether_bricks,39191F
cracked_nether_bricks,31151A
quartz_bricks,FFF9EF
amethyst_block,9A69E9
budding_amethyst,9968E3
tuff,84857B
polished_tuff,757F78
chiseled_tuff,71786E
tuff_bricks,777C73
chiseled_tuff_bricks,868A80
calcite,FEFFFA
powder_snow,F9FFFF
sculk_sensor,005466
calibrated_sculk_sensor,165D7A
sculk,0D2028
sculk_vein,013A47
sculk_catalyst,0F252E
copper_block,EA7650
exposed_copper,C49375
weathered_copper,7DBB80
oxidized_copper,58C69D
copper_ore,979892
deepslate_copper_ore,70716C
oxidized_cut_copper,56BB96
weathered_cut_copper,80B17D
exposed_cut_copper,BC8F73
cut_copper,E97551
oxidized_chiseled_copper,5AC49D
weathered_chiseled_copper,78B782
exposed_chiseled_copper,BC8C72
chiseled_copper,E06E49
copper_door,EA7954
exposed_copper_door,C89079
oxidized_copper_door,59C39D
weathered_copper_door,80B77F
copper_trapdoor,E87550
exposed_copper_trapdoor,C49377
oxidized_copper_trapdoor,5AC49D
weathered_copper_trapdoor,7DBB80
copper_grate,E97650
exposed_copper_grate,C49377
weathered_copper_grate,7BB980
oxidized_copper_grate,58C49B
copper_bulb,BE5F37
exposed_copper_bulb,A57E66
weathered_copper_bulb,6B9A75
oxidized_copper_bulb,4CA182
dripstone_block,A37F6A
azalea,78972E
flowering_azalea,879446
moss_block,6A852E
big_dripleaf,83AC31
rooted_dirt,B07853
mud,494549
deepslate,6A6A6D
cobbled_deepslate,5E5E62
polished_deepslate,585859
deepslate_tiles,424243
deepslate_bricks,555557
chiseled_deepslate,424242
cracked_deepslate_bricks,4E4E4F
cracked_deepslate_tiles,3F3F3F
smooth_basalt,57575F
raw_iron_block,CBA07A
raw_copper_block,BC7955
raw_gold_block,FFBC1D
ochre_froglight,FFF9CD
verdant_froglight,EDFFEC
pearlescent_froglight,FFF9F8
reinforced_deepslate,61645F
crafter,897677
trial_spawner,2D455D
vault,3E5360
heavy_core,626873
1 stone 989898
2 granite B6775E
3 polished_granite BC7A63
4 diorite E5E5E5
5 polished_diorite EAEBED
6 andesite A6A6A6
7 polished_andesite A1A3A2
8 grass_block 618149
9 dirt A37048
10 coarse_dirt 91633F
11 podzol 6F4913
12 cobblestone 9B9B9B
13 oak_planks C69A53
14 spruce_planks 8B6231
15 birch_planks EAD389
16 jungle_planks C38656
17 acacia_planks CD622C
18 cherry_planks FFC2BB
19 dark_oak_planks 513112
20 mangrove_planks 8F3930
21 bamboo_planks EBD051
22 bamboo_mosaic E8CC4F
23 bedrock 686868
24 sand FFEFB6
25 red_sand E87011
26 gravel A09A99
27 gold_ore B1A17C
28 deepslate_gold_ore 8C7B5A
29 iron_ore A69C93
30 deepslate_iron_ore 817871
31 coal_ore 808080
32 deepslate_coal_ore 5A5A5D
33 nether_gold_ore 8C3929
34 oak_log B88F4E
35 spruce_log 845E2F
36 birch_log EBD89C
37 jungle_log B67F4A
38 acacia_log B76235
39 cherry_log E2A6A0
40 dark_oak_log 523414
41 mangrove_log 7C332A
42 mangrove_roots 5A4629
43 muddy_mangrove_roots 554533
44 bamboo_block A9AC40
45 stripped_spruce_log 805E2F
46 stripped_birch_log E9CE83
47 stripped_jungle_log C98F57
48 stripped_acacia_log CB642D
49 stripped_cherry_log FFB5AC
50 stripped_dark_oak_log 4F3315
51 stripped_oak_log C39952
52 stripped_mangrove_log 852B2B
53 stripped_bamboo_block D9BE48
54 oak_leaves 4D7515
55 spruce_leaves 355C35
56 jungle_leaves 557E14
57 cherry_leaves FFB8D3
58 dark_oak_leaves 517B16
59 mangrove_leaves 456913
60 azalea_leaves 6A8B2B
61 flowering_azalea_leaves 778742
62 sponge EEEA49
63 wet_sponge CFDD45
64 lapis_ore 7E8BAC
65 deepslate_lapis_ore 5B6A8C
66 lapis_block 1447AB
67 dispenser 959393
68 sandstone FFF3BB
69 chiseled_sandstone FFECAE
70 cut_sandstone FFF1B3
71 note_block 6B422A
72 powered_rail A78151
73 detector_rail 967C69
74 piston BB975E
75 white_wool FBFFFF
76 orange_wool FF7200
77 magenta_wool E741D9
78 light_blue_wool 2EC8FF
79 yellow_wool FFC40E
80 lime_wool 7EE207
81 pink_wool FF8BB1
82 gray_wool 4A5357
83 light_gray_wool ADADA2
84 cyan_wool 07A6B1
85 purple_wool 8C20D2
86 blue_wool 3137C0
87 brown_wool 8B5026
88 green_wool 638515
89 red_wool C31E17
90 black_wool 18191E
91 gold_block FFD328
92 iron_block FFFFFF
93 bricks B76F5B
94 tnt AD4034
95 bookshelf 8F6F3F
96 chiseled_bookshelf D9AB5E
97 mossy_cobblestone 85906F
98 obsidian 110A1D
99 spawner 28364C
100 diamond_ore 91ACAB
101 deepslate_diamond_ore 628181
102 diamond_block 57FFF4
103 crafting_table 915228
104 farmland AE764B
105 furnace 868585
106 oak_door AB8246
107 iron_door EDEBEB
108 redstone_ore AB8080
109 deepslate_redstone_ore 7F5556
110 snow F9FFFF
111 ice 85B0FF
112 cactus 629B28
113 clay C0C9DA
114 jukebox 714A33
115 netherrack 762626
116 soul_sand 634938
117 soul_soil 5C4334
118 basalt 616269
119 polished_basalt 79777A
120 glowstone D19A5A
121 nether_portal 6400EA
122 carved_pumpkin B75D01
123 jack_o_lantern FFAC27
124 cake FFE1D8
125 repeater C3BFBE
126 oak_trapdoor 97753A
127 spruce_trapdoor 7E5D31
128 birch_trapdoor FDEBB8
129 jungle_trapdoor B98053
130 acacia_trapdoor BE602F
131 cherry_trapdoor FFC2BB
132 dark_oak_trapdoor 5C3814
133 mangrove_trapdoor 862F29
134 bamboo_trapdoor F2D857
135 stone_bricks 959395
136 mossy_stone_bricks 8B947E
137 cracked_stone_bricks 908F90
138 chiseled_stone_bricks 919091
139 packed_mud AD7C57
140 mud_bricks A77958
141 brown_mushroom_block B68259
142 red_mushroom_block F42220
143 mushroom_stem F8EEDF
144 pumpkin F28404
145 melon 83B014
146 mycelium 87767A
147 nether_bricks 36161D
148 enchanting_table 9C5461
149 cauldron 59585A
150 end_portal_frame 6B9273
151 end_stone FBFFAD
152 dragon_egg 0E0A12
153 redstone_lamp 743C1B
154 emerald_ore 80A689
155 deepslate_emerald_ore 5B7F68
156 emerald_block 1CF859
157 command_block D89C78
158 beacon 79FFF9
159 anvil 585858
160 chipped_anvil 585858
161 damaged_anvil 585858
162 comparator CBC4C1
163 daylight_detector 9F8B6D
164 redstone_block D61800
165 nether_quartz_ore 8F4844
166 hopper 5C5A5C
167 quartz_block FFF8EF
168 chiseled_quartz_block FFF9EE
169 quartz_pillar FFF8EF
170 activator_rail 8C6654
171 dropper 959393
172 white_terracotta FFD5BD
173 orange_terracotta C45A1B
174 magenta_terracotta B6627E
175 light_blue_terracotta 8680A7
176 yellow_terracotta E39B15
177 lime_terracotta 7C8F36
178 pink_terracotta C45353
179 gray_terracotta 463127
180 light_gray_terracotta A57D71
181 cyan_terracotta 686F6F
182 purple_terracotta 904E64
183 blue_terracotta 58436F
184 brown_terracotta 5E3A25
185 green_terracotta 5C652D
186 red_terracotta AE3E2A
187 black_terracotta 2D1910
188 slime_block 7CEA60
189 iron_trapdoor F6F6F6
190 prismarine 6EC6AE
191 prismarine_bricks 6ED1BF
192 dark_prismarine 386F59
193 sea_lantern CEF4E6
194 hay_block C9A700
195 terracotta B96A45
196 coal_block 141212
197 packed_ice 82AFFF
198 red_sandstone DD6A10
199 chiseled_red_sandstone DF680A
200 cut_red_sandstone E76E0F
201 smooth_stone_slab CCCCCC
202 smooth_stone C1C1C1
203 bamboo_fence_gate FBDF57
204 bamboo_fence FBE05B
205 spruce_door 815E32
206 birch_door FFF1C6
207 jungle_door C78B5B
208 acacia_door CC693A
209 cherry_door FFBBB3
210 dark_oak_door 5D3B17
211 mangrove_door 89312E
212 bamboo_door E9CE53
213 chorus_plant 714071
214 chorus_flower B88EB8
215 purpur_block CE92CE
216 purpur_pillar D196D1
217 end_stone_bricks F7FFB0
218 dirt_path B59043
219 repeating_command_block 967DCF
220 chain_command_block 9BC4B1
221 nether_wart_block 8B0000
222 red_nether_bricks 540003
223 bone_block FFFBD6
224 observer 787878
225 shulker_box AA6FAA
226 white_shulker_box F7FEFF
227 orange_shulker_box FF6F00
228 magenta_shulker_box D330C5
229 light_blue_shulker_box 23BDFF
230 yellow_shulker_box FFBA03
231 lime_shulker_box 6ED206
232 pink_shulker_box FF78A4
233 gray_shulker_box 42464C
234 light_gray_shulker_box 97978B
235 cyan_shulker_box 0892A5
236 purple_shulker_box 7615BE
237 blue_shulker_box 2629AB
238 brown_shulker_box 814B20
239 green_shulker_box 5D7A1C
240 red_shulker_box AB1614
241 black_shulker_box 1E1E23
242 white_glazed_terracotta DFFFF2
243 orange_glazed_terracotta BCB266
244 magenta_glazed_terracotta FE6AE7
245 light_blue_glazed_terracotta 62C2FE
246 yellow_glazed_terracotta FFCC4D
247 lime_glazed_terracotta C1F02E
248 pink_glazed_terracotta FF9DBD
249 gray_glazed_terracotta 646D71
250 light_gray_glazed_terracotta ACCACC
251 cyan_glazed_terracotta 358F98
252 purple_glazed_terracotta 7F2AB9
253 blue_glazed_terracotta 2C43AA
254 brown_glazed_terracotta 917F63
255 green_glazed_terracotta 8BAD47
256 red_glazed_terracotta DD362E
257 black_glazed_terracotta 521F22
258 white_concrete F6FEFF
259 orange_concrete FF6E00
260 magenta_concrete CE29C1
261 light_blue_concrete 139EF2
262 yellow_concrete FFB300
263 lime_concrete 68CD08
264 pink_concrete FF69A0
265 gray_concrete 41454A
266 light_gray_concrete 98988B
267 cyan_concrete 098FA6
268 purple_concrete 7214BE
269 blue_concrete 272AAE
270 brown_concrete 75431C
271 green_concrete 566F24
272 red_concrete AD1717
273 black_concrete 090B12
274 white_concrete_powder FCFFFF
275 orange_concrete_powder FF8608
276 magenta_concrete_powder EA55DF
277 light_blue_concrete_powder 45D3FF
278 yellow_concrete_powder FFD624
279 lime_concrete_powder 8FE71C
280 pink_concrete_powder FFA1C4
281 gray_concrete_powder 5C6266
282 light_gray_concrete_powder BCBCB4
283 cyan_concrete_powder 1AB2C0
284 purple_concrete_powder 9931D8
285 blue_concrete_powder 474BCB
286 brown_concrete_powder 986036
287 green_concrete_powder 73912B
288 red_concrete_powder CD312C
289 black_concrete_powder 1E1F26
290 dead_tube_coral_block 9F9590
291 dead_brain_coral_block 978E8A
292 dead_bubble_coral_block A0958F
293 dead_fire_coral_block A0958F
294 dead_horn_coral_block A29993
295 tube_coral_block 2559FB
296 brain_coral_block FD5EBB
297 bubble_coral_block C90BC5
298 fire_coral_block C71827
299 horn_coral_block FFE939
300 sea_pickle 6D7627
301 blue_ice 649EFF
302 bamboo EBD051
303 scaffolding CF9A4B
304 loom AD8E68
305 barrel A3753C
306 smoker 686562
307 blast_furnace 616163
308 cartography_table 7E684C
309 fletching_table F0D999
310 lectern D3A258
311 smithing_table 444555
312 stonecutter 968F86
313 warped_stem 388586
314 stripped_warped_stem 349C97
315 warped_nylium 2A8B79
316 warped_wart_block 0C9194
317 crimson_stem 89334F
318 stripped_crimson_stem 943B5E
319 crimson_nylium 9F1717
320 shroomlight FF8F35
321 crimson_planks 7B3351
322 warped_planks 2C7F78
323 crimson_trapdoor 7E3553
324 warped_trapdoor 2F9186
325 crimson_door 8B395B
326 warped_door 2A9A92
327 structure_block 6B586E
328 jigsaw 615263
329 target FFB8A8
330 bee_nest F6BD48
331 beehive C0954F
332 honey_block FFB41D
333 honeycomb_block FF9A06
334 netherite_block 514A4C
335 ancient_debris 734C41
336 crying_obsidian 230549
337 respawn_anchor 520BB6
338 lodestone B3B5B9
339 blackstone 332B32
340 polished_blackstone 403944
341 polished_blackstone_bricks 3A323C
342 cracked_polished_blackstone_bricks 362C34
343 chiseled_polished_blackstone 403944
344 gilded_blackstone 43312C
345 chiseled_nether_bricks 39191F
346 cracked_nether_bricks 31151A
347 quartz_bricks FFF9EF
348 amethyst_block 9A69E9
349 budding_amethyst 9968E3
350 tuff 84857B
351 polished_tuff 757F78
352 chiseled_tuff 71786E
353 tuff_bricks 777C73
354 chiseled_tuff_bricks 868A80
355 calcite FEFFFA
356 powder_snow F9FFFF
357 sculk_sensor 005466
358 calibrated_sculk_sensor 165D7A
359 sculk 0D2028
360 sculk_vein 013A47
361 sculk_catalyst 0F252E
362 copper_block EA7650
363 exposed_copper C49375
364 weathered_copper 7DBB80
365 oxidized_copper 58C69D
366 copper_ore 979892
367 deepslate_copper_ore 70716C
368 oxidized_cut_copper 56BB96
369 weathered_cut_copper 80B17D
370 exposed_cut_copper BC8F73
371 cut_copper E97551
372 oxidized_chiseled_copper 5AC49D
373 weathered_chiseled_copper 78B782
374 exposed_chiseled_copper BC8C72
375 chiseled_copper E06E49
376 copper_door EA7954
377 exposed_copper_door C89079
378 oxidized_copper_door 59C39D
379 weathered_copper_door 80B77F
380 copper_trapdoor E87550
381 exposed_copper_trapdoor C49377
382 oxidized_copper_trapdoor 5AC49D
383 weathered_copper_trapdoor 7DBB80
384 copper_grate E97650
385 exposed_copper_grate C49377
386 weathered_copper_grate 7BB980
387 oxidized_copper_grate 58C49B
388 copper_bulb BE5F37
389 exposed_copper_bulb A57E66
390 weathered_copper_bulb 6B9A75
391 oxidized_copper_bulb 4CA182
392 dripstone_block A37F6A
393 azalea 78972E
394 flowering_azalea 879446
395 moss_block 6A852E
396 big_dripleaf 83AC31
397 rooted_dirt B07853
398 mud 494549
399 deepslate 6A6A6D
400 cobbled_deepslate 5E5E62
401 polished_deepslate 585859
402 deepslate_tiles 424243
403 deepslate_bricks 555557
404 chiseled_deepslate 424242
405 cracked_deepslate_bricks 4E4E4F
406 cracked_deepslate_tiles 3F3F3F
407 smooth_basalt 57575F
408 raw_iron_block CBA07A
409 raw_copper_block BC7955
410 raw_gold_block FFBC1D
411 ochre_froglight FFF9CD
412 verdant_froglight EDFFEC
413 pearlescent_froglight FFF9F8
414 reinforced_deepslate 61645F
415 crafter 897677
416 trial_spawner 2D455D
417 vault 3E5360
418 heavy_core 626873
@@ -86,23 +86,29 @@ class MapRenderTest {
} }
@Test void blockNamesBecomeMapColours() { @Test void blockNamesBecomeMapColours() {
assertEquals(MapColors.NONE, BlockColors.of("minecraft:air")); assertEquals(MapColors.NONE, BlockColors.mapColor("minecraft:air"));
assertEquals(MapColors.NONE, BlockColors.of("minecraft:glass")); assertEquals(MapColors.NONE, BlockColors.mapColor("minecraft:glass"));
assertEquals(MapColors.GRASS, BlockColors.of("minecraft:grass_block")); assertEquals(MapColors.GRASS, BlockColors.mapColor("minecraft:grass_block"));
assertEquals(MapColors.WATER, BlockColors.of("minecraft:water")); assertEquals(MapColors.WATER, BlockColors.mapColor("minecraft:water"));
assertEquals(MapColors.STONE, BlockColors.of("minecraft:stone")); assertEquals(MapColors.STONE, BlockColors.mapColor("minecraft:stone"));
assertEquals(MapColors.STONE, BlockColors.of("minecraft:mossy_cobblestone_stairs")); assertEquals(MapColors.STONE, BlockColors.mapColor("minecraft:mossy_cobblestone_stairs"));
assertEquals(MapColors.WOOD, BlockColors.of("minecraft:oak_planks")); assertEquals(MapColors.WOOD, BlockColors.mapColor("minecraft:oak_planks"));
assertEquals(MapColors.WOOD, BlockColors.of("minecraft:oak_stairs")); assertEquals(MapColors.WOOD, BlockColors.mapColor("minecraft:oak_stairs"));
assertEquals(MapColors.PLANT, BlockColors.of("minecraft:oak_leaves")); assertEquals(MapColors.PLANT, BlockColors.mapColor("minecraft:oak_leaves"));
assertEquals(MapColors.SAND, BlockColors.of("minecraft:cut_sandstone_slab")); assertEquals(MapColors.SAND, BlockColors.mapColor("minecraft:cut_sandstone_slab"));
assertEquals(MapColors.NETHER, BlockColors.of("minecraft:netherrack")); assertEquals(MapColors.NETHER, BlockColors.mapColor("minecraft:netherrack"));
assertEquals(MapColors.RED, BlockColors.of("minecraft:red_wool") == MapColors.RED ? MapColors.RED : -1); assertEquals(MapColors.RED, BlockColors.mapColor("minecraft:red_wool") == MapColors.RED ? MapColors.RED : -1);
assertEquals(MapColors.LIGHT_BLUE, BlockColors.of("minecraft:light_blue_concrete")); assertEquals(MapColors.LIGHT_BLUE, BlockColors.mapColor("minecraft:light_blue_concrete"));
assertEquals(MapColors.DEEPSLATE, BlockColors.of("minecraft:deepslate_iron_ore")); assertEquals(MapColors.DEEPSLATE, BlockColors.mapColor("minecraft:deepslate_iron_ore"));
assertEquals(MapColors.FIRE, BlockColors.of("minecraft:lava")); assertEquals(MapColors.FIRE, BlockColors.mapColor("minecraft:lava"));
int modded = BlockColors.of("create:brass_casing"); assertEquals(0, BlockColors.of("minecraft:air"));
assertEquals(modded, BlockColors.of("create:brass_casing"), "stable for unknown blocks"); assertEquals(BlockColors.WATER_COLOR, BlockColors.of("minecraft:water"));
int grass = BlockColors.of("minecraft:grass_block");
assertTrue((grass >> 8 & 0xFF) > (grass >> 16 & 0xFF) && (grass >> 8 & 0xFF) > (grass & 0xFF), "grass is green");
assertEquals(BlockColors.of("minecraft:oak_planks"), BlockColors.of("minecraft:oak_stairs"), "shapes share their material's colour");
assertTrue(BlockColors.of("create:brass_casing") != 0, "modded blocks still get a colour");
int modded = BlockColors.mapColor("create:brass_casing");
assertEquals(modded, BlockColors.mapColor("create:brass_casing"), "stable for unknown blocks");
assertTrue(modded > 0); assertTrue(modded > 0);
} }
@@ -128,9 +134,9 @@ class MapRenderTest {
try (var in = new DataInputStream(new ByteArrayInputStream(nbt))) { c = Nbt.readRoot(in); } try (var in = new DataInputStream(new ByteArrayInputStream(nbt))) { c = Nbt.readRoot(in); }
ChunkSampler.Columns cols = new ChunkSampler.Columns(); ChunkSampler.Columns cols = new ChunkSampler.Columns();
assertTrue(ChunkSampler.sample(c, ChunkSampler.Kind.OVERWORLD, cols)); assertTrue(ChunkSampler.sample(c, ChunkSampler.Kind.OVERWORLD, cols));
assertEquals(MapColors.STONE, cols.color[15]); assertEquals(BlockColors.of("minecraft:stone"), cols.color[15]);
assertEquals(4 * 16 + 5, cols.height[15]); assertEquals(4 * 16 + 5, cols.height[15]);
assertEquals(MapColors.WATER, cols.color[0]); assertEquals(BlockColors.WATER_COLOR, cols.color[0]);
assertEquals(4 * 16 + 8, cols.height[0]); assertEquals(4 * 16 + 8, cols.height[0]);
assertEquals(3, cols.depth[0]); assertEquals(3, cols.depth[0]);
} }
@@ -143,7 +149,7 @@ class MapRenderTest {
try (var in = new DataInputStream(new ByteArrayInputStream(nbt))) { c = Nbt.readRoot(in); } try (var in = new DataInputStream(new ByteArrayInputStream(nbt))) { c = Nbt.readRoot(in); }
ChunkSampler.Columns cols = new ChunkSampler.Columns(); ChunkSampler.Columns cols = new ChunkSampler.Columns();
assertTrue(ChunkSampler.sample(c, ChunkSampler.Kind.NETHER, cols)); assertTrue(ChunkSampler.sample(c, ChunkSampler.Kind.NETHER, cols));
assertEquals(MapColors.NETHER, cols.color[0], "the floor, not the bedrock roof"); assertEquals(BlockColors.of("minecraft:netherrack"), cols.color[0], "the floor, not the bedrock roof");
assertEquals(7 * 16 + 3, cols.height[0]); assertEquals(7 * 16 + 3, cols.height[0]);
} }
@@ -165,7 +171,7 @@ class MapRenderTest {
@Test void slopesAreShadedAgainstTheNorth() { @Test void slopesAreShadedAgainstTheNorth() {
int n = 512; int n = 512;
int[] colors = new int[n * n], heights = new int[n * n], depths = new int[n * n]; int[] colors = new int[n * n], heights = new int[n * n], depths = new int[n * n];
Arrays.fill(colors, MapColors.STONE); Arrays.fill(colors, BlockColors.of("minecraft:stone"));
for (int z = 0; z < n; z++) Arrays.fill(heights, z * n, z * n + n, 64 + z / 8 * 3); for (int z = 0; z < n; z++) Arrays.fill(heights, z * n, z * n + n, 64 + z / 8 * 3);
int[] px = RegionRenderer.shade(colors, heights, depths); int[] px = RegionRenderer.shade(colors, heights, depths);
int uphill = px[16 * n + 3]; // a step up from the north int uphill = px[16 * n + 3]; // a step up from the north