electrodynamics/archaic/src/main/scala/resonantinduction/archaic/fluid/grate/TileGrate.java

530 lines
12 KiB
Java
Raw Normal View History

2014-02-28 03:31:44 +01:00
package resonantinduction.archaic.fluid.grate;
import calclavia.lib.config.Config;
import calclavia.lib.prefab.tile.IRotatable;
import calclavia.lib.utility.FluidUtility;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
2014-03-08 23:12:17 +01:00
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
2014-03-08 23:12:17 +01:00
import net.minecraft.util.Icon;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.fluids.*;
2014-03-08 23:12:17 +01:00
import resonantinduction.core.Reference;
import resonantinduction.core.fluid.TilePressureNode;
import resonantinduction.core.grid.fluid.FluidPressureNode;
import universalelectricity.api.vector.Vector3;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
2014-03-08 23:12:17 +01:00
public class TileGrate extends TilePressureNode implements IRotatable
{
@Config(comment = "The multiplier for the influence of the grate. Dependent on pressure.")
private static double grateEffectMultiplier = 5;
@Config(comment = "The speed in which the grate drains blocks. Dependent on grate block influence.")
private static double grateDrainSpeedMultiplier = 0.01;
2014-03-08 23:12:17 +01:00
@SideOnly(Side.CLIENT)
private static Icon iconFront, iconSide;
2014-02-23 06:39:44 +01:00
private GratePathfinder gratePath;
private boolean fillOver = true;
2014-03-08 23:12:17 +01:00
public TileGrate()
{
super(Material.rock);
isOpaqueCube = false;
normalRender = true;
rotationMask = Byte.parseByte("111111", 2);
node = new FluidPressureNode(this);
2014-03-12 15:11:02 +01:00
node.maxFlowRate = getPressureTank().getCapacity();
}
2014-03-08 23:12:17 +01:00
@Override
public Icon getIcon(IBlockAccess world, int side)
{
return side == getDirection().ordinal() ? iconFront : iconSide;
}
@Override
public Icon getIcon(int side, int metadata)
{
return side == 1 ? iconFront : iconSide;
}
@Override
@SideOnly(Side.CLIENT)
public void registerIcons(IconRegister iconRegister)
{
iconFront = iconRegister.registerIcon(Reference.PREFIX + "grate_front");
iconSide = iconRegister.registerIcon(Reference.PREFIX + "grate");
}
@Override
protected boolean configure(EntityPlayer player, int side, Vector3 hit)
{
if (!player.isSneaking())
{
if (!world().isRemote)
{
fillOver = !fillOver;
player.addChatMessage("Grate now set to " + (fillOver ? "" : "not ") + "fill higher than itself.");
gratePath = null;
}
return true;
}
return super.configure(player, side, hit);
}
@Override
public void readFromNBT(NBTTagCompound nbt)
{
super.readFromNBT(nbt);
fillOver = nbt.getBoolean("fillOver");
}
@Override
public void writeToNBT(NBTTagCompound nbt)
{
super.writeToNBT(nbt);
nbt.setBoolean("fillOver", fillOver);
}
2014-01-08 15:18:24 +01:00
@Override
2014-02-23 06:39:44 +01:00
public FluidTankInfo[] getTankInfo(ForgeDirection from)
2014-01-08 15:18:24 +01:00
{
return new FluidTankInfo[] { getPressureTank().getInfo() };
2014-01-08 15:18:24 +01:00
}
@Override
2014-02-23 06:39:44 +01:00
public boolean canFill(ForgeDirection from, Fluid fluid)
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
return getDirection() != from;
2014-01-25 13:25:27 +01:00
}
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
@Override
public boolean canDrain(ForgeDirection from, Fluid fluid)
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
return getDirection() != from;
2014-01-08 15:18:24 +01:00
}
@Override
public void updateEntity()
{
super.updateEntity();
if (!world().isRemote)
2014-01-23 15:50:22 +01:00
{
2014-03-12 15:11:02 +01:00
if (ticks % 10 == 0)
2014-02-23 06:39:44 +01:00
{
int pressure = node.getPressure(getDirection());
int blockEffect = (int) Math.abs(pressure * grateEffectMultiplier);
getPressureTank().setCapacity((int) Math.max(blockEffect * FluidContainerRegistry.BUCKET_VOLUME * grateDrainSpeedMultiplier, FluidContainerRegistry.BUCKET_VOLUME));
2014-01-23 15:50:22 +01:00
if (pressure > 0)
{
// Fill
if (getPressureTank().getFluidAmount() >= FluidContainerRegistry.BUCKET_VOLUME)
{
if (gratePath == null)
{
gratePath = new GratePathfinder(true);
gratePath.startFill(new Vector3(this), getPressureTank().getFluid().getFluid().getID());
}
int filledInWorld = gratePath.tryFill(getPressureTank().getFluidAmount(), blockEffect);
getPressureTank().drain(filledInWorld, true);
}
}
else if (pressure < 0)
{
// Drain
int maxDrain = getPressureTank().getCapacity() - getPressureTank().getFluidAmount();
if (maxDrain > 0)
{
if (gratePath == null)
{
gratePath = new GratePathfinder(false);
if (!gratePath.startDrain(new Vector3(this)))
{
resetPath();
}
}
if (gratePath != null && gratePath.tryPopulateDrainMap(blockEffect))
{
getPressureTank().fill(gratePath.tryDrain(maxDrain, true), true);
}
}
}
}
2014-01-23 15:50:22 +01:00
}
}
2014-02-23 06:39:44 +01:00
@Override
public int fill(ForgeDirection from, FluidStack resource, boolean doFill)
{
return getPressureTank().fill(resource, doFill);
2014-01-25 13:25:27 +01:00
}
2014-01-23 15:50:22 +01:00
2014-01-25 13:25:27 +01:00
@Override
2014-02-23 06:39:44 +01:00
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain)
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
if (resource != null)
{
2014-02-23 06:39:44 +01:00
return drain(from, resource.amount, doDrain);
}
2014-02-23 06:39:44 +01:00
return null;
2014-01-25 13:25:27 +01:00
}
2014-01-23 15:50:22 +01:00
2014-01-25 13:25:27 +01:00
@Override
2014-02-23 06:39:44 +01:00
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain)
2014-01-25 13:25:27 +01:00
{
return getPressureTank().drain(maxDrain, doDrain);
2014-01-23 15:50:22 +01:00
}
2014-02-23 06:39:44 +01:00
/**
* Pathfinding operations
*
2014-02-23 06:39:44 +01:00
* @author Calclavia
*/
public void resetPath()
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
this.gratePath = null;
}
2014-01-08 15:18:24 +01:00
public static class ComparableVector implements Comparable
{
public Vector3 position;
public int iterations;
public ComparableVector(Vector3 position, int iterations)
{
this.position = position;
this.iterations = iterations;
}
@Override
public int compareTo(Object obj)
{
ComparableVector wr = (ComparableVector) obj;
if (this.position.y == wr.position.y)
{
return this.iterations - wr.iterations;
}
return this.position.intY() - wr.position.intY();
}
}
2014-02-23 06:39:44 +01:00
public class GratePathfinder
{
/**
* The type of fluid we're dealing with. When draining, this will be the type of fluid being
* drained.
*/
public Fluid fluidType;
2014-02-23 06:39:44 +01:00
/**
* The starting vector for our grate.
*/
Vector3 start;
/**
* All the back trace blocks tracing back to the original.
*/
HashMap<Vector3, Vector3> navigationMap = new HashMap<Vector3, Vector3>();
/**
* The nodes we're currently working on.
*/
PriorityQueue<ComparableVector> workingNodes;
/**
* The list of blocks to drain.
*/
PriorityQueue<ComparableVector> drainNodes = new PriorityQueue<ComparableVector>(1024, Collections.reverseOrder());
public GratePathfinder(boolean checkVertical)
2014-01-25 13:48:06 +01:00
{
2014-02-23 06:39:44 +01:00
if (checkVertical)
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
this.workingNodes = new PriorityQueue<ComparableVector>();
2014-01-08 15:18:24 +01:00
}
2014-02-23 06:39:44 +01:00
else
{
this.workingNodes = new PriorityQueue<ComparableVector>(1024, new Comparator()
{
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
@Override
public int compare(Object a, Object b)
{
TileGrate.ComparableVector wa = (TileGrate.ComparableVector) a;
TileGrate.ComparableVector wb = (TileGrate.ComparableVector) b;
2014-01-25 13:25:27 +01:00
2014-02-23 06:39:44 +01:00
return wa.iterations - wb.iterations;
}
});
}
}
/**
* Traces back to the start position to see if this fluid position is connected with the
* starting position through fluid mediums.
*/
public boolean isConnected(Vector3 check)
{
if (check.equals(this.start))
{
2014-02-23 06:39:44 +01:00
return true;
}
2014-02-23 06:39:44 +01:00
do
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
check = this.navigationMap.get(check);
if (check == null)
{
2014-02-23 06:39:44 +01:00
return false;
}
2014-02-23 06:39:44 +01:00
if (check.equals(this.start))
{
2014-02-23 06:39:44 +01:00
return true;
}
2014-01-25 13:25:27 +01:00
}
2014-02-23 06:39:44 +01:00
while (FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check) != null && fluidType.getID() == FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check).getID());
2014-01-25 13:48:06 +01:00
2014-02-23 06:39:44 +01:00
return false;
}
public void startFill(Vector3 start, int fluidID)
{
this.fluidType = FluidRegistry.getFluid(fluidID);
this.start = start;
2014-01-25 15:07:27 +01:00
2014-02-23 06:39:44 +01:00
for (int i = 0; i < 6; i++)
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
ForgeDirection dir = ForgeDirection.getOrientation(i);
if (dir == TileGrate.this.getDirection())
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
Vector3 check = start.clone().translate(dir);
this.navigationMap.put(check, start);
this.workingNodes.add(new TileGrate.ComparableVector(check, 0));
2014-01-08 15:18:24 +01:00
}
}
2014-02-23 06:39:44 +01:00
}
2014-01-25 13:48:06 +01:00
2014-02-23 06:39:44 +01:00
/**
* Tries to fill.
*
2014-02-23 06:39:44 +01:00
* @param amount
* @param tries
* @return Amount filled.
*/
public int tryFill(int amount, int tries)
{
2014-02-24 13:25:50 +01:00
int filled = 0;
2014-02-23 06:39:44 +01:00
2014-02-24 13:25:50 +01:00
if (amount >= FluidContainerRegistry.BUCKET_VOLUME)
{
for (int i = 0; i < tries; i++)
2014-01-08 15:18:24 +01:00
{
2014-02-24 13:25:50 +01:00
ComparableVector next = workingNodes.poll();
2014-01-25 13:48:06 +01:00
2014-02-24 13:25:50 +01:00
if (next == null)
{
TileGrate.this.resetPath();
return 0;
}
2014-01-08 15:18:24 +01:00
2014-02-24 13:25:50 +01:00
if (!isConnected(next.position))
{
TileGrate.this.resetPath();
return 0;
}
2014-02-23 06:39:44 +01:00
int didFill = FluidUtility.fillBlock(TileGrate.this.worldObj, next.position, new FluidStack(fluidType, amount), true);
filled += didFill;
2014-02-24 13:25:50 +01:00
if (FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, next.position) > 0 || didFill > 0)
{
2014-02-24 13:25:50 +01:00
addNextFill(next);
}
if (filled >= amount)
{
2014-02-24 13:25:50 +01:00
return filled;
}
2014-01-08 15:18:24 +01:00
}
}
2014-01-25 13:48:06 +01:00
2014-02-24 13:25:50 +01:00
return filled;
2014-02-23 06:39:44 +01:00
}
/**
* Adds new nodes into the map.
*
2014-02-23 06:39:44 +01:00
* @param next
*/
public void addNextFill(ComparableVector next)
{
for (int i = 0; i < 6; i++)
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
Vector3 newPosition = next.position.clone().translate(ForgeDirection.getOrientation(i));
if (!this.navigationMap.containsKey(newPosition) && !(!fillOver && newPosition.intY() > y()))
2014-01-08 15:18:24 +01:00
{
2014-02-23 06:39:44 +01:00
this.navigationMap.put(newPosition, next.position);
this.workingNodes.add(new ComparableVector(newPosition, next.iterations + 1));
2014-01-08 15:18:24 +01:00
}
2014-02-23 06:39:44 +01:00
}
}
2014-01-25 13:48:06 +01:00
2014-02-23 06:39:44 +01:00
public boolean startDrain(Vector3 start)
{
fluidType = null;
this.start = start;
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
for (int i = 0; i < 6; i++)
{
ForgeDirection dir = ForgeDirection.getOrientation(i);
if (dir == TileGrate.this.getDirection())
{
Vector3 check = start.clone().translate(dir);
this.navigationMap.put(check, start);
this.workingNodes.add(new ComparableVector(check, 0));
fluidType = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check);
2014-01-08 15:18:24 +01:00
}
}
2014-01-25 13:25:27 +01:00
2014-02-23 06:39:44 +01:00
return fluidType != null;
2014-01-08 15:18:24 +01:00
}
2014-01-25 13:25:27 +01:00
2014-02-23 06:39:44 +01:00
/**
* Creates a map of all the fluids to be drained.
*
2014-02-23 06:39:44 +01:00
* @param tries
* @return True if there is drainable fluid.
2014-02-23 06:39:44 +01:00
*/
public boolean tryPopulateDrainMap(int tries)
{
for (int i = 0; i < tries; i++)
{
ComparableVector check = workingNodes.poll();
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
if (check == null)
{
2014-02-23 06:39:44 +01:00
return true;
}
2014-01-25 13:25:27 +01:00
2014-02-23 06:39:44 +01:00
Fluid checkFluid = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check.position);
2014-01-25 13:25:27 +01:00
2014-02-23 06:39:44 +01:00
if (checkFluid != null && fluidType.getID() == checkFluid.getID())
{
addNextDrain(check);
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
int checkAmount = FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, check.position);
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
if (checkAmount > 0)
{
drainNodes.add(check);
}
2014-02-23 06:39:44 +01:00
}
}
2014-01-23 15:50:22 +01:00
return drainNodes.size() > 0;
2014-02-23 06:39:44 +01:00
}
public void addNextDrain(ComparableVector next)
{
for (int i = 0; i < 6; i++)
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
Vector3 check = next.position.clone().translate(ForgeDirection.getOrientation(i));
Fluid checkFluid = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check);
if (checkFluid != null && fluidType.getID() == checkFluid.getID())
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
if (!navigationMap.containsKey(check))
{
navigationMap.put(check, next.position);
workingNodes.add(new TileGrate.ComparableVector(check, next.iterations + 1));
}
2014-01-25 13:25:27 +01:00
}
2014-02-23 06:39:44 +01:00
}
}
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
/**
* Tries to drain a specific amount of fluid.
*
2014-02-23 06:39:44 +01:00
* @return - The amount drained.
*/
2014-03-12 15:11:02 +01:00
public FluidStack tryDrain(int targetAmount, boolean doDrain)
2014-02-23 06:39:44 +01:00
{
int drainedAmount = 0;
2014-02-23 06:39:44 +01:00
while (!drainNodes.isEmpty())
{
ComparableVector fluidCoord = drainNodes.peek();
2014-01-08 15:18:24 +01:00
2014-02-23 06:39:44 +01:00
if (!isConnected(fluidCoord.position))
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
TileGrate.this.resetPath();
return new FluidStack(fluidType, drainedAmount);
2014-01-25 13:25:27 +01:00
}
2014-02-23 06:39:44 +01:00
if (FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, fluidCoord.position) == null || this.fluidType.getID() != FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, fluidCoord.position).getID())
2014-01-25 13:25:27 +01:00
{
2014-02-23 06:39:44 +01:00
this.drainNodes.poll();
2014-01-25 13:25:27 +01:00
}
2014-02-23 06:39:44 +01:00
else
2014-01-25 13:25:27 +01:00
{
int checkAmount = FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, fluidCoord.position);
2014-01-25 13:48:06 +01:00
2014-03-12 15:11:02 +01:00
if (drainedAmount + checkAmount > targetAmount)
{
2014-03-12 15:11:02 +01:00
break;
}
2014-03-12 15:11:02 +01:00
if (checkAmount == 0)
2014-02-23 06:39:44 +01:00
{
this.drainNodes.poll();
}
else
{
2014-03-12 15:11:02 +01:00
FluidStack fluidStack = FluidUtility.drainBlock(TileGrate.this.worldObj, fluidCoord.position, doDrain);
2014-01-25 13:48:06 +01:00
this.drainNodes.poll();
if (fluidStack != null)
2014-01-25 13:48:06 +01:00
{
drainedAmount += fluidStack.amount;
2014-03-12 15:11:02 +01:00
if (drainedAmount >= targetAmount)
{
break;
}
2014-01-25 13:48:06 +01:00
}
2014-02-23 06:39:44 +01:00
}
2014-01-25 13:25:27 +01:00
}
}
2014-02-23 06:39:44 +01:00
TileGrate.this.resetPath();
if (drainedAmount > 0)
{
return new FluidStack(fluidType, drainedAmount);
}
2014-02-23 06:39:44 +01:00
return null;
2014-01-25 13:25:27 +01:00
}
2014-01-08 15:18:24 +01:00
}
}