Optimized drain algorithm to be based off distance

This commit is contained in:
Calclavia 2014-01-25 21:39:15 +08:00
parent 11b8227fea
commit d91fdcf8fe
4 changed files with 94 additions and 61 deletions

View file

@ -1,5 +1,6 @@
package resonantinduction.api.fluid; package resonantinduction.api.fluid;
import java.util.List;
import java.util.Set; import java.util.Set;
import net.minecraftforge.common.ForgeDirection; import net.minecraftforge.common.ForgeDirection;
@ -17,8 +18,8 @@ import calclavia.lib.prefab.tile.IRotatable;
public interface IDrain extends IFluidHandler, IRotatable public interface IDrain extends IFluidHandler, IRotatable
{ {
/** Gets the list of fillable blocks */ /** Gets the list of fillable blocks */
public Set<Vector3> getFillList(); public List<Vector3> getFillList();
/** Gets the list of drainable blocks */ /** Gets the list of drainable blocks */
public Set<Vector3> getDrainList(); public List<Vector3> getDrainList();
} }

View file

@ -2,6 +2,7 @@ package resonantinduction.mechanical.fluid.network;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
@ -36,8 +37,11 @@ public class PipeNetwork extends FluidNetwork
FluidStack stack = this.getTank().getFluid().copy(); FluidStack stack = this.getTank().getFluid().copy();
int count = this.sideMap.size(); int count = this.sideMap.size();
for (Entry<IFluidHandler, EnumSet<ForgeDirection>> entry : this.sideMap.entrySet()) Iterator<Entry<IFluidHandler, EnumSet<ForgeDirection>>> it = new HashMap<IFluidHandler, EnumSet<ForgeDirection>>(sideMap).entrySet().iterator();
while (it.hasNext())
{ {
Entry<IFluidHandler, EnumSet<ForgeDirection>> entry = it.next();
int sideCount = entry.getValue().size(); int sideCount = entry.getValue().size();
for (ForgeDirection dir : entry.getValue()) for (ForgeDirection dir : entry.getValue())
@ -54,7 +58,7 @@ public class PipeNetwork extends FluidNetwork
{ {
stack.amount -= handler.fill(dir, FluidUtility.getStack(stack, Math.min(volPerSide, this.maxFlowRate)), true); stack.amount -= handler.fill(dir, FluidUtility.getStack(stack, Math.min(volPerSide, this.maxFlowRate)), true);
} }
if (sideCount > 1) if (sideCount > 1)
--sideCount; --sideCount;
if (volPer <= 0) if (volPer <= 0)

View file

@ -28,6 +28,7 @@ public class LiquidPathFinder
public Set<Vector3> nodeList = new HashSet<Vector3>(); public Set<Vector3> nodeList = new HashSet<Vector3>();
/** List of all nodes that match the search parms */ /** List of all nodes that match the search parms */
public Set<Vector3> results = new HashSet<Vector3>(); public Set<Vector3> results = new HashSet<Vector3>();
public final List<Vector3> sortedResults = new ArrayList<Vector3>();
/** Are we looking for liquid fillable blocks */ /** Are we looking for liquid fillable blocks */
private boolean fill = false; private boolean fill = false;
/** priority search direction either up or down only */ /** priority search direction either up or down only */
@ -143,15 +144,16 @@ public class LiquidPathFinder
public boolean find(ForgeDirection direction, Vector3 origin) public boolean find(ForgeDirection direction, Vector3 origin)
{ {
this.runs++; this.runs++;
Vector3 vec = origin.clone().modifyPositionFromSide(direction); Vector3 vec = origin.clone().translate(direction);
double distance = vec.toVector2().distance(this.Start.toVector2()); double distance = vec.toVector2().distance(this.Start.toVector2());
if (distance <= this.range && this.isValidNode(vec))
if (distance <= this.range && isValidNode(vec))
{ {
if (this.fill && FluidUtility.drainBlock(world, vec, false) != null || FluidUtility.isFillableFluid(world, vec)) if (this.fill && FluidUtility.drainBlock(world, vec, false) != null || FluidUtility.isFillableFluid(world, vec))
{ {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
{ {
Vector3 veb = vec.clone().modifyPositionFromSide(dir); Vector3 veb = vec.clone().translate(dir);
if (FluidUtility.isFillableBlock(world, veb)) if (FluidUtility.isFillableBlock(world, veb))
{ {
this.addNode(veb); this.addNode(veb);
@ -162,6 +164,7 @@ public class LiquidPathFinder
} }
} }
} }
if (this.findNodes(vec)) if (this.findNodes(vec))
{ {
return true; return true;
@ -183,6 +186,7 @@ public class LiquidPathFinder
{ {
return false; return false;
} }
return FluidUtility.drainBlock(world, pos, false) != null || FluidUtility.isFillableFluid(world, pos); return FluidUtility.drainBlock(world, pos, false) != null || FluidUtility.isFillableFluid(world, pos);
} }
@ -224,7 +228,7 @@ public class LiquidPathFinder
this.find(ForgeDirection.UNKNOWN, startNode); this.find(ForgeDirection.UNKNOWN, startNode);
this.refresh(); this.refresh();
this.sortBlockList(Start, results, !fill, fill); this.sortBlockList(Start, results, fill);
return this; return this;
} }
@ -270,60 +274,89 @@ public class LiquidPathFinder
* Used to sort a list of vector3 locations using the vector3's distance from one point and * Used to sort a list of vector3 locations using the vector3's distance from one point and
* elevation in the y axis * 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 start - start location to measure distance from
* @param results2 - list of vectors to sort * @param results2 - list of vectors to sort
* @param closest - sort closest distance to the top * @param prioritizeHighest - sort highest y value to the top.
* @param highest - sort highest y value to the top.
* *
* Note: highest takes priority over closest * Note: Height takes priority over distance.
*/ */
public void sortBlockList(final Vector3 start, final Set<Vector3> set, final boolean closest, final boolean highest) public void sortBlockList(final Vector3 start, final Set<Vector3> set, final boolean prioritizeHighest)
{ {
try try
{ {
List<Vector3> list = new ArrayList<Vector3>(); sortedResults.clear();
list.addAll(set); sortedResults.addAll(set);
Collections.sort(list, new Comparator<Vector3>()
// The highest and furthest fluid block for drain. Closest fluid block for fill.
Vector3 bestFluid = null;
for (Vector3 checkPos : set)
{
if (bestFluid == null)
{
bestFluid = checkPos;
}
if (fill)
{
/**
* We're filling, so we want the closest lowest 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 if (start.distance(checkPos) < start.distance(bestFluid))
{
bestFluid = checkPos;
}
}
else
{
/**
* 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 if (start.distance(checkPos) > start.distance(bestFluid))
{
bestFluid = checkPos;
}
}
}
final Vector3 optimalFluid = bestFluid;
Collections.sort(sortedResults, new Comparator<Vector3>()
{ {
@Override @Override
public int compare(Vector3 vecA, Vector3 vecB) public int compare(Vector3 vecA, Vector3 vecB)
{ {
// Though unlikely always return zero for equal vectors return Double.compare(vecA.distance(optimalFluid), vecB.distance(optimalFluid));
if (vecA.equals(vecB))
{
return 0;
}
// Check y value fist as this is the primary search area
if (Integer.compare(vecA.intY(), vecB.intY()) != 0)
{
if (highest)
{
return vecA.intY() > vecB.intY() ? -1 : 1;
}
else
{
return vecA.intY() > vecB.intY() ? 1 : -1;
}
}
// Check distance after that
double distanceA = Vector2.distance(vecA.toVector2(), start.toVector2());
double distanceB = Vector2.distance(vecB.toVector2(), start.toVector2());
if (Double.compare(distanceA, distanceB) != 0)
{
if (closest)
{
return distanceA > distanceB ? 1 : -1;
}
else
{
return distanceA > distanceB ? -1 : 1;
}
}
return Double.compare(distanceA, distanceB);
} }
}); });
set.clear();
set.addAll(list); Collections.reverse(sortedResults);
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -1,14 +1,11 @@
package resonantinduction.mechanical.fluid.pump; package resonantinduction.mechanical.fluid.pump;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
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.FluidContainerRegistry;
@ -23,8 +20,6 @@ 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;
import com.builtbroken.common.Pair;
public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
{ {
public static final int MAX_FLUID_MODIFY_RATE = 50; public static final int MAX_FLUID_MODIFY_RATE = 50;
@ -45,9 +40,9 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
} }
@Override @Override
public Set<Vector3> getFillList() public List<Vector3> getFillList()
{ {
return this.getFillFinder().refresh().results; return this.getFillFinder().refresh().sortedResults;
} }
public LiquidPathFinder getDrainFinder() public LiquidPathFinder getDrainFinder()
@ -60,9 +55,9 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
} }
@Override @Override
public Set<Vector3> getDrainList() public List<Vector3> getDrainList()
{ {
return getDrainFinder().refresh().results; return getDrainFinder().refresh().sortedResults;
} }
@Override @Override
@ -222,7 +217,7 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
doPathfinding(); doPathfinding();
} }
Set<Vector3> drainList = getDrainList(); List<Vector3> drainList = getDrainList();
if (drainList != null && drainList.size() > 0) if (drainList != null && drainList.size() > 0)
{ {
@ -257,7 +252,7 @@ public class TileGrate extends TileAdvanced implements IFluidHandler, IDrain
*/ */
NetworkTickHandler.addNetwork(new IUpdate() NetworkTickHandler.addNetwork(new IUpdate()
{ {
int wait = 60; int wait = 20;
@Override @Override
public void update() public void update()