Rewrote tank network in attempt to fix filling issue

This commit is contained in:
Robert S 2014-05-16 12:03:09 -04:00
parent 2a0d5454eb
commit 0e5633fcd0
7 changed files with 360 additions and 345 deletions

View file

@ -1,8 +1,7 @@
package resonantinduction.archaic.fluid.tank; package resonantinduction.archaic.fluid.tank;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.PriorityQueue; import java.util.LinkedList;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
@ -10,118 +9,137 @@ import resonant.lib.utility.FluidUtility;
import resonantinduction.core.fluid.FluidDistributionetwork; import resonantinduction.core.fluid.FluidDistributionetwork;
import resonantinduction.core.fluid.IFluidDistribution; import resonantinduction.core.fluid.IFluidDistribution;
/** /** Network that handles connected tanks
* Network that handles connected tanks
* *
* @author DarkGuardsman * @author DarkGuardsman */
*/
public class TankNetwork extends FluidDistributionetwork public class TankNetwork extends FluidDistributionetwork
{ {
public TankNetwork() public TankNetwork()
{ {
super(); super();
needsUpdate = true; needsUpdate = true;
} }
@Override @Override
public void update() public void update()
{ {
final FluidStack networkTankFluid = getTank().getFluid(); final FluidStack networkTankFluid = getTank().getFluid();
int lowestY = 255, highestY = 0; int lowestY = 255;
int highestY = 0;
int connectorCount = 0;
int totalFluid = networkTankFluid != null ? networkTankFluid.amount : 0;
boolean didChange = false;
if (getConnectors().size() > 0) //If we only have one tank only fill one tank
{ if (getConnectors().size() == 1)
int totalFluid = networkTankFluid != null ? networkTankFluid.amount : 0; {
IFluidDistribution tank = ((IFluidDistribution) getConnectors().toArray()[0]);
tank.getInternalTank().setFluid(networkTankFluid);
tank.onFluidChanged();
}
else if (getConnectors().size() > 0)
{
if (networkTankFluid != null)
{
//If fluid is gaseous fill all tanks equally
if (networkTankFluid.getFluid().isGaseous())
{
connectorCount = this.getConnectors().size();
for (IFluidDistribution connector : this.getConnectors())
{
FluidStack input = networkTankFluid.copy();
input.amount = (totalFluid / connectorCount) + (totalFluid % connectorCount);
connector.getInternalTank().setFluid(null);
totalFluid -= connector.getInternalTank().fill(input, true);
connector.onFluidChanged();
HashMap<Integer, Integer> heightCount = new HashMap<Integer, Integer>(); if (connectorCount > 0)
PriorityQueue<IFluidDistribution> heightPriorityQueue = new PriorityQueue<IFluidDistribution>(1024, new Comparator() connectorCount--;
{ }
@Override }
public int compare(Object a, Object b) else
{ {
if (networkTankFluid != null && networkTankFluid.getFluid().isGaseous()) HashMap<Integer, LinkedList<IFluidDistribution>> heightMap = new HashMap<Integer, LinkedList<IFluidDistribution>>();
return 0;
TileEntity wa = (TileEntity) a; //Build map of all tanks by their y level
TileEntity wb = (TileEntity) b; for (IFluidDistribution connector : this.getConnectors())
return wa.yCoord - wb.yCoord; {
} if (connector instanceof TileEntity)
}); {
LinkedList<IFluidDistribution> list = new LinkedList<IFluidDistribution>();
int yCoord = ((TileEntity) connector).yCoord;
for (IFluidDistribution connector : this.getConnectors()) if (yCoord < lowestY)
{ {
if (connector instanceof TileEntity) lowestY = yCoord;
{ }
int yCoord = ((TileEntity) connector).yCoord;
if (yCoord < lowestY) if (yCoord > highestY)
{ {
lowestY = yCoord; highestY = yCoord;
} }
if (yCoord > highestY) if (heightMap.containsKey(yCoord))
{ {
highestY = yCoord; list = heightMap.get(yCoord);
} }
list.add(connector);
heightMap.put(yCoord, list);
}
}
heightPriorityQueue.add(connector); //Loop threw levels
heightCount.put(yCoord, heightCount.containsKey(yCoord) ? heightCount.get(yCoord) + 1 : 1); for (int yLevel = lowestY; yLevel <= highestY; yLevel++)
} {
} if (heightMap.containsKey(yLevel))
{
connectorCount = heightMap.get(yLevel).size();
boolean didChange = false; if (connectorCount <= 0)
continue;
while (!heightPriorityQueue.isEmpty()) //Loop threw tanks in each level
{ for (IFluidDistribution connector : heightMap.get(yLevel))
IFluidDistribution distributeNode = heightPriorityQueue.poll(); {
int yCoord = ((TileEntity) distributeNode).yCoord; //If tank is empty clear internal and move on
int connectorCount = heightCount.get(yCoord); if (totalFluid <= 0)
{
connector.getInternalTank().setFluid(null);
connector.onFluidChanged();
continue;
}
if (totalFluid <= 0) FluidStack input = networkTankFluid.copy();
{ input.amount = (totalFluid / connectorCount) + (totalFluid % connectorCount);
distributeNode.getInternalTank().setFluid(null); connector.getInternalTank().setFluid(null);
distributeNode.onFluidChanged(); totalFluid -= connector.getInternalTank().fill(input, true);
continue; connector.onFluidChanged();
}
if (connectorCount > 1)
connectorCount--;
int fluidPer = totalFluid / connectorCount; }
int deltaFluidAmount = fluidPer - distributeNode.getInternalTank().getFluidAmount(); }
}
}
}
else
{
//In the cases the tank is empty just clear all tanks
//instead of doing additional logic that is wasting ticks
for (IFluidDistribution connector : this.getConnectors())
{
connector.getInternalTank().setFluid(null);
connector.onFluidChanged();
}
}
needsUpdate = false;
}
}
int current = distributeNode.getInternalTank().getFluidAmount(); @Override
public TankNetwork newInstance()
if (deltaFluidAmount > 0) {
{ return new TankNetwork();
int filled = distributeNode.getInternalTank().fill(FluidUtility.getStack(networkTankFluid, deltaFluidAmount), false); }
distributeNode.getInternalTank().fill(FluidUtility.getStack(networkTankFluid, deltaFluidAmount / 10), true);
totalFluid -= current + filled;
}
else
{
FluidStack drain = distributeNode.getInternalTank().drain(Math.abs(deltaFluidAmount), false);
distributeNode.getInternalTank().drain(Math.abs(deltaFluidAmount / 10), true);
if (drain != null)
totalFluid -= current - drain.amount;
}
if (deltaFluidAmount != 0)
didChange = true;
if (connectorCount > 1)
connectorCount--;
heightCount.put(yCoord, connectorCount);
distributeNode.onFluidChanged();
}
if (!didChange)
needsUpdate = false;
}
}
@Override
public TankNetwork newInstance()
{
return new TankNetwork();
}
} }

View file

@ -45,8 +45,7 @@ public class TileTank extends TileFluidDistribution implements IComparatorInputO
public TileTank() public TileTank()
{ {
super(UniversalElectricity.machine); super(UniversalElectricity.machine, VOLUME * FluidContainerRegistry.BUCKET_VOLUME);
this.getInternalTank().setCapacity(VOLUME * FluidContainerRegistry.BUCKET_VOLUME);
isOpaqueCube = false; isOpaqueCube = false;
normalRender = false; normalRender = false;
itemBlock = ItemBlockTank.class; itemBlock = ItemBlockTank.class;

View file

@ -23,15 +23,17 @@ public class WailaFluidTank implements IWailaDataProvider
if (tile instanceof TileTank) if (tile instanceof TileTank)
{ {
FluidTank tank = ((TileTank) tile).getInternalTank(); FluidTank tank = ((TileTank) tile).getInternalTank();
FluidTank tankNetwork = ((TileTank) tile).getNetwork().getTank();
if (tankNetwork != null && tankNetwork.getFluid() != null)
{
currenttip.add(LanguageUtility.getLocal("info.waila.tank.fluid") + " " + tankNetwork.getFluid().getFluid().getLocalizedName());
currenttip.add(LanguageUtility.getLocal("info.waila.tank.vol") + " " + tankNetwork.getFluidAmount() + " / " + tank.getCapacity());
}
if (tank != null && tank.getFluid() != null) if (tank != null && tank.getFluid() != null)
{ {
currenttip.add(LanguageUtility.getLocal("info.waila.tank.fluid") + " " + tank.getFluid().getFluid().getLocalizedName()); currenttip.add(LanguageUtility.getLocal("info.waila.tank.fluid") + " " + tank.getFluid().getFluid().getLocalizedName());
currenttip.add(LanguageUtility.getLocal("info.waila.tank.vol") + " " + tank.getFluidAmount() + " / " + tank.getCapacity()); currenttip.add(LanguageUtility.getLocal("info.waila.tank.vol") + " " + tank.getFluidAmount() + " / " + tank.getCapacity());
} }
else
{
currenttip.add(LanguageUtility.getLocal("info.waila.tank.empty"));
}
} }
return currenttip; return currenttip;
} }

View file

@ -85,7 +85,6 @@ public abstract class FluidDistributionetwork extends NodeNetwork<FluidDistribut
public int fill(IFluidDistribution source, ForgeDirection from, FluidStack resource, boolean doFill) public int fill(IFluidDistribution source, ForgeDirection from, FluidStack resource, boolean doFill)
{ {
int prev = this.getTank().getFluidAmount();
int fill = this.getTank().fill(resource.copy(), doFill); int fill = this.getTank().fill(resource.copy(), doFill);
needsUpdate = true; needsUpdate = true;
NetworkTickHandler.addNetwork(this); NetworkTickHandler.addNetwork(this);

View file

@ -9,148 +9,144 @@ import net.minecraftforge.fluids.FluidTankInfo;
import resonant.lib.utility.WorldUtility; import resonant.lib.utility.WorldUtility;
import universalelectricity.api.vector.Vector3; import universalelectricity.api.vector.Vector3;
/** /** A prefab class for tiles that use the fluid network.
* A prefab class for tiles that use the fluid network.
* *
* @author DarkGuardsman * @author DarkGuardsman */
*/
public abstract class TileFluidDistribution extends TileFluidNode implements IFluidDistribution public abstract class TileFluidDistribution extends TileFluidNode implements IFluidDistribution
{ {
public TileFluidDistribution(Material material) public TileFluidDistribution(Material material, int tankSize)
{ {
super(material); super(material, tankSize);
} }
protected Object[] connectedBlocks = new Object[6]; protected Object[] connectedBlocks = new Object[6];
/** Network used to link all parts together */ /** Network used to link all parts together */
protected FluidDistributionetwork network; protected FluidDistributionetwork network;
@Override @Override
public void initiate() public void initiate()
{ {
super.initiate(); super.initiate();
refresh(); refresh();
getNetwork().reconstruct(); getNetwork().reconstruct();
} }
@Override @Override
protected void onNeighborChanged() protected void onNeighborChanged()
{ {
refresh(); refresh();
getNetwork().reconstruct(); getNetwork().reconstruct();
} }
@Override @Override
public void invalidate() public void invalidate()
{ {
this.getNetwork().split(this); this.getNetwork().split(this);
super.invalidate(); super.invalidate();
} }
@Override @Override
public int fill(ForgeDirection from, FluidStack resource, boolean doFill) public int fill(ForgeDirection from, FluidStack resource, boolean doFill)
{ {
return getNetwork().fill(this, from, resource, doFill); return getNetwork().fill(this, from, resource, doFill);
} }
@Override @Override
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain)
{ {
return getNetwork().drain(this, from, resource, doDrain); return getNetwork().drain(this, from, resource, doDrain);
} }
@Override @Override
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain)
{ {
return getNetwork().drain(this, from, maxDrain, doDrain); return getNetwork().drain(this, from, maxDrain, doDrain);
} }
@Override @Override
public boolean canFill(ForgeDirection from, Fluid fluid) public boolean canFill(ForgeDirection from, Fluid fluid)
{ {
return true; return true;
} }
@Override @Override
public boolean canDrain(ForgeDirection from, Fluid fluid) public boolean canDrain(ForgeDirection from, Fluid fluid)
{ {
return true; return true;
} }
@Override @Override
public FluidTankInfo[] getTankInfo(ForgeDirection from) public FluidTankInfo[] getTankInfo(ForgeDirection from)
{ {
return new FluidTankInfo[] { getNetwork().getTank().getInfo() }; return new FluidTankInfo[] { getNetwork().getTank().getInfo() };
} }
@Override @Override
public Object[] getConnections() public Object[] getConnections()
{ {
return connectedBlocks; return connectedBlocks;
} }
public void refresh() public void refresh()
{ {
if (this.worldObj != null && !this.worldObj.isRemote) if (this.worldObj != null && !this.worldObj.isRemote)
{ {
byte previousConnections = renderSides; byte previousConnections = renderSides;
connectedBlocks = new Object[6]; connectedBlocks = new Object[6];
renderSides = 0; renderSides = 0;
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
{ {
this.validateConnectionSide(new Vector3(this).translate(dir).getTileEntity(worldObj), dir); this.validateConnectionSide(new Vector3(this).translate(dir).getTileEntity(worldObj), dir);
} }
/** Only send packet updates if visuallyConnected changed. */ /** Only send packet updates if visuallyConnected changed. */
if (previousConnections != renderSides) if (previousConnections != renderSides)
{ {
sendRenderUpdate(); sendRenderUpdate();
getNetwork().reconstruct(); getNetwork().reconstruct();
} }
} }
} }
/** /** Checks to make sure the connection is valid to the tileEntity
* Checks to make sure the connection is valid to the tileEntity *
* * @param tileEntity - the tileEntity being checked
* @param tileEntity - the tileEntity being checked * @param side - side the connection is too */
* @param side - side the connection is too public void validateConnectionSide(TileEntity tileEntity, ForgeDirection side)
*/ {
public void validateConnectionSide(TileEntity tileEntity, ForgeDirection side) if (!this.worldObj.isRemote)
{ {
if (!this.worldObj.isRemote) if (tileEntity instanceof IFluidDistribution)
{ {
if (tileEntity instanceof IFluidDistribution) this.getNetwork().merge(((IFluidDistribution) tileEntity).getNetwork());
{ renderSides = WorldUtility.setEnableSide(renderSides, side, true);
this.getNetwork().merge(((IFluidDistribution) tileEntity).getNetwork()); connectedBlocks[side.ordinal()] = tileEntity;
renderSides = WorldUtility.setEnableSide(renderSides, side, true); }
connectedBlocks[side.ordinal()] = tileEntity; }
} }
}
}
public int getSubID() public int getSubID()
{ {
return this.colorID; return this.colorID;
} }
public void setSubID(int id) public void setSubID(int id)
{ {
this.colorID = id; this.colorID = id;
} }
@Override @Override
public boolean canConnect(ForgeDirection direction, Object obj) public boolean canConnect(ForgeDirection direction, Object obj)
{ {
return true; return true;
} }
@Override @Override
public IFluidDistribution getInstance(ForgeDirection from) public IFluidDistribution getInstance(ForgeDirection from)
{ {
return this; return this;
} }
} }

View file

@ -16,141 +16,142 @@ import universalelectricity.api.vector.Vector3;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
/** /** A prefab class for tiles that use the fluid network.
* A prefab class for tiles that use the fluid network.
* *
* @author DarkGuardsman * @author DarkGuardsman */
*/
public abstract class TileFluidNode extends TileBase implements IPacketReceiverWithID public abstract class TileFluidNode extends TileBase implements IPacketReceiverWithID
{ {
public TileFluidNode(Material material) protected int pressure;
{
super(material);
}
protected int pressure; protected FluidTank tank;
protected FluidTank tank; protected int colorID = 0;
protected int colorID = 0; /** Copy of the tank's content last time it updated */
protected FluidStack prevStack = null;
/** Copy of the tank's content last time it updated */ public static final int PACKET_DESCRIPTION = 0;
protected FluidStack prevStack = null; public static final int PACKET_RENDER = 1;
public static final int PACKET_TANK = 2;
public static final int PACKET_DESCRIPTION = 0; /** Bitmask that handles connections for the renderer **/
public static final int PACKET_RENDER = 1; public byte renderSides = 0;
public static final int PACKET_TANK = 2;
/** Bitmask that handles connections for the renderer **/ protected boolean markTankUpdate;
public byte renderSides = 0;
protected boolean markTankUpdate; protected final int tankSize;
@Override public TileFluidNode(Material material, int tankSize)
public void updateEntity() {
{ super(material);
super.updateEntity(); this.tankSize = tankSize;
}
if (markTankUpdate) @Override
{ public void updateEntity()
sendTankUpdate(); {
markTankUpdate = false; super.updateEntity();
}
}
@Override if (markTankUpdate)
public void readFromNBT(NBTTagCompound nbt) {
{ sendTankUpdate();
super.readFromNBT(nbt); markTankUpdate = false;
colorID = nbt.getInteger("colorID"); }
getInternalTank().readFromNBT(nbt.getCompoundTag("FluidTank")); }
}
@Override @Override
public void writeToNBT(NBTTagCompound nbt) public void readFromNBT(NBTTagCompound nbt)
{ {
super.writeToNBT(nbt); super.readFromNBT(nbt);
nbt.setInteger("colorID", colorID); colorID = nbt.getInteger("colorID");
nbt.setCompoundTag("FluidTank", getInternalTank().writeToNBT(new NBTTagCompound())); getInternalTank().readFromNBT(nbt.getCompoundTag("FluidTank"));
} }
@Override @Override
public boolean onReceivePacket(int id, ByteArrayDataInput data, EntityPlayer player, Object... extra) public void writeToNBT(NBTTagCompound nbt)
{ {
try super.writeToNBT(nbt);
{ nbt.setInteger("colorID", colorID);
if (this.worldObj.isRemote) nbt.setCompoundTag("FluidTank", getInternalTank().writeToNBT(new NBTTagCompound()));
{ }
if (id == PACKET_DESCRIPTION)
{
colorID = data.readInt();
renderSides = data.readByte();
tank = new FluidTank(data.readInt());
getInternalTank().readFromNBT(PacketHandler.readNBTTagCompound(data));
return true;
}
else if (id == PACKET_RENDER)
{
colorID = data.readInt();
renderSides = data.readByte();
markRender();
return true;
}
else if (id == PACKET_TANK)
{
tank = new FluidTank(data.readInt()).readFromNBT(PacketHandler.readNBTTagCompound(data));
pressure = data.readInt();
updateLight();
return true;
}
}
}
catch (Exception e)
{
e.printStackTrace();
return true;
}
return false;
}
@Override @Override
public Packet getDescriptionPacket() public boolean onReceivePacket(int id, ByteArrayDataInput data, EntityPlayer player, Object... extra)
{ {
if (getInternalTank().getFluid() == null || (getInternalTank().getFluid() != null && getInternalTank().getFluid().getFluid().getName() != null)) try
return ResonantInduction.PACKET_TILE.getPacketWithID(PACKET_DESCRIPTION, this, this.colorID, this.renderSides, getInternalTank().getCapacity(), getInternalTank().writeToNBT(new NBTTagCompound())); {
return null; if (this.worldObj.isRemote)
} {
if (id == PACKET_DESCRIPTION)
{
colorID = data.readInt();
renderSides = data.readByte();
tank = new FluidTank(data.readInt());
getInternalTank().readFromNBT(PacketHandler.readNBTTagCompound(data));
return true;
}
else if (id == PACKET_RENDER)
{
colorID = data.readInt();
renderSides = data.readByte();
markRender();
return true;
}
else if (id == PACKET_TANK)
{
tank = new FluidTank(data.readInt()).readFromNBT(PacketHandler.readNBTTagCompound(data));
pressure = data.readInt();
updateLight();
return true;
}
}
}
catch (Exception e)
{
e.printStackTrace();
return true;
}
return false;
}
public void sendRenderUpdate() @Override
{ public Packet getDescriptionPacket()
if (!this.worldObj.isRemote) {
PacketHandler.sendPacketToClients(ResonantInduction.PACKET_TILE.getPacketWithID(PACKET_RENDER, this, this.colorID, this.renderSides)); if (getInternalTank().getFluid() == null || (getInternalTank().getFluid() != null && getInternalTank().getFluid().getFluid().getName() != null))
} return ResonantInduction.PACKET_TILE.getPacketWithID(PACKET_DESCRIPTION, this, this.colorID, this.renderSides, getInternalTank().getCapacity(), getInternalTank().writeToNBT(new NBTTagCompound()));
return null;
}
public void sendTankUpdate() public void sendRenderUpdate()
{ {
if (!this.worldObj.isRemote) if (!this.worldObj.isRemote)
PacketHandler.sendPacketToClients(ResonantInduction.PACKET_TILE.getPacketWithID(PACKET_TANK, this, getInternalTank().getCapacity(), getInternalTank().writeToNBT(new NBTTagCompound()), pressure), this.worldObj, new Vector3(this), 60); PacketHandler.sendPacketToClients(ResonantInduction.PACKET_TILE.getPacketWithID(PACKET_RENDER, this, this.colorID, this.renderSides));
} }
public void onFluidChanged() public void sendTankUpdate()
{ {
if (!worldObj.isRemote) if (!this.worldObj.isRemote)
{ PacketHandler.sendPacketToClients(ResonantInduction.PACKET_TILE.getPacketWithID(PACKET_TANK, this, getInternalTank().getCapacity(), getInternalTank().writeToNBT(new NBTTagCompound()), pressure), this.worldObj, new Vector3(this), 60);
if (!FluidUtility.matchExact(prevStack, getInternalTank().getFluid())) }
{
markTankUpdate = true;
prevStack = tank.getFluid() != null ? tank.getFluid().copy() : null;
}
}
}
public FluidTank getInternalTank() public void onFluidChanged()
{ {
if (this.tank == null) if (!worldObj.isRemote)
{ {
this.tank = new FluidTank(FluidContainerRegistry.BUCKET_VOLUME); if (!FluidUtility.matchExact(prevStack, getInternalTank().getFluid()))
} {
return this.tank; markTankUpdate = true;
} prevStack = tank.getFluid() != null ? tank.getFluid().copy() : null;
}
}
}
public FluidTank getInternalTank()
{
if (this.tank == null)
{
this.tank = new FluidTank(this.tankSize);
}
return this.tank;
}
} }

View file

@ -22,7 +22,7 @@ public abstract class TilePressureNode extends TileFluidNode implements IPressur
public TilePressureNode(Material material) public TilePressureNode(Material material)
{ {
super(material); super(material, 1000);
} }
@Override @Override