diff --git a/package.json b/package.json index 50c1486..1026701 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aeromc", - "version": "0.29.0", + "version": "0.33.1", "description": "AeroMC – Instanz-basierter Minecraft-Launcher (à la MultiMC/Prism)", "main": "src/main.js", "author": "AeroMC", diff --git a/src/icons.js b/src/icons.js new file mode 100644 index 0000000..e9f5c4c --- /dev/null +++ b/src/icons.js @@ -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 . 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 }; diff --git a/src/index.html b/src/index.html index ff1b5e9..1835bad 100644 --- a/src/index.html +++ b/src/index.html @@ -187,6 +187,7 @@ + @@ -212,6 +213,18 @@ Hier werden alle Instanzen als Unterordner (mit ihrem Namen) gespeichert. + + + + Gilt für alle Instanzen ohne eigene RAM-Einstellung. + +

Fenstergröße

+ +
+ + +
+ +