Upload via GUI (18 Dateien)
This commit is contained in:
+121
@@ -0,0 +1,121 @@
|
||||
'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'],
|
||||
['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'],
|
||||
['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 };
|
||||
Reference in New Issue
Block a user