动态 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() 双重门控。分组明细见:
- Bugfix Mixin - 12 个
- Optimization Mixin - 13 个
- Tweak Mixin - 10 个
- Diagnostics Mixin - 2 个
⚠️ 永久不可达的 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。
相关条目
- CoreTweaks 配置 - 门控开关的来源
- 功能兼容矩阵 - 被 mod 冲突自动禁用的规则
- Coremod 与 ASM 变换器 - 非 Mixin 的变换路径