blob: 3a7e471e1645df435aff80150452e3a005ed9c87 [file] [log] [blame] [raw]
package mekanism.api.gas;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mekanism.api.transmitters.DynamicNetwork;
import mekanism.api.transmitters.ITransmitter;
import mekanism.api.transmitters.TransmissionType;
import mekanism.common.FluidNetwork;
import mekanism.common.util.ListUtils;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.Event;
import net.minecraftforge.fluids.FluidStack;
import cpw.mods.fml.common.FMLCommonHandler;
public class GasNetwork extends DynamicNetwork<IGasHandler, GasNetwork>
{
public static final int TUBE_GAS = 256;
public int transferDelay = 0;
public boolean didTransfer;
public boolean prevTransfer;
public float gasScale;
public float prevScale;
/** Sent from server to client, actual stored buffer scale. Used by server as last-update scale. */
public float definedScale;
public Gas refGas = null;
public GasStack gasStored;
public GasNetwork(ITransmitter<GasNetwork>... varPipes)
{
transmitters.addAll(Arrays.asList(varPipes));
register();
}
public GasNetwork(Collection<ITransmitter<GasNetwork>> collection)
{
transmitters.addAll(collection);
register();
}
public GasNetwork(Set<GasNetwork> networks)
{
for(GasNetwork net : networks)
{
if(net != null)
{
if(net.refGas != null && net.gasScale > gasScale)
{
refGas = net.refGas;
gasScale = net.gasScale;
}
if(net.gasStored != null)
{
if(gasStored == null)
{
gasStored = net.gasStored;
}
else {
gasStored.amount += net.gasStored.amount;
}
}
addAllTransmitters(net.transmitters);
net.deregister();
}
}
refresh();
register();
}
@Override
public void onNetworksCreated(List<GasNetwork> networks)
{
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
if(gasStored != null)
{
int[] caps = new int[networks.size()];
int cap = 0;
for(GasNetwork network : networks)
{
caps[networks.indexOf(network)] = network.getCapacity();
cap += network.getCapacity();
}
gasStored.amount = Math.min(cap, gasStored.amount);
int[] values = ListUtils.calcPercentInt(ListUtils.percent(caps), gasStored.amount);
for(GasNetwork network : networks)
{
int index = networks.indexOf(network);
if(values[index] > 0)
{
network.gasStored = new GasStack(gasStored.getGas(), values[index]);
}
}
}
}
}
public synchronized int getGasNeeded()
{
return getCapacity()-(gasStored != null ? gasStored.amount : 0);
}
public synchronized int tickEmit(GasStack stack)
{
List availableAcceptors = Arrays.asList(getAcceptors(stack.getGas()).toArray());
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(Object obj : availableAcceptors)
{
if(obj instanceof IGasHandler)
{
IGasHandler acceptor = (IGasHandler)obj;
int currentSending = sending;
if(remaining > 0)
{
currentSending++;
remaining--;
}
toSend -= acceptor.receiveGas(acceptorDirections.get(acceptor).getOpposite(), new GasStack(stack.getGas(), currentSending));
}
}
}
int sent = prevSending-toSend;
if(sent > 0 && FMLCommonHandler.instance().getEffectiveSide().isServer())
{
didTransfer = true;
transferDelay = 2;
}
return sent;
}
public synchronized int emit(GasStack stack)
{
if(gasStored != null && gasStored.getGas() != stack.getGas())
{
return 0;
}
int toUse = Math.min(getGasNeeded(), stack.amount);
if(gasStored == null)
{
gasStored = stack.copy();
gasStored.amount = toUse;
}
else {
gasStored.amount += toUse;
}
return toUse;
}
@Override
public void tick()
{
super.tick();
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
if(transferDelay == 0)
{
didTransfer = false;
}
else {
transferDelay--;
}
if(Math.abs(getScale()-definedScale) > 0.01 || (getScale() != prevScale && (getScale() == 0 || getScale() == 1)))
{
needsUpdate = true;
}
prevScale = getScale();
if(didTransfer != prevTransfer || needsUpdate)
{
MinecraftForge.EVENT_BUS.post(new GasTransferEvent(this, gasStored != null ? gasStored.getGas().getID() : -1, didTransfer, getScale()));
needsUpdate = false;
definedScale = getScale();
}
prevTransfer = didTransfer;
if(gasStored != null)
{
gasStored.amount -= tickEmit(gasStored);
if(gasStored.amount <= 0)
{
gasStored = null;
}
}
}
}
@Override
public void clientTick()
{
super.clientTick();
gasScale = Math.max(gasScale, definedScale);
if(didTransfer && gasScale < 1)
{
gasScale = Math.max(definedScale, Math.min(1, gasScale+0.02F));
}
else if(!didTransfer && gasScale > 0)
{
gasScale = Math.max(definedScale, Math.max(0, gasScale-0.02F));
if(gasScale == 0)
{
refGas = null;
}
}
}
@Override
public synchronized Set<IGasHandler> getAcceptors(Object... data)
{
Gas type = (Gas)data[0];
Set<IGasHandler> toReturn = new HashSet<IGasHandler>();
for(IGasHandler acceptor : possibleAcceptors)
{
if(acceptorDirections.get(acceptor) == null)
{
continue;
}
if(acceptor.canReceiveGas(acceptorDirections.get(acceptor).getOpposite(), type))
{
toReturn.add(acceptor);
}
}
return toReturn;
}
@Override
public synchronized void refresh()
{
Set<ITransmitter<GasNetwork>> iterTubes = (Set<ITransmitter<GasNetwork>>)transmitters.clone();
Iterator<ITransmitter<GasNetwork>> it = iterTubes.iterator();
possibleAcceptors.clear();
acceptorDirections.clear();
while(it.hasNext())
{
ITransmitter<GasNetwork> conductor = (ITransmitter<GasNetwork>)it.next();
if(conductor == null || ((TileEntity)conductor).isInvalid())
{
it.remove();
transmitters.remove(conductor);
}
else {
conductor.setTransmitterNetwork(this);
}
}
for(ITransmitter<GasNetwork> pipe : transmitters)
{
IGasHandler[] acceptors = GasTransmission.getConnectedAcceptors((TileEntity)pipe);
for(IGasHandler acceptor : acceptors)
{
if(acceptor != null && !(acceptor instanceof ITransmitter))
{
possibleAcceptors.add(acceptor);
acceptorDirections.put(acceptor, ForgeDirection.getOrientation(Arrays.asList(acceptors).indexOf(acceptor)));
}
}
}
}
@Override
public synchronized void merge(GasNetwork network)
{
if(network != null && network != this)
{
Set<GasNetwork> networks = new HashSet();
networks.add(this);
networks.add(network);
GasNetwork newNetwork = create(networks);
newNetwork.refresh();
}
}
public static class GasTransferEvent extends Event
{
public final GasNetwork gasNetwork;
public final int transferType;
public final boolean didTransfer;
public final float gasScale;
public GasTransferEvent(GasNetwork network, int type, boolean did, float scale)
{
gasNetwork = network;
transferType = type;
didTransfer = did;
gasScale = scale;
}
}
public float getScale()
{
return (gasStored == null || getCapacity() == 0 ? 0 : (float)gasStored.amount/getCapacity());
}
@Override
public String toString()
{
return "[GasNetwork] " + transmitters.size() + " transmitters, " + possibleAcceptors.size() + " acceptors.";
}
@Override
protected GasNetwork create(ITransmitter<GasNetwork>... varTransmitters)
{
GasNetwork network = new GasNetwork(varTransmitters);
network.refGas = refGas;
network.gasScale = gasScale;
if(gasStored != null)
{
if(network.gasStored == null)
{
network.gasStored = gasStored;
}
else {
network.gasStored.amount += gasStored.amount;
}
}
return network;
}
@Override
protected GasNetwork create(Collection<ITransmitter<GasNetwork>> collection)
{
GasNetwork network = new GasNetwork(collection);
network.refGas = refGas;
network.gasScale = gasScale;
if(gasStored != null)
{
if(network.gasStored == null)
{
network.gasStored = gasStored;
}
else {
network.gasStored.amount += gasStored.amount;
}
}
return network;
}
@Override
protected GasNetwork create(Set<GasNetwork> networks)
{
return new GasNetwork(networks);
}
@Override
public TransmissionType getTransmissionType()
{
return TransmissionType.GAS;
}
@Override
public String getNeeded()
{
return Integer.toString(getGasNeeded());
}
@Override
public String getFlow()
{
return gasStored != null ? gasStored.getGas().getLocalizedName() + " (" + gasStored.amount + ")" : "None";
}
}