UNPKG

gmll

Version:

A generic launcher core for building custom launchers

334 lines (331 loc) 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.jarMod = exports.getForgeVersions = exports.installForge = exports.wrap = exports.pack = exports.getJarModPriority = void 0; const gfsl_1 = require("gfsl"); const os_1 = require("os"); const config_js_1 = require("../../config.js"); const handler_js_1 = require("../../handler.js"); const util_js_1 = require("../util.js"); /**Gets the load order of minecraft jars in jar mod loader. */ async function getJarModPriority() { return (await this.getMetaPaths()).jarMods .getFile("priority.json") .load({}); } exports.getJarModPriority = getJarModPriority; /**Wraps up an instance in a prepackaged format that can be easily uploaded to a server for distribution * @param baseUrl The base URL the generated files will be stored within on your server. For example http\:\/\/yourawesomdomain.net\/path\/to\/files\/ * @param save The file GMLL will generate the final files on. * @param name The name that should be used to identify the generated version files * @param forge The path to a forge installation jar * @param trimMisc Gets rid of any unnecessary miscellaneous files */ async function pack(config) { let modpackVersion = 1; const saveDir = typeof config.outputDir == "string" ? new gfsl_1.Dir(config.outputDir) : config.outputDir; const baseDownloadLink = config.baseDownloadLink; const trimMisc = config.trimMisc; let _forge = config.forgeInstallerPath; if (_forge) { _forge = config.forgeInstallerPath instanceof gfsl_1.File ? config.forgeInstallerPath : new gfsl_1.File(config.forgeInstallerPath); } const forge = _forge; const modpackName = config.modpackName || this.getName(); await this.install(); const blacklist = [ "usercache.json", "realms_persistence.json", "logs", "profilekeys", "usernamecache.json", ]; const separate = [ "resourcepacks", "texturepacks", "mods", "coremods", "jarmods", "shaderpacks", ]; const dynamic = ["saves", "config"]; const bundle = ["saves"]; const pack = ["config"]; const me = this.getDir(); const resources = []; const cp = (d, path) => { if (d.exists()) { d.ls().forEach((e) => { if (!e.exists()) return; if (e instanceof gfsl_1.File) { const f = new gfsl_1.File(saveDir.javaPath(), ...path, e.name); e.copyTo(f.mkdir()); resources.push({ key: [...path, e.name].join("/"), name: e.name, path: path, url: [baseDownloadLink, ...path, e.name].join("/"), chk: { sha1: f.getHash(), size: f.getSize() }, }); } else if (!e.isLink()) { const path2 = [...path, e.path[e.path.length - 1]]; cp(e, path2); } }); } }; separate.forEach((e) => cp(me.getDir(e), [e])); const data = saveDir.getDir(".data").mkdir(); for (let i = 0; i < bundle.length; i++) { const e = bundle[i]; const ls = me.getDir(e).ls(); for (let k = 0; k < ls.length; k++) { const e2 = ls[k]; if (!e2.isLink() && e2 instanceof gfsl_1.Dir && e2.exists()) { const name = e2.getName(); const zip = e + "_" + k + ".zip"; const file = data.getFile(zip); await (0, gfsl_1.packAsync)(e2.sysPath(), file.sysPath()); resources.push({ dynamic: dynamic.includes(e), unzip: { file: [e] }, key: [e, name].join("/"), name: zip, path: [".data"], url: [baseDownloadLink, ".data", zip].join("/"), chk: { sha1: file.getHash(), size: file.getSize() }, }); } } } for (let i = 0; i < pack.length; i++) { const e = pack[i]; const directory = me.getDir(e); if (directory.exists() && !directory.isLink()) { const zip = e + ".zip"; const file = data.getFile(zip); await (0, gfsl_1.packAsync)(directory.sysPath(), file.sysPath()); resources.push({ dynamic: dynamic.includes(e), unzip: { file: [] }, key: [e, modpackName].join("/"), name: zip, path: [".data"], url: [baseDownloadLink, ".data", zip].join("/"), chk: { sha1: file.getHash(), size: file.getSize() }, }); } } const ls2 = me.ls(); const zip = "misc.zip"; const miscZip = data.getFile(zip).mkdir(); const avoid = [...separate, ...bundle, ...blacklist, ...pack]; if (this.assets && this.assets.objects) { const assetDir = saveDir.getDir("assets").mkdir(); Object.values(this.assets.objects).forEach((e) => { (0, util_js_1.assetTag)((0, config_js_1.getAssets)().getDir("objects"), e.hash) .getFile(e.hash) .copyTo((0, util_js_1.assetTag)(assetDir.getDir("objects"), e.hash).mkdir().getFile(e.hash)); }); await (0, gfsl_1.packAsync)(assetDir.sysPath(), miscZip.sysPath()); assetDir.rm(); } if (!trimMisc) for (let k = 0; k < ls2.length; k++) { const e = ls2[k]; if (!e.isLink() && !avoid.includes(e.getName()) && !e.getName().startsWith(".")) await (0, gfsl_1.packAsync)(e.sysPath(), miscZip.sysPath()); } if (miscZip.exists()) { resources.push({ unzip: { file: [] }, key: "misc", name: "misc.zip", path: [".data"], url: [baseDownloadLink, ".data", zip].join("/"), chk: { sha1: miscZip.getHash(), size: miscZip.getSize() }, }); } else { (0, config_js_1.emit)("debug.warn", "No misc zip detected! If this is intended then please ignore"); } const ver = { instance: { // restart_Multiplier: 1, files: resources, assets: this.assets, meta: this.meta, }, id: modpackName, }; const versionFile = saveDir.getDir(".meta").mkdir().getFile("version.json"); let finalVersion = this.version; if (config.forgeVersion) { if (modpackVersion == 1) modpackVersion = 2; const forge = (0, handler_js_1.installForge)(config.forgeVersion); finalVersion = forge.id; ver.instance.forge = config.forgeVersion; } else if (forge) { const path = saveDir.getDir(".forgiac").rm().mkdir(); const _manifest = await (0, handler_js_1.installForge)(forge, [ "--.minecraft", path.sysPath(), ]); const forgePath = saveDir.getDir("forge").mkdir(); finalVersion = _manifest.id; forge.copyTo(forgePath.getFile(forge.getName())); ver.instance.files.push({ key: forge.getName(), name: forge.getName(), path: ["forge"], url: [baseDownloadLink, "forge", forge.getName()].join("/"), chk: { sha1: forge.getHash(), size: forge.getSize() }, }); ver.instance.forge = { installer: ["forge", forge.getName()] }; path.rm(); } ver.inheritsFrom = finalVersion; versionFile.write(ver); const manifest = { id: modpackName, type: "custom", sha1: versionFile.getHash(), base: finalVersion, url: baseDownloadLink + "/" + ".meta/version.json", _comment: "Drop this into gmll's manifest folder", }; delete manifest._comment; saveDir.getFile(".meta", "manifest.json").write(manifest); saveDir.getFile(".meta", "api.json").write({ name: modpackName, version: 1, sha: saveDir.getFile(".meta", "manifest.json").getHash(), _comment: "Here for future proofing incase we need to introduce a breaking change to this system.", }); let index = `<!DOCTYPE html><html><!--This is just a place holder! GMLL doesn't check this. It is merely here to look nice and serve as a directory listing-->`; index += `<head><link rel="stylesheet" href="https://styles.hanro50.net.za/v1/main"><title>${modpackName}</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="A GMLL minecraft modpack"></head><body><h1>${modpackName}</h1><h2>Copy the link to this page into gmll to import this modpack!</h2><h2>File list</h2>`; function read(f, directory = []) { f.ls().forEach((e) => { if (e.getName() == "index.html" || e.getName() == `manifest_${(0, util_js_1.fsSanitizer)(modpackName)}.json`) return; if (e instanceof gfsl_1.File) { const entry = [...directory, e.getName()].join("/"); index += `&nbsp;<br><div class="element button" onclick="document.location.href='./${entry}'">${entry}</div>`; } else read(e, [...directory, e.getName()]); }); } read(saveDir); index += `</body></html>`; saveDir.getFile("index.html").write(index); saveDir.getFile(`manifest_${(0, util_js_1.fsSanitizer)(modpackName)}.json`).write(manifest); return ver; } exports.pack = pack; /**An version of the wrap function that takes an object as a variable instead of the mess the base function takes. */ function wrap(baseUrl, save = new gfsl_1.Dir(), modpackName = "custom_" + this.name, forge, trimMisc = false) { const forgeInstallerPath = "jar" in forge ? forge.jar : forge; return this.pack({ baseDownloadLink: baseUrl, outputDir: save, forgeInstallerPath, modpackName, trimMisc, }); } exports.wrap = wrap; /**Install forge in this instance. */ async function installForge(forge) { const manifest = await (0, handler_js_1.installForge)(forge); this.version = manifest.id; return manifest; } exports.installForge = installForge; async function getForgeVersions() { const data = (await (0, handler_js_1.getForgeVersions)())[this.version]; return data.map((e) => { const forge = e; forge.install = () => this.installForge(forge); return forge; }); } exports.getForgeVersions = getForgeVersions; /** * Used to modify minecraft's jar file (Low level) * @param metaPaths * @param version * @returns */ async function jarMod(metaPaths, version) { const jarMods = metaPaths.jarMods; const bin = gfsl_1.Dir.tmpdir().getDir("gmll", "bin").rm().mkdir(); const custom = bin.getFile(`${version.name}.jar`); if (!jarMods || !jarMods.exists()) return; const lst = jarMods.ls(); if (lst.length < 1) return; (0, config_js_1.emit)("debug.warn", "Jar modding is experimental atm.\nWe still don't have a way to order jars\nRecommended for modding legacy versions or mcp..."); (0, config_js_1.emit)("debug.info", "Packing custom jar"); const tmp = gfsl_1.Dir.tmpdir().getDir("gmll", "tmp").rm().mkdir(); const jar = version.folder.getFile(version.name + ".jar"); if (!jar.exists()) return; await jar.unzip(tmp, { exclude: ["META-INF/*"] }); let priority = { _comment: "0 is the default, the lower the priority. The sooner a mod will be loaded. Deleting this file resets it", }; const pFile = jarMods.getFile("priority.json"); let fReset = false; if (pFile.exists()) try { priority = pFile.toJSON(); } catch (e) { (0, config_js_1.emit)("debug.warn", "Failed to parse priorities file!"); } else fReset = true; lst.sort((aF, bF) => { const a = aF.getName(); const b = bF.getName(); if (priority[a] != priority[b]) { if (a in priority && b in priority) return priority[a] - priority[b]; if (a in priority) return priority[a]; if (b in priority) return 0 - priority[b]; } return a > b ? 1 : -1; }); (0, config_js_1.emit)("debug.info", "Running through files"); for (const e of lst) { if (e instanceof gfsl_1.File) { const n = e.getName(); if (n.endsWith(".zip") || n.endsWith(".jar")) { if (!(n in priority)) { priority[n] = fReset ? (Object.keys(priority).length - 1) * 10 : 0; } await e.unzip(tmp); } } } pFile.write(priority); (0, config_js_1.emit)("debug.info", "Packing jar"); await (0, gfsl_1.packAsync)(tmp.sysPath() + ((0, os_1.platform)() == "win32" ? "\\." : "/."), custom.sysPath()); return custom; } exports.jarMod = jarMod;