Arcane Infusion Handler(奥法注入)
基本信息
| 属性 | 值 |
|---|---|
| 类型 | NEI Recipe / Usage Handler |
| 源码类 | com.gtnewhorizons.aspectrecipeindex.nei.InfusionRecipeHandler |
| 基类 | TemplateThaumHandler |
| Overlay ID | thaumcraft.infusion |
| 界面名 | aspectrecipeindex.infusion.title = “Arcane Infusion” |
| 底层配方类型 | Thaumcraft InfusionRecipe + TC4RecipeLib 的 EnhancedInfusionRecipe |
| IMC 关联物品 | Thaumcraft:blockStoneDevice:2(符文矩阵,handler 高度 152) |
| 特殊内容 | Runic 护甲强化配方(同一 handler 内) |
功能:展示奥法注入配方的中心物品、外围材料、essentia 需求与不稳定性数值。
索引数据结构
| 结构 | 类型 | 说明 |
|---|---|---|
runicArmor |
static TreeMap<Integer, ArrayList<ItemStack>> |
按 IRunicArmor.getRunicCharge(stack) 分组的护甲物品 |
aspects(继承自基类) |
ArrayList<AspectList> |
与 arecipes 按下标平行,供 getRecipeHeight 读取 |
runicArmor 由 NEIConfig.loadConfig() 末尾调用的 static init() 一次性构建:clear() 后遍历整个 Item.itemRegistry,取所有 instanceof IRunicArmor 的 Item;无子类型的直接加一个 new ItemStack(item),有子类型的调 getSubItems(item, item.getCreativeTab(), subItems)(整个调用被 catch (Exception ignored) 包住),为空则退回一个无 meta 的栈。
配方高度
getRecipeHeight(recipe) = 152 + (ceil(元素数 / 7) - 1) * 20。aspectsPerRow 固定为 7。元素多时页面变高,这是"按配方数计算高度"而非固定高度的少数 handler 之一。
加载路径
| 方法 | 行为 |
|---|---|
loadCraftingRecipes(ItemStack) |
产物用 areStacksSameTypeCraftingWithNBT 匹配;随后 loadRunicUpgradeRecipe(result) |
loadCraftingRecipes(String, Object...) |
overlay 分支遍历全部 InfusionRecipe(要求 getRecipeInput() != null 且 validOutput),再 loadAllRunicCraftingRecipes() |
loadUsageRecipes(ItemStack) |
见下 |
loadUsageRecipes 的三段:
getInfusionRecipesByInput(ingredient)取匹配配方,逐个过Util.shouldShowRecipe(recipe.getResearch()),并调用setIngredientPermutation高亮命中的材料。- 若输入
instanceof IRunicArmor:charge = EventHandlerRunic.getFinalCharge(ingredient) + 1,在0 < charge <= Byte.MAX_VALUE时生成一条"再强化一级"的配方。 - 否则若
isRunicUpgradeIngredient(ingredient):一次性生成全部 Runic 强化配方。
getInfusionRecipesByInput 的匹配顺序:中心物品 matches → 外围 RecipeIngredient.matches(整个遍历 catch (Throwable ignored))→ essentia 交集。转换用 InfusionRecipeExt.get().convert(raw),被 try / catch (RuntimeException) { continue; } 包住(源码注释 “keep bad recipe from killing the scan”)。
isRunicUpgradeIngredient 判据:钻石、Thaumcraft ConfigItems.itemResource 的 metadata 14,或 essentia 中含 ENERGY / ARMOR / MAGIC 三者之一。
输出合法性校验
validOutput(InfusionRecipe):
ItemStack且物品非空 → 合法。Object[](无泛型参数)长度 ≥ 2 且首元素是String→ 合法(对应"给原物品打 tagInfo"的配方,源码举例为铋 stronghold 头盔的面板)。- 否则返回
false,并打三行警告日志:研究键、中心物品、输出对象。日志前缀固定为 “Invalid output for infusion recipe, please report to Aspect Recipe Index:”。
界面布局
| 元素 | 坐标 / 规则 |
|---|---|
| 中心物品 | (OUTPUT_X, 63) = (75, 63),来自 r.getCentral().getRepresentativeStacks() |
| 外围材料 | 沿圆周排布:圆心 (27 + 56, -31 + itemOffset() + 102) = (83, 71),半径 40,起始角 -90°,角步长 360 / 材料数 |
| 外围贴图 | drawIngredientBackground 画符文矩阵 (27, 21, 207, 78, 42, 42),并做 (-0.5, -1, 0) 像素对齐平移 |
| 产物 | (75, 5)(setResult)或 Runic 的 (75, 5) |
| 元素网格 | 每行 7 个,baseX = 35,baseY = 130 + itemOffset(),水平间距 20 |
| 元素行分配 | 逆序行 reversedRow = -row + rows - 1,该行列数 (元素总数 + reversedRow) / rows,再按 (100 - 列数 * 20) / 2 居中 |
| 元素物品 metadata | 1 |
itemOffset() 目前固定返回 0(保留的扩展点)。
不稳定性显示
drawInstability 在 shouldShowRecipe 为假时不画。
showInstabilityNumber = true(默认):
- 文本 =
tc.inst+ 数值(直接拼接,无空格)。 - 颜色档位 =
Math.min(5, instability / 2)(整除),映射到instability0~instability5。 - 绘制位置:X 为
83 - 文本宽度 / 2(在 83 处居中),Y = 120。
showInstabilityNumber = false:文本 = tc.inst.<档位>,颜色统一 instabilityOff(白)。详见 颜色常量。
metadata 技巧
Thaumcraft 用 Short.MAX_VALUE(32767)作为物品 metadata 的"跟随输入"标记:
getResult()发现result.item.getItemDamage() == Short.MAX_VALUE时调Items.feather.setDamage(result.item, 0)改回 0——因为Items.feather是maxStackSize = 1的物品,可以直接改它的栈内 metadata 当作通用写入器。setIngredientPermutation覆写:结果 damage 为Short.MAX_VALUE且输入物品与结果相同时,用输入的 damage 覆盖结果,实现"结果复制输入子类型"。
Runic 护甲强化配方
RunicShieldCachedRecipe(内部类,继承 InfusionCachedRecipe):
| 属性 | 值 |
|---|---|
| 研究键 | 常量 RESEARCH = "RUNICAUGMENTATION" |
| 不稳定性 | 5 + charge / 2 |
| 中心物品 | 目标护甲(items 列表) |
| 外围材料 | 1 个钻石 + charge 个 ConfigItems.itemResource(metadata 14) |
| 产物 | 护甲副本,RS.HARDEN 设为 EventHandlerRunic.getHardening(item) + 1(NBTTagByte) |
| 结果槽备注 | 源码注明产物槽不显示排列变体,所以只取 items.getFirst() |
essentia 成本(setAspects(int charge),源码注释给出公式):
charge >= 26→ 不加任何 essentia。- 否则
cost = 8 << charge(即 8 × 2^charge):ENERGY(秩序 Potentia)=cost * 2ARMOR(防护 Tutamen)=costMAGIC(秘法 Praecantatio)=cost
去重策略(见 元素配方索引机制 同类思路):loadAllRunicCraftingRecipes() 按 charge 分组,每个 charge 只生成一条配方并把所有适用护甲塞进中心物品槽。但当玩家搜索某个护甲的用途时,loadUsageRecipes 会单独为它生成一条精确到"再升一级"的配方,所以不会丢失升级信息。
loadRunicUpgradeRecipe(ItemStack) 处理"搜索已强化过的护甲的产物":要求 instanceof IRunicArmor、有 NBT 且 getHardening > 0,复制一份并把 RS.HARDEN 设为 charge - 1(即回退一级显示)。