叠加层与 GUI 挂钩
基本信息
| 属性 | 值 |
|---|---|
| 类型 | GUI 叠加层基础设施与死代码清单 |
| 相关类 | utils/CustomOverlayHandler、utils/SetRecipeCommandHandler、utils/ModItemFilter、utils/LabeledPositionedStack、utils/ColorUtils |
自定义 IOverlayHandler |
0 个生效——唯一实现是死代码 |
| 生效的叠加层 | 只有 DefaultOverlayHandler(NEI 自带),由 合成工作台集成 批量注册 |
本条目是 mod 内看起来存在但实际不生效的那部分代码的集中说明,避免读者按类名误判功能。
CustomOverlayHandler(IOverlayHandler,死代码)
public class CustomOverlayHandler implements IOverlayHandler {
public CustomOverlayHandler(String command, int xOffs, int yOffs, boolean invert,
Class<? extends Slot> craftingSlot) { ... }
}
证据:grep -rn "CustomOverlayHandler" src 只有两处命中——第 33 行类声明与第 40 行构造函数自身。没有任何 new、没有工厂方法、没有反射入口。
它实现的能力(记录下来是因为设计意图明确,一旦有人补上注册就能用):
| 行为 | 触发条件 |
|---|---|
| 2D 叠加层预览 | shift == false(或 invert 取反后为 false)。构造 new OffsetPositioner(xOffs, yOffs) 喂给 new DefaultOverlayRenderer(ingr, positioner) 并赋给静态字段 LayoutManager.overlayRenderer |
| 服务端一键填装 | shift == true 且 ClientHandler.enabledCommands.contains(command)。把每个 ingredient 换算成 3×3 槽位号((relx - 25) / 18、(rely - 6) / 18,索引 y * 3 + x),结果栈固定放槽位 9,打包成 data.stacks 发出 |
| 纯客户端手动搬运 | 服务端不支持且 NEIClientUtils.getHeldItem() == null(必须空手)。用 GuiContainerManager.handleSlotClick 模拟:先左键清空所有 craftingSlot 实例槽位,再对每个 ingredient 做「拿起 → 右键放 1 个 → 放回」 |
findMatchingSlot 按 slot.xDisplayPosition == pstack.relx + xOffs 定位目标槽;找不到时打 "Failed to find matching slot - (%d,%d) in %s" 并 continue(不中断整条配方的搬运)。
isValidSlot 只允许两种槽位参与搬运:slot.inventory == Minecraft.getMinecraft().thePlayer.inventory(玩家背包),或 slot.getClass() == Slot.class(精确等于,子类不算)。这是为了避开机器内部的功能槽。
⚠️ 服务端填装分支里有一个源码自述的怪异之处:ItemStack stack = recipe.getResultStack(recipeIndex).items[0]; 写在 for (PositionedStack pstack : ingr) 循环体内部,每轮都追加一次结果栈到 stacksnbt。源码注释写着 "This is back-asswards but i don't see a better way :("。结果槽 9 会被重复追加多次。
SetRecipeCommandHandler(SubPacketHandler,死代码)
证据:grep -rn "SetRecipeCommandHandler" src 只有第 19 行与第 24 行自身。ServerHandler.registerHandler 全仓只有一处调用,注册的是 AE2 的 SetFakeSlotCommandHandler,不是它。
它设计的服务端行为:收到 stacks(NBT 列表,每项含 slot 与物品 NBT)后,若 ContainerClass.isInstance(player.openContainer),就遍历容器里所有 SlotClass 实例槽位——stmap 里有对应 slot.getSlotIndex() 的 putStack,没有的 putStack(null) 清空。
stacks 用 data.getTagList("stacks", 10) 读取,类型 10 即 NBTTagList。这与 CustomOverlayHandler 发包时 data.setTag("stacks", stacksnbt) 的格式一致——两个死代码是配套设计的,只是一起被弃用了。
ModItemFilter(ItemFilter,死代码)
证据:grep -rn "ModItemFilter" src 只有第 15 行与第 20 行自身。
matches(ItemStack) 的逻辑是先按 items 布尔过滤物品/方块,再按 modid 精确匹配:
| 情况 | 结果 |
|---|---|
item == null 或 item.getItem() == null |
false |
item.getItem() instanceof ItemBlock && items == true |
false |
!(item.getItem() instanceof ItemBlock) && items == false |
false |
注册名无 : 分隔符 |
false |
| 正常 | s[0].equals(modId) |
即 new ModItemFilter("Forestry", true) 会匹配所有 modid 为 Forestry 的非方块物品。
实际生效的 GUI 挂钩
| 挂钩点 | 实现类 | 注册 API | 状态 |
|---|---|---|---|
| 工作台合成叠加层 | NEI 自带 DefaultOverlayHandler |
API.registerGuiOverlay + API.registerGuiOverlayHandler |
生效,见 合成工作台集成 |
| AE2 拖拽 | AppEngGuiHandler(INEIGuiAdapter) |
API.registerNEIGuiHandler |
生效 |
| 槽位调试 tooltip | DeveloperGuiHandler(IContainerTooltipHandler) |
GuiContainerManager.addTooltipHandler |
生效但默认关闭 |
| 任意物品的配方叠加 | CustomOverlayHandler(IOverlayHandler) |
— | 死代码 |
| 物品过滤 | ModItemFilter(ItemFilter) |
— | 死代码 |
LabeledPositionedStack 与颜色
utils/LabeledPositionedStack extends PositionedStack,是育种类与产物类 handler 共用的带标签槽位。构造参数 (stack, x, y, label, yoffs, tooltip...)。
drawLabel() 的行为:标签含空格时按空格逐词换行,第 i 词画在 relx + 8, rely + 8 + yoffs + 9 * i;不含空格时单行画在 relx + 8, rely + 8 + yoffs。颜色取 ColorUtils.neiLabel。因为是逐词下移而非按宽度折行,长单词会溢出而非换行。
getTooltip() 返回构造时传入的 varargs 列表(可能是空 ArrayList)。
5 个 ColorResource
utils/ColorUtils 用 GTNHLib new ColorResource.Factory("neiaddons") 定义 5 个颜色,全部带硬编码默认值,且不在 .cfg 里——由资源包 assets/neiaddons/neiaddons_at.cfg 覆盖:
| 名称 | 默认值 | 用在哪 |
|---|---|---|
neiChanceTextNormal |
0xFFFFFF |
育种页正常概率数字 |
neiChanceTextRed |
0xFFFFFF |
育种页红色概率 / DERP 标记 |
neiLabel |
0xFFFFFF |
所有 LabeledPositionedStack 的标签 |
neiProd |
0xFFFFFF |
产物页 Prod: 段标题 |
neiSpec |
0xFFF200 |
产物页 Spec: 段标题(唯一带色默认值的,亮黄) |
⚠️ 仓库里的 src/main/resources/META-INF/neiaddons_at.cfg 不是颜色文件,而是一份 Forge Access Transformer,文件头注释 # Shamelessly stolen from NEI:
| 目标字段 | 注释名 |
|---|---|
net.minecraft.client.gui.inventory.GuiContainer.field_146999_f |
#xSize |
net.minecraft.client.gui.inventory.GuiContainer.field_147000_g |
#ySize |
net.minecraft.client.gui.inventory.GuiContainer.field_147003_i |
#guiLeft |
net.minecraft.client.gui.inventory.GuiContainer.field_147009_r |
#guiTop |
AT 的用途是给 GuiContainer 的 4 个私有字段开公有名。AppEngGuiHandler 与 DeveloperGuiHandler 都直接访问 gui.guiLeft / gui.guiTop,Forge 的 MCP 映射把它们命名为 field_147003_i / field_147009_r,本 mod 靠 AT 改名才编译得过——所以 NEI Addons 强依赖一个 core-mod 式 AT 生效的环境(Forge 1.7.10 默认即读取 jar 内 META-INF/*_at.cfg,无需额外设置)。
相关条目
- 合成工作台集成 - 唯一生效的叠加层来源
- Applied Energistics 2 集成 -
INEIGuiAdapter与槽位命中算法 - 开发者工具 - 另一处
guiLeft/guiTop使用者 - NEI 接口实现总表 - 死代码清单的汇总
- Forestry 集成 -
LabeledPositionedStack与颜色的实际消费方