blob: e08f9c1335e0085d1795d329dfa059b9fdca2572 [file] [log] [blame] [raw]
package mekanism.api.gas;
import com.google.common.collect.Lists;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.Event;
import mekanism.api.Coord4D;
import mekanism.api.transmitters.DynamicNetwork;
import mekanism.api.transmitters.IGridTransmitter;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.*;
/**
* A DynamicNetwork extension created specifically for the transfer of Gasses. By default this is server-only, but if ticked on
* the client side and if it's posted events are handled properly, it has the capability to visually display gasses network-wide.
* @author aidancbrady
*
*/
public class GasNetwork extends DynamicNetwork<IGasHandler, GasNetwork>
{
public int transferDelay = 0;
public boolean didTransfer;
public boolean prevTransfer;
public float gasScale;
public Gas refGas;
public GasStack buffer;
public int prevStored;
public int prevTransferAmount = 0;
public GasNetwork() {}
public GasNetwork(Collection<GasNetwork> networks)
{
for(GasNetwork net : networks)
{
if(net != null)
{
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
if(net.refGas != null && net.gasScale > gasScale)
{
gasScale = net.gasScale;
refGas = net.refGas;
buffer = net.buffer;
net.gasScale = 0;
net.refGas = null;
net.buffer = null;
}
} else
{
if(net.buffer != null)
{
if(buffer == null)
{
buffer = net.buffer.copy();
} else
{
if(buffer.isGasEqual(net.buffer))
{
buffer.amount += net.buffer.amount;
}
else if(net.buffer.amount > buffer.amount)
{
buffer = net.buffer.copy();
}
}
net.buffer = null;
}
}
adoptTransmittersAndAcceptorsFrom(net);
net.deregister();
}
}
gasScale = getScale();
register();
}
@Override
public void absorbBuffer(IGridTransmitter<IGasHandler, GasNetwork> transmitter)
{
Object b = transmitter.getBuffer();
if(!(b instanceof GasStack) || ((GasStack)b).getGas() == null || ((GasStack)b).amount == 0)
{
return;
}
GasStack gas = (GasStack)b;
if(buffer == null || buffer.getGas() == null || buffer.amount == 0)
{
buffer = gas.copy();
gas.amount = 0;
return;
}
//TODO better multiple buffer impl
if(buffer.isGasEqual(gas))
{
buffer.amount += gas.amount;
}
gas.amount = 0;
}
@Override
public void clampBuffer()
{
if(buffer != null && buffer.amount > getCapacity())
{
buffer.amount = capacity;
}
}
public int getGasNeeded()
{
return getCapacity()-(buffer != null ? buffer.amount : 0);
}
public int tickEmit(GasStack stack)
{
List<IGasHandler> availableAcceptors = Lists.newArrayList();
availableAcceptors.addAll(getAcceptors(stack.getGas()));
Collections.shuffle(availableAcceptors);
int toSend = stack.amount;
int prevSending = toSend;
if(!availableAcceptors.isEmpty())
{
int divider = availableAcceptors.size();
int remaining = toSend % divider;
int sending = (toSend-remaining)/divider;
for(IGasHandler acceptor : availableAcceptors)
{
int currentSending = sending;
EnumSet<ForgeDirection> sides = acceptorDirections.get(Coord4D.get((TileEntity)acceptor));
if(remaining > 0)
{
currentSending++;
remaining--;
}
for(ForgeDirection side : sides)
{
int prev = toSend;
toSend -= acceptor.receiveGas(side, new GasStack(stack.getGas(), currentSending), true);
if(toSend < prev)
{
break;
}
}
}
}
int sent = prevSending-toSend;
if(sent > 0 && FMLCommonHandler.instance().getEffectiveSide().isServer())
{
didTransfer = true;
transferDelay = 2;
}
return sent;
}
public int emit(GasStack stack, boolean doTransfer)
{
if(buffer != null && buffer.getGas() != stack.getGas())
{
return 0;
}
int toUse = Math.min(getGasNeeded(), stack.amount);
if(doTransfer)
{
if(buffer == null)
{
buffer = stack.copy();
buffer.amount = toUse;
}
else {
buffer.amount += toUse;
}
}
return toUse;
}
@Override
public void onUpdate()
{
super.onUpdate();
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
prevTransferAmount = 0;
if(transferDelay == 0)
{
didTransfer = false;
}
else {
transferDelay--;
}
int stored = buffer != null ? buffer.amount : 0;
if(stored != prevStored)
{
needsUpdate = true;
}
prevStored = stored;
if(didTransfer != prevTransfer || needsUpdate)
{
MinecraftForge.EVENT_BUS.post(new GasTransferEvent(this, buffer, didTransfer));
needsUpdate = false;
}
prevTransfer = didTransfer;
if(buffer != null)
{
prevTransferAmount = tickEmit(buffer);
buffer.amount -= prevTransferAmount;
if(buffer.amount <= 0)
{
buffer = null;
}
}
}
}
@Override
public void clientTick()
{
super.clientTick();
gasScale = Math.max(gasScale, getScale());
if(didTransfer && gasScale < 1)
{
gasScale = Math.max(getScale(), Math.min(1, gasScale+0.02F));
}
else if(!didTransfer && gasScale > 0)
{
gasScale = Math.max(getScale(), Math.max(0, gasScale-0.02F));
if(gasScale == 0)
{
buffer = null;
}
}
}
@Override
public Set<IGasHandler> getAcceptors(Object data)
{
Gas type = (Gas)data;
Set<IGasHandler> toReturn = new HashSet<IGasHandler>();
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
return toReturn;
}
for(Coord4D coord : possibleAcceptors.keySet())
{
EnumSet<ForgeDirection> sides = acceptorDirections.get(coord);
TileEntity tile = coord.getTileEntity(getWorld());
if(!(tile instanceof IGasHandler) || sides == null || sides.isEmpty())
{
continue;
}
IGasHandler acceptor = (IGasHandler)tile;
for(ForgeDirection side : sides)
{
if(acceptor != null && acceptor.canReceiveGas(side, type))
{
toReturn.add(acceptor);
break;
}
}
}
return toReturn;
}
public static class GasTransferEvent extends Event
{
public final GasNetwork gasNetwork;
public final GasStack transferType;
public final boolean didTransfer;
public GasTransferEvent(GasNetwork network, GasStack type, boolean did)
{
gasNetwork = network;
transferType = type;
didTransfer = did;
}
}
public float getScale()
{
return Math.min(1, (buffer == null || getCapacity() == 0 ? 0 : (float)buffer.amount/getCapacity()));
}
@Override
public String toString()
{
return "[GasNetwork] " + transmitters.size() + " transmitters, " + possibleAcceptors.size() + " acceptors.";
}
@Override
public String getNeededInfo()
{
return Integer.toString(getGasNeeded());
}
@Override
public String getStoredInfo()
{
return buffer != null ? buffer.getGas().getLocalizedName() + " (" + buffer.amount + ")" : "None";
}
@Override
public String getFlowInfo()
{
return Integer.toString(prevTransferAmount) + "/t";
}
}