electrodynamics/src/main/scala/edx/basic/fluid/grate/TileGrate.scala

388 lines
12 KiB
Scala
Raw Normal View History

2015-01-14 12:06:03 +01:00
package edx.basic.fluid.grate
2014-07-22 08:32:42 +02:00
import java.util.{Collections, Comparator, HashMap, PriorityQueue}
import cpw.mods.fml.relauncher.{Side, SideOnly}
2015-01-14 12:06:03 +01:00
import edx.basic.fluid.grate.TileGrate._
import edx.core.Reference
import edx.core.prefab.node.{NodeFluidPressure, TileFluidProvider}
2014-07-22 08:32:42 +02:00
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.texture.IIconRegister
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.{ChatComponentText, IIcon}
2014-07-22 08:32:42 +02:00
import net.minecraft.world.IBlockAccess
import net.minecraftforge.common.util.ForgeDirection
import net.minecraftforge.fluids.{Fluid, FluidContainerRegistry, FluidRegistry, FluidStack}
2015-01-26 12:40:32 +01:00
import resonantengine.lib.mod.config.Config
import resonantengine.lib.transform.vector.Vector3
import resonantengine.lib.utility.FluidUtility
import resonantengine.prefab.block.impl.TRotatable
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
object TileGrate
{
@Config(comment = "The multiplier for the influence of the grate. Dependent on pressure.")
private var grateEffectMultiplier: Double = 5
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
@Config(comment = "The speed in which the grate drains blocks. Dependent on grate block influence.")
private var grateDrainSpeedMultiplier: Double = 0.01
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
@SideOnly(Side.CLIENT)
private var iconFront: IIcon = _
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
@SideOnly(Side.CLIENT)
private var iconSide: IIcon = _
}
2014-07-22 08:32:42 +02:00
2015-01-09 05:10:44 +01:00
class TileGrate extends TileFluidProvider(Material.rock) with TRotatable
2014-09-07 05:50:03 +02:00
{
2014-11-13 03:22:46 +01:00
fluidNode = new NodeFluidPressure(this)
2014-09-07 05:50:03 +02:00
private var gratePath: GratePathfinder = _
private var fillOver: Boolean = true
isOpaqueCube = false
normalRender = true
override def getIcon(world: IBlockAccess, side: Int): IIcon =
{
if (side == getDirection.ordinal()) iconFront else iconSide
}
override def getIcon(side: Int, metadata: Int): IIcon = if (side == 1) iconFront else iconSide
@SideOnly(Side.CLIENT)
override def registerIcons(iconRegister: IIconRegister)
{
iconFront = iconRegister.registerIcon(Reference.prefix + "grate_front")
iconSide = iconRegister.registerIcon(Reference.prefix + "grate")
}
override def readFromNBT(nbt: NBTTagCompound)
{
super.readFromNBT(nbt)
fillOver = nbt.getBoolean("fillOver")
}
override def writeToNBT(nbt: NBTTagCompound)
{
super.writeToNBT(nbt)
nbt.setBoolean("fillOver", fillOver)
}
override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = getDirection != from
override def canDrain(from: ForgeDirection, fluid: Fluid): Boolean = getDirection != from
override def update()
{
super.update()
2014-11-07 05:27:31 +01:00
2014-09-07 05:50:03 +02:00
if (!world.isRemote)
{
if (ticks % 10 == 0)
{
2014-11-13 03:22:46 +01:00
val pressure = fluidNode.asInstanceOf[NodeFluidPressure].pressure(getDirection)
2014-09-07 05:50:03 +02:00
val blockEffect = Math.abs(pressure * grateEffectMultiplier).toInt
2015-01-26 13:56:09 +01:00
fluidNode.getTank.setCapacity(Math.max(blockEffect * FluidContainerRegistry.BUCKET_VOLUME * grateDrainSpeedMultiplier, FluidContainerRegistry.BUCKET_VOLUME).toInt)
2014-11-07 03:08:34 +01:00
2014-09-07 05:50:03 +02:00
if (pressure > 0)
{
2015-01-07 14:44:52 +01:00
//Output fluid
2014-11-07 05:27:31 +01:00
if (fluidNode.getFluidAmount >= FluidContainerRegistry.BUCKET_VOLUME)
2014-09-07 05:50:03 +02:00
{
if (gratePath == null)
{
gratePath = new GratePathfinder(true)
2014-11-08 13:58:31 +01:00
gratePath.startFill(toVectorWorld, fluidNode.getFluid.getFluid.getID)
2014-07-22 08:32:42 +02:00
}
2014-11-07 05:27:31 +01:00
val filledInWorld = gratePath.tryFill(fluidNode.getFluidAmount, blockEffect)
fluidNode.drain(filledInWorld, true)
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
else if (pressure < 0)
{
2015-01-07 14:44:52 +01:00
//Input fluid
2014-11-07 05:27:31 +01:00
val maxDrain = fluidNode.getCapacity - fluidNode.getFluidAmount
2014-09-07 05:50:03 +02:00
if (maxDrain > 0)
{
if (gratePath == null)
{
gratePath = new GratePathfinder(false)
2014-11-08 13:58:31 +01:00
if (!gratePath.startDrain(toVector3))
2014-09-07 05:50:03 +02:00
{
resetPath()
}
}
if (gratePath != null && gratePath.tryPopulateDrainMap(blockEffect))
{
2014-11-07 05:27:31 +01:00
fluidNode.fill(gratePath.tryDrain(maxDrain, true), true)
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
def resetPath()
{
this.gratePath = null
}
2014-07-22 08:32:42 +02:00
2014-11-07 05:27:31 +01:00
override def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = fluidNode.fill(resource, doFill)
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack =
{
if (resource != null)
{
return drain(from, resource.amount, doDrain)
}
null
}
override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack =
{
2014-11-07 05:27:31 +01:00
fluidNode.drain(maxDrain, doDrain)
2014-09-07 05:50:03 +02:00
}
protected override def configure(player: EntityPlayer, side: Int, hit: Vector3): Boolean =
{
if (!player.isSneaking)
{
if (!world.isRemote)
{
fillOver = !fillOver
2014-10-26 15:41:40 +01:00
player.addChatMessage(new ChatComponentText("Grate now set to " + (if (fillOver) "" else "not ") + "fill higher than itself."))
2014-09-07 05:50:03 +02:00
gratePath = null
}
return true
}
super.configure(player, side, hit)
}
class GratePathfinder(checkVertical: Boolean)
{
var fluidType: Fluid = _
var start: Vector3 = _
var navigationMap: HashMap[Vector3, Vector3] = new HashMap[Vector3, Vector3]()
2014-10-26 15:41:40 +01:00
var workingNodes: PriorityQueue[ComparableVector] =
if (checkVertical) new PriorityQueue[ComparableVector]()
else new PriorityQueue[ComparableVector](1024, new Comparator[ComparableVector]()
{
override def compare(a: ComparableVector, b: ComparableVector): Int =
{
2015-01-07 14:44:52 +01:00
val wa = a.asInstanceOf[ComparableVector]
val wb = b.asInstanceOf[ComparableVector]
2014-10-26 15:41:40 +01:00
wa.iterations - wb.iterations
}
})
2014-09-07 05:50:03 +02:00
2015-01-07 14:44:52 +01:00
var drainNodes = new PriorityQueue[ComparableVector](1024, Collections.reverseOrder())
2014-09-07 05:50:03 +02:00
def startFill(start: Vector3, fluidID: Int)
{
this.fluidType = FluidRegistry.getFluid(fluidID)
this.start = start
2015-01-08 11:53:26 +01:00
val check = start + TileGrate.this.getDirection
navigationMap.put(check, start)
workingNodes.add(new ComparableVector(check, 0))
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
def tryFill(amount: Int, tries: Int): Int =
{
var filled = 0
if (amount >= FluidContainerRegistry.BUCKET_VOLUME)
{
for (i <- 0 until tries)
{
val next = workingNodes.poll()
if (next == null)
{
TileGrate.this.resetPath()
return 0
}
if (!isConnected(next.position))
{
TileGrate.this.resetPath()
return 0
}
2015-01-08 10:55:38 +01:00
val didFill = FluidUtility.fillBlock(TileGrate.this.worldObj, next.position, new FluidStack(fluidType, amount), true)
2014-09-07 05:50:03 +02:00
filled += didFill
2015-01-08 10:55:38 +01:00
if (FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, next.position) > 0 || didFill > 0)
2014-09-07 05:50:03 +02:00
{
addNextFill(next)
}
if (filled >= amount)
{
return filled
}
}
}
filled
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
def addNextFill(next: ComparableVector)
{
for (i <- 0 until 6)
{
val newPosition = next.position.clone().add(ForgeDirection.getOrientation(i))
if (!this.navigationMap.containsKey(newPosition) && !(!fillOver && newPosition.yi > y))
{
this.navigationMap.put(newPosition, next.position)
this.workingNodes.add(new ComparableVector(newPosition, next.iterations + 1))
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
}
2014-07-22 08:32:42 +02:00
2015-01-14 12:06:03 +01:00
def isConnected(nCheck: Vector3): Boolean =
{
var check = nCheck
if (check.equals(start))
return true
//Trace back in the navigation map to see if it reaches the starting point
do
{
check = navigationMap.get(check)
if (check.equals(null))
return false
if (check.equals(start))
return true
}
while (FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check) != null && fluidType.getID == FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check).getID)
return false
}
2014-09-07 05:50:03 +02:00
def startDrain(start: Vector3): Boolean =
{
fluidType = null
this.start = start
2015-01-08 11:53:26 +01:00
val check = start + TileGrate.this.getDirection
navigationMap.put(check, start)
workingNodes.add(new ComparableVector(check, 0))
fluidType = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check)
2014-09-07 05:50:03 +02:00
fluidType != null
}
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
def tryPopulateDrainMap(tries: Int): Boolean =
{
for (i <- 0 until tries)
{
val check = workingNodes.poll()
if (check == null)
{
return true
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
val checkFluid = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check.position)
if (checkFluid != null && fluidType.getID == checkFluid.getID)
{
addNextDrain(check)
val checkAmount = FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, check.position)
if (checkAmount > 0)
{
drainNodes.add(check)
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
2015-01-07 14:44:52 +01:00
return drainNodes.size > 0
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
def addNextDrain(next: ComparableVector)
{
for (i <- 0 until 6)
{
val check = next.position.clone().add(ForgeDirection.getOrientation(i))
val checkFluid = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check)
if (checkFluid != null && fluidType.getID == checkFluid.getID)
{
if (!navigationMap.containsKey(check))
{
navigationMap.put(check, next.position)
2015-01-07 14:44:52 +01:00
workingNodes.add(new ComparableVector(check, next.iterations + 1))
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
}
2014-07-22 08:32:42 +02:00
2014-09-07 05:50:03 +02:00
def tryDrain(targetAmount: Int, doDrain: Boolean): FluidStack =
{
var drainedAmount = 0
2015-01-07 14:44:52 +01:00
var break = false
2015-01-08 10:55:38 +01:00
//Check all the potential drain coordinates
2015-01-07 14:44:52 +01:00
while (!drainNodes.isEmpty && !break)
2014-09-07 05:50:03 +02:00
{
val fluidCoord = drainNodes.peek()
2015-01-08 10:55:38 +01:00
2014-09-07 05:50:03 +02:00
if (!isConnected(fluidCoord.position))
{
2015-01-08 10:55:38 +01:00
//The coordinate is not connected with the starting coordinate, therefore, we will not drain this.
2014-09-07 05:50:03 +02:00
TileGrate.this.resetPath()
return new FluidStack(fluidType, drainedAmount)
2014-07-22 08:32:42 +02:00
}
2015-01-08 10:55:38 +01:00
2015-01-07 14:44:52 +01:00
if (FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, fluidCoord.position) == null || this.fluidType.getID != FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, fluidCoord.position).getID)
2014-09-07 05:50:03 +02:00
{
2015-01-08 10:55:38 +01:00
drainNodes.poll()
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
else
{
val checkAmount = FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, fluidCoord.position)
2015-01-07 14:44:52 +01:00
if (drainedAmount + checkAmount <= targetAmount)
2014-09-07 05:50:03 +02:00
{
2015-01-07 14:44:52 +01:00
if (checkAmount == 0)
2014-09-07 05:50:03 +02:00
{
2015-01-08 10:55:38 +01:00
drainNodes.poll()
2015-01-07 14:44:52 +01:00
}
else
{
2015-01-08 10:55:38 +01:00
val fluidStack = FluidUtility.drainBlock(TileGrate.this.worldObj, fluidCoord.position, doDrain, 2)
//TODO: Do a delayed block update!
drainNodes.poll()
2015-01-07 14:44:52 +01:00
if (fluidStack != null)
2014-09-07 05:50:03 +02:00
{
2015-01-07 14:44:52 +01:00
drainedAmount += fluidStack.amount
if (drainedAmount >= targetAmount)
{
break = true
}
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
2015-01-07 14:44:52 +01:00
else
{
break = true
}
2014-07-22 08:32:42 +02:00
}
2014-09-07 05:50:03 +02:00
}
TileGrate.this.resetPath()
if (drainedAmount > 0)
{
return new FluidStack(fluidType, drainedAmount)
}
null
2014-07-22 08:32:42 +02:00
}
2015-01-07 14:44:52 +01:00
}
class ComparableVector(var position: Vector3, var iterations: Int) extends Comparable[ComparableVector]
{
override def compareTo(obj: ComparableVector): Int =
{
val wr = obj.asInstanceOf[ComparableVector]
if (this.position.y == wr.position.y)
{
return this.iterations - wr.iterations
}
this.position.yi - wr.position.yi
}
2014-09-07 05:50:03 +02:00
}
2014-07-22 08:32:42 +02:00
}