diff --git a/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/IDrain.java b/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/IDrain.java deleted file mode 100644 index 12f1e61f7..000000000 --- a/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/IDrain.java +++ /dev/null @@ -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 getFillList(); - - /** Gets the list of drainable blocks */ - public List getDrainList(); -} diff --git a/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/LiquidPathFinder.java b/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/LiquidPathFinder.java deleted file mode 100644 index 5a291bdab..000000000 --- a/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/LiquidPathFinder.java +++ /dev/null @@ -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 nodeList = new HashSet(); - /** List of all nodes that match the search parms */ - public Set results = new HashSet(); - public final List sortedResults = new ArrayList(); - /** 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 shuffledDirections = new ArrayList(); - - 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 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 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() - { - @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; - } -} diff --git a/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/TileGrate.java b/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/TileGrate.java index 26f743789..229526711 100644 --- a/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/TileGrate.java +++ b/mechanical/src/main/java/resonantinduction/mechanical/fluid/transport/TileGrate.java @@ -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 getFillList() - { - return this.getFillFinder().refresh().sortedResults; - } - - public LiquidPathFinder getDrainFinder() - { - if (pathDrain == null) - { - pathDrain = new LiquidPathFinder(this.worldObj, 1000, 100); - } - return pathDrain; - } - - @Override - public List 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 fluids = new ArrayList(); - List blocks = new ArrayList(); - List filled = new ArrayList(); - - if (getFillList() == null || getFillList().size() == 0) - { - doPathfinding(); - } - - /* Sort results out into two groups and clear the rest out of the result list */ - Iterator 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 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 navigationMap = new HashMap(); + + /** + * The nodes we're currently working on. + */ + PriorityQueue workingNodes; + + /** + * The list of blocks to drain. + */ + PriorityQueue drainNodes = new PriorityQueue(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 iterator = drainList.iterator(); - - while (iterator.hasNext()) + if (checkVertical) { - if (currentWorldEdits >= MAX_FLUID_MODIFY_RATE) + this.workingNodes = new PriorityQueue(); + } + else + { + this.workingNodes = new PriorityQueue(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(); + } } }