AI works here

This commit is contained in:
2026-04-30 12:48:29 -04:00
parent 92024c8a64
commit 6f4519894b
16 changed files with 1793 additions and 303 deletions
+139
View File
@@ -0,0 +1,139 @@
'use strict';
const { PNG } = require('pngjs');
// Minecraft map color palette (base colors × 4 shades each)
// Source: https://minecraft.wiki/w/Map_item_format#Color_table
// Index 0-3 = NONE (transparent), 4-7 = GRASS, 8-11 = SAND, etc.
// Each base color has 4 multipliers: 0.71, 0.86, 1.0, 0.53
const BASE_COLORS = [
null, // 0: NONE
[127, 178, 56], // 1: GRASS
[247, 233, 163], // 2: SAND
[199, 199, 199], // 3: WOOL
[255, 0, 0], // 4: FIRE
[160, 160, 255], // 5: ICE
[167, 167, 167], // 6: METAL
[0, 124, 0], // 7: PLANT
[255, 255, 255], // 8: SNOW
[164, 168, 184], // 9: CLAY
[151, 109, 77], // 10: DIRT
[112, 112, 112], // 11: STONE
[64, 64, 255], // 12: WATER
[143, 119, 72], // 13: WOOD
[255, 252, 245], // 14: QUARTZ
[216, 127, 51], // 15: COLOR_ORANGE
[178, 76, 216], // 16: COLOR_MAGENTA
[102, 153, 216], // 17: COLOR_LIGHT_BLUE
[229, 229, 51], // 18: COLOR_YELLOW
[127, 204, 25], // 19: COLOR_LIGHT_GREEN
[242, 127, 165], // 20: COLOR_PINK
[76, 76, 76], // 21: COLOR_GRAY
[153, 153, 153], // 22: COLOR_LIGHT_GRAY
[76, 127, 153], // 23: COLOR_CYAN
[127, 63, 178], // 24: COLOR_PURPLE
[51, 76, 178], // 25: COLOR_BLUE
[102, 76, 51], // 26: COLOR_BROWN
[102, 127, 51], // 27: COLOR_GREEN
[153, 51, 51], // 28: COLOR_RED
[25, 25, 25], // 29: COLOR_BLACK
[250, 238, 77], // 30: GOLD
[92, 219, 213], // 31: DIAMOND
[74, 128, 255], // 32: LAPIS
[0, 217, 58], // 33: EMERALD
[129, 86, 49], // 34: PODZOL
[112, 2, 0], // 35: NETHER
[209, 177, 161], // 36: TERRACOTTA_WHITE
[159, 82, 36], // 37: TERRACOTTA_ORANGE
[149, 87, 108], // 38: TERRACOTTA_MAGENTA
[112, 108, 138], // 39: TERRACOTTA_LIGHT_BLUE
[186, 133, 36], // 40: TERRACOTTA_YELLOW
[103, 117, 53], // 41: TERRACOTTA_LIGHT_GREEN
[160, 77, 78], // 42: TERRACOTTA_PINK
[57, 41, 35], // 43: TERRACOTTA_GRAY
[135, 107, 98], // 44: TERRACOTTA_LIGHT_GRAY
[87, 92, 92], // 45: TERRACOTTA_CYAN
[122, 73, 88], // 46: TERRACOTTA_PURPLE
[76, 62, 92], // 47: TERRACOTTA_BLUE
[76, 50, 35], // 48: TERRACOTTA_BROWN
[76, 82, 42], // 49: TERRACOTTA_GREEN
[142, 60, 46], // 50: TERRACOTTA_RED
[37, 22, 16], // 51: TERRACOTTA_BLACK
[189, 48, 49], // 52: CRIMSON_NYLIUM
[148, 63, 97], // 53: CRIMSON_STEM
[92, 25, 29], // 54: CRIMSON_HYPHAE
[22, 126, 134], // 55: WARPED_NYLIUM
[58, 142, 140], // 56: WARPED_STEM
[86, 44, 62], // 57: WARPED_HYPHAE
[20, 180, 133], // 58: WARPED_WART_BLOCK
[100, 100, 100], // 59: DEEPSLATE
[216, 175, 147], // 60: RAW_IRON
[127, 167, 150], // 61: GLOW_LICHEN
];
const SHADE_MULTIPLIERS = [180, 220, 255, 135]; // out of 255
// Build the full 256-entry lookup: MAP_COLORS[colorIndex] → [r, g, b]
const MAP_COLORS = new Array(256).fill(null);
for (let base = 0; base < BASE_COLORS.length; base++) {
for (let shade = 0; shade < 4; shade++) {
const idx = base * 4 + shade;
if (!BASE_COLORS[base]) {
MAP_COLORS[idx] = [0, 0, 0, 0]; // transparent
} else {
const [r, g, b] = BASE_COLORS[base];
const m = SHADE_MULTIPLIERS[shade];
MAP_COLORS[idx] = [
Math.floor(r * m / 255),
Math.floor(g * m / 255),
Math.floor(b * m / 255),
255
];
}
}
}
/**
* Apply a partial map update from a protocol packet to a pixel buffer.
* @param {Uint8Array} pixels - 128×128 color index buffer (mutated in place)
* @param {Object} packet - Map protocol packet with columns, rows, x, y, data
*/
function applyMapUpdate(pixels, packet) {
const { columns, rows, x, y, data } = packet;
if (!columns || columns === 0 || !data) return;
for (let col = 0; col < columns; col++) {
for (let row = 0; row < rows; row++) {
const srcIdx = col * rows + row;
const dstX = x + col;
const dstY = y + row;
if (dstX < 128 && dstY < 128) {
pixels[dstY * 128 + dstX] = data[srcIdx];
}
}
}
}
/**
* Render a 128×128 color-index buffer to a base64 PNG string.
* @param {Uint8Array} pixels - 128×128 array of Minecraft color indices
* @returns {string} base64-encoded PNG
*/
function renderMapToPNG(pixels) {
const png = new PNG({ width: 128, height: 128 });
for (let i = 0; i < 128 * 128; i++) {
const colorIdx = pixels[i];
const color = MAP_COLORS[colorIdx] || [0, 0, 0, 0];
const offset = i * 4;
png.data[offset] = color[0]; // R
png.data[offset + 1] = color[1]; // G
png.data[offset + 2] = color[2]; // B
png.data[offset + 3] = color[3]; // A
}
const buffer = PNG.sync.write(png);
return buffer.toString('base64');
}
module.exports = { MAP_COLORS, applyMapUpdate, renderMapToPNG };