diff --git a/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java b/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java index 39e7f967..88ce6d05 100644 --- a/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java +++ b/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java @@ -1,6 +1,7 @@ package tconstruct.tools.inventory; import java.lang.ref.WeakReference; +import java.util.List; import javax.annotation.Nonnull; @@ -15,6 +16,7 @@ import net.minecraft.inventory.Slot; 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 tconstruct.items.tools.Arrow; @@ -48,6 +50,12 @@ public class CraftingStationContainer extends Container { public CraftingStationLogic logic; EntityPlayer player; + /** Last matched recipe, tried first to avoid rescanning the whole recipe list on every matrix change. */ + private IRecipe lastRecipe; + + /** While true, matrix changes don't recompute the result. Batches ingredient consumption into one lookup. */ + private boolean suppressCraftingUpdates; + public CraftingStationContainer(InventoryPlayer inventoryplayer, CraftingStationLogic logic, int x, int y, int z) { this.worldObj = logic.getWorldObj(); this.player = inventoryplayer.player; @@ -74,6 +82,7 @@ public class CraftingStationContainer extends Container { // 0 - crafting slot this.addSlotToContainer( new SlotCraftingStation( + this, inventoryplayer.player, this.craftMatrix, this.craftResult, @@ -280,11 +289,74 @@ public class CraftingStationContainer extends Container { } public void onCraftMatrixChanged(IInventory par1IInventory) { + if (suppressCraftingUpdates) return; + ItemStack tool = modifyItem(); if (tool != null) this.craftResult.setInventorySlotContents(0, tool); - else this.craftResult.setInventorySlotContents( - 0, - CraftingManager.getInstance().findMatchingRecipe(this.craftMatrix, this.worldObj)); + else this.craftResult.setInventorySlotContents(0, findMatchingRecipeCached()); + } + + /** Like {@link CraftingManager#findMatchingRecipe} but tries the last matched recipe first. */ + private ItemStack findMatchingRecipeCached() { + // Vanilla's two-item tool repair takes precedence over the recipe list + if (isVanillaToolRepair()) { + return CraftingManager.getInstance().findMatchingRecipe(this.craftMatrix, this.worldObj); + } + + IRecipe cached = this.lastRecipe; + if (cached != null && cached.matches(this.craftMatrix, this.worldObj)) { + return cached.getCraftingResult(this.craftMatrix); + } + this.lastRecipe = null; + + @SuppressWarnings("unchecked") + List recipes = CraftingManager.getInstance().getRecipeList(); + for (int i = 0; i < recipes.size(); i++) { + IRecipe recipe = recipes.get(i); + if (recipe.matches(this.craftMatrix, this.worldObj)) { + this.lastRecipe = recipe; + return recipe.getCraftingResult(this.craftMatrix); + } + } + return null; + } + + /** + * Mirrors the repair check in {@link CraftingManager#findMatchingRecipe}: two size-1 stacks of one repairable item. + */ + private boolean isVanillaToolRepair() { + ItemStack first = null; + ItemStack second = null; + int found = 0; + + for (int i = 0; i < this.craftMatrix.getSizeInventory(); i++) { + ItemStack stack = this.craftMatrix.getStackInSlot(i); + if (stack == null) continue; + + found++; + if (found == 1) first = stack; + else if (found == 2) second = stack; + else return false; + } + + return found == 2 && first.getItem() == second.getItem() + && first.stackSize == 1 + && second.stackSize == 1 + && first.getItem().isRepairable(); + } + + /** + * Suppresses result updates until {@link #endBatchCraftingUpdate}; each consumed ingredient fires a lookup + * otherwise. + */ + void beginBatchCraftingUpdate() { + suppressCraftingUpdates = true; + } + + /** Re-enables result updates and recomputes once. */ + void endBatchCraftingUpdate() { + suppressCraftingUpdates = false; + this.onCraftMatrixChanged(this.craftMatrix); } @Override @@ -438,16 +510,19 @@ public class CraftingStationContainer extends Container { public void dumpCraftingGrid() { if (logic.slotCount == 0) return; - // 46 is the first slot index of the attached inventory - for (int i = 0; i < 9; i++) { - ItemStack stack = craftMatrix.getStackInSlot(i); - if (stack != null && stack.stackSize > 0) { - if (mergeItemStack(stack, 46, 46 + logic.slotCount, false)) { - craftMatrix.setInventorySlotContents(i, stack.stackSize > 0 ? stack : null); + beginBatchCraftingUpdate(); + try { + // 46 is the first slot index of the attached inventory + for (int i = 0; i < 9; i++) { + ItemStack stack = craftMatrix.getStackInSlot(i); + if (stack != null && stack.stackSize > 0) { + if (mergeItemStack(stack, 46, 46 + logic.slotCount, false)) { + craftMatrix.setInventorySlotContents(i, stack.stackSize > 0 ? stack : null); + } } } + } finally { + endBatchCraftingUpdate(); } - - this.onCraftMatrixChanged(this.craftMatrix); } } diff --git a/src/main/java/tconstruct/tools/inventory/SlotCraftingStation.java b/src/main/java/tconstruct/tools/inventory/SlotCraftingStation.java index ba787acb..37bf31e7 100644 --- a/src/main/java/tconstruct/tools/inventory/SlotCraftingStation.java +++ b/src/main/java/tconstruct/tools/inventory/SlotCraftingStation.java @@ -11,18 +11,30 @@ import tconstruct.library.tools.AbilityHelper; public class SlotCraftingStation extends SlotCrafting { + private final CraftingStationContainer container; private final IInventory matrix; private final EntityPlayer player; - public SlotCraftingStation(EntityPlayer par1EntityPlayer, IInventory par2IInventory, IInventory par3iInventory, - int par4, int par5, int par6) { + public SlotCraftingStation(CraftingStationContainer container, EntityPlayer par1EntityPlayer, + IInventory par2IInventory, IInventory par3iInventory, int par4, int par5, int par6) { super(par1EntityPlayer, par2IInventory, par3iInventory, par4, par5, par6); + this.container = container; this.matrix = par2IInventory; this.player = par1EntityPlayer; } @Override public void onPickupFromSlot(EntityPlayer player, ItemStack stack) { + // Batch ingredient consumption into a single recipe lookup + container.beginBatchCraftingUpdate(); + try { + consumeIngredients(player, stack); + } finally { + container.endBatchCraftingUpdate(); + } + } + + private void consumeIngredients(EntityPlayer player, ItemStack stack) { ItemStack tool = this.matrix.getStackInSlot(4); if (stack.getItem() instanceof IModifyable modifyable && tool != null && tool.getItem() instanceof IModifyable) { diff --git a/src/main/java/tconstruct/tools/logic/CraftingStationLogic.java b/src/main/java/tconstruct/tools/logic/CraftingStationLogic.java index 15e59dbc..0731c477 100644 --- a/src/main/java/tconstruct/tools/logic/CraftingStationLogic.java +++ b/src/main/java/tconstruct/tools/logic/CraftingStationLogic.java @@ -32,6 +32,12 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent public int invRows, invColumns, slotCount; + private static final int[] NO_SLOTS = new int[0]; + + /** Cached result of {@link #getInventories()}; rebuilt when the adjacent inventories are rescanned. */ + @SuppressWarnings("rawtypes") + private WeakReference[] inventories = new WeakReference[4]; + public CraftingStationLogic() { super(10); // 9 for crafting, 1 for output } @@ -115,6 +121,8 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent } } + this.inventories = new WeakReference[] { this.chest, this.doubleChest, this.patternChest, this.furnace }; + return new CraftingStationContainer(inventoryplayer, this, x, y, z); } @@ -168,12 +176,12 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent @SuppressWarnings("rawtypes") public WeakReference[] getInventories() { - return new WeakReference[] { this.chest, this.doubleChest, this.patternChest, this.furnace }; + return this.inventories; } @Override public int[] getAccessibleSlotsFromSide(int var1) { - return new int[] {}; + return NO_SLOTS; } @Override diff --git a/src/main/java/tconstruct/tools/logic/PartBuilderLogic.java b/src/main/java/tconstruct/tools/logic/PartBuilderLogic.java index 061f73ff..e4072048 100644 --- a/src/main/java/tconstruct/tools/logic/PartBuilderLogic.java +++ b/src/main/java/tconstruct/tools/logic/PartBuilderLogic.java @@ -16,6 +16,8 @@ import tconstruct.tools.inventory.PartCrafterContainer; public class PartBuilderLogic extends InventoryLogic implements ISidedInventory { + private static final int[] NO_SLOTS = new int[0]; + boolean craftedTop; boolean craftedBottom; @@ -138,7 +140,7 @@ public class PartBuilderLogic extends InventoryLogic implements ISidedInventory @Override public int[] getAccessibleSlotsFromSide(int side) { - return new int[0]; + return NO_SLOTS; } @Override diff --git a/src/main/java/tconstruct/tools/logic/StencilTableLogic.java b/src/main/java/tconstruct/tools/logic/StencilTableLogic.java index 5724389a..2aa79263 100644 --- a/src/main/java/tconstruct/tools/logic/StencilTableLogic.java +++ b/src/main/java/tconstruct/tools/logic/StencilTableLogic.java @@ -15,6 +15,8 @@ import tconstruct.tools.inventory.PatternShaperContainer; public class StencilTableLogic extends InventoryLogic implements ISidedInventory { + private static final int[] NO_SLOTS = new int[0]; + private ItemStack selectedStack; public StencilTableLogic() { @@ -119,7 +121,7 @@ public class StencilTableLogic extends InventoryLogic implements ISidedInventory @Override public int[] getAccessibleSlotsFromSide(int side) { - return new int[0]; + return NO_SLOTS; } @Override diff --git a/src/main/java/tconstruct/tools/logic/ToolStationLogic.java b/src/main/java/tconstruct/tools/logic/ToolStationLogic.java index 9a52bf1d..47ea0a64 100644 --- a/src/main/java/tconstruct/tools/logic/ToolStationLogic.java +++ b/src/main/java/tconstruct/tools/logic/ToolStationLogic.java @@ -20,6 +20,8 @@ import tconstruct.tools.inventory.ToolStationContainer; public class ToolStationLogic extends InventoryLogic implements ISidedInventory { + private static final int[] NO_SLOTS = new int[0]; + public ItemStack previousTool; public String toolName; @@ -158,7 +160,7 @@ public class ToolStationLogic extends InventoryLogic implements ISidedInventory @Override public int[] getAccessibleSlotsFromSide(int side) { - return new int[0]; + return NO_SLOTS; } @Override