feat: add the instance class

This commit is contained in:
HerozDotExe 2025-11-25 21:53:38 +01:00
parent 3db0007789
commit 2819f164bc
17 changed files with 225 additions and 13 deletions

3
.gitignore vendored
View file

@ -141,7 +141,8 @@ vite.config.ts.timestamp-*
.vite/
# Test temp folder
tests/temp
tests/core/temp
tests/instance/temp
# Test files
handler.js

View file

@ -8,8 +8,8 @@ export async function AssetsDownloader(
destination: string,
versionManifest: Version,
) {
await ensureDir(path.join(destination, "indexes"));
await ensureDir(path.join(destination, "objects"));
await ensureDir(path.join(destination, "indexes"), true);
await ensureDir(path.join(destination, "objects"), true);
const assetIndexPath = path.join(
destination,

View file

@ -9,6 +9,7 @@ import {
RuntimeOS,
} from "../utils/types";
import { os } from "../utils/systemInfo";
import { ensureDir } from "../utils/fs";
export function getJavaExecutable(javaRoot: string, show = false) {
const executable = `${os() === "windows" && show ? "javaw" : "java"}${os() === "windows" ? ".exe" : ""}`;
@ -41,7 +42,7 @@ export async function JavaDownloader(
size: element.downloads.raw.size,
});
} else if (element.type === "directory") {
await fs.mkdir(path.join(destination, key));
await ensureDir(path.join(destination, key), true);
}
}
}

View file

@ -1 +1,2 @@
export * as core from "./core";
export * from "./instance";

16
src/instance/auth.ts Normal file
View file

@ -0,0 +1,16 @@
import { v3 } from "uuid";
function getUUID(value: string) {
return v3(value, v3.DNS);
}
export function offlineAuth(username: string) {
const uuid = getUUID(username);
return {
access_token: uuid,
client_token: uuid,
uuid,
name: username,
user_properties: "{}",
};
}

2
src/instance/index.ts Normal file
View file

@ -0,0 +1,2 @@
export { offlineAuth } from "./auth";
export { Instance } from "./instance";

149
src/instance/instance.ts Normal file
View file

@ -0,0 +1,149 @@
import { Auth, Paths, Version } from "../utils/types";
import * as core from "../core";
import path from "path";
import { os, arch } from "../utils/systemInfo";
function getJavaOs() {
switch (os()) {
case "windows":
switch (arch()) {
case "arm":
return "windows-arm64";
case "x86":
return "windows-x86";
case "x64":
default:
return "windows-x64";
}
case "osx":
switch (arch()) {
case "arm":
return "mac-os-arm64";
case "x64":
case "x86":
default:
return "mac-os";
}
case "linux":
switch (arch()) {
case "x86":
return "linux-i386";
case "x64":
case "arm":
default:
return "linux";
}
}
}
export class Instance {
version: string;
modLoader: { name: string; version: string };
auth: Auth;
paths: Paths;
versionManifest: Version;
setVersion(version: string) {
this.version = version;
}
setModLoader(name: string, version: string) {
this.modLoader = { name, version };
}
setPaths(paths: string);
setPaths(paths: Paths);
setPaths(paths: Paths | string) {
if (typeof paths === "string") {
this.paths = {
root: paths,
version: path.join(paths),
assets: path.join(paths, "assets"),
java: path.join(paths, "java"),
libraries: path.join(paths, "libraries"),
natives: path.join(paths, "natives"),
};
} else {
this.paths = {
root: paths.root,
version: paths.version || path.join(paths.root),
assets: paths.assets || path.join(paths.root, "assets"),
java: paths.java || path.join(paths.root, "java"),
libraries: paths.libraries || path.join(paths.root, "libraries"),
natives: paths.natives || path.join(paths.root, "natives"),
};
}
}
setAuth(auth: Auth) {
this.auth = auth;
}
async install() {
this.versionManifest = await core.version.getVersionManifest(
this.version,
this.paths.root,
);
await core.version.downloadJar(this.versionManifest, this.paths.root);
const librariesDownloader = await core.LibrariesDownloader(
this.paths.libraries,
this.versionManifest,
);
librariesDownloader.on("completed", () => {
console.log(
`${librariesDownloader.done}/${librariesDownloader.total} | ${librariesDownloader.doneSize}/${librariesDownloader.totalSize}`,
);
});
await librariesDownloader.run();
const assetsDownloader = await core.AssetsDownloader(
this.paths.assets,
this.versionManifest,
);
assetsDownloader.on("completed", () => {
console.log(
`${assetsDownloader.done}/${assetsDownloader.total} | ${assetsDownloader.doneSize}/${assetsDownloader.totalSize}`,
);
});
await assetsDownloader.run();
const nativesDownloader = await core.NativesDownloader(
this.paths.natives,
this.versionManifest,
);
nativesDownloader.on("completed", () => {
console.log(
`${nativesDownloader.done}/${nativesDownloader.total} | ${nativesDownloader.doneSize}/${nativesDownloader.totalSize}`,
);
});
await nativesDownloader.run();
const javaDownloader = await core.java.JavaDownloader(
getJavaOs(),
this.versionManifest.javaVersion.component,
this.paths.java,
);
javaDownloader.on("completed", () => {
console.log(
`${javaDownloader.done}/${javaDownloader.total} | ${javaDownloader.doneSize}/${javaDownloader.totalSize}`,
);
});
await javaDownloader.run();
}
async launch() {
const args = await core.arguments.generateLaunchArguments(
await core.version.getVersionManifest("1.21.8", this.paths.root),
path.join(this.paths.java),
path.join(this.paths.root),
path.join(this.paths.root, `${this.version}.jar`),
this.auth,
);
const process = core.launch(args, this.paths.root);
return process;
}
}

View file

@ -7,4 +7,16 @@ export function os() {
default:
return "linux";
}
}
export function arch() {
switch(process.arch) {
case "arm":
case "arm64":
return "arm"
case "x64":
return "x64"
default:
return "x86"
}
}

View file

@ -176,4 +176,13 @@ export type Auth = {
};
};
export type LaunchArguments = { command: string; args: string[] }
export type LaunchArguments = { command: string; args: string[] };
export type Paths = {
root: string
version?: string
assets?: string
libraries?: string
natives?: string
java?: string
}

View file

@ -1,5 +1,5 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import { v3 } from "uuid";

View file

@ -1,5 +1,5 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import fs from "fs/promises";

View file

@ -1,10 +1,10 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import fs from "fs/promises";
const javaPath = path.join(import.meta.dirname, "temp/java");
await fs.rm(javaPath, { recursive: true });
await fs.rm(javaPath, { recursive: true, force: true });
await fs.mkdir(javaPath, { recursive: true });
async function exists(path: string) {

View file

@ -1,5 +1,5 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import fs from "fs/promises";

View file

@ -1,5 +1,5 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import { hash } from "crypto";
import fs from "fs/promises";

View file

@ -1,5 +1,5 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import fs from "fs/promises";

View file

@ -1,5 +1,5 @@
import { expect, test, vi } from "vitest";
import * as nlk from "../dist/index.js";
import * as nlk from "../../dist/index.js";
import path from "path";
import fs from "fs/promises";

View file

@ -0,0 +1,21 @@
import { test } from "vitest";
import { Instance, offlineAuth } 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 auth = offlineAuth("player");
instance.setVersion("1.21.8");
instance.setPaths(gameRoot);
instance.setAuth(auth);
await instance.install();
await instance.launch();
});