原料转换
GTTweaker 提供两条静态转换方法,把 CraftTweaker 的 IIngredient 转成 GregTech 5 需要的 ItemStack / FluidStack。全 mod 的 55 台机器类与 RA2 Builder、Recipe Remover 都间接依赖这两条路径。
基本信息
| 属性 |
值 |
| 类 |
gttweaker.GTTweaker |
| 方法 1 |
public static ItemStack getItemStackOrNull(IIngredient ingredient) |
| 方法 2 |
public static FluidStack getFluidStackOrNull(IIngredient ingredient) |
| 行数 |
20(GTTweaker.java:146-159) |
| 使用者 |
56 个类通过方法引用(GTTweaker::getItemStackOrNull)间接调用 |
getItemStackOrNull(:146-153)
Object internal = ingredient.getInternal();
if (internal instanceof ItemStack) return (ItemStack) internal;
else if (internal instanceof String)
return OreDictionary.getOres((String) internal).size() > 0
? OreDictionary.getOres((String) internal).get(0) : null;
return null;
internal 类型 |
返回 |
风险 |
ItemStack |
原对象(同一引用,未 copy) |
调用方若修改会污染原 ingredient |
String(矿辞典名) |
OreDictionary.getOres(name).get(0) —— 静默取第一个 |
见下 |
其他(如 FluidStack、List<IItemStack>) |
null |
静默 |
getFluidStackOrNull(:155-159)
Object internal = ingredient.getInternal();
if (internal instanceof FluidStack) return (FluidStack) internal;
return null;
不处理矿辞典:流体在 CraftTweaker 中本就没有 ore dict 形式。IIngredient 若内部是 ILiquidStack 会被 AddMultipleRecipeAction 提前转成 FluidStack 再存入,本方法只处理这一路径。
三种失败模式
| 模式 |
触发条件 |
后果 |
| 静默取第一个 |
矿辞典含多个变体 |
配方只用了某一个具体物品,其余变体(可能是更便宜的替代)被无视,无日志 |
返回 null 被 filter 掉 |
矿辞典为空 / 类型不匹配 |
参数数量减少 → 见 Recipe Remover 的过度匹配风险;机器类中则可能 itemInputs(null) NPE |
| 同一引用 |
internal instanceof ItemStack |
调用方 recipeBuilder.itemInputs(stack) 若持有引用,后续修改会影响原 ingredient |
数值
| 数值 |
值 |
| 静态转换方法数 |
2 |
支持的 internal 类型 |
ItemStack / String(物品);FluidStack(流体) |
| 矿辞典取法 |
getOres(name).get(0) —— 第一个,无排序保证 |
| 空矿辞典 |
返回 null |
| 返回值是否 copy |
否(ItemStack 分支直接返回原引用) |
| 失败时是否有日志 |
否(全部静默) |
| 流体的矿辞典支持 |
无 |
源码缺陷
- 矿辞典静默取第一个变体(
:150-151):OreDictionary.getOres(name).get(0)。矿辞典的注册顺序由各 mod 的加载顺序决定,因此同一脚本在不同 mod 组合下可能生成不同的配方。这在打包整合包中是难以排查的问题。源码无注释、无日志。
- 调用两次
OreDictionary.getOres(:150 与 :151):getOres 每次返回一个新的 ArrayList(1.7.10 行为),因此有一次多余的列表分配 + 完整拷贝。size() > 0 与 get(0) 应合并为一次调用。
- 返回
null 后由调用方 filter(nonNull) 静默丢弃:RA2Builder 的 4 个数组方法与 RecipeRemover.remove 都用 .filter(Objects::nonNull)。后果分两种:
RA2Builder.itemInputs([<不存在的ore>]) → 传入空数组给 builder(不是 null),可能写出无输入的配方。
RecipeRemover.remove(map, [<不存在的ore>], []) → 查询条件被削弱,可能删掉一条与预期完全不同的配方。
ItemStack 分支不 copy:return (ItemStack) internal;。GTRecipeBuilder.itemInputs 在 GT5 中会保存引用。CraftTweaker 的 IItemStack 内部 ItemStack 通常是脚本创建的新对象,但若来自 IIngredient 的缓存可能被复用。
- 无
@Nullable / 无异常:两条路径都靠返回 null 表达失败,与 AddMultipleRecipeAction 里三个抛异常的校验风格相反(同仓库两种失败表达方式并存)。
- 方法名
OrNull 表明作者知晓会返回 null,但没有任何调用方检查 null(除了 filter)。
getFluidStackOrNull 不处理 List<FluidStack>:CraftTweaker 的 ILiquidStack 内部可能是列表(当 <ore:...> 类写法产生多流体时),本方法直接返回 null,与物品侧的矿辞典支持不对称。
- 两条方法放在
@Mod 主类而非工具类:它们是通用转换逻辑,却绑在模组入口类 GTTweaker 上,测试与复用不便。对比 util/ArrayHelper 有独立工具类但反而是死代码。
相关条目