diff --git a/src/core/arguments.ts b/src/core/arguments.ts
index 85dd331..9382f94 100644
--- a/src/core/arguments.ts
+++ b/src/core/arguments.ts
@@ -1,17 +1,18 @@
import path from "path";
import { isNeeded } from "../utils/rules";
-import { Argument, Auth, PoolFile, Version } from "../utils/types";
+import { Argument, Auth, Version } from "../utils/types";
import { getLibraries } from "./libraries";
import { version as packageVersion } from "../../package.json";
import { getArgument } from "./log4j";
+// Fill templates
function fillArguments(
arg: string,
versionManifest: Version,
assetsPath: string,
instancePath: string,
librariesPath: string,
- classPaths: PoolFile[],
+ classPaths: string,
auth: Auth,
) {
const argumentsToFill = {
@@ -25,6 +26,7 @@ function fillArguments(
"${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,
@@ -44,11 +46,10 @@ function fillArguments(
}
}
- console.log(arg)
-
return arg;
}
+// Check if each arg is needed and fill templates
function parseArg(
this: string[],
arg: Argument,
@@ -56,7 +57,7 @@ function parseArg(
assetsPath: string,
instancePath: string,
librariesPath: string,
- classPaths: PoolFile[],
+ classPaths: string,
auth: Auth,
) {
if (isNeeded(arg)) {
@@ -133,16 +134,15 @@ export async function generateLaunchArguments(
customGameArgs?: string;
},
) {
- // Log4j /!\
- // Replace templates /!\
-
const jvm: string[] = [];
- const game: string[] = [];
+ let game: string[] = [];
+
+ const versionJar = path.join(versionRoot, `${versionManifest.id}.jar`);
const classPaths = generateClassPaths(
versionManifest,
librariesPath,
- path.join(versionRoot, `${versionManifest.id}.jar`),
+ versionJar,
);
function p(args: string[], arg: Argument) {
@@ -157,11 +157,33 @@ export async function generateLaunchArguments(
]);
}
- for (const arg of versionManifest.arguments.jvm) {
- p(jvm, arg);
- }
- for (const arg of versionManifest.arguments.game) {
- p(game, arg);
+ if (versionManifest.arguments) {
+ for (const arg of versionManifest.arguments.jvm) {
+ p(jvm, arg);
+ }
+ for (const arg of versionManifest.arguments.game) {
+ p(game, arg);
+ }
+ } else {
+ console.log(versionManifest.minecraftArguments)
+ game = fillArguments(
+ versionManifest.minecraftArguments,
+ versionManifest,
+ assetsPath,
+ instancePath,
+ librariesPath,
+ classPaths,
+ auth,
+ ).split(" ");
+
+ jvm.push(`-Djava.library.path=${path.join(instancePath, "natives")}`);
+ jvm.push(`-Dminecraft.launcher.brand=nlk`);
+ jvm.push(`-Dminecraft.launcher.version=${packageVersion}`);
+ jvm.push(
+ `-Dminecraft.client.jar=${path.join(versionRoot, `${versionManifest.id}.jar`)}`,
+ );
+ jvm.push("-cp");
+ jvm.push(classPaths)
}
if (options.customJvmArgs !== "") {
@@ -178,21 +200,26 @@ export async function generateLaunchArguments(
const log4j = await getArgument(versionManifest, versionRoot);
+ let launchArguments = [
+ ...jvm,
+ `-Xms${options.minRam || "2G"}`,
+ `-Xmx${options.maxRam || "2G"}`,
+ "-XX:+UnlockExperimentalVMOptions",
+ "-XX:+UseG1GC",
+ "-XX:G1NewSizePercent=20",
+ "-XX:G1ReservePercent=20",
+ "-XX:MaxGCPauseMillis=50",
+ "-XX:G1HeapRegionSize=32M",
+ ]
+
+ if (log4j) {
+ launchArguments.push(log4j)
+ }
+
+ launchArguments = [...launchArguments, versionManifest.mainClass, ...game,]
+
return {
command: javaExecutable,
- args: [
- ...jvm,
- `-Xms${options.minRam || "2G"}`,
- `-Xmx${options.maxRam || "2G"}`,
- "-XX:+UnlockExperimentalVMOptions",
- "-XX:+UseG1GC",
- "-XX:G1NewSizePercent=20",
- "-XX:G1ReservePercent=20",
- "-XX:MaxGCPauseMillis=50",
- "-XX:G1HeapRegionSize=32M",
- log4j,
- versionManifest.mainClass,
- ...game,
- ],
+ args: launchArguments,
};
}
diff --git a/src/core/launch.ts b/src/core/launch.ts
index 4c14239..b199dd9 100644
--- a/src/core/launch.ts
+++ b/src/core/launch.ts
@@ -1,5 +1,5 @@
import { version as packageVersion } from "../../package.json";
-import { spawn } from "child_process";
+import { spawn, spawnSync } from "child_process";
import { LaunchArguments } from "../utils/types";
export function launch(
@@ -11,6 +11,7 @@ export function launch(
console.log(
`[nlk ${packageVersion}] Launching command : ${launchArguments.command} ${launchArguments.args.join(" ")}`,
);
+
const process = spawn(launchArguments.command, launchArguments.args, {
detached,
cwd: gameRoot,
diff --git a/src/core/libraries.ts b/src/core/libraries.ts
index 5f87afe..3a04be9 100644
--- a/src/core/libraries.ts
+++ b/src/core/libraries.ts
@@ -9,7 +9,7 @@ export function getLibraries(versionManifest: Version, librariesRoot: string) {
for (const key in versionManifest.libraries) {
if (Object.prototype.hasOwnProperty.call(versionManifest.libraries, key)) {
const library = versionManifest.libraries[key];
- if (isNeeded(library)) {
+ if (isNeeded(library) && library.downloads.artifact) {
libs.push({
url: library.downloads.artifact.url,
path: path.join(librariesRoot, library.downloads.artifact.path),
diff --git a/src/core/log4j.ts b/src/core/log4j.ts
index fedc2fe..5778564 100644
--- a/src/core/log4j.ts
+++ b/src/core/log4j.ts
@@ -5,37 +5,42 @@ import { exists } from "../utils/fs";
import { hash } from "crypto";
import fs from "fs/promises";
-async function patchFileLog4j(versionManifest: Version, xmlDestination: string) {
- const original = await fs.readFile(xmlDestination, {encoding: "utf-8"})
+async function patchFileLog4j(xmlDestination: string) {
+ const original = await fs.readFile(xmlDestination, { encoding: "utf-8" })
await fs.writeFile(xmlDestination, original.replace("", ""))
}
export async function getArgument(
versionManifest: Version,
destination: string,
-) {
- const xmlDestination = path.join(
- destination,
- versionManifest.logging.client.file.id,
- );
- if (!(await exists(xmlDestination))) {
- await downloadFile({
- url: versionManifest.logging.client.file.url,
- path: xmlDestination,
- });
+): Promise {
+ if (versionManifest.logging?.client) {
+ const xmlDestination = path.join(
+ destination,
+ versionManifest.logging.client.file.id,
+ );
+ if (!(await exists(xmlDestination))) {
+ await downloadFile({
+ url: versionManifest.logging.client.file.url,
+ path: xmlDestination,
+ });
- if (
- hash("sha1", await fs.readFile(xmlDestination, { encoding: "utf-8" })) !==
- versionManifest.logging.client.file.sha1
- ) {
- throw new Error("Wrong hash for log4j's xml config");
+ if (
+ hash("sha1", await fs.readFile(xmlDestination, { encoding: "utf-8" })) !==
+ versionManifest.logging.client.file.sha1
+ ) {
+ throw new Error("Wrong hash for log4j's xml config");
+ }
+
+ await patchFileLog4j(xmlDestination)
+
+ return versionManifest.logging.client.argument.replace(
+ "${path}",
+ xmlDestination,
+ );
}
-
- await patchFileLog4j(versionManifest, xmlDestination)
}
-
- return versionManifest.logging.client.argument.replace(
- "${path}",
- xmlDestination,
- );
+
+ // if logging is not present it means that the verson is older than 1.7 hence the fix for log4j isn't needed
+ return null
}
diff --git a/src/launcher/instance.ts b/src/launcher/instance.ts
index 76b2079..38fafe5 100644
--- a/src/launcher/instance.ts
+++ b/src/launcher/instance.ts
@@ -8,7 +8,6 @@ import {
} from "../utils/types";
import * as core from "../core";
import path from "path";
-import { os, arch } from "../utils/systemInfo";
import { EventEmitter } from "node:events";
import { InstallError, LaunchError } from "../utils/errors";
import { installForge } from "../core/modloaders";
@@ -149,7 +148,7 @@ export class Instance extends EventEmitter {
try {
const nativesDownloader = await core.NativesDownloader(
- this.instanceLocation,
+ path.join(this.instanceLocation, "natives"),
this.versionManifest,
);
nativesDownloader.on("completed", () => {
diff --git a/src/utils/types.ts b/src/utils/types.ts
index 352486c..28664e8 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -116,10 +116,11 @@ export type Library = {
};
export type Version = {
- arguments: {
+ arguments?: {
game: Argument[];
jvm: Argument[];
};
+ minecraftArguments: string;
assetIndex: {
id: string;
sha1: string;
@@ -141,7 +142,7 @@ export type Version = {
majorVersion: number;
};
libraries: Library[];
- logging: {
+ logging?: {
client: {
argument: string;
file: { id: string; sha1: string; size: number; url: string };
diff --git a/src/utils/unzip.ts b/src/utils/unzip.ts
index e30e799..711cf12 100644
--- a/src/utils/unzip.ts
+++ b/src/utils/unzip.ts
@@ -11,7 +11,6 @@ export function unzipAll(from: string, to: string, filters: string[]) {
for (const filter of filters) {
if (entry.entryName.includes(filter)) {
shouldSkip = true;
- console.log("skipping", entry.entryName);
}
}
if (shouldSkip) continue;
diff --git a/tests/instance/modloaders/oldForge.test.ts b/tests/instance/modloaders/oldForge.test.ts
new file mode 100644
index 0000000..2bb6334
--- /dev/null
+++ b/tests/instance/modloaders/oldForge.test.ts
@@ -0,0 +1,49 @@
+import { test } from "vitest";
+import { Instance, offlineAuth, RuntimeManager, getJavaComponent } from "../../../dist/index.js";
+import path from "path";
+import fs from "fs/promises";
+
+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 }, async () => {
+ const instance = new Instance();
+ const javaManager = new RuntimeManager(path.join(gameRoot, "java"));
+
+ javaManager.on("progress", console.log)
+
+ const java = await javaManager.use(await getJavaComponent("1.12.2"))
+
+ const auth = offlineAuth("player");
+
+ instance.setVersion("1.12.2");
+ instance.setPaths(gameRoot);
+ instance.setAuth(auth);
+ instance.setJavaExecutable(java)
+ instance.setModLoader("forge", "14.23.5.2864");
+
+ instance.on("progress", console.log);
+
+ await instance.install();
+ 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((res) => {
+ p.on("error", (d: Buffer) => {
+ console.log(d.toString());
+ res();
+ });
+ p.on("close", () => {
+ console.log("closed");
+ res();
+ });
+ });
+});