fix(core): 同一 loader 版本 id 撞两条父链时具名报错,不覆盖盘上清单(旧实例会静默换父链)

This commit is contained in:
AskaEth committed 2026-11-10 19:34:11 +08:00
1 parent 9c6b5eaa9b
commit 0eaefebf3b
2 files changed
+84

No files matched your search

+29
View File
@@ -182,6 +182,21 @@ impl LoaderInstallPlan {
/// 父版本缺了)。**不能默默回落成叠原版**:那会装出一份和用户意图不同的实例。
pub fn build(input: LoaderPlanInput<'_>) -> Result<Self, LoaderError> {
let release = input.release;
// 同一个 loader 版本 id 不能同时表示两条父链(`<原版>-liteloader-<ver>` 与
// 「叠在 Forge 上」撞同一个目录):盘上那份的 `inheritsFrom` 与本次请求不符就具名报错,
// 而不是把旧清单覆盖掉——旧实例会静默换父链,启动行为跟着变。
if let Some(existing) = existing_parent(input.layout, &release.version_id) {
if existing != release.parent_version_id {
return Err(LoaderError::unsupported(format!(
"{} 已装在盘上,父版本是 {existing},与本次请求的 {} 不同",
release.version_id, release.parent_version_id
))
.with_hint(format!(
"loader 版本 id 由「原版版本 + 加载器 + 加载器版本」决定,叠在别的层上会撞同一个目录:先删掉 versions/{}(旧实例也会失去这一层),或换一个加载器版本",
release.version_id
)));
}
}
if !input.parent_installed && !release.parent_is_vanilla() {
return Err(LoaderError::not_found(format!(
"父版本 {} 还没装好:{} {} 要叠在它上面",
@@ -262,3 +277,17 @@ impl LoaderInstallPlan {
summary
}
}
/// 盘上那份 `versions/<id>/<id>.json` 的 `inheritsFrom`(不存在 / 读不出 / 没写 → `None`)。
///
/// 只用来挡「同一版本 id 撞两条父链」,不参与其它判定:读失败不该让安装失败,
/// 所以错误一律吞成 `None`(真正的父子链校验由 [`crate::game::inherit::resolve`] 与
/// [`LoaderPlanInput::parent_installed`] 负责)。
fn existing_parent(layout: &GameLayout, version_id: &str) -> Option<String> {
let text = std::fs::read_to_string(layout.version_json(version_id)).ok()?;
let manifest = VersionJson::from_json_str(&text).ok()?;
manifest
.inherits_from
.map(|parent| parent.trim().to_string())
.filter(|parent| !parent.is_empty())
}