核心模组与 ASM 变换器

基本信息

属性 值
核心模组类 core.SalisArcanaCore(gradle.properties 的 coreModClass)
实际全限定名 dev.rndmorris.salisarcana.core.SalisArcanaCore
源文件 core/SalisArcanaCore.java(70 行)
标注 @IFMLLoadingPlugin + IEarlyMixinLoader
声明的 MC 版本 @IFMLLoadingPlugin.MCVersion("1.7.10")(SalisArcanaCore.java:17)
变换器排除 @IFMLLoadingPlugin.TransformerExclusions("dev.rndmorris.salisarcana.core")(SalisArcanaCore.java:18)
ASM 变换器 core/asm/SalisArcanaClassTransformer.java(78 行)
辅助文件 core/asm/ 5 个 + core/asm/transformers/ 2 个

功能

FML 的核心模组(coremod)在任何模组的 preInit 之前运行,因此可以在游戏类被 加载时修改其字节码。本模组通过两条途径做到这一点。

① ASM 变换器

getASMTransformerClass()(SalisArcanaCore.java:30-32)返回唯一一个变换器:

return new String[] { "dev.rndmorris.salisarcana.core.asm.SalisArcanaClassTransformer" };

SalisArcanaClassTransformer 内部维护一张 类全名 → ClassTransformer 的映射表 (SalisArcanaClassTransformer.java:17)。transform() 只对登记在表中的类 做字节码改写(SalisArcanaClassTransformer.java:62-68),其余类原样返回, 因此开销极小。同一个类被多次 addTransform 时由 ChainedTransformer::new 合并成链 (SalisArcanaClassTransformer.java:75)。

② 早期混入

getMixinConfig() 返回 mixins.salisarcana.early.json(SalisArcanaCore.java:56), getMixins(...) 交由 IMixins.getEarlyMixins(Mixins.class, loadedCoreMods) 解析 (SalisArcanaCore.java:61)。只有 2 个枚举常量走 Phase.EARLY。

其余 FML 钩子全部返回 null

钩子 返回值 行
getModContainerClass() null SalisArcanaCore.java:35-37
getSetupClass() null SalisArcanaCore.java:40-42
getAccessTransformerClass() null SalisArcanaCore.java:50-52

⚠️ getAccessTransformerClass() 返回 null 不代表没有访问变换器。 资源目录下存在 META-INF/salisarcana_at.cfg(8 行访问变换条目), 它是通过 gradle.properties 的 accessTransformersFile = salisarcana_at.cfg 声明的,走 gtnhconvention 插件的打包流程,而非 FML 钩子。

配置加载时机

SalisArcanaCore 的构造函数就调用了配置加载:

public SalisArcanaCore() {
    SalisConfig.synchronizeConfiguration();
}

——SalisArcanaCore.java:25-27。

这意味着 204 项设置在核心模组构造时(即任何模组的 preInit 之前) 就已全部读入。这也是补丁条件能在 Mixins 枚举求值时被安全查询的前提。

injectData(SalisArcanaCore.java:44-47)把 runtimeDeobfuscationEnabled 存入 isObf 字段;isObf()(SalisArcanaCore.java:64-69)在过早访问时 抛 IllegalStateException("Obfuscation state has been accessed too early!"), 而不是返回一个猜测值。

ASM 变换器的两处实际用途

ModCompatEditor — 与 Thaumic Mixins 抢占混入目标

构造函数第一段(SalisArcanaClassTransformer.java:20-32)创建了一个针对 xyz.uniblood.thaumicmixins.mixinplugin.ThaumicMixinsLateMixins 的 ModCompatEditor,拦截其 getMixins 方法(描述符 (Ljava/util/Set;)Ljava/util/List;),并声明 7 个冲突:

冲突的混入名 受哪个设置控制
MixinBlockCosmeticSolid bugfixes.beaconBlockFixSetting
MixinBlockCandleRenderer bugfixes.candleRendererCrashes
MixinBlockCandle bugfixes.candleRendererCrashes
MixinItemShard bugfixes.itemShardColor
MixinWandManager features.useAllBaublesSlots
MixinEventHandlerRunic features.useAllBaublesSlots
MixinWarpEvents_BaubleSlots features.useAllBaublesSlots

即:本模组对同一个 Thaumcraft 类做混入时,会让 Thaumic Mixins 让位, 避免两个模组对同一方法各注入一次。

⚠️ Thaumic Mixins 是一处未声明的集成:它既不在 dependencies.gradle 中, 也不在 TargetedMod 的 13 个常量里,只以字符串字面量形式出现在 SalisArcanaClassTransformer.java:21。因此它既没有 gradle 依赖声明, 也没有 FML 依赖声明,仅靠类名字符串定位。详见 模组兼容。

MethodRemover — 移除 fixBlockBoundsAlterations 覆盖的方法

受 SalisConfig.bugfixes.fixBlockBoundsAlterations 统一控制 (SalisArcanaClassTransformer.java:34),移除 3 组方法:

MCP 名 SRG 名 作用 目标类数
setBlockBoundsBasedOnState func_149719_a 按方块状态重设边界 9
getSelectedBoundingBoxFromPool func_149633_g 从对象池取选中包围盒 2
addCollisionBoxesToList func_149743_a 添加碰撞盒 4

目标类全部是 thaumcraft.common.blocks.* 下的方块类 (SalisArcanaClassTransformer.java:36-54)。 MethodRemover 同时接受 MCP 名与 SRG 名,因此对混淆/未混淆环境都有效。

源码同时给出两套名字,说明这批变换是为混淆后的 1.7.10 环境设计的。

与混入清单的关系

coreModClass 负责 ASM 与早期混入,普通混入的实际清单在别处。 三个 mixins.*.json 只有 package 而没有 mixins 数组, 真实清单是 mixins/Mixins.java 中的枚举 Mixins。

仅看 src/main/resources/ 会得出「本模组没有混入」的错误结论。 详见 补丁注册框架。

数值

SalisArcanaCore 用 Tags.VERSION 作为模组版本,该类由 gradle 的 generateGradleTokenClass 在构建期生成到 dev.rndmorris.salisarcana.Tags, 源码仓库中不存在 Tags.java。因此模组版本号无法从源码静态核实, 详见分类页的版本说明。

SalisArcanaClassTransformer 的 transform() 在入参 bytes 为 null 时 直接返回 null(SalisArcanaClassTransformer.java:60), 这是 IClassTransformer 的标准约定,不是缺陷。

交互

玩家不可感知。变换只针对登记过的 15 个类名发生。

合成配方

无。

相关条目