BuildCraft 配方体系:4 个配方管理器 + 30 个本仓调用点 + GTNH 短路边界
事实基准:
/Users/evlos/a/mirror/BuildCraft(master,minecraftVersion = 1.7.10)逐行读源码。 不逐条抄配方表,只写清体系、类别、数量分布与关键配方族。
⚠ 头号事实:GTNH 上这 6 个 loadRecipes() 全部直接 return
BuildCraftCore.java:293 定义标志位,BuildCraftCore.java:495 赋值:
public static boolean GTNH = false; // :293
GTNH = Loader.isModLoaded("dreamcraft"); // :495
6 个 loadRecipes() 的第一行都是同一个早退:
| 模块 | 早退位置 | 原文 |
|---|---|---|
BuildCraft|Core |
BuildCraftCore.java:843 |
if (GTNH) return; |
BuildCraft|Factory |
BuildCraftFactory.java:215 |
if (GTNH) return; |
BuildCraft|Silicon |
BuildCraftSilicon.java:200 |
if (GTNH) return; |
BuildCraft|Builders |
BuildCraftBuilders.java:659 |
if (GTNH) return; |
BuildCraft|Energy |
BuildCraftEnergy.java:510 |
if (GTNH) return; |
BuildCraft|Robotics |
BuildCraftRobotics.java:518 |
if (GTNH) return; |
在装了 DreamCraft(即 GTNH)的环境下,这 6 处全部一条配方都不注册。
⚠ 这是「数值取自错误来源」的典型陷阱:
只数 addCraftingRecipe 调用点会得到 48,但那是「源码里写了多少」,
不是「GTNH 上实际注册多少」——后者是 0。
BuildCraft|Transport 是反向守卫(BuildCraftTransport.java:728):
public void loadRecipes() {
if (!GTNH) { // :728 ← GTNH 上反而跳过
GameRegistry.addShapelessRecipe(new ItemStack(pipeWaterproof, 1), new ItemStack(Items.dye, 1, 2));
if (additionalWaterproofingRecipe) {
GameRegistry.addShapelessRecipe(new ItemStack(pipeWaterproof, 1), new ItemStack(Items.slime_ball));
}
}
}
即 Transport 的「防水管道」配方只在非 GTNH 环境注册。
配方来源分两类
| 来源 | 调用 | 用途 |
|---|---|---|
BCRegistry.INSTANCE.addCraftingRecipe(ItemStack, Object...) |
core/BCRegistry.java:94-97 |
工作台配方(有形状/材料字典) |
GameRegistry.addShapelessRecipe(...) |
Transport 等 | 无序配方 |
BCRegistry.addCraftingRecipe(core/BCRegistry.java:94)内部先过 isInvalidRecipeElement 守卫(:95-97)再转交 GameRegistry,
材料以 ore-dict 名书写(如 "ingotIron"、"dustRedstone"、"gearIron")。
⚠ 跨 mod 兼容引用:BuildCraft 配方大量使用 ore-dict 名 (
ingotIron/stickWood/dustRedstone/chestWood…), 这些不是 BuildCraft 拥有的物品。 例如BuildCraftCore.java:492有OreDictionary.registerOre("chestWood", Blocks.chest);——把原版箱子注册成chestWood供 Builder 配方取用。
调用点数量分布(静态计数)
addCraftingRecipe 在各文件的出现次数:
| 文件 | 次数 | 所属 modid |
|---|---|---|
BuildCraftCore.java |
12 | BuildCraft|Core |
BuildCraftSilicon.java |
11 | BuildCraft|Silicon |
BuildCraftFactory.java |
8 | BuildCraft|Factory |
BuildCraftBuilders.java |
8 | BuildCraft|Builders |
BuildCraftRobotics.java |
5 | BuildCraft|Robotics |
BuildCraftTransport.java |
2 | BuildCraft|Transport |
BuildCraftEnergy.java |
2 | BuildCraft|Energy |
core/BCRegistry.java |
1 | (方法定义本身,非调用) |
| 合计(调用点) | 48 | — |
⚠ 48 是「源码里写了多少条工作台配方」,不是任何环境下实际生效的数量:
- GTNH 上:0(见上节 6 处早退);
- 非 GTNH 上:48(不含 Transport 走
addShapelessRecipe的 2 条)。
4 个配方管理器(不是工作台配方,是「机器配方」)
BuildCraft 的机器配方与工作台配方是两套:
| 管理器 | 源码 | 添加方法 | 用途 |
|---|---|---|---|
RefineryRecipeManager |
core/recipes/RefineryRecipeManager.java |
addRecipe(String id, FluidStack ingredient, FluidStack result, int energy, int delay)(:30)<br>addRecipe(String id, FluidStack in1, FluidStack in2, FluidStack result, int energy, int delay)(:38) |
精炼:流体 → 流体(支持一进一出 / 两进一出) |
AssemblyRecipeManager |
core/recipes/AssemblyRecipeManager.java |
addRecipe(String id, int energyCost, ItemStack output, Object... input)(:23)<br>addRecipe(IFlexibleRecipe<ItemStack> recipe)(:28) |
装配台:Object... 可混物品与流体 |
IntegrationRecipeManager |
core/recipes/IntegrationRecipeManager.java |
addRecipe(IIntegrationRecipe recipe)(:21) |
集成台 |
ProgrammingRecipeManager |
core/recipes/ProgrammingRecipeManager.java |
addRecipe(IProgrammingRecipe recipe)(:17) |
编程台 |
对应的 API 接口在 api/recipes/:
IRecipeManager、IRefineryRecipeManager、IAssemblyRecipeManager、
IIntegrationRecipeManager、IProgrammingRecipeManager。
本仓自带的机器配方:30 个 .addRecipe( 调用点(不是 0 条)
机器配方既有本仓自带的,也有给第三方 mod 用的 IMC 钩子。两者必须分开数。
| 管理器 | 本仓 .addRecipe( 调用点 |
分布 |
|---|---|---|
| AssemblyRecipeManager | 25 | BuildCraftSilicon.java ×9(:348/:353/:359/:365/:371/:377/:383/:389/:397)、transport/TransportSiliconRecipes.java ×11(:41/:47/:56/:61/:71/:78/:85/:92/:104/:177/:182)、transport/ItemFacade.java ×4(:504/:506/:509/:510)、core/CoreSiliconRecipes.java ×1(:19) |
| RefineryRecipeManager | 1 | BuildCraftEnergy.java:356-357,即 buildcraft:fuel(油 → 燃料,energy = 120、delay = 1) |
| IntegrationRecipeManager | 3 | BuildCraftRobotics.java:585(RobotIntegrationRecipe)、transport/TransportSiliconRecipes.java:153(GateExpansionRecipe)、:154(AdvancedFacadeRecipe) |
| ProgrammingRecipeManager | 1 | BuildCraftRobotics.java:584(BoardProgrammingRecipe) |
| 合计 | 30 | 静态计数(.addRecipe( 出现次数) |
⚠ 30 是「源码里写了多少个调用点」,不是「游戏里生效多少条配方」,两处原因:
ItemFacade.java:504-510那 4 个调用点在按外观材质遍历的循环体里 (外层守卫是facadeIDLookup.add(recipeId)),运行时会展开成 N 条,不是 4 条。- GTNH 上有 6 处
if (GTNH) return;早退(见上文),会吃掉其中一部分。
GTNH 上哪些机器配方仍然会注册
这是最容易数错的一处。BuildCraft|Transport.loadRecipes() 的 if (!GTNH) { ... }
代码块在 BuildCraftTransport.java:790 就闭合了,而
TransportSiliconRecipes.loadSiliconRecipes() 的调用点在 :792——
落在 !GTNH 块之外,只被 if (Loader.isModLoaded("BuildCraft|Silicon"))(:791)保护。
| 调用点 | 守卫 | GTNH(装了 DreamCraft)上是否注册 |
|---|---|---|
BuildCraftSilicon.java ×9 |
if (GTNH) return;(:200) |
否 |
BuildCraftEnergy.java ×1 |
if (GTNH) return;(:510) |
否 |
BuildCraftRobotics.java ×2 |
if (GTNH) return;(:518) |
否 |
core/CoreSiliconRecipes.java ×1 |
经 BuildCraftCore.loadRecipes(),:843 早退 |
否 |
transport/TransportSiliconRecipes.java ×13 |
仅 `isModLoaded("BuildCraft | Silicon")(:791`) |
transport/ItemFacade.java ×4 |
仅 `isModLoaded("BuildCraft | Silicon") && !facadeForceNonLaserRecipe(:499`) |
⇒ GTNH 上仍有 17 个调用点会执行(13 + 4),
所以「机器配方在 GTNH 上全被短路掉」是错的——被短路的只是 6 个 loadRecipes()
里的那 13 个调用点,工作台配方才是真的全灭。
IMC 钩子(给第三方 mod 用的注册入口)
core/InterModComms.java 里另有 2 个 addRecipe IMC 处理分支,供其他 mod 通过
FMLInterModComms 推送机器配方:
| IMC 分支 | 位置 | 说明 |
|---|---|---|
| 装配台配方 | core/InterModComms.java:120 |
AssemblyRecipeManager.INSTANCE.addRecipe(...) |
| 精炼配方 | core/InterModComms.java:154 |
RefineryRecipeManager.INSTANCE.addRecipe(...) |
(同文件 :76 / :88 是 removeRecipe,不是 addRecipe,数调用点时别混进去。)
⚠ IMC 钩子的存在不等于「BuildCraft 自带 N 条机器配方」—— 钩子是接口,机器配方的真实来源是上面那张 30 个调用点的表。
关键配方族
| 族 | 载体 | 备注 |
|---|---|---|
| 齿轮系 | BuildCraftCore.loadRecipes |
woodenGearItem ← stickWood(BuildCraftCore.java:846) |
| 扳手 | BuildCraftCore.loadRecipes |
wrenchItem ← ingotIron + gearStone(BuildCraftCore.java:845-846) |
| 机器本体 | BuildCraftFactory.loadRecipes |
如 miningWellBlock(:217-232) |
| 硅 / 红石 | BuildCraftSilicon.loadRecipes |
Silicon 的 11 条 |
| 流体转化 | BuildCraftEnergy.loadRecipes |
buildcraft:fuel:油 → 燃料,经 BuildcraftRecipeRegistry.refinery.addRecipe(...),energy = 120、delay = 1(BuildCraftEnergy.java:356-357) |
| 防水管道 | BuildCraftTransport.loadRecipes |
pipeWaterproof ← 染料 meta 2(BuildCraftTransport.java:731)/ 黏液球(:733,受 additionalWaterproofingRecipe 开关控制,:732) |
⚠ 流体配方 buildcraft:fuel 走的是 BuildcraftRecipeRegistry.refinery.addRecipe(...)
(BuildCraftEnergy.java:356-357),不是 addCraftingRecipe——
它是精炼配方,对应
RefineryRecipeManager 的单参重载
addRecipe(String id, FluidStack, FluidStack, int energy, int delay)。
⚠ 它的 120 是能量、1 是延迟,两个参数单位不同,
不能把 120 说成「耗时 120 tick」,也不能说成「需要 120 桶油」。
⚠ 同文件 :359 还有一条燃料(不是配方)的注册:
BuildcraftFuelRegistry.fuel.addFuel(fluidOil, fuelOilEnergyOutput, (int) (5000 * fuelOilMultiplier))
——5000 是燃烧时长 tick,与上面的 120 不是同一个量。