| package universalelectricity.electricity; | |
| import java.util.ArrayList; | |
| import java.util.EnumSet; | |
| import java.util.HashMap; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.Map; | |
| import net.minecraft.src.TileEntity; | |
| import net.minecraftforge.common.ForgeDirection; | |
| import universalelectricity.core.Vector3; | |
| import universalelectricity.implement.IConductor; | |
| import universalelectricity.implement.IElectricityReceiver; | |
| import cpw.mods.fml.common.FMLLog; | |
| import cpw.mods.fml.common.TickType; | |
| /** | |
| * This class is used to manage electricity | |
| * transferring and flow. It is also used to call | |
| * updates on UE tile entities. | |
| * | |
| * @author Calclavia | |
| * | |
| */ | |
| public class ElectricityManager | |
| { | |
| /** | |
| * ElectricityManager exists on both client | |
| * and server side. Rely on the server side | |
| * one as it is more accurate! Client side | |
| * only simulates. | |
| */ | |
| public static ElectricityManager instance; | |
| private List<ElectricityTransferData> electricityTransferQueue = new ArrayList<ElectricityTransferData>(); | |
| private List<ElectricityNetwork> electricityNetworks = new ArrayList<ElectricityNetwork>(); | |
| public ElectricityManager() | |
| { | |
| System.out.println("Universal Electricity's Electricity Manager Initiated."); | |
| } | |
| /** | |
| * Registers a the conductor into the UE | |
| * electricity net. | |
| * | |
| * @param conductor | |
| * - The IConductor tile entity. | |
| */ | |
| public void registerConductor(IConductor newConductor) | |
| { | |
| cleanUpConnections(); | |
| this.electricityNetworks.add(new ElectricityNetwork(newConductor)); | |
| } | |
| /** | |
| * Merges two connection lines together into | |
| * one. | |
| * | |
| * @param networkA | |
| * - The network to be merged into. | |
| * This network will be kept. | |
| * @param networkB | |
| * - The network to be merged. This | |
| * network will be deleted. | |
| */ | |
| public void mergeConnection(ElectricityNetwork networkA, ElectricityNetwork networkB) | |
| { | |
| if (networkA != networkB) | |
| { | |
| if (networkA != null && networkB != null) | |
| { | |
| networkA.conductors.addAll(networkB.conductors); | |
| networkA.setNetwork(); | |
| this.electricityNetworks.remove(networkB); | |
| networkB = null; | |
| } | |
| else | |
| { | |
| System.err.println("Failed to merge Universal Electricity wire connections!"); | |
| } | |
| } | |
| } | |
| /** | |
| * Separate one connection line into two | |
| * different ones between two conductors. This | |
| * function does this by resetting all wires | |
| * in the connection line and making them each | |
| * reconnect. | |
| * | |
| * @param conductorA | |
| * - existing conductor | |
| * @param conductorB | |
| * - broken/invalid conductor | |
| */ | |
| public void splitConnection(IConductor conductorA, IConductor conductorB) | |
| { | |
| ElectricityNetwork connection = conductorA.getNetwork(); | |
| if (connection != null) | |
| { | |
| connection.cleanUpArray(); | |
| for (IConductor conductor : connection.conductors) | |
| { | |
| conductor.reset(); | |
| } | |
| for (IConductor conductor : connection.conductors) | |
| { | |
| for (byte i = 0; i < 6; i++) | |
| { | |
| conductor.updateConnectionWithoutSplit(Vector3.getConnectorFromSide(conductor.getWorld(), new Vector3(((TileEntity) conductor).xCoord, ((TileEntity) conductor).yCoord, ((TileEntity) conductor).zCoord), ForgeDirection.getOrientation(i)), ForgeDirection.getOrientation(i)); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| FMLLog.severe("Conductor invalid network while splitting connection!"); | |
| } | |
| } | |
| /** | |
| * Clean up and remove all useless and invalid | |
| * connections. | |
| */ | |
| public void cleanUpConnections() | |
| { | |
| try | |
| { | |
| for (int i = 0; i < this.electricityNetworks.size(); i++) | |
| { | |
| this.electricityNetworks.get(i).cleanUpArray(); | |
| if (this.electricityNetworks.get(i).conductors.size() == 0) | |
| { | |
| this.electricityNetworks.remove(i); | |
| } | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| FMLLog.severe("Failed to clean up wire connections!"); | |
| } | |
| } | |
| /** | |
| * Produces electricity into a specific wire | |
| * which will be distributed across the | |
| * electricity network. | |
| * | |
| * @param sender | |
| * The machine sending the | |
| * electricity. | |
| * @param targetConductor | |
| * The conductor receiving the | |
| * electricity (or connected to the | |
| * machine). | |
| * @param amps | |
| * The amount of amps this machine | |
| * is sending. | |
| * @param voltage | |
| * The amount of volts this machine | |
| * is sending. | |
| */ | |
| public void produceElectricity(TileEntity sender, IConductor targetConductor, double amps, double voltage) | |
| { | |
| if (targetConductor != null && amps > 0 && voltage > 0) | |
| { | |
| // Find a path between this conductor | |
| // and all connected units and | |
| // try to send the electricity to them | |
| // directly | |
| ElectricityNetwork electricityNetwork = targetConductor.getNetwork(); | |
| if (electricityNetwork != null) | |
| { | |
| List<IElectricityReceiver> allElectricUnitsInLine = electricityNetwork.getConnectedReceivers(); | |
| double leftOverAmps = amps; | |
| for (IConductor conductor : electricityNetwork.conductors) | |
| { | |
| for (byte i = 0; i < conductor.getConnectedBlocks().length; i++) | |
| { | |
| TileEntity tileEntity = conductor.getConnectedBlocks()[i]; | |
| if (tileEntity != null) | |
| { | |
| if (tileEntity instanceof IElectricityReceiver) | |
| { | |
| IElectricityReceiver receiver = (IElectricityReceiver) tileEntity; | |
| if (this.getActualWattRequest(receiver) > 0 && receiver.canReceiveFromSide(ForgeDirection.getOrientation(i).getOpposite())) | |
| { | |
| double transferAmps = Math.max(0, Math.min(leftOverAmps, Math.min(amps / allElectricUnitsInLine.size(), ElectricInfo.getAmps(this.getActualWattRequest(receiver), receiver.getVoltage())))); | |
| leftOverAmps -= transferAmps; | |
| // Calculate | |
| // electricity | |
| // loss | |
| double distance = Vector3.distance(Vector3.get(sender), Vector3.get((TileEntity) receiver)); | |
| double ampsReceived = transferAmps - (transferAmps * transferAmps * targetConductor.getResistance() * distance) / voltage; | |
| double voltsReceived = voltage - (transferAmps * targetConductor.getResistance() * distance); | |
| this.electricityTransferQueue.add(new ElectricityTransferData(sender, receiver, electricityNetwork, ForgeDirection.getOrientation(i).getOpposite(), ampsReceived, voltsReceived)); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| FMLLog.severe("Conductor not registered to a network!"); | |
| } | |
| } | |
| } | |
| /** | |
| * Gets the actual watt request of an electric | |
| * receiver accounting all current electricity | |
| * packets qued up for it. | |
| * | |
| * @return - The amount of watts requested. | |
| */ | |
| public double getActualWattRequest(IElectricityReceiver receiver) | |
| { | |
| double wattsRequest = receiver.wattRequest(); | |
| try | |
| { | |
| for (int i = 0; i < electricityTransferQueue.size(); i++) | |
| { | |
| if (electricityTransferQueue.get(i) != null) | |
| { | |
| if (electricityTransferQueue.get(i).isValid()) | |
| { | |
| if (electricityTransferQueue.get(i).receiver == receiver) | |
| { | |
| wattsRequest -= electricityTransferQueue.get(i).amps * electricityTransferQueue.get(i).voltage; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| FMLLog.severe("Failed to get watt request!"); | |
| } | |
| return Math.max(Math.min(wattsRequest, receiver.wattRequest()), 0); | |
| } | |
| /** | |
| * Checks if the current connection line needs | |
| * electricity | |
| * | |
| * @return - The amount of joules this | |
| * connection line needs | |
| */ | |
| public double getElectricityRequired(ElectricityNetwork network) | |
| { | |
| double need = 0; | |
| if (network != null) | |
| { | |
| for (IConductor conductor : network.conductors) | |
| { | |
| for (byte i = 0; i < conductor.getConnectedBlocks().length; i++) | |
| { | |
| TileEntity tileEntity = conductor.getConnectedBlocks()[i]; | |
| if (tileEntity != null) | |
| { | |
| if (tileEntity instanceof IElectricityReceiver) | |
| { | |
| IElectricityReceiver electricUnit = (IElectricityReceiver) tileEntity; | |
| if (electricUnit.canReceiveFromSide(ForgeDirection.getOrientation(i).getOpposite())) | |
| { | |
| need += electricUnit.wattRequest(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return need; | |
| } | |
| public double getActualElectricityRequired(ElectricityNetwork network) | |
| { | |
| double need = 0; | |
| if (network != null) | |
| { | |
| for (IConductor conductor : network.conductors) | |
| { | |
| for (byte i = 0; i < conductor.getConnectedBlocks().length; i++) | |
| { | |
| TileEntity tileEntity = conductor.getConnectedBlocks()[i]; | |
| if (tileEntity != null) | |
| { | |
| if (tileEntity instanceof IElectricityReceiver) | |
| { | |
| IElectricityReceiver electricUnit = (IElectricityReceiver) tileEntity; | |
| if (electricUnit.canReceiveFromSide(ForgeDirection.getOrientation(i).getOpposite())) | |
| { | |
| need += this.getActualWattRequest(electricUnit); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return need; | |
| } | |
| /** | |
| * This function is called to refresh all | |
| * conductors in the world. | |
| */ | |
| public void refreshConductors() | |
| { | |
| try | |
| { | |
| Iterator it = electricityNetworks.iterator(); | |
| while (it.hasNext()) | |
| { | |
| ((ElectricityNetwork) it.next()).refreshConductors(); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| FMLLog.fine("Failed to refresh conductors."); | |
| } | |
| } | |
| public void onTick(EnumSet<TickType> type, Object... tickData) | |
| { | |
| if (type.contains(TickType.WORLD) && !type.contains(TickType.WORLDLOAD)) | |
| { | |
| if (ElectricityManagerTicker.inGameTicks % 40 == 0) | |
| { | |
| this.refreshConductors(); | |
| } | |
| try | |
| { | |
| HashMap conductorAmpData = new HashMap<ElectricityNetwork, Double>(); | |
| for (int i = 0; i < electricityTransferQueue.size(); i++) | |
| { | |
| if (electricityTransferQueue.get(i) != null) | |
| { | |
| if (electricityTransferQueue.get(i).isValid()) | |
| { | |
| double amps = electricityTransferQueue.get(i).amps; | |
| if (conductorAmpData.containsKey(electricityTransferQueue.get(i).network)) | |
| { | |
| amps += (Double) conductorAmpData.get(electricityTransferQueue.get(i).network); | |
| } | |
| conductorAmpData.put(electricityTransferQueue.get(i).network, amps); | |
| electricityTransferQueue.get(i).receiver.onReceive(electricityTransferQueue.get(i).sender, electricityTransferQueue.get(i).amps, electricityTransferQueue.get(i).voltage, electricityTransferQueue.get(i).side); | |
| } | |
| } | |
| electricityTransferQueue.remove(i); | |
| } | |
| Iterator it = conductorAmpData.entrySet().iterator(); | |
| while (it.hasNext()) | |
| { | |
| Map.Entry pairs = (Map.Entry) it.next(); | |
| if (pairs.getKey() != null && pairs.getValue() != null) | |
| { | |
| if (pairs.getKey() instanceof ElectricityNetwork && pairs.getValue() instanceof Double) | |
| { | |
| if (((Double) pairs.getValue()) > ((ElectricityNetwork) pairs.getKey()).getLowestAmpConductor()) | |
| { | |
| ((ElectricityNetwork) pairs.getKey()).onOverCharge(); | |
| } | |
| } | |
| } | |
| it.remove(); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| System.err.println("Failed to transfer electricity to receivers."); | |
| e.printStackTrace(); | |
| } | |
| } | |
| if (ElectricityManagerTicker.inGameTicks == 0) | |
| { | |
| this.refreshConductors(); | |
| } | |
| } | |
| } |