From bf35baac77363fa5ccd06134ef89258a78b230ad Mon Sep 17 00:00:00 2001 From: Tobias Date: Sun, 19 May 2019 15:34:04 +0000 Subject: [PATCH] Improved Compression Sigil performance & fixed leftover eating bug (#1603) * Performance improvements, small cleanup * Moved the saved stacks to class scope to have an actual effect. * Variable scope change (no effect) * Saving known recipes to a Map in CompressionRegistry now, allowing quick lookup as long as the server has not been restarted for all but the first compression recipe of every itemstack type encountered. Fixed compression process consuming items even though the compression would not finish. --- .../compress/AdvancedCompressionHandler.java | 96 +++--------- .../compress/CompressionHandler.java | 23 ++- .../compress/CompressionRegistry.java | 22 ++- .../compress/StorageBlockCraftingManager.java | 146 ++++++++++-------- 4 files changed, 135 insertions(+), 152 deletions(-) diff --git a/src/main/java/WayofTime/bloodmagic/compress/AdvancedCompressionHandler.java b/src/main/java/WayofTime/bloodmagic/compress/AdvancedCompressionHandler.java index b5d78913..e2dc02d1 100644 --- a/src/main/java/WayofTime/bloodmagic/compress/AdvancedCompressionHandler.java +++ b/src/main/java/WayofTime/bloodmagic/compress/AdvancedCompressionHandler.java @@ -1,86 +1,12 @@ package WayofTime.bloodmagic.compress; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.CraftingManager; -import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.Tuple; import net.minecraft.world.World; public class AdvancedCompressionHandler extends CompressionHandler { - private static InventoryCrafting[] inventoryCrafting = { - new InventoryCrafting(new Container() { - public boolean canInteractWith(EntityPlayer player) { - return false; - } - }, - 3, 3), - new InventoryCrafting(new Container() { - public boolean canInteractWith(EntityPlayer player) { - return false; - } - }, - 2, 2), - new InventoryCrafting(new Container() { - public boolean canInteractWith(EntityPlayer player) { - return false; - } - }, - 1, 1) - - }; - - private static ItemStack reversibleCheck; - - public static boolean isResultStackReversible(ItemStack stack, World world) { - if (stack.isEmpty()) { - return false; - } - - inventoryCrafting[2].setInventorySlotContents(0, stack); - ItemStack returnStack = getNNRecipeOutput(inventoryCrafting[2], world); - - return !returnStack.isEmpty() && CompressionRegistry.areItemStacksEqual(reversibleCheck, returnStack); - } - - public static ItemStack getRecipe(ItemStack stack, World world, int gridSize) { - StorageBlockCraftingManager craftingManagerSB = StorageBlockCraftingManager.getInstance(); - InventoryCrafting inventory = inventoryCrafting[3 - gridSize]; - for (int i = 0; i < inventory.getSizeInventory(); i++) { - inventory.setInventorySlotContents(i, stack); - } - ItemStack notEmptyRecipe = craftingManagerSB.findMatchingRecipe(inventory, world); - if (!notEmptyRecipe.isEmpty()) { - return notEmptyRecipe; - } - ItemStack result = getNNRecipeOutput(inventory, world); - - if (isResultStackReversible(result, world)) { - craftingManagerSB.addRecipe(CraftingManager.findMatchingRecipe(inventory, world)); - return result; - } - return ItemStack.EMPTY; - } - - public static ItemStack getNNRecipeOutput(InventoryCrafting inventory, World world) { - IRecipe checkForNull = CraftingManager.findMatchingRecipe(inventory, world); - if (checkForNull != null) { - return checkForNull.getRecipeOutput(); - } - return ItemStack.EMPTY; - } - - public static ItemStack get22Recipe(ItemStack stack, World world) { - return getRecipe(stack, world, 2); - } - - public static ItemStack get33Recipe(ItemStack stack, World world) { - return getRecipe(stack, world, 3); - } - public ItemStack compressInventory(ItemStack[] inv, World world) { for (ItemStack invStack : inv) { if (invStack.isEmpty()) { @@ -88,12 +14,26 @@ public class AdvancedCompressionHandler extends CompressionHandler { } for (int i = 3; i >= 2; i--) { - reversibleCheck = invStack; - ItemStack stack = getRecipe(invStack, world, i); + ItemStack invStackCopy = invStack.copy(); + invStackCopy.setCount(1); + Tuple stackTuple = CompressionRegistry.compressionMap.get(invStackCopy); + ItemStack stack; + if (stackTuple == null) { + StorageBlockCraftingManager.reversibleCheck = invStack; + stack = StorageBlockCraftingManager.getRecipe(invStack, world, i); + if (stack.isEmpty()) + continue; + CompressionRegistry.compressionMap.put(invStackCopy, new Tuple<>(stack, i * i)); + } else { + stack = stackTuple.getFirst(); + if (stackTuple.getSecond() != i * i) + return ItemStack.EMPTY; + } + if (!stack.isEmpty()) { int needed = (i == 2 ? 4 : 9); - int remaining = iterateThroughInventory(invStack, invStack.getMaxStackSize() - needed, inv, needed, true); // if more than needed gets consumed at any point, the simulate test was needed after all + int remaining = iterateThroughInventory(invStack, CompressionRegistry.getItemThreshold(invStack, needed), inv, needed, true); if (remaining <= 0) return stack; } diff --git a/src/main/java/WayofTime/bloodmagic/compress/CompressionHandler.java b/src/main/java/WayofTime/bloodmagic/compress/CompressionHandler.java index 2cd74d14..715a7b19 100644 --- a/src/main/java/WayofTime/bloodmagic/compress/CompressionHandler.java +++ b/src/main/java/WayofTime/bloodmagic/compress/CompressionHandler.java @@ -3,6 +3,9 @@ package WayofTime.bloodmagic.compress; import net.minecraft.item.ItemStack; import net.minecraft.world.World; +import java.util.HashSet; +import java.util.Set; + public abstract class CompressionHandler { /** * Called to look at the inventory and syphons the required stack. Returns @@ -14,7 +17,9 @@ public abstract class CompressionHandler { public abstract ItemStack compressInventory(ItemStack[] inv, World world); public int iterateThroughInventory(ItemStack required, int kept, ItemStack[] inv, int needed, boolean doDrain) { + int oldNeeded = needed; int i = -1; + Set consumeSet = new HashSet<>(); for (ItemStack invStack : inv) { i++; @@ -31,26 +36,32 @@ public abstract class CompressionHandler { used += stackSize - remainingFromStack; } - kept -= used; // 0 + kept -= used; if (kept <= 0 && needed > 0) { int remainingFromStack = Math.max(stackSize - used - needed, 0); - if (doDrain) { + needed -= (stackSize - used - remainingFromStack); + if (needed != 0 && needed < oldNeeded) { + consumeSet.add(i); + } + + if (doDrain && (!(needed < oldNeeded) || needed == 0)) { invStack.setCount(remainingFromStack + used); + for (Integer j : consumeSet) { + inv[j].setCount(0); + inv[j] = ItemStack.EMPTY; + } + consumeSet.clear(); if (invStack.isEmpty()) { inv[i] = ItemStack.EMPTY; } } - - needed -= (stackSize - used - remainingFromStack); } - if (needed <= 0) { return 0; } } } - return needed; diff --git a/src/main/java/WayofTime/bloodmagic/compress/CompressionRegistry.java b/src/main/java/WayofTime/bloodmagic/compress/CompressionRegistry.java index 8c10fa3a..fb1de055 100644 --- a/src/main/java/WayofTime/bloodmagic/compress/CompressionRegistry.java +++ b/src/main/java/WayofTime/bloodmagic/compress/CompressionRegistry.java @@ -3,6 +3,7 @@ package WayofTime.bloodmagic.compress; import WayofTime.bloodmagic.util.Utils; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Tuple; import net.minecraft.world.World; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; @@ -18,8 +19,9 @@ import java.util.Map; * form. */ public class CompressionRegistry { - public static List compressionRegistry = new ArrayList<>(); + private static List compressionRegistry = new ArrayList<>(); public static Map thresholdMap = new HashMap<>(); + static Map> compressionMap = new HashMap<>(); public static void registerHandler(CompressionHandler handler) { compressionRegistry.add(handler); @@ -77,10 +79,24 @@ public class CompressionRegistry { return Pair.of(ItemStack.EMPTY, false); } - public static int getItemThreshold(ItemStack stack) { - return stack.getItem().getItemStackLimit(stack); //this should work according to the guide, leaving behind a full stack of the source item (unless otherwise specified with a BaseCompressionHandler recipe) + + public static int getItemThreshold(ItemStack stack, int needed) { + Integer threshold = thresholdMap.get(stack); + if (threshold != null) + return threshold; + else + return stack.getMaxStackSize() - needed; } + public static int getItemThreshold(ItemStack stack) { + Integer threshold = thresholdMap.get(stack); + if (threshold != null) + return threshold; + else + return stack.getMaxStackSize(); + } + + public static boolean areItemStacksEqual(ItemStack stack, ItemStack compressedStack) { return stack.isItemEqual(compressedStack) && (stack.getTagCompound() == null ? !compressedStack.hasTagCompound() : stack.getTagCompound().equals(compressedStack.getTagCompound())); } diff --git a/src/main/java/WayofTime/bloodmagic/compress/StorageBlockCraftingManager.java b/src/main/java/WayofTime/bloodmagic/compress/StorageBlockCraftingManager.java index cfe039c1..71b6120e 100644 --- a/src/main/java/WayofTime/bloodmagic/compress/StorageBlockCraftingManager.java +++ b/src/main/java/WayofTime/bloodmagic/compress/StorageBlockCraftingManager.java @@ -6,15 +6,89 @@ import net.minecraft.inventory.Container; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; import net.minecraft.world.World; -import java.util.LinkedList; -import java.util.List; +import java.util.HashSet; +import java.util.Set; public class StorageBlockCraftingManager { private static final StorageBlockCraftingManager instance = new StorageBlockCraftingManager(); - private List recipes = new LinkedList<>(); + private static InventoryCrafting[] inventoryCrafting = { + new InventoryCrafting(new Container() { + public boolean canInteractWith(EntityPlayer player) { + return false; + } + }, + 3, 3), + new InventoryCrafting(new Container() { + public boolean canInteractWith(EntityPlayer player) { + return false; + } + }, + 2, 2), + new InventoryCrafting(new Container() { + public boolean canInteractWith(EntityPlayer player) { + return false; + } + }, + 1, 1) + + }; + static ItemStack reversibleCheck; + private HashSet recipes = new HashSet<>(); // TODO: Clear when recipes are reloaded in 1.14 + private Set blacklist = new HashSet<>(); + + public static boolean isResultStackReversible(ItemStack stack, World world) { + if (stack.isEmpty()) { + return false; + } + + inventoryCrafting[2].setInventorySlotContents(0, stack); + ItemStack returnStack = getNNRecipeOutput(inventoryCrafting[2], world); + + return !returnStack.isEmpty() && CompressionRegistry.areItemStacksEqual(reversibleCheck, returnStack); + } + + public static ItemStack getRecipe(ItemStack stack, World world, int gridSize) { + StorageBlockCraftingManager craftingManagerSB = getInstance(); + if (craftingManagerSB.blacklist.contains(stack)) { + return ItemStack.EMPTY; + } + InventoryCrafting inventory = inventoryCrafting[3 - gridSize]; + for (int i = 0; i < inventory.getSizeInventory(); i++) { + inventory.setInventorySlotContents(i, stack); + } + ItemStack notEmptyRecipe = craftingManagerSB.findMatchingRecipe(inventory, world); + if (!notEmptyRecipe.isEmpty()) { + return notEmptyRecipe; + } + ItemStack result = getNNRecipeOutput(inventory, world); + + if (isResultStackReversible(result, world)) { + craftingManagerSB.addRecipe(CraftingManager.findMatchingRecipe(inventory, world)); + return result; + } + craftingManagerSB.blacklist.add(stack); + return ItemStack.EMPTY; + } + + public static ItemStack getNNRecipeOutput(InventoryCrafting inventory, World world) { + IRecipe checkForNull = CraftingManager.findMatchingRecipe(inventory, world); + if (checkForNull != null) { + return checkForNull.getRecipeOutput(); + } + return ItemStack.EMPTY; + } + + public static ItemStack get22Recipe(ItemStack stack, World world) { + return getRecipe(stack, world, 2); + } + + public static ItemStack get33Recipe(ItemStack stack, World world) { + return getRecipe(stack, world, 3); + } public void addRecipe(IRecipe recipe) { this.recipes.add(recipe); @@ -32,7 +106,7 @@ public class StorageBlockCraftingManager { return this.findMatchingRecipe(craftingInventory, world, this.recipes); } - private ItemStack findMatchingRecipe(InventoryCrafting craftingInventory, World world, List list) { + private ItemStack findMatchingRecipe(InventoryCrafting craftingInventory, World world, HashSet list) { int i = 0; ItemStack itemstack = ItemStack.EMPTY; ItemStack itemstack1 = ItemStack.EMPTY; @@ -67,11 +141,10 @@ public class StorageBlockCraftingManager { return new ItemStack(itemstack.getItem(), 1, i1); } else { - for (j = 0; j < list.size(); ++j) { - IRecipe irecipe = list.get(j); + for (IRecipe iRecipe : list) { - if (irecipe.matches(craftingInventory, world)) { - return irecipe.getCraftingResult(craftingInventory); + if (iRecipe.matches(craftingInventory, world)) { + return iRecipe.getCraftingResult(craftingInventory); } } @@ -83,62 +156,5 @@ public class StorageBlockCraftingManager { return instance; } - private static boolean isResultStackReversible(ItemStack stack, int gridSize, World world, List list) { - if (stack.isEmpty()) { - return false; - } - InventoryCrafting inventory = new InventoryCrafting(new Container() { - public boolean canInteractWith(EntityPlayer player) { - return false; - } - }, 2, 2); - inventory.setInventorySlotContents(0, stack); - - ItemStack returnStack = StorageBlockCraftingManager.getInstance().findMatchingRecipe(inventory, world, list); - if (returnStack.isEmpty()) { - return false; - } - - ItemStack compressedStack = ItemStack.EMPTY; - switch (gridSize) { - case 2: - compressedStack = get22Recipe(returnStack, world, list); - break; - case 3: - compressedStack = get33Recipe(returnStack, world, list); - break; - } - - return !compressedStack.isEmpty() && CompressionRegistry.areItemStacksEqual(stack, compressedStack); - } - - private static ItemStack getRecipe(ItemStack stack, World world, int gridSize, List list) { - InventoryCrafting inventory = new InventoryCrafting(new Container() { - public boolean canInteractWith(EntityPlayer player) { - return false; - } - }, gridSize, gridSize); - for (int i = 0; i < inventory.getSizeInventory(); i++) { - inventory.setInventorySlotContents(i, stack); - } - - return StorageBlockCraftingManager.getInstance().findMatchingRecipe(inventory, world, list); - } - - private static boolean has22Recipe(ItemStack stack, World world, List list) { - return !get22Recipe(stack, world, list).isEmpty(); - } - - private static ItemStack get22Recipe(ItemStack stack, World world, List list) { - return getRecipe(stack, world, 2, list); - } - - private static boolean has33Recipe(ItemStack stack, World world, List list) { - return !get33Recipe(stack, world, list).isEmpty(); - } - - private static ItemStack get33Recipe(ItemStack stack, World world, List list) { - return getRecipe(stack, world, 3, list); - } }