blob: 8aa7bd5741d6da0da87fe1291dfd9c8ac9fc69f2 [file] [log] [blame] [raw]
package li.cil.oc.common.tileentity
import li.cil.oc.Settings
import li.cil.oc.api.network.{Connector, SidedEnvironment}
import net.minecraftforge.common.ForgeDirection
trait PowerBalancer extends PowerInformation with SidedEnvironment {
var globalBuffer, globalBufferSize = 0.0
override def updateEntity() {
super.updateEntity()
if (isServer && world.getWorldTime % Settings.get.tickFrequency == 0) {
val nodes = connectors
def network(connector: Connector) = if (connector != null) connector.network else this
// Yeeeeah, so that just happened... it's not a beauty, but it works. This
// is necessary because power in networks can be updated asynchronously,
// i.e. in separate threads (e.g. to allow screens to consume energy when
// they change, which usually happens in a computers executor thread).
// This multi-lock only happens in the main server thread, though, so we
// don't have to fear deadlocks. I think.
network(nodes(0)).synchronized {
network(nodes(1)).synchronized {
network(nodes(2)).synchronized {
network(nodes(3)).synchronized {
network(nodes(4)).synchronized {
network(nodes(5)).synchronized {
val (sumBuffer, sumSize) = distribute()
if (sumSize > 0) {
val ratio = sumBuffer / sumSize
for (node <- connectors if isPrimary(node)) {
node.changeBuffer(node.globalBufferSize * ratio - node.globalBuffer)
}
}
globalBuffer = sumBuffer
globalBufferSize = sumSize
}
}
}
}
}
}
updatePowerInformation()
}
}
protected def distribute() = {
var sumBuffer, sumSize = 0.0
for (node <- connectors if isPrimary(node)) {
sumBuffer += node.globalBuffer
sumSize += node.globalBufferSize
}
(sumBuffer, sumSize)
}
private def connectors = ForgeDirection.VALID_DIRECTIONS.view.map(sidedNode(_) match {
case connector: Connector => connector
case _ => null
})
private def isPrimary(connector: Connector) = {
val nodes = connectors
connector != null && nodes(nodes.indexWhere(_.network == connector.network)) == connector
}
}