fix(core): LiteLoader 快照仓固定为 repo.mumfrey.com/snapshots(1.10.2 的 repo.url 是 /repo/ 形态,照它会 404)

This commit is contained in:
AskaEth committed 2026-11-10 19:34:10 +08:00
1 parent 944b1610c8
commit 7ed954f7fa
5 files changed
+164 -12

No files matched your search

+16 -7
View File
@@ -216,15 +216,28 @@ fn lift_flat_digest(library: &mut Library) {
} }
/// loader 本体库必须在列表里:缺了就补一条(并用告警说明),别装出个"没有 loader"的实例。 /// loader 本体库必须在列表里:缺了就补一条(并用告警说明),别装出个"没有 loader"的实例。
///
/// 只有 fabric 系会走到这里(调用方 [`build_release`] 的入口已按
/// [`LoaderKind::is_fabric_family`] 分流);这里仍然**穷尽 match**,因为过去那对 `_ =>`
/// 会在新加一支加载器时把它静默当成 `fabric-loader` 补进库表。
fn ensure_loader_library( fn ensure_loader_library(
kind: LoaderKind, kind: LoaderKind,
loader_version: &str, loader_version: &str,
libraries: &mut Vec<Library>, libraries: &mut Vec<Library>,
warnings: &mut Vec<String>, warnings: &mut Vec<String>,
) { ) {
let (group, artifact) = match kind { let (group, artifact, maven_base) = match kind {
LoaderKind::Quilt => ("org.quiltmc", "quilt-loader"), LoaderKind::Fabric => (
_ => ("net.fabricmc", "fabric-loader"), "net.fabricmc",
"fabric-loader",
"https://maven.fabricmc.net/",
),
LoaderKind::Quilt => (
"org.quiltmc",
"quilt-loader",
"https://maven.quiltmc.org/repository/release/",
),
LoaderKind::NeoForge | LoaderKind::Forge | LoaderKind::LiteLoader => return,
}; };
let present = libraries.iter().any(|library| { let present = libraries.iter().any(|library| {
library library
@@ -234,10 +247,6 @@ fn ensure_loader_library(
if present { if present {
return; return;
} }
let maven_base = match kind {
LoaderKind::Quilt => "https://maven.quiltmc.org/repository/release/",
_ => "https://maven.fabricmc.net/",
};
libraries.push(Library { libraries.push(Library {
name: format!("{group}:{artifact}:{loader_version}"), name: format!("{group}:{artifact}:{loader_version}"),
url: Some(maven_base.to_string()), url: Some(maven_base.to_string()),
@@ -45,6 +45,18 @@ pub const DEFAULT_REPO: &str = "https://dl.liteloader.com/versions/";
/// 非 Mojang 库的基址:Mojang 库仓里没有 `asm-all:5.2`(实测 404),Central 有(实测 206)。 /// 非 Mojang 库的基址:Mojang 库仓里没有 `asm-all:5.2`(实测 404),Central 有(实测 206)。
pub const CENTRAL_REPO: &str = "https://repo1.maven.org/maven2/"; pub const CENTRAL_REPO: &str = "https://repo1.maven.org/maven2/";
/// 快照分支的仓库根——**固定这一个**,不跟着 `repo.url` 走。
///
/// 上游每个原版版本的 `repo.url` 有两种形态(`…/versions/` 与 `…/repo/`),而**快照只发布在
/// snapshots 仓**:1.10.2 的 `repo.url` 是 `http://dl.liteloader.com/repo/`,按它拼
/// `…/repo/com/mumfrey/liteloader/1.10.2-SNAPSHOT/maven-metadata.xml` 实测会 302 到
/// `…/repositories/liteloader/…` 再 404;而
/// `https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/1.10.2-SNAPSHOT/maven-metadata.xml`
/// 是 200。HMCL 的构建脚本同样把这个快照仓**写死**(`UpdateLiteLoaderVersionList.SNAPSHOT_FILE`,
/// 注释还引了它自己的 issue #3147)。1.12.2 的 `repo.url` 恰好就是这条路径,所以只测 1.12.2
/// 看不出这个问题——单测专门钉了 1.10.2。
pub const SNAPSHOT_REPO: &str = "https://repo.mumfrey.com/content/repositories/snapshots/";
/// launchwrapper 主类(LiteLoader 靠它做 tweak 注入)。 /// launchwrapper 主类(LiteLoader 靠它做 tweak 注入)。
pub const LAUNCHWRAPPER_MAIN: &str = "net.minecraft.launchwrapper.Launch"; pub const LAUNCHWRAPPER_MAIN: &str = "net.minecraft.launchwrapper.Launch";
@@ -7,7 +7,9 @@ use std::collections::{BTreeMap, BTreeSet};
use serde::Deserialize; use serde::Deserialize;
use super::{LiteLoaderEntry, LoaderError, CENTRAL_REPO, DEFAULT_REPO, VERSION_LIST_URL}; use super::{
LiteLoaderEntry, LoaderError, CENTRAL_REPO, DEFAULT_REPO, SNAPSHOT_REPO, VERSION_LIST_URL,
};
use crate::game::library::Library; use crate::game::library::Library;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@@ -110,7 +112,8 @@ fn collect(
let snapshot = snapshot_branch || record.stream.eq_ignore_ascii_case("SNAPSHOT"); let snapshot = snapshot_branch || record.stream.eq_ignore_ascii_case("SNAPSHOT");
let dir = format!("{repo}com/mumfrey/liteloader/{mc_version}/"); let dir = format!("{repo}com/mumfrey/liteloader/{mc_version}/");
let (url, snapshot_dir) = if snapshot { let (url, snapshot_dir) = if snapshot {
let snap_dir = format!("{repo}com/mumfrey/liteloader/{mc_version}-SNAPSHOT/"); // 快照仓是**固定**的(见 `SNAPSHOT_REPO` 的注释),不跟 `repo.url` 走。
let snap_dir = format!("{SNAPSHOT_REPO}com/mumfrey/liteloader/{mc_version}-SNAPSHOT/");
(None, Some(snap_dir)) (None, Some(snap_dir))
} else { } else {
( (
@@ -1,8 +1,9 @@
//! LiteLoader 数据源与合成:官方版本表(**真实响应的裁剪版**)→ 版本条目 → 合成清单。 //! LiteLoader 数据源与合成:官方版本表(**真实响应的裁剪版**)→ 版本条目 → 合成清单。
//! //!
//! 夹具 `LITELOADER_VERSIONS` 是 2026-11 从 `https://dl.liteloader.com/versions/versions.json` //! 夹具 `LITELOADER_VERSIONS` 是 2026-11 从 `https://dl.liteloader.com/versions/versions.json`
//! 真取的一份响应(200 / 49129 字节 / 16 个原版版本)里挑两个原版版本原样留下: //! 真取的一份响应(200 / 49129 字节 / 16 个原版版本)里挑三个原版版本原样留下:
//! `1.7.10`(release 分支)+ `1.12.2`(只有 snapshots 分支)。删掉的是另外 14 个原版版本与 //! `1.7.10`(只有 release 分支)、`1.10.2`(release + snapshots,且 `repo.url` 是 `…/repo/`
//! 形态——专门用来钉「快照仓固定」这条)、`1.12.2`(只有 snapshots 分支)。删掉的是另外 13 个原版版本与
//! 每个版本下的多余分支;**字段名与结构一个没改**(键仍是 md5、`latest` 别名也留着,用来 //! 每个版本下的多余分支;**字段名与结构一个没改**(键仍是 md5、`latest` 别名也留着,用来
//! 钉「跳过别名 + 按 version 去重」)。`LITELOADER_METADATA` 是同一次探测里取的 //! 钉「跳过别名 + 按 version 去重」)。`LITELOADER_METADATA` 是同一次探测里取的
//! `repo.mumfrey.com/…/liteloader/1.12.2-SNAPSHOT/maven-metadata.xml`(200 / 358 字节)。 //! `repo.mumfrey.com/…/liteloader/1.12.2-SNAPSHOT/maven-metadata.xml`(200 / 358 字节)。
@@ -52,6 +53,39 @@ const LITELOADER_VERSIONS: &str = r#"{
} }
}} }}
}, },
"1.10.2": {
"repo": {"stream": "RELEASE", "type": "m2", "url": "http://dl.liteloader.com/repo/", "classifier": ""},
"artefacts": {"com.mumfrey:liteloader": {
"8a7c21f32d77ee08b393dd3921ced8eb": {
"tweakClass": "com.mumfrey.liteloader.launch.LiteLoaderTweaker",
"libraries": [{"name": "net.minecraft:launchwrapper:1.12"}, {"name": "org.ow2.asm:asm-all:5.0.3"}],
"stream": "RELEASE",
"file": "liteloader-1.10.2.jar",
"version": "1.10.2",
"md5": "8a7c21f32d77ee08b393dd3921ced8eb",
"timestamp": "1479473570"
}
}},
"snapshots": {
"libraries": [
{"name": "net.minecraft:launchwrapper:1.12"},
{"name": "org.spongepowered:mixin:0.5.17-SNAPSHOT", "url": "https://repo.spongepowered.org/maven/"}
],
"com.mumfrey:liteloader": {
"1cdd72f7232e45551f16cc8ffd27ccf3": {
"tweakClass": "com.mumfrey.liteloader.launch.LiteLoaderTweaker",
"libraries": [{"name": "net.minecraft:launchwrapper:1.12"}, {"name": "org.ow2.asm:asm-all:5.0.3"}],
"stream": "SNAPSHOT",
"file": "liteloader-1.10.2-SNAPSHOT.jar",
"version": "1.10.2-SNAPSHOT",
"build": "1.10.2-SNAPSHOT-rE85C8AE-b11-11",
"md5": "1cdd72f7232e45551f16cc8ffd27ccf3",
"timestamp": "1485987183",
"lastSuccessfulBuild": 11
}
}
}
},
"1.12.2": { "1.12.2": {
"repo": {"stream": "SNAPSHOT", "type": "m2", "url": "http://repo.mumfrey.com/content/repositories/snapshots/", "classifier": ""}, "repo": {"stream": "SNAPSHOT", "type": "m2", "url": "http://repo.mumfrey.com/content/repositories/snapshots/", "classifier": ""},
"snapshots": { "snapshots": {
@@ -105,7 +139,7 @@ const LITELOADER_METADATA: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
#[test] #[test]
fn parses_the_real_version_table() { fn parses_the_real_version_table() {
let table = parse_versions(LITELOADER_VERSIONS).expect("真实响应必须能解析"); let table = parse_versions(LITELOADER_VERSIONS).expect("真实响应必须能解析");
assert_eq!(table.len(), 2, "只留了两个原版版本"); assert_eq!(table.len(), 3, "只留了三个原版版本");
// release 分支:按 version 去重、新的排前面。 // release 分支:按 version 去重、新的排前面。
let releases = &table["1.7.10"]; let releases = &table["1.7.10"];
@@ -274,3 +308,31 @@ fn unknown_version_does_not_fall_back() {
let error = parse_versions(r#"{"versions": []}"#).expect_err("形状不符必须报错"); let error = parse_versions(r#"{"versions": []}"#).expect_err("形状不符必须报错");
assert_eq!(error.kind(), LoaderErrorKind::Metadata); assert_eq!(error.kind(), LoaderErrorKind::Metadata);
} }
/// 快照仓**固定**在 `repo.mumfrey.com/content/repositories/snapshots/`,不跟 `repo.url` 走。
///
/// 抓得住:1.10.2 的 `repo.url` 是 `…/repo/`,照它拼快照路径会 302 到
/// `…/repositories/liteloader/…` 再 404(实测)。1.12.2 的 `repo.url` 恰好就是快照仓,
/// 所以只测 1.12.2 会漏掉这个 bug。
#[test]
fn snapshot_repo_is_fixed_not_taken_from_repo_url() {
let table = parse_versions(LITELOADER_VERSIONS).expect("解析");
let entries = &table["1.10.2"];
let snapshot = entries
.iter()
.find(|entry| entry.snapshot)
.expect("1.10.2 应有快照条目");
assert_eq!(
snapshot.snapshot_dir.as_deref(),
Some("https://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/1.10.2-SNAPSHOT/")
);
// release 条目仍走该版本自己的 `repo.url`(上游 `/repo/` 会 302 到真地址,引擎跟重定向)。
let release = entries
.iter()
.find(|entry| !entry.snapshot)
.expect("1.10.2 应有 release 条目");
assert_eq!(
release.url.as_deref(),
Some("https://dl.liteloader.com/repo/com/mumfrey/liteloader/1.10.2/liteloader-1.10.2.jar")
);
}
+66
View File
@@ -172,3 +172,69 @@ fn stacks_on_forge_and_keeps_the_forge_tweak_class() {
.expect("缺 LiteLoader 本体库"); .expect("缺 LiteLoader 本体库");
assert!(forge_lib < liteloader_lib, "{libraries:?}"); assert!(forge_lib < liteloader_lib, "{libraries:?}");
} }
/// **新式 args 的父链**:父版本用 `arguments.game`(没有 `minecraftArguments`)。
///
/// 现实里 LiteLoader 只到 1.12.2,碰不到这种父版本;但「追加语义」是这套路线的准入条件,
/// 两种父版本形状都得钉住——否则哪天上游把老版本清单改成新式,我们会静默丢参数。
/// 这里用一份**手工夹具**(`--launchTarget forgeclient` 是 Forge 1.13+ 的真实形态)说明:
/// 父层参数在前、LiteLoader 的 tweakClass 在后,中间不互相覆盖。
#[test]
fn new_style_parent_args_are_appended_not_replaced() {
const MODERN_PARENT: &str = r#"{
"id": "1.12.2-modern-1.0",
"inheritsFrom": "1.12.2",
"mainClass": "net.minecraft.launchwrapper.Launch",
"arguments": {"game": ["--launchTarget", "forgeclient"], "jvm": ["-Dmodern=1"]},
"libraries": [{"name": "example:modern:1.0", "url": "https://example.invalid/"}]
}"#;
let temp = TempDir::new("modern-args");
let layout = GameLayout::new(temp.path());
put_version(&layout, "1.12.2", VANILLA_1122);
put_version(&layout, "1.12.2-modern-1.0", MODERN_PARENT);
let release = liteloader_release("1.12.2-modern-1.0");
let plan = LoaderInstallPlan::build(LoaderPlanInput {
layout: &layout,
release: &release,
environment: &Environment::host(),
parent_installed: true,
})
.expect("计划应可组");
let engine = engine(temp.path());
prefill(&plan.install);
let report = block_on(execute(&engine, &plan.install, 4, None)).expect("执行应成功");
assert!(report.is_complete(), "{:?}", report.failures(3));
let mut source = std::collections::BTreeMap::new();
source.insert("1.12.2".to_string(), read_version(&layout, "1.12.2"));
source.insert(
"1.12.2-modern-1.0".to_string(),
read_version(&layout, "1.12.2-modern-1.0"),
);
source.insert(
release.version_id.clone(),
read_version(&layout, &release.version_id),
);
let resolved = resolve(&source, &source[&release.version_id]).expect("三层继承应可解析");
// 父层用的是新式参数:子层没有把 legacy 串写进来,继承后仍然没有。
assert!(resolved.minecraft_arguments.is_none());
let game = resolved
.arguments
.as_ref()
.expect("arguments")
.expand(&Environment::host())
.game;
let assert_order = |needle: &str| {
game.iter()
.position(|token| token == needle)
.unwrap_or_else(|| panic!("缺 `{needle}`:{game:?}"))
};
assert!(
assert_order("forgeclient")
< assert_order("com.mumfrey.liteloader.launch.LiteLoaderTweaker"),
"父层参数必须在前:{game:?}"
);
}