blob: ef695f125ddfd6f086992cc62946bf959d6db264 [file] [log] [blame] [raw]
package universalelectricity.core.grid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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.IConnector;
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.path.Pathfinder;
import universalelectricity.core.path.PathfinderChecker;
import universalelectricity.core.vector.Vector3;
import universalelectricity.core.vector.VectorHelper;
import cpw.mods.fml.common.FMLLog;
/**
* An Electrical Network specifies a wire connection. Each wire connection line will have its own
* electrical network.
*
* !! Do not include this class if you do not intend to have custom wires in your mod. This will
* increase future compatibility. !!
*
* @author Calclavia
*
*/
public class ElectricityNetwork implements IElectricityNetwork
{
public Map<TileEntity, ArrayList<ForgeDirection>> electricalTiles = new HashMap<TileEntity, ArrayList<ForgeDirection>>();
private final Set<IConductor> conductors = new HashSet<IConductor>();
@Override
public float produce(ElectricityPack electricity, TileEntity... ignoreTiles)
{
ElectricityProductionEvent evt = new ElectricityProductionEvent(electricity, ignoreTiles);
MinecraftForge.EVENT_BUS.post(evt);
float energy = electricity.getWatts();
float totalEnergy = energy;
float voltage = electricity.voltage;
if (!evt.isCanceled())
{
Set<TileEntity> avaliableEnergyTiles = this.getAcceptors();
if (!avaliableEnergyTiles.isEmpty())
{
final float totalEnergyRequest = this.getRequest(ignoreTiles).getWatts();
if (totalEnergyRequest > 0)
{
for (TileEntity tileEntity : avaliableEnergyTiles)
{
if (tileEntity instanceof IElectrical && !Arrays.asList(ignoreTiles).contains(tileEntity))
{
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 = totalEnergy * (electricalTile.getRequest(direction) / totalEnergyRequest);
if (energyToSend > 0)
{
ElectricityPack electricityToSend = ElectricityPack.getFromWatts(energyToSend, voltage);
// Calculate energy loss caused by resistance.
float ampsReceived = electricityToSend.amperes - (electricityToSend.amperes * electricityToSend.amperes * this.getTotalResistance()) / electricityToSend.voltage;
float voltsReceived = electricityToSend.voltage - (electricityToSend.amperes * this.getTotalResistance());
electricityToSend = new ElectricityPack(ampsReceived, voltsReceived);
energy -= ((IElectrical) tileEntity).receiveElectricity(direction, electricityToSend, true);
}
}
}
}
}
}
}
}
return energy;
}
/**
* @return How much electricity this network needs.
*/
@Override
public ElectricityPack getRequest(TileEntity... ignoreTiles)
{
List<ElectricityPack> requests = new ArrayList<ElectricityPack>();
Iterator<TileEntity> it = this.getAcceptors().iterator();
while (it.hasNext())
{
TileEntity tileEntity = it.next();
if (Arrays.asList(ignoreTiles).contains(tileEntity))
{
continue;
}
if (tileEntity instanceof IElectrical)
{
if (!tileEntity.isInvalid())
{
if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) == tileEntity)
{
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;
}
}
}
}
}
}
ElectricityPack mergedPack = ElectricityPack.merge(requests);
ElectricityRequestEvent evt = new ElectricityRequestEvent(mergedPack, ignoreTiles);
MinecraftForge.EVENT_BUS.post(evt);
return mergedPack;
}
/**
* @return Returns all producers in this electricity network.
*/
@Override
public Set<TileEntity> getAcceptors()
{
return this.electricalTiles.keySet();
}
/**
* @param tile The tile to get connections for
* @return The list of directions that can be connected to for the provided tile
*/
@Override
public ArrayList<ForgeDirection> getPossibleDirections(TileEntity tile)
{
return this.electricalTiles.containsKey(tile) ? this.electricalTiles.get(tile) : null;
}
/**
* This function is called to refresh all conductors in this network
*/
@Override
public void refresh()
{
this.electricalTiles.clear();
try
{
Iterator<IConductor> it = this.conductors.iterator();
while (it.hasNext())
{
IConductor conductor = it.next();
if (conductor == null)
{
it.remove();
}
else if (((TileEntity) conductor).isInvalid())
{
it.remove();
}
else
{
conductor.setNetwork(this);
}
for (int i = 0; i < conductor.getAdjacentConnections().length; i++)
{
TileEntity acceptor = conductor.getAdjacentConnections()[i];
if (!(acceptor instanceof IConductor) && acceptor instanceof IConnector)
{
ArrayList<ForgeDirection> possibleDirections = null;
if (this.electricalTiles.containsKey(acceptor))
{
possibleDirections = this.electricalTiles.get(acceptor);
}
else
{
possibleDirections = new ArrayList<ForgeDirection>();
}
possibleDirections.add(ForgeDirection.getOrientation(i));
this.electricalTiles.put(acceptor, possibleDirections);
}
}
}
}
catch (Exception e)
{
FMLLog.severe("Universal Electricity: Failed to refresh conductor.");
e.printStackTrace();
}
}
@Override
public float getTotalResistance()
{
float resistance = 0;
for (IConductor conductor : this.conductors)
{
resistance += conductor.getResistance();
}
return resistance;
}
@Override
public float getLowestCurrentCapacity()
{
float lowestAmperage = 0;
for (IConductor conductor : this.conductors)
{
if (lowestAmperage == 0 || conductor.getCurrentCapacity() < lowestAmperage)
{
lowestAmperage = conductor.getCurrentCapacity();
}
}
return lowestAmperage;
}
@Override
public Set<IConductor> getConductors()
{
return this.conductors;
}
@Override
public void merge(IElectricityNetwork network)
{
if (network != null && network != this)
{
ElectricityNetwork newNetwork = new ElectricityNetwork();
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 ElectricityNetwork();
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 "ElectricityNetwork[" + this.hashCode() + "|Wires:" + this.conductors.size() + "|Acceptors:" + this.electricalTiles.size() + "]";
}
}