| package mekanism.common.util; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| |
| import mekanism.api.Coord4D; |
| import mekanism.api.energy.IStrictEnergyOutputter; |
| import mekanism.api.energy.IStrictEnergyAcceptor; |
| import mekanism.api.transmitters.TransmissionType; |
| import mekanism.common.base.IEnergyWrapper; |
| import mekanism.common.capabilities.Capabilities; |
| import mekanism.common.config.MekanismConfig.general; |
| import mekanism.common.integration.ic2.IC2Integration; |
| import net.darkhax.tesla.api.ITeslaConsumer; |
| import net.minecraft.tileentity.TileEntity; |
| import net.minecraft.util.EnumFacing; |
| import net.minecraft.util.math.BlockPos; |
| import net.minecraft.world.World; |
| import net.minecraftforge.energy.CapabilityEnergy; |
| import net.minecraftforge.energy.IEnergyStorage; |
| import cofh.api.energy.IEnergyConnection; |
| import cofh.api.energy.IEnergyProvider; |
| import cofh.api.energy.IEnergyReceiver; |
| |
| public final class CableUtils |
| { |
| public static boolean isCable(TileEntity tileEntity) |
| { |
| if(tileEntity != null && CapabilityUtils.hasCapability(tileEntity, Capabilities.GRID_TRANSMITTER_CAPABILITY, null)) |
| { |
| return TransmissionType.checkTransmissionType(CapabilityUtils.getCapability(tileEntity, Capabilities.GRID_TRANSMITTER_CAPABILITY, null), TransmissionType.ENERGY); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * 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<EnumFacing> sides) |
| { |
| boolean[] connectable = new boolean[] {false, false, false, false, false, false}; |
| Coord4D coord = Coord4D.get(tileEntity); |
| |
| for(EnumFacing side : sides) |
| { |
| TileEntity tile = coord.offset(side).getTileEntity(tileEntity.getWorld()); |
| |
| connectable[side.ordinal()] = isValidAcceptorOnSide(tileEntity, tile, side); |
| connectable[side.ordinal()] |= isCable(tile); |
| } |
| |
| return connectable; |
| } |
| |
| /** |
| * Gets the adjacent connections to a TileEntity, from a subset of its sides. |
| * @param cableEntity - TileEntity that's trying to connect |
| * @param side - side to check |
| * @return boolean whether the acceptor is valid |
| */ |
| public static boolean isValidAcceptorOnSide(TileEntity cableEntity, TileEntity tile, EnumFacing side) |
| { |
| if(tile == null || isCable(tile)) |
| { |
| return false; |
| } |
| |
| return isAcceptor(cableEntity, tile, side) || isOutputter(tile, side) || |
| (MekanismUtils.useRF() && tile instanceof IEnergyConnection && ((IEnergyConnection)tile).canConnectEnergy(side.getOpposite())); |
| } |
| |
| /** |
| * 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) |
| { |
| return getConnectedOutputters(tileEntity.getPos(), tileEntity.getWorld()); |
| } |
| |
| public static TileEntity[] getConnectedOutputters(BlockPos pos, World world) |
| { |
| TileEntity[] outputters = new TileEntity[] {null, null, null, null, null, null}; |
| |
| for(EnumFacing orientation : EnumFacing.VALUES) |
| { |
| TileEntity outputter = world.getTileEntity(pos.offset(orientation)); |
| |
| if(isOutputter(outputter, orientation)) |
| { |
| outputters[orientation.ordinal()] = outputter; |
| } |
| } |
| |
| return outputters; |
| } |
| |
| public static boolean isOutputter(TileEntity tileEntity, EnumFacing side) |
| { |
| if(tileEntity == null) |
| { |
| return false; |
| } |
| |
| if(CapabilityUtils.hasCapability(tileEntity, Capabilities.ENERGY_OUTPUTTER_CAPABILITY, side.getOpposite())) |
| { |
| IStrictEnergyOutputter outputter = CapabilityUtils.getCapability(tileEntity, Capabilities.ENERGY_OUTPUTTER_CAPABILITY, side.getOpposite()); |
| |
| if(outputter != null && outputter.canOutputEnergy(side.getOpposite())) |
| { |
| return true; |
| } |
| } |
| |
| if(MekanismUtils.useTesla() && CapabilityUtils.hasCapability(tileEntity, Capabilities.TESLA_PRODUCER_CAPABILITY, side.getOpposite())) |
| { |
| return true; |
| } |
| |
| if(MekanismUtils.useForge() && CapabilityUtils.hasCapability(tileEntity, CapabilityEnergy.ENERGY, side.getOpposite())) |
| { |
| return CapabilityUtils.getCapability(tileEntity, CapabilityEnergy.ENERGY, side.getOpposite()).canExtract(); |
| } |
| |
| if(MekanismUtils.useRF() && tileEntity instanceof IEnergyProvider && ((IEnergyConnection)tileEntity).canConnectEnergy(side.getOpposite())) |
| { |
| return true; |
| } |
| |
| if(MekanismUtils.useIC2() && IC2Integration.isOutputter(tileEntity, side)) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| public static boolean isAcceptor(TileEntity orig, TileEntity tileEntity, EnumFacing side) |
| { |
| if(CapabilityUtils.hasCapability(tileEntity, Capabilities.GRID_TRANSMITTER_CAPABILITY, side.getOpposite())) |
| { |
| return false; |
| } |
| |
| if(CapabilityUtils.hasCapability(tileEntity, Capabilities.ENERGY_ACCEPTOR_CAPABILITY, side.getOpposite())) |
| { |
| if(CapabilityUtils.getCapability(tileEntity, Capabilities.ENERGY_ACCEPTOR_CAPABILITY, side.getOpposite()).canReceiveEnergy(side.getOpposite())) |
| { |
| return true; |
| } |
| } |
| else if(MekanismUtils.useTesla() && CapabilityUtils.hasCapability(tileEntity, Capabilities.TESLA_CONSUMER_CAPABILITY, side.getOpposite())) |
| { |
| return true; |
| } |
| else if(MekanismUtils.useForge() && CapabilityUtils.hasCapability(tileEntity, CapabilityEnergy.ENERGY, side.getOpposite())) |
| { |
| return CapabilityUtils.getCapability(tileEntity, CapabilityEnergy.ENERGY, side.getOpposite()).canReceive(); |
| } |
| else if(MekanismUtils.useIC2() && IC2Integration.isAcceptor(orig, tileEntity, side)) |
| { |
| return true; |
| } |
| else if(MekanismUtils.useRF() && tileEntity instanceof IEnergyReceiver) |
| { |
| if(((IEnergyReceiver)tileEntity).canConnectEnergy(side.getOpposite())) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| public static void emit(IEnergyWrapper emitter) |
| { |
| if(!((TileEntity)emitter).getWorld().isRemote && MekanismUtils.canFunction((TileEntity)emitter)) |
| { |
| double energyToSend = Math.min(emitter.getEnergy(), emitter.getMaxOutput()); |
| |
| if(energyToSend > 0) |
| { |
| List<EnumFacing> outputtingSides = new ArrayList<EnumFacing>(); |
| boolean[] connectable = getConnections((TileEntity)emitter, emitter.getOutputtingSides()); |
| |
| for(EnumFacing side : emitter.getOutputtingSides()) |
| { |
| if(connectable[side.ordinal()]) |
| { |
| outputtingSides.add(side); |
| } |
| } |
| |
| if(outputtingSides.size() > 0) |
| { |
| double sent = 0; |
| boolean tryAgain = false; |
| int i = 0; |
| |
| do { |
| double prev = sent; |
| sent += emit_do(emitter, outputtingSides, energyToSend-sent, tryAgain); |
| |
| tryAgain = energyToSend-sent > 0 && sent-prev > 0 && i < 100; |
| |
| i++; |
| } while(tryAgain); |
| |
| emitter.setEnergy(emitter.getEnergy() - sent); |
| } |
| } |
| } |
| } |
| |
| private static double emit_do(IEnergyWrapper emitter, List<EnumFacing> outputtingSides, double totalToSend, boolean tryAgain) |
| { |
| double remains = totalToSend%outputtingSides.size(); |
| double splitSend = (totalToSend-remains)/outputtingSides.size(); |
| double sent = 0; |
| |
| List<EnumFacing> toRemove = new ArrayList<EnumFacing>(); |
| |
| for(EnumFacing side : outputtingSides) |
| { |
| TileEntity tileEntity = Coord4D.get((TileEntity)emitter).offset(side).getTileEntity(((TileEntity)emitter).getWorld()); |
| double toSend = splitSend+remains; |
| remains = 0; |
| |
| double prev = sent; |
| sent += emit_do_do(emitter, tileEntity, side, toSend, tryAgain); |
| |
| if(sent-prev == 0) |
| { |
| toRemove.add(side); |
| } |
| } |
| |
| for(EnumFacing side : toRemove) |
| { |
| outputtingSides.remove(side); |
| } |
| |
| return sent; |
| } |
| |
| private static double emit_do_do(IEnergyWrapper from, TileEntity tileEntity, EnumFacing side, double currentSending, boolean tryAgain) |
| { |
| double sent = 0; |
| |
| if(CapabilityUtils.hasCapability(tileEntity, Capabilities.ENERGY_ACCEPTOR_CAPABILITY, side.getOpposite())) |
| { |
| IStrictEnergyAcceptor acceptor = CapabilityUtils.getCapability(tileEntity, Capabilities.ENERGY_ACCEPTOR_CAPABILITY, side.getOpposite()); |
| |
| if(acceptor.canReceiveEnergy(side.getOpposite())) |
| { |
| sent += acceptor.acceptEnergy(side.getOpposite(), currentSending, false); |
| } |
| } |
| else if(MekanismUtils.useTesla() && CapabilityUtils.hasCapability(tileEntity, Capabilities.TESLA_CONSUMER_CAPABILITY, side.getOpposite())) |
| { |
| ITeslaConsumer consumer = CapabilityUtils.getCapability(tileEntity, Capabilities.TESLA_CONSUMER_CAPABILITY, side.getOpposite()); |
| sent += consumer.givePower((long)Math.round(currentSending*general.TO_TESLA), false)*general.FROM_TESLA; |
| } |
| else if(MekanismUtils.useForge() && CapabilityUtils.hasCapability(tileEntity, CapabilityEnergy.ENERGY, side.getOpposite())) |
| { |
| IEnergyStorage storage = CapabilityUtils.getCapability(tileEntity, CapabilityEnergy.ENERGY, side.getOpposite()); |
| sent += storage.receiveEnergy((int)Math.round(Math.min(Integer.MAX_VALUE, currentSending*general.TO_FORGE)), false)*general.FROM_FORGE; |
| } |
| else if(MekanismUtils.useRF() && tileEntity instanceof IEnergyReceiver) |
| { |
| IEnergyReceiver handler = (IEnergyReceiver)tileEntity; |
| |
| if(handler.canConnectEnergy(side.getOpposite())) |
| { |
| int toSend = Math.min((int)Math.round(currentSending*general.TO_RF), Integer.MAX_VALUE); |
| int used = handler.receiveEnergy(side.getOpposite(), toSend, false); |
| sent += used*general.FROM_RF; |
| } |
| } |
| else if(MekanismUtils.useIC2()) |
| { |
| sent += IC2Integration.emitEnergy(from, tileEntity, side, currentSending); |
| } |
| |
| return sent; |
| } |
| } |