2023-06-18 15:07:15 +03:00
|
|
|
const child = require("child_process");
|
|
|
|
const path = require("path");
|
|
|
|
const Handler = require("./handler");
|
|
|
|
const fs = require("fs");
|
|
|
|
const EventEmitter = require("events").EventEmitter;
|
|
|
|
|
|
|
|
class PiMiCore extends EventEmitter {
|
|
|
|
async launch(options) {
|
2022-03-02 05:52:06 +03:00
|
|
|
try {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.options = { ...options };
|
|
|
|
this.options.root = path.resolve(this.options.root);
|
2022-03-02 05:52:06 +03:00
|
|
|
this.options.overrides = {
|
|
|
|
detached: true,
|
|
|
|
...this.options.overrides,
|
|
|
|
url: {
|
2023-06-18 15:07:15 +03:00
|
|
|
meta: "https://launchermeta.mojang.com",
|
|
|
|
resource: "https://resources.download.minecraft.net",
|
|
|
|
mavenForge: "http://files.minecraftforge.net/maven/",
|
|
|
|
defaultRepoForge: "https://libraries.minecraft.net/",
|
|
|
|
fallbackMaven: "https://search.maven.org/remotecontent?filepath=",
|
|
|
|
...(this.options.overrides ? this.options.overrides.url : undefined),
|
2022-03-02 05:52:06 +03:00
|
|
|
},
|
|
|
|
fw: {
|
2023-06-18 15:07:15 +03:00
|
|
|
baseUrl:
|
|
|
|
"https://github.com/ZekerZhayard/ForgeWrapper/releases/download/",
|
|
|
|
version: "1.5.5",
|
|
|
|
sh1: "566dfd60aacffaa02884614835f1151d36f1f985",
|
2022-03-02 05:52:06 +03:00
|
|
|
size: 34331,
|
2023-06-18 15:07:15 +03:00
|
|
|
...(this.options.overrides ? this.options.overrides.fw : undefined),
|
|
|
|
},
|
|
|
|
};
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
this.handler = new Handler(this);
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
this._printVersion();
|
2021-02-01 01:09:37 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const java = await this.handler.checkJava(
|
|
|
|
this.options.javaPath || "java"
|
|
|
|
);
|
2022-03-02 05:52:06 +03:00
|
|
|
if (!java.run) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
`[PiMi]: Couldn't start Minecraft due to: ${java.message}`
|
|
|
|
);
|
|
|
|
this.emit("close", 1);
|
|
|
|
return null;
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
this._createRootDirectory();
|
|
|
|
this._createGameDirectory();
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
await this._extractPackage();
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2022-03-02 05:52:06 +03:00
|
|
|
if (this.options.installer) {
|
|
|
|
// So installers that create a profile in launcher_profiles.json can run without breaking.
|
2023-06-18 15:07:15 +03:00
|
|
|
const profilePath = path.join(
|
|
|
|
this.options.root,
|
|
|
|
"launcher_profiles.json"
|
|
|
|
);
|
|
|
|
if (
|
|
|
|
!fs.existsSync(profilePath) ||
|
|
|
|
!JSON.parse(fs.readFileSync(profilePath)).profiles
|
|
|
|
) {
|
|
|
|
fs.writeFileSync(
|
|
|
|
profilePath,
|
|
|
|
JSON.stringify({ profiles: {} }, null, 4)
|
|
|
|
);
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2023-06-18 15:07:15 +03:00
|
|
|
const code = await this.handler.runInstaller(this.options.installer);
|
2022-03-02 05:52:06 +03:00
|
|
|
if (!this.options.version.custom && code === 0) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
"[PiMi]: Installer successfully ran, but no custom version was provided"
|
|
|
|
);
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit("debug", `[PiMi]: Installer closed with code ${code}`);
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const directory =
|
|
|
|
this.options.overrides.directory ||
|
|
|
|
path.join(
|
|
|
|
this.options.root,
|
|
|
|
"versions",
|
|
|
|
this.options.version.custom
|
|
|
|
? this.options.version.custom
|
|
|
|
: this.options.version.number
|
|
|
|
);
|
|
|
|
this.options.directory = directory;
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const versionFile = await this.handler.getVersion();
|
|
|
|
const mcPath =
|
|
|
|
this.options.overrides.minecraftJar ||
|
|
|
|
(this.options.version.custom
|
|
|
|
? path.join(
|
|
|
|
this.options.root,
|
|
|
|
"versions",
|
|
|
|
this.options.version.custom,
|
|
|
|
`${this.options.version.custom}.jar`
|
|
|
|
)
|
|
|
|
: path.join(directory, `${this.options.version.number}.jar`));
|
|
|
|
this.options.mcPath = mcPath;
|
|
|
|
const nativePath = await this.handler.getNatives();
|
2018-10-30 01:13:58 +03:00
|
|
|
|
2022-03-02 05:52:06 +03:00
|
|
|
if (!fs.existsSync(mcPath)) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
"[PiMi]: Attempting to download Minecraft version jar"
|
|
|
|
);
|
|
|
|
await this.handler.getJar();
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const modifyJson = await this._getModifyJson();
|
2022-03-02 05:52:06 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const args = [];
|
2022-03-02 05:52:06 +03:00
|
|
|
|
|
|
|
let jvm = [
|
2023-06-18 15:07:15 +03:00
|
|
|
"-XX:-UseAdaptiveSizePolicy",
|
|
|
|
"-XX:-OmitStackTraceInFastThrow",
|
|
|
|
"-Dfml.ignorePatchDiscrepancies=true",
|
|
|
|
"-Dfml.ignoreInvalidMinecraftCertificates=true",
|
2022-03-02 05:52:06 +03:00
|
|
|
`-Djava.library.path=${nativePath}`,
|
|
|
|
`-Xmx${this.handler.getMemory()[0]}`,
|
2023-06-18 15:07:15 +03:00
|
|
|
`-Xms${this.handler.getMemory()[1]}`,
|
|
|
|
];
|
|
|
|
if (this.handler.getOS() === "osx") {
|
|
|
|
if (parseInt(versionFile.id.split(".")[1]) > 12)
|
|
|
|
jvm.push(await this.handler.getJVM());
|
|
|
|
} else jvm.push(await this.handler.getJVM());
|
2022-03-02 05:52:06 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
if (this.options.customArgs) jvm = jvm.concat(this.options.customArgs);
|
2022-03-02 05:52:06 +03:00
|
|
|
if (this.options.overrides.logj4ConfigurationFile) {
|
2023-06-18 15:07:15 +03:00
|
|
|
jvm.push(
|
|
|
|
`-Dlog4j.configurationFile=${path.resolve(
|
|
|
|
this.options.overrides.logj4ConfigurationFile
|
|
|
|
)}`
|
|
|
|
);
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
|
|
|
// https://help.minecraft.net/hc/en-us/articles/4416199399693-Security-Vulnerability-in-Minecraft-Java-Edition
|
2023-06-18 15:07:15 +03:00
|
|
|
if (parseInt(versionFile.id.split(".")[1]) === 17)
|
|
|
|
jvm.push("-Dlog4j2.formatMsgNoLookups=true");
|
|
|
|
if (parseInt(versionFile.id.split(".")[1]) < 17) {
|
|
|
|
if (!jvm.find((arg) => arg.includes("Dlog4j.configurationFile"))) {
|
|
|
|
const configPath = path.resolve(
|
|
|
|
this.options.overrides.cwd || this.options.root
|
|
|
|
);
|
|
|
|
const intVersion = parseInt(versionFile.id.split(".")[1]);
|
2022-03-02 05:52:06 +03:00
|
|
|
if (intVersion >= 12) {
|
2023-06-18 15:07:15 +03:00
|
|
|
await this.handler.downloadAsync(
|
|
|
|
"https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml",
|
|
|
|
configPath,
|
|
|
|
"log4j2_112-116.xml",
|
|
|
|
true,
|
|
|
|
"log4j"
|
|
|
|
);
|
|
|
|
jvm.push("-Dlog4j.configurationFile=log4j2_112-116.xml");
|
2022-03-02 05:52:06 +03:00
|
|
|
} else if (intVersion >= 7) {
|
2023-06-18 15:07:15 +03:00
|
|
|
await this.handler.downloadAsync(
|
|
|
|
"https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml",
|
|
|
|
configPath,
|
|
|
|
"log4j2_17-111.xml",
|
|
|
|
true,
|
|
|
|
"log4j"
|
|
|
|
);
|
|
|
|
jvm.push("-Dlog4j.configurationFile=log4j2_17-111.xml");
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2021-12-13 20:44:09 +03:00
|
|
|
}
|
|
|
|
}
|
2020-05-29 05:39:13 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const classes =
|
|
|
|
this.options.overrides.classes ||
|
|
|
|
this.handler.cleanUp(await this.handler.getClasses(modifyJson));
|
|
|
|
const classPaths = ["-cp"];
|
|
|
|
const separator = this.handler.getOS() === "windows" ? ";" : ":";
|
|
|
|
this.emit("debug", `[PiMi]: Using ${separator} to separate class paths`);
|
2022-03-02 05:52:06 +03:00
|
|
|
// Handling launch arguments.
|
2023-06-18 15:07:15 +03:00
|
|
|
const file = modifyJson || versionFile;
|
2022-03-02 05:52:06 +03:00
|
|
|
// So mods like fabric work.
|
|
|
|
const jar = fs.existsSync(mcPath)
|
|
|
|
? `${separator}${mcPath}`
|
2023-06-18 15:07:15 +03:00
|
|
|
: `${separator}${path.join(
|
|
|
|
directory,
|
|
|
|
`${this.options.version.number}.jar`
|
|
|
|
)}`;
|
|
|
|
classPaths.push(
|
|
|
|
`${
|
|
|
|
this.options.forge ? this.options.forge + separator : ""
|
|
|
|
}${classes.join(separator)}${jar}`
|
|
|
|
);
|
|
|
|
classPaths.push(file.mainClass);
|
2022-03-02 05:52:06 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit("debug", "[PiMi]: Attempting to download assets");
|
|
|
|
await this.handler.getAssets();
|
2022-03-02 05:52:06 +03:00
|
|
|
|
|
|
|
// Forge -> Custom -> Vanilla
|
2023-06-18 15:07:15 +03:00
|
|
|
const launchOptions = await this.handler.getLaunchOptions(modifyJson);
|
2022-03-02 05:52:06 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
const launchArguments = args.concat(jvm, classPaths, launchOptions);
|
|
|
|
this.emit("arguments", launchArguments);
|
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
`[PiMi]: Launching with arguments ${launchArguments.join(" ")}`
|
|
|
|
);
|
2022-03-02 05:52:06 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
return this.startMinecraft(launchArguments);
|
2022-03-02 05:52:06 +03:00
|
|
|
} catch (e) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit("debug", `[PiMi]: Failed to start due to ${e}, closing...`);
|
|
|
|
return null;
|
2022-03-02 05:52:06 +03:00
|
|
|
}
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
_printVersion() {
|
|
|
|
if (fs.existsSync(path.join(__dirname, "..", "package.json"))) {
|
|
|
|
const { version } = require("../package.json");
|
|
|
|
this.emit("debug", `[PiMi]: PiMi version ${version}`);
|
|
|
|
} else {
|
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
"[PiMi]: Package JSON not found, skipping PiMi version check."
|
|
|
|
);
|
|
|
|
}
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
_createRootDirectory() {
|
2021-02-01 01:09:37 +03:00
|
|
|
if (!fs.existsSync(this.options.root)) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit("debug", "[PiMi]: Attempting to create root folder");
|
|
|
|
fs.mkdirSync(this.options.root);
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
_createGameDirectory() {
|
2021-02-01 01:09:37 +03:00
|
|
|
if (this.options.overrides.gameDirectory) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.options.overrides.gameDirectory = path.resolve(
|
|
|
|
this.options.overrides.gameDirectory
|
|
|
|
);
|
2021-02-01 01:09:37 +03:00
|
|
|
if (!fs.existsSync(this.options.overrides.gameDirectory)) {
|
2023-06-18 15:07:15 +03:00
|
|
|
fs.mkdirSync(this.options.overrides.gameDirectory, { recursive: true });
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
async _extractPackage() {
|
2021-02-01 01:09:37 +03:00
|
|
|
if (this.options.clientPackage) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
`[PiMi]: Extracting client package to ${this.options.root}`
|
|
|
|
);
|
|
|
|
await this.handler.extractPackage();
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
async _getModifyJson() {
|
|
|
|
let modifyJson = null;
|
2021-02-01 01:09:37 +03:00
|
|
|
|
|
|
|
if (this.options.forge) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.options.forge = path.resolve(this.options.forge);
|
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
"[PiMi]: Detected Forge in options, getting dependencies"
|
|
|
|
);
|
|
|
|
modifyJson = await this.handler.getForgedWrapped();
|
2021-02-01 01:09:37 +03:00
|
|
|
} else if (this.options.version.custom) {
|
2023-06-18 15:07:15 +03:00
|
|
|
this.emit(
|
|
|
|
"debug",
|
|
|
|
"[PiMi]: Detected custom in options, setting custom version file"
|
|
|
|
);
|
|
|
|
modifyJson =
|
|
|
|
modifyJson ||
|
|
|
|
JSON.parse(
|
|
|
|
fs.readFileSync(
|
|
|
|
path.join(
|
|
|
|
this.options.root,
|
|
|
|
"versions",
|
|
|
|
this.options.version.custom,
|
|
|
|
`${this.options.version.custom}.json`
|
|
|
|
),
|
|
|
|
{ encoding: "utf8" }
|
|
|
|
)
|
|
|
|
);
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
return modifyJson;
|
2021-02-01 01:09:37 +03:00
|
|
|
}
|
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
startMinecraft(launchArguments) {
|
|
|
|
const minecraft = child.spawn(
|
|
|
|
this.options.javaPath ? this.options.javaPath : "java",
|
|
|
|
launchArguments,
|
|
|
|
{
|
|
|
|
cwd: this.options.overrides.cwd || this.options.root,
|
|
|
|
detached: this.options.overrides.detached,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
minecraft.stdout.on("data", (data) =>
|
|
|
|
this.emit("data", data.toString("utf-8"))
|
|
|
|
);
|
|
|
|
minecraft.stderr.on("data", (data) =>
|
|
|
|
this.emit("data", data.toString("utf-8"))
|
|
|
|
);
|
|
|
|
minecraft.on("close", (code) => this.emit("close", code));
|
|
|
|
return minecraft;
|
2020-05-29 05:39:13 +03:00
|
|
|
}
|
2019-05-23 01:28:48 +03:00
|
|
|
}
|
2018-10-30 01:13:58 +03:00
|
|
|
|
2023-06-18 15:07:15 +03:00
|
|
|
module.exports = PiMiCore;
|