化学类机器
GT 5 流体处理 / 化学机器的脚本 API,共 12 个 ZenClass、20 个 ZenMethod。全部走 AddMultipleRecipeAction,不可撤销。
⚠️ 本条目含全 mod 第二个必然抛异常的缺陷:FusionReactor.addRecipe 每次调用都抛 ClassCastException。
全表
| ZenClass | 方法数 | 目标 RecipeMap | 特殊字段 |
|---|---|---|---|
mods.gregtech.ChemicalReactor |
4 | UniversalChemical(注意:不是 chemicalReactorRecipes) |
— |
mods.gregtech.ChemicalBath |
1 | chemicalBathRecipes |
|
mods.gregtech.Distillery |
1 | distilleryRecipes |
hidden |
mods.gregtech.DistillationTower |
2 | distillationTowerRecipes + distilleryRecipes |
|
mods.gregtech.Electrolyzer |
2 | electrolyzerRecipes |
|
mods.gregtech.Centrifuge |
3 | centrifugeRecipes |
|
mods.gregtech.ThermalCentrifuge |
1 | thermalCentrifugeRecipes |
|
mods.gregtech.Fermenter |
1 | fermentingRecipes |
hidden |
mods.gregtech.Brewery |
1 | brewingRecipes |
hidden |
mods.gregtech.FluidExtractor |
1 | fluidExtractionRecipes |
|
mods.gregtech.Autoclave |
2 | autoclaveRecipes |
metadata(LOW_GRAVITY, boolean) |
mods.gregtech.FusionReactor |
1 | fusionRecipes |
⚠️ i.nextLong() 读 int → 必抛 CCE |
方法签名(全部实测自源码)
ChemicalReactor.addRecipe(IItemStack output1, IItemStack output2, ILiquidStack fluidOutput, IIngredient input1, IIngredient input2, ILiquidStack fluidInput, int durationTicks, int euPerTick)
ChemicalReactor.addRecipe(IItemStack output, ILiquidStack fluidOutput, IIngredient input1, IIngredient input2, ILiquidStack fluidInput, int durationTicks, int euPerTick)
ChemicalReactor.addRecipe(IItemStack output, ILiquidStack fluidOutput, IIngredient input1, IIngredient input2, ILiquidStack fluidInput, int durationTicks)
ChemicalReactor.addRecipe(IItemStack output, IIngredient input1, IIngredient input2, int durationTicks)
ChemicalBath.addRecipe(IItemStack[] output, IIngredient input, ILiquidStack fluidInput, int[] chances, int durationTicks, int euPerTick)
Distillery.addRecipe(ILiquidStack fluidOutput, IItemStack circuit, ILiquidStack fluidInput, int durationTicks, int euPerTick, boolean hidden)
DistillationTower.addRecipe(ILiquidStack[] fluidOutput, IItemStack itemOutput, ILiquidStack fluidInput, int durationTicks, int euPerTick)
DistillationTower.addUniversalRecipe(ILiquidStack[] fluidOutput, IItemStack itemOutput, ILiquidStack fluidInput, int durationTicks, int euPerTick)
Electrolyzer.addRecipe(IItemStack[] outputs, ILiquidStack fluidOutput, IIngredient input, IIngredient cells, ILiquidStack fluidInput, int[] chances, int durationTicks, int euPerTick)
Electrolyzer.addRecipe(IItemStack[] outputs, IIngredient input, int cells, int durationTicks, int euPerTick)
Centrifuge.addRecipe(IItemStack[] outputs, ILiquidStack fluidOutput, IIngredient input1, IIngredient input2, ILiquidStack fluidInput, int[] chances, int durationTicks, int euPerTick)
Centrifuge.addRecipeFuelCan(IItemStack[] outputs, IIngredient input, int numCans, int duration)
Centrifuge.addRecipe(IItemStack[] outputs, IIngredient input, int cells, int durationTicks)
ThermalCentrifuge.addRecipe(IItemStack output1, IItemStack output2, IItemStack output3, IIngredient input, int durationTicks, int euPerTick)
Fermenter.addRecipe(ILiquidStack fluidOutput, ILiquidStack fluidInput, int duration, boolean hidden)
Brewery.addRecipe(ILiquidStack output, IIngredient ingredient, ILiquidStack input, boolean hidden)
FluidExtractor.addRecipe(IItemStack output, IIngredient input, ILiquidStack fluidOutput, int durationTicks, int euPerTick, int chance)
Autoclave.addRecipe(IItemStack output, IIngredient input, ILiquidStack fluidInput, int chance, int durationTicks, int euPerTick, boolean lowGravity)
Autoclave.addRecipe(IItemStack output, IIngredient input, ILiquidStack fluidInput, int chance, int durationTicks, int euPerTick) ← 委托,lowGravity=false
FusionReactor.addRecipe(ILiquidStack fluidOutput, ILiquidStack fluidInput1, ILiquidStack fluidInput2, int durationTicks, int euPerTick, int startEU) ← 必抛 CCE
⚠️ FusionReactor:每次调用必抛 ClassCastException(FusionReactor.java:46-55)
protected void applySingleRecipe(ArgIterator i) {
RA.stdBuilder()
.fluidInputs(i.nextFluid(), i.nextFluid())
.fluidOutputs(i.nextFluid())
.duration(i.nextInt())
.eut(i.nextInt())
.metadata(FUSION_THRESHOLD, i.nextLong()) // ← 参数是 int startEU
.addTo(fusionRecipes);
}
AddMultipleRecipeAction 构造器收到的 startEU 是 int 参数,被 extendBySingle 以 Integer 装箱存入 recipesData。而 ArgIterator.nextLong() 是 (Long) iterator.next() 的无检查强转:
public long nextLong() { return (Long) iterator.next(); } // AddMultipleRecipeAction.java:169-171
→ java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
与 Extruder 的关键区别:Extruder 是静默无效(不抛异常、不改配方);FusionReactor 是必然抛异常。且 ArgIterator 中 nextLong() 是全 mod 唯一的调用点(grep -rn nextLong 仅 2 处:定义 + 本调用)—— 该方法从未被其他机器用过,因此这个类型错误一直没暴露。
DistillationTower.addUniversalRecipe —— 一次调用最多 12 条配方
for (int idx = 0; idx < Math.min(fluidOutputs.length, 11); idx++) {
RA.stdBuilder()
.itemInputs(GTUtility.getIntegratedCircuit(idx + 1)) // 电路 1..11
.itemOutputs(output)
.fluidInputs(fluidInput)
.fluidOutputs(fluidOutputs[idx]) // 每次只输出 1 种
.duration(duration * 2) // ← 2 倍时长
.eut(eut / 4) // ← 1/4 EUT
.addTo(distilleryRecipes);
}
RA.stdBuilder().itemOutputs(output).fluidInputs(fluidInput)
.fluidOutputs(fluidOutputs).duration(duration).eut(eut)
.addTo(distillationTowerRecipes);
它把「多输出流体」拆成 N 条单流体输出的 Distillery 配方(自动插入电路 1…N,时长 ×2,EUT ÷4),再加 1 条 DistillationTower 配方。N 上限由 Math.min(..., 11) 硬限制为 11。
数值
| 数值 | 值 |
|---|---|
| ZenClass 数 | 12 |
| ZenMethod 数 | 20 |
| 涉及 RecipeMap 数 | 12(distilleryRecipes 被 Distillery 与 DistillationTower 共用) |
| 必然抛异常的 ZenMethod 数 | 1(FusionReactor.addRecipe) |
addUniversalRecipe 单次最多产出 |
12 条(11 Distillery + 1 Tower) |
addUniversalRecipe 输出流上限 |
11(Math.min(length, 11)) |
addUniversalRecipe 时长 |
duration * 2(Distillery 部分) |
addUniversalRecipe EUT |
eut / 4(Distillery 部分,整数除法) |
| 自动电路范围 | 1–11(GTUtility.getIntegratedCircuit(idx + 1)) |
Autoclave 第 2 重载默认值 |
lowGravity = false |
FusionReactor 双流体输入 |
fluidInputs(nextFluid(), nextFluid())(固定 2 种,无 1/3 种重载) |
hidden 参数 |
Distillery / Fermenter / Brewery 有;用于 GT5 的 hidden 机制 |
| 可撤销 | 全部否 |
@ModOnly |
全部 "gregtech" |
源码缺陷
FusionReactor.addRecipe每次调用抛ClassCastException(:53):i.nextLong()读的是int startEU装箱出的Integer。全 mod 唯一的nextLong()调用点,因此该类型错误从未被其他机器暴露。这是比 Extruder 更严重的问题 —— 至少Extruder是静默无效,本方法是必抛。Autoclave的outputChances(chance)传标量 int(:68):chance是int,而 GT5GTRecipeBuilder.outputChances标准签名是int[]。传单个 int 说明依赖了 GT5 的重载或 varargs 版本 —— 本条目无法从本仓库源码确认其语义(是「单个输出物的概率」还是被静默忽略),不下结论。FusionReactor的 Javadoc 复制粘贴错误(:24):Adds a Mixer recipe.—— 应为Fusion Reactor recipe。类级@author DreamMasterXXL(其余多数类是Stan Hebben)。FusionReactor只支持 2 种流体输入:fluidInputs(i.nextFluid(), i.nextFluid())硬编码两个,无 1 种或 3 种输入的重载。addUniversalRecipe的 EUT 整数除法截断(:101):eut / 4。脚本传eut = 2→ 0;eut = 6→ 1。源码无下限保护(无Math.max(1, ...)),可能写出 EUT=0 的配方。addUniversalRecipe的时长/EUT 缩放无注释:duration * 2/eut / 4是 GT 平衡性硬编码,源码仅两行无说明,脚本作者无从得知为何自己传的数值被改动。duration * 2可能溢出:duration为int,脚本传Integer.MAX_VALUE / 2 + 1即溢出为负。ChemicalReactor写入UniversalChemical而非chemicalReactorRecipes:GT5 5.09 的反应器配方确实在UniversalChemical,但类名ChemicalReactor与 map 名UniversalChemical无对应关系,检索源码时极易误判为笔误。源码无注释。ChemicalReactor的 4 个重载参数数量递减但无明显规律:8 → 7 → 7 → 5 参,第 3 个重载去掉了euPerTick,第 4 个再去掉所有流体。第 3 重载的eut会取RA.stdBuilder()的默认值,源码未显式设置 —— 未调用 setter = 默认值的典型位置。Distillery与DistillationTower共用distilleryRecipes:用mods.gregtech.Distillery.addRecipe写的配方会在 DistillationTower 里也能跑,反之addUniversalRecipe生成的 Distillery 配方不带circuit参数(自动插入)。两条路径产出同一 map 但字段不同,源码无交叉说明。Brewery.addRecipe无duration/euPerTick参数:与Fermenter.addRecipe(有duration)不同,脚本无法控制酿造时长。是否取 GT5 默认值取决于本类未调用的 setter,源码无法确认。hidden布尔参数在 3 个类中出现(Distillery / Fermenter / Brewery)但语义未在源码注释中说明。Centrifuge有 3 个重载且命名不一致:addRecipeFuelCan(numCans)与addRecipe(cells)是同一概念(离心机容器)却用两个不同参数名,且第 3 个重载也用cells。脚本作者容易误以为addRecipeFuelCan与addRecipe是不同机制。
相关条目
- 冶炼类机器 - 流体输出类对照
- GT++ 机器 -
Dehydrator/MultiblockCentrifuge/MultiblockElectrolyzer写入centrifugeNonCellRecipes等 map - AddMultipleRecipeAction - 全部方法的共同基类
- Fuels - 同属流体/能源体系