UNPKG

gmll

Version:

A generic launcher core for building custom launchers

241 lines (240 loc) 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.launch = exports.install = void 0; const tslib_1 = require("tslib"); const child_process_1 = require("child_process"); const crypto_1 = require("crypto"); const gfsl_1 = require("gfsl"); const os_1 = require("os"); const path_1 = require("path"); const config_js_1 = require("../../config.js"); const downloader_js_1 = require("../../downloader.js"); const instance_js_1 = tslib_1.__importDefault(require("../../objects/instance.js")); const util_js_1 = require("../util.js"); /** * For internal use only */ function parseArguments(val = {}, args) { let out = ""; args.forEach((e) => { if (typeof e == "string") out += "\u0000" + e.trim().replace(/\s/g, ""); else if ((0, util_js_1.lawyer)(e.rules, val)) out += "\u0000" + (e.value instanceof Array ? e.value.join("\u0000") : e.value); }); return out; } /** * Runs the installer script without launching MC * @returns The instance's version object. * @see {@link getVersion} if you just want the instance's version */ async function install() { //Making links (0, config_js_1.getlibraries)().linkFrom(this.getDir().getDir("libraries")); (0, config_js_1.getAssets)().linkFrom(this.getDir().getDir("assets")); const version = await this.getVersion(); if (version.json.instance) { const chk = this.getDir().getFile(".installed.txt"); if (version.mergeFailure()) chk.rm(); let security = false; const instance = version.json.instance; for (let i = 0; i < instance.files.length; i++) { instance.files[i].path = [ this.getDir().sysPath(), ...instance.files[i].path, ]; instance.files[i].path.forEach((e) => { if (e.includes("..")) security = true; }); new gfsl_1.Dir(...instance.files[i].path).mkdir(); if (instance.files[i].unzip) { instance.files[i].unzip.file = [ this.getDir().sysPath(), ...instance.files[i].unzip.file, ]; } } if (security) { /**DO NOT REMOVE. * 1) This is here to prevent someone escaping the instance sandbox. * 2) This stops non standard modPacks causing issues... * 3) This is here to allow for future security measures */ throw "Security exception!\nFound '..' in file path which is not allowed as it allows one to escape the instance folder"; } await (0, downloader_js_1.download)(instance.files); if (!chk.exists()) { if (instance.meta) this.meta = (0, util_js_1.combine)(this.meta, instance.meta); if (instance.assets) this.assets = (0, util_js_1.combine)(instance.assets, this.assets); if (instance.forge) { if ("installer" in instance.forge) { const fFile = this.getDir().getFile(...instance.forge.installer); if (!fFile.exists()) { throw "Cannot find forge installer"; } await this.installForge(fFile); } else { await this.installForge(instance.forge); } } } chk.write(Date.now().toString()); } await version.install(); if (version.json.jarmods) { for (const mod of version.json.jarmods) { const file = (await this.getMetaPaths()).jarMods .mkdir() .getFile(mod.path); await file.download(mod.url, { sha1: mod.sha1, size: mod.size }); } } return version; } exports.install = install; /** * This function is used to launch the game. It also runs the install script for you. * This essentially does an integrity check. * @param token The player login token * @param resolution Optional information defining the game's resolution * @returns The process that was used to launch the game. */ async function launch(token, resolution) { //const metaPaths = (await this.getMetaPaths()); if (!token) { (0, config_js_1.emit)("debug.warn", "No token detected. Launching game in demo mode!"); const demoFile = (0, config_js_1.getMeta)().index.getFile("demo.txt"); if (!demoFile.exists()) demoFile.write((0, crypto_1.randomUUID)()); token = { profile: { id: demoFile.read(), demo: true, name: "player", }, access_token: "", }; } const version = await this.install(); const jarModded = await instance_js_1.default.jarMod(await this.getMetaPaths(), version); const cp = version.getClassPath(undefined, jarModded); const versionJson = await version.getJSON(); let assetRoot = (0, config_js_1.getAssets)(); let assetsFile = this.getDir().getDir("assets"); let AssetIndex = (0, config_js_1.getAssets)() .getFile("indexes", (versionJson.assets || "pre-1.6") + ".json") .toJSON(); let assets_index_name = versionJson.assetIndex.id; if (this.assets.objects) { AssetIndex = (0, util_js_1.combine)(AssetIndex, this.assets); assets_index_name = (0, util_js_1.fsSanitizer)(assets_index_name + "_" + this.name); (0, config_js_1.getAssets)() .getFile("indexes", assets_index_name + ".json") .write(AssetIndex); (0, util_js_1.processAssets)(AssetIndex); } let mac_icon = ""; if ((0, os_1.platform)() === "darwin") { const obj = AssetIndex.objects["icons/minecraft.icns"]; mac_icon = (0, util_js_1.assetTag)(assetRoot.getDir("objects"), obj.hash) .getFile(obj.hash) .sysPath(); } if (AssetIndex.virtual || AssetIndex.map_to_resources) { assetRoot = (0, config_js_1.getAssets)().getDir("legacy", AssetIndex.virtual ? "virtual" : "resources"); assetsFile = this.getDir().getFile("resources").rm(); assetRoot.linkFrom(assetsFile); } const classpath_separator = (0, os_1.type)() == "Windows_NT" ? ";" : ":"; const classPath = cp.join(classpath_separator); const args = { ram: Math.floor(this.ram * 1024), cores: (0, os_1.cpus)().length, is_demo_user: !!token.profile.demo, has_custom_resolution: !!resolution, resolution_width: resolution ? resolution.width : "", resolution_height: resolution ? resolution.height : "", auth_player_name: token.profile.name, version_name: versionJson.inheritsFrom || versionJson.id, game_directory: this.getDir().sysPath() + "/", assets_root: assetsFile, assets_index_name: assets_index_name, auth_uuid: token.profile.id, user_type: token.profile.type, auth_xuid: token.profile.xuid, clientid: (0, util_js_1.getClientID)(), version_type: versionJson.type, auth_access_token: token.access_token, natives_directory: (0, config_js_1.getNatives)(), launcher_name: (0, config_js_1.getLauncherName)(), launcher_version: (0, config_js_1.getLauncherVersion)(), classpath: classPath, auth_session: token.access_token, game_assets: assetsFile, classpath_separator: classpath_separator, library_directory: (0, config_js_1.getlibraries)(), user_properties: JSON.stringify(token.profile.properties || {}), game_jar: version.getJarPath().sysPath(), port: 0, mac_icon, mac_name: "Minecraft", }; const javaPath = this.javaPath == "default" ? version.getJavaPath() : new gfsl_1.File(this.javaPath); const rawJvmArgs = [...instance_js_1.default.defaultGameArguments]; rawJvmArgs.push(...(versionJson.arguments?.jvm || instance_js_1.default.defJVM)); const agentFile = (0, downloader_js_1.getAgentFile)(); if (!this.noLegacyFix && version.manifest.releaseTime && Date.parse(version.manifest.releaseTime) < Date.parse("2014-04-14T17:29:23+00:00")) { if (agentFile.exists()) rawJvmArgs.push(`-javaagent:${agentFile.sysPath()}`); rawJvmArgs.push(...instance_js_1.default.oldJVM); } const jvmArgs = parseArguments(args, rawJvmArgs); let gameArgs = versionJson.arguments ? parseArguments(args, versionJson.arguments.game) : ""; gameArgs += versionJson.minecraftArguments ? "\x00" + versionJson.minecraftArguments.replace(/\s/g, "\x00") : ""; let launchCom = jvmArgs + "\x00" + versionJson.mainClass + (!gameArgs.startsWith("\x00") ? "\x00" : "") + gameArgs; Object.keys(args).forEach((key) => { const regex = new RegExp(`\\$\{${key}}`, "g"); launchCom = launchCom.replace(regex, args[key]); }); (0, config_js_1.emit)("jvm.start", "Minecraft", this.getDir().sysPath(), this); const launchArgs = launchCom.trim().split("\x00"); if (launchArgs[0] == "") launchArgs.shift(); const runningInstance = (0, child_process_1.spawn)(javaPath.sysPath(), launchArgs, { cwd: (0, path_1.join)(this.getDir().sysPath()), env: (0, util_js_1.combine)(process.env, this.env), detached: this.detach, }); runningInstance.stdout.on("data", (chunk) => { if (chunk.includes(token.access_token)) chunk = chunk .toString() .replace(token.access_token, "*".repeat(token.access_token.length)) .replace(token.profile.id, "*".repeat(token.profile.id.length)); (0, config_js_1.emit)("jvm.stdout", "Minecraft", chunk, this); }); runningInstance.stderr.on("data", (chunk) => (0, config_js_1.emit)("jvm.stderr", "Minecraft", chunk, this)); return runningInstance; } exports.launch = launch;