Files
AeroMc-Launcher/src/icons.js
T

133 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/*
* icons.js echte Minecraft-Item-Icons
* -------------------------------------
* Die Original-Texturen werden aus der bereits heruntergeladenen client.jar
* des Nutzers extrahiert (also aus seinen eigenen Spieldateien) und lokal
* als Icons abgelegt. Es werden keine fremden Assets mitgeliefert.
*/
const fs = require('fs');
const path = require('path');
const forge = require('./forge');
// Auswahl gut erkennbarer 16x16-Texturen (Pfade im client.jar)
const WANTED = [
['grass', 'block/grass_block_side.png', 'Grasblock'],
['dirt', 'block/dirt.png', 'Erde'],
['stone', 'block/cobblestone.png', 'Bruchstein'],
['planks', 'block/oak_planks.png', 'Holzbretter'],
['tnt', 'block/tnt_side.png', 'TNT'],
['obsidian', 'block/obsidian.png', 'Obsidian'],
['netherrack', 'block/netherrack.png', 'Netherrack'],
['crafting', 'block/crafting_table_front.png', 'Werkbank'],
['furnace', 'block/furnace_front.png', 'Ofen'],
['bookshelf', 'block/bookshelf.png', 'Bücherregal'],
['diamondblock', 'block/diamond_block.png', 'Diamantblock'],
['goldblock', 'block/gold_block.png', 'Goldblock'],
['emeraldblock', 'block/emerald_block.png', 'Smaragdblock'],
['redstoneblock', 'block/redstone_block.png', 'Redstoneblock'],
['diamond', 'item/diamond.png', 'Diamant'],
['emerald', 'item/emerald.png', 'Smaragd'],
['gold', 'item/gold_ingot.png', 'Goldbarren'],
['iron', 'item/iron_ingot.png', 'Eisenbarren'],
['redstone', 'item/redstone.png', 'Redstone'],
['coal', 'item/coal.png', 'Kohle'],
['potion', 'item/potion.png', 'Trank'],
['paper', 'item/paper.png', 'Papier'],
['feather', 'item/feather.png', 'Feder'],
['slimeball', 'item/slime_ball.png', 'Schleimball'],
['magma', 'item/magma_cream.png', 'Magmacreme'],
['quartz', 'item/quartz.png', 'Netherquarz'],
['brick', 'item/brick.png', 'Ziegel'],
['cookie', 'item/cookie.png', 'Keks'],
['snowball', 'item/snowball.png', 'Schneeball'],
['sword', 'item/diamond_sword.png', 'Diamantschwert'],
['pickaxe', 'item/diamond_pickaxe.png', 'Diamantspitzhacke'],
['axe', 'item/diamond_axe.png', 'Diamantaxt'],
['bow', 'item/bow.png', 'Bogen'],
['apple', 'item/apple.png', 'Apfel'],
['goldenapple', 'item/golden_apple.png', 'Goldener Apfel'],
['book', 'item/book.png', 'Buch'],
['enchantedbook', 'item/enchanted_book.png', 'Verzaubertes Buch'],
['map', 'item/map.png', 'Karte'],
['star', 'item/nether_star.png', 'Netherstern'],
['endereye', 'item/ender_eye.png', 'Enderauge'],
['enderpearl', 'item/ender_pearl.png', 'Enderperle'],
['blaze', 'item/blaze_powder.png', 'Lohenstaub'],
['xp', 'item/experience_bottle.png', 'Erfahrungsfläschchen'],
['cake', 'item/cake.png', 'Kuchen'],
['bucket', 'item/water_bucket.png', 'Wassereimer'],
['lava', 'item/lava_bucket.png', 'Lavaeimer'],
['chest', 'item/chest.png', 'Truhe'],
['creeper', 'item/creeper_head.png', 'Creeper-Kopf'],
['tnt_item', 'item/gunpowder.png', 'Schwarzpulver'],
];
// sucht die neueste vorhandene client.jar (auch im Datenordner vor der Umbenennung)
function findClientJars(sharedDirs) {
const jars = [];
for (const shared of sharedDirs) {
const vdir = path.join(shared, 'versions');
if (!fs.existsSync(vdir)) continue;
for (const entry of fs.readdirSync(vdir, { withFileTypes: true })) {
if (!entry.isDirectory()) continue;
const jar = path.join(vdir, entry.name, entry.name + '.jar');
try {
if (fs.existsSync(jar) && fs.statSync(jar).size > 1024 * 1024) {
jars.push({ version: entry.name, path: jar, mtime: fs.statSync(jar).mtimeMs });
}
} catch { /* überspringen */ }
}
}
jars.sort((a, b) => b.mtime - a.mtime);
return jars;
}
/*
* Extrahiert die Texturen in <outDir>. Gibt die Liste der gefundenen Icons zurück.
*/
function extractIcons(sharedDirs, outDir) {
const jars = findClientJars(sharedDirs);
if (!jars.length) return { ok: false, reason: 'no-jar' };
const jar = jars[0];
const buf = fs.readFileSync(jar.path);
const zip = forge.readZipIndex(buf);
fs.mkdirSync(outDir, { recursive: true });
const found = [];
for (const [key, rel, label] of WANTED) {
const entry = zip['assets/minecraft/textures/' + rel];
if (!entry) continue;
try {
const png = forge.readZipEntry(buf, entry);
// sehr große Dateien überspringen (animierte Texturen sind gestreckt)
if (png.length > 64 * 1024) continue;
const dest = path.join(outDir, key + '.png');
fs.writeFileSync(dest, png);
found.push({ key, label, file: dest });
} catch { /* Textur überspringen */ }
}
return { ok: true, version: jar.version, count: found.length, icons: found };
}
// liest die extrahierten Icons als data:-URIs (für die Anzeige)
function listIcons(outDir) {
if (!fs.existsSync(outDir)) return [];
const labels = Object.fromEntries(WANTED.map(([k, , l]) => [k, l]));
return fs.readdirSync(outDir)
.filter((f) => f.endsWith('.png'))
.map((f) => {
const key = path.basename(f, '.png');
try {
const data = fs.readFileSync(path.join(outDir, f)).toString('base64');
return { key, label: labels[key] || key, dataUri: 'data:image/png;base64,' + data };
} catch { return null; }
})
.filter(Boolean);
}
module.exports = { extractIcons, listIcons, findClientJars, WANTED };