Now using brand new grate algorithm
This commit is contained in:
parent
ff84c867b0
commit
d6d028df70
3 changed files with 338 additions and 614 deletions
|
@ -1,23 +0,0 @@
|
|||
package resonantinduction.mechanical.fluid.transport;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraftforge.fluids.IFluidHandler;
|
||||
import universalelectricity.api.vector.Vector3;
|
||||
import calclavia.lib.prefab.tile.IRotatable;
|
||||
|
||||
/**
|
||||
* Interface to make or use the TileEntityDrain. This is mostly a dummy interface to help the
|
||||
* construction pump use the TileEntity as the center of drain location
|
||||
*
|
||||
* The use of ITankContainer is optional but is need for the drain to be added to a Fluid Network
|
||||
* Same goes for IRotatable but make sure to return direction as the direction the drain faces
|
||||
*/
|
||||
public interface IDrain extends IFluidHandler, IRotatable
|
||||
{
|
||||
/** Gets the list of fillable blocks */
|
||||
public List<Vector3> getFillList();
|
||||
|
||||
/** Gets the list of drainable blocks */
|
||||
public List<Vector3> getDrainList();
|
||||
}
|
|
@ -1,361 +0,0 @@
|
|||
package resonantinduction.mechanical.fluid.transport;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
import universalelectricity.api.vector.Vector3;
|
||||
import calclavia.lib.utility.FluidUtility;
|
||||
|
||||
/**
|
||||
* A simpler path Finder used to find drainable or fillable tiles
|
||||
*
|
||||
* @author DarkGuardsman
|
||||
*/
|
||||
public class LiquidPathFinder
|
||||
{
|
||||
/** Curent world this pathfinder will operate in */
|
||||
private World world;
|
||||
/** List of all nodes traveled by the path finder */
|
||||
public Set<Vector3> nodeList = new HashSet<Vector3>();
|
||||
/** List of all nodes that match the search parms */
|
||||
public Set<Vector3> results = new HashSet<Vector3>();
|
||||
public final List<Vector3> sortedResults = new ArrayList<Vector3>();
|
||||
/** Are we looking for liquid fillable blocks */
|
||||
private boolean fill = false;
|
||||
/** priority search direction either up or down only */
|
||||
private ForgeDirection priority;
|
||||
/** Limit on the searched nodes per run */
|
||||
private int resultLimit = 200;
|
||||
private int resultsFound = 0;
|
||||
private int resultRun = resultLimit;
|
||||
private int runs = 0;
|
||||
/** Start location of the pathfinder used for range calculations */
|
||||
private Vector3 start;
|
||||
/** Range to limit the search to */
|
||||
private double range;
|
||||
/** List of forgeDirection to use that are shuffled to prevent strait lines */
|
||||
List<ForgeDirection> shuffledDirections = new ArrayList<ForgeDirection>();
|
||||
|
||||
public LiquidPathFinder(final World world, final int resultLimit, final double range)
|
||||
{
|
||||
this.range = range;
|
||||
this.world = world;
|
||||
if (fill)
|
||||
{
|
||||
priority = ForgeDirection.DOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = ForgeDirection.UP;
|
||||
}
|
||||
this.resultLimit = resultLimit;
|
||||
this.reset();
|
||||
shuffledDirections.add(ForgeDirection.EAST);
|
||||
shuffledDirections.add(ForgeDirection.WEST);
|
||||
shuffledDirections.add(ForgeDirection.NORTH);
|
||||
shuffledDirections.add(ForgeDirection.SOUTH);
|
||||
}
|
||||
|
||||
public void addNode(Vector3 vec)
|
||||
{
|
||||
if (!this.nodeList.contains(vec))
|
||||
{
|
||||
this.nodeList.add(vec);
|
||||
}
|
||||
}
|
||||
|
||||
public void addResult(Vector3 vec)
|
||||
{
|
||||
if (!this.results.contains(vec))
|
||||
{
|
||||
this.resultsFound++;
|
||||
this.results.add(vec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for nodes attached to the given node
|
||||
*
|
||||
* @return True on success finding, false on failure.
|
||||
*/
|
||||
public boolean findNodes(Vector3 node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
this.addNode(node);
|
||||
|
||||
if (this.isValidResult(node))
|
||||
{
|
||||
this.addResult(node);
|
||||
}
|
||||
|
||||
if (this.isDone(node.clone()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (find(this.priority, node.clone()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Collections.shuffle(shuffledDirections);
|
||||
Collections.shuffle(shuffledDirections);
|
||||
|
||||
for (ForgeDirection direction : shuffledDirections)
|
||||
{
|
||||
if (find(direction, node.clone()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (find(this.priority.getOpposite(), node.clone()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all node attached to the origin mode in the given direction
|
||||
*
|
||||
* Note: Calls findNode if the next code is valid
|
||||
*/
|
||||
public boolean find(ForgeDirection direction, Vector3 origin)
|
||||
{
|
||||
this.runs++;
|
||||
Vector3 vec = origin.clone().translate(direction);
|
||||
double distance = vec.toVector2().distance(this.start.toVector2());
|
||||
|
||||
if (distance <= this.range && isValidNode(vec))
|
||||
{
|
||||
if (this.fill && FluidUtility.drainBlock(world, vec, false) != null || FluidUtility.isFillableFluid(world, vec))
|
||||
{
|
||||
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
|
||||
{
|
||||
Vector3 veb = vec.clone().translate(dir);
|
||||
if (FluidUtility.isFillableBlock(world, veb))
|
||||
{
|
||||
this.addNode(veb);
|
||||
if (this.isValidResult(veb))
|
||||
{
|
||||
this.addResult(veb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.findNodes(vec))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Checks to see if this node is valid to path find threw */
|
||||
public boolean isValidNode(Vector3 pos)
|
||||
{
|
||||
if (pos == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/* Check if the chunk is loaded to prevent action outside of the loaded area */
|
||||
Chunk chunk = this.world.getChunkFromBlockCoords(pos.intX(), pos.intZ());
|
||||
if (chunk == null || !chunk.isChunkLoaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return FluidUtility.drainBlock(world, pos, false) != null || FluidUtility.isFillableFluid(world, pos);
|
||||
}
|
||||
|
||||
public boolean isValidResult(Vector3 node)
|
||||
{
|
||||
if (this.fill)
|
||||
{
|
||||
return FluidUtility.isFillableBlock(world, node) || FluidUtility.isFillableFluid(world, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FluidUtility.drainBlock(world, node, false) != null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks to see if we are done pathfinding */
|
||||
public boolean isDone(Vector3 vec)
|
||||
{
|
||||
if (this.runs > 1000)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (this.resultsFound >= this.resultRun)
|
||||
if (this.results.size() >= this.resultLimit || this.nodeList.size() >= 10000)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called to execute the pathfinding operation. */
|
||||
public LiquidPathFinder start(final Vector3 startNode, int runCount, final boolean fill)
|
||||
{
|
||||
this.start = startNode;
|
||||
this.fill = fill;
|
||||
this.runs = 0;
|
||||
this.resultsFound = 0;
|
||||
this.resultRun = runCount;
|
||||
this.find(ForgeDirection.UNKNOWN, startNode);
|
||||
|
||||
this.refresh();
|
||||
this.sortBlockList(start, results, fill);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiquidPathFinder reset()
|
||||
{
|
||||
this.nodeList.clear();
|
||||
this.results.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiquidPathFinder refresh()
|
||||
{
|
||||
Iterator<Vector3> it = this.nodeList.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Vector3 vec = it.next();
|
||||
if (!this.isValidNode(vec))
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
if (this.isValidResult(vec))
|
||||
{
|
||||
this.addResult(vec);
|
||||
}
|
||||
}
|
||||
it = this.results.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Vector3 vec = it.next();
|
||||
if (!this.isValidResult(vec))
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
if (this.isValidNode(vec))
|
||||
{
|
||||
this.addNode(vec);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to sort a list of vector3 locations using the vector3's distance from one point and
|
||||
* elevation in the y axis
|
||||
*
|
||||
* Sorting is ordered from the highest-furthest block and consequently will have its adjacent
|
||||
* blocks as the "next blocks" to make sure the fluid can easily remove infinite fluids like
|
||||
* water.
|
||||
*
|
||||
* @param start - start location to measure distance from
|
||||
* @param results2 - list of vectors to sort
|
||||
* @param prioritizeHighest - sort highest y value to the top.
|
||||
*
|
||||
* Note: Height takes priority over distance.
|
||||
*/
|
||||
public void sortBlockList(final Vector3 start, final Set<Vector3> set, final boolean prioritizeHighest)
|
||||
{
|
||||
try
|
||||
{
|
||||
sortedResults.clear();
|
||||
sortedResults.addAll(set);
|
||||
|
||||
// The highest and furthest fluid block for drain. Closest fluid block for fill.
|
||||
Vector3 bestFluid = null;
|
||||
|
||||
if (fill)
|
||||
{
|
||||
bestFluid = start;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Vector3 checkPos : set)
|
||||
{
|
||||
if (bestFluid == null)
|
||||
{
|
||||
bestFluid = checkPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're draining, so we want the highest furthest block first.
|
||||
*/
|
||||
if (prioritizeHighest)
|
||||
{
|
||||
if (checkPos.y > bestFluid.y)
|
||||
{
|
||||
bestFluid = checkPos;
|
||||
}
|
||||
else if (checkPos.y == bestFluid.y && start.distance(checkPos) > start.distance(bestFluid))
|
||||
{
|
||||
bestFluid = checkPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* We're filling, so prioritize the lowest block first.
|
||||
*/
|
||||
if (checkPos.y < bestFluid.y)
|
||||
{
|
||||
bestFluid = checkPos;
|
||||
}
|
||||
else if (start.distance(checkPos) > start.distance(bestFluid))
|
||||
{
|
||||
bestFluid = checkPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Vector3 optimalFluid = bestFluid;
|
||||
Collections.sort(sortedResults, new Comparator<Vector3>()
|
||||
{
|
||||
@Override
|
||||
public int compare(Vector3 vecA, Vector3 vecB)
|
||||
{
|
||||
if (vecA.equals(vecB))
|
||||
return 0;
|
||||
|
||||
return vecA.distance(optimalFluid) < vecB.distance(optimalFluid) ? -1 : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public LiquidPathFinder setWorld(World world2)
|
||||
{
|
||||
if (world2 != this.world)
|
||||
{
|
||||
this.reset();
|
||||
this.world = world2;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,62 +1,23 @@
|
|||
package resonantinduction.mechanical.fluid.transport;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidTank;
|
||||
import net.minecraftforge.fluids.FluidTankInfo;
|
||||
import net.minecraftforge.fluids.IFluidHandler;
|
||||
import universalelectricity.api.net.IUpdate;
|
||||
import universalelectricity.api.vector.Vector3;
|
||||
import universalelectricity.core.net.NetworkTickHandler;
|
||||
import calclavia.lib.prefab.tile.TileAdvanced;
|
||||
import calclavia.lib.utility.FluidUtility;
|
||||
|
||||
public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
||||
public class TileGrate extends TileAdvanced implements IFluidHandler
|
||||
{
|
||||
|
||||
public static final int MAX_FLUID_MODIFY_RATE = 50;
|
||||
|
||||
private long lastUseTime = 0;
|
||||
private int currentWorldEdits = 0;
|
||||
|
||||
private LiquidPathFinder pathDrain;
|
||||
private LiquidPathFinder pathFill;
|
||||
|
||||
public LiquidPathFinder getFillFinder()
|
||||
{
|
||||
if (pathFill == null)
|
||||
{
|
||||
pathFill = new LiquidPathFinder(this.worldObj, 100, 100);
|
||||
}
|
||||
return pathFill;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vector3> getFillList()
|
||||
{
|
||||
return this.getFillFinder().refresh().sortedResults;
|
||||
}
|
||||
|
||||
public LiquidPathFinder getDrainFinder()
|
||||
{
|
||||
if (pathDrain == null)
|
||||
{
|
||||
pathDrain = new LiquidPathFinder(this.worldObj, 1000, 100);
|
||||
}
|
||||
return pathDrain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vector3> getDrainList()
|
||||
{
|
||||
return getDrainFinder().refresh().sortedResults;
|
||||
}
|
||||
private GratePathfinder gratePath;
|
||||
|
||||
@Override
|
||||
public boolean canUpdate()
|
||||
|
@ -64,36 +25,10 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
|||
return false;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
if (System.currentTimeMillis() - lastUseTime > 1000)
|
||||
{
|
||||
currentWorldEdits = 0;
|
||||
lastUseTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the pathfinding operation.
|
||||
*/
|
||||
public void doPathfinding()
|
||||
{
|
||||
if (this.getDrainFinder().results.size() < TileGrate.MAX_FLUID_MODIFY_RATE + 10)
|
||||
{
|
||||
this.getDrainFinder().refresh().start(new Vector3(this).translate(this.getDirection()), TileGrate.MAX_FLUID_MODIFY_RATE, false);
|
||||
}
|
||||
|
||||
if (this.getFillFinder().results.size() < TileGrate.MAX_FLUID_MODIFY_RATE + 10)
|
||||
{
|
||||
this.getFillFinder().refresh().start(new Vector3(this).translate(this.getDirection()), TileGrate.MAX_FLUID_MODIFY_RATE, true);
|
||||
getFillFinder().results.add(new Vector3(this).translate(this.getDirection()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForgeDirection getDirection()
|
||||
{
|
||||
return ForgeDirection.getOrientation(worldObj.getBlockMetadata(xCoord, yCoord, zCoord));
|
||||
return ForgeDirection.getOrientation(getBlockMetadata());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,96 +37,36 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
|||
this.worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, direction.ordinal(), 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidTankInfo[] getTankInfo(ForgeDirection from)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canFill(ForgeDirection from, Fluid fluid)
|
||||
{
|
||||
return getDirection() != from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDrain(ForgeDirection from, Fluid fluid)
|
||||
{
|
||||
return getDirection() != from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(ForgeDirection from, FluidStack resource, boolean doFill)
|
||||
{
|
||||
update();
|
||||
|
||||
if (resource == null)
|
||||
if (resource != null && resource.amount > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (currentWorldEdits < MAX_FLUID_MODIFY_RATE)
|
||||
{
|
||||
int remainingVolume = resource.amount;
|
||||
|
||||
/* ID LIQUID BLOCK AND SET VARS FOR BLOCK PLACEMENT */
|
||||
if (resource == null || resource.amount < FluidContainerRegistry.BUCKET_VOLUME)
|
||||
if (gratePath == null)
|
||||
{
|
||||
return 0;
|
||||
gratePath = new GratePathfinder(true);
|
||||
gratePath.startFill(new Vector3(this), resource.fluidID);
|
||||
}
|
||||
|
||||
List<Vector3> fluids = new ArrayList<Vector3>();
|
||||
List<Vector3> blocks = new ArrayList<Vector3>();
|
||||
List<Vector3> filled = new ArrayList<Vector3>();
|
||||
|
||||
if (getFillList() == null || getFillList().size() == 0)
|
||||
{
|
||||
doPathfinding();
|
||||
}
|
||||
|
||||
/* Sort results out into two groups and clear the rest out of the result list */
|
||||
Iterator<Vector3> it = getFillList().iterator();
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
Vector3 vec = it.next();
|
||||
if (FluidUtility.isFillableFluid(worldObj, vec) && !fluids.contains(vec) && !blocks.contains(vec))
|
||||
{
|
||||
fluids.add(vec);
|
||||
}
|
||||
else if (FluidUtility.isFillableBlock(worldObj, vec) && !blocks.contains(vec) && !fluids.contains(vec))
|
||||
{
|
||||
blocks.add(vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill non-full fluids first */
|
||||
for (Vector3 loc : fluids)
|
||||
{
|
||||
if (remainingVolume <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (FluidUtility.isFillableFluid(worldObj, loc))
|
||||
{
|
||||
remainingVolume -= FluidUtility.fillBlock(worldObj, loc, FluidUtility.getStack(resource, remainingVolume), doFill);
|
||||
|
||||
if (doFill)
|
||||
{
|
||||
filled.add(loc);
|
||||
currentWorldEdits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill air or replaceable blocks after non-full fluids */
|
||||
for (Vector3 loc : blocks)
|
||||
{
|
||||
if (remainingVolume <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (FluidUtility.isFillableBlock(worldObj, loc))
|
||||
{
|
||||
remainingVolume -= FluidUtility.fillBlock(worldObj, loc, FluidUtility.getStack(resource, remainingVolume), doFill);
|
||||
|
||||
if (doFill)
|
||||
{
|
||||
filled.add(loc);
|
||||
currentWorldEdits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.getDrainFinder().results.removeAll(filled);
|
||||
return Math.max(resource.amount - remainingVolume, 0);
|
||||
return gratePath.tryFill(resource.amount, 2000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -208,103 +83,336 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
|||
@Override
|
||||
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain)
|
||||
{
|
||||
update();
|
||||
|
||||
FluidStack resultStack = null;
|
||||
|
||||
if (getDrainList() == null || getDrainList().size() == 0)
|
||||
if (maxDrain > 0)
|
||||
{
|
||||
doPathfinding();
|
||||
if (gratePath == null)
|
||||
{
|
||||
gratePath = new GratePathfinder(false);
|
||||
|
||||
if (!gratePath.startDrain(new Vector3(this)))
|
||||
{
|
||||
resetPath();
|
||||
}
|
||||
}
|
||||
|
||||
if (gratePath != null && gratePath.tryPopulateDrainMap(500))
|
||||
{
|
||||
return gratePath.tryDrain(maxDrain, doDrain);
|
||||
}
|
||||
}
|
||||
|
||||
List<Vector3> drainList = getDrainList();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (drainList != null && drainList.size() > 0)
|
||||
/**
|
||||
* Pathfinding operations
|
||||
*
|
||||
* @author Calclavia
|
||||
*/
|
||||
public void resetPath()
|
||||
{
|
||||
this.gratePath = null;
|
||||
}
|
||||
|
||||
public class GratePathfinder
|
||||
{
|
||||
/**
|
||||
* 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());
|
||||
|
||||
/**
|
||||
* The type of fluid we're dealing with. When draining, this will be the type of fluid being
|
||||
* drained.
|
||||
*/
|
||||
public Fluid fluidType;
|
||||
|
||||
public GratePathfinder(boolean checkVertical)
|
||||
{
|
||||
Iterator<Vector3> iterator = drainList.iterator();
|
||||
|
||||
while (iterator.hasNext())
|
||||
if (checkVertical)
|
||||
{
|
||||
if (currentWorldEdits >= MAX_FLUID_MODIFY_RATE)
|
||||
this.workingNodes = new PriorityQueue<ComparableVector>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.workingNodes = new PriorityQueue<ComparableVector>(1024, new Comparator()
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
final Vector3 drainLocation = iterator.next();
|
||||
FluidStack drainStack = FluidUtility.drainBlock(worldObj, drainLocation, false, 3);
|
||||
|
||||
if (resultStack == null)
|
||||
{
|
||||
drainStack = FluidUtility.drainBlock(worldObj, drainLocation, doDrain, 2);
|
||||
resultStack = drainStack;
|
||||
}
|
||||
else if (resultStack.equals(drainStack))
|
||||
{
|
||||
drainStack = FluidUtility.drainBlock(worldObj, drainLocation, doDrain, 2);
|
||||
resultStack.amount += drainStack.amount;
|
||||
}
|
||||
|
||||
if (doDrain)
|
||||
{
|
||||
/**
|
||||
* Add a delayed notify event to prevent infinite fluids from reconstructing
|
||||
* quickly.
|
||||
*/
|
||||
NetworkTickHandler.addNetwork(new IUpdate()
|
||||
@Override
|
||||
public int compare(Object a, Object b)
|
||||
{
|
||||
int wait = 20;
|
||||
TileGrate.ComparableVector wa = (TileGrate.ComparableVector) a;
|
||||
TileGrate.ComparableVector wb = (TileGrate.ComparableVector) b;
|
||||
|
||||
@Override
|
||||
public void update()
|
||||
{
|
||||
if (--wait <= 0)
|
||||
{
|
||||
worldObj.notifyBlocksOfNeighborChange(drainLocation.intX(), drainLocation.intY(), drainLocation.intZ(), worldObj.getBlockId(drainLocation.intX(), drainLocation.intY(), drainLocation.intZ()), 20);
|
||||
}
|
||||
}
|
||||
return wa.iterations - wb.iterations;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUpdate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* 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))
|
||||
return true;
|
||||
do
|
||||
{
|
||||
check = this.navigationMap.get(check);
|
||||
|
||||
@Override
|
||||
public boolean continueUpdate()
|
||||
{
|
||||
return wait > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (check == null)
|
||||
return false;
|
||||
|
||||
currentWorldEdits++;
|
||||
iterator.remove();
|
||||
if (check.equals(this.start))
|
||||
return true;
|
||||
}
|
||||
while (FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check) != null && fluidType.getID() == FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check).getID());
|
||||
|
||||
if (resultStack != null && resultStack.amount >= maxDrain)
|
||||
return false;
|
||||
}
|
||||
|
||||
public void startFill(Vector3 start, int fluidID)
|
||||
{
|
||||
this.fluidType = FluidRegistry.getFluid(fluidID);
|
||||
this.start = start;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
ForgeDirection dir = ForgeDirection.getOrientation(i);
|
||||
|
||||
if (dir == TileGrate.this.getDirection())
|
||||
{
|
||||
break;
|
||||
Vector3 check = start.clone().translate(dir);
|
||||
this.navigationMap.put(check, start);
|
||||
this.workingNodes.add(new TileGrate.ComparableVector(check, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultStack;
|
||||
/**
|
||||
* Tries to fill.
|
||||
*
|
||||
* @param amount
|
||||
* @param tries
|
||||
* @return Amount filled.
|
||||
*/
|
||||
public int tryFill(int amount, int tries)
|
||||
{
|
||||
for (int i = 0; i < tries; i++)
|
||||
{
|
||||
ComparableVector next = this.workingNodes.poll();
|
||||
|
||||
if (next == null)
|
||||
{
|
||||
TileGrate.this.resetPath();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!isConnected(next.position))
|
||||
{
|
||||
TileGrate.this.resetPath();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filled = FluidUtility.fillBlock(TileGrate.this.worldObj, next.position, new FluidStack(fluidType, amount), true);
|
||||
amount -= filled;
|
||||
|
||||
if (filled > 0)
|
||||
{
|
||||
addNextFill(next);
|
||||
return filled;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new nodes into the map.
|
||||
*
|
||||
* @param next
|
||||
*/
|
||||
public void addNextFill(ComparableVector next)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
Vector3 newPosition = next.position.clone().translate(ForgeDirection.getOrientation(i));
|
||||
|
||||
if (!this.navigationMap.containsKey(newPosition))
|
||||
{
|
||||
this.navigationMap.put(newPosition, next.position);
|
||||
this.workingNodes.add(new ComparableVector(newPosition, next.iterations + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startDrain(Vector3 start)
|
||||
{
|
||||
fluidType = null;
|
||||
this.start = start;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return fluidType != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a map of all the fluids.
|
||||
*
|
||||
* @param tries
|
||||
* @return
|
||||
*/
|
||||
public boolean tryPopulateDrainMap(int tries)
|
||||
{
|
||||
if (drainNodes.size() >= Integer.MAX_VALUE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tries; i++)
|
||||
{
|
||||
ComparableVector check = workingNodes.poll();
|
||||
|
||||
if (check == null)
|
||||
return true;
|
||||
|
||||
Fluid checkFluid = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check.position);
|
||||
|
||||
if (checkFluid != null && fluidType.getID() == checkFluid.getID())
|
||||
{
|
||||
addNextDrain(check);
|
||||
|
||||
int checkAmount = FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, check.position);
|
||||
|
||||
if (checkAmount > 0)
|
||||
this.drainNodes.add(check);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addNextDrain(ComparableVector next)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
Vector3 check = next.position.clone().translate(ForgeDirection.getOrientation(i));
|
||||
Fluid checkFluid = FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, check);
|
||||
|
||||
if (checkFluid != null && fluidType.getID() == checkFluid.getID())
|
||||
{
|
||||
if (!navigationMap.containsKey(check))
|
||||
{
|
||||
navigationMap.put(check, next.position);
|
||||
workingNodes.add(new TileGrate.ComparableVector(check, next.iterations + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to drain a specific amount of fluid.
|
||||
*
|
||||
* @return - The amount drained.
|
||||
*/
|
||||
public FluidStack tryDrain(int amount, boolean doDrain)
|
||||
{
|
||||
int tryAmount = 0;
|
||||
|
||||
while (!drainNodes.isEmpty())
|
||||
{
|
||||
ComparableVector fluidCoord = drainNodes.peek();
|
||||
|
||||
if (!isConnected(fluidCoord.position))
|
||||
{
|
||||
TileGrate.this.resetPath();
|
||||
return new FluidStack(fluidType, tryAmount);
|
||||
}
|
||||
|
||||
if (!this.fluidType.equals(FluidUtility.getFluidFromBlock(TileGrate.this.worldObj, fluidCoord.position)))
|
||||
{
|
||||
this.drainNodes.poll();
|
||||
}
|
||||
else
|
||||
{
|
||||
int amount1 = FluidUtility.getFluidAmountFromBlock(TileGrate.this.worldObj, fluidCoord.position);
|
||||
|
||||
if (amount1 == 0)
|
||||
{
|
||||
this.drainNodes.poll();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tryAmount + amount1 <= amount)
|
||||
{
|
||||
tryAmount += amount1;
|
||||
fluidCoord.position.setBlock(TileGrate.this.worldObj, 0);
|
||||
this.drainNodes.poll();
|
||||
if (tryAmount == amount)
|
||||
return new FluidStack(fluidType, amount);
|
||||
}
|
||||
|
||||
FluidStack fluidStack = FluidUtility.drainBlock(TileGrate.this.worldObj, fluidCoord.position, doDrain, 3);
|
||||
|
||||
if (fluidStack != null && fluidStack.amount > 0)
|
||||
{
|
||||
return new FluidStack(fluidType, fluidStack.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TileGrate.this.resetPath();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidTankInfo[] getTankInfo(ForgeDirection from)
|
||||
public static class ComparableVector implements Comparable
|
||||
{
|
||||
return new FluidTankInfo[] { new FluidTank(this.getDrainFinder().results.size() * FluidContainerRegistry.BUCKET_VOLUME).getInfo() };
|
||||
}
|
||||
public Vector3 position;
|
||||
public int iterations;
|
||||
|
||||
@Override
|
||||
public boolean canFill(ForgeDirection from, Fluid fluid)
|
||||
{
|
||||
return getDirection() != from;
|
||||
}
|
||||
public ComparableVector(Vector3 position, int iterations)
|
||||
{
|
||||
this.position = position;
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDrain(ForgeDirection from, Fluid fluid)
|
||||
{
|
||||
return getDirection() != from;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue