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.
This commit is contained in:
parent
0090ec0a56
commit
bf35baac77
|
@ -1,86 +1,12 @@
|
||||||
package WayofTime.bloodmagic.compress;
|
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.ItemStack;
|
||||||
import net.minecraft.item.crafting.CraftingManager;
|
import net.minecraft.util.Tuple;
|
||||||
import net.minecraft.item.crafting.IRecipe;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
|
||||||
public class AdvancedCompressionHandler extends CompressionHandler {
|
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) {
|
public ItemStack compressInventory(ItemStack[] inv, World world) {
|
||||||
for (ItemStack invStack : inv) {
|
for (ItemStack invStack : inv) {
|
||||||
if (invStack.isEmpty()) {
|
if (invStack.isEmpty()) {
|
||||||
|
@ -88,12 +14,26 @@ public class AdvancedCompressionHandler extends CompressionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 3; i >= 2; i--) {
|
for (int i = 3; i >= 2; i--) {
|
||||||
reversibleCheck = invStack;
|
ItemStack invStackCopy = invStack.copy();
|
||||||
ItemStack stack = getRecipe(invStack, world, i);
|
invStackCopy.setCount(1);
|
||||||
|
Tuple<ItemStack, Integer> 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()) {
|
if (!stack.isEmpty()) {
|
||||||
|
|
||||||
int needed = (i == 2 ? 4 : 9);
|
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)
|
if (remaining <= 0)
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ package WayofTime.bloodmagic.compress;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class CompressionHandler {
|
public abstract class CompressionHandler {
|
||||||
/**
|
/**
|
||||||
* Called to look at the inventory and syphons the required stack. Returns
|
* 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 abstract ItemStack compressInventory(ItemStack[] inv, World world);
|
||||||
|
|
||||||
public int iterateThroughInventory(ItemStack required, int kept, ItemStack[] inv, int needed, boolean doDrain) {
|
public int iterateThroughInventory(ItemStack required, int kept, ItemStack[] inv, int needed, boolean doDrain) {
|
||||||
|
int oldNeeded = needed;
|
||||||
int i = -1;
|
int i = -1;
|
||||||
|
Set<Integer> consumeSet = new HashSet<>();
|
||||||
|
|
||||||
for (ItemStack invStack : inv) {
|
for (ItemStack invStack : inv) {
|
||||||
i++;
|
i++;
|
||||||
|
@ -31,26 +36,32 @@ public abstract class CompressionHandler {
|
||||||
used += stackSize - remainingFromStack;
|
used += stackSize - remainingFromStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
kept -= used; // 0
|
kept -= used;
|
||||||
|
|
||||||
if (kept <= 0 && needed > 0) {
|
if (kept <= 0 && needed > 0) {
|
||||||
int remainingFromStack = Math.max(stackSize - used - 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);
|
invStack.setCount(remainingFromStack + used);
|
||||||
|
for (Integer j : consumeSet) {
|
||||||
|
inv[j].setCount(0);
|
||||||
|
inv[j] = ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
consumeSet.clear();
|
||||||
if (invStack.isEmpty()) {
|
if (invStack.isEmpty()) {
|
||||||
inv[i] = ItemStack.EMPTY;
|
inv[i] = ItemStack.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
needed -= (stackSize - used - remainingFromStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needed <= 0) {
|
if (needed <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return needed;
|
return needed;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package WayofTime.bloodmagic.compress;
|
||||||
import WayofTime.bloodmagic.util.Utils;
|
import WayofTime.bloodmagic.util.Utils;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.Tuple;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.items.CapabilityItemHandler;
|
import net.minecraftforge.items.CapabilityItemHandler;
|
||||||
import net.minecraftforge.items.IItemHandler;
|
import net.minecraftforge.items.IItemHandler;
|
||||||
|
@ -18,8 +19,9 @@ import java.util.Map;
|
||||||
* form.
|
* form.
|
||||||
*/
|
*/
|
||||||
public class CompressionRegistry {
|
public class CompressionRegistry {
|
||||||
public static List<CompressionHandler> compressionRegistry = new ArrayList<>();
|
private static List<CompressionHandler> compressionRegistry = new ArrayList<>();
|
||||||
public static Map<ItemStack, Integer> thresholdMap = new HashMap<>();
|
public static Map<ItemStack, Integer> thresholdMap = new HashMap<>();
|
||||||
|
static Map<ItemStack, Tuple<ItemStack, Integer>> compressionMap = new HashMap<>();
|
||||||
|
|
||||||
public static void registerHandler(CompressionHandler handler) {
|
public static void registerHandler(CompressionHandler handler) {
|
||||||
compressionRegistry.add(handler);
|
compressionRegistry.add(handler);
|
||||||
|
@ -77,10 +79,24 @@ public class CompressionRegistry {
|
||||||
return Pair.of(ItemStack.EMPTY, false);
|
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) {
|
public static boolean areItemStacksEqual(ItemStack stack, ItemStack compressedStack) {
|
||||||
return stack.isItemEqual(compressedStack) && (stack.getTagCompound() == null ? !compressedStack.hasTagCompound() : stack.getTagCompound().equals(compressedStack.getTagCompound()));
|
return stack.isItemEqual(compressedStack) && (stack.getTagCompound() == null ? !compressedStack.hasTagCompound() : stack.getTagCompound().equals(compressedStack.getTagCompound()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,89 @@ import net.minecraft.inventory.Container;
|
||||||
import net.minecraft.inventory.InventoryCrafting;
|
import net.minecraft.inventory.InventoryCrafting;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.crafting.CraftingManager;
|
||||||
import net.minecraft.item.crafting.IRecipe;
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
public class StorageBlockCraftingManager {
|
public class StorageBlockCraftingManager {
|
||||||
private static final StorageBlockCraftingManager instance = new StorageBlockCraftingManager();
|
private static final StorageBlockCraftingManager instance = new StorageBlockCraftingManager();
|
||||||
private List<IRecipe> 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<IRecipe> recipes = new HashSet<>(); // TODO: Clear when recipes are reloaded in 1.14
|
||||||
|
private Set<ItemStack> 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) {
|
public void addRecipe(IRecipe recipe) {
|
||||||
this.recipes.add(recipe);
|
this.recipes.add(recipe);
|
||||||
|
@ -32,7 +106,7 @@ public class StorageBlockCraftingManager {
|
||||||
return this.findMatchingRecipe(craftingInventory, world, this.recipes);
|
return this.findMatchingRecipe(craftingInventory, world, this.recipes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack findMatchingRecipe(InventoryCrafting craftingInventory, World world, List<IRecipe> list) {
|
private ItemStack findMatchingRecipe(InventoryCrafting craftingInventory, World world, HashSet<IRecipe> list) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ItemStack itemstack = ItemStack.EMPTY;
|
ItemStack itemstack = ItemStack.EMPTY;
|
||||||
ItemStack itemstack1 = ItemStack.EMPTY;
|
ItemStack itemstack1 = ItemStack.EMPTY;
|
||||||
|
@ -67,11 +141,10 @@ public class StorageBlockCraftingManager {
|
||||||
|
|
||||||
return new ItemStack(itemstack.getItem(), 1, i1);
|
return new ItemStack(itemstack.getItem(), 1, i1);
|
||||||
} else {
|
} else {
|
||||||
for (j = 0; j < list.size(); ++j) {
|
for (IRecipe iRecipe : list) {
|
||||||
IRecipe irecipe = list.get(j);
|
|
||||||
|
|
||||||
if (irecipe.matches(craftingInventory, world)) {
|
if (iRecipe.matches(craftingInventory, world)) {
|
||||||
return irecipe.getCraftingResult(craftingInventory);
|
return iRecipe.getCraftingResult(craftingInventory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,62 +156,5 @@ public class StorageBlockCraftingManager {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isResultStackReversible(ItemStack stack, int gridSize, World world, List<IRecipe> 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<IRecipe> 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<IRecipe> list) {
|
|
||||||
return !get22Recipe(stack, world, list).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ItemStack get22Recipe(ItemStack stack, World world, List<IRecipe> list) {
|
|
||||||
return getRecipe(stack, world, 2, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean has33Recipe(ItemStack stack, World world, List<IRecipe> list) {
|
|
||||||
return !get33Recipe(stack, world, list).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ItemStack get33Recipe(ItemStack stack, World world, List<IRecipe> list) {
|
|
||||||
return getRecipe(stack, world, 3, list);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue