package micdoodle8.mods.galacticraft.core.energy; import cofh.api.energy.IEnergyConnection; import cofh.api.energy.IEnergyContainerItem; import cofh.api.energy.IEnergyHandler; import cofh.api.energy.IEnergyProvider; import cofh.api.energy.IEnergyReceiver; import ic2.api.energy.EnergyNet; import ic2.api.energy.tile.*; import ic2.api.item.IElectricItem; import ic2.api.item.ISpecialElectricItem; import mekanism.api.energy.ICableOutputter; import mekanism.api.energy.IEnergizedItem; import mekanism.api.energy.IStrictEnergyAcceptor; import micdoodle8.mods.galacticraft.api.item.IItemElectric; import micdoodle8.mods.galacticraft.api.transmission.NetworkType; import micdoodle8.mods.galacticraft.api.transmission.tile.IConductor; import micdoodle8.mods.galacticraft.api.transmission.tile.IConnector; import micdoodle8.mods.galacticraft.api.transmission.tile.IElectrical; import micdoodle8.mods.galacticraft.api.vector.BlockVec3; import micdoodle8.mods.galacticraft.core.energy.tile.EnergyStorageTile; import micdoodle8.mods.galacticraft.core.energy.tile.TileBaseConductor; import micdoodle8.mods.galacticraft.core.util.ConfigManagerCore; import micdoodle8.mods.galacticraft.core.util.GCLog; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.world.World; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import java.util.Set; public class EnergyUtil { private static boolean isMekLoaded = EnergyConfigHandler.isMekanismLoaded(); private static boolean isRFLoaded = EnergyConfigHandler.isRFAPILoaded(); private static boolean isRF1Loaded = EnergyConfigHandler.isRFAPIv1Loaded(); private static boolean isRF2Loaded = EnergyConfigHandler.isRFAPIv2Loaded(); private static boolean isIC2Loaded = EnergyConfigHandler.isIndustrialCraft2Loaded(); private static boolean isIC2TileLoaded = false; private static boolean isBCReallyLoaded = EnergyConfigHandler.isBuildcraftReallyLoaded(); public static boolean voltageParameterIC2 = false; public static Method demandedEnergyIC2 = null; public static Method injectEnergyIC2 = null; public static Method offeredEnergyIC2 = null; public static Method drawEnergyIC2 = null; public static Class<?> clazzIC2EnergyTile = null; public static Class<?> clazzIC2Cable = null; public static Class<?> clazzMekCable = null; public static Class<?> clazzEnderIOCable = null; public static Class<?> clazzMFRRednetEnergyCable = null; public static Class<?> clazzRailcraftEngine = null; private static Class<?> clazzPipeTile = null; private static Class<?> clazzPipeWood = null; public static boolean initialisedIC2Methods = EnergyUtil.initialiseIC2Methods(); public static TileEntity[] getAdjacentPowerConnections(TileEntity tile) { final TileEntity[] adjacentConnections = new TileEntity[6]; BlockVec3 thisVec = new BlockVec3(tile); for (EnumFacing direction : EnumFacing.values()) { if (tile instanceof IConductor && !((IConductor)tile).canConnect(direction, NetworkType.POWER)) { continue; } TileEntity tileEntity = thisVec.getTileEntityOnSide(tile.getWorld(), direction); if (tileEntity == null) { continue; } if (tileEntity instanceof IConnector) { if (((IConnector) tileEntity).canConnect(direction.getOpposite(), NetworkType.POWER)) { adjacentConnections[direction.ordinal()] = tileEntity; } continue; } if (isMekLoaded && (tileEntity instanceof IStrictEnergyAcceptor || tileEntity instanceof ICableOutputter)) { //Do not connect GC wires directly to Mek Universal Cables try { if (clazzMekCable != null && clazzMekCable.isInstance(tileEntity)) { continue; } } catch (Exception e) { e.printStackTrace(); } if (tileEntity instanceof IStrictEnergyAcceptor && ((IStrictEnergyAcceptor) tileEntity).canReceiveEnergy(direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; } else if (tileEntity instanceof ICableOutputter && ((ICableOutputter) tileEntity).canOutputTo(direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; } continue; } if (isBCReallyLoaded) { //Do not connect GC wires directly to BC pipes of any type try { if (clazzPipeTile.isInstance(tileEntity)) { continue; } } catch (Exception e) { } } if (isRFLoaded && tileEntity instanceof IEnergyConnection) { if (isRF2Loaded && (tileEntity instanceof IEnergyProvider || tileEntity instanceof IEnergyReceiver) || isRF1Loaded && tileEntity instanceof IEnergyHandler || clazzRailcraftEngine != null && clazzRailcraftEngine.isInstance(tileEntity)) { //Do not connect GC wires directly to power conduits if (clazzEnderIOCable != null && clazzEnderIOCable.isInstance(tileEntity)) { continue; } if (clazzMFRRednetEnergyCable != null && clazzMFRRednetEnergyCable.isInstance(tileEntity)) { continue; } if (((IEnergyConnection) tileEntity).canConnectEnergy(direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; } } continue; } if (isIC2Loaded) { if (tileEntity instanceof IEnergyConductor) { continue; } if(!tile.getWorld().isRemote) { Object IC2tile = tileEntity; BlockPos checkingIC2 = thisVec.toBlockPos().offset(direction); try { IC2tile = EnergyNet.instance.getSubTile(tile.getWorld(), checkingIC2); } catch (Exception e) { e.printStackTrace(); } if (IC2tile instanceof IEnergyAcceptor && tile instanceof IEnergyEmitter) { if (((IEnergyAcceptor) IC2tile).acceptsEnergyFrom((IEnergyEmitter) tile, direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; } continue; } if (IC2tile instanceof IEnergyEmitter && tile instanceof IEnergyAcceptor) { if (((IEnergyEmitter) IC2tile).emitsEnergyTo((IEnergyAcceptor) tile, direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; } continue; } } else { try { Class clazz = tileEntity.getClass(); if (clazz.getName().startsWith("ic2")) { //Special case: IC2's transformers don't seem to setup their sink and source directions in Energy clientside if (clazz.getName().startsWith("ic2.core.block.wiring.TileEntityTransformer")) { adjacentConnections[direction.ordinal()] = tileEntity; continue; } Field energyField = null; fieldLoop: while (energyField == null && clazz != null) { for (Field f : clazz.getDeclaredFields()) { if (f.getName().equals("energy")) { energyField = f; break fieldLoop; } } clazz = clazz.getSuperclass(); } energyField.setAccessible(true); Object energy = energyField.get(tileEntity); Set <EnumFacing> connections; if (tile instanceof IEnergyEmitter) { connections = (Set<EnumFacing>) energy.getClass().getMethod("getSinkDirs").invoke(energy); if (connections.contains(direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; continue; } } if (tile instanceof IEnergyAcceptor) { connections = (Set<EnumFacing>) energy.getClass().getMethod("getSourceDirs").invoke(energy); if (connections.contains(direction.getOpposite())) { adjacentConnections[direction.ordinal()] = tileEntity; continue; } } } } catch (Exception e) { e.printStackTrace(); } } } } return adjacentConnections; } /** * Similar to getAdjacentPowerConnections but specific to energy receivers only * Adds the adjacent power connections found to the passed acceptors, directions parameter Lists * (Note: an acceptor can therefore sometimes be entered in the Lists more than once, with a different direction each time: * this would represent GC wires connected to the acceptor on more than one side.) * * @param conductor * @param connectedAcceptors * @param directions * @throws Exception */ public static void setAdjacentPowerConnections(TileEntity conductor, List<Object> connectedAcceptors, List <EnumFacing> directions) throws Exception { final BlockVec3 thisVec = new BlockVec3(conductor); final World world = conductor.getWorld(); for (EnumFacing direction : EnumFacing.values()) { TileEntity tileEntity = thisVec.getTileEntityOnSide(world, direction); if (tileEntity == null || tileEntity instanceof IConductor) //world.getTileEntity will not have returned an invalid tile, invalid tiles are null { continue; } EnumFacing sideFrom = direction.getOpposite(); if (tileEntity instanceof IElectrical) { if (((IElectrical) tileEntity).canConnect(sideFrom, NetworkType.POWER)) { connectedAcceptors.add(tileEntity); directions.add(sideFrom); } continue; } if (isMekLoaded && tileEntity instanceof IStrictEnergyAcceptor) { if (clazzMekCable != null && clazzMekCable.isInstance(tileEntity)) { continue; } if (((IStrictEnergyAcceptor) tileEntity).canReceiveEnergy(sideFrom)) { connectedAcceptors.add(tileEntity); directions.add(sideFrom); } continue; } if (isBCReallyLoaded && clazzPipeTile.isInstance(tileEntity)) { continue; } if (isIC2Loaded && !world.isRemote) { IEnergyTile IC2tile = null; BlockPos checkingIC2 = thisVec.toBlockPos().offset(direction); try { IC2tile = EnergyNet.instance.getSubTile(world, checkingIC2); } catch (Exception e) { e.printStackTrace(); } if (IC2tile instanceof IEnergyConductor) { continue; } if (IC2tile instanceof IEnergyAcceptor && ((IEnergyAcceptor) IC2tile).acceptsEnergyFrom((IEnergyEmitter) conductor, sideFrom)) { connectedAcceptors.add(IC2tile); directions.add(sideFrom); } continue; } if ((isRF2Loaded && tileEntity instanceof IEnergyReceiver) || (isRF1Loaded && tileEntity instanceof IEnergyHandler)) { if (clazzEnderIOCable != null && clazzEnderIOCable.isInstance(tileEntity)) { continue; } if (clazzMFRRednetEnergyCable != null && clazzMFRRednetEnergyCable.isInstance(tileEntity)) { continue; } if (((IEnergyConnection) tileEntity).canConnectEnergy(sideFrom)) { connectedAcceptors.add(tileEntity); directions.add(sideFrom); } continue; } } return; } public static float otherModsEnergyTransfer(TileEntity tileAdj, EnumFacing inputAdj, float toSend, boolean simulate) { if (isMekLoaded && !EnergyConfigHandler.disableMekanismOutput && tileAdj instanceof IStrictEnergyAcceptor) { IStrictEnergyAcceptor tileMek = (IStrictEnergyAcceptor) tileAdj; if (tileMek.canReceiveEnergy(inputAdj)) { float transferredMek; if (simulate) { transferredMek = tileMek.canReceiveEnergy(inputAdj) ? (float) (tileMek.getMaxEnergy() - tileMek.getEnergy()) : 0F; } else { transferredMek = (float) tileMek.transferEnergyToAcceptor(inputAdj, toSend * EnergyConfigHandler.TO_MEKANISM_RATIO); } return transferredMek / EnergyConfigHandler.TO_MEKANISM_RATIO; } } else if (isIC2Loaded && !EnergyConfigHandler.disableIC2Output && tileAdj instanceof IEnergySink) { //TODO: need to use new subTile system double demanded = 0; try { demanded = (Double) EnergyUtil.demandedEnergyIC2.invoke(tileAdj); } catch (Exception ex) { if (ConfigManagerCore.enableDebug) { ex.printStackTrace(); } } if (simulate) { return Math.min(toSend, (float) demanded / EnergyConfigHandler.TO_IC2_RATIO); } double energySendingIC2 = Math.min(toSend * EnergyConfigHandler.TO_IC2_RATIO, demanded); if (energySendingIC2 >= 1D) { double result = 0; try { if (EnergyUtil.voltageParameterIC2) { result = energySendingIC2 - (Double) EnergyUtil.injectEnergyIC2.invoke(tileAdj, inputAdj, energySendingIC2, 120D); } else { result = energySendingIC2 - (Double) EnergyUtil.injectEnergyIC2.invoke(tileAdj, inputAdj, energySendingIC2); } } catch (Exception ex) { if (ConfigManagerCore.enableDebug) { ex.printStackTrace(); } } if (result < 0D) { return 0F; } return (float) result / EnergyConfigHandler.TO_IC2_RATIO; } } else if (isRF2Loaded && !EnergyConfigHandler.disableRFOutput && tileAdj instanceof IEnergyReceiver) { float sent = ((IEnergyReceiver) tileAdj).receiveEnergy(inputAdj, (int) Math.floor(toSend * EnergyConfigHandler.TO_RF_RATIO), simulate) / EnergyConfigHandler.TO_RF_RATIO; // GCLog.debug("Beam/storage offering RF2 up to " + toSend + " into pipe, it accepted " + sent); return sent; } return 0F; } public static float otherModsEnergyExtract(TileEntity tileAdj, EnumFacing inputAdj, float toPull, boolean simulate) { if (isIC2Loaded && !EnergyConfigHandler.disableIC2Input && tileAdj instanceof IEnergySource) { double offered = 0; try { offered = (Double) EnergyUtil.offeredEnergyIC2.invoke(tileAdj); } catch (Exception ex) { if (ConfigManagerCore.enableDebug) { ex.printStackTrace(); } } if (simulate) { return Math.min(toPull, (float) offered / EnergyConfigHandler.TO_IC2_RATIO); } double energySendingIC2 = Math.min(toPull * EnergyConfigHandler.TO_IC2_RATIO, offered); if (energySendingIC2 >= 1D) { double resultIC2 = 0; try { resultIC2 = energySendingIC2 - (Double) EnergyUtil.drawEnergyIC2.invoke(tileAdj, energySendingIC2); } catch (Exception ex) { if (ConfigManagerCore.enableDebug) { ex.printStackTrace(); } } if (resultIC2 < 0D) { resultIC2 = 0D; } return (float) resultIC2 / EnergyConfigHandler.TO_IC2_RATIO; } } else if (isRF2Loaded && !EnergyConfigHandler.disableRFInput && tileAdj instanceof IEnergyProvider) { float sent = ((IEnergyProvider) tileAdj).extractEnergy(inputAdj, (int) Math.floor(toPull * EnergyConfigHandler.TO_RF_RATIO), simulate) / EnergyConfigHandler.TO_RF_RATIO; return sent; } return 0F; } /** * Test whether an energy connection can be made to a tile using other mods' energy methods. * <p> * Parameters: * * @param tileAdj - the tile under test, it might be an energy tile from another mod * @param inputAdj - the energy input side for that tile which is under test */ public static boolean otherModCanReceive(TileEntity tileAdj, EnumFacing inputAdj) { if (tileAdj instanceof TileBaseConductor || tileAdj instanceof EnergyStorageTile) { return false; //Do not try using other mods' methods to connect to GC's own tiles } if (isMekLoaded && tileAdj instanceof IStrictEnergyAcceptor) { return ((IStrictEnergyAcceptor) tileAdj).canReceiveEnergy(inputAdj); } else if (isIC2Loaded && tileAdj instanceof IEnergyAcceptor) { return ((IEnergyAcceptor) tileAdj).acceptsEnergyFrom(null, inputAdj); } else if (isRF1Loaded && tileAdj instanceof IEnergyHandler || isRF2Loaded && tileAdj instanceof IEnergyReceiver) { return ((IEnergyConnection) tileAdj).canConnectEnergy(inputAdj); } return false; } /** * Test whether a tile can output energy using other mods' energy methods. * Currently restricted to IC2 and RF mods - Mekanism tiles do not provide an interface to "output" energy * <p> * Parameters: * * @param tileAdj - the tile under test, it might be an energy tile from another mod * @param side - the energy output side for that tile which is under test */ public static boolean otherModCanProduce(TileEntity tileAdj, EnumFacing side) { if (tileAdj instanceof TileBaseConductor || tileAdj instanceof EnergyStorageTile) { return false; //Do not try using other mods' methods to connect to GC's own tiles } if (isIC2Loaded && tileAdj instanceof IEnergyEmitter) { return ((IEnergyEmitter) tileAdj).emitsEnergyTo(null, side); } return false; } public static boolean initialiseIC2Methods() { //Initialise a couple of non-IC2 classes try { clazzMekCable = Class.forName("codechicken.multipart.TileMultipart"); } catch (Exception e) { } try { clazzEnderIOCable = Class.forName("crazypants.enderio.conduit.TileConduitBundle"); } catch (Exception e) { } try { clazzMFRRednetEnergyCable = Class.forName("powercrystals.minefactoryreloaded.tile.rednet.TileEntityRedNetEnergy"); } catch (Exception e) { } try { clazzRailcraftEngine = Class.forName("mods.railcraft.common.blocks.machine.beta.TileEngine"); } catch (Exception e) { } try { clazzPipeTile = Class.forName("buildcraft.transport.TileGenericPipe"); } catch (Exception e) { } try { clazzPipeWood = Class.forName("buildcraft.transport.pipes.PipePowerWood"); } catch (Exception e) { } if (isIC2Loaded) { GCLog.debug("Initialising IC2 methods OK"); try { clazzIC2EnergyTile = Class.forName("ic2.core.energy.Tile"); if (clazzIC2EnergyTile != null) isIC2TileLoaded = true; clazzIC2Cable = Class.forName("ic2.api.energy.tile.IEnergyConductor"); Class<?> clazz = Class.forName("ic2.api.energy.tile.IEnergySink"); GCLog.debug("Found IC2 IEnergySink class OK"); try { //1.7.2 version EnergyUtil.demandedEnergyIC2 = clazz.getMethod("demandedEnergyUnits"); } catch (Exception e) { //if that fails, try 1.7.10 version try { EnergyUtil.demandedEnergyIC2 = clazz.getMethod("getDemandedEnergy"); } catch (Exception ee) { ee.printStackTrace(); } } GCLog.debug("Set IC2 demandedEnergy method OK"); try { //1.7.2 version EnergyUtil.injectEnergyIC2 = clazz.getMethod("injectEnergyUnits", EnumFacing.class, double.class); GCLog.debug("IC2 inject 1.7.2 succeeded"); } catch (Exception e) { //if that fails, try 1.7.10 version try { EnergyUtil.injectEnergyIC2 = clazz.getMethod("injectEnergy", EnumFacing.class, double.class, double.class); EnergyUtil.voltageParameterIC2 = true; GCLog.debug("Set IC2 injectEnergy method OK"); } catch (Exception ee) { ee.printStackTrace(); } } Class<?> clazzSource = Class.forName("ic2.api.energy.tile.IEnergySource"); EnergyUtil.offeredEnergyIC2 = clazzSource.getMethod("getOfferedEnergy"); EnergyUtil.drawEnergyIC2 = clazzSource.getMethod("drawEnergy", double.class); } catch (Exception e) { e.printStackTrace(); } } if (clazzPipeTile == null) isBCReallyLoaded = false; return true; } public static boolean isElectricItem(Item item) { if (item instanceof IItemElectric) return true; if (item == null) return false; if (EnergyConfigHandler.isRFAPILoaded()) { if (item instanceof IEnergyContainerItem) return true; } if (EnergyConfigHandler.isIndustrialCraft2Loaded()) { if (item instanceof IElectricItem) return true; if (item instanceof ISpecialElectricItem) return true; } if (EnergyConfigHandler.isMekanismLoaded()) { if (item instanceof IEnergizedItem) return true; } return false; } public static boolean isChargedElectricItem(ItemStack stack) { if (stack == null) return false; Item item = stack.getItem(); if (item instanceof IItemElectric) { return ((IItemElectric) item).getElectricityStored(stack) > 0; } if (item == null) return false; if (EnergyConfigHandler.isRFAPILoaded()) { if (item instanceof IEnergyContainerItem) return ((IEnergyContainerItem)item).getEnergyStored(stack) > 0; } if (EnergyConfigHandler.isIndustrialCraft2Loaded()) { if (item instanceof ISpecialElectricItem) { ISpecialElectricItem electricItem = (ISpecialElectricItem) item; return electricItem.canProvideEnergy(stack); //TODO return (Info.itemInfo.getEnergyValue(stack) > 0.0D) || (ElectricItem.manager.discharge(stack, Double.POSITIVE_INFINITY, this.tier, true, true, true) > 0.0D); //See also: } else if (item instanceof IElectricItem) { IElectricItem electricItem = (IElectricItem) item; return electricItem.canProvideEnergy(stack); //TODO return (Info.itemInfo.getEnergyValue(stack) > 0.0D) || (ElectricItem.manager.discharge(stack, Double.POSITIVE_INFINITY, this.tier, true, true, true) > 0.0D); } } if (EnergyConfigHandler.isMekanismLoaded()) { if (item instanceof IEnergizedItem) return ((IEnergizedItem)item).getEnergy(stack) > 0; } return false; } public static boolean isFillableElectricItem(ItemStack stack) { if (stack == null) return false; Item item = stack.getItem(); if (item instanceof IItemElectric) { return ((IItemElectric) item).getElectricityStored(stack) < ((IItemElectric) item).getMaxElectricityStored(stack); } if (item == null) return false; if (EnergyConfigHandler.isRFAPILoaded()) { if (item instanceof IEnergyContainerItem) return ((IEnergyContainerItem)item).getEnergyStored(stack) < ((IEnergyContainerItem)item).getMaxEnergyStored(stack); } if (EnergyConfigHandler.isIndustrialCraft2Loaded()) { if (item instanceof ISpecialElectricItem) { ISpecialElectricItem electricItem = (ISpecialElectricItem) item; return electricItem.canProvideEnergy(stack); //TODO return ElectricItem.manager.charge(stack, Double.POSITIVE_INFINITY, this.tier, true, true) > 0.0D; } else if (item instanceof IElectricItem) { IElectricItem electricItem = (IElectricItem) item; return electricItem.canProvideEnergy(stack); //TODO return ElectricItem.manager.charge(stack, Double.POSITIVE_INFINITY, this.tier, true, true) > 0.0D; } } if (EnergyConfigHandler.isMekanismLoaded()) { if (item instanceof IEnergizedItem) return ((IEnergizedItem)item).getEnergy(stack) < ((IEnergizedItem)item).getMaxEnergy(stack); } return false; } }