gmll
Version:
A generic launcher core for building custom launchers
334 lines (331 loc) • 13.2 kB
JavaScript
"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 += ` <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;