容器兼容性
基本信息
| 属性 | 值 |
|---|---|
| 实现类 | 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 的反射是嵌套的:
- 先找
codechicken.nei.recipe.GuiRecipe;找不到则NEI.compatible保持false, 整个 NEI 兼容失效; - 找到后再找
codechicken.nei.GuiEnchantmentModifier;也找不到则仍为false。
只有两级都命中才会打印 Successfully reflected NEI!。由于 GuiEnchantmentModifier
存在才让 NEI 界面可用,缺少附魔台类时 NEI 界面会被整体判为 NOTGUICONTAINER。
ModCompatibility.getModGuiContainerID 里 GuiEnchantmentModifier 的判断没有 NEIInstalled
前置条件,但 ReflectionCache.isInstance 在类未缓存时返回 false,效果等价。
相关条目
- IMTModGuiContainer 接口 - 让自家界面按需启停的接口
- 滚轮搬运(WheelTweak) - 滚轮在
GuiEnchantmentModifier上可用 - 右键拖拽替换(RMBTweak) - 产物栏位与起点补点逻辑
- 左键拖拽(手持物品) - 产物栏位排除逻辑
- 配置文件系统 - 访问转换器与容器字段的
public化