@kzheart_/mc-pilot 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@
9
9
  "loader": "fabric",
10
10
  "support": "ready",
11
11
  "validation": "verified",
12
- "modVersion": "0.1.1",
12
+ "modVersion": "0.9.1",
13
13
  "fabricLoaderVersion": "0.16.14",
14
14
  "yarnMappings": "1.18.2+build.4",
15
15
  "javaVersion": 17,
@@ -21,7 +21,7 @@
21
21
  "loader": "fabric",
22
22
  "support": "ready",
23
23
  "validation": "verified",
24
- "modVersion": "0.1.1",
24
+ "modVersion": "0.9.1",
25
25
  "fabricLoaderVersion": "0.16.14",
26
26
  "yarnMappings": "1.20.1+build.10",
27
27
  "javaVersion": 17,
@@ -31,11 +31,12 @@
31
31
  "id": "1.20.1-forge",
32
32
  "minecraftVersion": "1.20.1",
33
33
  "loader": "forge",
34
- "support": "planned",
35
- "validation": "planned",
36
- "modVersion": "0.1.1",
34
+ "support": "configured",
35
+ "validation": "limited",
36
+ "modVersion": "0.9.1",
37
37
  "forgeVersion": "47.3.0",
38
- "javaVersion": 17
38
+ "javaVersion": 17,
39
+ "gradleModule": "version-1.20.1-forge"
39
40
  },
40
41
  {
41
42
  "id": "1.20.2-fabric",
@@ -43,7 +44,7 @@
43
44
  "loader": "fabric",
44
45
  "support": "ready",
45
46
  "validation": "verified",
46
- "modVersion": "0.1.1",
47
+ "modVersion": "0.9.1",
47
48
  "fabricLoaderVersion": "0.16.14",
48
49
  "yarnMappings": "1.20.2+build.4",
49
50
  "javaVersion": 17,
@@ -53,11 +54,12 @@
53
54
  "id": "1.20.2-forge",
54
55
  "minecraftVersion": "1.20.2",
55
56
  "loader": "forge",
56
- "support": "planned",
57
- "validation": "planned",
58
- "modVersion": "0.1.1",
57
+ "support": "configured",
58
+ "validation": "limited",
59
+ "modVersion": "0.9.1",
59
60
  "forgeVersion": "48.1.0",
60
- "javaVersion": 17
61
+ "javaVersion": 17,
62
+ "gradleModule": "version-1.20.2-forge"
61
63
  },
62
64
  {
63
65
  "id": "1.20.4-fabric",
@@ -65,7 +67,7 @@
65
67
  "loader": "fabric",
66
68
  "support": "ready",
67
69
  "validation": "verified",
68
- "modVersion": "0.1.1",
70
+ "modVersion": "0.9.1",
69
71
  "fabricLoaderVersion": "0.16.14",
70
72
  "yarnMappings": "1.20.4+build.3",
71
73
  "javaVersion": 17,
@@ -75,11 +77,12 @@
75
77
  "id": "1.20.4-forge",
76
78
  "minecraftVersion": "1.20.4",
77
79
  "loader": "forge",
78
- "support": "planned",
79
- "validation": "planned",
80
- "modVersion": "0.1.1",
80
+ "support": "configured",
81
+ "validation": "limited",
82
+ "modVersion": "0.9.1",
81
83
  "forgeVersion": "49.0.49",
82
- "javaVersion": 17
84
+ "javaVersion": 17,
85
+ "gradleModule": "version-1.20.4-forge"
83
86
  },
84
87
  {
85
88
  "id": "1.20.4-neoforge",
@@ -87,7 +90,7 @@
87
90
  "loader": "neoforge",
88
91
  "support": "planned",
89
92
  "validation": "planned",
90
- "modVersion": "0.1.1",
93
+ "modVersion": "0.9.1",
91
94
  "neoforgeVersion": "20.4.237",
92
95
  "javaVersion": 17
93
96
  },
@@ -97,7 +100,7 @@
97
100
  "loader": "fabric",
98
101
  "support": "ready",
99
102
  "validation": "verified",
100
- "modVersion": "0.1.1",
103
+ "modVersion": "0.9.1",
101
104
  "fabricLoaderVersion": "0.16.14",
102
105
  "yarnMappings": "1.21.1+build.3",
103
106
  "javaVersion": 21,
@@ -109,7 +112,7 @@
109
112
  "loader": "neoforge",
110
113
  "support": "planned",
111
114
  "validation": "planned",
112
- "modVersion": "0.1.1",
115
+ "modVersion": "0.9.1",
113
116
  "neoforgeVersion": "21.1.77",
114
117
  "javaVersion": 21
115
118
  },
@@ -119,7 +122,7 @@
119
122
  "loader": "fabric",
120
123
  "support": "ready",
121
124
  "validation": "verified",
122
- "modVersion": "0.1.1",
125
+ "modVersion": "0.9.1",
123
126
  "fabricLoaderVersion": "0.16.14",
124
127
  "yarnMappings": "1.21.4+build.1",
125
128
  "javaVersion": 21,
@@ -131,7 +134,7 @@
131
134
  "loader": "neoforge",
132
135
  "support": "planned",
133
136
  "validation": "planned",
134
- "modVersion": "0.1.1",
137
+ "modVersion": "0.9.1",
135
138
  "neoforgeVersion": "21.4.75",
136
139
  "javaVersion": 21
137
140
  }
@@ -5,14 +5,8 @@ import { ServerInstanceManager } from "../instance/ServerInstanceManager.js";
5
5
  import { MctError } from "../util/errors.js";
6
6
  import { createRequestAction } from "./request-helpers.js";
7
7
  import { wrapCommand } from "../util/command.js";
8
- import { CacheManager } from "../download/CacheManager.js";
9
- import { findVariantByVersionAndLoader, getModArtifactFileName, loadModVariantCatalog } from "../download/ModVariantCatalog.js";
10
- import { detectJava } from "../download/JavaDetector.js";
11
- import { prepareManagedFabricRuntime } from "../download/client/FabricRuntimeDownloader.js";
12
- import { copyFileIfMissing, downloadFile } from "../download/DownloadUtils.js";
8
+ import { downloadClientModToDir } from "../download/client/ClientDownloader.js";
13
9
  import { resolveClientInstanceDir } from "../util/paths.js";
14
- import { access, mkdir } from "node:fs/promises";
15
- import path from "node:path";
16
10
  export async function resolveProfileServerAddress(context, explicitServer, loadPort) {
17
11
  if (explicitServer) {
18
12
  return explicitServer;
@@ -50,93 +44,46 @@ export function createClientCommand() {
50
44
  .description("Create a new client instance")
51
45
  .argument("<name>", "Client instance name (e.g. fabric-1.20.4)")
52
46
  .option("--version <version>", "Minecraft version (default: 1.21.4)")
53
- .option("--loader <loader>", "Client loader: fabric (default: fabric)")
47
+ .option("--loader <loader>", "Client loader: fabric|forge (default: fabric)")
54
48
  .option("--ws-port <port>", "WebSocket port (auto-assigned if omitted)", Number)
55
49
  .option("--account <account>", "Offline username or account identifier")
56
50
  .option("--headless", "Launch in headless mode")
51
+ .option("--mute", "Mute all in-game audio for this client")
52
+ .option("--no-mute", "Keep in-game audio enabled for this client")
57
53
  .option("--java <command>", "Java command to use")
58
54
  .action(wrapCommand(async (_context, { args, options }) => {
59
55
  const clientName = args[0];
60
56
  const loader = options.loader ?? "fabric";
61
57
  const version = options.version ?? "1.21.4";
62
- const cacheManager = new CacheManager();
63
- const catalog = await loadModVariantCatalog();
64
- const variant = findVariantByVersionAndLoader(catalog, version, loader);
65
- if (!variant) {
66
- throw new MctError({ code: "VARIANT_NOT_FOUND", message: `No mod variant found for ${version} / ${loader}` }, 4);
67
- }
68
- if (variant.loader !== "fabric") {
69
- throw new MctError({ code: "UNSUPPORTED_LOADER", message: `Loader ${variant.loader} is not implemented yet` }, 4);
70
- }
71
- // Check Java
72
- const java = await detectJava(options.java ?? "java");
73
- const requiredJava = variant.javaVersion ?? 17;
74
- if (!java.available || (java.majorVersion ?? 0) < requiredJava) {
75
- throw new MctError({ code: "JAVA_NOT_FOUND", message: `Java ${requiredJava}+ is required for ${variant.id}` }, 4);
76
- }
77
- // Resolve mod artifact
78
- const artifactFileName = getModArtifactFileName(variant);
79
- const cacheArtifactPath = cacheManager.getModFile(artifactFileName);
80
- const gradleModule = variant.gradleModule ?? `version-${variant.minecraftVersion}`;
81
- const localBuildPath = path.join(process.cwd(), "client-mod", gradleModule, "build", "libs", artifactFileName);
82
- let sourcePath;
83
- try {
84
- await access(localBuildPath);
85
- sourcePath = localBuildPath;
86
- await copyFileIfMissing(localBuildPath, cacheArtifactPath);
87
- }
88
- catch {
89
- try {
90
- await access(cacheArtifactPath);
91
- sourcePath = cacheArtifactPath;
92
- }
93
- catch {
94
- const modVersion = variant.modVersion ?? "0.1.0";
95
- const baseUrl = process.env.MCT_MOD_DOWNLOAD_BASE_URL || "https://github.com/kzheart/mc-pilot/releases/download";
96
- const downloadUrl = `${baseUrl}/v${modVersion}/${artifactFileName}`;
97
- await downloadFile(downloadUrl, cacheArtifactPath, fetch);
98
- sourcePath = cacheArtifactPath;
99
- }
100
- }
101
- // Set up client instance directory
102
58
  const instanceDir = resolveClientInstanceDir(clientName);
103
- const minecraftDir = path.join(instanceDir, "minecraft");
104
- const modsDir = path.join(minecraftDir, "mods");
105
- await mkdir(modsDir, { recursive: true });
106
- await copyFileIfMissing(sourcePath, path.join(modsDir, artifactFileName));
107
- // Prepare Fabric runtime
108
- const runtimeRootDir = path.join(cacheManager.getRootDir(), "client", "runtime", variant.minecraftVersion);
109
- const managedRuntime = await prepareManagedFabricRuntime(variant, {
110
- runtimeRootDir,
111
- gameDir: minecraftDir
112
- }, { fetchImpl: fetch });
113
- const launchArgs = [
114
- "--runtime-root", managedRuntime.runtimeRootDir,
115
- "--version-id", managedRuntime.versionId,
116
- "--game-dir", managedRuntime.gameDir
117
- ];
59
+ const downloaded = await downloadClientModToDir(process.cwd(), instanceDir, {
60
+ version,
61
+ loader,
62
+ java: options.java
63
+ });
118
64
  const manager = new ClientInstanceManager(_context.globalState);
119
65
  const meta = await manager.create({
120
66
  name: clientName,
121
- loader,
122
- version: variant.minecraftVersion,
67
+ loader: downloaded.loader,
68
+ version: downloaded.minecraftVersion,
123
69
  wsPort: options.wsPort,
124
70
  account: options.account,
125
71
  headless: options.headless,
126
- launchArgs,
72
+ mute: options.mute,
73
+ launchArgs: downloaded.launchArgs,
127
74
  env: {
128
- MCT_CLIENT_MOD_VARIANT: variant.id,
129
- MCT_CLIENT_MOD_JAR: path.join(modsDir, artifactFileName)
75
+ MCT_CLIENT_MOD_VARIANT: downloaded.variantId,
76
+ MCT_CLIENT_MOD_JAR: downloaded.jar
130
77
  }
131
78
  });
132
79
  return {
133
80
  created: true,
134
81
  ...meta,
135
- javaCommand: java.command,
136
- javaVersion: java.majorVersion,
137
- modsDir,
138
- runtimeRootDir: managedRuntime.runtimeRootDir,
139
- runtimeVersionId: managedRuntime.versionId
82
+ javaCommand: downloaded.javaCommand,
83
+ javaVersion: downloaded.javaVersion,
84
+ modsDir: downloaded.modsDir,
85
+ runtimeRootDir: downloaded.runtimeRootDir,
86
+ runtimeVersionId: downloaded.runtimeVersionId
140
87
  };
141
88
  }));
142
89
  command
@@ -147,6 +94,8 @@ export function createClientCommand() {
147
94
  .option("--account <account>", "Offline username or account identifier")
148
95
  .option("--ws-port <port>", "WebSocket port override", Number)
149
96
  .option("--headless", "Launch in headless mode")
97
+ .option("--mute", "Mute all in-game audio for this launch")
98
+ .option("--no-mute", "Keep in-game audio enabled for this launch")
150
99
  .option("--force", "Kill any existing client with the same name before launching")
151
100
  .action(wrapCommand(async (context, { args, options }) => {
152
101
  const clientName = args[0] ?? context.activeProfile?.clients[0];
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createImageCommand(): Command;
@@ -0,0 +1,211 @@
1
+ import { Command } from "commander";
2
+ import { readFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { PNG } from "pngjs";
5
+ import { wrapCommand } from "../util/command.js";
6
+ import { MctError } from "../util/errors.js";
7
+ import { resolveProjectRelativePath } from "./request-helpers.js";
8
+ function parseRect(value, field) {
9
+ if (!value)
10
+ return undefined;
11
+ const parts = value.split(",").map((part) => Number(part.trim()));
12
+ if (parts.length !== 4 || parts.some((part) => !Number.isFinite(part))) {
13
+ throw new MctError({ code: "INVALID_PARAMS", message: `${field} must use x,y,w,h format.` }, 4);
14
+ }
15
+ return { x: parts[0], y: parts[1], width: parts[2], height: parts[3] };
16
+ }
17
+ function parseRgb(value) {
18
+ if (!value)
19
+ return undefined;
20
+ const parts = value.split(",").map((part) => Number(part.trim()));
21
+ if (parts.length !== 3 || parts.some((part) => !Number.isFinite(part) || part < 0 || part > 255)) {
22
+ throw new MctError({ code: "INVALID_PARAMS", message: "--background must use r,g,b format." }, 4);
23
+ }
24
+ return [parts[0], parts[1], parts[2]];
25
+ }
26
+ function loadPng(file) {
27
+ return PNG.sync.read(readFileSync(file));
28
+ }
29
+ function pixelOffset(image, x, y) {
30
+ return (image.width * y + x) << 2;
31
+ }
32
+ function colorDistance(a, b) {
33
+ return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + Math.abs(a[2] - b[2]);
34
+ }
35
+ function clampRect(rect, image) {
36
+ const raw = rect ?? { x: 0, y: 0, width: image.width, height: image.height };
37
+ const x = Math.max(0, Math.min(image.width, Math.floor(raw.x)));
38
+ const y = Math.max(0, Math.min(image.height, Math.floor(raw.y)));
39
+ const right = Math.max(x, Math.min(image.width, Math.floor(raw.x + raw.width)));
40
+ const bottom = Math.max(y, Math.min(image.height, Math.floor(raw.y + raw.height)));
41
+ return { x, y, width: right - x, height: bottom - y };
42
+ }
43
+ function findForegroundBounds(image, options) {
44
+ const region = clampRect(options.region, image);
45
+ const background = options.background ?? [
46
+ image.data[pixelOffset(image, 0, 0)],
47
+ image.data[pixelOffset(image, 0, 0) + 1],
48
+ image.data[pixelOffset(image, 0, 0) + 2]
49
+ ];
50
+ let minX = Number.POSITIVE_INFINITY;
51
+ let minY = Number.POSITIVE_INFINITY;
52
+ let maxX = -1;
53
+ let maxY = -1;
54
+ let pixels = 0;
55
+ for (let y = region.y; y < region.y + region.height; y++) {
56
+ for (let x = region.x; x < region.x + region.width; x++) {
57
+ const offset = pixelOffset(image, x, y);
58
+ const a = image.data[offset + 3];
59
+ const rgb = [image.data[offset], image.data[offset + 1], image.data[offset + 2]];
60
+ if (a > options.alphaThreshold && colorDistance(rgb, background) > options.threshold) {
61
+ minX = Math.min(minX, x);
62
+ minY = Math.min(minY, y);
63
+ maxX = Math.max(maxX, x);
64
+ maxY = Math.max(maxY, y);
65
+ pixels++;
66
+ }
67
+ }
68
+ }
69
+ if (pixels === 0)
70
+ return null;
71
+ return { x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1, pixels };
72
+ }
73
+ function collectTemplatePixels(template, alphaThreshold, maxSamples) {
74
+ const pixels = [];
75
+ for (let y = 0; y < template.height; y++) {
76
+ for (let x = 0; x < template.width; x++) {
77
+ const offset = pixelOffset(template, x, y);
78
+ if (template.data[offset + 3] > alphaThreshold) {
79
+ pixels.push({ x, y, r: template.data[offset], g: template.data[offset + 1], b: template.data[offset + 2] });
80
+ }
81
+ }
82
+ }
83
+ if (pixels.length <= maxSamples)
84
+ return pixels;
85
+ const stride = pixels.length / maxSamples;
86
+ const sampled = [];
87
+ for (let i = 0; i < maxSamples; i++) {
88
+ sampled.push(pixels[Math.floor(i * stride)]);
89
+ }
90
+ return sampled;
91
+ }
92
+ function scoreTemplateAt(screenshot, samples, x, y, scale) {
93
+ let score = 0;
94
+ let compared = 0;
95
+ for (const sample of samples) {
96
+ const sx = Math.round(x + sample.x * scale);
97
+ const sy = Math.round(y + sample.y * scale);
98
+ if (sx < 0 || sy < 0 || sx >= screenshot.width || sy >= screenshot.height)
99
+ continue;
100
+ const offset = pixelOffset(screenshot, sx, sy);
101
+ score += Math.abs(screenshot.data[offset] - sample.r) +
102
+ Math.abs(screenshot.data[offset + 1] - sample.g) +
103
+ Math.abs(screenshot.data[offset + 2] - sample.b);
104
+ compared++;
105
+ }
106
+ return compared === 0 ? Number.POSITIVE_INFINITY : score / compared;
107
+ }
108
+ export function createImageCommand() {
109
+ const command = new Command("image").description("Image analysis helpers for screenshots and UI offset tuning");
110
+ command
111
+ .command("bbox")
112
+ .description("Find the foreground bounding box in a PNG image")
113
+ .argument("<image>", "PNG image path")
114
+ .option("--background <rgb>", "Background color to ignore, format r,g,b. Defaults to top-left pixel.")
115
+ .option("--threshold <value>", "RGB distance threshold", (value) => Number(value), 24)
116
+ .option("--alpha-threshold <value>", "Alpha threshold", (value) => Number(value), 8)
117
+ .option("--region <rect>", "Optional scan region x,y,w,h")
118
+ .action(wrapCommand(async (context, { args, options }) => {
119
+ const imagePath = resolveProjectRelativePath(context, args[0] ?? "");
120
+ const image = loadPng(imagePath);
121
+ const bbox = findForegroundBounds(image, {
122
+ background: parseRgb(options.background),
123
+ threshold: Number(options.threshold),
124
+ alphaThreshold: Number(options.alphaThreshold),
125
+ region: parseRect(options.region, "--region")
126
+ });
127
+ return {
128
+ image: path.resolve(imagePath),
129
+ size: { width: image.width, height: image.height },
130
+ bbox,
131
+ center: bbox ? { x: bbox.x + bbox.width / 2, y: bbox.y + bbox.height / 2 } : null
132
+ };
133
+ }));
134
+ command
135
+ .command("locate-template")
136
+ .description("Locate a transparent PNG template inside a screenshot, useful for tuning GUI title offsets")
137
+ .argument("<screenshot>", "Screenshot PNG path")
138
+ .argument("<template>", "Template PNG path")
139
+ .option("--region <rect>", "Screenshot search region x,y,w,h")
140
+ .option("--expected <rect>", "Expected rectangle x,y,w,h; output includes delta from it")
141
+ .option("--scale <value>", "Single scale to test", (value) => Number(value))
142
+ .option("--min-scale <value>", "Minimum scale", (value) => Number(value), 0.5)
143
+ .option("--max-scale <value>", "Maximum scale", (value) => Number(value), 3)
144
+ .option("--scale-step <value>", "Scale step", (value) => Number(value), 0.1)
145
+ .option("--stride <pixels>", "Search stride in screenshot pixels", (value) => Number(value), 2)
146
+ .option("--alpha-threshold <value>", "Template alpha threshold", (value) => Number(value), 16)
147
+ .option("--max-samples <count>", "Maximum template pixels to sample", (value) => Number(value), 4000)
148
+ .action(wrapCommand(async (context, { args, options }) => {
149
+ const screenshotPath = resolveProjectRelativePath(context, args[0] ?? "");
150
+ const templatePath = resolveProjectRelativePath(context, args[1] ?? "");
151
+ const screenshot = loadPng(screenshotPath);
152
+ const template = loadPng(templatePath);
153
+ const region = clampRect(parseRect(options.region, "--region"), screenshot);
154
+ const expected = parseRect(options.expected, "--expected");
155
+ const samples = collectTemplatePixels(template, Number(options.alphaThreshold), Number(options.maxSamples));
156
+ if (samples.length === 0) {
157
+ throw new MctError({ code: "INVALID_PARAMS", message: "Template has no visible pixels after alpha filtering." }, 4);
158
+ }
159
+ const scales = options.scale
160
+ ? [Number(options.scale)]
161
+ : Array.from({ length: Math.max(1, Math.floor((Number(options.maxScale) - Number(options.minScale)) / Number(options.scaleStep)) + 1) }, (_, index) => Number((Number(options.minScale) + index * Number(options.scaleStep)).toFixed(4)));
162
+ let best;
163
+ for (const scale of scales) {
164
+ const width = Math.round(template.width * scale);
165
+ const height = Math.round(template.height * scale);
166
+ for (let y = region.y - height; y <= region.y + region.height; y += Number(options.stride)) {
167
+ for (let x = region.x - width; x <= region.x + region.width; x += Number(options.stride)) {
168
+ const score = scoreTemplateAt(screenshot, samples, x, y, scale);
169
+ if (!best || score < best.score) {
170
+ best = { x, y, scale, score, compared: samples.length };
171
+ }
172
+ }
173
+ }
174
+ }
175
+ if (!best) {
176
+ throw new MctError({ code: "INVALID_STATE", message: "No template match candidate found." }, 3);
177
+ }
178
+ const bbox = {
179
+ x: best.x,
180
+ y: best.y,
181
+ width: Math.round(template.width * best.scale),
182
+ height: Math.round(template.height * best.scale)
183
+ };
184
+ const center = { x: bbox.x + bbox.width / 2, y: bbox.y + bbox.height / 2 };
185
+ const expectedCenter = expected ? { x: expected.x + expected.width / 2, y: expected.y + expected.height / 2 } : undefined;
186
+ return {
187
+ screenshot: path.resolve(screenshotPath),
188
+ template: path.resolve(templatePath),
189
+ screenshotSize: { width: screenshot.width, height: screenshot.height },
190
+ templateSize: { width: template.width, height: template.height },
191
+ samples: samples.length,
192
+ match: {
193
+ bbox,
194
+ center,
195
+ scale: best.scale,
196
+ score: Number(best.score.toFixed(3))
197
+ },
198
+ expected: expected
199
+ ? {
200
+ bbox: expected,
201
+ center: expectedCenter,
202
+ delta: {
203
+ x: Number((center.x - expectedCenter.x).toFixed(3)),
204
+ y: Number((center.y - expectedCenter.y).toFixed(3))
205
+ }
206
+ }
207
+ : undefined
208
+ };
209
+ }));
210
+ return command;
211
+ }
@@ -40,21 +40,7 @@ export interface ClientSearchResult {
40
40
  notes?: string;
41
41
  javaVersion: string;
42
42
  }
43
- export declare function getVersionMatrix(): {
44
- minecraftVersion: string;
45
- javaVersion: string;
46
- servers: {
47
- paper: ServerSupportInfo;
48
- purpur: ServerSupportInfo;
49
- vanilla: ServerSupportInfo;
50
- spigot: ServerSupportInfo;
51
- };
52
- clients: {
53
- fabric: ClientLoaderSupportInfo;
54
- forge: ClientLoaderSupportInfo;
55
- neoforge: ClientLoaderSupportInfo;
56
- };
57
- }[];
43
+ export declare function getVersionMatrix(): MinecraftSupportEntry[];
58
44
  export declare function getSupportedMinecraftVersions(): string[];
59
45
  export declare function getMinecraftSupport(version: string): MinecraftSupportEntry | undefined;
60
46
  export declare function searchServerVersions(filter?: {
@@ -10,9 +10,9 @@ const VERSION_MATRIX = [
10
10
  spigot: { supported: true, requiresBuildTools: true }
11
11
  },
12
12
  clients: {
13
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1", validation: "verified" },
13
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1", validation: "verified" },
14
14
  forge: { supported: false, notes: "不支持此版本" },
15
- neoforge: { supported: true, loaderVersion: "21.4.x", modVersion: "0.1.1" }
15
+ neoforge: { supported: true, loaderVersion: "21.4.x", modVersion: "0.9.1" }
16
16
  }
17
17
  },
18
18
  {
@@ -25,9 +25,9 @@ const VERSION_MATRIX = [
25
25
  spigot: { supported: true, requiresBuildTools: true }
26
26
  },
27
27
  clients: {
28
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1", validation: "verified" },
28
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1", validation: "verified" },
29
29
  forge: { supported: false, notes: "不支持此版本" },
30
- neoforge: { supported: true, loaderVersion: "21.1.x", modVersion: "0.1.1" }
30
+ neoforge: { supported: true, loaderVersion: "21.1.x", modVersion: "0.9.1" }
31
31
  }
32
32
  },
33
33
  {
@@ -40,8 +40,8 @@ const VERSION_MATRIX = [
40
40
  spigot: { supported: true, requiresBuildTools: true }
41
41
  },
42
42
  clients: {
43
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1" },
44
- forge: { supported: true, loaderVersion: "49.0.49", modVersion: "0.1.1" },
43
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1" },
44
+ forge: { supported: true, loaderVersion: "49.0.49", modVersion: "0.9.1", validation: "limited" },
45
45
  neoforge: { supported: false, notes: "不支持此版本" }
46
46
  }
47
47
  },
@@ -55,8 +55,8 @@ const VERSION_MATRIX = [
55
55
  spigot: { supported: true, requiresBuildTools: true }
56
56
  },
57
57
  clients: {
58
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1", validation: "verified" },
59
- forge: { supported: false, notes: "当前未接入此 loader" },
58
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1", validation: "verified" },
59
+ forge: { supported: true, loaderVersion: "48.1.0", modVersion: "0.9.1", validation: "limited" },
60
60
  neoforge: { supported: false, notes: "不支持此版本" }
61
61
  }
62
62
  },
@@ -70,7 +70,7 @@ const VERSION_MATRIX = [
70
70
  spigot: { supported: true, requiresBuildTools: true }
71
71
  },
72
72
  clients: {
73
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1" },
73
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1" },
74
74
  forge: { supported: false, notes: "当前未接入此 loader" },
75
75
  neoforge: { supported: false, notes: "不支持此版本" }
76
76
  }
@@ -85,8 +85,8 @@ const VERSION_MATRIX = [
85
85
  spigot: { supported: true, requiresBuildTools: true }
86
86
  },
87
87
  clients: {
88
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1" },
89
- forge: { supported: true, loaderVersion: "47.x", modVersion: "0.1.1" },
88
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1" },
89
+ forge: { supported: true, loaderVersion: "47.3.0", modVersion: "0.9.1", validation: "limited" },
90
90
  neoforge: { supported: false, notes: "不支持此版本" }
91
91
  }
92
92
  },
@@ -100,8 +100,8 @@ const VERSION_MATRIX = [
100
100
  spigot: { supported: true, requiresBuildTools: true }
101
101
  },
102
102
  clients: {
103
- fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.1.1", validation: "verified" },
104
- forge: { supported: true, loaderVersion: "40.x", modVersion: "0.1.1" },
103
+ fabric: { supported: true, loaderVersion: "0.16.14", modVersion: "0.9.1", validation: "verified" },
104
+ forge: { supported: true, loaderVersion: "40.x", modVersion: "0.9.1" },
105
105
  neoforge: { supported: false, notes: "不支持此版本" }
106
106
  }
107
107
  },
@@ -116,7 +116,7 @@ const VERSION_MATRIX = [
116
116
  },
117
117
  clients: {
118
118
  fabric: { supported: false, notes: "当前未接入此版本 mod" },
119
- forge: { supported: true, loaderVersion: "36.x", modVersion: "0.1.1" },
119
+ forge: { supported: true, loaderVersion: "36.x", modVersion: "0.9.1" },
120
120
  neoforge: { supported: false, notes: "不支持此版本" }
121
121
  }
122
122
  },
@@ -131,7 +131,7 @@ const VERSION_MATRIX = [
131
131
  },
132
132
  clients: {
133
133
  fabric: { supported: false, notes: "不支持此版本" },
134
- forge: { supported: true, loaderVersion: "14.23.x", modVersion: "0.1.1" },
134
+ forge: { supported: true, loaderVersion: "14.23.x", modVersion: "0.9.1" },
135
135
  neoforge: { supported: false, notes: "不支持此版本" }
136
136
  }
137
137
  }
@@ -150,8 +150,8 @@ function overlayClientSupport(entry, loader) {
150
150
  notes: variant.notes
151
151
  };
152
152
  }
153
- export function getVersionMatrix() {
154
- return VERSION_MATRIX.map((entry) => ({
153
+ function overlayMinecraftSupport(entry) {
154
+ return {
155
155
  minecraftVersion: entry.minecraftVersion,
156
156
  javaVersion: entry.javaVersion,
157
157
  servers: { ...entry.servers },
@@ -160,13 +160,17 @@ export function getVersionMatrix() {
160
160
  forge: overlayClientSupport(entry, "forge"),
161
161
  neoforge: overlayClientSupport(entry, "neoforge")
162
162
  }
163
- }));
163
+ };
164
+ }
165
+ export function getVersionMatrix() {
166
+ return VERSION_MATRIX.map((entry) => overlayMinecraftSupport(entry));
164
167
  }
165
168
  export function getSupportedMinecraftVersions() {
166
169
  return VERSION_MATRIX.map((entry) => entry.minecraftVersion);
167
170
  }
168
171
  export function getMinecraftSupport(version) {
169
- return VERSION_MATRIX.find((entry) => entry.minecraftVersion === version);
172
+ const entry = VERSION_MATRIX.find((candidate) => candidate.minecraftVersion === version);
173
+ return entry ? overlayMinecraftSupport(entry) : undefined;
170
174
  }
171
175
  export function searchServerVersions(filter) {
172
176
  const types = filter?.type ? [filter.type] : getServerTypes();
@@ -1,7 +1,7 @@
1
1
  import { CacheManager } from "../CacheManager.js";
2
2
  import { detectJava } from "../JavaDetector.js";
3
3
  import type { LoaderType, ModVariant } from "../types.js";
4
- import { prepareManagedFabricRuntime } from "./FabricRuntimeDownloader.js";
4
+ import { prepareManagedClientRuntime } from "./FabricRuntimeDownloader.js";
5
5
  export interface DownloadClientOptions {
6
6
  loader?: LoaderType;
7
7
  version?: string;
@@ -20,7 +20,7 @@ export interface DownloadClientDependencies {
20
20
  cacheManager?: CacheManager;
21
21
  detectJavaImpl?: typeof detectJava;
22
22
  fetchImpl?: typeof fetch;
23
- prepareManagedRuntimeImpl?: typeof prepareManagedFabricRuntime;
23
+ prepareManagedRuntimeImpl?: typeof prepareManagedClientRuntime;
24
24
  }
25
25
  export declare function resolveArtifact(cwd: string, variant: ModVariant, cacheManager: CacheManager, fetchImpl?: typeof fetch): Promise<{
26
26
  sourcePath: string;