blob: 1a24a2471bc0b016a0cb26d4ba7381ef6c09a174 [file] [log] [blame] [raw]
package li.cil.oc.common.tileentity
import li.cil.oc.api.network._
import li.cil.oc.client.{PacketSender => ClientPacketSender}
import li.cil.oc.server.network.Connector
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.{Config, api}
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
class PowerDistributor extends Environment with Analyzable {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("power", Visibility.Network).
create()
var globalBuffer = 0.0
var globalBufferSize = 0.0
var average = 0.0
private var lastSentAverage = 0.0
private val buffers = mutable.Set.empty[Connector]
private val distributors = mutable.Set.empty[PowerDistributor]
private var dirty = true
// ----------------------------------------------------------------------- //
@LuaCallback(value = "buffer", direct = true)
def buffer(context: Context, args: Arguments): Array[AnyRef] = result(globalBuffer)
@LuaCallback(value = "bufferSize", direct = true)
def bufferSize(context: Context, args: Arguments): Array[AnyRef] = result(globalBufferSize)
// ----------------------------------------------------------------------- //
def onAnalyze(stats: NBTTagCompound, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = {
stats.setString(Config.namespace + "text.Analyzer.TotalEnergy", "%.2f/%.2f".format(globalBuffer, globalBufferSize))
this
}
// ----------------------------------------------------------------------- //
def changeBuffer(delta: Double): Boolean = {
if (delta != 0) this.synchronized {
val oldBuffer = globalBuffer
globalBuffer = (globalBuffer + delta) max 0 min globalBufferSize
if (globalBuffer != oldBuffer) {
dirty = true
if (delta < 0) {
var remaining = -delta
for (connector <- buffers) {
connector.synchronized(if (connector.localBuffer > 0) {
connector.dirty = true
if (connector.localBuffer < remaining) {
remaining -= connector.localBuffer
connector.localBuffer = 0
}
else {
connector.localBuffer -= remaining
return true
}
})
}
}
else if (delta > 0) {
var remaining = delta
for (connector <- buffers) {
connector.synchronized(if (connector.localBuffer < connector.localBufferSize) {
connector.dirty = true
val space = connector.localBufferSize - connector.localBuffer
if (space < remaining) {
remaining -= space
connector.localBuffer = connector.localBufferSize
}
else {
connector.localBuffer += remaining
return true
}
})
}
}
}
}
false
}
// ----------------------------------------------------------------------- //
override def updateEntity() {
super.updateEntity()
if (isServer && (dirty || buffers.exists(_.dirty))) {
updateCachedValues()
}
}
override def validate() {
super.validate()
if (isClient) {
ClientPacketSender.sendPowerStateRequest(this)
}
}
// ----------------------------------------------------------------------- //
override def onConnect(node: Node) {
super.onConnect(node)
if (node == this.node) {
for (node <- node.network.nodes) node match {
case connector: Connector if connector.localBufferSize > 0 => this.synchronized {
buffers += connector
globalBuffer += connector.localBuffer
globalBufferSize += connector.localBufferSize
}
case _ => node.host match {
case distributor: PowerDistributor => distributors += distributor
case _ =>
}
}
dirty = true
}
else node match {
case connector: Connector => this.synchronized {
buffers += connector
globalBuffer += connector.localBuffer
globalBufferSize += connector.localBufferSize
dirty = true
}
case _ => node.host match {
case distributor: PowerDistributor => distributors += distributor
case _ =>
}
}
}
override def onDisconnect(node: Node) {
super.onDisconnect(node)
if (node == this.node) this.synchronized {
buffers.clear()
distributors.clear()
globalBuffer = 0
globalBufferSize = 0
average = -1
}
else node match {
case connector: Connector => this.synchronized {
buffers -= connector
globalBuffer -= connector.localBuffer
globalBufferSize -= connector.localBufferSize
dirty = true
}
case _ => node.host match {
case distributor: PowerDistributor => distributors -= distributor
case _ =>
}
}
}
// ----------------------------------------------------------------------- //
def updateCachedValues() {
// Computer average fill ratio of all buffers.
val (sumBuffer, sumBufferSize) =
buffers.foldRight((0.0, 0.0))((c, acc) => {
c.dirty = false // clear dirty flag for all connectors
(acc._1 + c.localBuffer, acc._2 + c.localBufferSize)
})
average = if (globalBufferSize > 0) globalBuffer / globalBufferSize else 0
val shouldSend = (lastSentAverage - average).abs > 0.05
for (distributor <- distributors) distributor.synchronized {
distributor.dirty = false
distributor.globalBuffer = sumBuffer
distributor.globalBufferSize = sumBufferSize
distributor.average = average
if (shouldSend) {
distributor.lastSentAverage = lastSentAverage
ServerPacketSender.sendPowerState(distributor)
}
}
}
}