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.ITransmitterNetwork; 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.Fluid; import net.minecraftforge.fluids.FluidStack; import cpw.mods.fml.common.FMLCommonHandler; public class GasNetwork extends DynamicNetwork { public int transferDelay = 0; public boolean didTransfer; public boolean prevTransfer; public float gasScale; public Gas refGas; public GasStack gasStored; public int prevStored; public GasNetwork(ITransmitter... varPipes) { transmitters.addAll(Arrays.asList(varPipes)); register(); } public GasNetwork(Collection> collection) { transmitters.addAll(collection); register(); } public GasNetwork(Set 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; gasStored = net.gasStored; net.gasScale = 0; net.refGas = null; net.gasStored = null; } } else { if(net.gasStored != null) { if(gasStored == null) { gasStored = net.gasStored; } else { gasStored.amount += net.gasStored.amount; } net.gasStored = null; } } addAllTransmitters(net.transmitters); net.deregister(); } } gasScale = getScale(); refresh(); register(); } @Override public void onNetworksCreated(List networks) { if(gasStored != null && FMLCommonHandler.instance().getEffectiveSide().isServer()) { 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]); network.refGas = gasStored.getGas(); } } } gasScale = 0; refGas = null; gasStored = null; } 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--; } int stored = gasStored != null ? gasStored.amount : 0; if(stored != prevStored) { needsUpdate = true; } prevStored = stored; if(didTransfer != prevTransfer || needsUpdate) { MinecraftForge.EVENT_BUS.post(new GasTransferEvent(this, gasStored, didTransfer)); needsUpdate = false; } 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, 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) { gasStored = null; } } } @Override public synchronized Set getAcceptors(Object... data) { Gas type = (Gas)data[0]; Set toReturn = new HashSet(); 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> iterTubes = (Set>)transmitters.clone(); Iterator> it = iterTubes.iterator(); possibleAcceptors.clear(); acceptorDirections.clear(); while(it.hasNext()) { ITransmitter conductor = (ITransmitter)it.next(); if(conductor == null || ((TileEntity)conductor).isInvalid()) { it.remove(); transmitters.remove(conductor); } else { conductor.setTransmitterNetwork(this); } } for(ITransmitter transmitter : transmitters) { IGasHandler[] acceptors = GasTransmission.getConnectedAcceptors((TileEntity)transmitter); for(IGasHandler acceptor : acceptors) { ForgeDirection side = ForgeDirection.getOrientation(Arrays.asList(acceptors).indexOf(acceptor)); if(side != null && acceptor != null && !(acceptor instanceof ITransmitter) && transmitter.canConnect(side)) { 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 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 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, (gasStored == null || getCapacity() == 0 ? 0 : (float)gasStored.amount/getCapacity())); } @Override public String toString() { return "[GasNetwork] " + transmitters.size() + " transmitters, " + possibleAcceptors.size() + " acceptors."; } @Override public boolean canMerge(List> networks) { Gas found = null; for(ITransmitterNetwork network : networks) { if(network instanceof FluidNetwork) { GasNetwork net = (GasNetwork)network; if(net.gasStored != null) { if(found != null && found != net.gasStored.getGas()) { return false; } found = net.gasStored.getGas(); } } } return true; } @Override protected GasNetwork create(ITransmitter... varTransmitters) { GasNetwork network = new GasNetwork(varTransmitters); network.refGas = refGas; if(gasStored != null) { if(network.gasStored == null) { network.gasStored = gasStored; } else { network.gasStored.amount += gasStored.amount; } } network.gasScale = network.getScale(); gasScale = 0; refGas = null; gasStored = null; return network; } @Override protected GasNetwork create(Collection> collection) { GasNetwork network = new GasNetwork(collection); network.refGas = refGas; if(gasStored != null) { if(network.gasStored == null) { network.gasStored = gasStored; } else { network.gasStored.amount += gasStored.amount; } } network.gasScale = network.getScale(); return network; } @Override protected GasNetwork create(Set 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"; } }