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;
|
package resonantinduction.mechanical.fluid.transport;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.HashMap;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
import net.minecraftforge.common.ForgeDirection;
|
import net.minecraftforge.common.ForgeDirection;
|
||||||
import net.minecraftforge.fluids.Fluid;
|
import net.minecraftforge.fluids.Fluid;
|
||||||
import net.minecraftforge.fluids.FluidContainerRegistry;
|
import net.minecraftforge.fluids.FluidRegistry;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
import net.minecraftforge.fluids.FluidTank;
|
|
||||||
import net.minecraftforge.fluids.FluidTankInfo;
|
import net.minecraftforge.fluids.FluidTankInfo;
|
||||||
import net.minecraftforge.fluids.IFluidHandler;
|
import net.minecraftforge.fluids.IFluidHandler;
|
||||||
import universalelectricity.api.net.IUpdate;
|
|
||||||
import universalelectricity.api.vector.Vector3;
|
import universalelectricity.api.vector.Vector3;
|
||||||
import universalelectricity.core.net.NetworkTickHandler;
|
|
||||||
import calclavia.lib.prefab.tile.TileAdvanced;
|
import calclavia.lib.prefab.tile.TileAdvanced;
|
||||||
import calclavia.lib.utility.FluidUtility;
|
import calclavia.lib.utility.FluidUtility;
|
||||||
|
|
||||||
public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
public class TileGrate extends TileAdvanced implements IFluidHandler
|
||||||
{
|
{
|
||||||
|
private GratePathfinder gratePath;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canUpdate()
|
public boolean canUpdate()
|
||||||
|
@ -64,36 +25,10 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
||||||
return false;
|
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
|
@Override
|
||||||
public ForgeDirection getDirection()
|
public ForgeDirection getDirection()
|
||||||
{
|
{
|
||||||
return ForgeDirection.getOrientation(worldObj.getBlockMetadata(xCoord, yCoord, zCoord));
|
return ForgeDirection.getOrientation(getBlockMetadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -102,96 +37,36 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
||||||
this.worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, direction.ordinal(), 3);
|
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
|
@Override
|
||||||
public int fill(ForgeDirection from, FluidStack resource, boolean doFill)
|
public int fill(ForgeDirection from, FluidStack resource, boolean doFill)
|
||||||
{
|
{
|
||||||
update();
|
if (resource != null && resource.amount > 0)
|
||||||
|
|
||||||
if (resource == null)
|
|
||||||
{
|
{
|
||||||
return 0;
|
if (gratePath == null)
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return 0;
|
gratePath = new GratePathfinder(true);
|
||||||
|
gratePath.startFill(new Vector3(this), resource.fluidID);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Vector3> fluids = new ArrayList<Vector3>();
|
return gratePath.tryFill(resource.amount, 2000);
|
||||||
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 0;
|
return 0;
|
||||||
|
@ -208,103 +83,336 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
|
||||||
@Override
|
@Override
|
||||||
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain)
|
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain)
|
||||||
{
|
{
|
||||||
update();
|
if (maxDrain > 0)
|
||||||
|
|
||||||
FluidStack resultStack = null;
|
|
||||||
|
|
||||||
if (getDrainList() == null || getDrainList().size() == 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();
|
if (checkVertical)
|
||||||
|
|
||||||
while (iterator.hasNext())
|
|
||||||
{
|
{
|
||||||
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();
|
@Override
|
||||||
FluidStack drainStack = FluidUtility.drainBlock(worldObj, drainLocation, false, 3);
|
public int compare(Object a, Object b)
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
int wait = 20;
|
TileGrate.ComparableVector wa = (TileGrate.ComparableVector) a;
|
||||||
|
TileGrate.ComparableVector wb = (TileGrate.ComparableVector) b;
|
||||||
|
|
||||||
@Override
|
return wa.iterations - wb.iterations;
|
||||||
public void update()
|
}
|
||||||
{
|
});
|
||||||
if (--wait <= 0)
|
}
|
||||||
{
|
}
|
||||||
worldObj.notifyBlocksOfNeighborChange(drainLocation.intX(), drainLocation.intY(), drainLocation.intZ(), worldObj.getBlockId(drainLocation.intX(), drainLocation.intY(), drainLocation.intZ()), 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean canUpdate()
|
* Traces back to the start position to see if this fluid position is connected with the
|
||||||
{
|
* starting position through fluid mediums.
|
||||||
return true;
|
*/
|
||||||
}
|
public boolean isConnected(Vector3 check)
|
||||||
|
{
|
||||||
|
if (check.equals(this.start))
|
||||||
|
return true;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
check = this.navigationMap.get(check);
|
||||||
|
|
||||||
@Override
|
if (check == null)
|
||||||
public boolean continueUpdate()
|
return false;
|
||||||
{
|
|
||||||
return wait > 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
currentWorldEdits++;
|
if (check.equals(this.start))
|
||||||
iterator.remove();
|
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 static class ComparableVector implements Comparable
|
||||||
public FluidTankInfo[] getTankInfo(ForgeDirection from)
|
|
||||||
{
|
{
|
||||||
return new FluidTankInfo[] { new FluidTank(this.getDrainFinder().results.size() * FluidContainerRegistry.BUCKET_VOLUME).getInfo() };
|
public Vector3 position;
|
||||||
}
|
public int iterations;
|
||||||
|
|
||||||
@Override
|
public ComparableVector(Vector3 position, int iterations)
|
||||||
public boolean canFill(ForgeDirection from, Fluid fluid)
|
{
|
||||||
{
|
this.position = position;
|
||||||
return getDirection() != from;
|
this.iterations = iterations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int compareTo(Object obj)
|
||||||
public boolean canDrain(ForgeDirection from, Fluid fluid)
|
{
|
||||||
{
|
ComparableVector wr = (ComparableVector) obj;
|
||||||
return getDirection() != from;
|
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