gmll
Version:
A generic launcher core for building custom launchers
241 lines (240 loc) • 10.1 kB
JavaScript
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;
;