package universalelectricity.compatibility; import ic2.api.energy.tile.IEnergyAcceptor; import ic2.api.energy.tile.IEnergySink; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.ForgeDirection; import net.minecraftforge.common.MinecraftForge; import universalelectricity.core.block.IConductor; import universalelectricity.core.block.IElectrical; import universalelectricity.core.block.INetworkConnection; import universalelectricity.core.block.INetworkProvider; import universalelectricity.core.electricity.ElectricalEvent.ElectricityProductionEvent; import universalelectricity.core.electricity.ElectricalEvent.ElectricityRequestEvent; import universalelectricity.core.electricity.ElectricityPack; import universalelectricity.core.grid.ElectricityNetwork; import universalelectricity.core.grid.IElectricityNetwork; import universalelectricity.core.path.Pathfinder; import universalelectricity.core.path.PathfinderChecker; import universalelectricity.core.vector.Vector3; import universalelectricity.core.vector.VectorHelper; import buildcraft.api.power.IPowerReceptor; import buildcraft.api.power.PowerHandler.PowerReceiver; import buildcraft.api.power.PowerHandler.Type; import cofh.api.energy.IEnergyHandler; import cpw.mods.fml.common.FMLLog; /** * A universal network that words with multiple energy systems. * * @author micdoodle8, Calclavia, Aidancbrady * */ public class UniversalNetwork extends ElectricityNetwork { @Override public float produce(ElectricityPack electricity, TileEntity... ignoreTiles) { ElectricityProductionEvent evt = new ElectricityProductionEvent(this, electricity, ignoreTiles); MinecraftForge.EVENT_BUS.post(evt); float totalEnergy = electricity.getWatts(); float networkResistance = getTotalResistance(); float proportionWasted = getTotalResistance() / (getTotalResistance() + acceptorResistance); float energyWasted = totalEnergy * proportionWasted; float totalUsableEnergy = totalEnergy - energyWasted; float remainingUsableEnergy = totalUsableEnergy; float voltage = electricity.voltage; if (!evt.isCanceled()) { Set avaliableEnergyTiles = this.getAcceptors(); if (!avaliableEnergyTiles.isEmpty()) { final float totalEnergyRequest = this.getRequest(ignoreTiles).getWatts(); if (totalEnergyRequest > 0) { boolean markRefresh = false; for (TileEntity tileEntity : avaliableEnergyTiles) { if (tileEntity != null && !tileEntity.isInvalid()) { if (remainingUsableEnergy > 0 && !Arrays.asList(ignoreTiles).contains(tileEntity)) { if (tileEntity instanceof IElectrical) { IElectrical electricalTile = (IElectrical) tileEntity; for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { if (electricalTile.canConnect(direction) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) { float energyToSend = totalUsableEnergy * (Math.min(electricalTile.getRequest(direction), totalEnergyRequest) / totalEnergyRequest); if (energyToSend > 0) { ElectricityPack electricityToSend = ElectricityPack.getFromWatts(energyToSend, voltage); remainingUsableEnergy -= electricalTile.receiveElectricity(direction, electricityToSend, true); } } } } else if (tileEntity instanceof IEnergySink) { IEnergySink electricalTile = (IEnergySink) tileEntity; for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { TileEntity conductor = VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction); if (this.getConductors().contains(conductor) && electricalTile.acceptsEnergyFrom(conductor, direction)) { float energyToSend = (float) Math.min(totalUsableEnergy * ((electricalTile.demandedEnergyUnits() * Compatibility.IC2_RATIO) / totalEnergyRequest), electricalTile.getMaxSafeInput() * Compatibility.IC2_RATIO); if (energyToSend > 0) { remainingUsableEnergy -= electricalTile.injectEnergyUnits(direction, energyToSend * Compatibility.TO_IC2_RATIO) * Compatibility.IC2_RATIO; } } } } else if (tileEntity instanceof IPowerReceptor) { IPowerReceptor electricalTile = (IPowerReceptor) tileEntity; for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { TileEntity conductor = VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction); PowerReceiver receiver = electricalTile.getPowerReceiver(direction); if (receiver != null) { if (this.getConductors().contains(conductor)) { float energyToSend = totalUsableEnergy * ((receiver.powerRequest() * Compatibility.BC3_RATIO) / totalEnergyRequest); if (energyToSend > 0) { remainingUsableEnergy -= receiver.receiveEnergy(Type.PIPE, energyToSend * Compatibility.TO_BC_RATIO, direction) * Compatibility.BC3_RATIO; } } } } } else if (tileEntity instanceof IEnergyHandler) { IEnergyHandler receiver = (IEnergyHandler) tileEntity; for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { TileEntity conductor = VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction); if (receiver.canInterface(direction)) { if (this.getConductors().contains(conductor)) { float energyToSend = totalUsableEnergy * ((receiver.receiveEnergy(direction, (int) (remainingUsableEnergy * Compatibility.TO_TE_RATIO), true) * Compatibility.TE_RATIO) / totalEnergyRequest); if (energyToSend > 0) { remainingUsableEnergy -= receiver.receiveEnergy(direction, (int) (energyToSend * Compatibility.TO_TE_RATIO), false) * Compatibility.TE_RATIO; } } } } } } } else { markRefresh = true; } } if (markRefresh) { this.refresh(); } } } } return remainingUsableEnergy; } @Override public ElectricityPack getRequest(TileEntity... ignoreTiles) { List requests = new ArrayList(); Iterator it = new HashSet(this.getAcceptors()).iterator(); while (it.hasNext()) { TileEntity tileEntity = it.next(); if (Arrays.asList(ignoreTiles).contains(tileEntity)) { continue; } if (tileEntity != null && !tileEntity.isInvalid()) { if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) == tileEntity) { if (tileEntity instanceof IElectrical) { for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { if (((IElectrical) tileEntity).canConnect(direction) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) { requests.add(ElectricityPack.getFromWatts(((IElectrical) tileEntity).getRequest(direction), ((IElectrical) tileEntity).getVoltage())); } } continue; } if (tileEntity instanceof IEnergyHandler) { IEnergyHandler receiver = (IEnergyHandler) tileEntity; for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { TileEntity conductor = VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction); if (receiver.canInterface(direction) && this.getConductors().contains(conductor)) { ElectricityPack pack = ElectricityPack.getFromWatts(receiver.receiveEnergy(direction, (int) Integer.MAX_VALUE, true) * Compatibility.TE_RATIO, 1); if (pack.getWatts() > 0) { requests.add(pack); break; } } } continue; } if (tileEntity instanceof IEnergySink) { for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { if (((IEnergySink) tileEntity).acceptsEnergyFrom(VectorHelper.getTileEntityFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction), direction) && this.getConductors().contains(VectorHelper.getConnectorFromSide(tileEntity.worldObj, new Vector3(tileEntity), direction))) { ElectricityPack pack = ElectricityPack.getFromWatts((float) (((IEnergySink) tileEntity).demandedEnergyUnits() * Compatibility.IC2_RATIO), 1); if (pack.getWatts() > 0) { requests.add(pack); } } } continue; } if (tileEntity instanceof IPowerReceptor) { for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { if (((IPowerReceptor) tileEntity).getPowerReceiver(direction) != null) { ElectricityPack pack = ElectricityPack.getFromWatts(((IPowerReceptor) tileEntity).getPowerReceiver(direction).powerRequest() * Compatibility.BC3_RATIO, 1); if (pack.getWatts() > 0) { requests.add(pack); break; } } } continue; } } } } ElectricityPack mergedPack = ElectricityPack.merge(requests); ElectricityRequestEvent evt = new ElectricityRequestEvent(this, mergedPack, ignoreTiles); MinecraftForge.EVENT_BUS.post(evt); return mergedPack; } @Override public void refresh() { this.electricalTiles.clear(); try { Iterator it = this.getConductors().iterator(); while (it.hasNext()) { IConductor conductor = it.next(); if (conductor == null) { it.remove(); continue; } else if (((TileEntity) conductor).isInvalid() || ((TileEntity) conductor).getWorldObj() == null) { it.remove(); continue; } else if (((TileEntity) conductor).getWorldObj().getBlockTileEntity(((TileEntity) conductor).xCoord, ((TileEntity) conductor).yCoord, ((TileEntity) conductor).zCoord) != conductor) { it.remove(); continue; } else { conductor.setNetwork(this); } for (int i = 0; i < conductor.getAdjacentConnections().length; i++) { TileEntity acceptor = conductor.getAdjacentConnections()[i]; // The direction is from the perspective of the conductor. ForgeDirection direction = ForgeDirection.getOrientation(i); if (!(acceptor instanceof IConductor)) { if (acceptor instanceof IElectrical || acceptor instanceof IEnergyHandler || acceptor instanceof IEnergyAcceptor || acceptor instanceof IPowerReceptor) { ArrayList possibleDirections = null; if (this.electricalTiles.containsKey(acceptor)) { possibleDirections = this.electricalTiles.get(acceptor); } else { possibleDirections = new ArrayList(); } if (acceptor instanceof IElectrical && ((IElectrical) acceptor).canConnect(direction)) { possibleDirections.add(direction); } else if (acceptor instanceof IEnergyHandler && ((IEnergyHandler) acceptor).canInterface(direction)) { possibleDirections.add(direction); } else if (acceptor instanceof IEnergyAcceptor && ((IEnergyAcceptor) acceptor).acceptsEnergyFrom((TileEntity) conductor, direction)) { possibleDirections.add(direction); } else if (acceptor instanceof IPowerReceptor && ((IPowerReceptor) acceptor).getPowerReceiver(direction) != null) { possibleDirections.add(direction); } if (!possibleDirections.isEmpty()) { this.electricalTiles.put(acceptor, possibleDirections); } continue; } } } } } catch (Exception e) { FMLLog.severe("Universal Electricity: Failed to refresh conductor."); e.printStackTrace(); } } @Override public void merge(IElectricityNetwork network) { if (network != null && network != this) { UniversalNetwork newNetwork = new UniversalNetwork(); newNetwork.getConductors().addAll(this.getConductors()); newNetwork.getConductors().addAll(network.getConductors()); newNetwork.refresh(); } } @Override public void split(IConductor splitPoint) { if (splitPoint instanceof TileEntity) { this.getConductors().remove(splitPoint); /** * Loop through the connected blocks and attempt to see if there are connections between * the two points elsewhere. */ TileEntity[] connectedBlocks = splitPoint.getAdjacentConnections(); for (int i = 0; i < connectedBlocks.length; i++) { TileEntity connectedBlockA = connectedBlocks[i]; if (connectedBlockA instanceof INetworkConnection) { for (int ii = 0; ii < connectedBlocks.length; ii++) { final TileEntity connectedBlockB = connectedBlocks[ii]; if (connectedBlockA != connectedBlockB && connectedBlockB instanceof INetworkConnection) { Pathfinder finder = new PathfinderChecker(((TileEntity) splitPoint).worldObj, (INetworkConnection) connectedBlockB, splitPoint); finder.init(new Vector3(connectedBlockA)); if (finder.results.size() > 0) { /** * The connections A and B are still intact elsewhere. Set all * references of wire connection into one network. */ for (Vector3 node : finder.closedSet) { TileEntity nodeTile = node.getTileEntity(((TileEntity) splitPoint).worldObj); if (nodeTile instanceof INetworkProvider) { if (nodeTile != splitPoint) { ((INetworkProvider) nodeTile).setNetwork(this); } } } } else { /** * The connections A and B are not connected anymore. Give both of * them a new network. */ IElectricityNetwork newNetwork = new UniversalNetwork(); for (Vector3 node : finder.closedSet) { TileEntity nodeTile = node.getTileEntity(((TileEntity) splitPoint).worldObj); if (nodeTile instanceof INetworkProvider) { if (nodeTile != splitPoint) { newNetwork.getConductors().add((IConductor) nodeTile); } } } newNetwork.refresh(); } } } } } } } @Override public String toString() { return "UniversalNetwork[" + this.hashCode() + "|Wires:" + this.getConductors().size() + "|Acceptors:" + this.electricalTiles.size() + "]"; } }