Mixin 与底层补丁

基本信息

属性 值
Mixin 枚举 core/mixinplugin/Mixins.java:7(implements IMixins)
coremod 入口 core/ModularUICore.java:18(implements IFMLLoadingPlugin, IEarlyMixinLoader)
MC 版本声明 @IFMLLoadingPlugin.MCVersion("1.7.10")(ModularUICore.java:17)
实际注册的 Mixin 17
ASM 变换器 1(ModularUITransformer)
Mixin 配置文件 3 个(early / 默认 / late)
加载机制 GTNHLib Mixins 框架(com.gtnewhorizon.gtnhmixins),非 FML 原生

功能

加载机制(重要)

src/main/resources/ 下 3 个 mixins.modularui2*.json 的 mixins / client / server 数组全是空的:

// mixins.modularui2.json
{ "required": true, "minVersion": "0.8.5-GTNH",
  "package": "com.cleanroommc.modularui.core.mixins",
  "refmap": "mixins.modularui2.refmap.json", …,
  "mixins": [], "client": [], "server": [] }

真正的 Mixin 列表来自 GTNHLib 的 IMixins 枚举:

阶段 入口 文件
EARLY coremod IFMLLoadingPlugin.getMixins() → IMixins.getEarlyMixins(Mixins.class, loadedCoreMods) core/ModularUICore.java:33-35
LATE ModularUILateMixinLoader(@LateMixin)→ IMixins.getLateMixins(Mixins.class, loadedMods) core/mixinplugin/ModularUILateMixinLoader.java:20-22

ModularUICore.getMixinConfig()(:28-30)返回 mixins.modularui2.early.json; ModularUILateMixinLoader.getMixinConfig()(:15-17)返回 mixins.modularui2.late.json。

17 个实际注册的 Mixin

来自 core/mixinplugin/Mixins.java(grep -c 'Mixin"' 计 17 项):

阶段 组 Mixin 行
EARLY MINECRAFT(客户端,10 个) forge.ForgeHooksClientMixin :11
minecraft.FontRendererAccessor :12
minecraft.GuiAccessor :13
minecraft.GuiButtonMixin :14
minecraft.GuiContainerAccessor :15
minecraft.GuiContainerMixin :16
minecraft.GuiScreenAccessor :17
minecraft.GuiScreenMixin :18
minecraft.MinecraftMixin :19
minecraft.SimpleResourceAccessor :20
EARLY MINECRAFT(通用,5 个) minecraft.ContainerAccessor :22
minecraft.EntityAccessor :23
minecraft.EntityPlayerMPMixin :24
minecraft.InventoryCraftingAccessor :25
forge.SimpleNetworkWrapperMixin :26
LATE THAUMCRAFT(1 个) thaumcraft.ClientTickEventsFMLMixin :29
LATE NEI(1 个) nei.RecipeInfoMixin :35

补丁目标可归为 5 类:

类别 目标 用途
访问器(*Accessor) GuiAccessor、GuiScreenAccessor、GuiContainerAccessor、ContainerAccessor、EntityAccessor、InventoryCraftingAccessor、SimpleResourceAccessor、FontRendererAccessor 让 MUI2 读取原版私有字段(如 guiLeft/guiTop/xSize)
GUI 行为注入 GuiScreenMixin、GuiContainerMixin、GuiButtonMixin 拦截输入、派发 KeyboardInputEvent / MouseInputEvent
客户端核心 MinecraftMixin、ForgeHooksClientMixin 模板缓冲、键盘重复等
服务端实体 EntityPlayerMPMixin 玩家同步
网络 SimpleNetworkWrapperMixin 放宽封包处理

三个 Mixin 组的目标 mod 与冲突回避

Mixins 枚举用 TargetedMod(core/mixinplugin/TargetedMod.java:7)声明依赖:

组 需要的 mod 声明行 排除的 mod 排除行
THAUMCRAFT Thaumcraft :33 salisarcana :32
NEI NotEnoughItems :37 —— ——

TargetedMod 只有 3 个常量:SALISARCANA("salisarcana")(:9)、 THAUMCRAFT("Thaumcraft")(:10)、NEI("NotEnoughItems")(:11)。

Salis Arcana 的排除有源码注释说明(Mixins.java:31): 「salis arcana implements the same mixin so our fails」——两者实现同一 Mixin, 同时加载会冲突。

ASM 变换器

core/ModularUITransformer.java:11 实现 IClassTransformer, 在 core/ModularUICore.java:37-40 以 new String[]{"com.cleanroommc.modularui.core.ModularUITransformer"} 注册。

只改写一个类:net.minecraft.network.PacketBuffer (core/visitor/PacketByteBufferVisitor.java:14), 把 ItemStack 的堆叠数字段从 byte 改成 varint。详见 网络封包。

开发环境检测

ModularUICore.injectData(:52-55)读取 runtimeDeobfuscationEnvironment, 存入静态字段 isDevEnv(:21),供 ASM 变换器选择 MCP 名还是混淆名 (PacketByteBufferVisitor.java:17-22)。

已知缺陷

❌ 缩放光标纹理路径写错,缩放功能静默失效

ClientProxy.java:99 与 :104 从旧资源域读取缩放光标纹理:

// ClientProxy.java:99
BufferedImage img = ImageIO.read(getClass().getClassLoader()
        .getResourceAsStream("assets/modularui/textures/gui/icons/cursor_resize_diag.png"));
// ClientProxy.java:104
img = ImageIO.read(getClass().getClassLoader()
        .getResourceAsStream("assets/modularui/textures/gui/icons/cursor_resize.png"));

但这两个文件实际位于 modularui2 域:

src/main/resources/assets/modularui2/textures/gui/icons/cursor_resize.png
src/main/resources/assets/modularui2/textures/gui/icons/cursor_resize_diag.png

而 assets/modularui/ 下只有 lang/en_us.lang 和 themes.json, 没有 textures/ 目录。三种验证:

# A. 字面量定位
grep -n 'assets/modularui' src/main/java/com/cleanroommc/modularui/ClientProxy.java
  → 99, 104(且全仓仅此两处引用旧域)

# B. 目录是否存在
ls src/main/resources/assets/modularui/
  → lang, themes.json          (无 textures)

# C. 实际文件在哪
find src/main/resources -name 'cursor_resize*'
  → assets/modularui2/textures/gui/icons/cursor_resize.png
  → assets/modularui2/textures/gui/icons/cursor_resize_diag.png

后果:getResourceAsStream 返回 null,ImageIO.read(null) 抛异常, 被 ClientProxy.java:110-113 的 catch (Throwable e) 吞掉, 仅打一行 ModularUI.LOGGER.info("Custom Cursors failed to load.")。 窗口缩放光标在运行时不会生效(setCursorResizeIcon 因此永远拿不到光标对象)。 同时 resizeCursorH/V/Diag/DiagInverse 四个静态字段保持 null(:56-59)。

相关条目