本篇教程由作者设定使用 CC BY-NC 协议。

许多人似乎对GT6中的电线,流体管道的机制不太熟悉,这里简单讲解一下这两种东西的分配机制(以后有空说不定会把物流管道的也写出来qvq画饼.jpg)。

电线

先看代码:

for (byte tSide : ALL_SIDES_VALID_BUT[aSide]) if (canEmitEnergyTo(tSide)) {
   if (aAmperage <= rUsedAmperes) break;
   DelegatorTileEntity<TileEntity> tDelegator = getAdjacentTileEntity(tSide);
   if (aAlreadyPassed.add(tDelegator.mTileEntity)) {
      if (tDelegator.mTileEntity instanceof MultiTileEntityWireElectric) {
         if (((MultiTileEntityWireElectric)tDelegator.mTileEntity).isEnergyAcceptingFrom(TD.Energy.EU, tDelegator.mSideOfTileEntity, F)) {
            rUsedAmperes += ((MultiTileEntityWireElectric)tDelegator.mTileEntity).transferElectricity(tDelegator.mSideOfTileEntity, aVoltage, aAmperage-rUsedAmperes, aChannel, aAlreadyPassed);
         }
      } else {
         rUsedAmperes += ITileEntityEnergy.Util.insertEnergyInto(TD.Energy.EU, aVoltage, aAmperage-rUsedAmperes, this, tDelegator);
      }
   }
}

其中aSide是向导线输入电力的面。


简单来说,当电源向某格导线输出电力时,导线会尝试从"除了输入的面"的其他"每个具有有效连接的面"输出电力,如果是面对的是导线则递归执行此方法,否则向那个面的机器输出电力,消耗由机器报告的消耗电流数,如果有剩余电流则继续向下一优先级的面输出电流。

gregapi.data.CS中有规定ALL_SIDES_VALID=0,1,2,3,4,5,则导线的输出顺序也是从编号0到5的面依次尝试输出,实际是按照 下>上>北>南>东>西 的顺序进行输出。


因此,gt6中的电线是邻域交换的算法,不应将一根导线视为整体,而应视为一格格单独的导线在进行传输。(不过,递归执行是在同一个tick中进行的,也就是电会瞬间到达用电器,导线并不会缓存电量)

(另:根据大部分加工机器的基础类代码,消耗的电流数N 实际上是 当(N*输入电压)>需求电压时可取的最小值,比如普通MV机器会默认消耗256EU,假如因线损等原因提供了120EU的电压,机器会接受3A*120EU的电,多余的3*120-256EU(104EU)的电则会存入缓存,在下一刻需求电压即变为256-104EU。

其他的机器超频机制等,请参考站内另一篇教程:https://www.mcmod.cn/post/3180.html



下面举几个实例来看(供电电池盒均放8个满电池):

简析GT6中管道和电线的机制-第1张图片


电池盒缓存未满时可输入16A电流,根据上文优先级,下面的电池盒会优先填满缓存,右面的电池盒则得不到任何电流。

电池盒缓存满之后,根据下方电池盒的空电池数决定可输入电流的安培数,若可输入电流<8,则会向右方的电池盒输出剩余电流。


简析GT6中管道和电线的机制-第2张图片


如图,两相对比可以看出来,导线输出电流的顺序与距离,位置等因素均无关,导线只会按照 下>上>北>南>东>西 的顺序依次尝试输出。输出电池盒紧邻的那格导线会按该顺序先将电输给它下面的那格导线,之后再递归搜索到连接的电池盒,另一面的电池盒/导线则得不到任何电流。


(光缆与电线是一样的算法)


流体管道

先看代码:

//省略:填充炼药锅等方块,检测对应面是否接受流体,覆盖版是否允许流体通过,防止流体流向上一游戏刻的输入面等
for (byte tSide : ALL_SIDES_VALID) {
//省略:检测六个面的所有可能输出的流体管道或具有流体槽的机器(并且剔除上次向本管道输入的流体管道),并将其计数(tTargetCount),压制到两个列表中(管道:tPipes,流体槽:tTanks)
// Amount to distribute normally.
tAmount = UT.Code.divup(tAmount, tTargetCount);
// Distribute to Pipes first.
for (FluidTankGT tPipe : tPipes) mTransferredAmount += aTank.remove(tPipe.add(aTank.amount(tAmount-tPipe.amount()), aTank.get()));
// Check if we are empty.
if (aTank.isEmpty()) return;
// Distribute to Tanks afterwards.
for (DelegatorTileEntity tTank : tTanks) mTransferredAmount += aTank.remove(FL.fill(tTank, aTank.get(tAmount), T));
// Check if we are empty.
if (aTank.isEmpty()) return;
// No Targets? Nothing to do then.
if (tPipes.isEmpty()) return;
// And then if there still is pressure, distribute to Pipes again.
tAmount = (aTank.amount() - mCapacity/2) / tPipes.size();
if (tAmount > 0) for (FluidTankGT tPipe : tPipes) mTransferredAmount += aTank.remove(tPipe.add(aTank.amount(tAmount), aTank.get()));
}


简而言之,流体管道会计数六个面中所有可能输出的流体管道或具有流体槽的机器数(记为N),并先向每个连接的管道输出N L的流体,再向每个流体槽输出N L的流体。注意输出N L不等于会接受N L,目标可能半满以至于只能接受一部分。因此若管道不空,最后会再次向每个连接的管道输出一次(本管道当前剩余流体量-(本管道容量/2)/目标数量) L的流体。

尽管gt有做流体管道防倒流的代码,但是那句代码仍没有解决1L流体来回窜的现象,期待gt以后的解决方案呢。