blob: e364cf81eda724123f91a174a59245eb0ccf32c8 [file] [log] [blame] [raw]
package mekanism.api.transmitters;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import mekanism.api.Coord4D;
import mekanism.api.IClientTicker;
import mekanism.api.Range4D;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.Event;
import scala.collection.parallel.ParIterableLike.Collect;
public abstract class DynamicNetwork<A, N extends DynamicNetwork<A, N>> implements IClientTicker, INetworkDataHandler
{
public LinkedHashSet<IGridTransmitter<A, N>> transmitters = new LinkedHashSet<>();
public LinkedHashSet<IGridTransmitter<A, N>> transmittersToAdd = new LinkedHashSet<>();
public LinkedHashSet<IGridTransmitter<A, N>> transmittersAdded = new LinkedHashSet<>();
public HashMap<Coord4D, A> possibleAcceptors = new HashMap<Coord4D, A>();
public HashMap<Coord4D, EnumSet<ForgeDirection>> acceptorDirections = new HashMap<Coord4D, EnumSet<ForgeDirection>>();
public HashMap<IGridTransmitter<A, N>, EnumSet<ForgeDirection>> changedAcceptors = new HashMap<>();
private Set<DelayQueue> updateQueue = new LinkedHashSet<DelayQueue>();
protected Range4D packetRange = null;
protected int ticksSinceCreate = 0;
protected int capacity = 0;
protected double meanCapacity = 0;
protected boolean needsUpdate = false;
protected int updateDelay = 0;
protected boolean firstUpdate = true;
protected World worldObj = null;
public void addNewTransmitters(Collection<IGridTransmitter<A, N>> newTransmitters)
{
transmittersToAdd.addAll(newTransmitters);
}
public void commit()
{
if(!transmittersToAdd.isEmpty())
{
for(IGridTransmitter<A, N> transmitter : transmittersToAdd)
{
if(transmitter.isValid())
{
if(worldObj == null) worldObj = transmitter.world();
Coord4D coord = transmitter.coord();
for(ForgeDirection side : ForgeDirection.VALID_DIRECTIONS)
{
A acceptor = transmitter.getAcceptor(side);
if(acceptor != null)
{
Coord4D acceptorCoord = coord.getFromSide(side);
possibleAcceptors.put(acceptorCoord, acceptor);
EnumSet<ForgeDirection> directions = acceptorDirections.get(acceptorCoord);
if(directions != null)
{
directions.add(side.getOpposite());
} else
{
acceptorDirections.put(acceptorCoord, EnumSet.of(side.getOpposite()));
}
}
}
transmitter.setTransmitterNetwork((N)this);
absorbBuffer(transmitter);
transmitters.add(transmitter);
}
}
updateCapacity();
clampBuffer();
queueClientUpdate(new ArrayList<>(transmittersToAdd));
transmittersToAdd.clear();
}
if(!changedAcceptors.isEmpty())
{
for(Entry<IGridTransmitter<A, N>, EnumSet<ForgeDirection>> entry : changedAcceptors.entrySet())
{
IGridTransmitter<A, N> transmitter = entry.getKey();
EnumSet<ForgeDirection> directionsChanged = entry.getValue();
for(ForgeDirection side : directionsChanged)
{
A acceptor = transmitter.getAcceptor(side);
Coord4D acceptorCoord = transmitter.coord().getFromSide(side);
EnumSet<ForgeDirection> directions = acceptorDirections.get(acceptorCoord);
if(acceptor != null)
{
possibleAcceptors.put(acceptorCoord, acceptor);
if(directions != null)
{
directions.add(side.getOpposite());
} else
{
acceptorDirections.put(acceptorCoord, EnumSet.of(side.getOpposite()));
}
}
else
{
if(directions != null)
{
directions.remove(side.getOpposite());
if(directions.isEmpty())
{
possibleAcceptors.remove(acceptorCoord);
acceptorDirections.remove(acceptorCoord);
}
}
}
}
}
changedAcceptors.clear();
}
}
public abstract void absorbBuffer(IGridTransmitter<A, N> transmitter);
public abstract void clampBuffer();
public void invalidate()
{
for(IGridTransmitter<A, N> transmitter : transmitters)
{
invalidateTransmitter(transmitter);
}
transmitters.clear();
deregister();
}
public void invalidateTransmitter(IGridTransmitter<A, N> transmitter)
{
if(!worldObj.isRemote && transmitter.isValid())
{
transmitter.takeShare();
transmitter.setTransmitterNetwork(null);
TransmitterNetworkRegistry.registerOrphanTransmitter(transmitter);
}
}
public void acceptorChanged(IGridTransmitter<A, N> transmitter, ForgeDirection side)
{
EnumSet<ForgeDirection> directions = changedAcceptors.get(transmitter);
if(directions != null)
{
directions.add(side);
} else
{
changedAcceptors.put(transmitter, EnumSet.of(side));
}
TransmitterNetworkRegistry.registerChangedNetwork(this);
}
public void adoptTransmittersAndAcceptorsFrom(N net)
{
for(IGridTransmitter<A, N> transmitter : net.transmitters)
{
transmitter.setTransmitterNetwork((N)this);
transmitters.add(transmitter);
transmittersAdded.add(transmitter);
}
possibleAcceptors.putAll(net.possibleAcceptors);
for(Entry<Coord4D, EnumSet<ForgeDirection>> entry : net.acceptorDirections.entrySet())
{
Coord4D coord = entry.getKey();
if(acceptorDirections.containsKey(coord))
{
acceptorDirections.get(coord).addAll(entry.getValue());
}
else
{
acceptorDirections.put(coord, entry.getValue());
}
}
}
public Range4D getPacketRange()
{
if(packetRange == null)
{
return genPacketRange();
}
return packetRange;
}
protected Range4D genPacketRange()
{
if(getSize() == 0)
{
deregister();
return null;
}
IGridTransmitter<A, N> initTransmitter = transmitters.iterator().next();
Coord4D initCoord = initTransmitter.coord();
int minX = initCoord.xCoord;
int minY = initCoord.yCoord;
int minZ = initCoord.zCoord;
int maxX = initCoord.xCoord;
int maxY = initCoord.yCoord;
int maxZ = initCoord.zCoord;
for(IGridTransmitter transmitter : transmitters)
{
Coord4D coord = transmitter.coord();
if(coord.xCoord < minX) minX = coord.xCoord;
if(coord.yCoord < minY) minY = coord.yCoord;
if(coord.zCoord < minZ) minZ = coord.zCoord;
if(coord.xCoord > maxX) maxX = coord.xCoord;
if(coord.yCoord > maxY) maxY = coord.yCoord;
if(coord.zCoord > maxZ) maxZ = coord.zCoord;
}
return new Range4D(minX, minY, minZ, maxX, maxY, maxZ, initTransmitter.world().provider.dimensionId);
}
public void register()
{
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
TransmitterNetworkRegistry.getInstance().registerNetwork(this);
}
else {
MinecraftForge.EVENT_BUS.post(new ClientTickUpdate(this, (byte)1));
}
}
public void deregister()
{
transmitters.clear();
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
TransmitterNetworkRegistry.getInstance().removeNetwork(this);
}
else {
MinecraftForge.EVENT_BUS.post(new ClientTickUpdate(this, (byte)0));
}
}
public int getSize()
{
return transmitters.size();
}
public int getAcceptorSize()
{
return possibleAcceptors.size();
}
public synchronized void updateCapacity()
{
updateMeanCapacity();
capacity = (int)meanCapacity * transmitters.size();
}
/**
* Override this if things can have variable capacity along the network.
* @return An 'average' value of capacity. Calculate it how you will.
*/
protected synchronized void updateMeanCapacity()
{
if(transmitters.size() > 0)
{
meanCapacity = transmitters.iterator().next().getCapacity();
}
else {
meanCapacity = 0;
}
}
public int getCapacity()
{
return capacity;
}
public World getWorld()
{
return worldObj;
}
public abstract Set<A> getAcceptors(Object data);
public void tick()
{
onUpdate();
}
public void onUpdate()
{
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
Iterator<DelayQueue> i = updateQueue.iterator();
try
{
while(i.hasNext())
{
DelayQueue q = i.next();
if(q.delay > 0)
{
q.delay--;
} else
{
transmittersAdded.addAll(transmitters);
updateDelay = 1;
i.remove();
}
}
} catch(Exception e)
{
}
if(updateDelay > 0)
{
updateDelay--;
if(updateDelay == 0)
{
MinecraftForge.EVENT_BUS.post(new TransmittersAddedEvent(this, firstUpdate, (Collection)transmittersAdded));
firstUpdate = false;
transmittersAdded.clear();
needsUpdate = true;
}
}
}
}
@Override
public boolean needsTicks()
{
return getSize() > 0;
}
@Override
public void clientTick() {}
public void queueClientUpdate(Collection<IGridTransmitter<A, N>> newTransmitters)
{
transmittersAdded.addAll(newTransmitters);
updateDelay = 3;
}
public static class TransmittersAddedEvent extends Event
{
public DynamicNetwork<?, ?> network;
public boolean newNetwork;
public Collection<IGridTransmitter> newTransmitters;
public TransmittersAddedEvent(DynamicNetwork net, boolean newNet, Collection<IGridTransmitter> added)
{
network = net;
newNetwork = newNet;
newTransmitters = added;
}
}
public static class ClientTickUpdate extends Event
{
public DynamicNetwork network;
public byte operation; /*0 remove, 1 add*/
public ClientTickUpdate(DynamicNetwork net, byte b)
{
network = net;
operation = b;
}
}
public static class NetworkClientRequest extends Event
{
public TileEntity tileEntity;
public NetworkClientRequest(TileEntity tile)
{
tileEntity = tile;
}
}
public void addUpdate(EntityPlayer player)
{
updateQueue.add(new DelayQueue(player));
}
public static class DelayQueue
{
public EntityPlayer player;
public int delay;
public DelayQueue(EntityPlayer p)
{
player = p;
delay = 5;
}
@Override
public int hashCode()
{
return player.hashCode();
}
@Override
public boolean equals(Object o)
{
return o instanceof DelayQueue && ((DelayQueue)o).player.equals(this.player);
}
}
}