Coremod 与 ASM 变换器

[!INFO] 实现类:makamys.coretweaks.CoreTweaksPlugin(@MCVersion("1.7.10")) 声明:gradle.properties 的 coreModClass = CoreTweaksPlugin

基本信息

CoreTweaks 是双重身份 mod:既是 @Mod 普通模组,也是 IFMLLoadingPlugin coremod。二者由 Gradle 分别声明:

机制 声明位置 值
coremod gradle.properties coreModClass CoreTweaksPlugin
访问变换器 gradle.properties accessTransformersFile coretweaks_at.cfg
Mixin gradle.properties usesMixins true

⚠️ CoreTweaksPlugin.getAccessTransformerClass() 返回 null, 尽管 META-INF/coretweaks_at.cfg 确实存在。AT 生效靠的是 ForgeGradle 把该文件打进 jar 并由 FML 扫描 META-INF, 不是靠 coremod 回调。

构造即执行

CoreTweaksPlugin 的构造函数就调用了重逻辑:

public CoreTweaksPlugin() {
    LOGGER.info("Instantiating CoreTweaksPlugin");
    Config.reload();
    CoreTweaks.init();
}

CoreTweaks.init() 负责构造纹理加载器、变换器缓存、 jar 发现器缓存等跨越整个类加载生命周期的长生命周期对象 —— 它们必须在任何类被转换之前就位,故只能放在 coremod 构造期。

3 个 ASM 变换器

getASMTransformerClass() 按配置动态返回类名数组:

变换器类 门控配置 默认 额外条件
asm.ModDiscovererTransformer forgeModDiscovererSkipKnownLibraries true —
asm.FMLFastSplashTransformer forgeFastProgressBar true !isForgeSplashEnabled()
asm.FMLLogTransformer forgeFixLoggerClassLoadingError true —
@Override public String[] getASMTransformerClass() {
    List<String> transformerClasses = new ArrayList<>();
    if (Config.forgeModDiscovererSkipKnownLibraries.isActive())
        transformerClasses.add("makamys.coretweaks.asm.ModDiscovererTransformer");
    if (!MixinConfigPlugin.isForgeSplashEnabled()) {
        if (Config.forgeFastProgressBar.isActive())
            transformerClasses.add("makamys.coretweaks.asm.FMLFastSplashTransformer");
    }
    if (Config.forgeFixLoggerClassLoadingError.isActive())
        transformerClasses.add("makamys.coretweaks.asm.FMLLogTransformer");
    return transformerClasses.toArray(new String[] {});
}

三者互相独立:数组可能为空、含 1、2 或 3 个元素。

⚠️ isForgeSplashEnabled() 定义在 MixinConfigPlugin(Mixin 侧)却被 coremod 侧调用 —— 同一份逻辑在 ASM 与 Mixin 两条路径间共享。

其余 IFMLLoadingPlugin 回调

回调 返回 说明
getASMTransformerClass 动态数组 见上
getModContainerClass null 不提供自定义 mod 容器
getSetupClass null 不提供 setup 类
injectData 空实现 不读 data map
getAccessTransformerClass null ⚠️ 见上文 AT 说明

后三项源码里均带 // TODO Auto-generated method stub 注释, 即从未实现过,是 FML 接口的占位空实现。

访问变换器 META-INF/coretweaks_at.cfg

全文仅 1 行:

public net.minecraft.entity.player.EntityPlayer field_71074_e #itemInUse

把 EntityPlayer 的私有字段 itemInUse(玩家正在使用的物品, 即进食/喝瓶/举盾的计数)由 private 放宽为 public。

用途:供 bugfix/DoubleEatFixer 读取该字段以修复 「额外食物被静默吞掉」(MC-849),该修复在 CoreTweaks 中 不经 Mixin,而是普通事件监听器 (CoreTweaksMod.init() 中 Config.fixDoubleEat.isActive() 时 FMLCommonHandler.instance().bus().register(new DoubleEatFixer()))。

三条变换路径的关系

路径 阶段 用途
ASM coremod 最早期 3 个 FML/Forge 自身类变换(发现器、启动画面、日志)
Mixin PREINIT / INIT / DEFAULT 37 个,见 动态 Mixin 注册
AT 类加载期 1 个字段可见性放宽

注意 fixDoubleEat 是唯一走 AT + 事件监听器的 bugfix, 不走 Mixin —— 其余 11 个 bugfix Mixin 均不需要 AT。

日志记录

CoreTweaks 持有静态 logger LogManager.getLogger("coretweaks"), 并额外提供 CoreTweaks.logger() 工厂方法,注释说明用途:

Attempts to create a new logger every time it’s called. This should be used in shutdown hooks, since the LOGGER reference becomes invalid.

coremod 侧的 LOGGER 来自 import static ...CoreTweaks.LOGGER。

相关条目