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;
import java.util.List;
import java.util.Set;
import net.minecraftforge.common.ForgeDirection;
@ -17,8 +18,8 @@ import calclavia.lib.prefab.tile.IRotatable;
public interface IDrain extends IFluidHandler, IRotatable
{
/** Gets the list of fillable blocks */
public Set<Vector3> getFillList();
public List<Vector3> getFillList();
/** 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.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import net.minecraft.tileentity.TileEntity;
@ -36,8 +37,11 @@ public class PipeNetwork extends FluidNetwork
FluidStack stack = this.getTank().getFluid().copy();
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();
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);
}
if (sideCount > 1)
--sideCount;
if (volPer <= 0)

View file

@ -28,6 +28,7 @@ public class LiquidPathFinder
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 */
@ -143,15 +144,16 @@ public class LiquidPathFinder
public boolean find(ForgeDirection direction, Vector3 origin)
{
this.runs++;
Vector3 vec = origin.clone().modifyPositionFromSide(direction);
Vector3 vec = origin.clone().translate(direction);
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))
{
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
{
Vector3 veb = vec.clone().modifyPositionFromSide(dir);
Vector3 veb = vec.clone().translate(dir);
if (FluidUtility.isFillableBlock(world, veb))
{
this.addNode(veb);
@ -162,6 +164,7 @@ public class LiquidPathFinder
}
}
}
if (this.findNodes(vec))
{
return true;
@ -183,6 +186,7 @@ public class LiquidPathFinder
{
return false;
}
return FluidUtility.drainBlock(world, pos, false) != null || FluidUtility.isFillableFluid(world, pos);
}
@ -224,7 +228,7 @@ public class LiquidPathFinder
this.find(ForgeDirection.UNKNOWN, startNode);
this.refresh();
this.sortBlockList(Start, results, !fill, fill);
this.sortBlockList(Start, results, fill);
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
* 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 closest - sort closest distance to the top
* @param highest - sort highest y value to the top.
* @param prioritizeHighest - 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
{
List<Vector3> list = new ArrayList<Vector3>();
list.addAll(set);
Collections.sort(list, new Comparator<Vector3>()
sortedResults.clear();
sortedResults.addAll(set);
// 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
public int compare(Vector3 vecA, Vector3 vecB)
{
// Though unlikely always return zero for equal vectors
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);
return Double.compare(vecA.distance(optimalFluid), vecB.distance(optimalFluid));
}
});
set.clear();
set.addAll(list);
Collections.reverse(sortedResults);
}
catch (Exception e)
{

View file

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