feat: rewrite instance class with a config system similar to vite, with better errors and cleaner code
This commit is contained in:
parent
ad91a39e09
commit
66967c955c
15 changed files with 707 additions and 502 deletions
|
|
@ -1,41 +1,39 @@
|
|||
import path from "path";
|
||||
import { isNeeded } from "../utils/rules";
|
||||
import { Argument, Auth, Version } from "../utils/types";
|
||||
import { Argument, Version } from "../utils/types";
|
||||
import { getLibraries } from "./libraries";
|
||||
import { version as packageVersion } from "../../package.json";
|
||||
import { getArgument } from "./log4j";
|
||||
import { Config } from "../launcher/instance";
|
||||
|
||||
// Fill templates
|
||||
function fillArguments(
|
||||
arg: string,
|
||||
versionManifest: Version,
|
||||
assetsPath: string,
|
||||
instancePath: string,
|
||||
librariesPath: string,
|
||||
classPaths: string,
|
||||
auth: Auth,
|
||||
config: Config,
|
||||
classPaths: string
|
||||
) {
|
||||
const argumentsToFill: { [key: string]: string } = {
|
||||
"${natives_directory}": path.join(instancePath, "natives"),
|
||||
"${natives_directory}": path.join(config.paths.instance, "natives"),
|
||||
"${launcher_name}": "nlk",
|
||||
"${launcher_version}": packageVersion,
|
||||
"${classpath}": classPaths,
|
||||
"${library_directory}": librariesPath,
|
||||
"${game_directory}": instancePath,
|
||||
"${library_directory}": config.paths.libraries,
|
||||
"${game_directory}": config.paths.instance,
|
||||
"${version_name}": versionManifest.id,
|
||||
"${version_type}": versionManifest.type,
|
||||
"${assets_index_name}": versionManifest.assets,
|
||||
"${assets_root}": assetsPath,
|
||||
"${game_assets}": assetsPath,
|
||||
"${auth_access_token}": auth.access_token,
|
||||
"${auth_session}": auth.access_token,
|
||||
"${auth_player_name}": auth.name,
|
||||
"${auth_uuid}": auth.uuid,
|
||||
"${auth_xuid}": auth.meta?.xuid || auth.access_token,
|
||||
"${user_properties}": auth.user_properties,
|
||||
"${user_type}": auth.meta?.type || "msa",
|
||||
"${assets_root}": config.paths.assets,
|
||||
"${game_assets}": config.paths.assets,
|
||||
"${auth_access_token}": config.auth.access_token,
|
||||
"${auth_session}": config.auth.access_token,
|
||||
"${auth_player_name}": config.auth.name,
|
||||
"${auth_uuid}": config.auth.uuid,
|
||||
"${auth_xuid}": config.auth.meta?.xuid || config.auth.access_token,
|
||||
"${user_properties}": config.auth.user_properties,
|
||||
"${user_type}": config.auth.meta?.type || "msa",
|
||||
"${clientid}":
|
||||
auth.meta?.clientId || auth.client_token || auth.access_token,
|
||||
config.auth.meta?.clientId || config.auth.client_token || config.auth.access_token,
|
||||
"${classpath_separator}": path.delimiter,
|
||||
};
|
||||
|
||||
|
|
@ -54,11 +52,8 @@ function parseArg(
|
|||
this: string[],
|
||||
arg: Argument,
|
||||
versionManifest: Version,
|
||||
assetsPath: string,
|
||||
instancePath: string,
|
||||
librariesPath: string,
|
||||
classPaths: string,
|
||||
auth: Auth,
|
||||
config: Config,
|
||||
classPaths: string
|
||||
) {
|
||||
if (isNeeded(arg)) {
|
||||
if (typeof arg === "string") {
|
||||
|
|
@ -66,11 +61,8 @@ function parseArg(
|
|||
fillArguments(
|
||||
arg,
|
||||
versionManifest,
|
||||
assetsPath,
|
||||
instancePath,
|
||||
librariesPath,
|
||||
classPaths,
|
||||
auth,
|
||||
config,
|
||||
classPaths
|
||||
),
|
||||
);
|
||||
} else if (typeof arg.value === "string") {
|
||||
|
|
@ -78,24 +70,18 @@ function parseArg(
|
|||
fillArguments(
|
||||
arg.value,
|
||||
versionManifest,
|
||||
assetsPath,
|
||||
instancePath,
|
||||
librariesPath,
|
||||
classPaths,
|
||||
auth,
|
||||
),
|
||||
);
|
||||
config,
|
||||
classPaths
|
||||
)
|
||||
)
|
||||
} else if (arg.value.length > 1) {
|
||||
for (const e of arg.value) {
|
||||
this.push(
|
||||
fillArguments(
|
||||
e,
|
||||
versionManifest,
|
||||
assetsPath,
|
||||
instancePath,
|
||||
librariesPath,
|
||||
classPaths,
|
||||
auth,
|
||||
config,
|
||||
classPaths
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -121,23 +107,16 @@ function generateClassPaths(
|
|||
|
||||
export async function generateLaunchArguments(
|
||||
versionManifest: Version,
|
||||
javaExecutable: string,
|
||||
instancePath: string,
|
||||
librariesPath: string,
|
||||
assetsPath: string,
|
||||
versionRoot: string,
|
||||
auth: Auth,
|
||||
customArgs: { java: string; game: string },
|
||||
ram: { max: string; min: string },
|
||||
config: Config
|
||||
) {
|
||||
const jvm: string[] = [];
|
||||
let game: string[] = [];
|
||||
|
||||
const versionJar = path.join(versionRoot, `${versionManifest.id}.jar`);
|
||||
const versionJar = path.join(config.paths.versions, versionManifest.id, `${versionManifest.id}.jar`);
|
||||
|
||||
const classPaths = generateClassPaths(
|
||||
versionManifest,
|
||||
librariesPath,
|
||||
config.paths.libraries,
|
||||
versionJar,
|
||||
);
|
||||
|
||||
|
|
@ -145,11 +124,8 @@ export async function generateLaunchArguments(
|
|||
parseArg.apply(args, [
|
||||
arg,
|
||||
versionManifest,
|
||||
assetsPath,
|
||||
instancePath,
|
||||
librariesPath,
|
||||
config,
|
||||
classPaths,
|
||||
auth,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -161,45 +137,41 @@ export async function generateLaunchArguments(
|
|||
p(game, arg);
|
||||
}
|
||||
} else {
|
||||
console.log(versionManifest.minecraftArguments)
|
||||
game = fillArguments(
|
||||
versionManifest.minecraftArguments!,
|
||||
versionManifest,
|
||||
assetsPath,
|
||||
instancePath,
|
||||
librariesPath,
|
||||
classPaths,
|
||||
auth,
|
||||
config,
|
||||
classPaths
|
||||
).split(" ");
|
||||
|
||||
jvm.push(`-Djava.library.path=${path.join(instancePath, "natives")}`);
|
||||
jvm.push(`-Djava.library.path=${path.join(config.paths.instance, "natives")}`);
|
||||
jvm.push(`-Dminecraft.launcher.brand=nlk`);
|
||||
jvm.push(`-Dminecraft.launcher.version=${packageVersion}`);
|
||||
jvm.push(
|
||||
`-Dminecraft.client.jar=${path.join(versionRoot, `${versionManifest.id}.jar`)}`,
|
||||
`-Dminecraft.client.jar=${path.join(config.paths.versions, versionManifest.id, `${versionManifest.id}.jar`)}`,
|
||||
);
|
||||
jvm.push("-cp");
|
||||
jvm.push(classPaths)
|
||||
}
|
||||
|
||||
if (customArgs.java !== "") {
|
||||
for (const arg of customArgs.java.split(" ")) {
|
||||
if (config.args.java !== "") {
|
||||
for (const arg of config.args.java.split(" ")) {
|
||||
jvm.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (customArgs.game !== "") {
|
||||
for (const arg of customArgs.game.split(" ")) {
|
||||
if (config.args.game !== "") {
|
||||
for (const arg of config.args.game.split(" ")) {
|
||||
game.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
const log4j = await getArgument(versionManifest, versionRoot);
|
||||
const log4j = await getArgument(versionManifest, config.paths.versions);
|
||||
|
||||
let launchArguments = [
|
||||
...jvm,
|
||||
`-Xms${ram.min}`,
|
||||
`-Xmx${ram.max}`,
|
||||
`-Xms${config.ram.min}`,
|
||||
`-Xmx${config.ram.max}`,
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:G1NewSizePercent=20",
|
||||
|
|
@ -215,7 +187,7 @@ export async function generateLaunchArguments(
|
|||
launchArguments = [...launchArguments, versionManifest.mainClass, ...game,]
|
||||
|
||||
return {
|
||||
command: javaExecutable,
|
||||
command: config.javaExecutable,
|
||||
args: launchArguments,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ export { AssetsDownloader } from "./assets";
|
|||
export { LibrariesDownloader } from "./libraries";
|
||||
export { NativesDownloader } from "./natives";
|
||||
export * as version from "./version";
|
||||
export * as arguments from "./arguments";
|
||||
export * as argumentsGenerator from "./arguments";
|
||||
export * as log4j from "./log4j";
|
||||
export { launch } from "./launch";
|
||||
|
|
|
|||
|
|
@ -8,57 +8,57 @@ import { version as packageVersion } from "../../package.json";
|
|||
import { ensureDir, exists, readJson } from "../utils/fs";
|
||||
import { InstallError } from "../utils/errors";
|
||||
import AdmZip from "adm-zip";
|
||||
import { Config } from "../launcher/instance";
|
||||
|
||||
const versionWithDoubleName = ["1.9.4", "1.9.0", "1.8.9", "1.8.8", "1.8", "1.7.10"]
|
||||
export function fixVersionWithDoubleName(version: string, modloader: Modloader) {
|
||||
let modLoaderVersion = modloader.version
|
||||
if (versionWithDoubleName.includes(version)) {
|
||||
// these versions have a different file name on forge's maven
|
||||
modloader.version = modloader.version + `-${version}`
|
||||
modLoaderVersion = modloader.version + `-${version}`
|
||||
}
|
||||
return modloader
|
||||
return modLoaderVersion
|
||||
}
|
||||
|
||||
async function downloadJar(
|
||||
minecraftVersion: string,
|
||||
modloader: Modloader,
|
||||
config: ModloaderConfig,
|
||||
type: "universal" | "installer",
|
||||
destination: string,
|
||||
) {
|
||||
let filePath = "";
|
||||
try {
|
||||
if (modloader.name === "forge") {
|
||||
if (config.modloader.name === "forge") {
|
||||
if (type === "universal") {
|
||||
filePath = path.join(
|
||||
destination,
|
||||
`forge-${minecraftVersion}-${modloader.version}-universal.jar`,
|
||||
`forge-${config.version}-${config.modloader.version}-universal.jar`,
|
||||
);
|
||||
await downloadFile({
|
||||
url: `https://maven.minecraftforge.net/net/minecraftforge/forge/${minecraftVersion}-${modloader.version}/forge-${minecraftVersion}-${modloader.version}-universal.jar`,
|
||||
url: `https://maven.minecraftforge.net/net/minecraftforge/forge/${config.version}-${config.modloader.version}/forge-${config.version}-${config.modloader.version}-universal.jar`,
|
||||
path: filePath,
|
||||
});
|
||||
} else {
|
||||
filePath = path.join(
|
||||
destination,
|
||||
`forge-${minecraftVersion}-${modloader.version}-installer.jar`,
|
||||
`forge-${config.version}-${config.modloader.version}-installer.jar`,
|
||||
);
|
||||
await downloadFile({
|
||||
url: `https://maven.minecraftforge.net/net/minecraftforge/forge/${minecraftVersion}-${modloader.version}/forge-${minecraftVersion}-${modloader.version}-installer.jar`,
|
||||
url: `https://maven.minecraftforge.net/net/minecraftforge/forge/${config.version}-${config.modloader.version}/forge-${config.version}-${config.modloader.version}-installer.jar`,
|
||||
path: filePath,
|
||||
});
|
||||
}
|
||||
} else if (modloader.name === "neoforge") {
|
||||
} else if (config.modloader.name === "neoforge") {
|
||||
filePath = path.join(
|
||||
destination,
|
||||
`neoforge-${modloader.version}-installer.jar`,
|
||||
`neoforge-${config.modloader.version}-installer.jar`,
|
||||
);
|
||||
await downloadFile({
|
||||
url: `https://maven.neoforged.net/releases/net/neoforged/neoforge/${modloader.version}/neoforge-${modloader.version}-installer.jar`,
|
||||
url: `https://maven.neoforged.net/releases/net/neoforged/neoforge/${config.modloader.version}/neoforge-${config.modloader.version}-installer.jar`,
|
||||
path: filePath,
|
||||
});
|
||||
}
|
||||
} catch (original) {
|
||||
const error = new InstallError("modloader", null, original, "Check that the version of the modloader exists.");
|
||||
error.throw();
|
||||
} catch (error) {
|
||||
throw new InstallError("An error occured while downloadng natives", "natives", config, { cause: error })
|
||||
}
|
||||
|
||||
return filePath;
|
||||
|
|
@ -112,32 +112,30 @@ function isModernForge(version: string) {
|
|||
} else return false
|
||||
}
|
||||
|
||||
export interface ModloaderConfig extends Config {
|
||||
modloader: Modloader
|
||||
}
|
||||
|
||||
export async function installForge(
|
||||
versionManifest: Version,
|
||||
modloader: Modloader,
|
||||
javaExecutable: string,
|
||||
root: string,
|
||||
instanceLocation: string,
|
||||
librariesPath: string,
|
||||
versionsPath: string
|
||||
config: ModloaderConfig,
|
||||
versionManifest: Version
|
||||
) {
|
||||
const forgeLibDir = path.join(root, "libraries", "net", "minecraftforge", "forge", `${versionManifest.id}-${modloader.version}`)
|
||||
const neoForgeLibDir = path.join(root, "libraries", "net", "neoforged", "neoforge", `${modloader.version}`)
|
||||
const forgeLibDir = path.join(config.paths.root, "libraries", "net", "minecraftforge", "forge", `${versionManifest.id}-${config.modloader.version}`)
|
||||
const neoForgeLibDir = path.join(config.paths.root, "libraries", "net", "neoforged", "neoforge", `${config.modloader.version}`)
|
||||
|
||||
// older forge jar path
|
||||
const universalDestination = path.join(forgeLibDir, `forge-${versionManifest.id}-${modloader.version}.jar`)
|
||||
const universalDestination = path.join(forgeLibDir, `forge-${versionManifest.id}-${config.modloader.version}.jar`)
|
||||
// newer forge jar path
|
||||
const forgeClientDestination = path.join(forgeLibDir, `forge-${versionManifest.id}-${modloader.version}-client.jar`)
|
||||
const forgeClientDestination = path.join(forgeLibDir, `forge-${versionManifest.id}-${config.modloader.version}-client.jar`)
|
||||
// neoforge jar path
|
||||
const neoForgeClientDestination = path.join(neoForgeLibDir, `neoforge-${modloader.version}-client.jar`)
|
||||
const neoForgeClientDestination = path.join(neoForgeLibDir, `neoforge-${config.modloader.version}-client.jar`)
|
||||
|
||||
if (await exists(universalDestination) || await exists(forgeClientDestination) || await exists(neoForgeClientDestination)) return;
|
||||
|
||||
const tempFolder = await getTempFolder("forge");
|
||||
// Download and extract installer file
|
||||
const forgeInstallerPath = await downloadJar(
|
||||
versionManifest.id,
|
||||
modloader,
|
||||
config,
|
||||
"installer",
|
||||
tempFolder,
|
||||
);
|
||||
|
|
@ -149,13 +147,13 @@ export async function installForge(
|
|||
|
||||
const modernInstaller = isModernForge(versionManifest.id)
|
||||
|
||||
await runForgeInstaller(javaExecutable, forgeInstallerPath, fakeLauncher, modernInstaller ? "Client" : "Server");
|
||||
await runForgeInstaller(config.javaExecutable, forgeInstallerPath, fakeLauncher, modernInstaller ? "Client" : "Server");
|
||||
|
||||
// Copy libraries and versions files
|
||||
for (const file of await fs.readdir(path.join(fakeLauncher, "libraries"))) {
|
||||
await fs.cp(
|
||||
path.join(fakeLauncher, "libraries", file),
|
||||
path.join(librariesPath, file),
|
||||
path.join(config.paths.libraries, file),
|
||||
{
|
||||
recursive: true,
|
||||
},
|
||||
|
|
@ -173,17 +171,15 @@ export async function installForge(
|
|||
|
||||
await fs.cp(
|
||||
path.join(fakeLauncher, "versions", originalVersionId),
|
||||
path.join(versionsPath, originalVersionId),
|
||||
path.join(config.paths.versions, originalVersionId),
|
||||
{ recursive: true },
|
||||
);
|
||||
} else {
|
||||
// Older versions (from 1.5.2 to 1.12.2, even older versions are not supported)
|
||||
//await runForgeInstaller(javaExecutable, forgeInstallerPath, fakeLauncher, "Server");
|
||||
|
||||
const universalPath = path.join(fakeLauncher, `forge-${versionManifest.id}-${modloader.version}-universal.jar`)
|
||||
const universalPath = path.join(fakeLauncher, `forge-${versionManifest.id}-${config.modloader.version}-universal.jar`)
|
||||
|
||||
// Copy forge jar
|
||||
await ensureDir(path.join(root, "libraries", "net", "minecraftforge", "forge", `${versionManifest.id}-${modloader.version}`), true)
|
||||
await ensureDir(path.join(config.paths.root, "libraries", "net", "minecraftforge", "forge", `${versionManifest.id}-${config.modloader.version}`), true)
|
||||
await fs.cp(
|
||||
universalPath,
|
||||
universalDestination,
|
||||
|
|
@ -192,7 +188,7 @@ export async function installForge(
|
|||
|
||||
// Copy version json
|
||||
const zip = new AdmZip(universalPath)
|
||||
zip.extractEntryTo("version.json", path.join(versionsPath, `${versionManifest.id}-forge-${modloader.version}`))
|
||||
await fs.rename(path.join(versionsPath, `${versionManifest.id}-forge-${modloader.version}`, "version.json"), path.join(versionsPath, `${versionManifest.id}-forge-${modloader.version}`, `${versionManifest.id}-forge-${modloader.version}.json`))
|
||||
zip.extractEntryTo("version.json", path.join(config.paths.versions, `${versionManifest.id}-forge-${config.modloader.version}`))
|
||||
await fs.rename(path.join(config.paths.versions, `${versionManifest.id}-forge-${config.modloader.version}`, "version.json"), path.join(config.paths.versions, `${versionManifest.id}-forge-${config.modloader.version}`, `${versionManifest.id}-forge-${config.modloader.version}.json`))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export { offlineAuth } from "./auth";
|
||||
export { Instance } from "./instance";
|
||||
export { Instance, defineConfig } from "./instance";
|
||||
export { RuntimeManager, getJavaComponent } from "./java";
|
||||
274
src/launcher/instance-old.ts
Normal file
274
src/launcher/instance-old.ts
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
import {
|
||||
Auth,
|
||||
InstanceEvents,
|
||||
Modloader,
|
||||
Paths,
|
||||
SupportedModloaders,
|
||||
Version,
|
||||
} from "../utils/types";
|
||||
import * as core from "../core";
|
||||
import path from "path";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { throwLaunch, throwInstall } from "../utils/errors";
|
||||
import { fixVersionWithDoubleName, installForge } from "../core/modloaders";
|
||||
import { readJson } from "../utils/fs";
|
||||
import { mergeManifests } from "../core/mergeManifests";
|
||||
import { checkJava } from "./java";
|
||||
import { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
|
||||
export class Instance extends EventEmitter<InstanceEvents> {
|
||||
version?: string;
|
||||
modloader?: Modloader;
|
||||
auth?: Auth;
|
||||
paths?: Paths;
|
||||
args: { java: string; game: string };
|
||||
ram: { max: string; min: string };
|
||||
versionManifest?: Version;
|
||||
versionLocation?: string;
|
||||
instanceLocation?: string;
|
||||
ready: boolean;
|
||||
javaExecutable?: string;
|
||||
forgeVersionPatched: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.args = { java: "", game: "" };
|
||||
this.ram = { max: "2G", min: "2G" };
|
||||
this.ready = false;
|
||||
this.forgeVersionPatched = false;
|
||||
}
|
||||
|
||||
setVersion(version: string) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
setModLoader(name: SupportedModloaders, version: string) {
|
||||
this.modloader = { name, version };
|
||||
}
|
||||
|
||||
setJavaExecutable(path: string) {
|
||||
this.javaExecutable = path;
|
||||
}
|
||||
|
||||
setPaths(paths: Paths | string): void {
|
||||
if (typeof paths === "string") {
|
||||
this.paths = {
|
||||
root: paths,
|
||||
versions: path.join(paths, "versions"),
|
||||
assets: path.join(paths, "assets"),
|
||||
libraries: path.join(paths, "libraries"),
|
||||
instances: path.join(paths, "instances"),
|
||||
};
|
||||
} else {
|
||||
this.paths = {
|
||||
root: paths.root,
|
||||
versions: paths.versions || path.join(paths.root, "versions"),
|
||||
assets: paths.assets || path.join(paths.root, "assets"),
|
||||
libraries: paths.libraries || path.join(paths.root, "libraries"),
|
||||
instances: paths.instances || path.join(paths.root, "instances"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setAuth(auth: Auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
setArgs({ java, game }: { java?: string; game?: string }) {
|
||||
this.args.java = java || "";
|
||||
this.args.game = game || "";
|
||||
}
|
||||
|
||||
setRAM({ min, max }: { min?: string; max?: string }) {
|
||||
this.ram.min = min || "2G";
|
||||
this.ram.max = max || "2G";
|
||||
}
|
||||
|
||||
private async initialize() {
|
||||
if (this.modloader && !this.forgeVersionPatched) {
|
||||
this.modloader = fixVersionWithDoubleName(this.version!, this.modloader)
|
||||
this.forgeVersionPatched = true
|
||||
}
|
||||
if (!this.javaExecutable || !this.paths?.root || !this.version || !this.auth) {
|
||||
throw new Error("Missing options")
|
||||
}
|
||||
|
||||
this.versionLocation = path.join(this.paths.versions!, this.version);
|
||||
this.instanceLocation = path.join(this.paths.instances!, this.version);
|
||||
|
||||
this.versionManifest = await core.version.getVersionManifest(
|
||||
this.version,
|
||||
this.versionLocation,
|
||||
);
|
||||
}
|
||||
|
||||
async install() {
|
||||
try {
|
||||
await this.initialize();
|
||||
this.ready = true;
|
||||
await core.version.downloadJar(
|
||||
this.versionManifest!,
|
||||
this.versionLocation!,
|
||||
);
|
||||
} catch (original) {
|
||||
throwInstall("installInit", original, this)
|
||||
}
|
||||
|
||||
try {
|
||||
const librariesDownloader = await core.LibrariesDownloader(
|
||||
this.paths!.libraries!,
|
||||
this.versionManifest!,
|
||||
);
|
||||
|
||||
librariesDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"libraries",
|
||||
librariesDownloader.done,
|
||||
librariesDownloader.total,
|
||||
librariesDownloader.doneSize,
|
||||
librariesDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await librariesDownloader.run();
|
||||
} catch (original) {
|
||||
throwInstall("libraries", original, this)
|
||||
}
|
||||
|
||||
try {
|
||||
const assetsDownloader = await core.AssetsDownloader(
|
||||
this.paths!.assets!,
|
||||
this.versionManifest!,
|
||||
);
|
||||
assetsDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"assets",
|
||||
assetsDownloader.done,
|
||||
assetsDownloader.total,
|
||||
assetsDownloader.doneSize,
|
||||
assetsDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await assetsDownloader.run();
|
||||
} catch (original) {
|
||||
throwInstall("assets", original, this)
|
||||
}
|
||||
|
||||
try {
|
||||
const nativesDownloader = await core.NativesDownloader(
|
||||
path.join(this.instanceLocation!, "natives"),
|
||||
this.versionManifest!,
|
||||
);
|
||||
nativesDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"natives",
|
||||
nativesDownloader.done,
|
||||
nativesDownloader.total,
|
||||
nativesDownloader.doneSize,
|
||||
nativesDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await nativesDownloader.run();
|
||||
} catch (original) {
|
||||
throwInstall("natives", original, this)
|
||||
}
|
||||
|
||||
const javaError = await checkJava(this.javaExecutable!)
|
||||
if (javaError) {
|
||||
throwInstall("java", javaError, this)
|
||||
}
|
||||
|
||||
if (this.modloader) {
|
||||
try {
|
||||
switch (this.modloader.name) {
|
||||
case "forge":
|
||||
case "neoforge":
|
||||
await installForge(
|
||||
this.versionManifest!,
|
||||
this.modloader,
|
||||
this.javaExecutable!,
|
||||
this.paths!.root,
|
||||
this.instanceLocation!,
|
||||
this.paths!.libraries!,
|
||||
this.paths!.versions!
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown modloader");
|
||||
}
|
||||
} catch (original) {
|
||||
throwInstall("modloader", original, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async launch(): Promise<ChildProcessWithoutNullStreams> {
|
||||
try {
|
||||
if (!this.ready) {
|
||||
try {
|
||||
await this.initialize();
|
||||
} catch (original) {
|
||||
throw throwLaunch(original, this)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.modloader) {
|
||||
switch (this.modloader.name) {
|
||||
case "forge": {
|
||||
const forgeVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
this.paths!.versions!,
|
||||
`${this.version}-${this.modloader.name}-${this.modloader.version}`,
|
||||
`${this.version}-${this.modloader.name}-${this.modloader.version}.json`,
|
||||
),
|
||||
);
|
||||
|
||||
this.versionManifest = mergeManifests(
|
||||
this.versionManifest!,
|
||||
forgeVersionManifest,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "neoforge":
|
||||
{
|
||||
const neoForgeVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
this.paths!.versions!,
|
||||
`${this.modloader.name}-${this.modloader.version}`,
|
||||
`${this.modloader.name}-${this.modloader.version}.json`,
|
||||
),
|
||||
);
|
||||
|
||||
this.versionManifest = mergeManifests(
|
||||
this.versionManifest!,
|
||||
neoForgeVersionManifest,
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown modloader");
|
||||
}
|
||||
}
|
||||
|
||||
const args = await core.arguments.generateLaunchArguments(
|
||||
this.versionManifest!,
|
||||
this.javaExecutable!,
|
||||
this.instanceLocation!,
|
||||
this.paths!.libraries!,
|
||||
this.paths!.assets!,
|
||||
this.versionLocation!,
|
||||
this.auth!,
|
||||
this.args,
|
||||
this.ram
|
||||
);
|
||||
|
||||
const process = core.launch(args, this.instanceLocation!);
|
||||
|
||||
return process;
|
||||
} catch (original) {
|
||||
throw throwLaunch(original, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,274 +1,249 @@
|
|||
import {
|
||||
Auth,
|
||||
InstanceEvents,
|
||||
Modloader,
|
||||
Paths,
|
||||
SupportedModloaders,
|
||||
Version,
|
||||
} from "../utils/types";
|
||||
import * as core from "../core";
|
||||
import path from "path";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { throwLaunch, throwInstall } from "../utils/errors";
|
||||
import { fixVersionWithDoubleName, installForge } from "../core/modloaders";
|
||||
import { EventEmitter } from "node:stream";
|
||||
import { Auth, InstanceEvents, Modloader, Paths, ProcessArgs, ProcessRam, Version } from "../utils/types";
|
||||
import path from "node:path";
|
||||
import { argumentsGenerator, AssetsDownloader, launch, LibrariesDownloader, NativesDownloader, version } from "../core";
|
||||
import { ConfigError, InstallError, LaunchError } from "../utils/errors";
|
||||
import { checkJava } from "./java";
|
||||
import { fixVersionWithDoubleName, installForge, ModloaderConfig } from "../core/modloaders";
|
||||
import { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import { readJson } from "../utils/fs";
|
||||
import { mergeManifests } from "../core/mergeManifests";
|
||||
import { checkJava } from "./java";
|
||||
import { ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
|
||||
export interface BaseConfig {
|
||||
version: string;
|
||||
auth: Auth;
|
||||
paths: Paths
|
||||
javaExecutable: string
|
||||
modloader?: Modloader;
|
||||
args?: ProcessArgs;
|
||||
ram?: { max?: string; min?: string }
|
||||
}
|
||||
|
||||
export interface Config extends BaseConfig {
|
||||
paths: Required<Paths>
|
||||
args: Required<ProcessArgs>
|
||||
ram: Required<ProcessRam>
|
||||
}
|
||||
|
||||
export function defineConfig(...layers: Partial<BaseConfig>[]) {
|
||||
let config: Partial<BaseConfig> = {} as Partial<BaseConfig>;
|
||||
for (const layer of layers) {
|
||||
config = { ...config, ...layer }
|
||||
}
|
||||
if (!config.auth || !config.paths?.root || !config.paths?.instance || !config.version || !config.javaExecutable) {
|
||||
throw new ConfigError("Invalid config provided", config)
|
||||
}
|
||||
|
||||
config.paths = {
|
||||
root: config.paths.root,
|
||||
instance: config.paths.instance,
|
||||
versions: config.paths.versions ?? path.join(config.paths.root, "versions"),
|
||||
assets: config.paths.assets ?? path.join(config.paths.root, "assets"),
|
||||
libraries: config.paths.libraries ?? path.join(config.paths.root, "libraries"),
|
||||
};
|
||||
|
||||
config.args = { java: config.args?.java ?? "", game: config.args?.game ?? "" };
|
||||
|
||||
config.ram = { max: config.ram?.max ?? "2G", min: config.ram?.min ?? "2G" };
|
||||
|
||||
return config as Config
|
||||
}
|
||||
|
||||
export class Instance extends EventEmitter<InstanceEvents> {
|
||||
version?: string;
|
||||
modloader?: Modloader;
|
||||
auth?: Auth;
|
||||
paths?: Paths;
|
||||
args: { java: string; game: string };
|
||||
ram: { max: string; min: string };
|
||||
versionManifest?: Version;
|
||||
versionLocation?: string;
|
||||
instanceLocation?: string;
|
||||
ready: boolean;
|
||||
javaExecutable?: string;
|
||||
forgeVersionPatched: boolean;
|
||||
ready: boolean
|
||||
config: Config
|
||||
versionLocation: string
|
||||
versionManifest: Version
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.args = { java: "", game: "" };
|
||||
this.ram = { max: "2G", min: "2G" };
|
||||
this.ready = false;
|
||||
this.forgeVersionPatched = false;
|
||||
}
|
||||
|
||||
setVersion(version: string) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
setModLoader(name: SupportedModloaders, version: string) {
|
||||
this.modloader = { name, version };
|
||||
}
|
||||
|
||||
setJavaExecutable(path: string) {
|
||||
this.javaExecutable = path;
|
||||
}
|
||||
|
||||
setPaths(paths: Paths | string): void {
|
||||
if (typeof paths === "string") {
|
||||
this.paths = {
|
||||
root: paths,
|
||||
versions: path.join(paths, "versions"),
|
||||
assets: path.join(paths, "assets"),
|
||||
libraries: path.join(paths, "libraries"),
|
||||
instances: path.join(paths, "instances"),
|
||||
};
|
||||
} else {
|
||||
this.paths = {
|
||||
root: paths.root,
|
||||
versions: paths.versions || path.join(paths.root, "versions"),
|
||||
assets: paths.assets || path.join(paths.root, "assets"),
|
||||
libraries: paths.libraries || path.join(paths.root, "libraries"),
|
||||
instances: paths.instances || path.join(paths.root, "instances"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setAuth(auth: Auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
setArgs({ java, game }: { java?: string; game?: string }) {
|
||||
this.args.java = java || "";
|
||||
this.args.game = game || "";
|
||||
}
|
||||
|
||||
setRAM({ min, max }: { min?: string; max?: string }) {
|
||||
this.ram.min = min || "2G";
|
||||
this.ram.max = max || "2G";
|
||||
}
|
||||
|
||||
private async initialize() {
|
||||
if (this.modloader && !this.forgeVersionPatched) {
|
||||
this.modloader = fixVersionWithDoubleName(this.version!, this.modloader)
|
||||
this.forgeVersionPatched = true
|
||||
}
|
||||
if (!this.javaExecutable || !this.paths?.root || !this.version || !this.auth) {
|
||||
throw new Error("Missing options")
|
||||
constructor(...layers: Partial<BaseConfig>[]) {
|
||||
super()
|
||||
this.config = defineConfig(...layers)
|
||||
this.ready = false
|
||||
this.versionManifest = {} as Version
|
||||
this.versionLocation = ""
|
||||
}
|
||||
|
||||
this.versionLocation = path.join(this.paths.versions!, this.version);
|
||||
this.instanceLocation = path.join(this.paths.instances!, this.version);
|
||||
private async init() {
|
||||
this.versionLocation = path.join(this.config.paths.versions, this.config.version);
|
||||
|
||||
this.versionManifest = await core.version.getVersionManifest(
|
||||
this.version,
|
||||
this.versionLocation,
|
||||
);
|
||||
}
|
||||
|
||||
async install() {
|
||||
try {
|
||||
await this.initialize();
|
||||
this.ready = true;
|
||||
await core.version.downloadJar(
|
||||
this.versionManifest!,
|
||||
this.versionLocation!,
|
||||
);
|
||||
} catch (original) {
|
||||
throwInstall("installInit", original, this)
|
||||
}
|
||||
|
||||
try {
|
||||
const librariesDownloader = await core.LibrariesDownloader(
|
||||
this.paths!.libraries!,
|
||||
this.versionManifest!,
|
||||
);
|
||||
|
||||
librariesDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"libraries",
|
||||
librariesDownloader.done,
|
||||
librariesDownloader.total,
|
||||
librariesDownloader.doneSize,
|
||||
librariesDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await librariesDownloader.run();
|
||||
} catch (original) {
|
||||
throwInstall("libraries", original, this)
|
||||
}
|
||||
|
||||
try {
|
||||
const assetsDownloader = await core.AssetsDownloader(
|
||||
this.paths!.assets!,
|
||||
this.versionManifest!,
|
||||
);
|
||||
assetsDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"assets",
|
||||
assetsDownloader.done,
|
||||
assetsDownloader.total,
|
||||
assetsDownloader.doneSize,
|
||||
assetsDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await assetsDownloader.run();
|
||||
} catch (original) {
|
||||
throwInstall("assets", original, this)
|
||||
}
|
||||
|
||||
try {
|
||||
const nativesDownloader = await core.NativesDownloader(
|
||||
path.join(this.instanceLocation!, "natives"),
|
||||
this.versionManifest!,
|
||||
);
|
||||
nativesDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"natives",
|
||||
nativesDownloader.done,
|
||||
nativesDownloader.total,
|
||||
nativesDownloader.doneSize,
|
||||
nativesDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await nativesDownloader.run();
|
||||
} catch (original) {
|
||||
throwInstall("natives", original, this)
|
||||
}
|
||||
|
||||
const javaError = await checkJava(this.javaExecutable!)
|
||||
if (javaError) {
|
||||
throwInstall("java", javaError, this)
|
||||
}
|
||||
|
||||
if (this.modloader) {
|
||||
try {
|
||||
switch (this.modloader.name) {
|
||||
case "forge":
|
||||
case "neoforge":
|
||||
await installForge(
|
||||
this.versionManifest!,
|
||||
this.modloader,
|
||||
this.javaExecutable!,
|
||||
this.paths!.root,
|
||||
this.instanceLocation!,
|
||||
this.paths!.libraries!,
|
||||
this.paths!.versions!
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown modloader");
|
||||
if (this.config.modloader) {
|
||||
this.config.modloader.version = fixVersionWithDoubleName(this.config.version, this.config.modloader)
|
||||
}
|
||||
} catch (original) {
|
||||
throwInstall("modloader", original, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async launch(): Promise<ChildProcessWithoutNullStreams> {
|
||||
try {
|
||||
if (!this.ready) {
|
||||
this.versionManifest = await version.getVersionManifest(
|
||||
this.config.version,
|
||||
this.versionLocation,
|
||||
);
|
||||
|
||||
this.ready = true
|
||||
}
|
||||
|
||||
async install() {
|
||||
try {
|
||||
await this.initialize();
|
||||
} catch (original) {
|
||||
throw throwLaunch(original, this)
|
||||
if (!this.ready) await this.init()
|
||||
|
||||
await version.downloadJar(
|
||||
this.versionManifest,
|
||||
this.versionLocation,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new InstallError("An error occured while initializing instance", "install-init", this.config, { cause: error })
|
||||
}
|
||||
}
|
||||
|
||||
if (this.modloader) {
|
||||
switch (this.modloader.name) {
|
||||
case "forge": {
|
||||
const forgeVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
this.paths!.versions!,
|
||||
`${this.version}-${this.modloader.name}-${this.modloader.version}`,
|
||||
`${this.version}-${this.modloader.name}-${this.modloader.version}.json`,
|
||||
),
|
||||
try {
|
||||
const librariesDownloader = await LibrariesDownloader(
|
||||
this.config.paths.libraries,
|
||||
this.versionManifest,
|
||||
);
|
||||
|
||||
this.versionManifest = mergeManifests(
|
||||
this.versionManifest!,
|
||||
forgeVersionManifest,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "neoforge":
|
||||
{
|
||||
const neoForgeVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
this.paths!.versions!,
|
||||
`${this.modloader.name}-${this.modloader.version}`,
|
||||
`${this.modloader.name}-${this.modloader.version}.json`,
|
||||
),
|
||||
);
|
||||
librariesDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"libraries",
|
||||
librariesDownloader.done,
|
||||
librariesDownloader.total,
|
||||
librariesDownloader.doneSize,
|
||||
librariesDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
|
||||
this.versionManifest = mergeManifests(
|
||||
await librariesDownloader.run();
|
||||
} catch (error) {
|
||||
throw new InstallError("An error occured while downloading libraries", "libraries", this.config, { cause: error })
|
||||
}
|
||||
|
||||
try {
|
||||
const assetsDownloader = await AssetsDownloader(
|
||||
this.config.paths.assets,
|
||||
this.versionManifest,
|
||||
);
|
||||
|
||||
assetsDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"assets",
|
||||
assetsDownloader.done,
|
||||
assetsDownloader.total,
|
||||
assetsDownloader.doneSize,
|
||||
assetsDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
|
||||
await assetsDownloader.run();
|
||||
} catch (error) {
|
||||
throw new InstallError("An error occured while downloading assets", "assets", this.config, { cause: error })
|
||||
}
|
||||
|
||||
try {
|
||||
const nativesDownloader = await NativesDownloader(
|
||||
path.join(this.config.paths.instance, "natives"),
|
||||
this.versionManifest!,
|
||||
neoForgeVersionManifest,
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown modloader");
|
||||
);
|
||||
nativesDownloader.on("completed", () => {
|
||||
this.emit(
|
||||
"progress",
|
||||
"natives",
|
||||
nativesDownloader.done,
|
||||
nativesDownloader.total,
|
||||
nativesDownloader.doneSize,
|
||||
nativesDownloader.totalSize,
|
||||
);
|
||||
});
|
||||
await nativesDownloader.run();
|
||||
} catch (error) {
|
||||
throw new InstallError("An error occured while downloadng natives", "natives", this.config, { cause: error })
|
||||
}
|
||||
}
|
||||
|
||||
const args = await core.arguments.generateLaunchArguments(
|
||||
this.versionManifest!,
|
||||
this.javaExecutable!,
|
||||
this.instanceLocation!,
|
||||
this.paths!.libraries!,
|
||||
this.paths!.assets!,
|
||||
this.versionLocation!,
|
||||
this.auth!,
|
||||
this.args,
|
||||
this.ram
|
||||
);
|
||||
const javaError = await checkJava(this.config.javaExecutable)
|
||||
if (javaError) {
|
||||
throw new InstallError("Invalid java provieded", "java", this.config, { cause: javaError })
|
||||
}
|
||||
|
||||
const process = core.launch(args, this.instanceLocation!);
|
||||
|
||||
return process;
|
||||
} catch (original) {
|
||||
throw throwLaunch(original, this)
|
||||
if (this.config.modloader) {
|
||||
try {
|
||||
switch (this.config.modloader.name) {
|
||||
case "forge":
|
||||
case "neoforge":
|
||||
await installForge(
|
||||
this.config as ModloaderConfig,
|
||||
this.versionManifest
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown modloader");
|
||||
}
|
||||
} catch (error) {
|
||||
throw new InstallError("An error occured while installing the modloader", "modloader", this.config, { cause: error })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async launch(): Promise<ChildProcessWithoutNullStreams> {
|
||||
try {
|
||||
if (!this.ready) await this.init()
|
||||
} catch (error) {
|
||||
throw new LaunchError("An error occured while initializing instance", "launch-init", this.config, { cause: error })
|
||||
}
|
||||
|
||||
if (this.config.modloader) {
|
||||
try {
|
||||
switch (this.config.modloader.name) {
|
||||
case "forge": {
|
||||
const forgeVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
this.config.paths.versions,
|
||||
`${this.config.version}-${this.config.modloader.name}-${this.config.modloader.version}`,
|
||||
`${this.config.version}-${this.config.modloader.name}-${this.config.modloader.version}.json`,
|
||||
),
|
||||
);
|
||||
|
||||
this.versionManifest = mergeManifests(
|
||||
this.versionManifest!,
|
||||
forgeVersionManifest,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "neoforge":
|
||||
{
|
||||
const neoForgeVersionManifest = await readJson<Version>(
|
||||
path.join(
|
||||
this.config.paths.versions,
|
||||
`${this.config.modloader.name}-${this.config.modloader.version}`,
|
||||
`${this.config.modloader.name}-${this.config.modloader.version}.json`,
|
||||
),
|
||||
);
|
||||
|
||||
this.versionManifest = mergeManifests(
|
||||
this.versionManifest!,
|
||||
neoForgeVersionManifest,
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown modloader");
|
||||
}
|
||||
} catch (error) {
|
||||
throw new LaunchError("An error occured while preparing the modloader", "modloader", this.config, { cause: error })
|
||||
}
|
||||
}
|
||||
|
||||
let args;
|
||||
try {
|
||||
args = await argumentsGenerator.generateLaunchArguments(
|
||||
this.versionManifest,
|
||||
this.config
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
throw new LaunchError("An error occured while generating launch arguments", "arguments", this.config, { cause: error })
|
||||
}
|
||||
|
||||
try {
|
||||
const process = launch(args!, this.config.paths.instance);
|
||||
|
||||
return process;
|
||||
} catch (error) {
|
||||
throw new LaunchError("An error occured while launching minecraft", "launch-process", this.config, { cause: error })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ import { ensureDir } from "../utils/fs";
|
|||
import { EventEmitter } from "stream";
|
||||
import { exec } from "child_process";
|
||||
import { arch, os } from "../utils/systemInfo";
|
||||
import { InstallError } from "../utils/errors";
|
||||
import { getVersionManifest } from "../core/version";
|
||||
import { getTempFolder } from "../utils/temp";
|
||||
|
||||
|
|
@ -114,12 +113,12 @@ async function JavaDownloader(
|
|||
}
|
||||
|
||||
export async function getJavaComponent(mcVersion: string, versionsRoot?: string) {
|
||||
if(!versionsRoot) {
|
||||
if (!versionsRoot) {
|
||||
versionsRoot = await getTempFolder("nlk-versions-cache")
|
||||
}
|
||||
|
||||
const versionManifest = await getVersionManifest(mcVersion, versionsRoot);
|
||||
|
||||
|
||||
return versionManifest.javaVersion.component
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +155,8 @@ export class RuntimeManager extends EventEmitter<InstanceEvents> {
|
|||
);
|
||||
});
|
||||
await javaDownloader.run();
|
||||
} catch (original) {
|
||||
new InstallError("java", null, original, "An error happened while downloading java.")
|
||||
} catch (error) {
|
||||
throw new Error("An error occured while downloading java", { cause: error })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,87 +1,19 @@
|
|||
import { version as packageVersion } from "../../package.json";
|
||||
import { Instance } from "../launcher";
|
||||
import { LaunchErrorConfig } from "./types";
|
||||
import { BaseConfig, Config } from "../launcher/instance"
|
||||
|
||||
function redactToken(config: LaunchErrorConfig) {
|
||||
config.auth.access_token = "token"
|
||||
config.auth.client_token = "token"
|
||||
return config
|
||||
export class ConfigError extends Error {
|
||||
constructor(message: string, config: Partial<BaseConfig>, options?: ErrorOptions) {
|
||||
super(message, options)
|
||||
console.log("Provided config was:")
|
||||
console.log(config)
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallError extends Error {
|
||||
config: LaunchErrorConfig | null;
|
||||
step: string;
|
||||
original: Error;
|
||||
moreInfo?: string;
|
||||
constructor(step: string, config: LaunchErrorConfig | null, original: unknown, moreInfo?: string) {
|
||||
super();
|
||||
this.step = step;
|
||||
this.original = original as Error;
|
||||
this.config = config;
|
||||
this.moreInfo = moreInfo;
|
||||
}
|
||||
|
||||
throw() {
|
||||
console.error(
|
||||
`[nlk ${packageVersion}] Error occured when installing ${this.step}: ${this.original.message}`,
|
||||
);
|
||||
console.error(`[nlk ${packageVersion}] Original error is:`, this.original);
|
||||
|
||||
if (this.moreInfo) {
|
||||
console.error(this.moreInfo);
|
||||
}
|
||||
|
||||
if (this.config) console.dir(redactToken(this.config));
|
||||
|
||||
throw this;
|
||||
constructor(message: string, step: string, config: Config, options?: ErrorOptions) {
|
||||
super(`[${step}] ${message}`, options)
|
||||
console.log("Provided config was:")
|
||||
console.log(config)
|
||||
}
|
||||
}
|
||||
|
||||
export class LaunchError extends Error {
|
||||
config: LaunchErrorConfig;
|
||||
original: Error;
|
||||
constructor(config: LaunchErrorConfig, original: Error) {
|
||||
super();
|
||||
this.config = config;
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
throw() {
|
||||
console.error(
|
||||
`[nlk ${packageVersion}] Error occured when launching the game: ${this.original.message}`,
|
||||
);
|
||||
console.error(`[nlk ${packageVersion}] Original error is:`, this.original);
|
||||
console.dir(redactToken(this.config));
|
||||
|
||||
throw this;
|
||||
}
|
||||
}
|
||||
|
||||
export function throwInstall(step: string, original: unknown, config: Instance) {
|
||||
const error = new InstallError(step,
|
||||
{
|
||||
version: config.version!,
|
||||
auth: config.auth!,
|
||||
paths: config.paths!,
|
||||
customGameArgs: config.args.game!,
|
||||
customJvmArgs: config.args.java!,
|
||||
versionManifest: config.versionManifest!,
|
||||
modloader: config.modloader!,
|
||||
},
|
||||
original);
|
||||
error.throw();
|
||||
}
|
||||
|
||||
export function throwLaunch(original: unknown, config: Instance) {
|
||||
const error = new LaunchError({
|
||||
version: config.version!,
|
||||
auth: config.auth!,
|
||||
paths: config.paths!,
|
||||
customGameArgs: config.args.game!,
|
||||
customJvmArgs: config.args.java!,
|
||||
versionManifest: config.versionManifest!,
|
||||
modloader: config.modloader!,
|
||||
},
|
||||
original as Error);
|
||||
throw error.throw();
|
||||
}
|
||||
export class LaunchError extends InstallError {}
|
||||
|
|
@ -184,11 +184,10 @@ export type LaunchArguments = { command: string; args: string[] };
|
|||
|
||||
export type Paths = {
|
||||
root: string;
|
||||
instance: string;
|
||||
versions?: string;
|
||||
assets?: string;
|
||||
libraries?: string;
|
||||
instances?: string;
|
||||
javaRoot?: string;
|
||||
};
|
||||
|
||||
export type LaunchErrorConfig = {
|
||||
|
|
@ -231,4 +230,14 @@ export interface InstanceEvents {
|
|||
doneSize: number,
|
||||
totalSize: number,
|
||||
];
|
||||
}
|
||||
|
||||
export type ProcessArgs = {
|
||||
game?: string,
|
||||
java?: string
|
||||
}
|
||||
|
||||
export type ProcessRam = {
|
||||
max?: string,
|
||||
min?: string
|
||||
}
|
||||
56
tests/config.test.ts
Normal file
56
tests/config.test.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { test } from "vitest";
|
||||
import { Instance } from "../dist/";
|
||||
import path from "node:path";
|
||||
|
||||
const temp = path.join(import.meta.dirname, "temp")
|
||||
|
||||
test("instance", async () => {
|
||||
const instance = new Instance({
|
||||
version: "1.21.1",
|
||||
auth: {
|
||||
access_token: "token",
|
||||
client_token: "token",
|
||||
name: "player",
|
||||
user_properties: "{}",
|
||||
uuid: "uuid"
|
||||
},
|
||||
paths: { root: temp, instance: temp },
|
||||
javaExecutable: "java"
|
||||
},
|
||||
{
|
||||
modloader: {
|
||||
name: "forge",
|
||||
version: "52.1.12"
|
||||
}
|
||||
},
|
||||
{
|
||||
modloader: {
|
||||
name: "neoforge",
|
||||
version: "21.1.220"
|
||||
}
|
||||
})
|
||||
|
||||
await instance.install();
|
||||
|
||||
instance.on("progress", console.log);
|
||||
// const p = await instance.launch();
|
||||
|
||||
// p.stdout.on("data", (d: Buffer) => {
|
||||
// console.log(d.toString());
|
||||
// });
|
||||
|
||||
// p.stderr.on("data", (d: Buffer) => {
|
||||
// console.log(d.toString());
|
||||
// });
|
||||
|
||||
// await new Promise<void>((res) => {
|
||||
// p.on("error", (d: Buffer) => {
|
||||
// console.log(d.toString());
|
||||
// res();
|
||||
// });
|
||||
// p.on("close", () => {
|
||||
// console.log("closed");
|
||||
// res();
|
||||
// });
|
||||
// });
|
||||
})
|
||||
|
|
@ -7,21 +7,21 @@ const gameRoot = path.join(import.meta.dirname, "..", "..", "temp");
|
|||
// await fs.rm(gameRoot, { recursive: true, force: true });
|
||||
// await fs.mkdir(gameRoot, { recursive: true });
|
||||
|
||||
test("launch game", { timeout: 0, tags:["full", "forge"] }, async () => {
|
||||
const instance = new Instance();
|
||||
test("launch game", { timeout: 0, tags: ["full", "forge"] }, async () => {
|
||||
const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
|
||||
|
||||
javaManager.on("progress", console.log)
|
||||
|
||||
// const java = await javaManager.use(await getJavaComponent("${version}"))
|
||||
|
||||
const auth = offlineAuth("player");
|
||||
|
||||
instance.setVersion("${version}");
|
||||
instance.setPaths(gameRoot);
|
||||
instance.setAuth(auth);
|
||||
instance.setJavaExecutable("${java}")
|
||||
instance.setModLoader("${modloader}", "${modloader_version}");
|
||||
const instance = new Instance({
|
||||
version: "${version}",
|
||||
auth: offlineAuth("player"),
|
||||
paths: { root: gameRoot, instance: path.join(gameRoot, "instances", "${version}") },
|
||||
javaExecutable: "${java}",
|
||||
modloader: {
|
||||
name: "${modloader}",
|
||||
version: "${modloader_version}"
|
||||
}
|
||||
});
|
||||
|
||||
instance.on("progress", console.log);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,21 +7,21 @@ const gameRoot = path.join(import.meta.dirname, "..", "..", "temp");
|
|||
// await fs.rm(gameRoot, { recursive: true, force: true });
|
||||
// await fs.mkdir(gameRoot, { recursive: true });
|
||||
|
||||
test("launch game", { timeout: 0, tags:["full", "forge"] }, async () => {
|
||||
const instance = new Instance();
|
||||
test("launch game", { timeout: 0, tags: ["full", "vanilla"] }, async () => {
|
||||
const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
|
||||
|
||||
javaManager.on("progress", console.log)
|
||||
|
||||
const java = await javaManager.use(await getJavaComponent("${version}"))
|
||||
|
||||
const auth = offlineAuth("player");
|
||||
|
||||
instance.setVersion("${version}");
|
||||
instance.setPaths(gameRoot);
|
||||
instance.setAuth(auth);
|
||||
instance.setJavaExecutable(java)
|
||||
instance.setModLoader("${modloader}", "${modloader_version}");
|
||||
const instance = new Instance({
|
||||
version: "${version}",
|
||||
auth: offlineAuth("player"),
|
||||
paths: { root: gameRoot, instance: path.join(gameRoot, "instances", "${version}") },
|
||||
javaExecutable: java,
|
||||
modloader: {
|
||||
name: "${modloader}",
|
||||
version: "${modloader_version}"
|
||||
}
|
||||
});
|
||||
|
||||
instance.on("progress", console.log);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ await fs.mkdir(path.join(tempFolder, "modloaders/neoforge"))
|
|||
let result = ""
|
||||
if (java) {
|
||||
const template = await fs.readFile(path.join(tempFolder, "forge-java.test.ts.template"), { encoding: "utf-8" })
|
||||
result = template.replaceAll("${version}", version).replace("${modloader}", "forge").replace("${modloader_version}", forgeVersion).replace("${java}", await getJava(version))
|
||||
result = template.replaceAll("${version}", version).replaceAll("${modloader}", "forge").replaceAll("${modloader_version}", forgeVersion).replaceAll("${java}", await getJava(version))
|
||||
} else {
|
||||
const template = await fs.readFile(path.join(tempFolder, "forge.test.ts.template"), { encoding: "utf-8" })
|
||||
result = template.replaceAll("${version}", version).replace("${modloader}", "forge").replace("${modloader_version}", forgeVersion)
|
||||
result = template.replaceAll("${version}", version).replaceAll("${modloader}", "forge").replaceAll("${modloader_version}", forgeVersion)
|
||||
}
|
||||
await fs.writeFile(path.join(tempFolder, `modloaders/forge/forge-${version}-${forgeVersion}.test.ts`), result)
|
||||
console.log(`Done forge ${forgeVersion}`)
|
||||
|
|
@ -100,10 +100,10 @@ await fs.mkdir(path.join(tempFolder, "modloaders/neoforge"))
|
|||
let result = ""
|
||||
if (java) {
|
||||
const template = await fs.readFile(path.join(tempFolder, "forge-java.test.ts.template"), { encoding: "utf-8" })
|
||||
result = template.replaceAll("${version}", mcVersion).replace("${modloader}", "neoforge").replace("${modloader_version}", neoForgeVersion).replace("${java}", await getJava(mcVersion))
|
||||
result = template.replaceAll("${version}", mcVersion).replaceAll("${modloader}", "neoforge").replaceAll("${modloader_version}", neoForgeVersion).replaceAll("${java}", await getJava(mcVersion))
|
||||
} else {
|
||||
const template = await fs.readFile(path.join(tempFolder, "forge.test.ts.template"), { encoding: "utf-8" })
|
||||
result = template.replaceAll("${version}", mcVersion).replace("${modloader}", "neoforge").replace("${modloader_version}", neoForgeVersion)
|
||||
result = template.replaceAll("${version}", mcVersion).replaceAll("${modloader}", "neoforge").replaceAll("${modloader_version}", neoForgeVersion)
|
||||
}
|
||||
await fs.writeFile(path.join(tempFolder, `modloaders/neoforge/neoforge-${mcVersion}-${neoForgeVersion}.test.ts`), result)
|
||||
console.log(`Done neoforge ${neoForgeVersion}`)
|
||||
|
|
@ -118,7 +118,7 @@ await fs.mkdir(path.join(tempFolder, "modloaders/neoforge"))
|
|||
let result = ""
|
||||
if (java) {
|
||||
const template = await fs.readFile(path.join(tempFolder, "vanilla-java.test.ts.template"), { encoding: "utf-8" })
|
||||
result = template.replaceAll("${version}", v.id).replace("${java}", await getJava(v.id))
|
||||
result = template.replaceAll("${version}", v.id).replaceAll("${java}", await getJava(v.id))
|
||||
} else {
|
||||
const template = await fs.readFile(path.join(tempFolder, "vanilla.test.ts.template"), { encoding: "utf-8" })
|
||||
result = template.replaceAll("${version}", v.id)
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
import { test } from "vitest";
|
||||
import { Instance, offlineAuth, RuntimeManager } from "../../dist/index.js";
|
||||
import { Instance, offlineAuth, RuntimeManager, getJavaComponent } from "../../dist/index.js";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import { getJavaComponent } from "../../src/index.js";
|
||||
|
||||
const gameRoot = path.join(import.meta.dirname, "..", "temp");
|
||||
// await fs.rm(gameRoot, { recursive: true, force: true });
|
||||
// await fs.mkdir(gameRoot, { recursive: true });
|
||||
|
||||
test("launch game", { timeout: 0, tags:["full", "vanilla"] }, async () => {
|
||||
const instance = new Instance();
|
||||
test("launch game", { timeout: 0, tags: ["full", "forge"] }, async () => {
|
||||
const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
|
||||
|
||||
javaManager.on("progress", console.log)
|
||||
|
||||
// const java = await javaManager.use(await getJavaComponent("${version}"))
|
||||
|
||||
const auth = offlineAuth("player");
|
||||
|
||||
instance.setVersion("${version}");
|
||||
instance.setPaths(gameRoot);
|
||||
instance.setJavaExecutable("${java}")
|
||||
instance.setAuth(auth);
|
||||
const instance = new Instance({
|
||||
version: "${version}",
|
||||
auth: offlineAuth("player"),
|
||||
paths: { root: gameRoot, instance: path.join(gameRoot, "instances", "${version}") },
|
||||
javaExecutable: "${java}"
|
||||
});
|
||||
|
||||
instance.on("progress", console.log);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
import { test } from "vitest";
|
||||
import { Instance, offlineAuth, RuntimeManager } from "../../dist/index.js";
|
||||
import { Instance, offlineAuth, RuntimeManager, getJavaComponent } from "../../dist/index.js";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import { getJavaComponent } from "../../src/index.js";
|
||||
|
||||
const gameRoot = path.join(import.meta.dirname, "..", "temp");
|
||||
// await fs.rm(gameRoot, { recursive: true, force: true });
|
||||
// await fs.mkdir(gameRoot, { recursive: true });
|
||||
|
||||
test("launch game", { timeout: 0, tags: ["full", "vanilla"] }, async () => {
|
||||
const instance = new Instance();
|
||||
test("launch game", { timeout: 0, tags: ["full", "forge"] }, async () => {
|
||||
const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
|
||||
|
||||
javaManager.on("progress", console.log)
|
||||
|
||||
const java = await javaManager.use(await getJavaComponent("${version}"))
|
||||
|
||||
const auth = offlineAuth("player");
|
||||
|
||||
instance.setVersion("${version}");
|
||||
instance.setPaths(gameRoot);
|
||||
instance.setJavaExecutable(java)
|
||||
instance.setAuth(auth);
|
||||
const instance = new Instance({
|
||||
version: "${version}",
|
||||
auth: offlineAuth("player"),
|
||||
paths: { root: gameRoot, instance: path.join(gameRoot, "instances", "${version}") },
|
||||
javaExecutable: java
|
||||
});
|
||||
|
||||
instance.on("progress", console.log);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue