diff --git a/src/main/java/appeng/core/sync/packets/PacketJEIRecipe.java b/src/main/java/appeng/core/sync/packets/PacketJEIRecipe.java index c93ba55e0..73e7cfda8 100644 --- a/src/main/java/appeng/core/sync/packets/PacketJEIRecipe.java +++ b/src/main/java/appeng/core/sync/packets/PacketJEIRecipe.java @@ -68,10 +68,10 @@ import static appeng.helpers.ItemStackHelper.stackFromNBT; public class PacketJEIRecipe extends AppEngPacket { + static ItemStack[] emptyArray = {ItemStack.EMPTY}; private List recipe; private List output; private boolean shouldCondense; - static ItemStack[] emptyArray = {ItemStack.EMPTY}; // automatic. @@ -124,27 +124,34 @@ public class PacketJEIRecipe extends AppEngPacket { @Override public void serverPacketData(final INetworkInfo manager, final AppEngPacket packet, final EntityPlayer player) { + // oops :) + if (this.recipe == null) return; + final EntityPlayerMP pmp = (EntityPlayerMP) player; final Container con = pmp.openContainer; - - if (!(con instanceof IContainerCraftingPacket cct)) { - return; - } + if (!(con instanceof IContainerCraftingPacket cct)) return; final IGridNode node = cct.getNetworkNode(); - - if (node == null) { - return; - } + if (node == null) return; final IGrid grid = node.getGrid(); - if (grid == null) { - return; - } + if (grid == null) return; final IStorageGrid inv = grid.getCache(IStorageGrid.class); + if (inv == null) return; final IEnergyGrid energy = grid.getCache(IEnergyGrid.class); - final ISecurityGrid security = grid.getCache(ISecurityGrid.class); + if (energy == null) return; + + final boolean hasExtractPermissions; + final boolean hasInjectPermissions; + if (grid.getCache(ISecurityGrid.class) instanceof ISecurityGrid security) { + hasInjectPermissions = security.hasPermission(player, SecurityPermissions.INJECT); + hasExtractPermissions = security.hasPermission(player, SecurityPermissions.EXTRACT); + } else { + hasInjectPermissions = false; + hasExtractPermissions = false; + } + final ICraftingGrid crafting = grid.getCache(ICraftingGrid.class); final IItemHandler craftMatrix = cct.getInventoryByName("crafting"); final IItemHandler playerInventory = cct.getInventoryByName("player"); @@ -156,172 +163,173 @@ public class PacketJEIRecipe extends AppEngPacket { condensedBuffer = null; } - if (inv != null && this.recipe != null && security != null) { - final IMEMonitor storage = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)); - final IPartitionList filter = ItemViewCell.createFilter(cct.getViewCells()); + final IMEMonitor storage = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)); + final IPartitionList filter = ItemViewCell.createFilter(cct.getViewCells()); - for (int x = 0; x < recipe.size(); x++) { - ItemStack currentItem; + // First iteration, find what can be used and send everything else into the network. + for (int matrixSlotIndex = 0; matrixSlotIndex < craftMatrix.getSlots(); matrixSlotIndex++) { + var currentItem = craftMatrix.getStackInSlot(matrixSlotIndex); + if (!currentItem.isEmpty()) { + if (this.canUseInSlot(matrixSlotIndex, currentItem)) continue; - if (x < craftMatrix.getSlots()) { - currentItem = craftMatrix.getStackInSlot(x); - } else if (this.shouldCondense) { - // If the inputs should be condensed, we can read past the current grid. - currentItem = ItemStack.EMPTY; - } else { - // Otherwise break. - break; + if (!cct.useRealItems()) { + currentItem.setCount(0); + } else if (hasInjectPermissions) { + final var out = Platform.poweredInsert(energy, storage, + AEItemStack.fromItemStack(currentItem), cct.getActionSource()); + + currentItem.setCount(out != null ? (int) out.getStackSize() : 0); } + } + } - // prepare slots - if (!currentItem.isEmpty()) { - // already the correct item? - ItemStack newItem = this.canUseInSlot(x, currentItem); + // Second iteration, query AE2 & player inventory for items. + for (int recipeSlotIndex = 0; recipeSlotIndex < recipe.size(); recipeSlotIndex++) { + ItemStack currentItem; - if (!cct.useRealItems() && this.recipe.get(x) != null) { - if (this.recipe.get(x).length > 0) { - currentItem.setCount(recipe.get(x)[0].getCount()); - } - } + if (recipeSlotIndex < craftMatrix.getSlots()) { + currentItem = craftMatrix.getStackInSlot(recipeSlotIndex); + } else if (this.shouldCondense) { + // If the inputs should be condensed, we can read past the current grid. + currentItem = ItemStack.EMPTY; + } else { + // Otherwise break. + break; + } - // put away old item - if (newItem != currentItem && security.hasPermission(player, SecurityPermissions.INJECT)) { - final IAEItemStack in = AEItemStack.fromItemStack(currentItem); - final IAEItemStack out = cct.useRealItems() ? Platform.poweredInsert(energy, storage, in, cct.getActionSource()) : null; - if (out != null) { - currentItem = out.createItemStack(); - } else { - currentItem = ItemStack.EMPTY; - } - } - } + if (currentItem.isEmpty() && recipe.get(recipeSlotIndex) != null) { + // for each variant + for (int y = 0; y < this.recipe.get(recipeSlotIndex).length && currentItem.isEmpty(); y++) { + var recipeStackVariant = this.recipe.get(recipeSlotIndex)[y]; + final IAEItemStack request = AEItemStack.fromItemStack(recipeStackVariant); + if (request != null) { + // try ae + if ((filter == null || filter.isListed(request)) && hasExtractPermissions) { + request.setStackSize(1); + IAEItemStack out; - if (currentItem.isEmpty() && recipe.size() > x && recipe.get(x) != null) { - // for each variant - for (int y = 0; y < this.recipe.get(x).length && currentItem.isEmpty(); y++) { - final IAEItemStack request = AEItemStack.fromItemStack(this.recipe.get(x)[y]); - if (request != null) { - // try ae - if ((filter == null || filter.isListed(request)) && security.hasPermission(player, SecurityPermissions.EXTRACT)) { - request.setStackSize(1); - IAEItemStack out; - - if (cct.useRealItems()) { - out = Platform.poweredExtraction(energy, storage, request, cct.getActionSource()); - if (out == null) { - if (request.getItem().isDamageable() || Platform.isGTDamageableItem(request.getItem())) { - Collection outList = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)).getStorageList().findFuzzy(request, FuzzyMode.IGNORE_ALL); - for (IAEItemStack is : outList) { - if (is.getStackSize() == 0) { + if (cct.useRealItems()) { + out = Platform.poweredExtraction(energy, storage, request, cct.getActionSource()); + if (out == null) { + if (request.getItem().isDamageable() || Platform.isGTDamageableItem(request.getItem())) { + Collection outList = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)).getStorageList().findFuzzy(request, FuzzyMode.IGNORE_ALL); + for (IAEItemStack is : outList) { + if (is.getStackSize() == 0) { + continue; + } + if (Platform.isGTDamageableItem(request.getItem())) { + if (!(is.getDefinition().getMetadata() == request.getDefinition().getMetadata())) { continue; } - if (Platform.isGTDamageableItem(request.getItem())) { - if (!(is.getDefinition().getMetadata() == request.getDefinition().getMetadata())) { - continue; - } - } - out = Platform.poweredExtraction(energy, storage, is.copy().setStackSize(1), cct.getActionSource()); - if (out != null) { - break; - } + } + out = Platform.poweredExtraction(energy, storage, is.copy().setStackSize(1), cct.getActionSource()); + if (out != null) { + break; } } } - } else { - // Query the crafting grid if there is a pattern providing the item - if (!crafting.getCraftingFor(request, null, 0, null).isEmpty()) { - out = request; - } else { - // Fall back using an existing item - out = storage.extractItems(request, Actionable.SIMULATE, cct.getActionSource()); - } } - - if (out != null) { - if (!cct.useRealItems()) { - out.setStackSize(recipe.get(x)[y].getCount()); - } - currentItem = out.createItemStack(); + } else { + // Query the crafting grid if there is a pattern providing the item + if (!crafting.getCraftingFor(request, null, 0, null).isEmpty()) { + out = request; + } else { + // Fall back using an existing item + out = storage.extractItems(request, Actionable.SIMULATE, cct.getActionSource()); } } - // try inventory - if (currentItem.isEmpty()) { - AdaptorItemHandler ad = new AdaptorItemHandler(playerInventory); - - if (cct.useRealItems()) { - currentItem = ad.removeSimilarItems(1, this.recipe.get(x)[y], FuzzyMode.IGNORE_ALL, null); - } else { - currentItem = ad.simulateSimilarRemove(recipe.get(x)[y].getCount(), this.recipe.get(x)[y], FuzzyMode.IGNORE_ALL, null); + if (out != null) { + if (!cct.useRealItems()) { + out.setStackSize(recipeStackVariant.getCount()); } + currentItem = out.createItemStack(); } } - } - if (!cct.useRealItems()) { - if (currentItem.isEmpty() && recipe.size() > x && this.recipe.get(x) != null) { - currentItem = this.recipe.get(x)[0].copy(); + + // try inventory + if (currentItem.isEmpty()) { + AdaptorItemHandler ad = new AdaptorItemHandler(playerInventory); + + if (cct.useRealItems()) { + currentItem = ad.removeSimilarItems(1, recipeStackVariant, FuzzyMode.IGNORE_ALL, null); + } else { + currentItem = ad.simulateSimilarRemove(recipeStackVariant.getCount(), recipeStackVariant, FuzzyMode.IGNORE_ALL, null); + } } } } - if (condensedBuffer != null) { - var aeItemStack = AEItemStack.fromItemStack(currentItem); - if (aeItemStack != null) { - condensedBuffer.compute(aeItemStack, (k, v) -> (v == null ? 0 : v) + k.getStackSize()); + if (!cct.useRealItems()) { + if (currentItem.isEmpty() && recipe.size() > recipeSlotIndex && this.recipe.get(recipeSlotIndex) != null) { + currentItem = this.recipe.get(recipeSlotIndex)[0].copy(); } - } else { - ItemHandlerUtil.setStackInSlot(craftMatrix, x, currentItem); } } if (condensedBuffer != null) { - var slotIndex = 0; - for (var entry : condensedBuffer.entrySet()) { - if (slotIndex >= craftMatrix.getSlots()) { - break; - } - - ItemHandlerUtil.setStackInSlot(craftMatrix, slotIndex, - entry.getKey().copy().setStackSize(entry.getValue()).createItemStack()); - slotIndex++; + var aeItemStack = AEItemStack.fromItemStack(currentItem); + if (aeItemStack != null) { + condensedBuffer.compute(aeItemStack, (k, v) -> (v == null ? 0 : v) + k.getStackSize()); } + } else { + ItemHandlerUtil.setStackInSlot(craftMatrix, recipeSlotIndex, currentItem); + } + } - for (var i = slotIndex; i < craftMatrix.getSlots(); i++) { - ItemHandlerUtil.setStackInSlot(craftMatrix, i, ItemStack.EMPTY); - } + if (condensedBuffer != null) { + var slotIndex = 0; + + // Fill the craft matrix with items from the condensed buffer. + for (var entry : condensedBuffer.entrySet()) { + if (slotIndex >= craftMatrix.getSlots()) break; + + ItemHandlerUtil.setStackInSlot(craftMatrix, slotIndex, + entry.getKey().copy().setStackSize(entry.getValue()).createItemStack()); + slotIndex++; } - con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix)); + // Clear the remaining slots. + for (var i = slotIndex; i < craftMatrix.getSlots(); i++) { + ItemHandlerUtil.setStackInSlot(craftMatrix, i, ItemStack.EMPTY); + } + } - if (this.output != null && ((con instanceof ContainerPatternEncoder && !((ContainerPatternEncoder) con).isCraftingMode()))) { - IItemHandler outputSlots = cct.getInventoryByName("output"); - for (int i = 0; i < outputSlots.getSlots(); ++i) { - ItemHandlerUtil.setStackInSlot(outputSlots, i, ItemStack.EMPTY); - } - for (int i = 0; i < this.output.size() && i < outputSlots.getSlots(); ++i) { - if (this.output.get(i) == null || this.output.get(i) == ItemStack.EMPTY) { + con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix)); + + if (this.output != null && con instanceof ContainerPatternEncoder encoder && !encoder.isCraftingMode()) { + var outputSlots = cct.getInventoryByName("output"); + for (int i = 0; i < outputSlots.getSlots(); ++i) { + if (i < this.output.size()) { + var outputStack = this.output.get(i); + if (outputStack != null && outputStack != ItemStack.EMPTY) { + ItemHandlerUtil.setStackInSlot(outputSlots, i, outputStack); continue; } - ItemHandlerUtil.setStackInSlot(outputSlots, i, this.output.get(i)); } + + ItemHandlerUtil.setStackInSlot(outputSlots, i, ItemStack.EMPTY); } } } /** - * @param slot + * @param slot slot index * @param is itemstack * @return is if it can be used, else EMPTY */ - private ItemStack canUseInSlot(int slot, ItemStack is) { - if (this.recipe.get(slot) != null) { - for (ItemStack option : this.recipe.get(slot)) { + private boolean canUseInSlot(int slot, ItemStack is) { + if (slot >= this.recipe.size()) return false; + + var variants = this.recipe.get(slot); + if (variants != null) { + for (ItemStack option : variants) { if (ItemStack.areItemStacksEqual(is, option)) { - return is; + return true; } } } - return ItemStack.EMPTY; + return false; } }