动态 Mixin 注册

[!INFO] 注册真源:makamys.coretweaks.MixinConfigPlugin.getMixins() ⚠️ 不能靠数 JSON 数组 —— 三个 mixin JSON 的 mixins 数组全是空的

⚠️ 关键陷阱:JSON 数组全空

三个 mixin 配置文件的 "mixins": [] 一个元素都没有:

文件 target 元素数
coretweaks.mixin.json (默认 / DEFAULT) 0
coretweaks-init.mixin.json @env(INIT) 0
coretweaks-preinit.mixin.json @env(PREINIT) 0

全部靠 "plugin": "makamys.coretweaks.MixinConfigPlugin" 的 IMixinConfigPlugin.getMixins() 在运行时动态返回类名列表。

配置项 值
package makamys.coretweaks.mixin
refmap mixins.coretweaks.refmap.json(三个 JSON 共用同一个)
compatibilityLevel JAVA_8
minVersion 0.6
required true
plugin makamys.coretweaks.MixinConfigPlugin

实际注册的 Mixin 总数:37

对 mixin/ 目录下 37 个 .java 与 getMixins() 中所有 mixins.add("…") 字符串做集合差运算,结果为:

on-disk .java under mixin/ : 37   (全部带 @Mixin 注解)
registered in getMixins()  : 37
on disk but NEVER registered : (空集)
registered but file MISSING  : (空集)

即 37 个类双向严格一一对应,零死文件、零悬空引用。 但其中有 3 个因配置被硬编码而永不可达,见下方「永久不可达的 Mixin」。

按阶段(Phase)分组

getMixins() 用 MixinEnvironment.getCurrentEnvironment().getPhase() 分派:

PREINIT 阶段(1 个)

Mixin 生效条件
optimization.fmlmessagestrip.MixinFMLClientHandler !isForgeSplashEnabled() 且 forgeFastStepMessageStrip 启用

双重条件的原因:只有在 Forge 启动画面被关闭时,消息条才存在可优化之处。

INIT 阶段(0 个)

} else if (phase == Phase.INIT) {
    // 空实现
}

⚠️ coretweaks-init.mixin.json 的 getMixins() 分支完全为空, 该配置文件永远不注入任何 Mixin —— 它是一个空壳, 文件本身存在且 required: true,但无实际作用。

DEFAULT 阶段(36 个)

绝大多数 Mixin 在此阶段注册,且每个都由独立的配置开关 + FMLLaunchHandler.side().isClient() 双重门控。分组明细见:

⚠️ 永久不可达的 Mixin(3 个)

以下 Mixin 虽然在 getMixins() 中被 add,但其门控配置项被 硬编码为 FeatureSetting.FALSE(注解被注释掉), isActive() 恒为 false,故永远不会被注入:

Mixin 门控字段 硬编码方式
optimization.clientchunkmap.MixinChunkProviderClient Config.clientChunkMap = FeatureSetting.FALSE,@ConfigWrappedEnum 被注释
optimization.threadedtextureloader.ITextureMap Config.threadedTextureLoader = FeatureSetting.FALSE,@ConfigBoolean 被注释
optimization.threadedtextureloader.MixinTextureMap 同上 同上

源码中保留了 WIP 说明:

// @ConfigWrappedEnum(cat="Optimizations", def=FALSE, com="(WIP) Faster implementation of
// ChunkProviderClient#chunkMapping. From 1.16 ... Might be a little buggy ...")
public static FeatureSetting clientChunkMap = FeatureSetting.FALSE;

即这是作者主动注释掉的开发中功能,而非 bug。但从注册真源角度看, 这三个类确实属于「已注册却永不可达」,统计时必须扣除。

其它 IMixinConfigPlugin 方法

方法 实现 说明
onLoad Config.reload() 插件加载即重读配置
getRefMapperConfig return null 不接管 refmap 生成
shouldApplyMixin return true 无条件放行所有 Mixin,不做目标类存在性检查
acceptTargets 空 不处理 @Mixin(targets=…)
preApply / postApply 空 无回调
getMixins 见上 唯一的注册入口

shouldApplyMixin 无条件 true 意味着:若某目标类在当前环境不存在, Mixin 应用会直接失败。这也是为何 tweakCloudHeightCheck 等与 NotFine 的互斥要在配置层而非本层处理。

Plugin.getMixins() 的前置副作用

Phase.DEFAULT 分支在返回列表之前就执行了副作用代码:

if (transformerCache 启用 && 模式 == LITE && lateLiteTransformerCache) {
    TransformerCache.instance.init(true);   // 延后初始化
}

即 lateLiteTransformerCache 走的是「在 DEFAULT 阶段才挂钩 transformer 链」 的路径,而非在 onConstruction 里提前初始化(见 CoreTweaks 配置)。

外部 mod 门控

DEFAULT 阶段中,3 个 OptiFine 相关 Mixin 由 Compat.isOptifinePresent() && isClient 统一门控; FastCraft 的 4 个 Mixin 由 Launch.blackboard.get("fcVersion") 门控, 且按版本号二选一:

fcVersion 注入
"1.23" MixinFastcraft1_23TextureUtil
"1.25" MixinFastcraft1_25TextureUtil
其它 / 缺失 打 WARN 日志,一个都不注入

FastCraft 成功时还会从 LaunchClassLoader 的 transformerExceptions 集合中移除 "fastcraft"(反射写入),再额外注入 MixinTextureUtil 与 MixinTextureMap。

相关条目