配方系统
概述
GT5-Unofficial 的配方系统由 139 个 RecipeMap(RecipeMaps.java,2259 行)和 api/recipe/ 下的 99 个类 / 13135 行代码 构成。它决定了每台机器能做什么、需要什么条件、以及能同时做几份。
代码基线:GT5U 5.09.54.183(Minecraft 1.7.10)。
[!NOTE] 本版本只支持 NEI(
codechicken.nei),没有 EMI 适配层。
配方图 ≠ 机器(常见误解)
RecipeMapBuilder.maxIO(...) 只是 NEI GUI 的槽位绘制参数,不构成机器绑定。真正绑定是每台机器显式指定:
- 多方块:
ProcessingLogic.setRecipeMap(RecipeMaps.chemicalPlantRecipes) - 单方块:覆写
getRecipeMap()
所以配方图数量远多于机器数量——purification* 系列 8 个图只对应 Purification Plant 的 8 个子模块。机器侧统计:MTE*.java 共 715 个,其中 42 个多方块、38 个单方块。
配方图可分为几类玩家可见的用途:
| 类别 | 数量 | 示例 |
|---|---|---|
| Fake(仅展示,永不执行) | 11 | scannerFakeRecipes、assemblylineVisualRecipes、ic2NuclearFakeRecipes |
| 燃料/发电 | 17 | dieselFuels、hotFuels、rocketFuels、plasmaFuels |
| 纳米科技流水线 | 11 | nanochipEtchingArray、nanochipOpticalOrganizer |
| Purification Plant 子模块 | 8 | purificationClarifierRecipes |
并行(Parallel)机制 — 玩家最该懂的规则
并行是多方块专属机制。单方块机器完全不支持并行(MTEBasicMachine 对 ParallelHelper 引用数为 0),它只做 0/1/2 三态判断,输出放不下就停机。
并行上限从哪来
ProcessingLogic.maxParallel 默认 1,实际值来自各多方块覆写的 getMaxParallelRecipes()(全仓 100 处方法覆写)。主流公式是「每电压等级固定倍率 × tier」:
| 公式 | 出现次数 |
|---|---|
4 × tier |
10 台 |
8 × tier |
5 台 |
6 × tier |
4 台 |
16 × tier |
3 台 |
2 × (tier + 1) / tier / 2 + 1 |
其他 |
也有按结构等级而非电压的:powInt(2, 4 + casingTier + 1)(Precise Assembler)、itemPipeTier × 12(Rock Breaker)、PARALLELS_PER_SOLENOID × solenoidLevel(Solar Tower)。
MegaMachines 类机器固定 256 并行(Configuration.Multiblocks.megaMachinesMax),Bio Vat 上限 1000。
超频与并行的双重放大
ParallelHelper.determineParallel() 的判定顺序:
availableEUt < recipe.mEUt→ 电力不足recipe.mEUt > 最大允许 EU/t→ 电压不足- 超频放大并行:
maxParallel × calculateMultiplierUnderOneTick()——把单次配方压到 1 tick 以下的每一 tick 超频都成倍放大批量 - 批量模式:
maxParallel × batchModifier - 电力上限:
min(上限, availableEUt / recipe.mEUt)
批量模式上限是 128 tick(MAX_BATCH_MODE_TICK_TIME)。只有超频后耗时 < 128 tick 才追加并行,且 durationMultiplier = 1.0 + 额外并行 / 当前并行——批量是用耗时倍率换产出,净 EU/t 效率不变。
溢出保护:并行被「降级」而非丢弃
若 protectExcessItem / protectExcessFluid 开启:
maxParallel = Math.min(voidProtectionHelper.getMaxParallel(), maxParallel);
并行被压低,只有降到 ≤ 0 才停机并报 ITEM_OUTPUT_FULL / FLUID_OUTPUT_FULL。预留空间时按最坏情况估算:
int stackSize = (int)(stack.stackSize * Math.ceil(outputChanceMultiplier * chance / 10000d));
即按 100% 掉落率向上取整预留。推论:带概率产出的配方会压缩可用并行。
ME 例外(重要):产物能倒进 AE2 ME 网络时完全跳过溢出检查,并行不再受输出空间限制。
隐藏配方
GTRecipe.mHidden 只影响 NEI 显示,配方仍真实存在、机器正常执行。
- 装配线的
assemblylineVisualRecipes全部隐藏,只能靠玩家自行推导 - 唯一揭示路径:创意模式玩家拾取 Debug Scanner 时自动揭示并逐条发放成就(
GTAchievements.java:775) - 没有配置项可以主动揭示
与之易混的是 mFakeRecipe:假配方仍在 HashMap 里(containsInput 返回 true),但 findRecipe 查不到,机器永远不会执行——纯展示模板。
特殊配方输入(Metadata)
现代 GT5U 用 RecipeMetadataKey<T> 表达物品/流体之外的要求。
COIL_HEAT — 线圈温度
.metadata(GTRecipeConstants.COIL_HEAT, 2400) // 需要 2400 K
EBF 判定(MTEElectricBlastFurnace.java:214):
recipe.mSpecialValue <= mHeatingCapacity ? SUCCESSFUL : insufficientHeat(...)
而机器容量:
mHeatingCapacity = 线圈等级温度 + 100 × (机器 tier - 2)
换更高等级线圈,或每提升一级电压 +100 K。
热度折扣:pow(0.95, (机器热度 - 配方热度) / 900)——EBF 余温每超 900 K,配方 EU/t 就乘 0.95。
mSpecialValue 为负数是另一套语义:LOW_GRAVITY = -100,CLEANROOM = -200,单方块机器据此判断是否需要洁净室。
EU/t 与电压跳级
配方声明名义功率(mEUt),机器按超频后的 calculatedEut 实际扣电。
每跳一级电压,配方 EU/t 上限 ×4:
getMaxAllowedRecipeEUt(machineVoltage, maxTierSkip)
= floor(machineVoltage × 4^maxTierSkip)
maxTierSkips 默认为 1(即默认允许跳 1 级 = ×4)。
其他常见 metadata
ADDITIVE_AMOUNT、CONDENSATE_INPUT、DISSOLUTION_TANK_RATIO、SPARGE_MAX_BYPRODUCT、NO_GAS、FUSION_THRESHOLD、FOG_PLASMA_MULTISTEP、SIEVERT、HALF_LIFE、GLASS、MASS、RESEARCH_ITEM、RECYCLE(回收率)、EXPLODE / ON_FIRE(单方块机器命中即爆炸/着火)。
特殊槽物品(mSpecialItems,如 Printer 里的复制槽)只用于 NEI 展示,findRecipe() 和 containsInput() 都不看这个字段。
概率输出编码
四个并列数组(GTRecipe.java:77):
public int @Nullable [] mInputChances, mOutputChances, mFluidInputChances, mFluidOutputChances;
规则:
- 取值 1–10000,10000 = 100%
- 数组为
null→ 对应槽位全部 100% mInputChances控制「是否被消耗」(不是「是否必须存在」——输入总是要齐)- 越界或
null一律返回 10000
Builder 侧:.outputChances(int...)、.fluidOutputChances(int...)、.fluidOutputs(FluidStack[], int[] chances)。
「做不出来」的 UI 机制
所有失败原因集中注册在 CheckRecipeResultRegistry(210 行):
| 常量 | 玩家看到的意思 |
|---|---|
NO_RECIPE |
没有匹配配方 |
insufficientPower |
EU/t 不够(瞬时供电不足) |
insufficientVoltage |
电压等级不够(跳级受限) |
insufficientHeat |
线圈温度不够 |
insufficientMachineTier |
机器等级不够 |
insufficientStartupPower |
启动功率不足(按机器等级分档) |
ITEM_OUTPUT_FULL / FLUID_OUTPUT_FULL |
输出装不下 |
NO_FUEL_FOUND / NO_TURBINE_FOUND / NO_BLACK_HOLE / NO_SEE_SKY |
特殊机器专属 |
「电力不足」和「电压不足」是两回事:前者是瞬时供电达不到(加大电源/电容),后者是电压等级跳级不够(换高电压机器或开 maxTierSkip)。
玩家如何规划
- 并行是多方块独占收益:单方块机器再高电压也做不到并行。
- 想提并行,优先升电压而非堆机器:并行公式大多是
常数 × tier,而跳级是 ×4。 - 批量模式不是免费午餐:它用耗时换产出,净 EU/t 不变,别被「看起来产量翻倍」误导。
- 概率产物会压低并行:溢出保护按 100% 预留空间,出货前先把输出空间备好。
- 接了 ME 网络就不怕溢出:产物能倒进 AE2 时溢出检查直接跳过。
- EBF 温度不够有两条路:换高等级线圈,或提升电压(每级 +100 K),余温还能换 0.95 的 EU/t 折扣。
- 装配线配方看不见是设计如此,需要自己推导或用 NEI 的 Debug Scanner(创意模式)。
相关条目
- 电压等级 — 跳级 ×4 规则的来源与各级电压值
- 超频 — 超频如何同时放大并行与耗时
- 矿物加工 — 矿物加工链上大量配方依赖 metadata 机制
- 盖板系统 — 机器控制器盖板与机器开关状态的关系
审计订正(2026-10-01)
| 项 | 原文 | 订正为 | 证据 |
|---|---|---|---|
getMaxParallelRecipes 覆写数 |
127 处覆写 | 100 处方法覆写 | grep -rnE "(public|protected|default).*getMaxParallelRecipes\s*\(" --include="*.java" 命中 100;原文的 127 是全部出现次数(含 27 处调用点/接口引用),属「数值取自错误来源」 |
| RecipeMap 数量 | 139 个 | 139 个,正确 | grep -cE "public static final RecipeMap" gregtech/api/recipe/RecipeMaps.java = 139 |
RecipeMaps.java 行数 |
2259 行 | 正确 | wc -l = 2259 |
api/recipe/ 规模 |
99 类 / 13135 行 | 正确 | find = 99;cat | wc -l = 13135 |
MTE*.java 数量 |
715 | 正确 | find -name 'MTE*.java' = 715 |
单方块机器不支持并行(MTEBasicMachine 对 ParallelHelper 引用数为 0)——未复核。