package mekanism.api.transmitters; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import mekanism.api.Object3D; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import net.minecraftforge.common.ForgeDirection; public abstract class DynamicNetwork implements ITransmitterNetwork { public HashSet> transmitters = new HashSet>(); public HashSet possibleAcceptors = new HashSet(); public HashMap acceptorDirections = new HashMap(); protected int ticksSinceCreate = 0; protected boolean fixed = false; protected abstract ITransmitterNetwork create(ITransmitter... varTransmitters); protected abstract ITransmitterNetwork create(Collection> collection); protected abstract ITransmitterNetwork create(Set networks); public void addAllTransmitters(Set> newTransmitters) { transmitters.addAll(newTransmitters); } @Override public void removeTransmitter(ITransmitter transmitter) { transmitters.remove(transmitter); if(transmitters.size() == 0) { deregister(); } } @Override public void register() { try { ITransmitter aTransmitter = transmitters.iterator().next(); if(aTransmitter instanceof TileEntity && !((TileEntity)aTransmitter).worldObj.isRemote) { TransmitterNetworkRegistry.getInstance().registerNetwork(this); } } catch(NoSuchElementException e) {} } @Override public void deregister() { transmitters.clear(); TransmitterNetworkRegistry.getInstance().removeNetwork(this); } @Override public int getSize() { return transmitters.size(); } @Override public int getAcceptorSize() { return possibleAcceptors.size(); } @Override public void tick() { if(!fixed) { ++ticksSinceCreate; if(ticksSinceCreate > 1200) { ticksSinceCreate = 0; fixMessedUpNetwork(transmitters.iterator().next()); } } } @Override public synchronized void fixMessedUpNetwork(ITransmitter transmitter) { if(transmitter instanceof TileEntity) { NetworkFinder finder = new NetworkFinder(((TileEntity)transmitter).getWorldObj(), getTransmissionType(), Object3D.get((TileEntity)transmitter)); List partNetwork = finder.exploreNetwork(); Set> newTransporters = new HashSet>(); for(Object3D node : partNetwork) { TileEntity nodeTile = node.getTileEntity(((TileEntity)transmitter).worldObj); if(TransmissionType.checkTransmissionType(nodeTile, getTransmissionType(), (TileEntity) transmitter)) { ((ITransmitter)nodeTile).removeFromTransmitterNetwork(); newTransporters.add((ITransmitter)nodeTile); } } ITransmitterNetwork newNetwork = create(newTransporters); newNetwork.refresh(); newNetwork.setFixed(true); deregister(); } } @Override public synchronized void split(ITransmitter splitPoint) { if(splitPoint instanceof TileEntity) { removeTransmitter(splitPoint); TileEntity[] connectedBlocks = new TileEntity[6]; boolean[] dealtWith = {false, false, false, false, false, false}; for(ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { TileEntity sideTile = Object3D.get((TileEntity)splitPoint).getFromSide(direction).getTileEntity(((TileEntity)splitPoint).worldObj); if(sideTile != null) { connectedBlocks[Arrays.asList(ForgeDirection.values()).indexOf(direction)] = sideTile; } } for(int countOne = 0; countOne < connectedBlocks.length; countOne++) { TileEntity connectedBlockA = connectedBlocks[countOne]; if(TransmissionType.checkTransmissionType(connectedBlockA, getTransmissionType()) && !dealtWith[countOne]) { NetworkFinder finder = new NetworkFinder(((TileEntity)splitPoint).worldObj, getTransmissionType(), Object3D.get(connectedBlockA), Object3D.get((TileEntity)splitPoint)); List partNetwork = finder.exploreNetwork(); for(int countTwo = countOne + 1; countTwo < connectedBlocks.length; countTwo++) { TileEntity connectedBlockB = connectedBlocks[countTwo]; if(TransmissionType.checkTransmissionType(connectedBlockB, getTransmissionType()) && !dealtWith[countTwo]) { if(partNetwork.contains(Object3D.get(connectedBlockB))) { dealtWith[countTwo] = true; } } } Set> newNetCables = new HashSet>(); for(Object3D node : finder.iterated) { TileEntity nodeTile = node.getTileEntity(((TileEntity)splitPoint).worldObj); if(TransmissionType.checkTransmissionType(nodeTile, getTransmissionType())) { if(nodeTile != splitPoint) { newNetCables.add((ITransmitter)nodeTile); } } } ITransmitterNetwork newNetwork = create(newNetCables); newNetwork.refresh(); } } deregister(); } } @Override public void setFixed(boolean value) { fixed = value; } public static class NetworkFinder { public TransmissionType transmissionType; public World worldObj; public Object3D start; public List iterated = new ArrayList(); public List toIgnore = new ArrayList(); public NetworkFinder(World world, TransmissionType type, Object3D location, Object3D... ignore) { worldObj = world; start = location; transmissionType = type; if(ignore != null) { for(int i = 0; i < ignore.length; i++) { this.toIgnore.add(ignore[i]); } } } public void loopAll(Object3D location) { if(TransmissionType.checkTransmissionType(location.getTileEntity(worldObj), transmissionType)) { iterated.add(location); } else { toIgnore.add(location); } for(ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { Object3D obj = location.getFromSide(direction); if(!iterated.contains(obj) && !toIgnore.contains(obj)) { TileEntity tileEntity = obj.getTileEntity(worldObj); if(TransmissionType.checkTransmissionType(tileEntity, transmissionType, location.getTileEntity(worldObj))) { loopAll(obj); } } } } public List exploreNetwork() { loopAll(start); return iterated; } } }