blob: 563e456bb9d6aa085df645504e79ea4c9a4a01d3 [file] [log] [blame] [raw]
package mekanism.common.util;
import ic2.api.energy.tile.IEnergyAcceptor;
import ic2.api.energy.tile.IEnergySink;
import ic2.api.energy.tile.IEnergySource;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import mekanism.api.Coord4D;
import mekanism.api.energy.ICableOutputter;
import mekanism.api.energy.IStrictEnergyAcceptor;
import mekanism.api.transmitters.IGridTransmitter;
import mekanism.api.transmitters.TransmissionType;
import mekanism.common.Mekanism;
import mekanism.common.tile.TileEntityElectricBlock;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import buildcraft.api.power.IPowerEmitter;
import buildcraft.api.power.IPowerReceptor;
import buildcraft.api.power.PowerHandler.PowerReceiver;
import buildcraft.api.power.PowerHandler.Type;
import cofh.api.energy.IEnergyHandler;
public final class CableUtils
{
private static Set<ForgeDirection> allSides;
static
{
allSides = EnumSet.allOf(ForgeDirection.class);
allSides.remove(ForgeDirection.UNKNOWN);
}
/**
* Gets all the connected energy acceptors, whether IC2-based or BuildCraft-based, surrounding a specific tile entity.
* @param tileEntity - center tile entity
* @return TileEntity[] of connected acceptors
*/
public static TileEntity[] getConnectedEnergyAcceptors(TileEntity tileEntity)
{
TileEntity[] acceptors = new TileEntity[] {null, null, null, null, null, null};
for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity acceptor = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj());
if(isEnergyAcceptor(acceptor))
{
acceptors[orientation.ordinal()] = acceptor;
}
}
return acceptors;
}
public static boolean isEnergyAcceptor(TileEntity tileEntity)
{
return (tileEntity instanceof IStrictEnergyAcceptor ||
(MekanismUtils.useIC2() && tileEntity instanceof IEnergySink) ||
(MekanismUtils.useBuildCraft() && tileEntity instanceof IPowerReceptor && !(tileEntity instanceof IGridTransmitter)) ||
(MekanismUtils.useRF() && tileEntity instanceof IEnergyHandler));
}
/**
* Gets all the connected cables around a specific tile entity.
* @param tileEntity - center tile entity
* @return TileEntity[] of connected cables
*/
public static TileEntity[] getConnectedCables(TileEntity tileEntity)
{
TileEntity[] cables = new TileEntity[] {null, null, null, null, null, null};
for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity cable = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj());
if(isCable(cable))
{
cables[orientation.ordinal()] = cable;
}
}
return cables;
}
public static boolean isCable(TileEntity tileEntity)
{
return TransmissionType.checkTransmissionType(tileEntity, TransmissionType.ENERGY);
}
/**
* Gets all the adjacent connections to a TileEntity.
* @param tileEntity - center TileEntity
* @return boolean[] of adjacent connections
*/
public static boolean[] getConnections(TileEntity tileEntity)
{
return getConnections(tileEntity, allSides);
}
/**
* Gets the adjacent connections to a TileEntity, from a subset of its sides.
* @param tileEntity - center TileEntity
* @param sides - set of sides to check
* @return boolean[] of adjacent connections
*/
public static boolean[] getConnections(TileEntity tileEntity, Set<ForgeDirection> sides)
{
boolean[] connectable = new boolean[] {false, false, false, false, false, false};
Coord4D coord = Coord4D.get(tileEntity);
for(ForgeDirection side : sides)
{
TileEntity tile = coord.getFromSide(side).getTileEntity(tileEntity.getWorldObj());
connectable[side.ordinal()] |= isEnergyAcceptor(tile) && isConnectable(tileEntity, tile, side);
connectable[side.ordinal()] |= isCable(tile);
connectable[side.ordinal()] |= isOutputter(tile, side);
}
return connectable;
}
/**
* Gets all the connected cables around a specific tile entity.
* @param tileEntity - center tile entity
* @return TileEntity[] of connected cables
*/
public static TileEntity[] getConnectedOutputters(TileEntity tileEntity)
{
TileEntity[] outputters = new TileEntity[] {null, null, null, null, null, null};
for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity outputter = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj());
if(isOutputter(outputter, orientation))
{
outputters[orientation.ordinal()] = outputter;
}
}
return outputters;
}
public static boolean isOutputter(TileEntity tileEntity, ForgeDirection side)
{
return (tileEntity instanceof ICableOutputter && ((ICableOutputter)tileEntity).canOutputTo(side.getOpposite())) ||
(MekanismUtils.useIC2() && tileEntity instanceof IEnergySource && ((IEnergySource)tileEntity).emitsEnergyTo(null, side.getOpposite())) ||
(MekanismUtils.useRF() && tileEntity instanceof IEnergyHandler && ((IEnergyHandler)tileEntity).canConnectEnergy(side.getOpposite())) ||
(MekanismUtils.useBuildCraft() && tileEntity instanceof IPowerEmitter && ((IPowerEmitter)tileEntity).canEmitPowerFrom(side.getOpposite()));
}
/**
* Whether or not a cable can connect to a specific acceptor.
* @param side - side to check
* @param tile - cable TileEntity
* @return whether or not the cable can connect to the specific side
*/
public static boolean canConnectToAcceptor(ForgeDirection side, TileEntity tile)
{
if(tile == null)
{
return false;
}
TileEntity tileEntity = Coord4D.get(tile).getFromSide(side).getTileEntity(tile.getWorldObj());
return isConnectable(tile, tileEntity, side);
}
public static boolean isConnectable(TileEntity orig, TileEntity tileEntity, ForgeDirection side)
{
if(tileEntity instanceof IGridTransmitter)
{
return false;
}
if(tileEntity instanceof IStrictEnergyAcceptor)
{
if(((IStrictEnergyAcceptor)tileEntity).canReceiveEnergy(side.getOpposite()))
{
return true;
}
}
else if(MekanismUtils.useIC2() && tileEntity instanceof IEnergyAcceptor)
{
if(((IEnergyAcceptor)tileEntity).acceptsEnergyFrom(orig, side.getOpposite()))
{
return true;
}
}
else if(tileEntity instanceof ICableOutputter)
{
if(((ICableOutputter)tileEntity).canOutputTo(side.getOpposite()))
{
return true;
}
}
else if(MekanismUtils.useRF() && tileEntity instanceof IEnergyHandler)
{
if(((IEnergyHandler)tileEntity).canConnectEnergy(side.getOpposite()))
{
return true;
}
}
else if(MekanismUtils.useBuildCraft() && tileEntity instanceof IPowerReceptor)
{
if(((IPowerReceptor)tileEntity).getPowerReceiver(side.getOpposite()) != null)
{
return true;
}
}
return false;
}
public static void emit(TileEntityElectricBlock emitter)
{
if(!emitter.getWorldObj().isRemote && MekanismUtils.canFunction(emitter))
{
double sendingEnergy = Math.min(emitter.getEnergy(), emitter.getMaxOutput());
if(sendingEnergy > 0)
{
List<ForgeDirection> outputtingSides = new ArrayList<ForgeDirection>();
boolean[] connectable = getConnections(emitter, emitter.getOutputtingSides());
for(ForgeDirection side : emitter.getOutputtingSides())
{
if(connectable[side.ordinal()])
{
outputtingSides.add(side);
}
}
if(outputtingSides.size() > 0)
{
double sent = 0;
boolean cont = false;
do {
cont = false;
double prev = sent;
sent += emit_do(emitter, outputtingSides, sendingEnergy-sent);
if(sendingEnergy-sent > 0 && sent-prev > 0)
{
cont = true;
}
} while(cont);
emitter.setEnergy(emitter.getEnergy() - sent);
}
}
}
}
private static double emit_do(TileEntityElectricBlock emitter, List<ForgeDirection> outputtingSides, double totalToSend)
{
double remains = totalToSend%outputtingSides.size();
double splitSend = (totalToSend-remains)/outputtingSides.size();
double sent = 0;
List<ForgeDirection> toRemove = new ArrayList<ForgeDirection>();
for(ForgeDirection side : outputtingSides)
{
TileEntity tileEntity = Coord4D.get(emitter).getFromSide(side).getTileEntity(emitter.getWorldObj());
double toSend = splitSend+remains;
remains = 0;
double prev = sent;
sent += emit_do_do(emitter, tileEntity, side, toSend);
if(sent-prev == 0)
{
toRemove.add(side);
}
}
for(ForgeDirection side : toRemove)
{
outputtingSides.remove(side);
}
return sent;
}
private static double emit_do_do(TileEntityElectricBlock from, TileEntity tileEntity, ForgeDirection side, double sendingEnergy)
{
double sent = 0;
if(tileEntity instanceof IStrictEnergyAcceptor)
{
IStrictEnergyAcceptor acceptor = (IStrictEnergyAcceptor)tileEntity;
if(acceptor.canReceiveEnergy(side.getOpposite()))
{
double prev = sent;
sent += acceptor.transferEnergyToAcceptor(side.getOpposite(), sendingEnergy);
}
}
else if(MekanismUtils.useRF() && tileEntity instanceof IEnergyHandler)
{
IEnergyHandler handler = (IEnergyHandler)tileEntity;
if(handler.canConnectEnergy(side.getOpposite()))
{
int used = handler.receiveEnergy(side.getOpposite(), (int)Math.round(sendingEnergy*Mekanism.TO_TE), false);
sent += used*Mekanism.FROM_TE;
}
}
else if(MekanismUtils.useIC2() && tileEntity instanceof IEnergySink)
{
if(((IEnergySink)tileEntity).acceptsEnergyFrom(from, side.getOpposite()))
{
double toSend = Math.min(sendingEnergy, Math.min(((IEnergySink)tileEntity).getMaxSafeInput(), ((IEnergySink)tileEntity).demandedEnergyUnits())*Mekanism.FROM_IC2);
double rejects = ((IEnergySink)tileEntity).injectEnergyUnits(side.getOpposite(), toSend*Mekanism.TO_IC2)*Mekanism.FROM_IC2;
sent += (toSend - rejects);
}
}
else if(MekanismUtils.useBuildCraft() && tileEntity instanceof IPowerReceptor)
{
PowerReceiver receiver = ((IPowerReceptor)tileEntity).getPowerReceiver(side.getOpposite());
if(receiver != null)
{
double transferEnergy = Math.min(sendingEnergy, receiver.powerRequest()*Mekanism.FROM_BC);
double used = receiver.receiveEnergy(Type.STORAGE, (float)(transferEnergy*Mekanism.TO_BC), side.getOpposite());
sent += used*Mekanism.FROM_BC;
}
}
return sent;
}
}