fix(core): M110 r2 —— duplicate_override_paths 两种冲突同时报,补 mrpack 同侧分支用例

- p2-2:`duplicate_override_paths` 改成「先按 path 分组,再在组内报 (侧集合, 条目份数)」,
  判据 `侧数 > 1 || 份数 > 侧数`。r1 修好了跨侧(Both×Client)但按侧去重把「同侧两个组
  撞同一路径」这条旧能力换掉了(实测返回 []);现在两种冲突同时报得出来,返回值升为
  `Vec<(String, Vec<PackSide>, usize)>`(M111 注意:这是最后一次改形状的窗口)。
- p3-a:mrpack `check_overrides` 的「每侧只能有一个覆盖目录」分支补用例(此前零测试,
  删掉它 54 条全绿;现在删掉即红)。
- p3-b:把 ReadBudget 的「每次调用一份额度,不是整包一份」写进 `override_files` /
  `ReadBudget` 文档(mrpack 连调三次 ⇒ 理论上限 3×;要整包共用额度就走
  `override_files_with`;`open` 阶段的声明总量仍是整包一次)。
- 顺带(复审点名、各一行):mrpack 非表达目录的 hint 里 21 个连续空格;
  curseforge 文档里 `.minecraft/.minecraft/…` 的说法按 CF 语义订正(overrides 是 zip 内前缀,
  内容铺开不丢;要不要多拷一层取决于导入器)。
This commit is contained in:
AskaEth committed 2026-11-04 00:20:25 +08:00
1 parent 6dd652aced
commit 34f3db359a
7 files changed
+111 -22

No files matched your search

+7 -2
View File
@@ -254,8 +254,13 @@ impl PackArchive {
/// 目录不存在时返回空表——"包没带 overrides"不是错误。
///
/// 这是**唯一会批量解压的 API**,所以它自己持有一个累计预算
/// (`PackLimits::max_uncompressed_bytes`),逐条按实际读出的字节扣减:
/// 声明大小撒谎的包不会在这里把 CPU 时间耗光(r1 p3-4)。
/// (`PackLimits::max_uncompressed_bytes`),本次调用内逐条按实际读出的字节扣减:
/// 声明大小撒谎的包不会靠"很多条各自合规"把 CPU 时间耗光(r1 p3-4)。
///
/// **额度是"每次调用一份",不是"整包一份"**(r2 p3-b):格式读者若对多个覆盖目录各调一次
/// (mrpack 会连调三次:`overrides` / `client-overrides` / `server-overrides`),理论上限
/// 是 `max_uncompressed_bytes × 调用次数`。要整包共用一份额度,就自己建 [`ReadBudget`]
/// 并走 [`Self::override_files_with`];`open` 阶段的"声明总量"仍然是整包只判一次。
pub fn override_files(&self, dir: &str) -> PackResult<Vec<OverrideFile>> {
let budget = ReadBudget::new(self.limits.max_uncompressed_bytes);
self.override_files_with(dir, &budget)