水力坝(Hydro Dam)

基本信息

属性 值
实现类 blocks/HEHydroDamTileEntity.java(438 行)
注册 ID HEConfig.blockIdOffset(默认 17000)
物品形式 new HEHydroDamTileEntity(HEConfig.blockIdOffset, "he_dam", "Hydro Dam").getStackForm(1L)(hooks/HEHooksShared.java:96)
多方块尺寸 5 × 5 × 5(tt.beginStructureBlock(5, 5, 5, true),HEHydroDamTileEntity.java:328)
控制器位置 正面中心(x+2, y+3, z+0),tt.addController("Front Center")(HEHydroDamTileEntity.java:329)
壳体材料 GT GregTechAPI.sBlockConcretes,meta 8(concreteBlockMeta = 8,HEHydroDamTileEntity.java:61)
内部容积 3×3×3 的空腔(水就存在这里)
维护需求 无(HEHydroDamTileEntity.java:95-101 把 6 个扳手类标志全置 true)

这是本 mod 唯一的多层(5 层)多方块结构。 ULV 被禁用(配方注释 // ULV is disabled!), 坝的电压档位由插入槽 1 的电路决定,不分型号。

结构定义(逐格对照)

HEHydroDamTileEntity.java:71-90:

private static final IStructureDefinition<HEHydroDamTileEntity> multiblockDefinition = StructureDefinition
        .<HEHydroDamTileEntity>builder()
        .addShape(
                HETags.structurePieceMain,
                transpose(
                        new String[][] { { "HHHHH", "CCCCC", "CCCCC", "CCCCC", "CCCCC" },
                                { "HHHHH", "C   C", "C   C", "C   C", "C   C" },
                                { "HHHHH", "C   C", "C   C", "C   C", "C   C" },
                                { "HH~HH", "C   C", "C   C", "C   C", "C   C" },
                                { "HHHHH", "CCCCC", "CCCCC", "CCCCC", "CCCCC" } }))
        .addElement('H', ofChain(
                ofHatchAdder(HEHydroDamTileEntity::addClassicToMachineList, steelTextureIndex,
                        GregTechAPI.sBlockConcretes, concreteBlockMeta),
                ofBlockAnyMeta(GregTechAPI.sBlockConcretes, concreteBlockMeta)))
        .addElement('C', ofBlockAnyMeta(GregTechAPI.sBlockConcretes, concreteBlockMeta)).build();

字符串数组为 [y][z],每串 5 字符代表该 z 层沿 x 的 5 格:

y 层 z=0 z=1 z=2 z=3 z=4
4(顶) HHHHH CCCCC CCCCC CCCCC CCCCC
3 HH~HH ← 控制器在 x=2 C C C C C C C C
2 HHHHH C C C C C C C C
1 HHHHH C C C C C C C C
0(底) HHHHH CCCCC CCCCC CCCCC CCCCC
元素 含义
H GT 混凝土 meta 8(ofBlockAnyMeta)或 任意输入舱(ofHatchAdder)——纹理索引 steelTextureIndex = 16(HEHydroDamTileEntity.java:60)
C GT 混凝土 meta 8(ofBlockAnyMeta)
~ 控制器(HEHydroDamTileEntity.java:79 的 HH~HH)
空格 空气 —— 3×3×3 内部空腔,水在此生成

checkPiece(HETags.structurePieceMain, 2, 3, 0, errors)(HEHydroDamTileEntity.java:115) 与 buildPiece(..., 2, 3, 0)(HEHydroDamTileEntity.java:120)的偏移 (2, 3, 0) 与形状里的 ~ 位置一致。

关于「可否旋转 / 拆除」

源码没有任何旋转或拆除的特殊处理:

  • 结构定义无 setSymmetry / setOrientation 声明,即固定朝向, 控制器必须在 z+0 那一面
  • 未覆写 onBlockBroken / onBlockDestroyed 之类方法
  • 破坏控制器会走 onBreakController(waterId)(HEHydroDamTileEntity.java:300), 释放该坝占用的 waterId

⚠️ 不要臆断「可以旋转建造」——源码里找不到任何支持旋转的声明。

电压档位:靠电路,不是分型号

坝没有电压型号,档位在运行时读取:

private int getVoltageTier() {
    boolean configCircuitIsPresent = mInventory != null && mInventory[1] != null
            && mInventory[1].getItem() == GTUtility.getIntegratedCircuit(0).getItem();
    return configCircuitIsPresent ? HEUtil.clamp(mInventory[1].getItemDamage(), 1, GTValues.V.length - 1) : 1;
}

(HEHydroDamTileEntity.java:138-142)

  • 在槽 1 放入集成电路(getIntegratedCircuit(0) 只用来取物品类型比对)
  • 档位 = 电路的 itemDamage,用 HEUtil.clamp 夹在 1 ~ GTValues.V.length - 1
  • 不放电路时固定为档位 1(LV)

该档位只用于两处压力换算:

用途 公式 行
GUI 最大压力 HEConfig.pressureIncreasePerTier * getVoltageTier() HEHydroDamTileEntity.java:134-136
吸入加压水的门槛 见下 HEHydroDamTileEntity.java:156-160

每 tick 逻辑 onRunningTick(HEHydroDamTileEntity.java:144-191)

mMaxProgresstime = 1(HEHydroDamTileEntity.java:130),即每 tick 都跑。

1. 容量与钳制(151-154)

euCapacity = HEServer.instance.getEuCapacity(waterId);
euStored = HEUtil.clamp(euStored, 0, euCapacity);
euCapacityGui = HEServer.instance.getEuCapacityAt(waterId, (int) (getYCoord() + getMaxGuiPressure()));

容量按水坝的蓄水高度动态计算,GUI 上限用「控制器 Y + 最大压力」。

2. 从流体舱吸入加压水(156-167)

final int waterLevelOverController = (int) (HEServer.instance.getWaterLevel(waterId) - getYCoord());
getStoredFluids().forEach(fluidStack -> {
    if (fluidStack.getFluidID() == HE.pressurizedWater.getID()
            && HE.pressurizedWater.getPressure(fluidStack) >= waterLevelOverController) {
        final long availableEnergy = (long) (fluidStack.amount * HEConfig.euPerMilliBucket);
        final long storableEnergy = Math.min(euCapacity - euStored, availableEnergy);
        fluidStack.amount -= storableEnergy;
        euStored += storableEnergy;
        euPerTickIn += storableEnergy;
    }
});

语义:只有当进水压力 ≥ 水面高出控制器的格数时才吸。 即「水压必须压得住这个高度差」——这正是坝的意义。

📌 单位不一致(可疑):fluidStack.amount 是毫桶(mB), 注释里也写 EU per tick。 第 163 行写的是 fluidStack.amount -= storableEnergy;—— 直接把「按 euPerMilliBucket 换算出的能量」从流体数量里扣, 而不是先换算回 mB 再扣。euPerMilliBucket 默认 1.0 时两者数值相同, 改这个配置就会出现能量与流体量不匹配。源码无注释说明是有意为之。

3. 输出加压水(169-176)

final int availableOutput = (int) Math.min(HEConfig.damDrainPerSecond, euStored);
final int availableOutputAsWater = (int) (availableOutput * HEConfig.milliBucketPerEU);
if (availableOutput > 0) {
    final int distributedFluid = distributeFluid(new FluidStack(HE.pressurizedWater, availableOutputAsWater));
    final long distributedEu = (long) (distributedFluid * HEConfig.euPerMilliBucket);
    euStored -= distributedEu;
    euPerTickOut += distributedEu;
}

单 tick 最多放 damDrainPerSecond(默认 2048,配置注释写「per tick」, 但配置项名与 Defaults 注释都写 damDrainPerSecond/per second—— 单位在命名与注释间不一致,见 配置项)。

4. 雨天发电(178-184)

if (getBaseMetaTileEntity().getWorld().isRaining()) {
    final long rainingEuGeneration = (long) (HEServer.instance.getRainedOnBlocks(waterId)
            * HEConfig.waterBonusPerSurfaceBlockPerRainTick);
    final long addedEu = Math.min(euCapacity - euStored, rainingEuGeneration);
    euStored += addedEu;
    euPerTickIn += addedEu;
}

下雨时按水面方块数 × waterBonusPerSurfaceBlockPerRainTick(默认 1.0)产 EU。

5. 收尾(186-190)

写入两个 AveragedRingBuffer(64) 滑动平均(euPerTickInAverage / euPerTickOutAverage, HEHydroDamTileEntity.java:68-69),然后 HEServer.instance.setWaterLevel(waterId, euStored) —— 蓄水量与能量是同一个值。

if (waterId < 0 || waterId >= HEConfig.maxDams) return false;(HEHydroDamTileEntity.java:146) 是入口保护:waterId 初始为 -1(HEHydroDamTileEntity.java:62), 必须在 onPlacecontroller 分配到合法 ID 后才工作。

输出分配 distributeFluid(HEHydroDamTileEntity.java:193-…)

遍历 mOutputHatches(filterValidMTEs),对每个:

检查 跳过条件 行
能否输出液体 !hatch.outputsLiquids() 196-198
流体锁 hatch.isFluidLocked() && lockedFluid != null && !lockedFluid.equals(fluidStack.getFluid()) 199-202
输出槽为空则先填 0 量的加压水 currentFluid.getFluid().getID() <= 0 204-207
容量 hatch.getCapacity() - currentFluid.amount 209

结构提示文本(HEHydroDamTileEntity.java:328-333)

tt.beginStructureBlock(5, 5, 5, true);
tt.addController("Front Center");
tt.addStructureInfo("Fill the rest with Light Concrete");
tt.addStructureInfo("No Maintenance Hatch required!");

GUI

坝有自己的配置 GUI(不是标准 GT GUI):

  • network/container/HEHydroDamConfigContainer.java
  • client/gui/HEHydroDamConfigContainer.java(GUI 容器)
  • client/gui/HEPopupLimitGui.java(六方向限高弹窗)
  • 背景贴图:textures/gui/he_water_config.png、 textures/gui/he_water_config_limits_popup.png(HE.java 的两个 dam*BackgroundLocation)

GUI 刷新有 200 tick(10 秒)延迟:HE.controllerGuiUpdateDelay = 200(HE.java)。

关联