补丁注册框架

基本信息

属性 值
注册表 mixins/Mixins.java(815 行,枚举 Mixins)
注册接口 com.gtnewhorizon.gtnhmixins.builders.IMixins
枚举常量数 153
引用的 mixin 类 206 处引用,去重后 204 个
磁盘上的 mixin 类 204(mixins/early 4 个 + mixins/late 200 个)
构建器 Mixins.SalisBuilder(Mixins.java:764 起)
目标模组表 mixins/TargetedMod.java(13 个常量)

功能

三个 mixins.*.json 里的 mixins 数组全是空的——它们只声明了 package(如 dev.rndmorris.salisarcana.mixins.late), 清单由注解处理器在编译期生成。真正的清单是 Mixins 枚举本身:

{
  "required": true,
  "minVersion": "0.7.10",
  "refmap": "mixins.salisarcana.refmap.json",
  "package": "dev.rndmorris.salisarcana.mixins.late",
  "target": "@env(DEFAULT)",
  "compatibilityLevel": "JAVA_8",
  "mixinextras": {"minVersion": "0.5.0"}
}

——src/main/resources/mixins.salisarcana.late.json。

Mixins 实现 GTNHLib 的 IMixins,由框架反射读取枚举常量,每个常量通过 SalisBuilder 声明自己的条件与混入类。这是本模组唯一的内容注册表。

上述 IMixins 形参类型取自 Mixins.java:5 的真实 import com.gtnewhorizon.gtnhmixins.builders.IMixins。 附带说明:mirror/UniMixins 中的 com/gtnewhorizon/gtnhmixins/ 包 只有 GTNHMixins、IEarlyMixinLoader、ILateMixinLoader、LateMixin 等, 没有 builders/ 子包与 IMixins.java——本地 UniMixins 镜像与本模组 编译所依赖的版本(README 要求 0.1.23+)布局不同。 因此该接口类是否存在于所依赖的确切版本中无法本地核实; 可核实的只有 import 语句本身。同目录下的 IEarlyMixinLoader 则确实存在。

完整性校验

Mixins.java 中以字符串形式引用的 mixin 类,与磁盘上的 .java 文件做了双向比对:

方向 结果
注册表引用 → 磁盘文件 204 个引用全部存在,悬空引用 0
磁盘文件 → 注册表引用 204 个文件全部被引用,孤儿文件 0
阶段一致性 全部匹配(early 包中的类只被 Phase.EARLY 常量引用,反之亦然)

被两个枚举常量共同引用的类有 2 个(属有意为之,类内部会同时读取两组设置):

类 被引用的常量
thaumcraft.client.gui.MixinGuiResearchBrowser_Creative_Scroll CTRL_SCROLL_NAVIGATION、CREATIVE_OP_THAUMONOMICON
thaumcraft.common.lib.world.MixinThaumcraftWorldGenerator_NodeGenerationWeights NODE_GENERATION_MODIFIER_WEIGHTS、NODE_GENERATION_TYPE_WEIGHTS

因此 206 = 204 + 2。

构建器 API

SalisBuilder extends MixinBuilder(Mixins.java:764)在枚举体内被调用的方法:

方法 出现次数 作用
addRequiredMod(TargetedMod.X) 152 要求目标模组已加载
applyIf(Setting) 137 直接以某个设置为条件
addCommonMixins(String...) 123 公共侧混入类
addClientMixins(String...) 40 客户端混入类
setApplyIf(BooleanSupplier) 12 以 lambda 为条件(需要组合多个条件时使用)
addExcludedMod(TargetedMod.X) 1 目标模组存在时不应用
setRequired() 1 声明本补丁必须应用

applyIf 与 setRequired 都只是对父类 setApplyIf 的薄封装:

public MixinBuilder applyIf(Setting config) {
    return super.setApplyIf(config::isEnabled);
}

public MixinBuilder setRequired() {
    return super.setApplyIf(() -> true);
}

——Mixins.java:774-780。这正是 applyIf 的形参类型可以直接是 Setting (137 处调用中绝大多数只写一个 SalisConfig.xxx.yyy)的原因。

Mixins.java:787-813 另有 4 段被注释掉的覆写(addServerMixins、 addClientMixins、addCommonMixins 与 assertClassesExist)。它们是开发期校验工具, 按「注释掉的注册计为零」的规则不计入上表。Mixins.java:747-749 还有一个 被注释掉的 INTENTIONAL_FAILURE 枚举常量(故意指向不存在的类名), 同样不计入 153 之数。源码注释(Mixins.java:745-746、Mixins.java:782-785) 明确写了这套校验「仅供开发期使用,合并进 main 时不应取消注释」, 属于有明确意图证据的注释,不是缺陷。

阶段

只有 2 个常量使用 Phase.EARLY(Mixins.java:17、Mixins.java:19), 其余 151 个走默认的 LATE 阶段:

枚举常量 行 混入类 条件 排除
ACCESSORS 17 accessor.AccessorGuiContainer、accessor.AccessorMinecraft、accessor.AccessorCreativeSlot 始终应用 —
VANILLA_GUI_KEY_TYPED 19 gui.MixinGuiContainer_HandleKeyTyped 始终应用 NotEnoughItems

VANILLA_GUI_KEY_TYPED 是全仓唯一使用 addExcludedMod 的补丁:NEI 会自行接管 按键处理,装了 NEI 就必须让开。

不受配置开关控制的条件

以下 9 个常量的条件里没有 SalisConfig 引用,或引用方式特殊:

枚举常量 行 条件 依赖 混入类
ACCESSORS 17 始终应用 — 3 个访问器
VANILLA_GUI_KEY_TYPED 19 始终应用 — gui.MixinGuiContainer_HandleKeyTyped
THAUM_ACCESSORS 27 始终应用 Thaumcraft thaumcraft.common.container.AccessorContainerFocusPouch
CAPTURE_FOCUS_KEYBIND 30 () -> !MixinModCompat.multiKeyBindsPermitted() Thaumcraft thaumcraft.common.lib.events.MixinKeyHandler_CaptureFocusKeybind
ADD_VISCONTAINER_INTERFACE 737 始终应用(setRequired()) Thaumcraft thaumcraft.common.items.MixinAmuletWand_AddInterface
AUTOMAGY_BOILER_FAKEPLAYER 301 SalisConfig.addons.automagyBoilerFakePlayer Automagy automagy.blocks.MixinBlockBoiler_FakePlayer
DEBUG_LOG_WARP_STACK_TRACE 731 SalisConfig.debug.logWarpSources Thaumcraft thaumcraft.common.lib.research.MixinPlayerKnowledge_DebugLogWarp
FOCUS_POUCH_SLOT 645 SalisConfig.modCompat.baublesExpanded.focusPouchSlot Thaumcraft、Baubles|Expanded thaumcraft.common.items.wands.MixinItemFocusPouchBauble_ExpandedBaublesSlot
MIXIN_ANGELICA_FONTRENDERER 717 () -> SalisConfig.modCompat.angelica.replaceTCFontRenderer.isEnabled() && TargetedMod.ANGELICA.isLoaded() && AngelicaConfig.enableFontRenderer Thaumcraft、angelica thaumcraft.client.lib.MixinTCFontRenderer_AngelicaFontRenderer

其中 MIXIN_ANGELICA_FONTRENDERER 的条件是三重与:不仅要设置开启、 Angelica 已加载,还要求 AngelicaConfig.enableFontRenderer 自身为真。 AUTOMAGY_BOILER_FAKEPLAYER 的混入目标也不在 Thaumcraft 包里, 而是 automagy.blocks.MixinBlockBoiler_FakePlayer。

ACCESSORS 与 THAUM_ACCESSORS 的源码注释说明了「始终应用」的理由:这些访问器 不改变 Thaumcraft 代码的执行过程,冲突概率极低,且始终应用使得次元袋快捷存入 可以在运行时动态开关(Mixins.java:24-26)。

按配置分组统计

153 个常量按其 applyIf 指向的 SalisConfig 分组归类:

分组 常量数 引用 mixin 类数 对应页面
SalisConfig.bugfixes.* 73 106 缺陷修复补丁
SalisConfig.features.* 53 70 功能增强补丁
SalisConfig.thaum.* 18 19 神秘时代配置补丁
SalisConfig.modCompat.* 2 2 见上表
SalisConfig.addons.* 1 1 见上表
SalisConfig.debug.* 1 1 见上表
无配置条件 5 7 见上表
合计 153 206

「无配置条件」= 4 个始终应用 + CAPTURE_FOCUS_KEYBIND(条件为 !MixinModCompat.multiKeyBindsPermitted(),不含 SalisConfig)。 各组引用数之和 106+70+19+2+1+1+7 = 206。

目标模组

TargetedMod(mixins/TargetedMod.java:12-24)列出 13 个可被补丁定向的模组, modId 字段即真实 modid,isLoaded() 走 Loader.isModLoaded(modId) 并缓存结果。 其中 NotEnoughItems 是本模组唯一声明了核心模组类的目标:

常量 modid 核心模组类
NOT_ENOUGH_ITEMS NotEnoughItems codechicken.nei.asm.NEICorePlugin

其余 12 个常量使用单参构造,无核心模组类。13 个常量全部被引用, 无未使用的死枚举项(THAUMCRAFT 被引用 147 次,TC4_TWEAKS、NOT_ENOUGH_ITEMS、 ANGELICA 各 3 次,其余各 1–2 次)。

相关条目