electrodynamics/src/main/scala/edx/core/prefab/node/NodeFluidPressure.scala
2015-01-26 20:56:09 +08:00

194 lines
5.3 KiB
Scala

package edx.core.prefab.node
import net.minecraftforge.common.util.ForgeDirection
import net.minecraftforge.fluids.{FluidContainerRegistry, IFluidHandler}
import resonantengine.api.graph.{INodeProvider, IUpdate}
import resonantengine.lib.grid.core.UpdateTicker
import scala.collection.convert.wrapAll._
/**
* A node for fluid that moves based on pressure
*
* @param parent Parent(TileEntity or Multipart) that contains this node
* @param volume Amount of fluid in liters
*
* @author Calclavia
*/
class NodeFluidPressure(parent: INodeProvider, volume: Int = FluidContainerRegistry.BUCKET_VOLUME) extends NodeFluid(parent, volume) with IUpdate
{
var maxFlowRate = 1000
var maxPressure = 100
var doPressureUpdate = true
private var _pressure: Int = 0
override def reconstruct()
{
super.reconstruct()
UpdateTicker.world.addUpdater(this)
}
override def deconstruct()
{
super.deconstruct()
UpdateTicker.world.removeUpdater(this)
}
def update(deltaTime: Double)
{
if (!world.isRemote)
{
if (doPressureUpdate)
updatePressure()
distribute(deltaTime)
}
}
def distribute(deltaTime: Double)
{
val flowRate = (maxFlowRate * deltaTime).toInt
directionMap synchronized
{
directionMap.foreach
{
case (handler: IFluidHandler, dir: ForgeDirection) =>
{
if (handler.isInstanceOf[NodeFluidPressure])
{
//"A" is this node. "B" is the other node
//It's another pressure node
val otherNode = handler.asInstanceOf[NodeFluidPressure]
val pressureA = pressure(dir)
val pressureB = otherNode.pressure(dir.getOpposite)
//High pressure to low
if (pressureA >= pressureB)
{
val tankA = getTank
if (tankA != null)
{
val fluidA = tankA.getFluid
if (fluidA != null)
{
val amountA = fluidA.amount
if (amountA > 0)
{
val tankB = otherNode.getTank
if (tankB != null)
{
doDistribute(deltaTime, dir, this, otherNode, flowRate)
}
}
}
}
}
}
else
{
//It's a fluid handler.
val pressure = this.pressure(dir)
val tankPressure = 0
val sourceTank = getTank
val transferAmount = (Math.max(pressure, tankPressure) - Math.min(pressure, tankPressure)) * flowRate
if (pressure > tankPressure)
{
if (sourceTank.getFluidAmount > 0 && transferAmount > 0)
{
val drainStack = drain(dir.getOpposite, transferAmount, false)
drain(dir.getOpposite, handler.fill(dir.getOpposite, drainStack, true), true)
}
}
else if (pressure < tankPressure)
{
if (transferAmount > 0)
{
val drainStack = handler.drain(dir.getOpposite, transferAmount, false)
if (drainStack != null)
{
handler.drain(dir.getOpposite, fill(dir.getOpposite, drainStack, true), true)
}
}
}
}
}
}
}
}
protected def doDistribute(deltaTime: Double, dir: ForgeDirection, nodeA: NodeFluidPressure, nodeB: NodeFluidPressure, flowRate: Int)
{
val tankA = nodeA.getTank
val tankB = nodeB.getTank
val pressureA = nodeA.pressure(dir)
val pressureB = nodeB.pressure(dir.getOpposite)
val amountA = tankA.getFluidAmount
val amountB = tankB.getFluidAmount - nodeB.fill(dir, drain(dir.getOpposite, amountA, false), false)
var quantity = if (pressureA > pressureB) (pressureA - pressureB) * flowRate else 0
quantity = Math.min(Math.min(quantity, tankB.getCapacity - amountB), amountA)
if (quantity > 0)
{
val drainStack = drain(dir.getOpposite, quantity, false)
if (drainStack != null && drainStack.amount > 0)
{
drain(dir.getOpposite, nodeB.fill(dir, drainStack, true), true)
}
}
}
def pressure(direction: ForgeDirection): Int = _pressure
protected def updatePressure()
{
var totalPressure = 0
val connectionSize = connections.size
var minPressure = 0
var maxPressure = 0
directionMap.foreach
{
case (handler: IFluidHandler, dir: ForgeDirection) =>
{
if (handler.isInstanceOf[NodeFluidPressure])
{
val node = handler.asInstanceOf[NodeFluidPressure]
val pressure = node.pressure(dir.getOpposite)
minPressure = Math.min(pressure, minPressure)
maxPressure = Math.max(pressure, maxPressure)
totalPressure += pressure
}
}
}
if (connectionSize == 0)
{
pressure = 0
}
else
{
if (minPressure < 0)
minPressure += 1
if (maxPressure > 0)
maxPressure -= 1
pressure = Math.max(minPressure, Math.min(maxPressure, totalPressure / connectionSize + Integer.signum(totalPressure)))
}
}
def pressure: Int = _pressure
def pressure_=(pressure: Int)
{
this._pressure = pressure
}
override def updatePeriod: Int = 50
}