diff --git a/src/main/java/com/refinedmods/refinedstorage/api/network/grid/ICraftingGridBehavior.java b/src/main/java/com/refinedmods/refinedstorage/api/network/grid/ICraftingGridBehavior.java index 8709c83f7..169756f87 100644 --- a/src/main/java/com/refinedmods/refinedstorage/api/network/grid/ICraftingGridBehavior.java +++ b/src/main/java/com/refinedmods/refinedstorage/api/network/grid/ICraftingGridBehavior.java @@ -1,9 +1,12 @@ package com.refinedmods.refinedstorage.api.network.grid; +import com.refinedmods.refinedstorage.api.util.IStackList; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.ICraftingRecipe; +import javax.annotation.Nullable; + /** * Defines default behavior of crafting grids. */ @@ -11,11 +14,13 @@ public interface ICraftingGridBehavior { /** * Logic for regular crafting. * - * @param grid the grid - * @param recipe the recipe - * @param player the player + * @param grid the grid + * @param recipe the recipe + * @param player the player + * @param availableItems the items available for shift crafting + * @param usedItems the items used by shift crafting */ - void onCrafted(INetworkAwareGrid grid, ICraftingRecipe recipe, PlayerEntity player); + void onCrafted(INetworkAwareGrid grid, ICraftingRecipe recipe, PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems); /** * Logic for crafting with shift click (mass crafting). diff --git a/src/main/java/com/refinedmods/refinedstorage/api/network/grid/IGrid.java b/src/main/java/com/refinedmods/refinedstorage/api/network/grid/IGrid.java index b8f809a8a..f96f85388 100644 --- a/src/main/java/com/refinedmods/refinedstorage/api/network/grid/IGrid.java +++ b/src/main/java/com/refinedmods/refinedstorage/api/network/grid/IGrid.java @@ -5,6 +5,7 @@ import com.refinedmods.refinedstorage.api.network.grid.handler.IItemGridHandler; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCache; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCacheListener; import com.refinedmods.refinedstorage.api.util.IFilter; +import com.refinedmods.refinedstorage.api.util.IStackList; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.CraftResultInventory; @@ -201,9 +202,11 @@ public interface IGrid { /** * Called when an item is crafted in a crafting grid. * - * @param player the player that crafted the item + * @param player the player that crafted the item + * @param availableItems the items available for shift crafting + * @param usedItems the items used by shift crafting */ - void onCrafted(PlayerEntity player); + void onCrafted(PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems); /** * Called when the clear button is pressed in the pattern grid or crafting grid. diff --git a/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/grid/CraftingGridBehavior.java b/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/grid/CraftingGridBehavior.java index 1700d485c..8616dbc02 100644 --- a/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/grid/CraftingGridBehavior.java +++ b/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/grid/CraftingGridBehavior.java @@ -7,6 +7,7 @@ import com.refinedmods.refinedstorage.api.network.grid.INetworkAwareGrid; import com.refinedmods.refinedstorage.api.network.security.Permission; import com.refinedmods.refinedstorage.api.util.Action; import com.refinedmods.refinedstorage.api.util.IComparer; +import com.refinedmods.refinedstorage.api.util.IStackList; import com.refinedmods.refinedstorage.apiimpl.API; import com.refinedmods.refinedstorage.apiimpl.network.node.GridNetworkNode; import net.minecraft.entity.player.PlayerEntity; @@ -19,12 +20,13 @@ import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fml.hooks.BasicEventHooks; import net.minecraftforge.items.ItemHandlerHelper; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; public class CraftingGridBehavior implements ICraftingGridBehavior { @Override - public void onCrafted(INetworkAwareGrid grid, ICraftingRecipe recipe, PlayerEntity player) { + public void onCrafted(INetworkAwareGrid grid, ICraftingRecipe recipe, PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems) { NonNullList remainder = recipe.getRemainingItems(grid.getCraftingMatrix()); INetwork network = grid.getNetwork(); @@ -53,7 +55,17 @@ public class CraftingGridBehavior implements ICraftingGridBehavior { } } else if (!slot.isEmpty()) { // We don't have a remainder, but the slot is not empty. if (slot.getCount() == 1 && network != null) { // Attempt to refill the slot with the same item from the network, only if we have a network and only if it's the last item. - ItemStack refill = network.extractItem(slot, 1, Action.PERFORM); + ItemStack refill; + if (availableItems == null) { // for regular crafting + refill = network.extractItem(slot, 1, Action.PERFORM); + } else { // for shift crafting + if (availableItems.get(slot) != null) { + refill = availableItems.remove(slot, 1).getStack().copy(); + usedItems.add(refill); + } else { + refill = ItemStack.EMPTY; + } + } matrix.setInventorySlotContents(i, refill); @@ -71,28 +83,48 @@ public class CraftingGridBehavior implements ICraftingGridBehavior { @Override public void onCraftedShift(INetworkAwareGrid grid, PlayerEntity player) { + CraftingInventory matrix = grid.getCraftingMatrix(); + INetwork network = grid.getNetwork(); List craftedItemsList = new ArrayList<>(); - int amountCrafted = 0; ItemStack crafted = grid.getCraftingResult().getStackInSlot(0); int maxCrafted = crafted.getMaxStackSize(); - ForgeHooks.setCraftingPlayer(player); + int amountCrafted = 0; + boolean useNetwork = network != null; + IStackList availableItems = null; + if (useNetwork) { + // We need a modifiable list of the items in storage that are relevant for this craft. + // For performance reason we extract these into an extra list + availableItems = createFilteredItemList(network, matrix); + } + + //A second list to remember which items have been extracted + IStackList usedItems = API.instance().createItemStackList(); + + ForgeHooks.setCraftingPlayer(player); // Do while the item is still craftable (aka is the result slot still the same as the original item?) and we don't exceed the max stack size. do { - grid.onCrafted(player); + grid.onCrafted(player, availableItems, usedItems); craftedItemsList.add(crafted.copy()); amountCrafted += crafted.getCount(); - } while (API.instance().getComparer().isEqual(crafted, grid.getCraftingResult().getStackInSlot(0)) && amountCrafted < maxCrafted && amountCrafted + crafted.getCount() <= maxCrafted ); + } while (API.instance().getComparer().isEqual(crafted, grid.getCraftingResult().getStackInSlot(0)) && amountCrafted < maxCrafted && amountCrafted + crafted.getCount() <= maxCrafted); - INetwork network = grid.getNetwork(); + if (useNetwork) { + usedItems.getStacks().forEach(stack -> network.extractItem(stack.getStack(), stack.getStack().getCount(), Action.PERFORM)); + } for (ItemStack craftedItem : craftedItemsList) { if (!player.inventory.addItemStackToInventory(craftedItem.copy())) { - ItemStack remainder = network == null ? craftedItem : network.insertItem(craftedItem, craftedItem.getCount(), Action.PERFORM); + + ItemStack remainder = craftedItem; + + if (useNetwork) { + remainder = network.insertItem(craftedItem, craftedItem.getCount(), Action.PERFORM); + } if (!remainder.isEmpty()) { InventoryHelper.spawnItemStack(player.getEntityWorld(), player.getPosition().getX(), player.getPosition().getY(), player.getPosition().getZ(), remainder); @@ -108,6 +140,19 @@ public class CraftingGridBehavior implements ICraftingGridBehavior { ForgeHooks.setCraftingPlayer(null); } + private IStackList createFilteredItemList(INetwork network, CraftingInventory matrix) { + IStackList availableItems = API.instance().createItemStackList(); + for (int i = 0; i < matrix.getSizeInventory(); ++i) { + ItemStack stack = network.getItemStorageCache().getList().get(matrix.getStackInSlot(i)); + + //Don't add the same item twice into the list. Items may appear twice in a recipe but not in storage. + if (stack != null && availableItems.get(stack) == null) { + availableItems.add(stack); + } + } + return availableItems; + } + @Override public void onRecipeTransfer(INetworkAwareGrid grid, PlayerEntity player, ItemStack[][] recipe) { INetwork network = grid.getNetwork(); diff --git a/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/node/GridNetworkNode.java b/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/node/GridNetworkNode.java index b4112ec14..e92c39401 100644 --- a/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/node/GridNetworkNode.java +++ b/src/main/java/com/refinedmods/refinedstorage/apiimpl/network/node/GridNetworkNode.java @@ -10,6 +10,7 @@ import com.refinedmods.refinedstorage.api.storage.cache.IStorageCache; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCacheListener; import com.refinedmods.refinedstorage.api.util.Action; import com.refinedmods.refinedstorage.api.util.IFilter; +import com.refinedmods.refinedstorage.api.util.IStackList; import com.refinedmods.refinedstorage.apiimpl.API; import com.refinedmods.refinedstorage.apiimpl.autocrafting.AllowedTagList; import com.refinedmods.refinedstorage.apiimpl.storage.cache.listener.FluidGridStorageCacheListener; @@ -55,10 +56,7 @@ import net.minecraftforge.items.wrapper.InvWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, IType { public static final ResourceLocation ID = new ResourceLocation(RS.ID, "grid"); @@ -422,8 +420,8 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I } @Override - public void onCrafted(PlayerEntity player) { - API.instance().getCraftingGridBehavior().onCrafted(this, currentRecipe, player); + public void onCrafted(PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems) { + API.instance().getCraftingGridBehavior().onCrafted(this, currentRecipe, player, availableItems, usedItems); } @Override diff --git a/src/main/java/com/refinedmods/refinedstorage/container/slot/grid/ResultCraftingGridSlot.java b/src/main/java/com/refinedmods/refinedstorage/container/slot/grid/ResultCraftingGridSlot.java index e791d8f04..f1a1c8ae5 100644 --- a/src/main/java/com/refinedmods/refinedstorage/container/slot/grid/ResultCraftingGridSlot.java +++ b/src/main/java/com/refinedmods/refinedstorage/container/slot/grid/ResultCraftingGridSlot.java @@ -23,7 +23,7 @@ public class ResultCraftingGridSlot extends CraftingResultSlot { onCrafting(stack); if (!player.getEntityWorld().isRemote) { - grid.onCrafted(player); + grid.onCrafted(player, null, null); } return ItemStack.EMPTY; diff --git a/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessFluidGrid.java b/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessFluidGrid.java index 4534948aa..2349758fb 100644 --- a/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessFluidGrid.java +++ b/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessFluidGrid.java @@ -8,6 +8,7 @@ import com.refinedmods.refinedstorage.api.network.grid.handler.IItemGridHandler; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCache; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCacheListener; import com.refinedmods.refinedstorage.api.util.IFilter; +import com.refinedmods.refinedstorage.api.util.IStackList; import com.refinedmods.refinedstorage.apiimpl.storage.cache.listener.FluidGridStorageCacheListener; import com.refinedmods.refinedstorage.inventory.item.FilterItemHandler; import com.refinedmods.refinedstorage.item.WirelessFluidGridItem; @@ -271,7 +272,7 @@ public class WirelessFluidGrid implements INetworkAwareGrid { } @Override - public void onCrafted(PlayerEntity player) { + public void onCrafted(PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems) { // NO OP } diff --git a/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessGrid.java b/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessGrid.java index 48aaff156..aca75c700 100644 --- a/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessGrid.java +++ b/src/main/java/com/refinedmods/refinedstorage/tile/grid/WirelessGrid.java @@ -8,6 +8,7 @@ import com.refinedmods.refinedstorage.api.network.grid.handler.IItemGridHandler; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCache; import com.refinedmods.refinedstorage.api.storage.cache.IStorageCacheListener; import com.refinedmods.refinedstorage.api.util.IFilter; +import com.refinedmods.refinedstorage.api.util.IStackList; import com.refinedmods.refinedstorage.apiimpl.storage.cache.listener.ItemGridStorageCacheListener; import com.refinedmods.refinedstorage.inventory.item.FilterItemHandler; import com.refinedmods.refinedstorage.item.WirelessGridItem; @@ -277,7 +278,7 @@ public class WirelessGrid implements INetworkAwareGrid { } @Override - public void onCrafted(PlayerEntity player) { + public void onCrafted(PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems) { // NO OP } diff --git a/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGrid.java b/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGrid.java index 2e425fe6e..4a0511fa0 100644 --- a/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGrid.java +++ b/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGrid.java @@ -17,6 +17,7 @@ import com.refinedmods.refinedstorage.api.storage.disk.IStorageDiskContainerCont import com.refinedmods.refinedstorage.api.storage.disk.IStorageDiskProvider; import com.refinedmods.refinedstorage.api.storage.disk.StorageDiskSyncData; import com.refinedmods.refinedstorage.api.util.IFilter; +import com.refinedmods.refinedstorage.api.util.IStackList; import com.refinedmods.refinedstorage.apiimpl.API; import com.refinedmods.refinedstorage.apiimpl.network.grid.handler.PortableFluidGridHandler; import com.refinedmods.refinedstorage.apiimpl.network.grid.handler.PortableItemGridHandler; @@ -397,7 +398,7 @@ public class PortableGrid implements IGrid, IPortableGrid, IStorageDiskContainer } @Override - public void onCrafted(PlayerEntity player) { + public void onCrafted(PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems) { // NO OP } diff --git a/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGridTile.java b/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGridTile.java index 5d5414a8a..068cc9069 100644 --- a/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGridTile.java +++ b/src/main/java/com/refinedmods/refinedstorage/tile/grid/portable/PortableGridTile.java @@ -18,6 +18,7 @@ import com.refinedmods.refinedstorage.api.storage.disk.IStorageDiskContainerCont import com.refinedmods.refinedstorage.api.storage.disk.IStorageDiskProvider; import com.refinedmods.refinedstorage.api.storage.tracker.IStorageTracker; import com.refinedmods.refinedstorage.api.util.IFilter; +import com.refinedmods.refinedstorage.api.util.IStackList; import com.refinedmods.refinedstorage.apiimpl.API; import com.refinedmods.refinedstorage.apiimpl.network.grid.handler.PortableFluidGridHandler; import com.refinedmods.refinedstorage.apiimpl.network.grid.handler.PortableItemGridHandler; @@ -490,7 +491,7 @@ public class PortableGridTile extends BaseTile implements IGrid, IPortableGrid, } @Override - public void onCrafted(PlayerEntity player) { + public void onCrafted(PlayerEntity player, @Nullable IStackList availableItems, @Nullable IStackList usedItems) { // NO OP }