Merged pathfinder into one class

This path finder no longer depends on Calc's PathFinder to function.
however it is derived from his work so he still gets credit.

The new pathfinder works about the same as calc's except instead of
trying to find a path its trying to find all resources along the path. I
still need to improve this to have a dumped down version of A* so that
i'm filling the closest blocks first and draining the furthest block
first.
This commit is contained in:
Rseifert 2013-04-08 13:27:44 -04:00
parent 8bc375b0ee
commit 135e20f453
7 changed files with 137 additions and 304 deletions

View file

@ -31,6 +31,7 @@ public class BlockConstructionPump extends BlockAdvanced
this.setCreativeTab(TabFluidMech.INSTANCE); this.setCreativeTab(TabFluidMech.INSTANCE);
this.setHardness(1f); this.setHardness(1f);
this.setResistance(5f); this.setResistance(5f);
} }
@Override @Override
@ -117,4 +118,6 @@ public class BlockConstructionPump extends BlockAdvanced
} }
return this.onUseWrench(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ); return this.onUseWrench(world, x, y, z, entityPlayer, side, hitX, hitY, hitZ);
} }
} }

View file

@ -1,10 +1,6 @@
package fluidmech.common.pump; package fluidmech.common.pump;
import fluidmech.common.FluidMech; import fluidmech.common.pump.path.LiquidPathFinder;
import fluidmech.common.pump.path.PathfinderCheckerFindFillable;
import fluidmech.common.pump.path.PathfinderCheckerLiquid;
import fluidmech.common.pump.path.PathfinderFindHighestSource;
import fluidmech.common.pump.path.PathfinderFindPathThrewWater;
import hydraulic.api.IDrain; import hydraulic.api.IDrain;
import hydraulic.fluidnetwork.IFluidNetworkPart; import hydraulic.fluidnetwork.IFluidNetworkPart;
import hydraulic.helpers.FluidHelper; import hydraulic.helpers.FluidHelper;
@ -15,10 +11,8 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Random;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection; import net.minecraftforge.common.ForgeDirection;
@ -26,7 +20,6 @@ import net.minecraftforge.liquids.ILiquid;
import net.minecraftforge.liquids.ILiquidTank; import net.minecraftforge.liquids.ILiquidTank;
import net.minecraftforge.liquids.ITankContainer; import net.minecraftforge.liquids.ITankContainer;
import net.minecraftforge.liquids.LiquidContainerRegistry; import net.minecraftforge.liquids.LiquidContainerRegistry;
import net.minecraftforge.liquids.LiquidDictionary;
import net.minecraftforge.liquids.LiquidStack; import net.minecraftforge.liquids.LiquidStack;
import universalelectricity.core.vector.Vector3; import universalelectricity.core.vector.Vector3;
import universalelectricity.core.vector.VectorHelper; import universalelectricity.core.vector.VectorHelper;
@ -36,7 +29,7 @@ public class TileEntityDrain extends TileEntityFluidDevice implements ITankConta
/* MAX BLOCKS DRAINED PER 1/2 SECOND */ /* MAX BLOCKS DRAINED PER 1/2 SECOND */
public static int MAX_WORLD_EDITS_PER_PROCESS = 30; public static int MAX_WORLD_EDITS_PER_PROCESS = 30;
private int currentWorldEdits = 0; private int currentWorldEdits = 0;
public int yFillStart = 0;
/* LIST OF PUMPS AND THERE REQUESTS FOR THIS DRAIN */ /* LIST OF PUMPS AND THERE REQUESTS FOR THIS DRAIN */
private HashMap<TileEntityConstructionPump, LiquidStack> requestMap = new HashMap<TileEntityConstructionPump, LiquidStack>(); private HashMap<TileEntityConstructionPump, LiquidStack> requestMap = new HashMap<TileEntityConstructionPump, LiquidStack>();
@ -156,8 +149,16 @@ public class TileEntityDrain extends TileEntityFluidDevice implements ITankConta
*/ */
public void getNextFluidBlock() public void getNextFluidBlock()
{ {
PathfinderCheckerLiquid pathFinder = new PathfinderCheckerLiquid(this.worldObj, this); LiquidPathFinder pathFinder = new LiquidPathFinder(this.worldObj, false, this.MAX_WORLD_EDITS_PER_PROCESS * 2);
pathFinder.init(new Vector3(this.xCoord + this.getFacing().offsetX, this.yCoord + this.getFacing().offsetY, this.zCoord + this.getFacing().offsetZ)); pathFinder.init(new Vector3(this.xCoord + this.getFacing().offsetX, this.yCoord + this.getFacing().offsetY, this.zCoord + this.getFacing().offsetZ));
for (Vector3 vec : pathFinder.results)
{
if (!this.targetSources.contains(vec))
{
this.targetSources.add(vec);
}
}
} }
public void doCleanup() public void doCleanup()
@ -204,13 +205,8 @@ public class TileEntityDrain extends TileEntityFluidDevice implements ITankConta
public int fillArea(LiquidStack resource, boolean doFill) public int fillArea(LiquidStack resource, boolean doFill)
{ {
int drained = 0; int drained = 0;
/* INIT SET FILL HEIGHT */
if (yFillStart == 0 || yFillStart >= 255)
{
yFillStart = this.yCoord + this.getFacing().offsetY;
}
if (!this.canDrainSources() && this.currentWorldEdits >= MAX_WORLD_EDITS_PER_PROCESS) if (!this.canDrainSources() && this.currentWorldEdits < MAX_WORLD_EDITS_PER_PROCESS)
{ {
/* ID LIQUID BLOCK AND SET VARS FOR BLOCK PLACEMENT */ /* ID LIQUID BLOCK AND SET VARS FOR BLOCK PLACEMENT */
if (resource == null || resource.amount < LiquidContainerRegistry.BUCKET_VOLUME) if (resource == null || resource.amount < LiquidContainerRegistry.BUCKET_VOLUME)
@ -244,12 +240,12 @@ public class TileEntityDrain extends TileEntityFluidDevice implements ITankConta
int blocks = (resource.amount / LiquidContainerRegistry.BUCKET_VOLUME); int blocks = (resource.amount / LiquidContainerRegistry.BUCKET_VOLUME);
/* FIND ALL VALID BLOCKS ON LEVEL OR BELLOW */ /* FIND ALL VALID BLOCKS ON LEVEL OR BELLOW */
PathfinderCheckerFindFillable pathFinder = new PathfinderCheckerFindFillable(this.worldObj); LiquidPathFinder pathFinder = new LiquidPathFinder(this.worldObj, true, this.MAX_WORLD_EDITS_PER_PROCESS * 2);
pathFinder.init(new Vector3(this.xCoord + this.getFacing().offsetX, yFillStart, this.zCoord + this.getFacing().offsetZ)); pathFinder.init(new Vector3(this.xCoord + this.getFacing().offsetX, this.yCoord + this.getFacing().offsetY, this.zCoord + this.getFacing().offsetZ));
/* START FILLING IN OR CHECKING IF CAN FILL AREA */ /* START FILLING IN OR CHECKING IF CAN FILL AREA */
int fillable = 0; int fillable = 0;
for (Vector3 loc : pathFinder.closedSet) for (Vector3 loc : pathFinder.results)
{ {
if (blocks <= 0) if (blocks <= 0)
{ {
@ -274,7 +270,7 @@ public class TileEntityDrain extends TileEntityFluidDevice implements ITankConta
} }
for (Vector3 loc : pathFinder.closedSet) for (Vector3 loc : pathFinder.results)
{ {
if (blocks <= 0) if (blocks <= 0)
{ {
@ -296,21 +292,6 @@ public class TileEntityDrain extends TileEntityFluidDevice implements ITankConta
} }
} }
} }
/* IF NO FILL TARGETS WERE FOUND ON THIS LEVEL INCREASE YFILLSTART */
if (fillable == 0)
{
PathfinderFindPathThrewWater aPath = new PathfinderFindPathThrewWater(this.worldObj, new Vector3(xCoord, yCoord, zCoord));
aPath.init(new Vector3(this.xCoord + this.getFacing().offsetX, this.yCoord + this.getFacing().offsetY, this.zCoord + this.getFacing().offsetZ));
if (aPath.results.size() > 0)
{
this.yFillStart++;
}
else
{
yFillStart = this.yCoord + this.getFacing().offsetY;
}
}
} }
return drained; return drained;
} }

View file

@ -0,0 +1,118 @@
package fluidmech.common.pump.path;
import hydraulic.helpers.FluidHelper;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.liquids.LiquidStack;
import universalelectricity.core.vector.Vector3;
/**
* A simpler pathfinder based on Calclavia's PathFinder from UE api
*/
public class LiquidPathFinder
{
private World world; /* MC WORLD */
public Set<Vector3> nodes; /* LOCATIONs THE PATH FINDER HAS GONE OVER */
public Set<Vector3> results;/* LOCATIONS THAT ARE VALID RESULTS */
private boolean fill; /* ARE WE FILLING THE PATH OR DRAINING THE PATH */
private ForgeDirection priority; /* BASED ON fill -- WHICH DIRECTION WILL THE PATH GO FIRST */
private int resultLimit = 2000;
public LiquidPathFinder(final World world, final boolean fill, int resultLimit)
{
this.world = world;
this.fill = fill;
if (fill)
{
priority = ForgeDirection.DOWN;
}
else
{
priority = ForgeDirection.UP;
}
this.resultLimit = resultLimit;
this.reset();
}
/**
* @return True on success finding, false on failure.
*/
public boolean findNodes(Vector3 currentNode)
{
this.nodes.add(currentNode);
if (this.fill || FluidHelper.isSourceBlock(world, currentNode))
{
this.results.add(currentNode);
}
if (this.isDone(currentNode))
{
return false;
}
Vector3 vec = currentNode.modifyPositionFromSide(this.priority);
if (this.isValidNode(vec) & !this.nodes.contains(vec))
{
if (this.findNodes(vec))
{
return true;
}
}
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS)
{
if (direction != this.priority)
{
vec = currentNode.modifyPositionFromSide(direction);
if (this.isValidNode(vec) & !this.nodes.contains(vec))
{
if (this.findNodes(vec))
{
return true;
}
}
}
}
return false;
}
public boolean isValidNode(Vector3 pos)
{
LiquidStack liquid = FluidHelper.getLiquidFromBlockId(pos.getBlockID(world));
if (this.fill)
{
return (liquid != null || pos.getBlockID(world) == 0) && FluidHelper.getConnectedSources(world, pos) > 0;
}
else
{
return liquid != null;
}
}
public boolean isDone(Vector3 vec)
{
if (this.results.size() >= this.resultLimit || this.nodes.size() >= 10000)
{
return true;
}
return false;
}
/**
* Called to execute the pathfinding operation.
*/
public LiquidPathFinder init(Vector3 startNode)
{
this.findNodes(startNode);
return this;
}
public LiquidPathFinder reset()
{
this.nodes = new HashSet<Vector3>();
this.results = new HashSet<Vector3>();
return this;
}
}

View file

@ -1,73 +0,0 @@
package fluidmech.common.pump.path;
import fluidmech.common.FluidMech;
import fluidmech.common.pump.TileEntityDrain;
import hydraulic.helpers.FluidHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.liquids.LiquidStack;
import universalelectricity.core.path.IPathCallBack;
import universalelectricity.core.path.Pathfinder;
import universalelectricity.core.vector.Vector3;
public class PathfinderCheckerFindFillable extends Pathfinder
{
public List<Vector3> targetList = new ArrayList<Vector3>();
public PathfinderCheckerFindFillable(final World world)
{
super(new IPathCallBack()
{
@Override
public Set<Vector3> getConnectedNodes(Pathfinder finder, Vector3 currentNode)
{
Set<Vector3> neighbors = new HashSet<Vector3>();
int sources = 0;
Vector3 pos = currentNode.clone().modifyPositionFromSide(ForgeDirection.DOWN);
LiquidStack liquid = FluidHelper.getLiquidFromBlockId(pos.getBlockID(world));
/* SEARCH DOWN */
if ((liquid != null || pos.getBlockID(world) == 0) && FluidHelper.getConnectedSources(world, pos) > 0)
{
neighbors.add(pos);
return neighbors;
}
/* SEARCH AROUND - UP SEARCH IS DONE BY THE OBJECT USING THIS PATHFINDER */
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS)
{
if (direction != ForgeDirection.UP && direction != ForgeDirection.DOWN)
{
pos = currentNode.clone().modifyPositionFromSide(direction);
liquid = FluidHelper.getLiquidFromBlockId(pos.getBlockID(world));
if ((liquid != null || pos.getBlockID(world) == 0) && FluidHelper.getConnectedSources(world, pos) > 0)
{
neighbors.add(pos);
}
}
}
return neighbors;
}
@Override
public boolean onSearch(Pathfinder finder, Vector3 node)
{
if (finder.closedSet.size() >= 2000)
{
return true;
}
return false;
}
});
}
}

View file

@ -1,62 +0,0 @@
package fluidmech.common.pump.path;
import fluidmech.common.FluidMech;
import fluidmech.common.pump.TileEntityDrain;
import hydraulic.helpers.FluidHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.liquids.LiquidStack;
import universalelectricity.core.path.IPathCallBack;
import universalelectricity.core.path.Pathfinder;
import universalelectricity.core.vector.Vector3;
public class PathfinderCheckerLiquid extends Pathfinder
{
public List<Vector3> targetList = new ArrayList<Vector3>();
public PathfinderCheckerLiquid(final World world, final TileEntityDrain drain)
{
super(new IPathCallBack()
{
@Override
public Set<Vector3> getConnectedNodes(Pathfinder finder, Vector3 currentNode)
{
Set<Vector3> neighbors = new HashSet<Vector3>();
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS)
{
Vector3 pos = currentNode.clone().modifyPositionFromSide(direction);
if (FluidHelper.isSourceBlock(world, pos))
{
neighbors.add(pos);
}
}
return neighbors;
}
@Override
public boolean onSearch(Pathfinder finder, Vector3 node)
{
if (FluidHelper.isSourceBlock(world, node))
{
drain.addVectorToQue(node);
}
if (finder.closedSet.size() >= 2000)
{
return true;
}
return false;
}
});
}
}

View file

@ -1,73 +0,0 @@
package fluidmech.common.pump.path;
import fluidmech.common.FluidMech;
import hydraulic.helpers.FluidHelper;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.liquids.LiquidStack;
import universalelectricity.core.path.IPathCallBack;
import universalelectricity.core.path.Pathfinder;
import universalelectricity.core.vector.Vector3;
public class PathfinderFindHighestSource extends Pathfinder
{
public static int highestY = 0;
public PathfinderFindHighestSource(final World world, final LiquidStack resource, final Vector3... ignoreList)
{
super(new IPathCallBack()
{
@Override
public Set<Vector3> getConnectedNodes(Pathfinder finder, Vector3 currentNode)
{
Set<Vector3> neighbors = new HashSet<Vector3>();
Vector3 pos = currentNode.clone().modifyPositionFromSide(ForgeDirection.UP);
LiquidStack liquid = FluidHelper.getLiquidFromBlockId(pos.getBlockID(world));
if (pos.getBlockID(world) != 0 && liquid != null && (liquid.equals(resource) || resource == null))
{
neighbors.add(pos);
if (pos.intY() > highestY)
{
highestY = pos.intY();
}
return neighbors;
}
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS)
{
pos = currentNode.clone().modifyPositionFromSide(direction);
liquid = FluidHelper.getLiquidFromBlockId(pos.getBlockID(world));
if (pos.getBlockID(world) != 0 && liquid != null && (liquid.equals(resource) || resource == null))
{
neighbors.add(pos);
if (pos.intY() > highestY)
{
highestY = pos.intY();
}
}
}
return neighbors;
}
@Override
public boolean onSearch(Pathfinder finder, Vector3 node)
{
if (finder.closedSet.size() >= 1000 || highestY >= 255)
{
return true;
}
return false;
}
});
this.highestY = 0;
}
}

View file

@ -1,61 +0,0 @@
package fluidmech.common.pump.path;
import hydraulic.helpers.FluidHelper;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import universalelectricity.core.path.IPathCallBack;
import universalelectricity.core.path.Pathfinder;
import universalelectricity.core.path.PathfinderAStar;
import universalelectricity.core.vector.Vector3;
/**
* Check if a conductor connects with another.
*
* @author Calclavia
*
*/
public class PathfinderFindPathThrewWater extends PathfinderAStar
{
public PathfinderFindPathThrewWater(final World world, final Vector3 goal)
{
super(new IPathCallBack()
{
@Override
public Set<Vector3> getConnectedNodes(Pathfinder finder, Vector3 currentNode)
{
Set<Vector3> neighbors = new HashSet<Vector3>();
for (int i = 0; i < 6; i++)
{
ForgeDirection direction = ForgeDirection.getOrientation(i);
Vector3 position = currentNode.clone().modifyPositionFromSide(direction);
if (FluidHelper.getLiquidFromBlockId(position.getBlockID(world)) != null || (position.getBlockID(world) == 0 && FluidHelper.getConnectedSources(world, position) > 0))
{
neighbors.add(position);
}
}
return neighbors;
}
@Override
public boolean onSearch(Pathfinder finder, Vector3 node)
{
if (node == goal)
{
finder.results.add(node);
return true;
}
return false;
}
}, goal);
}
}