diff --git a/dependencies.gradle b/dependencies.gradle index e0e3d971..36afbd01 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -2,26 +2,26 @@ dependencies { api('com.github.GTNewHorizons:EnderCore:0.5.14:dev') {transitive = false} - compileOnly('com.github.GTNewHorizons:ForestryMC:4.11.32:dev') - compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.8.118-GTNH:dev') - api("com.github.GTNewHorizons:GTNHLib:0.11.35:dev") + compileOnly('com.github.GTNewHorizons:ForestryMC:4.11.37:dev') + compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.8.129-GTNH:dev') + api("com.github.GTNewHorizons:GTNHLib:0.11.44:dev") compileOnly('com.github.GTNewHorizons:BuildCraft:7.1.63:dev') api('curse.maven:cofh-lib-220333:2388748') // https://www.curseforge.com/minecraft/mc-mods/cofh-lib/files/2388748 shadowImplementation('cglib:cglib-nodep:3.3.0') - api("com.github.GTNewHorizons:TinkersConstruct:1.14.96-GTNH:dev") + api("com.github.GTNewHorizons:TinkersConstruct:1.14.106-GTNH:dev") - devOnlyNonPublishable('com.github.GTNewHorizons:waila:1.19.31:dev') {transitive = false} + devOnlyNonPublishable('com.github.GTNewHorizons:waila:1.19.34:dev') {transitive = false} compileOnly('ganymedes01.etfuturum:Et-Futurum-Requiem:2.6.48-GTNH:dev') {transitive = false} runtimeOnlyNonPublishable('com.github.GTNewHorizons:WAILAPlugins:0.7.2:dev') {transitive = false} - compileOnly("com.github.GTNewHorizons:Backhand:1.8.13:dev") { transitive = false } + compileOnly("com.github.GTNewHorizons:Backhand:1.8.14:dev") { transitive = false } compileOnly('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-999-GTNH:api') {transitive = false} - compileOnly('com.github.GTNewHorizons:Baubles-Expanded:2.2.21-GTNH:dev') {transitive = false} - compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.54.73:dev') {transitive = false} - compileOnly("com.github.GTNewHorizons:ModularUI2:2.3.85-1.7.10:dev") {transitive = false} - compileOnly('com.github.GTNewHorizons:Railcraft:9.17.30:dev') {transitive = false} - compileOnly('com.github.GTNewHorizons:StorageDrawers:2.2.26-GTNH:api') {transitive = false} - compileOnly('com.github.GTNewHorizons:Chisel:2.17.31-GTNH:dev') {transitive = false} - compileOnly('com.github.GTNewHorizons:OpenComputers:1.12.55-GTNH:api') {transitive = false} + compileOnly('com.github.GTNewHorizons:Baubles-Expanded:2.2.22-GTNH:dev') {transitive = false} + compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.54.122:dev') {transitive = false} + compileOnly("com.github.GTNewHorizons:ModularUI2:2.3.88-1.7.10:dev") {transitive = false} + compileOnly('com.github.GTNewHorizons:Railcraft:9.17.31:dev') {transitive = false} + compileOnly('com.github.GTNewHorizons:StorageDrawers:2.2.29-GTNH:api') {transitive = false} + compileOnly('com.github.GTNewHorizons:Chisel:2.17.32-GTNH:dev') {transitive = false} + compileOnly('com.github.GTNewHorizons:OpenComputers:1.12.59-GTNH:api') {transitive = false} compileOnly('curse.maven:minefactory-reloaded-66672:2366150') // https://www.curseforge.com/minecraft/mc-mods/minefactory-reloaded/files/2366150 compileOnly('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev') compileOnly('curse.maven:ee3-65509:2305023') // https://www.curseforge.com/minecraft/mc-mods/ee3/files/2305023 @@ -29,7 +29,7 @@ dependencies { compileOnly(rfg.deobf('curse.maven:mekanism-268560:2475797')) // https://www.curseforge.com/minecraft/mc-mods/mekanism/files/2475797 compileOnly(rfg.deobf('maven.modrinth:immibis-microblocks:59.1.2')) // https://modrinth.com/mod/immibis-microblocks/version/59.1.2 - compileOnlyApi('com.github.GTNewHorizons:Angelica:2.1.60:api') {transitive = false} - compileOnly("com.github.GTNewHorizons:Hodgepodge:2.7.179:dev") + compileOnlyApi('com.github.GTNewHorizons:Angelica:2.2.8:api') {transitive = false} + compileOnly("com.github.GTNewHorizons:Hodgepodge:2.7.194:dev") compileOnly('curse.maven:automagy-222153:2285272') } diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties index ebbbdaea..1924b053 100644 --- a/gradle/gradle-daemon-jvm.properties +++ b/gradle/gradle-daemon-jvm.properties @@ -1,12 +1,12 @@ #This file is generated by updateDaemonJvm -toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect -toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect -toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect -toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect -toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1df82b76031285ef2e6a4f59ffe9299d/redirect -toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/c7d5be6a02945ac2e045048ee54a7d32/redirect -toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97d46b5ff4df0bf61e95652a190a5567/redirect -toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/9ef54a08e06b0754cee9fc95ed3a3134/redirect -toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/643f404f769811f5f265fd66f7af5d89/redirect -toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/38256085a73e137cb4937ea9c4807fec/redirect +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9064f22734b42ac03e85df04b632e167/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/4d0277c49991306ac78048580fe34bcf/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/539ea72837c6244075f8ee037babc29e/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/876dbbf00bf4ef6190f7da074cee903a/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/a9fa3b809e484a1e1ac4308a5dda661a/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/aa99913fa6d767d899ffc96082da01ca/redirect toolchainVersion=25 diff --git a/settings.gradle b/settings.gradle index 8b837e51..b9976f56 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,7 @@ pluginManagement { } plugins { - id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.27' + id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.29' } diff --git a/src/main/java/crazypants/enderio/config/Config.java b/src/main/java/crazypants/enderio/config/Config.java index 2faaf580..fd0bbdf2 100644 --- a/src/main/java/crazypants/enderio/config/Config.java +++ b/src/main/java/crazypants/enderio/config/Config.java @@ -597,6 +597,11 @@ public final class Config { public static float fusedQuartzExplosionResistance = 2000.0f; + public static boolean enchanterOutputEnableBlockRestriction = false; + public static boolean enchanterOutputAllowlistAsDenylist = false; + public static String[] enchanterOutputFilterlist = new String[] { "minecraft:hopper", + "EnderIO:blockConduitBundle" }; + public static void load(FMLPreInitializationEvent event) { PacketHandler.INSTANCE .registerMessage(PacketConfigSync.class, PacketConfigSync.class, PacketHandler.nextID(), Side.CLIENT); @@ -2978,6 +2983,22 @@ public final class Config { 0.0f, Float.MAX_VALUE, "How blast resistant the three Fused Quartz blocks should be."); + + enchanterOutputEnableBlockRestriction = config.getBoolean( + "enchanterOutputEnableBlockRestriction", + sectionMisc.name, + enchanterOutputEnableBlockRestriction, + "Enable restricting the valid blocks that are allowed to pull from the output slot of an Enchanter, to prevent dupes"); + enchanterOutputAllowlistAsDenylist = config.getBoolean( + "enchanterOutputAllowlistAsDenylist", + sectionMisc.name, + enchanterOutputAllowlistAsDenylist, + "Treat the list of blocks allowed to pull from an Enchanter's output slot as a denylist instead (if you know only some specific blocks bypass inventory APIs)"); + enchanterOutputFilterlist = config.getStringList( + "enchanterOutputFilterlist", + sectionMisc.name, + enchanterOutputFilterlist, + "These blocks are allowed/denied from pulling from the output slot of an Enchanter (default is allowlist)"); } public static void checkYetaAccess() { diff --git a/src/main/java/crazypants/enderio/machine/enchanter/ContainerEnchanter.java b/src/main/java/crazypants/enderio/machine/enchanter/ContainerEnchanter.java index 35c8c1cc..db4d49c4 100644 --- a/src/main/java/crazypants/enderio/machine/enchanter/ContainerEnchanter.java +++ b/src/main/java/crazypants/enderio/machine/enchanter/ContainerEnchanter.java @@ -68,6 +68,11 @@ public class ContainerEnchanter extends ContainerEnderTileEntity return false; } + @Override + public ItemStack getStack() { + return te.getOutput(); + } + @Override public void onPickupFromSlot(EntityPlayer player, ItemStack stack) { if (!player.capabilities.isCreativeMode) { diff --git a/src/main/java/crazypants/enderio/machine/enchanter/TileEnchanter.java b/src/main/java/crazypants/enderio/machine/enchanter/TileEnchanter.java index 6eb64c1e..6c994e99 100644 --- a/src/main/java/crazypants/enderio/machine/enchanter/TileEnchanter.java +++ b/src/main/java/crazypants/enderio/machine/enchanter/TileEnchanter.java @@ -2,8 +2,6 @@ package crazypants.enderio.machine.enchanter; import static crazypants.enderio.EnderIO.hasAutomagy; -import java.util.ArrayList; - import net.minecraft.enchantment.EnchantmentData; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; @@ -11,16 +9,21 @@ import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; import com.gtnewhorizon.gtnhlib.geometry.CubeIterator; +import cpw.mods.fml.common.registry.GameRegistry; +import crazypants.enderio.Log; import crazypants.enderio.ModObject; import crazypants.enderio.TileEntityEio; import crazypants.enderio.config.Config; import crazypants.enderio.machine.obelisk.xp.TileExperienceObelisk; import crazypants.enderio.xp.ExperienceContainer; import crazypants.enderio.xp.XpUtil; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; import tuhljin.automagy.tiles.TileEntityJarXP; public class TileEnchanter extends TileEntityEio implements ISidedInventory { @@ -28,6 +31,8 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { private final ItemStack[] inv = new ItemStack[3]; private byte[] stacksizes = new byte[2]; + private IntList cachedXPsources = new IntArrayList(); + private short facing = (short) ForgeDirection.NORTH.ordinal(); public void setFacing(short s) { @@ -65,6 +70,9 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { root.setTag("Items", itemList); root.setByteArray("SizeCache", stacksizes); root.setShort("facing", facing); + root.setIntArray( + "XpCache", + (cachedXPsources.size() <= 200 ? cachedXPsources : cachedXPsources.subList(0, 200)).toIntArray()); } @Override @@ -82,6 +90,11 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { stacksizes = root.getByteArray("SizeCache"); if (stacksizes == null || stacksizes.length < 2) stacksizes = new byte[2]; facing = root.getShort("facing"); + cachedXPsources.clear(); + int[] xpcache = root.getIntArray("XpCache"); + if (xpcache != null) { + cachedXPsources.addAll(IntList.of(xpcache)); + } } @Override @@ -96,9 +109,10 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { @Override public ItemStack getStackInSlot(int slot) { - if (slot < 0 || slot >= inv.length) { + if (slot < 0 || slot > inv.length - 1) { return null; } + if (slot == 2 && !doesCraftHaveXP()) return null; return inv[slot]; } @@ -130,69 +144,97 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { return result; } - // part of the next method - public boolean absorbXP(int amt) { - if (inv[2] == null || amt <= 0 || inv[2].stackSize < amt) return true; + public boolean doesCraftHaveXP() { + if (inv[2] == null) return false; int LV = getCurrentEnchantmentCost(); - if (LV == 0) return false; - int xpCost = XpUtil.getExperienceForLevel(LV * amt); - int xp; - absorb: { - ArrayList obelisksToEmpty = new ArrayList<>(); - if (true) { - CubeIterator iter = new CubeIterator(8); - while (iter.hasNext()) { - iter.next(); - if (worldObj.getTileEntity( - iter.n + xCoord, - iter.l + yCoord, - iter.m + zCoord) instanceof TileExperienceObelisk obelisk) { - ExperienceContainer cont = obelisk.getContainer(); - xp = cont.getExperienceTotal(); - if (xp >= xpCost) { - if (!worldObj.isRemote) { - obelisksToEmpty.forEach(o -> o.drain(null, Integer.MAX_VALUE, true)); - cont.drain(null, Integer.MAX_VALUE, true); - cont.addExperience(Math.max(0, xp - xpCost)); - } - return false; - } - xpCost -= xp; - obelisksToEmpty.add(cont); - } - } - } - if (hasAutomagy) { - ArrayList jarsToEmpty = new ArrayList<>(); - CubeIterator iter = new CubeIterator(8); - while (iter.hasNext()) { - iter.next(); - if (worldObj.getTileEntity( - iter.n + xCoord, - iter.l + yCoord, - iter.m + zCoord) instanceof TileEntityJarXP jar) { - xp = jar.getXP(); - if (xp >= xpCost) { - if (!worldObj.isRemote) { - obelisksToEmpty.forEach(o -> o.drain(null, Integer.MAX_VALUE, true)); - jarsToEmpty.forEach(j -> j.setXP(0)); - jar.setXP(xp - xpCost); - } - return false; - } - xpCost -= xp; - jarsToEmpty.add(jar); - } - } - } - return true; - } + if (LV == 0) return true; + return checkAndCacheXPSources(XpUtil.getExperienceForLevel(LV)); } - // checks AND drains XP; returns true if xp is NOT sufficient + private boolean checkAndCacheXPSources(int xpCost) { + if (drainFromCache(xpCost, false)) return true; + cachedXPsources.clear(); + int xp; + CubeIterator iter; + iter = new CubeIterator(8); + while (iter.hasNext()) { + iter.next(); + int x = iter.n + xCoord; + int y = iter.l + yCoord; + int z = iter.m + zCoord; + if (!worldObj.blockExists(x, y, z)) continue; + final TileEntity te = worldObj.getTileEntity(x, y, z); + if (te instanceof TileExperienceObelisk obelisk) { + ExperienceContainer cont = obelisk.getContainer(); + xp = cont.getExperienceTotal(); + if (xp != 0) cachedXPsources.add(((iter.n & 0xff) << 16) + ((iter.l & 0xff) << 8) + (iter.m & 0xff)); + if (xp >= xpCost) return true; + xpCost -= xp; + } else if (hasAutomagy && te instanceof TileEntityJarXP jar) { + xp = jar.getXP(); + if (xp != 0) cachedXPsources.add(((iter.n & 0xff) << 16) + ((iter.l & 0xff) << 8) + (iter.m & 0xff)); + if (xp >= xpCost) return true; + xpCost -= xp; + } + } + return false; + } + + private boolean drainFromCache(int xpCost, boolean actual) { + ExperienceContainer cont; + int len = cachedXPsources.size(); + if (len == 0) return false; + for (int ind = 0; ind < len; ind++) { + int nlm = cachedXPsources.getInt(ind); + int z = (byte) nlm + zCoord; + int y = (byte) (nlm >>= 8) + yCoord; + int x = (byte) (nlm >>= 8) + xCoord; + if (!worldObj.blockExists(x, y, z)) continue; + TileEntity te = worldObj.getTileEntity(x, y, z); + if (te instanceof TileExperienceObelisk obelisk) { + cont = obelisk.getContainer(); + int xp = cont.getExperienceTotal(); + if (xp == 0) continue; + if (actual) cont.drain(null, Integer.MAX_VALUE, true); + int ebx = xp - xpCost; + if (ebx < 0) { + xpCost = -ebx; + continue; + } + if (actual) cont.addExperience(ebx); + return true; + } + if (hasAutomagy && te instanceof TileEntityJarXP jar) { + int xp = jar.getXP(); + if (xp == 0) continue; + int ebx = xp - xpCost; // 5head JIT optimization + if (ebx < 0) { + xpCost = -ebx; + if (actual) jar.setXP(0); + continue; + } + if (actual) jar.setXP(ebx); + return true; + } + cachedXPsources.removeInt(ind); + } + return false; + } + + // part of the next method + private boolean absorbXP(int amt) { + if (inv[2] == null) return false; + int LV = getCurrentEnchantmentCost(); + if (LV == 0) return true; + int xpCost = XpUtil.getExperienceForLevel(LV * amt); + if (!checkAndCacheXPSources(xpCost)) return false; + return drainFromCache(xpCost, !worldObj.isRemote); + } + + // checks AND drains XP; returns false if xp is not sufficient // also removes the items from the other two slots when automation does the recipe - public boolean checkAndDrainXP(int amt) { - if (absorbXP(amt)) return true; + private boolean checkAndDrainXP(int amt) { + if (!absorbXP(amt)) return false; EnchantmentData enchData = getCurrentEnchantmentData(); EnchanterRecipe recipe = getCurrentEnchantmentRecipe(); ItemStack curStack = inv[1]; @@ -212,7 +254,7 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { if (!worldObj.isRemote) { worldObj.playSoundEffect(xCoord + 0.5d, yCoord + 0.5d, zCoord + 0.5d, "random.anvil_land", 0.2f, 1.0f); } - return false; + return true; } @Override @@ -222,6 +264,15 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { @Override public void setInventorySlotContents(int slot, ItemStack contents) { + if (slot == 2) { + if (inv[2] == null || inv[2].stackSize <= 0 + || contents != null && contents.stackSize > 0 + && contents.getItem() == Items.enchanted_book + && contents.stackSize == inv[2].stackSize) + return; + if (checkAndDrainXP(1)) Log.warn("Potentially duped books at: " + xCoord + " " + yCoord + " " + zCoord); + // return; + } ; if (contents == null) { inv[slot] = contents; } else { @@ -240,10 +291,11 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { output = new ItemStack(Items.enchanted_book); Items.enchanted_book.addEnchantment(output, enchantment); } - setOutput(output); if (inv[0] != null) stacksizes[0] = (byte) inv[0].stackSize; if (inv[1] != null) stacksizes[1] = (byte) inv[1].stackSize; + + setOutput(output); } @Override @@ -388,18 +440,34 @@ public class TileEnchanter extends TileEntityEio implements ISidedInventory { markDirty(); } + public ItemStack getOutput() { + return inv[2]; + } + @Override public int[] getAccessibleSlotsFromSide(int side) { return side == 0 ? new int[] { 2 } : new int[] { 0, 1 }; } @Override - public boolean canInsertItem(int p_102007_1_, ItemStack p_102007_2_, int p_102007_3_) { - return true; + public boolean canInsertItem(int slot, ItemStack p_102007_2_, int p_102007_3_) { + return slot == 0 || slot == 1; } @Override - public boolean canExtractItem(int p_102008_1_, ItemStack p_102008_2_, int p_102008_3_) { - return true; + public boolean canExtractItem(int slot, ItemStack p_102008_2_, int p_102008_3_) { + return slot == 2 ? isAllowedBlockBeneath() : true; } + + public boolean isAllowedBlockBeneath() { + if (!Config.enchanterOutputEnableBlockRestriction) return true; + var blockBeneath = worldObj.getBlock(this.xCoord, this.yCoord - 1, this.zCoord); + for (String blocknam : Config.enchanterOutputFilterlist) { + String[] splitname = blocknam.split(":", 1); + if (GameRegistry.findBlock(splitname[0], splitname[1]) != blockBeneath) continue; + return !Config.enchanterOutputAllowlistAsDenylist; + } + return Config.enchanterOutputAllowlistAsDenylist; + } + }