blob: 6bc3bff1a91b6563a2aa2def2500bc175a7a16f1 [file] [log] [blame] [raw]
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<TileEntity> 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<ElectricityPack> requests = new ArrayList<ElectricityPack>();
Iterator<TileEntity> 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<IConductor> 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<ForgeDirection> possibleDirections = null;
if (this.electricalTiles.containsKey(acceptor))
{
possibleDirections = this.electricalTiles.get(acceptor);
}
else
{
possibleDirections = new ArrayList<ForgeDirection>();
}
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() + "]";
}
}