容器兼容性

基本信息

属性 值
实现类 yalter.mousetweaks.ModCompatibility
上下文类 yalter.mousetweaks.handlers.ContainerContext
容器 ID 常量 yalter.mousetweaks.Constants
识别顺序 IMTModGuiContainer → Forestry → CodeChickenCore → NEI → 原版 GuiContainer
反射目标 Forestry / CodeChickenCore / NEI 三套 ReflectionCache

容器 ID 表

常量 值 含义 识别依据
NOTASSIGNED -1 尚未判定(ContainerContext 初始态) —
NOTGUICONTAINER 0 这不是容器界面,Mouse Tweaks 完全不介入 所有识别都失败
MINECRAFT 1 原版 GuiContainer 系容器,tweak 全部生效 screen instanceof GuiContainer 且通过校验
MTMODGUICONTAINER 2 实现了 IMTModGuiContainer 接口的自定义容器 screen instanceof IMTModGuiContainer
FORESTRY 3 Forestry 机器界面 forestry.core.gui.GuiForestry
CODECHICKENCORE 4 CodeChickenCore 通用容器框架 codechicken.core.inventory.GuiContainerWidget
NEI 5 NEI 界面 codechicken.nei.recipe.GuiRecipe 或 codechicken.nei.GuiEnchantmentModifier

识别顺序先 mod 后原版:源码注释明确说明「很多 mod 继承的是原版 Minecraft 的那个类」, 因此必须先让 mod 分支抢占,再回落到 isGuiContainer。IMTModGuiContainer 优先级最高。

各容器的启用 / 禁用规则

ModCompatibility.isDisabledForThisModContainer(NOTGUICONTAINER 已被上层拦掉):

容器 ID Mouse Tweaks 是否启用 依据
MINECRAFT(1) 启用 该方法直接 return false
FORESTRY(3) 启用 落到 default: → return false
NEI(5) 仅附魔台界面启用 !NEI.isInstance("GuiEnchantmentModifier", screen)——即 GuiEnchantmentModifier 启用,其余 NEI 界面(含合成配方 GuiRecipe)全部禁用
CODECHICKENCORE(4) 永远禁用 case CODECHICKENCORE: return true; 无条件返回
MTMODGUICONTAINER(2) 由接口决定 ((IMTModGuiContainer) screen).isMouseTweaksDisabled()

滚轮另有一层独立的禁用开关 isWheelDisabledForThisModContainer:

容器 ID 滚轮是否禁用
MINECRAFT / FORESTRY / NEI / CODECHICKENCORE 不禁用(ContainerContext 对 MINECRAFT 直接 return false,其余落到 ModCompatibility 的 default: → false)
MTMODGUICONTAINER 由 IMTModGuiContainer#isWheelTweakDisabled() 决定

原版容器的有效性与产物栏位

isValidGuiContainer 排除两类界面:

排除对象 原因
类名包含 CJB_GuiCrafting 的界面 旧版 Crafting 模组的合成界面
GuiContainerCreative 创造模式物品栏

isVanillaCraftingOutputSlot 判定的合成产物栏位(只有这 4 种):

容器 产物栏位下标
ContainerWorkbench(工作台) 0
ContainerPlayer(2×2 合成) 0
ContainerFurnace(熔炉) 2
ContainerRepair(铁砧) 2

⚠️ 源码中没有收录酿造台(ContainerBrewing_Stand,产物在下标 3)、 箱子、潜影盒等其它原版容器的产物栏位。这些容器的对应槽位不会被当作产物栏位处理。

Forestry 容器的产物栏位

ModCompatibility.modIsCraftingOutputSlot 的 FORESTRY 分支按容器类名(Reflection.is 比较 getClass().getSimpleName())逐个硬编码:

Forestry 容器 产物栏位下标
ContainerSqueezer(榨汁机) 9 或 11
ContainerMoistener(保湿房) 9
ContainerCentrifuge(离心机) 1 ~ 9(9 个全部)
ContainerCarpenter(木匠) 21
ContainerFabricator(制造器) 20
ContainerWorktable(abricator 工作台 / 木材机) 27
其它 Forestry 容器 false(break 缺省穿透到 return false)

各类容器的操作注入方式

容器 ID 取栏位 点击栏位 关闭原版 RMB 拖拽
MINECRAFT container.inventorySlots.get(i) playerController.windowClick(windowId, slotNumber, btn, shift?1:0) disableVanillaRMBDrag(写两个 public 混淆字段)
FORESTRY 反射调用 GUI 的 getSlotAtPosition(mouseX, mouseY) 反射调用 GUI 的 handleMouseClick(slot, 0, mouseButton, shift?1:0),鼠标坐标硬编码为 0 不做任何事(落到 default: 空实现)
NEI container.inventorySlots windowClick disableVanillaRMBDrag + 按需对起点补一次右键
MTMODGUICONTAINER IMTModGuiContainer#getModSlot IMTModGuiContainer#clickModSlot IMTModGuiContainer#disableRMBDragIfRequired
CODECHICKENCORE 整个界面被禁用,不做任何操作 同左 同左

Forestry 的容器对象取自 GUI 屏幕的 inventorySlots 字段(不是 Container), getModSlotCount / modGetSlot 则直接读该字段的 List<Slot> 大小与下标。

NEI 反射的两级依赖

ModCompatibility.initialize() 中 NEI 的反射是嵌套的:

  1. 先找 codechicken.nei.recipe.GuiRecipe;找不到则 NEI.compatible 保持 false, 整个 NEI 兼容失效;
  2. 找到后再找 codechicken.nei.GuiEnchantmentModifier;也找不到则仍为 false。

只有两级都命中才会打印 Successfully reflected NEI!。由于 GuiEnchantmentModifier 存在才让 NEI 界面可用,缺少附魔台类时 NEI 界面会被整体判为 NOTGUICONTAINER。 ModCompatibility.getModGuiContainerID 里 GuiEnchantmentModifier 的判断没有 NEIInstalled 前置条件,但 ReflectionCache.isInstance 在类未缓存时返回 false,效果等价。

相关条目