插件注册 API(RecipeManager)
基本信息
| 属性 | 值 |
|---|---|
| 入口类 | api/RecipeManager.java(514 行) |
| 底层实现 | core/util/WitcheryRecipeHandlerInternal.java |
| 插件基类 | api/plugin/base/BasePluginWitchery.java(100 行) |
| 插件接口 | api/plugin/interfaces/WitcheryPlugin.java(12 行) |
| 示例 | api/plugin/ExamplePlugin.java(70 行) |
| 嵌套类 | 9 个(8 个注册表 + 1 个 PluginManager) |
| 本 mod 自用 | 仅 Oven 一组(OvenRecipes.generateDefaultOvenRecipes() 不走本 API) |
这是本 mod 暴露给其它 mod 的接口层,用来增删 Witchery 的配方与仪式。
⚠️ 它操作的 8 类注册表全部属于 Witchery 本体, Witchery 不在本 wiki 收录范围(见 分类页), 本页只列本 mod 暴露的方法签名,不复述各注册表的内部结构。
8 个注册表
| 嵌套类 | RecipeManager.java 行 |
方法数 | 增 | 删 | 查 |
|---|---|---|---|---|---|
WitchesOven |
106 |
5 | addRecipe(ItemStack, String, int, ...) |
removeRecipe(OvenRecipe) |
getOvenResult / findRecipeForOutput / findRecipeUsingIngredient |
SpinningWheel |
166 |
6 | addRecipe(ItemStack fibre, ItemStack output, ItemStack[] modifiers) |
removeRecipe × 2 重载 |
getRecipe / findRecipeFor / findRecipeUsing / findRecipeUsingFibre |
Distillery |
244 |
5 | addRecipe(input1, input2, jars, output1, ...) |
removeRecipe(DistilleryRecipe) |
getDistillingResult / findRecipeForOutput / findRecipeUsingIngredient |
Kettle |
306 |
4 | addRecipe(output, hatBonus, familiarType, ...) |
removeRecipe(ItemStack mOutput) |
findRecipeWithSomeInputsAndAnOutput / findRecipesFor |
CreaturePowers |
355 |
4 | add(CreaturePower) |
remove(CreaturePower) |
getCreaturePower(EntityLiving) / getCreaturePower(int entityID) |
RitesAndRituals |
392 |
3 | add(ritualID, bookIndex, Rite, Sacrifice, ...) |
remove(int ritualID) |
getLastUsedRitualID() |
Predictions |
431 |
4 | add(Prediction) |
remove(Prediction) |
getPredictions() / getPrediction(int aID) |
Infusions |
467 |
5 | add(Infusion) |
remove(Infusion) |
getInfusion(int) / getInfusionOnPlayer(EntityPlayer) / getLastUsedInfusionID() |
拼写照抄源码:
RitesAndRituals的查询方法叫getLastUsedRitualID(Ritual,少一个 i),而Infusions的是getLastUsedInfusionID(Infusion,有 i)。
并发标注不一致:SpinningWheel.addRecipe 与
SpinningWheel.removeRecipe(ItemStack, ItemStack, ItemStack...)
没有 synchronized(RecipeManager.java 的 SpinningWheel 段),
而该类其余方法以及其它 7 个类的所有 add / remove 都是
public static synchronized。见下方「源码缺陷」。
PluginManager(RecipeManager.java:64)
3 个方法,把插件挂到本 mod 的三个生命周期阶段:
| 方法 | 行 | 对应本 mod 阶段 |
|---|---|---|
loadPluginForPreInit(BasePluginWitchery) |
RecipeManager.java:64 段 |
WitcheryExtras.java:59-61 |
loadPluginForInit(BasePluginWitchery) |
同上 | WitcheryExtras.java:74-76 |
loadPluginForPostInit(BasePluginWitchery) |
同上 | WitcheryExtras.java:86-88 |
本 mod 侧的三个静态列表(WitcheryExtras.java:46-48):
private static final List<BasePluginWitchery> mPreInitEvents = new ArrayList<>();
private static final List<BasePluginWitchery> mInitEvents = new ArrayList<>();
private static final List<BasePluginWitchery> mPostInitEvents = new ArrayList<>();
以及 3 个公开注册入口(WitcheryExtras.java:116-126):
addEventPreInit / addEventInit / addEventPostInit。
⚠️ 三个列表都是普通
ArrayList,没有同步保护; 遍历时若其它线程调用addEventXxx会抛ConcurrentModificationException。
插件生命周期
BasePluginWitchery 提供 preInit() / init() / postInit()
(WitcheryExtras.java:60、75、87 分别调用),
WitcheryPlugin(12 行)是标记接口。
ExamplePlugin 演示的三件事(api/plugin/ExamplePlugin.java):
- 注册一条纺车配方(约
ExamplePlugin.java:40-46,用ItemStack[]传输入) - 注册一条烤炉配方
- 移除一条既有蒸馏器配方:
RecipeManager.Distillery.removeRecipe(RecipeManager.Distillery.findRecipeUsingIngredient(new ItemStack(Items.diamond)))(ExamplePlugin.java:61)
⚠️
ExamplePlugin位于主源码集src/main/java/alkalus/main/api/plugin/, 不是src/test或独立示例工程。它会被打进正式 jar。 它的类名以Example开头,不代表它是生效的插件—— 本仓库没有任何代码调用loadPluginForXxx传入它, 因此实际不会执行。
底层 WitcheryRecipeHandlerInternal
core/util/WitcheryRecipeHandlerInternal.java 提供 8 对 add/remove:
| 方法 | 行 |
|---|---|
addOvenRecipe / removeOvenRecipe |
36 / 41 |
addDistilleryRecipe / removeDistilleryRecipe |
64 / 69 |
addKettleRecipe / removeKettleRecipe |
91 / 97 |
addNewCreaturePower / removeCreaturePower |
120 / 130 |
addNewRiteToRiteRegistry / removeRiteFromRiteRegistry |
157 / 170 |
addNewPrediction / removePrediction |
205 / 214 |
addNewInfusion / removeInfusion |
244 / 253 |
addSpinningWheelRecipe / removeSpinningWheelRecipe / removeSpinningRecipe |
285 / 294 / 313 |
只有 addOvenRecipe / addNewRiteToRiteRegistry / addNewInfusion 等
部分方法带 synchronized。
9 个 core/types/Witchery_*.java 门面
core/types/ 下 9 个类是薄门面,只转发查询,不含注册逻辑:
| 文件 | 行数 | 转发到 |
|---|---|---|
Witchery_Cauldron.java |
68 | WitcheryRecipeHandlerInternal + 反射 |
Witchery_CreaturePower.java |
67 | 反射读 CreaturePower 注册表 |
Witchery_Distillery.java |
35 | Witchery 静态表 |
Witchery_Infusion.java |
63 | 反射 |
Witchery_Kettle.java |
50 | Witchery 静态表 |
Witchery_Oven.java |
21 | 本 mod 的 OvenRecipes(唯一有本地实现的) |
Witchery_Predictions.java |
26 | 反射(见 预言权重重写) |
Witchery_Rite.java |
27 | 反射 |
Witchery_SpinningWheel.java |
25 | Witchery 静态表 |
⚠️ 源码缺陷
| # | 位置 | 问题 |
|---|---|---|
| 1 | Witchery_Predictions.java:22 |
catch (Throwable t) {} 空 catch。反射失败被吞掉,调用方拿到空 Hashtable,无法与「真的没有预言」区分 |
| 2 | OvenRecipes.java:19-21 |
getRecipeMap() 直接返回私有可变 ArrayList 引用,未做防御性拷贝。外部可任意增删(本意是开放 API,但同时使 mRecipeMap 无法保证完整性) |
| 3 | WitcheryExtras.java:46-48 |
3 个插件列表无同步保护 |
| 4 | RecipeManager.java 的 SpinningWheel 段 |
addRecipe / removeRecipe 缺 synchronized,与同类其余方法不一致 |
| 5 | ExamplePlugin.java |
示例类打进正式 jar,且无人加载 |