NEI 配方树处理器
基本信息
| 属性 | 值 |
|---|---|
| 处理器类 | hellfirepvp.beebetteratbees.client.gui.BBABGuiRecipeTreeHandler |
| 基类 | AbstractTreeGUIHandler(同时 implements ICraftingHandler, IUsageHandler) |
| 注册位置 | ClientProxy#registerNEIGUIs(ClientProxy.java:23-27) |
| 面板贴图 | beebetteratbees:textures/gui/neiBlank.png |
| 面板标题 | bbab.gui.breedtree = Bee Breeding Tree |
| 每页配方数 | 1(recipiesPerPage() 硬编码返回 1) |
| 注册方块 / 物品 / 实体 | 0 / 0 / 0 |
这是一个纯客户端 NEI 附属
仓库中没有任何 GameRegistry.registerBlock / registerItem / registerTileEntity
之类调用。@Mod 注解(BeeBetterAtBees.java:17-21)声明依赖:
required-after:NotEnoughItems;required-after:Forestry
gradle.properties 里 usesMixins = false,无 coremod、无 AccessTransformer 之外的补丁。
CommonProxy#registerNEIGUIs() 是空方法(CommonProxy.java:11),
所有实际逻辑只在客户端代理里。
注册方式
同一个 handler 实例被同时注册成两类处理器(ClientProxy.java:24-26):
BBABGuiRecipeTreeHandler handler = new BBABGuiRecipeTreeHandler();
API.registerRecipeHandler(handler);
API.registerUsageHandler(handler);
AbstractTreeGUIHandler#getRecipeHandler / getUsageHandler 每次都用
newInstance() 反射无参构造出一个新 handler 承载本次查询的结果,
实例字段 arecipes 承载当前页的配方列表。
蜜蜂物种根的加载
speciesRoot 是处理器唯一的静态状态(BBABGuiRecipeTreeHandler.java:37),
唯一的赋值点是 loadBeeRoot()(:208-215):
speciesRoot = (IBeeRoot) AlleleManager.alleleRegistry.getSpeciesRoot("rootBees");
rootBees 是 Forestry 的蜜蜂物种根 UID。找不到时只打一条 warn 日志,
不抛异常、不阻断加载。
因为加载可能失败或根本没被调用,loadCraftingRecipes / loadUsageRecipes
的每个入口都先判 speciesRoot == null 直接 return(:66、:74、:135、:143)。
rootBees 为空时这个 mod 静默失效——这是设计上的容错,不是崩溃路径。
合成侧与用途侧的匹配规则不同
| 侧 | 匹配字段 | 条件 |
|---|---|---|
合成 loadCraftingRecipes |
mutation.getTemplate()[0] |
模板主位等于查询物种 |
用途 loadUsageRecipes |
getAllele0() 或 getAllele1() |
父代任一等位等于查询物种 |
两侧都遵守 !mutation.isSecret() || shouldShowSecretRecipes,
并在末尾调用 cleanupDuplicateRecipes()。
源码缺陷
NEIBBABConfig 在仓库内没有任何引用点。 全仓库 grep -rn "NEIBBABConfig" src/
只命中该文件自身的类声明与 javadoc,没有 new NEIBBABConfig(),也没有注册代码。
它 implements IConfigureNEI,其 loadConfig()(NEIBBABConfig.java:17)
是唯一调用 loadBeeRoot() 的地方,因此 speciesRoot 的填充依赖 NEI 侧的
附属加载机制而非本 mod 自己的生命周期。IConfigureNEI 还实现了
getName() / getVersion(),同样只用于 NEI 的显示。
cleanupDuplicateRecipes() 边遍历边删除。(:177-196)
它对 arecipes 做增强 for,同时又用 iterator.remove() 修改同一个列表,
命中重复后 break 并递归重入。逻辑上靠 break 规避了
ConcurrentModificationException,但递归 + O(n²) 的组合在大型
mod 组合(大量 secret 变异开启时)会很脆弱。