feat(launch): M157 实例级启动参数(五项回落 + graphicsBackend 三态)

core: 新增 game/launch_overrides(LaunchOverrides 五项 All-Option + 三级回落 + 文本补丁校验)与 launch/overrides(拼装落位:全局 java.extra_args 进 user.jvm、实例 jvmArgs 进 override_jvm、gameArgs 进 user.game、memory 进 -Xmx、backend 进 --graphicsBackend 并复用既有版本门槛告警);实例 schema 登记 launch.* 五键。

presenter: dto/LaunchArgsView+LaunchArgsPatch,主机侧读/写与门槛判定(backend_allowed),AppCommand::SetInstanceLaunchArgs。

cli: 新命令 instances launch-args(读/写/--clear),launch 装配链消费回落值。

app-iced: 实例详情页「启动参数」区(JVM/游戏参数、内存、Java、三态后端 chips + 灰化提示 + 保存/恢复),表单状态归 App、i18n 中英文案同步。
This commit is contained in:
AskaEth committed 2026-11-07 10:36:35 +08:00
1 parent d68523b02a
commit e2021645d7
56 files changed
+3776 -607

No files matched your search

+26 -10
View File
@@ -52,9 +52,28 @@ pub struct JavaPick {
pub summary: String,
}
/// 选一个能用的 Java:托管 > JAVA_HOME > PATH(`core::game::java` 的探测与优先级)。
pub fn pick_java(env: &HostEnv, version_id: &str) -> JavaPick {
/// 选一个能用的 Java:显式路径(实例 → 全局 `java.selected_path`)> 托管 > JAVA_HOME > PATH。
///
/// 显式路径**先探测**(`java -version`):探测失败不报错,按版本要求的基准主版本兜底——
/// 与自动挑的退路同一口径(启动路径不该因为探测不到就拒绝启动)。
pub fn pick_java(env: &HostEnv, version_id: &str, explicit: Option<&std::path::Path>) -> JavaPick {
let store = env.store();
let required = unlucky_core::game::java::requirement_for_version(&env.game, version_id);
if let Some(path) = explicit {
let runtime = unlucky_core::game::java::probe::probe(
path,
unlucky_core::game::java::probe::JavaOrigin::Instance,
);
let major = runtime.major.unwrap_or(required.minimum);
return JavaPick {
selection: JavaSelection::new(runtime.binary.clone(), major, runtime.bits),
summary: format!(
"实例指定 Java {}({})",
runtime.version.clone().unwrap_or_else(|| major.to_string()),
path.display()
),
};
}
let install_root = store
.doc()
.effective_str("java.installRoot")
@@ -69,7 +88,6 @@ pub fn pick_java(env: &HostEnv, version_id: &str) -> JavaPick {
&ProcessEnv,
);
let candidates = unlucky_core::game::java::candidates_in_roots(&roots);
let required = unlucky_core::game::java::requirement_for_version(&env.game, version_id);
let picked = unlucky_core::game::java::pick(&candidates, &required).cloned();
match picked {
Some(runtime) => {
@@ -201,18 +219,14 @@ pub fn build_request(
game_assets: assets_root,
};
let java = pick_java(env, &version_id);
let overrides = super::launch_args::resolved(env, &target.id);
let java = pick_java(env, &version_id, overrides.java_path.as_deref());
let (auth, identity_line) = super::identity::resolve(env, target.account.as_deref())?;
let memory = env
.store()
.effective("java.default_memory_mb")
.and_then(serde_json::Value::as_u64)
.and_then(|value| u32::try_from(value).ok());
let options = AdapterOptions {
java: java.selection,
memory: MemoryOptions {
min_mb: None,
max_mb: memory,
max_mb: Some(overrides.memory_mb),
},
auth,
launcher_name: LAUNCHER_NAME.to_string(),
@@ -227,6 +241,8 @@ pub fn build_request(
let mut request = output.request;
request.instance.id = target.id.clone();
request.instance.name = target.name.clone();
// 实例级启动参数(三级回落后的生效值)最后落位:user.* / memory / graphics_backend。
unlucky_core::launch::overrides::apply(&mut request, &overrides);
Ok((request, warnings))
}