diff options
-rw-r--r-- | src/main/java/gregtech/common/tileentities/generators/GT_MetaTileEntity_MagicalEnergyAbsorber.java | 735 |
1 files changed, 539 insertions, 196 deletions
diff --git a/src/main/java/gregtech/common/tileentities/generators/GT_MetaTileEntity_MagicalEnergyAbsorber.java b/src/main/java/gregtech/common/tileentities/generators/GT_MetaTileEntity_MagicalEnergyAbsorber.java index 3bc2731d4a..bb3b24f5e3 100644 --- a/src/main/java/gregtech/common/tileentities/generators/GT_MetaTileEntity_MagicalEnergyAbsorber.java +++ b/src/main/java/gregtech/common/tileentities/generators/GT_MetaTileEntity_MagicalEnergyAbsorber.java @@ -1,8 +1,8 @@ package gregtech.common.tileentities.generators; +import com.google.common.base.Enums; import cpw.mods.fml.common.Loader; import gregtech.api.GregTech_API; -import gregtech.api.enums.ConfigCategories; import gregtech.api.enums.TC_Aspects; import gregtech.api.enums.Textures; import gregtech.api.interfaces.ITexture; @@ -10,285 +10,628 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicGenerator; import gregtech.api.objects.GT_RenderedTexture; -import gregtech.api.util.GT_Recipe; +import gregtech.api.util.*; import net.minecraft.block.Block; +import net.minecraft.block.BlockDragonEgg; import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.item.EntityEnderCrystal; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.ItemEnchantedBook; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.util.ForgeDirection; import thaumcraft.api.aspects.Aspect; -import thaumcraft.api.aspects.AspectList; -import thaumcraft.api.aspects.IEssentiaContainerItem; +import thaumcraft.api.aspects.AspectSourceHelper; +import thaumcraft.api.aspects.IAspectSource; import thaumcraft.api.visnet.VisNetHandler; -import java.util.ArrayList; -import java.util.Locale; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import static gregtech.api.enums.ConfigCategories.machineconfig; +import static gregtech.api.enums.GT_Values.MOD_ID_TC; import static gregtech.api.enums.GT_Values.V; - -public class GT_MetaTileEntity_MagicalEnergyAbsorber extends GT_MetaTileEntity_BasicGenerator { - - public static final ArrayList<EntityEnderCrystal> sUsedDragonCrystalList = new ArrayList<EntityEnderCrystal>(); - public static boolean sAllowMultipleEggs = true; - public static GT_MetaTileEntity_MagicalEnergyAbsorber mActiveSiphon = null; - public static int sEnergyPerEnderCrystal = 32; - public static int sEnergyFromVis = 512; - public static int sDragonEggEnergyPerTick = 128; - public static boolean isThaumcraftLoaded; - public int mEfficiency; - public EntityEnderCrystal mTargetedCrystal; +import static net.minecraft.util.EnumChatFormatting.*; + +interface MagicalEnergyBBListener { + void onMagicalEnergyBBUpdate(); +} + +public class GT_MetaTileEntity_MagicalEnergyAbsorber extends GT_MetaTileEntity_BasicGenerator implements MagicalEnergyBBListener { + + private static final boolean THAUMCRAFT_LOADED = Loader.isModLoaded(MOD_ID_TC); + private static final ConcurrentHashMap<UUID, GT_MetaTileEntity_MagicalEnergyAbsorber> sSubscribedCrystals = new ConcurrentHashMap<>(4); + private static List<Aspect> sPrimalAspects = (THAUMCRAFT_LOADED) ? Aspect.getPrimalAspects() : new ArrayList<Aspect>(); + private static boolean sAllowMultipleEggs = false; + private static GT_MetaTileEntity_MagicalEnergyAbsorber sActiveSiphon = null; + private static int sEnergyPerEndercrystal = 512; + private static int sEnergyFromVis = 20; + private static int sEnergyPerEssentia = 320; + private static Map<Aspect, Integer> sAspectsEnergy = new HashMap<>(); + private static int sDragonEggEnergyPerTick = 2048; + private int mEfficiency; + private int mMaxVisPerDrain; + private MagicalEnergyBB mMagicalEnergyBB = new MagicalEnergyBB(this, mTier, mTier + 2); + private long mNextGenerateTickRate = 1; + private int mNoGenerationTicks = 0; public GT_MetaTileEntity_MagicalEnergyAbsorber(int aID, String aName, String aNameRegional, int aTier) { - super(aID, aName, aNameRegional, aTier, "Feasts on magic close to it", new ITexture[0]); - onConfigLoad(); + super(aID, aName, aNameRegional, aTier, "Feasts on magic close to it:"); + onConfigLoad(GregTech_API.sMachineFile); } - public GT_MetaTileEntity_MagicalEnergyAbsorber(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + private GT_MetaTileEntity_MagicalEnergyAbsorber(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { super(aName, aTier, aDescription, aTextures); - onConfigLoad(); + onConfigLoad(GregTech_API.sMachineFile); } - public GT_MetaTileEntity_MagicalEnergyAbsorber(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { - super(aName, aTier, aDescription, aTextures); - onConfigLoad(); - } - - public boolean isOutputFacing(byte aSide) { - return aSide == getBaseMetaTileEntity().getFrontFacing(); + /** + * Populates static variables dependant on config settings + * + * @param aConfig GT_Config + */ + private static void sharedConfigLoad(GT_Config aConfig) { + sAllowMultipleEggs = aConfig.get(machineconfig, "MagicEnergyAbsorber.AllowMultipleEggs", false); + sDragonEggEnergyPerTick = aConfig.get(machineconfig, "MagicEnergyAbsorber.EnergyPerTick.DragonEgg", 2048); + sEnergyPerEndercrystal = aConfig.get(machineconfig, "MagicEnergyAbsorber.EnergyPerTick.EnderCrystal", 512); + if (THAUMCRAFT_LOADED) { + sEnergyFromVis = aConfig.get(machineconfig, "MagicEnergyAbsorber.EnergyPerVis", 20); + sEnergyPerEssentia = aConfig.get(machineconfig, "MagicEnergyAbsorber.EnergyPerEssentia", 320); + for (Aspect tAspect : Aspect.aspects.values()) { + sAspectsEnergy.put(tAspect, + Enums.getIfPresent(TC_Aspects.class, + tAspect.getTag().toUpperCase(Locale.ENGLISH)).or(TC_Aspects.AER).mValue + * sEnergyPerEssentia); + } + } } - public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { - return new GT_MetaTileEntity_MagicalEnergyAbsorber(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + private static void setActiveSiphon(GT_MetaTileEntity_MagicalEnergyAbsorber aSiphon) { + sActiveSiphon = aSiphon; } - public GT_Recipe.GT_Recipe_Map getRecipes() { - return GT_Recipe.GT_Recipe_Map.sMagicFuels; + @Override + public void onConfigLoad(GT_Config aConfig) { + sharedConfigLoad(aConfig); + mEfficiency = aConfig.get(machineconfig, "MagicEnergyAbsorber.efficiency.tier." + mTier, 100 - mTier * 10); + mMaxVisPerDrain = (int) Math.round(Math.sqrt(V[mTier] * 10000 / (sEnergyFromVis * (getEfficiency() != 0 ? getEfficiency() : 100)))); + if (Math.pow(mMaxVisPerDrain, 2) * sEnergyFromVis * (getEfficiency() != 0 ? getEfficiency() : 100) < V[mTier]) { + mMaxVisPerDrain += 1; + } } - public int getCapacity() { - return 16000; + @Override + public void onScrewdriverRightClick(byte aSide, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (aPlayer.isSneaking()) mMagicalEnergyBB.decreaseTier(); + else mMagicalEnergyBB.increaseTier(); + GT_Utility.sendChatToPlayer(aPlayer, String.format(GT_LanguageManager.addStringLocalization("Interaction_DESCRIPTION_MagicalEnergyAbsorber_Screwdriver", "Absorption range: %s blocks"), mMagicalEnergyBB.getRange(), true)); + mMagicalEnergyBB.update(); } - public void onConfigLoad() { - this.mEfficiency = GregTech_API.sMachineFile.get(ConfigCategories.machineconfig, "MagicEnergyAbsorber.efficiency.tier." + this.mTier, - 100 - this.mTier * 10); - this.sAllowMultipleEggs = GregTech_API.sMachineFile.get(ConfigCategories.machineconfig, "MagicEnergyAbsorber.AllowMultipleEggs", false); - this.sEnergyPerEnderCrystal = GregTech_API.sMachineFile.get(ConfigCategories.machineconfig, "MagicEnergyAbsorber.EnergyPerTick.EnderCrystal", 32); - this.sEnergyFromVis = (GregTech_API.sMachineFile.get(ConfigCategories.machineconfig, "MagicEnergyAbsorber.EnergyPerVisDivisor", 2500) * 10); - this.sDragonEggEnergyPerTick = GregTech_API.sMachineFile.get(ConfigCategories.machineconfig, "MagicEnergyAbsorber.EnergyPerTick", 2048); - this.isThaumcraftLoaded = Loader.isModLoaded("Thaumcraft"); + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + if (!aBaseMetaTileEntity.isServerSide()) return; + mMagicalEnergyBB.update(); } @Override - public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { - if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.isAllowedToWork() - && aBaseMetaTileEntity.getUniversalEnergyStored() < maxEUOutput() + aBaseMetaTileEntity.getEUCapacity()) { - // Dragon Egg - if (hasEgg() && aTick % 10 == 0) { - getBaseMetaTileEntity().increaseStoredEnergyUnits(sDragonEggEnergyPerTick * getEfficiency() / 10, false); - if ((mActiveSiphon != this) && (!sAllowMultipleEggs)) { - if ((mActiveSiphon == null) || (mActiveSiphon.getBaseMetaTileEntity() == null) - || (mActiveSiphon.getBaseMetaTileEntity().isInvalidTileEntity()) || (!mActiveSiphon.hasEgg())) { - mActiveSiphon = this; - } else { - Block tEgg = mActiveSiphon.getBaseMetaTileEntity().getBlockOffset(0, 1, 0); - if (!getBaseMetaTileEntity().getWorld().getChunkFromBlockCoords(mActiveSiphon.getBaseMetaTileEntity().getXCoord(), mActiveSiphon.getBaseMetaTileEntity().getZCoord()).isChunkLoaded && (tEgg == Blocks.dragon_egg || tEgg.getUnlocalizedName().equals("tile.dragonEgg"))) { - getBaseMetaTileEntity().doExplosion(Integer.MAX_VALUE); - } else { - mActiveSiphon = this; - } - } - } - } - // Energyzed node - if (isThaumcraftLoaded) { - try { - int multFactor = 2; - World tmpWorld = this.getBaseMetaTileEntity().getWorld(); - int tmpX = this.getBaseMetaTileEntity().getXCoord(); - int tmpY = this.getBaseMetaTileEntity().getYCoord(); - int tmpZ = this.getBaseMetaTileEntity().getZCoord(); - int fire = VisNetHandler.drainVis(tmpWorld, tmpX, tmpY, tmpZ, Aspect.FIRE, 1000); // all of these should be 1000 - int earth = VisNetHandler.drainVis(tmpWorld, tmpX, tmpY, tmpZ, Aspect.EARTH, 1000); - int air = VisNetHandler.drainVis(tmpWorld, tmpX, tmpY, tmpZ, Aspect.AIR, 1000); - int entropy = VisNetHandler.drainVis(tmpWorld, tmpX, tmpY, tmpZ, Aspect.ENTROPY, 1000); - int order = VisNetHandler.drainVis(tmpWorld, tmpX, tmpY, tmpZ, Aspect.ORDER, 1000); - int water = VisNetHandler.drainVis(tmpWorld, tmpX, tmpY, tmpZ, Aspect.WATER, 1000); - int visEU = (int) (Math.pow(fire, 2) + Math.pow(earth, 2) + Math.pow(air, 2) + Math.pow(entropy, 2) + Math.pow(order, 2) + Math.pow(water, 2)); - int mult = 0; //this should make it more dependant on how big your node is - mult += fire * multFactor; - mult += earth * multFactor; - mult += air * multFactor; - mult += entropy * multFactor; - mult += order * multFactor; - mult += water * multFactor; - visEU = (visEU * mult) / 100; - - getBaseMetaTileEntity().increaseStoredEnergyUnits(Math.min(maxEUOutput(), visEU * getEfficiency() / sEnergyFromVis), false); - - } catch (Throwable e) { - - } - } - // EnderCrystal - if (sEnergyPerEnderCrystal > 0) { - if (this.mTargetedCrystal == null) { - ArrayList<EntityEnderCrystal> tList = (ArrayList) getBaseMetaTileEntity().getWorld().getEntitiesWithinAABB( - EntityEnderCrystal.class, - AxisAlignedBB.getBoundingBox(getBaseMetaTileEntity().getXCoord() - 64, getBaseMetaTileEntity().getYCoord() - 64, - getBaseMetaTileEntity().getZCoord() - 64, getBaseMetaTileEntity().getXCoord() + 64, - getBaseMetaTileEntity().getYCoord() + 64, getBaseMetaTileEntity().getZCoord() + 64)); - if ((tList != null) && (!tList.isEmpty())) { - tList.removeAll(sUsedDragonCrystalList); - if (tList.size() > 0) { - this.mTargetedCrystal = ((EntityEnderCrystal) tList.get(0)); - if (this.mTargetedCrystal != null) { - sUsedDragonCrystalList.add(this.mTargetedCrystal); - } - } - } - } else if (this.mTargetedCrystal.isEntityAlive()) { - getBaseMetaTileEntity().increaseStoredEnergyUnits(sEnergyPerEnderCrystal * 10, false); - } else { - sUsedDragonCrystalList.remove(this.mTargetedCrystal); - this.mTargetedCrystal = null; - } - } - - // Absorb entchantments and TC essentia - try { - if ((this.mInventory[0] != null) && (this.mInventory[1] == null)) { - if (isThaumcraftLoaded && this.mInventory[0].getItem() instanceof IEssentiaContainerItem) { - AspectList tAspect = ((IEssentiaContainerItem) this.mInventory[0].getItem()).getAspects(this.mInventory[0]); - TC_Aspects tValue = TC_Aspects.valueOf(tAspect.getAspects()[0].getTag().toUpperCase(Locale.ENGLISH)); - int tEU = (tValue.mValue * tAspect.getAmount((Aspect) tValue.mAspect) * 100); - getBaseMetaTileEntity().increaseStoredEnergyUnits(tEU * getEfficiency() / 100, true); - ItemStack tStack = this.mInventory[0].copy(); - tStack.setTagCompound(null); - tStack.setItemDamage(0); - tStack.stackSize = 1; - this.mInventory[1] = tStack; - this.mInventory[0].stackSize--; - if (this.mInventory[0].stackSize < 1) { - this.mInventory[0] = null; - } - - } else { - if ((this.mInventory[0].isItemEnchanted()) && (this.mInventory[0].getItem().getItemEnchantability() > 0)) { - NBTTagList tEnchantments = this.mInventory[0].getEnchantmentTagList(); - if (tEnchantments != null) { - for (int i = 0; i < tEnchantments.tagCount(); i++) { - short tID = ((NBTTagCompound) tEnchantments.getCompoundTagAt(i)).getShort("id"); - short tLevel = ((NBTTagCompound) tEnchantments.getCompoundTagAt(i)).getShort("lvl"); - if ((tID > -1) && (tID < Enchantment.enchantmentsList.length)) { - Enchantment tEnchantment = Enchantment.enchantmentsList[tID]; - if (tEnchantment != null) { - getBaseMetaTileEntity().increaseStoredEnergyUnits( - 1000000 * getEfficiency() * tLevel / (tEnchantment.getMaxLevel() * tEnchantment.getWeight() * 100), true); - } - } - } - this.mInventory[0].stackTagCompound.removeTag("ench"); - } - } else if ((this.mInventory[0].getItem() instanceof ItemEnchantedBook)) { - NBTTagList tEnchantments = ((ItemEnchantedBook) this.mInventory[0].getItem()).func_92110_g(this.mInventory[0]); - if (tEnchantments != null) { - for (int i = 0; i < tEnchantments.tagCount(); i++) { - short tID = ((NBTTagCompound) tEnchantments.getCompoundTagAt(i)).getShort("id"); - short tLevel = ((NBTTagCompound) tEnchantments.getCompoundTagAt(i)).getShort("lvl"); - if ((tID > -1) && (tID < Enchantment.enchantmentsList.length)) { - Enchantment tEnchantment = Enchantment.enchantmentsList[tID]; - if (tEnchantment != null) { - getBaseMetaTileEntity().increaseStoredEnergyUnits( - 1000000 * tLevel / (tEnchantment.getMaxLevel() * tEnchantment.getWeight()), true); - } - } - } - this.mInventory[0] = new ItemStack(Items.book, 1); - } - } - this.mInventory[1] = this.mInventory[0]; - this.mInventory[0] = null; - } - } - } catch (Throwable e) { - } - } + public void onRemoval() { + super.onRemoval(); + releaseEgg(); + unsubscribeCrystals(); } - public void inValidate() { - if (mActiveSiphon == this) { - mActiveSiphon = null; + private void releaseEgg() { + if (sActiveSiphon == this) { + setActiveSiphon(null); } } - public boolean hasEgg() { - Block above = getBaseMetaTileEntity().getBlockOffset(0, 1, 0); - if (above == null || Blocks.air == above) { - return false; + private void unsubscribeCrystals() { + for (UUID tCrystalID : sSubscribedCrystals.keySet()) { + sSubscribedCrystals.remove(tCrystalID, this); } - return Blocks.dragon_egg == above || above.getUnlocalizedName().equals("tile.dragonEgg"); } - public int getEfficiency() { - return this.mEfficiency; + /** + * Call-back from the Bounding Box when its content is updated + */ + @Override + public void onMagicalEnergyBBUpdate() { + List<UUID> tCrystalIDsInRange = mMagicalEnergyBB.getLivingCrystalIDs(); + // Release unreachable Crystals subscriptions + for (UUID tSubscribedCrystalID : sSubscribedCrystals.keySet()) { + if (!tCrystalIDsInRange.contains(tSubscribedCrystalID)) { + sSubscribedCrystals.remove(tSubscribedCrystalID, this); + } + } + // Subscribe to available and not already subscribed Crystals + for (UUID tCrystalID : tCrystalIDsInRange) { + sSubscribedCrystals.putIfAbsent(tCrystalID, this); + } } @Override - public long maxEUStore() { - return Math.max(getEUVar(), V[mTier] * 16000L + getMinimumStoredEU()); + public String[] getDescription() { + final String LI = "-%%%"; + final String EU_PER = "%%%EU per "; + List<String> description = new ArrayList<>(); + description.add(UNDERLINE + "Feasts on " + LIGHT_PURPLE + UNDERLINE + "magic" + GRAY + UNDERLINE + " close to it:"); + description.add(LI + (sAllowMultipleEggs ? "A " : "An " + YELLOW + UNDERLINE + "EXCLUSIVE" + RESET) + GRAY + " " + LIGHT_PURPLE + "Dragon Egg" + GRAY + " atop"); + if (sEnergyPerEndercrystal > 0) { + description.add(LI + sEnergyPerEndercrystal + EU_PER + LIGHT_PURPLE + "Ender Crystal" + GRAY + " in range"); + } + if (THAUMCRAFT_LOADED) { + description.add(LI + mMaxVisPerDrain + "%%%CV/t from an " + LIGHT_PURPLE + "Energised Node" + GRAY); + description.add(LI + (sEnergyPerEssentia * getEfficiency()) / 100 + EU_PER + LIGHT_PURPLE + "Essentia" + GRAY + " Aspect-Value from containers in range"); + } + description.add(" "); + description.add(UNDERLINE + "Lookup range (Use Screwdriver to change):"); + description.add("Default:%%%" + GREEN + mMagicalEnergyBB.getDefaultRange()); + description.add("Max:%%%" + GREEN + mMagicalEnergyBB.getMaxRange()); + description.add(" "); + description.add(UNDERLINE + "Fuels on " + LIGHT_PURPLE + UNDERLINE + "enchantments" + GRAY + UNDERLINE + " input:"); + description.add("- Item:%%%" + (10000 * getEfficiency()) / 100 + EU_PER + LIGHT_PURPLE + "enchant" + GRAY + " weight × level / max"); + description.add("- Book:%%%" + 10000 + EU_PER + LIGHT_PURPLE + "enchant" + GRAY + " weight × level / max"); + description.add(" "); + description.add("Efficiency:%%%" + GREEN + getEfficiency() + "%"); + return description.toArray(new String[0]); } + @Override public ITexture[] getFront(byte aColor) { return new ITexture[]{super.getFront(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC), - Textures.BlockIcons.OVERLAYS_ENERGY_OUT[this.mTier]}; + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier]}; } + @Override public ITexture[] getBack(byte aColor) { return new ITexture[]{super.getBack(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC_FRONT)}; } + @Override public ITexture[] getBottom(byte aColor) { return new ITexture[]{super.getBottom(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC)}; } + @Override public ITexture[] getTop(byte aColor) { return new ITexture[]{super.getTop(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_DRAGONEGG)}; } + @Override public ITexture[] getSides(byte aColor) { return new ITexture[]{super.getSides(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC)}; } + @Override public ITexture[] getFrontActive(byte aColor) { return new ITexture[]{super.getFrontActive(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC_ACTIVE), - Textures.BlockIcons.OVERLAYS_ENERGY_OUT[this.mTier]}; + Textures.BlockIcons.OVERLAYS_ENERGY_OUT[mTier]}; } + @Override public ITexture[] getBackActive(byte aColor) { return new ITexture[]{super.getBackActive(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC_FRONT_ACTIVE)}; } + @Override public ITexture[] getBottomActive(byte aColor) { return new ITexture[]{super.getBottomActive(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC_ACTIVE)}; } + @Override public ITexture[] getTopActive(byte aColor) { return new ITexture[]{super.getTopActive(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_DRAGONEGG)}; } + @Override public ITexture[] getSidesActive(byte aColor) { return new ITexture[]{super.getSidesActive(aColor)[0], new GT_RenderedTexture(Textures.BlockIcons.MACHINE_CASING_MAGIC_ACTIVE)}; } - @Override - public int getPollution() { - return 0; - } + @Override + public boolean isOutputFacing(byte aSide) { + return aSide == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public long maxEUStore() { + return Math.max(getEUVar(), V[mTier] * 16000 + getMinimumStoredEU()); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (!aBaseMetaTileEntity.isServerSide()) return; + if (!aBaseMetaTileEntity.isAllowedToWork()) return; + if ((aBaseMetaTileEntity.getUniversalEnergyStored() >= aBaseMetaTileEntity.getEUCapacity())) return; + + long tGeneratedEU; + + if (aTick % 100 == 0) mMagicalEnergyBB.update(); + + // Adaptive EU Generation Ticking + if (aTick % mNextGenerateTickRate == 0) { + tGeneratedEU = generateEU(); + if (tGeneratedEU > 0) { + mNoGenerationTicks = 0; + if (tGeneratedEU >= 2 * V[mTier]) + mNextGenerateTickRate = (long) (1.0D / ((2.0D * (double) (V[mTier])) / (double) tGeneratedEU)); + else mNextGenerateTickRate = 1; + mInventory[getStackDisplaySlot()] = new ItemStack(Blocks.fire, 1); + mInventory[getStackDisplaySlot()].setStackDisplayName("Generating: " + tGeneratedEU + " EU"); + } else { + mInventory[getStackDisplaySlot()] = null; + mNoGenerationTicks += 1; + } + if (mNoGenerationTicks > 20) { + mNoGenerationTicks = 0; + mNextGenerateTickRate = 20; + } + aBaseMetaTileEntity.increaseStoredEnergyUnits(tGeneratedEU, true); + aBaseMetaTileEntity.setActive(aBaseMetaTileEntity.isAllowedToWork() && aBaseMetaTileEntity.getUniversalEnergyStored() >= maxEUOutput() + getMinimumStoredEU()); + } + } + + @Override + public int getPollution() { + return 0; + } + + @Override + public GT_Recipe.GT_Recipe_Map getRecipes() { + return GT_Recipe.GT_Recipe_Map.sMagicFuels; + } + + @Override + public int getEfficiency() { + return mEfficiency; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, byte aSide, ItemStack aStack) { + // Restrict input to disenchantable items or enchanted books + return (isDisenchantableItem(aStack) || isEnchantedBook(aStack)); + } + + @Override + public int getCapacity() { + return 16000; + } + + private boolean isDisenchantableItem(ItemStack aStack) { + return ((aStack.isItemEnchanted()) && (aStack.getItem().getItemEnchantability() > 0)); + } + + private boolean isEnchantedBook(ItemStack aStack) { + return (aStack.getItem() instanceof ItemEnchantedBook); + } + + private long generateEU() { + long tEU; + + if ((tEU = absorbFromEgg()) > 0) return tEU; + if ((tEU = absorbFromEnderCrystals()) > 0) return tEU; + if ((tEU = absorbFromEnchantedItems()) > 0) return tEU; + if ((tEU = absorbFromVisNet()) > 0) return tEU; + if ((tEU = absorbFromEssentiaContainers()) > 0) return tEU; + return 0; + } + + private long absorbFromEnchantedItems() { + ItemStack tStack = getBaseMetaTileEntity().getStackInSlot(getInputSlot()); + if (tStack == null) return 0; + if (tStack.stackSize == 0) return 0; + if (!(isDisenchantableItem(tStack) || isEnchantedBook(tStack))) return 0; + long tEU = 0; + // Convert enchantments to their EU Value + Map<?, ?> tMap = EnchantmentHelper.getEnchantments(tStack); + for (Map.Entry<?, ?> e : tMap.entrySet()) { + if ((Integer) e.getKey() < Enchantment.enchantmentsList.length) { + Enchantment tEnchantment = Enchantment.enchantmentsList[(Integer) e.getKey()]; + Integer tLevel = (Integer) e.getValue(); + tEU += 1000000 * tLevel / (tEnchantment.getMaxLevel() * tEnchantment.getWeight()); + } + } + if (isDisenchantableItem(tStack)) { + EnchantmentHelper.setEnchantments(new HashMap(), tStack); + tEU = tEU * getEfficiency() / 100; + } else if (isEnchantedBook(tStack)) { + tStack = new ItemStack(Items.book, 1); + } + + // Only consume input if can store EU and push output + if ((getBaseMetaTileEntity().getStoredEU() + tEU) < getBaseMetaTileEntity().getEUCapacity() + && getBaseMetaTileEntity().addStackToSlot(getOutputSlot(), tStack)) { + decrStackSize(getInputSlot(), 1); + } else { + tEU = 0; + } + return tEU; + } + + private boolean hasEgg() { + Block above = getBaseMetaTileEntity().getBlockOffset(0, 1, 0); + return isEgg(above); + } + + private long absorbFromEgg() { + if (!hasEgg()) return 0; + if (!sAllowMultipleEggs) { + if (sActiveSiphon != null + && sActiveSiphon != this + && sActiveSiphon.getBaseMetaTileEntity() != null + && !sActiveSiphon.getBaseMetaTileEntity().isInvalidTileEntity() + && sActiveSiphon.isChunkLoaded() + && sActiveSiphon.hasEgg()) { + getBaseMetaTileEntity().doExplosion(Integer.MAX_VALUE); + } else { + setActiveSiphon(this); + } + } + return sDragonEggEnergyPerTick; + } + + private long absorbFromEnderCrystals() { + if (sEnergyPerEndercrystal <= 0) return 0; + long tEU = 0; + for (GT_MetaTileEntity_MagicalEnergyAbsorber tSubscriber : sSubscribedCrystals.values()) { + if (tSubscriber == this) { // This Crystal is for me + tEU += sEnergyPerEndercrystal; + } + } + return tEU; + } + + private long absorbFromVisNet() { + if (!THAUMCRAFT_LOADED) return 0; + + long tEU; + IGregTechTileEntity tBaseMetaTileEntity = getBaseMetaTileEntity(); + World tWorld = tBaseMetaTileEntity.getWorld(); + int tX = tBaseMetaTileEntity.getXCoord(); + int tY = tBaseMetaTileEntity.getYCoord(); + int tZ = tBaseMetaTileEntity.getZCoord(); + + // Attempt to drain as much Vis as needed for max EU/t, from all primal aspects. + int toDrain = mMaxVisPerDrain; + + for (int i = sPrimalAspects.size() - 1; i >= 0 && toDrain > 0; i--) { + toDrain -= VisNetHandler.drainVis(tWorld, tX, tY, tZ, sPrimalAspects.get(i), toDrain); + } + + int drained = mMaxVisPerDrain - toDrain; + tEU = (long) Math.min(maxEUOutput(), (Math.pow(drained, 2) * sEnergyFromVis * getEfficiency() / 10000)); + + return tEU; + } + + private long absorbFromEssentiaContainers() { + if (!THAUMCRAFT_LOADED) return 0; + + long tEU = 0; + + long tEUtoGen = getBaseMetaTileEntity().getEUCapacity() - getBaseMetaTileEntity().getUniversalEnergyStored(); + List<Aspect> mAvailableEssentiaAspects = mMagicalEnergyBB.getAvailableAspects(); + + // try to drain 1 of whatever aspect available in containers within RANGE + for (int i = mAvailableEssentiaAspects.size() - 1; i >= 0 && tEUtoGen > 0; i--) { + Aspect aspect = mAvailableEssentiaAspects.get(i); + long tAspectEU = (sAspectsEnergy.get(aspect) * getEfficiency()) / 100; + if (tAspectEU <= tEUtoGen + && AspectSourceHelper.drainEssentia((TileEntity) getBaseMetaTileEntity(), aspect, ForgeDirection.UNKNOWN, mMagicalEnergyBB.getRange())) { + tEUtoGen -= tAspectEU; + tEU += tAspectEU; + } + } + return tEU; + } + + private boolean isEgg(Block aBlock) { + if (aBlock == null) return false; + if (aBlock == Blocks.air) return false; + if (aBlock == Blocks.dragon_egg) return true; + if (aBlock instanceof BlockDragonEgg) return true; + return (aBlock.getUnlocalizedName().equals("tile.dragonEgg")); + } + + private boolean isChunkLoaded() { + IGregTechTileEntity tBaseMetaTileEntity = getBaseMetaTileEntity(); + int tX = tBaseMetaTileEntity.getXCoord(); + int tY = tBaseMetaTileEntity.getYCoord(); + World tWorld = tBaseMetaTileEntity.getWorld(); + Chunk tChunk = tWorld.getChunkFromBlockCoords(tX, tY); + return tChunk.isChunkLoaded; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_MagicalEnergyAbsorber(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("mMagicalEnergyBBTier", mMagicalEnergyBB.getTier()); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mMagicalEnergyBB.setTier(aNBT.getInteger("mMagicalEnergyBBTier")); + } + + /** + * Handles Bounding Box ranged operations for Magic sources + */ + static class MagicalEnergyBB { + private GT_MetaTileEntity_MagicalEnergyAbsorber mAbsorber; + private MagicalEnergyBBListener mListener; + private int mDefaultTier; + private int mTier; + private int mMaxTier; + private List<UUID> mLivingCrystalIDs = new ArrayList<>(); + private List<Aspect> mAvailableAspects; + + /** + * @param aAbsorber user and subscriber for updated BB content + * @param aDefaultTier Initial tier value + * @param aMaxTier Maximum allowed tier + */ + MagicalEnergyBB(GT_MetaTileEntity_MagicalEnergyAbsorber aAbsorber, int aDefaultTier, int aMaxTier) { + mAbsorber = aAbsorber; + mListener = aAbsorber; + mMaxTier = Math.max(aMaxTier > 0 ? aMaxTier : 0, aDefaultTier > 0 ? aDefaultTier : 0); + mDefaultTier = Math.min(aDefaultTier, mMaxTier); + mTier = mDefaultTier; + if (THAUMCRAFT_LOADED) mAvailableAspects = new ArrayList<>(Aspect.aspects.size()); + } + + int getTier() { + return mTier; + } + + /** + * Set Bounding Box Tier within allowed bounds + * + * @param aTier new tier value + * @return effective new tier + */ + int setTier(int aTier) { + if (aTier >= 0) { + if (aTier <= mMaxTier) { + mTier = aTier; + } else { + mTier = mMaxTier; + } + } else { + mTier = 0; + } + return mTier; + } + + int getRange() { + return getRange(mTier); + } + + int getRange(int aTier) { + return 1 << aTier; + } + + int getDefaultTier() { + return mDefaultTier; + } + + int getDefaultRange() { + return getRange(getDefaultTier()); + } + + int getMaxTier() { + return mMaxTier; + } + + int getMaxRange() { + return getRange(getMaxTier()); + } + + private AxisAlignedBB getAxisAlignedBB() { + double tRange = getRange(); + IGregTechTileEntity tBaseMetaTileEntity = mAbsorber.getBaseMetaTileEntity(); + double tX = tBaseMetaTileEntity.getXCoord(); + double tY = tBaseMetaTileEntity.getYCoord(); + double tZ = tBaseMetaTileEntity.getZCoord(); + return AxisAlignedBB.getBoundingBox(tX - tRange, tY - tRange, tZ - tRange, + tX + tRange, tY + tRange, tZ + tRange); + } + + private void scanLivingCrystals() { + World tWorld = mAbsorber.getBaseMetaTileEntity().getWorld(); + mLivingCrystalIDs.clear(); + for (Object o : tWorld.getEntitiesWithinAABB(EntityEnderCrystal.class, + getAxisAlignedBB())) { + if (((EntityEnderCrystal) o).isEntityAlive()) { + mLivingCrystalIDs.add(((EntityEnderCrystal) o).getPersistentID()); + } + } + } + + private void scanAvailableAspects() { + if (!THAUMCRAFT_LOADED) return; + IGregTechTileEntity tBaseMetaTileEntity = mAbsorber.getBaseMetaTileEntity(); + if (tBaseMetaTileEntity.isInvalidTileEntity()) return; + int tRange = getRange(); + mAvailableAspects.clear(); + for (int rX = -tRange; rX <= tRange; rX++) { + for (int rZ = -tRange; rZ <= tRange; rZ++) { + // rY < tRange is not a bug. See: thaumcraft.common.lib.events.EssentiaHandler.getSources() + for (int rY = -tRange; rY < tRange; rY++) { + TileEntity tTile = tBaseMetaTileEntity.getTileEntityOffset(rX, rY, rZ); + if (tTile instanceof IAspectSource) { + Set<Aspect> tAspects = ((IAspectSource) tTile).getAspects().aspects.keySet(); + mAvailableAspects.addAll(tAspects); + } + } + } + } + } + + /** + * @return List of Living Ender Crystal Entity IDs in range + */ + List<UUID> getLivingCrystalIDs() { + return mLivingCrystalIDs; + } + + /** + * @return List of drainable Essentia Aspects from containers in range + */ + List<Aspect> getAvailableAspects() { + return mAvailableAspects; + } + + /** + * Scan range for magic sources + */ + void update() { + if (mAbsorber == null) return; + if (mAbsorber.getBaseMetaTileEntity() == null) return; + if (mAbsorber.getBaseMetaTileEntity().isInvalidTileEntity()) return; + if (mAbsorber.getBaseMetaTileEntity().getWorld() == null) return; + scanLivingCrystals(); + scanAvailableAspects(); + if (mListener != null) { + mListener.onMagicalEnergyBBUpdate(); + } + } + + void increaseTier() { + offsetTier(1); + } + + void decreaseTier() { + offsetTier(-1); + } + + /** + * Change the Bounding Box tier relatively to offset + * with wrapping at tier limits + * + * @param aOffset relative tier change + */ + void offsetTier(int aOffset) { + int tNumTiers = mMaxTier + 1; + int tTier = (mTier + aOffset + tNumTiers) % tNumTiers; + int tTrueTier = setTier(tTier); + if (tTier != tTrueTier) { + GT_Log.out.format("Absorber's BB Tier set to %d was capped to %d", tTier, tTrueTier); + } + } + } }
\ No newline at end of file |