diff --git a/crates/presenter/src/host/game.rs b/crates/presenter/src/host/game.rs index fb33603..960ab82 100644 --- a/crates/presenter/src/host/game.rs +++ b/crates/presenter/src/host/game.rs @@ -87,17 +87,24 @@ pub fn loader_from_id(version_id: &str) -> LoaderInfo { } } -/// core 的加载器种类 → DTO 种类(穷尽 match:core 加一支,这里就编不过)。 +/// core 的加载器种类 → DTO 种类。 +/// +/// **这里没有映射表**:种类由 core 的稳定 id 反查 DTO 词表得来([`LoaderKind::parse`] → +/// `dto::LoaderKind::from_core`,全仓唯一那份 core↔DTO 映射)。M134 之前这里是七支手写 match, +/// M126 r3 复审实测过:core 加第八家、契约与 help 都补齐、**只在这一支写 `=> Vanilla`**,三个 +/// crate 全绿(402 / 220 / 42)而磁贴静默显示「原版」——M122 修掉的用户可见 bug 复活。委派之后 +/// **没有落笔处**:新种类必须先过 `dto::LoaderKind::from_core`(那边编不过就说明 DTO 还没决定怎么 +/// 显示它),糊错的后果由 `dto::instances` 的 `loader_kind_ids_are_the_released_contract` 与本 +/// 文件的 `every_core_loader_kind_reaches_the_tile_as_itself` 钉住。反查不到只能是 core 的 +/// `as_str` 与 `parse` 自相矛盾(同一张宏表长出来,物理上做不到),真发生了就 panic:**不许** +/// 退回「原版」。 fn dto_kind(kind: unlucky_core::game::LoaderKind) -> LoaderKind { - match kind { - unlucky_core::game::LoaderKind::Vanilla => LoaderKind::Vanilla, - unlucky_core::game::LoaderKind::Fabric => LoaderKind::Fabric, - unlucky_core::game::LoaderKind::Quilt => LoaderKind::Quilt, - unlucky_core::game::LoaderKind::Forge => LoaderKind::Forge, - unlucky_core::game::LoaderKind::NeoForge => LoaderKind::NeoForge, - unlucky_core::game::LoaderKind::OptiFine => LoaderKind::OptiFine, - unlucky_core::game::LoaderKind::LiteLoader => LoaderKind::LiteLoader, - } + LoaderKind::parse(kind.as_str()).unwrap_or_else(|| { + unreachable!( + "core 的稳定 id `{}` 反查不到 DTO 种类:词表两边脱节了", + kind.as_str() + ) + }) } /// 实例的隔离档位(实例文件优先,缺省显示全局档位)。 @@ -203,9 +210,9 @@ mod tests { /// 版本 id → DTO 加载器的接口面(解析在 core,这里只验翻译没走样)。 /// - /// 抓得住:`dto_kind` 把某个种类翻错/翻塌(例如 Quilt 写成 Forge),以及 core 解析端 - /// 退回老口径(`fabric-loader-…` 才认、自家 `1.20.4-fabric-0.16.5` 认不出)——后两条 - /// 正是 M122 的 bug 面。 + /// 抓得住:显示路径把某个种类翻错/翻塌(例如 Quilt 写成 Forge)——`dto_kind` 的委派与 + /// `dto` 的 `from_core` 都落在这一条上;以及 core 解析端退回老口径(`fabric-loader-…` 才认、 + /// 自家 `1.20.4-fabric-0.16.5` 认不出)——后两条正是 M122 的 bug 面。 /// 抓不住:core 解析规则本身(真值表在 `unlucky_core::game::loader` 的测试里,那边才是 /// 真相源);也抓不住「版本号为空时不显示品牌名」那条(在 `LoaderInfo::badge` 与 /// app-iced 的 `loader_badge`,M120 已修,别在这里重复)。 @@ -233,32 +240,36 @@ mod tests { } } - /// 边界翻译不许把两个种类塌成一个(七个 arm 手写,复制粘贴最容易在这里出事)。 + /// 显示路径的**全量**锚:core 的每一种加载器,从自家版本 id 走到磁贴时仍然是**它自己**。 /// - /// 抓得住:`dto_kind` 里某个 arm 抄错(`Quilt => LoaderKind::Fabric` 之类)——种类集合 - /// 会少一个、出现重复;`Vanilla` 只能由 `Vanilla` 来,所以「认成原版」不会被错翻掩盖。 - /// 抓不住:core 端把 id 认成错的种类(那是 core 真值表的活)。 + /// 清单取自 [`unlucky_core::game::LoaderKind::ALL`],**不手抄**:M126 r3 复审实测出的缺口正是 + /// 「手抄的清单跟着漏」——core 加第八家、契约与 help 都补齐、只在 `dto_kind` 那一支写 + /// `=> Vanilla`,三个 crate 全绿而磁贴静默显示「原版」。`ALL` 由 core 的宏表长出来,加一家 + /// 自动进圈,测试作者不需要(也没法)记得补一行。 + /// + /// 抓得住:显示路径任何一环把种类翻塌成原版——`dto_kind` 又变回手写映射、`dto` 的 + /// `from_core` 那一支接错、`label()` 被写成「原版」;**包括新加的那种**(那时 `ALL` 先变长)。 + /// 抓不住:core 的 id 解析规则本身(真值表在 `unlucky_core::game::loader`);版本号为空的 + /// 徽标判据(M120 的 `loader_badge`,本 crate 不渲染)。 #[test] - fn dto_kind_is_injective_over_all_core_kinds() { + fn every_core_loader_kind_reaches_the_tile_as_itself() { use unlucky_core::game::LoaderKind as Core; - let all = [ - Core::Vanilla, - Core::Fabric, - Core::Quilt, - Core::Forge, - Core::NeoForge, - Core::OptiFine, - Core::LiteLoader, - ]; - let mapped: Vec = all.iter().copied().map(dto_kind).collect(); - for (index, kind) in mapped.iter().enumerate() { - assert!( - !mapped[..index].contains(kind), - "core 的 {:?} 与前面的种类翻成了同一个 DTO 种类 {kind:?}", - all[index] + for kind in Core::ALL { + let info = loader_from_id(&format!("1.20.4-{}-0.16.5", kind.as_str())); + assert_eq!( + info.kind.as_str(), + kind.as_str(), + "core 的 {kind:?} 走到磁贴时变成了 `{}`(徽标 `{}`)", + info.kind.as_str(), + info.badge() + ); + assert_eq!( + info.badge().starts_with(LoaderKind::Vanilla.label()), + kind == Core::Vanilla, + "core 的 {kind:?} 在磁贴上的徽标是 `{}`", + info.badge() ); } - assert_eq!(dto_kind(Core::Vanilla), LoaderKind::Vanilla); } /// 端到端(数据层):真装出来的四个加载器实例,走 [`instances`] 的快照各自带对加载器。