feat(presenter): 多根发现(配置根 + 官方启动器标准位置),实例按自己的根解析存档/模组/启动(M274)

This commit is contained in:
AskaEth committed 2026-11-12 19:55:51 +08:00
1 parent dfc0f4bcb3
commit dc8323531b
20 files changed
+943 -121

No files matched your search

+27 -17
View File
@@ -63,7 +63,10 @@ pub fn build_request(
target: &LaunchTarget,
) -> Result<(LaunchRequest, Vec<String>), LaunchFailureView> {
let version_id = target.version_id.clone();
let manifest_path = env.game.version_json(&version_id);
// **这个实例自己的根**(M274):官方根 / 另一个 `.minecraft` 里的版本,清单、库、natives、
// assets 全在它自己那个根下。拿 `env.game` 去读会读空(甚至读到同名的另一个版本)。
let game = super::game::game_for(env, &target.id);
let manifest_path = game.version_json(&version_id);
let text = std::fs::read_to_string(&manifest_path).map_err(|error| {
LaunchFailureView::new(
LaunchFailureStage::VersionManifest,
@@ -77,7 +80,7 @@ pub fn build_request(
)
})?;
let source = |id: &str| -> Option<VersionJson> {
std::fs::read_to_string(env.game.version_json(id))
std::fs::read_to_string(game.version_json(id))
.ok()
.and_then(|text| VersionJson::from_json_str(&text).ok())
};
@@ -121,22 +124,22 @@ pub fn build_request(
}
};
let path = if library.is_local() {
env.game.version_library(&version_id, &coordinate)
game.version_library(&version_id, &coordinate)
} else {
env.game.library(&coordinate)
game.library(&coordinate)
};
libraries.push(LibraryInput::new(path, name));
}
let natives = unlucky_core::launch::natives::collect(
&env.game,
&game,
&version_id,
resolved.libraries.as_deref().unwrap_or_default(),
&environment,
);
let game_dir = run_dir(env, target)?;
let game_dir = run_dir(env, &game, target)?;
let jar_id = resolved.jar.clone().unwrap_or_else(|| version_id.clone());
let assets_root = env.game.assets_dir();
let assets_root = game.assets_dir();
let assets_index = resolved
.assets
.clone()
@@ -145,7 +148,7 @@ pub fn build_request(
// `26w14a-fabric-0.16.5` 这种 id 在 `GameVersion::is_weekly_snapshot`(6 字符形态)上判不出来,
// 周快照的 `--graphicsBackend` 会在拼装链里被静默跳过——而详情页的门槛
// (`host::launch_args::backend_gate`)与 CLI 用的都是根版本,两边必须同一口径。
let (mc_version, _) = super::game::describe_version(env, &version_id);
let (mc_version, _) = super::game::describe_version(&game, &version_id);
let snapshot = SnapshotInput {
version_id: &version_id,
version_name: Some(&target.name),
@@ -157,11 +160,11 @@ pub fn build_request(
legacy_arguments: resolved.minecraft_arguments.as_deref(),
libraries: &libraries,
natives: &natives,
primary_jar: env.game.version_jar(&jar_id),
primary_jar: game.version_jar(&jar_id),
game_dir,
assets_index: assets_index.as_deref(),
natives_dir: env.game.natives_dir(&version_id),
library_dir: env.game.libraries_dir(),
natives_dir: game.natives_dir(&version_id),
library_dir: game.libraries_dir(),
assets_root: assets_root.clone(),
game_assets: assets_root,
};
@@ -197,18 +200,22 @@ pub fn build_request(
///
/// 基底档对自动发现的实例是「盘上有没有痕迹」,对其它实例就是全局 `instances.mode`——
/// 于是这里不需要知道实例是从哪来的,只有一处判据。
fn run_dir(env: &HostEnv, target: &LaunchTarget) -> Result<PathBuf, LaunchFailureView> {
let base = super::game::base_mode(env, &target.id, &target.version_id);
fn run_dir(
env: &HostEnv,
game: &unlucky_core::game::GameLayout,
target: &LaunchTarget,
) -> Result<PathBuf, LaunchFailureView> {
let base = super::game::base_mode(env, game, &target.id, &target.version_id);
let config = read_instance_config(&env.layout, &target.id).map_err(|error| {
LaunchFailureView::new(LaunchFailureStage::InstanceConfig, error.to_string())
})?;
let derivation = derive_game_dir(&env.game, &target.version_id, base, config.as_ref(), None)
let derivation = derive_game_dir(game, &target.version_id, base, config.as_ref(), None)
.map_err(|error| {
LaunchFailureView::new(LaunchFailureStage::Isolation, error.to_string())
})?;
if let Some(mut config) = config {
let at = format_rfc3339_millis(now());
if observe_mode(&mut config, &env.game, &at, derivation.isolation).unwrap_or(false) {
if observe_mode(&mut config, game, &at, derivation.isolation).unwrap_or(false) {
let _ =
unlucky_core::game::install::instance::write_instance_config(&env.layout, &config);
}
@@ -227,11 +234,14 @@ pub fn start(env: HostEnv, tx: JobSender, target: LaunchTarget) {
let logs_dir = env.layout.logs();
launcher_log::set_dir(&logs_dir);
let started_at = std::time::SystemTime::now();
// 崩溃报告里的「游戏目录」必须是**这个实例自己那个根**(M274):官方根里的实例崩了,
// 报告却写着 ULL 便携根的路径,等于把排障指到别人的目录上。
let game = super::game::game_for(&env, &target.id);
let mut report = ReportContext::new(
&target.id,
&target.name,
&target.version_id,
&env.data.game_home,
game.root(),
&logs_dir,
started_at,
unlucky_core::platform::os_info::current().summary_line(),
@@ -261,7 +271,7 @@ pub fn start(env: HostEnv, tx: JobSender, target: LaunchTarget) {
}
};
report.run_dir = request.dirs.game_dir.clone();
report.version_json = Some(env.game.version_json(&target.version_id));
report.version_json = Some(game.version_json(&target.version_id));
report.java = launcher_log::java_label(&request.java.binary, request.java.major);
for warning in &warnings {
let _ = tx.send(HostTask::Notice(Box::new(crate::dto::NoticeView::new(