Files
dream_pep 3653e26a09 feat: 发布 v1.2.0 版本,新增多项核心功能
- 引入 electron-updater 实现自动更新功能
- 新增 Java 环境扫描与校验的 IPC 处理逻辑
- 实现离线账号登录功能
- 新增配置变更跨进程广播机制
- 重构游戏启动逻辑,使用主进程内存配置作为唯一权威来源
- 新增界面显示与语言设置的配置页面
- 添加 Windows 平台自动发布 CI 流水线
- 迁移旧版配置/认证文件到用户数据目录
- 修复崩溃日志路径、表单控件等多项 bug
- 重构设置页组件系统统一界面样式
2026-08-28 02:08:12 +08:00

149 lines
5.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// __ __ __ __ ______ __ __ ______ __ __ ______ ______
// /\ \ /\ \ /\ "-.\ \ /\ ___\ /\ \/ / /\ ___\ /\ "-.\ \ /\ ___\ /\__ _\
// \ \ \____ \ \ \ \ \ \-. \ \ \ \__ \ \ \ _"-. \ \ __\ \ \ \-. \ \ \ __\ \/_/\ \/
// \ \_____\ \ \_\ \ \_\\"\_\ \ \_____\ \ \_\ \_\ \ \_____\ \ \_\\"\_\ \ \_____\ \ \_\
// \/_____/ \/_/ \/_/ \/_/ \/_____/ \/_/\/_/ \/_____/ \/_/ \/_/ \/_____/ \/_/
//
// 所有权利归Lingke Network (china)所有 | dream_pep拥有其艺术改变权力
// 未经允许的情况下删除此版权头可能会受到民事指控
// 请勿在未经Lingke Network (china)允许的范围内修改代码并分发
import type { LaunchOption } from '@xmcl/core';
import { resolveJava, getPotentialJavaLocations } from '@xmcl/installer';
import type { AppConfig } from '../config';
import type { InstanceInfo } from './instance';
/** 游戏启动所需的账户档案 */
export interface LaunchProfile {
username: string;
uuid: string;
accessToken?: string;
}
/** 快速联机目标服务器 */
export interface LaunchServer {
ip: string;
port?: number;
}
/**
* 引号感知的命令行参数切分器。
* 支持双引号 / 单引号包裹的含空格参数与反斜杠转义。
* 用于 jvmArgs / gameArgs / preLaunchCmd 的解析。
*/
export function parseArgs(line: string): string[] {
const args: string[] = [];
const re = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|(\S+)/g;
let match: RegExpExecArray | null;
while ((match = re.exec(line)) !== null) {
if (match[1] !== undefined) {
args.push(match[1].replace(/\\(["\\])/g, '$1'));
} else if (match[2] !== undefined) {
args.push(match[2].replace(/\\(['\\])/g, '$1'));
} else {
args.push(match[3]);
}
}
return args;
}
/**
* 将启动器配置(AppConfig.java / AppConfig.advanced+ 实例信息 + 账户档案
* 映射为 @xmcl/core 的 LaunchOption。
*
* 配置 → 启动参数 对应关系:
* - java.memMode=auto → 实例 minMemory/maxMemory(未设置则 1024/4096
* - java.memMode=custom → min=min(2,memGB)Gmax=memGB G
* - java.gc=zgc/g1 → -XX:+UseZGC / -XX:+UseG1GC
* - java.jvmArgs → 逐行解析并入 extraJVMArgs
* - advanced.gameArgs → 解析并入 extraMCArgs
* - advanced.winMode → resolutionfullscreen / custom 宽高)
* - advanced.preLaunchCmd → prependCommandWindows 批处理需 `cmd /c` 前缀)
* - advanced.debugMode → -Dkoring.debugMode=true
*/
export function buildLaunchOptions(
config: AppConfig,
instance: InstanceInfo,
profile: LaunchProfile,
javaPath: string,
server?: LaunchServer,
): LaunchOption {
const java = config.java;
const adv = config.advanced;
// ---- 内存 ----
let minMemory = instance.config.minMemory ?? 1024;
let maxMemory = instance.config.maxMemory ?? 4096;
if (java.memMode === 'custom') {
const gb = Math.max(1, Math.min(16, java.memGB || 4));
minMemory = Math.min(2, gb) * 1024;
maxMemory = gb * 1024;
}
// ---- JVM 参数 ----
const extraJVMArgs: string[] = [];
if (java.gc === 'zgc') extraJVMArgs.push('-XX:+UseZGC');
else if (java.gc === 'g1') extraJVMArgs.push('-XX:+UseG1GC');
if (java.jvmArgs?.trim()) {
extraJVMArgs.push(...parseArgs(java.jvmArgs));
}
if (adv.debugMode) {
extraJVMArgs.push('-Dkoring.debugMode=true');
}
// ---- 游戏参数 ----
const extraMCArgs: string[] = [];
if (adv.gameArgs?.trim()) {
extraMCArgs.push(...parseArgs(adv.gameArgs));
}
// ---- 窗口 / 分辨率 ----
let resolution: { width?: number; height?: number; fullscreen?: boolean } | undefined;
if (adv.winMode === 'fullscreen') {
resolution = { fullscreen: true };
} else if (adv.winMode === 'custom') {
resolution = { width: adv.customWidth || 854, height: adv.customHeight || 480 };
}
return {
gameProfile: { name: profile.username, id: profile.uuid },
accessToken: profile.accessToken,
javaPath,
// version 由调用方在 Version.parse 后覆盖为 ResolvedVersion
version: instance.config.runtime.minecraft,
gamePath: instance.path,
minMemory,
maxMemory,
resolution,
extraJVMArgs,
extraMCArgs,
server,
prependCommand: adv.preLaunchCmd?.trim() ? parseArgs(adv.preLaunchCmd) : undefined,
launcherName: 'Koring Launcher',
launcherBrand: 'Koring',
};
}
/**
* 解析 Java 可执行文件路径,优先级:
* 1. 用户配置路径(resolveJava 校验,无效则继续向下)
* 2. 系统扫描(`where java` / `which java` 结果逐个 resolve
* 3. 兜底 PATH 中的 `java`
*/
export async function resolveJavaPath(configuredPath: string): Promise<string> {
if (configuredPath?.trim()) {
const info = await resolveJava(configuredPath.trim()).catch(() => undefined);
if (info) return info.path;
}
try {
const locations = await getPotentialJavaLocations();
for (const loc of locations) {
const info = await resolveJava(loc).catch(() => undefined);
if (info) return info.path;
}
} catch {
// 扫描失败则继续回退
}
return 'java';
}