高级配方注册表

跳过 Forge 形状数组,直接拿 InventoryCrafting 的内容做运行时匹配的配方框架。适用于槽位非固定的机器类配方。

基本信息

属性 值
接口 wanion.lib.recipe.advanced.IAdvancedRecipe
注册表 wanion.lib.recipe.advanced.AbstractRecipeRegistry<R extends IAdvancedRecipe>
存储 两个 TShortObjectMap<List<R>>(Trove,TShortObjectHashMap)
泛型参数 R 必须是 IAdvancedRecipe 的子类型

IAdvancedRecipe 接口

public interface IAdvancedRecipe extends IRemovable {
    short getRecipeKey();
    short getRecipeSize();
    boolean recipeMatch(@Nonnull InventoryCrafting inventoryCrafting, int offSetX, int offSetY);
    @Nonnull ItemStack getOutput();
}
成员 返回类型 契约
getRecipeKey() short 0 表示无序(shapeless),非 0 表示有序,键 = recipeSize | (width << 8) | (height << 12)
getRecipeSize() short 非空格占用的物品总数,作为 shapeless 桶的键
recipeMatch(InventoryCrafting, int offSetX, int offSetY) boolean 由消费方实现;offSetX / offSetY 是工作台内第一个非空格位的列/行坐标
getOutput() @Nonnull ItemStack 产物

继承自 IRemovable 的成员:

成员 签名 说明
removed() boolean 软删除标记,供消费方过滤已注销配方
setRemoved(boolean) void 写该标记

AbstractRecipeRegistry 不检查 removed() —— 移除必须由消费方显式调 移除方法。

注册表成员

成员 签名 行为
有序桶 public final TShortObjectMap<List<R>> shapedRecipes 键 = recipeKey
无序桶 public final TShortObjectMap<List<R>> shapelessRecipes 键 = recipeSize
添加 public final void addRecipe(@Nonnull R recipe) getRecipeKey() != 0 → 进 shapedRecipes;否则取 getRecipeSize() 进 shapelessRecipes。桶不存在时 new ArrayList<>()
移除 public final void removeRecipe(@Nullable R recipe) recipe == null 直接 return;按同一分流规则 List.remove(recipe),列表为 null 时静默跳过
匹配 public final R findMatchingRecipe(@Nonnull InventoryCrafting inventoryCrafting) 见下

findMatchingRecipe 流程

  1. root = (int) Math.sqrt(inventoryCrafting.getSizeInventory()) —— 3×3 工作台得 root = 3。
  2. 求 offSetX:外层 x、内层 y 扫 y * root + x,找到第一个非空格位即停,取该 x。
  3. 求 offSetY:外层 y、内层 x 扫同一索引式,取该 y。
  4. 求 width / height:以 (offSetX - 1, offSetY - 1) 为原点量出包围盒,超界即停。
  5. 数 recipeSize:遍历 height × width 内非空格格数。
  6. 算 recipeKey = recipeSize | (width << 8) | (height << 12)。
  7. 先查 shapedRecipes.get(recipeKey),未命中回落 shapelessRecipes.get(recipeSize)。
  8. 桶非 null 时逐个 recipe.recipeMatch(inventoryCrafting, offSetX, offSetY),命中即返回;全不命中返回 null。

⚠️ 键位宽:width 落在位 8~11、height 落在位 12~15,各占 4 bit,故两者都隐含被限制在 0~15;recipeSize 占位 0~7。recipeKey 为 short(有符号),height == 8 起会置符号位。

⚠️ AbstractRecipeRegistry 是 abstract 但没有任何抽象方法 —— 它是可直接实例化的容器基类,抽象只是留给消费方当命名空间/类型参数锚点。

使用流程

  1. 实现 IAdvancedRecipe:getRecipeKey() 返回 (size | (w << 8) | (h << 12)) 或 0(无序),recipeMatch() 里自行遍历 InventoryCrafting 比对。
  2. class MyRegistry extends AbstractRecipeRegistry<MyRecipe> {}。
  3. registry.addRecipe(new MyRecipe(...))。
  4. 在 Container / GUI 的 slot 变化回调里 registry.findMatchingRecipe(inventoryCrafting)。

相关条目