511 lines
12 KiB
Java
511 lines
12 KiB
Java
package universalelectricity.core.electricity;
|
|
|
|
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 universalelectricity.core.block.IConductor;
|
|
import universalelectricity.core.block.IConnectionProvider;
|
|
import universalelectricity.core.block.INetworkProvider;
|
|
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
|
|
{
|
|
private final HashMap<TileEntity, ElectricityPack> producers = new HashMap<TileEntity, ElectricityPack>();
|
|
private final HashMap<TileEntity, ElectricityPack> consumers = new HashMap<TileEntity, ElectricityPack>();
|
|
|
|
private final Set<IConductor> conductors = new HashSet<IConductor>();
|
|
|
|
public ElectricityNetwork()
|
|
{
|
|
|
|
}
|
|
|
|
public ElectricityNetwork(IConductor... conductors)
|
|
{
|
|
this.conductors.addAll(Arrays.asList(conductors));
|
|
}
|
|
|
|
@Override
|
|
public void startProducing(TileEntity tileEntity, ElectricityPack electricityPack)
|
|
{
|
|
if (tileEntity != null && electricityPack.getWatts() > 0)
|
|
{
|
|
this.producers.put(tileEntity, electricityPack);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void startProducing(TileEntity tileEntity, double amperes, double voltage)
|
|
{
|
|
this.startProducing(tileEntity, new ElectricityPack(amperes, voltage));
|
|
}
|
|
|
|
@Override
|
|
public boolean isProducing(TileEntity tileEntity)
|
|
{
|
|
return this.producers.containsKey(tileEntity);
|
|
}
|
|
|
|
/**
|
|
* Sets this tile entity to stop producing energy in this network.
|
|
*/
|
|
@Override
|
|
public void stopProducing(TileEntity tileEntity)
|
|
{
|
|
this.producers.remove(tileEntity);
|
|
}
|
|
|
|
/**
|
|
* Sets this tile entity to start producing energy in this network.
|
|
*/
|
|
@Override
|
|
public void startRequesting(TileEntity tileEntity, ElectricityPack electricityPack)
|
|
{
|
|
if (tileEntity != null && electricityPack.getWatts() > 0)
|
|
{
|
|
this.consumers.put(tileEntity, electricityPack);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void startRequesting(TileEntity tileEntity, double amperes, double voltage)
|
|
{
|
|
this.startRequesting(tileEntity, new ElectricityPack(amperes, voltage));
|
|
}
|
|
|
|
@Override
|
|
public boolean isRequesting(TileEntity tileEntity)
|
|
{
|
|
return this.consumers.containsKey(tileEntity);
|
|
}
|
|
|
|
/**
|
|
* Sets this tile entity to stop producing energy in this network.
|
|
*/
|
|
@Override
|
|
public void stopRequesting(TileEntity tileEntity)
|
|
{
|
|
this.consumers.remove(tileEntity);
|
|
}
|
|
|
|
/**
|
|
* @param ignoreTiles The TileEntities to ignore during this calculation. Null will make it not
|
|
* ignore any.
|
|
* @return The electricity produced in this electricity network
|
|
*/
|
|
@Override
|
|
public ElectricityPack getProduced(TileEntity... ignoreTiles)
|
|
{
|
|
ElectricityPack totalElectricity = new ElectricityPack(0, 0);
|
|
|
|
Iterator it = this.producers.entrySet().iterator();
|
|
|
|
loop:
|
|
while (it.hasNext())
|
|
{
|
|
Map.Entry pairs = (Map.Entry) it.next();
|
|
|
|
if (pairs != null)
|
|
{
|
|
TileEntity tileEntity = (TileEntity) pairs.getKey();
|
|
|
|
if (tileEntity == null)
|
|
{
|
|
it.remove();
|
|
continue;
|
|
}
|
|
|
|
if (tileEntity.isInvalid())
|
|
{
|
|
it.remove();
|
|
continue;
|
|
}
|
|
|
|
if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) != tileEntity)
|
|
{
|
|
it.remove();
|
|
continue;
|
|
}
|
|
|
|
if (ignoreTiles != null)
|
|
{
|
|
for (TileEntity ignoreTile : ignoreTiles)
|
|
{
|
|
if (tileEntity == ignoreTile)
|
|
{
|
|
continue loop;
|
|
}
|
|
}
|
|
}
|
|
|
|
ElectricityPack pack = (ElectricityPack) pairs.getValue();
|
|
|
|
if (pairs.getKey() != null && pairs.getValue() != null && pack != null)
|
|
{
|
|
double newWatts = totalElectricity.getWatts() + pack.getWatts();
|
|
double newVoltage = Math.max(totalElectricity.voltage, pack.voltage);
|
|
|
|
totalElectricity.amperes = newWatts / newVoltage;
|
|
totalElectricity.voltage = newVoltage;
|
|
}
|
|
}
|
|
}
|
|
|
|
return totalElectricity;
|
|
}
|
|
|
|
/**
|
|
* @return How much electricity this network needs.
|
|
*/
|
|
@Override
|
|
public ElectricityPack getRequest(TileEntity... ignoreTiles)
|
|
{
|
|
ElectricityPack totalElectricity = this.getRequestWithoutReduction();
|
|
totalElectricity.amperes = Math.max(totalElectricity.amperes - this.getProduced(ignoreTiles).amperes, 0);
|
|
return totalElectricity;
|
|
}
|
|
|
|
@Override
|
|
public ElectricityPack getRequestWithoutReduction()
|
|
{
|
|
ElectricityPack totalElectricity = new ElectricityPack(0, 0);
|
|
|
|
Iterator it = this.consumers.entrySet().iterator();
|
|
|
|
while (it.hasNext())
|
|
{
|
|
Map.Entry pairs = (Map.Entry) it.next();
|
|
|
|
if (pairs != null)
|
|
{
|
|
TileEntity tileEntity = (TileEntity) pairs.getKey();
|
|
|
|
if (tileEntity == null)
|
|
{
|
|
it.remove();
|
|
continue;
|
|
}
|
|
|
|
if (tileEntity.isInvalid())
|
|
{
|
|
it.remove();
|
|
continue;
|
|
}
|
|
|
|
if (tileEntity.worldObj.getBlockTileEntity(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord) != tileEntity)
|
|
{
|
|
it.remove();
|
|
continue;
|
|
}
|
|
|
|
ElectricityPack pack = (ElectricityPack) pairs.getValue();
|
|
|
|
if (pack != null)
|
|
{
|
|
totalElectricity.amperes += pack.amperes;
|
|
totalElectricity.voltage = Math.max(totalElectricity.voltage, pack.voltage);
|
|
}
|
|
}
|
|
}
|
|
|
|
return totalElectricity;
|
|
}
|
|
|
|
/**
|
|
* @param tileEntity
|
|
* @return The electricity being input into this tile entity.
|
|
*/
|
|
@Override
|
|
public ElectricityPack consumeElectricity(TileEntity tileEntity)
|
|
{
|
|
ElectricityPack totalElectricity = new ElectricityPack(0, 0);
|
|
|
|
try
|
|
{
|
|
ElectricityPack tileRequest = this.consumers.get(tileEntity);
|
|
|
|
if (this.consumers.containsKey(tileEntity) && tileRequest != null)
|
|
{
|
|
// Calculate the electricity this TileEntity is receiving in percentage.
|
|
totalElectricity = this.getProduced();
|
|
|
|
if (totalElectricity.getWatts() > 0)
|
|
{
|
|
ElectricityPack totalRequest = this.getRequestWithoutReduction();
|
|
totalElectricity.amperes *= (tileRequest.amperes / totalRequest.amperes);
|
|
|
|
double ampsReceived = totalElectricity.amperes - (totalElectricity.amperes * totalElectricity.amperes * this.getTotalResistance()) / totalElectricity.voltage;
|
|
double voltsReceived = totalElectricity.voltage - (totalElectricity.amperes * this.getTotalResistance());
|
|
|
|
totalElectricity.amperes = ampsReceived;
|
|
totalElectricity.voltage = voltsReceived;
|
|
|
|
return totalElectricity;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
FMLLog.severe("Failed to consume electricity!");
|
|
e.printStackTrace();
|
|
}
|
|
|
|
return totalElectricity;
|
|
}
|
|
|
|
/**
|
|
* @return Returns all producers in this electricity network.
|
|
*/
|
|
@Override
|
|
public HashMap<TileEntity, ElectricityPack> getProducers()
|
|
{
|
|
return this.producers;
|
|
}
|
|
|
|
/**
|
|
* Gets all the electricity receivers.
|
|
*/
|
|
@Override
|
|
public List<TileEntity> getProviders()
|
|
{
|
|
List<TileEntity> providers = new ArrayList<TileEntity>();
|
|
providers.addAll(this.producers.keySet());
|
|
return providers;
|
|
}
|
|
|
|
/**
|
|
* @return Returns all consumers in this electricity network.
|
|
*/
|
|
@Override
|
|
public HashMap<TileEntity, ElectricityPack> getConsumers()
|
|
{
|
|
return this.consumers;
|
|
}
|
|
|
|
/**
|
|
* Gets all the electricity receivers.
|
|
*/
|
|
@Override
|
|
public List<TileEntity> getReceivers()
|
|
{
|
|
List<TileEntity> receivers = new ArrayList<TileEntity>();
|
|
receivers.addAll(this.consumers.keySet());
|
|
return receivers;
|
|
}
|
|
|
|
@Override
|
|
public void cleanUpConductors()
|
|
{
|
|
Iterator it = this.conductors.iterator();
|
|
|
|
while (it.hasNext())
|
|
{
|
|
IConductor conductor = (IConductor) it.next();
|
|
|
|
if (conductor == null)
|
|
{
|
|
it.remove();
|
|
}
|
|
else if (((TileEntity) conductor).isInvalid())
|
|
{
|
|
it.remove();
|
|
}
|
|
else
|
|
{
|
|
conductor.setNetwork(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function is called to refresh all conductors in this network
|
|
*/
|
|
@Override
|
|
public void refreshConductors()
|
|
{
|
|
this.cleanUpConductors();
|
|
|
|
try
|
|
{
|
|
Iterator<IConductor> it = this.conductors.iterator();
|
|
|
|
while (it.hasNext())
|
|
{
|
|
IConductor conductor = it.next();
|
|
conductor.updateAdjacentConnections();
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
FMLLog.severe("Universal Electricity: Failed to refresh conductor.");
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public double getTotalResistance()
|
|
{
|
|
double resistance = 0;
|
|
|
|
for (IConductor conductor : this.conductors)
|
|
{
|
|
resistance += conductor.getResistance();
|
|
}
|
|
|
|
return resistance;
|
|
}
|
|
|
|
@Override
|
|
public double getLowestCurrentCapacity()
|
|
{
|
|
double lowestAmp = 0;
|
|
|
|
for (IConductor conductor : this.conductors)
|
|
{
|
|
if (lowestAmp == 0 || conductor.getCurrentCapcity() < lowestAmp)
|
|
{
|
|
lowestAmp = conductor.getCurrentCapcity();
|
|
}
|
|
}
|
|
|
|
return lowestAmp;
|
|
}
|
|
|
|
@Override
|
|
public Set<IConductor> getConductors()
|
|
{
|
|
return this.conductors;
|
|
}
|
|
|
|
@Override
|
|
public void mergeConnection(IElectricityNetwork network)
|
|
{
|
|
if (network != null && network != this)
|
|
{
|
|
ElectricityNetwork newNetwork = new ElectricityNetwork();
|
|
newNetwork.getConductors().addAll(this.getConductors());
|
|
newNetwork.getConductors().addAll(network.getConductors());
|
|
newNetwork.cleanUpConductors();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void splitNetwork(IConnectionProvider splitPoint)
|
|
{
|
|
if (splitPoint instanceof TileEntity)
|
|
{
|
|
this.getConductors().remove(splitPoint);
|
|
|
|
for (ForgeDirection dir : ForgeDirection.values())
|
|
{
|
|
if (dir != ForgeDirection.UNKNOWN)
|
|
{
|
|
Vector3 splitVec = new Vector3((TileEntity) splitPoint);
|
|
TileEntity tileAroundSplit = VectorHelper.getTileEntityFromSide(((TileEntity) splitPoint).worldObj, splitVec, dir);
|
|
|
|
if (this.producers.containsKey(tileAroundSplit))
|
|
{
|
|
this.stopProducing(tileAroundSplit);
|
|
this.stopRequesting(tileAroundSplit);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 IConnectionProvider)
|
|
{
|
|
for (int ii = 0; ii < connectedBlocks.length; ii++)
|
|
{
|
|
final TileEntity connectedBlockB = connectedBlocks[ii];
|
|
|
|
if (connectedBlockA != connectedBlockB && connectedBlockB instanceof IConnectionProvider)
|
|
{
|
|
Pathfinder finder = new PathfinderChecker(((TileEntity) splitPoint).worldObj, (IConnectionProvider) 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.cleanUpConductors();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return "ElectricityNetwork[" + this.hashCode() + "|Wires:" + this.conductors.size() + "]";
|
|
}
|
|
|
|
}
|