储罐共用机制(BlockExtendedTank / TileIronTank)
本页说明 10 个储罐方块共享的全部行为。所有差异只来自 TankType 枚举的 5 个数值字段(容量、材料、配方、抗爆、硬度),本 mod 没有为任何等级覆写交互逻辑。
三个类
| 类 | 文件 | 角色 |
|---|---|---|
BlockExtendedTank |
block/BlockExtendedTank.java |
10 个方块的同一个类,10 个独立实例 |
TileIronTank |
tile/TileIronTank.java |
10 个等级共用同一个 TileEntity 类,靠 NBT 里的 type 区分 |
ItemBlockExtendedTank |
item/ItemBlockExtendedTank.java |
10 个方块的方块物品,只有覆写了 tooltip |
ModBlocks(init/ModBlocks.java:11-20)创建 10 个 new BlockExtendedTank(TankType.X) 实例,init()(:23-32)逐一 GameRegistry.registerBlock(..., ItemBlockExtendedTank.class, ironTank.type.name)。所以方块注册名 = TankType.name,物品名与方块同名(irontank:ironTank 同时是方块和方块物品的注册名)。
继承自 BuildCraft
public class BlockExtendedTank extends buildcraft.factory.BlockTank { ... } // BlockExtendedTank.java:23
public class TileIronTank extends buildcraft.factory.TileTank { ... } // TileIronTank.java:10
- 硬依赖声明在
Reference.DEPENDENCIES=required-after:BuildCraft|Factory@[7.0.0,)(reference/Reference.java:11)。 - 本 mod 没有自绘 GUI,也没有自己实现任何流体填充/抽取逻辑。
TileTank的tank字段、右键开关 GUI、漏斗/管道填充、活塞推出行为全部继承自 BuildCraft Transport 的TileTank。 - 本 mod 只做两件事:把
tank容量改掉、把type存进 NBT。
容量计算
TileIronTank.setCapacityFromType()(:36-39):
int capacity = FluidContainerRegistry.BUCKET_VOLUME * type.capacity;
this.tank.setCapacity(capacity);
FluidContainerRegistry.BUCKET_VOLUME= 1000 mB(Forge 1.7.10 常量)。- 所以
TankType.capacity字段的单位是桶,tank实际容量是 mB。IRON的 32 → 32000 mB。 - 10 个储罐的 tooltip 文案(
en_US.lang)写的是Stores up to 32 Buckets,与TankType.capacity数值完全一致,可交叉验证单位换算无误。
NBT 存储(TileIronTank:24-34)
| 方向 | 键 | 值 |
|---|---|---|
| 写 | type |
type.ordinal()(枚举下标,整数) |
| 读 | type |
TankType.values()[data.getInteger("type")] |
⚠️ 顺序依赖:
readFromNBT用 NBT 里的整数直接当TankType.values()的下标。TankType当前下标顺序为 COPPER(0) SILVER(1) IRON(2) GOLD(3) DIAMOND(4) OBSIDIAN(5) GLASS(6) EMERALD(7) STAINLESSSTEEL(8) TITANIUM(9) TUNGSTENSTEEL(10) —— 与枚举声明顺序完全一致(注意TankType.java:19-35就是这个顺序)。在枚举中间插入新常量会让所有旧存档的储罐等级错位并可能抛ArrayIndexOutOfBoundsException。新增等级只能追加到末尾。
读档后 readFromNBT 会再调一次 setCapacityFromType()(:28),所以容量永远由 type 决定,与 NBT 里的数值无关。构造器也调一次(:21),无参构造器默认 TankType.IRON(:14-16)。
硬度与抗爆(BlockExtendedTank:32-39)
this.setResistance(type.resistance); // TankType 的第 5 个构造参数
this.setHardness(type.hardness); // TankType 的第 6 个构造参数
TankType 的 Javadoc(:58-66)确认 resistance = blast resistance(爆炸抗性)、hardness = hardness(硬度),构造函数顺序也是 (capacity, name, materials, recipes, resistance, hardness)(:68-69)。
⚠️ 注意各等级硬度普遍高于抗爆,与原版金属块(铁 5.0/6.0)的惯例相反;黑曜石储罐是唯一抗爆远高于硬度的等级(6000000 / 50)。
方块外观与竖向堆叠(BlockExtendedTank:45-58)
public IIcon getIconAbsolute(IBlockAccess access, int i, int j, int k, int side, int metadata) {
if (side >= 2 && access.getBlock(i, j - 1, k) instanceof BlockTank) {
return textureStackedSide;
} else {
return super.getIconAbsolute(side, metadata);
}
}
textureStackedSide注册自irontank:<name>/side_stacked(:48),即每个等级一张专门的"堆叠侧板"贴图。side >= 2指方块 4 个水平面(面序号 0=下 1=上 2~5=四侧),不包括顶面和底面。- 判定条件是正下方那个方块是不是任意
BlockTank—— 包括 BuildCraft 原版储罐和其他等级的储罐,不限同等级。所以竖向叠放的储罐会自动接上侧板贴图,形成连续的罐柱外观。 - 本类没有覆写
onBlockActivated/onNeighborChanged等交互方法,GUI 与流体行为全在TileTank里。
未本地化名(BlockExtendedTank:140-150)
return String.format("tile.%s%s", Reference.MODID.toLowerCase() + ":", getUnwrappedUnlocalizedName(...));
即 tile.irontank:ironTank。zh_CN.lang 提供 10 条 tile.irontank:*Tank.name(铁储罐 / 金储罐 / 钻石储罐 / 铝储罐 / 黑曜石储罐 / 铜储罐 / 钢储罐 / 不锈钢储罐 / 钛储罐 / 钨钢储罐)。
方块物品与 tooltip(ItemBlockExtendedTank:20-29)
ItemBlockExtendedTank 只覆写了一个方法 addInformation:取 tile.<name>.tooltip 本地化文本,按字面量 \n 分割成多行加进 tooltip。
- tooltip 键不带
irontank:命名空间前缀(是tile.ironTank.tooltip,不是tile.irontank.ironTank.tooltip)。 en_US.lang有全部 10 条 tooltip,文案形如Stores up to 32 Buckets of one Liquid+\n§4Not portable, use a dolly(2 行);黑曜石储罐是唯一 3 行的,额外带(Blast Proof)。- ⚠️
zh_CN.lang完全没有 tooltip 条目,只有 10 条方块名、13 条物品名和 1 条itemGroup.irontank。所以中文环境下按住 Shift 看不到容量和"需搬运器"的提示。 - 方块物品的其余行为全部继承
ItemBlock(正常放置、正常掉落),本类没有覆写放置或破坏逻辑。
合成配方机制(BlockExtendedTank:60-138)
配方来自 TankType.recipes 里的一串 9 个字符,被切成 3 行 3 列:
String[] recipeSplit = { recipe.substring(0,3), recipe.substring(3,6), recipe.substring(6,9) };
10 个配方的结构完全统一:
[ N N N ] N = 该等级的 screw<材料>
[ x q x ] x = paneGlass, q = BuildCraftFactory.tankBlock
[ r P v ] P = 该等级的双层板, r/v = 工具
- 核心是 BuildCraft 的储罐方块(
q=BuildCraftFactory.tankBlock):本 mod 是在 BC 储罐外套壳改容量,不是从零实现储罐。 r=craftingToolHardHammer(硬锤)、v=craftingToolScrewdriver(螺丝刀),两者都必须消耗,套装成本很高。- 每个等级只有一条配方,
TankType.recipes是List但实际都只放 1 条。
⚠️ 'r' 在 addRecipe() 里被定义了两次::86-87 是 'r', "plateSteel",:132-133 是 'r', "craftingToolHardHammer"。ShapedOreRecipe 构造器按顺序把 (字符, 物品) 对写进映射表,后写入者覆盖先写入者,所以实际生效的是硬锤(此为推断,依赖 Forge ShapedOreRecipe 的实现,该实现不在本仓库内)。本页及各等级页的配方图按"生效值 = 硬锤"绘制。
⚠️ 'm' 槽(矿石字典材料)在 10 条配方里一次都没出现:addRecipe() 计算了 targetMaterial = MaterialHelper.translateOreName(material) 并把 'm' 映射给它,但 10 条配方串全部不含 m。所以 TankType.materials 字段对方块配方实际不起作用,等级差异完全靠配方串里硬编码的字母表达。materials 列表对升级器配方同样不起作用(见 储罐升级器共用机制)。
MaterialHelper.translateOreName(utility/MaterialHelper.java:7-12)只特判字符串 "obsidian" → Blocks.obsidian,而 TankType 里用的是 "plateDenseObsidian",因此这个特例在本 mod 中从未命中。
已知问题 / 设计缺陷
-
TileEntity 注册 ID 字符串与实际包名不符:
IronTank.java:50-53用@Mod.EventHandler注册GameRegistry.registerTileEntity(TileIronTank.class, Reference.TILE_IRON_TANK),而Reference.TILE_IRON_TANK = "com.indemnity83.irontank.block.TileIronTank"(Reference.java:10)——block包,但类实际在tile包(com.indemnity83.irontank.tile.TileIronTank)。字符串 ID 与类真实全名不匹配(运行时后果未验证,本仓库无 Forge 源码)。 -
onRemap是空实现:IronTank.java:55-58的FMLMissingMappingsEvent处理器只打一行日志"Missing Mapping Event Fired!",没有任何重映射逻辑。该 GTNH fork 若改过方块/物品名,旧存档的irontank:*数据不会被迁移。 -
@Mod.EventHandler标在load(FMLInitializationEvent)上:方法名叫load但参数是初始化事件,与标准命名的init并列(IronTank.java:40-53),两个事件都是FMLInitializationEvent,行为等价但命名有误导性。 -
TankType.GLASS是死枚举值:capacity=0、name=""、配方为空串,ModBlocks没有为它注册方块,zh_CN.lang也没有名字。它只作为"把 BuildCraft 原版储罐当作玻璃罐来升级"的中间标记使用。
相关条目
- 10 个储罐方块:见分类页方块列表
- 储罐升级器共用机制 - 13 个升级器物品与
ItemTankChanger的右键逻辑