电力网络
概述
GT5-Unofficial 的电力传输采用有向图(Directed Graph)作为底层网络结构。每个电缆方块是图中的一个节点(Node),相邻电缆或机器之间通过**路径(Path)**连接。这种设计使得能量可以沿着多条路径从多个电源流向多个消费者,同时自动处理电压等级匹配、电压损失累积和过载检测。
核心组件
节点(Node)
每个电缆方块在网络中对应一个 Node 对象:
| 字段 | 类型 | 含义 |
|---|---|---|
mNodeValue |
int | 该节点的电压等级值(用于路由排序) |
mHighestNodeValue |
int | 整个网络中最高的节点等级 |
mNeighbourNodes[6] |
Node[] | 6 个方向的相邻节点(null 表示未连接) |
mNodePaths[6] |
NodePath[] | 6 个方向的路径对象(包含损耗、载流量等) |
mSelfPath |
NodePath | 该节点自身的路径属性 |
mConsumers |
List<ConsumerNode> | 连接在该节点的消费者列表 |
locks[6] |
Lock[] | 6 个方向的锁定状态 |
mCreationTime |
long | 创建时的 tick 数(防止每 tick 重复生成) |
PowerNode 在 Node 基础上增加了 mHadVoltage 字段,标记该节点是否曾经接收过电压(影响消费者供电行为)。
路径(Path / PowerNodePath)
路径代表两个节点之间的电缆段属性:
| 字段 | 类型 | 含义 |
|---|---|---|
mLoss |
long | 路径上所有电缆的损耗总和 |
mMaxAmps |
long | 路径中最弱电缆的载流量 |
mMaxVoltage |
long | 路径中最弱电缆的额定电压 |
mAmps |
long | 当前累积电流(用于过载检测) |
mVoltage |
long | 当前电压值(用于过压检测) |
mPipes |
List<MetaPipeEntity> | 路径上的所有电缆方块 |
消费者(ConsumerNode)
消费者是电力网络的目的地,包括:
NodeEnergyConnected:GT 机器(实现IEnergyConnected接口)NodeEnergyReceiver:RF/CoFH 机器(通过 EU→RF 转换接入)
路由算法
节点值层级
电压等级越高 → mNodeValue 越大 → 越靠近电源端
电压等级越低 → mNodeValue 越小 → 越靠近消费端
能量流动方向:高 mNodeValue → 低 mNodeValue(类似于水往低处流)
powerNode() 遍历流程
1. 从电源节点开始
2. 找到需要供电的消费者节点
3. 比较消费者与当前的 mNodeValue:
- 如果消费者等级更低:向下遍历(向低等级节点方向)
- 如果消费者等级更高:向上遍历(向高等级节点方向,但不超过网络最高值)
4. 沿着路径逐段传递能量,每段扣除电压损失
5. 当到达等级匹配的节点时,注入能量到消费者
6. 循环直到所有消费者都被处理或电流耗尽
电压损失累积
long tVoltLoss = 0;
if (tSelfPath != null) {
tVoltLoss += tSelfPath.getLoss(); // 自身电缆损耗
tSelfPath.applyVoltage(aVoltage, false);
}
tPath.applyVoltage(aVoltage - tVoltLoss, true); // 下一段施加剩余电压
tVoltLoss += tPath.getLoss(); // 累加下一段损耗
// 继续向下一节点传递,电压逐渐降低
循环保护
路由算法有最大 20 次迭代的循环保护:
// 如果 20 次迭代仍未找到目标节点,抛出异常
if (iterations > 20) {
throw new NullPointerException("infinite loop in powering nodes");
}
网络生命周期
网络形成
当电缆被放置并连接到机器或另一根电缆时:
checkConnections()被调用(每 20 tick 检查一次,或连接变化时立即检查)- 电缆调用
joinEnet()加入网络 - 创建
Node和NodePath对象 - 相邻节点相互注册为邻居
网络断开
当电缆被破坏时:
- 该电缆的
Node从网络中移除 - 相邻节点的邻居引用被清除
- 路径(Path)对象被销毁
- 如果路径上有
Lock,锁定状态仍然保留(永久锁定)
锁定状态
当路径发生过载(燃烧)时:
lock.addTileEntity(null); // null 被添加到锁定列表
// isLocked() 永远返回 true(除非重载世界)
被锁定的路径在后续所有遍历中被直接跳过:
if (aCurrentNode.locks[ordinalSide].isLocked()) {
return 0; // 跳过该方向
}
与 IC2 / RF 的兼容性
IC2 兼容
GT5 可以与 IndustrialCraft² 互操作:
// Util.emitEnergyToNetwork 中处理
for (IC2EnergySink sink : adjacentIC2Sinks) {
sink.acceptEnergyFrom(emitter);
sink.injectEnergy(...);
}
RF/CoFH 兼容
RF 机器通过 NodeEnergyReceiver 接入:
// EU → RF 转换
rfOut = (voltage * GregTechAPI.mEUtoRF) / 100;
mTileEntity.receiveEnergy(side, rfOut, false);
// 可选:RF 爆炸保护
if (GregTechAPI.mRFExplosions && machineCapacity < rfOut * 600) {
explode(); // 容量不足的 RF 机器会爆炸
}
玩家可观测的网络状态
扫描仪读取
使用扫描仪或 Waila bmod 可以查看:
- 当前电缆电压和电流
- 电缆最大载流量
- 能量吞吐量(EU/t)
- 路径状态(正常/锁定)
- 平均电压/电流(1 秒滚动平均)
玩家行为对网络的影响
| 玩家操作 | 网络效果 |
|---|---|
| 放置电缆 | 创建新节点,加入网络 |
| 破坏电缆 | 节点从网络移除,路径断开 |
| 安装 Cover | 阻止该方向的能量流向(类似断路) |
| 移除 Cover | 恢复该方向的能量流动 |
| 更换电缆类型 | 节点属性更新,可能改变载流量/损耗 |
| 破坏并替换电缆 | 重置该路径的 Lock 状态 |
网络设计建议
拓扑原则
- 同等级连接:同一电压等级的设备之间使用同等级电缆
- 树形结构优于网状:简单清晰的供电拓扑更容易排查问题
- 避免环路:虽然算法有循环保护,但环路会增加不必要的遍历
- 分压供电:不同电压等级使用独立的电缆网络,通过变压器连接
变压器中继
长距离输电时,每隔一定距离设置变压器进行电压补偿:
发电机 (HV) → 50 格铜缆 → 变压器降压 → 分送到 MV 设备
变压器可以恢复电压水平,确保下游设备获得足够电压。