Search in sources :

Example 1 with CraftingWindowInventorySlot

use of mekanism.common.inventory.slot.CraftingWindowInventorySlot in project Mekanism by mekanism.

the class QIOServerCraftingTransferHandler method transferItems.

private void transferItems(Byte2ObjectMap<List<SingularHashedItemSource>> sources) {
    SelectedWindowData windowData = craftingWindow.getWindowData();
    // Extract items that will be put into the crafting window
    Byte2ObjectMap<ItemStack> targetContents = new Byte2ObjectArrayMap<>(sources.size());
    for (Byte2ObjectMap.Entry<List<SingularHashedItemSource>> entry : sources.byte2ObjectEntrySet()) {
        for (SingularHashedItemSource source : entry.getValue()) {
            byte slot = source.getSlot();
            ItemStack stack;
            if (slot == -1) {
                UUID qioSource = source.getQioSource();
                // Neither the source nor the frequency can be null here as we validated that during simulation
                HashedItem storedItem = frequency.getTypeByUUID(qioSource);
                if (storedItem == null) {
                    bail(targetContents, "Received transfer request from: {}, for: {}, could not find stored item with UUID: {}. " + "This likely means that more of it was requested than is stored.", player, recipeID, qioSource);
                    return;
                }
                stack = frequency.removeByType(storedItem, source.getUsed());
                if (stack.isEmpty()) {
                    bail(targetContents, "Received transfer request from: {}, for: {}, but could not extract item: {} with nbt: {} from the QIO.", player, recipeID, storedItem.getStack().getItem(), storedItem.getStack().getTag());
                    return;
                } else if (stack.getCount() < source.getUsed()) {
                    Mekanism.logger.warn("Received transfer request from: {}, for: {}, but was unable to extract the expected amount: {} of item: {} " + "with nbt: {} from the QIO. This should not be possible as it should have been caught during simulation. Attempting " + "to continue anyways with the actual extracted amount of {}.", player, recipeID, source.getUsed(), storedItem.getStack().getItem(), storedItem.getStack().getTag(), stack.getCount());
                }
            } else {
                int actualSlot;
                String slotType;
                if (slot < 9) {
                    // Crafting Window
                    actualSlot = slot;
                    slotType = "crafting window";
                    stack = craftingWindow.getInputSlot(slot).extractItem(source.getUsed(), Action.EXECUTE, AutomationType.MANUAL);
                } else if (slot < 9 + PlayerInventory.getSelectionSize()) {
                    // Hotbar
                    actualSlot = slot - 9;
                    slotType = "hotbar";
                    stack = hotBarSlots.get(actualSlot).remove(source.getUsed());
                } else {
                    // Main inventory
                    actualSlot = slot - 9 - PlayerInventory.getSelectionSize();
                    slotType = "main inventory";
                    stack = mainInventorySlots.get(actualSlot).remove(source.getUsed());
                }
                if (stack.isEmpty()) {
                    bail(targetContents, "Received transfer request from: {}, for: {}, could not extract item from {} slot: {}. " + "This likely means that more of it was requested than is stored.", player, recipeID, slotType, actualSlot);
                    return;
                } else if (stack.getCount() < source.getUsed()) {
                    Mekanism.logger.warn("Received transfer request from: {}, for: {}, but was unable to extract the expected amount: {} from {} slot: {}. " + "This should not be possible as it should have been caught during simulation. Attempting to continue anyways with the " + "actual extracted amount of {}.", player, recipeID, source.getUsed(), slotType, actualSlot, stack.getCount());
                }
            }
            byte targetSlot = entry.getByteKey();
            if (targetContents.containsKey(targetSlot)) {
                ItemStack existing = targetContents.get(targetSlot);
                if (ItemHandlerHelper.canItemStacksStack(existing, stack)) {
                    int needed = existing.getMaxStackSize() - existing.getCount();
                    if (stack.getCount() <= needed) {
                        existing.grow(stack.getCount());
                    } else {
                        existing.grow(needed);
                        // Note: We can safely modify the stack as all our ways of extracting return a new stack
                        stack.shrink(needed);
                        Mekanism.logger.warn("Received transfer request from: {}, for: {}, but contents could not fully fit into target slot: {}. " + "This should not be able to happen, returning excess stack, and attempting to continue.", player, recipeID, targetSlot);
                        returnItem(stack, windowData);
                    }
                } else {
                    Mekanism.logger.warn("Received transfer request from: {}, for: {}, but contents could not stack into target slot: {}. " + "This should not be able to happen, returning extra stack, and attempting to continue.", player, recipeID, targetSlot);
                    returnItem(stack, windowData);
                }
            } else {
                // Note: We can safely modify the stack as all our ways of extracting return a new stack
                targetContents.put(targetSlot, stack);
            }
        }
    }
    // Extract what items are still in the window
    Byte2ObjectMap<ItemStack> remainingCraftingGridContents = new Byte2ObjectArrayMap<>(9);
    for (byte slot = 0; slot < 9; slot++) {
        CraftingWindowInventorySlot inputSlot = craftingWindow.getInputSlot(slot);
        if (!inputSlot.isEmpty()) {
            ItemStack stack = inputSlot.extractItem(inputSlot.getCount(), Action.EXECUTE, AutomationType.MANUAL);
            if (!stack.isEmpty()) {
                remainingCraftingGridContents.put(slot, stack);
            } else {
                bail(targetContents, remainingCraftingGridContents, "Received transfer request from: {}, for: {}, but failed to remove items from crafting " + "input slot: {}. This should not be possible as it should have been caught by an earlier check.", player, recipeID, slot);
                return;
            }
        }
    }
    // Insert items for the crafting window into it
    for (ObjectIterator<Byte2ObjectMap.Entry<ItemStack>> iter = targetContents.byte2ObjectEntrySet().iterator(); iter.hasNext(); ) {
        Byte2ObjectMap.Entry<ItemStack> entry = iter.next();
        byte targetSlot = entry.getByteKey();
        CraftingWindowInventorySlot inputSlot = craftingWindow.getInputSlot(targetSlot);
        ItemStack remainder = inputSlot.insertItem(entry.getValue(), Action.EXECUTE, AutomationType.MANUAL);
        if (remainder.isEmpty()) {
            // If it was fully inserted, remove the entry from what we have left to deal with
            iter.remove();
        } else {
            // otherwise, update the stack for what is remaining and also print a warning as this should have been caught earlier,
            // as we then will handle any remaining contents at the end (though we shouldn't have any)
            // Note: We need to use put, as entry#setValue is not supported in fastutil maps
            targetContents.put(targetSlot, remainder);
            Mekanism.logger.warn("Received transfer request from: {}, for: {}, but was unable to fully insert it into the {} crafting input slot. " + "This should not be possible as it should have been caught during simulation. Attempting to continue anyways.", player, recipeID, targetSlot);
        }
    }
    // Put the items that were in the crafting window in the player's inventory
    for (Byte2ObjectMap.Entry<ItemStack> entry : remainingCraftingGridContents.byte2ObjectEntrySet()) {
        // Insert into player's inventory
        ItemStack stack = returnItemToInventory(entry.getValue(), windowData);
        if (!stack.isEmpty()) {
            // If we couldn't insert it all, try recombining with the slots they were in the crafting window
            // (only if the type matches though)
            CraftingWindowInventorySlot inputSlot = craftingWindow.getInputSlot(entry.getByteKey());
            if (ItemHandlerHelper.canItemStacksStack(inputSlot.getStack(), stack)) {
                stack = inputSlot.insertItem(stack, Action.EXECUTE, AutomationType.MANUAL);
            }
            if (!stack.isEmpty()) {
                // If we couldn't insert it, then try to put the remaining items in the frequency
                if (frequency != null) {
                    stack = frequency.addItem(stack);
                }
                if (!stack.isEmpty()) {
                    // If we couldn't insert it all, either because there was no frequency or it didn't have room for it all
                    // drop it as the player, and print a warning as ideally we should never have been able to get to this
                    // point as our simulation should have marked it as invalid
                    // Note: In theory we should never get to this point due to having accurate simulations ahead of time
                    player.drop(stack, false);
                    Mekanism.logger.warn("Received transfer request from: {}, for: {}, and was unable to fit all contents that were in the crafting window " + "into the player's inventory/QIO system; dropping items by player.", player, recipeID);
                }
            }
        }
    }
    if (!targetContents.isEmpty()) {
        // If we have any contents we wanted to move remaining try to return them, in theory
        // this should never happen but in case it does make sure we don't void any items
        bail(targetContents, "Received transfer request from: {}, for: {}, but ended up with {} items that could not be transferred into " + "the proper crafting grid slot. This should not be possible as it should have been caught during simulation.", player, recipeID, targetContents.size());
    }
}
Also used : HashedItem(mekanism.common.lib.inventory.HashedItem) SingularHashedItemSource(mekanism.common.content.qio.QIOCraftingTransferHelper.SingularHashedItemSource) Byte2ObjectMap(it.unimi.dsi.fastutil.bytes.Byte2ObjectMap) ArrayList(java.util.ArrayList) NonNullList(net.minecraft.util.NonNullList) List(java.util.List) Byte2ObjectArrayMap(it.unimi.dsi.fastutil.bytes.Byte2ObjectArrayMap) ItemStack(net.minecraft.item.ItemStack) UUID(java.util.UUID) SelectedWindowData(mekanism.common.inventory.container.SelectedWindowData) CraftingWindowInventorySlot(mekanism.common.inventory.slot.CraftingWindowInventorySlot)

Example 2 with CraftingWindowInventorySlot

use of mekanism.common.inventory.slot.CraftingWindowInventorySlot in project Mekanism by mekanism.

the class QIOCraftingWindow method performCraft.

/**
 * @apiNote For use with shift clicking
 */
public void performCraft(@Nonnull PlayerEntity player, List<HotBarSlot> hotBarSlots, List<MainInventorySlot> mainInventorySlots) {
    if (lastRecipe == null || outputSlot.isEmpty()) {
        // Note: lastRecipe will always null on the client, so we can assume we are server side below
        return;
    }
    World world = holder.getHolderWorld();
    if (!validateAndUnlockRecipe(world, player)) {
        // If the recipe isn't valid, fail
        return;
    }
    QIOFrequency frequency = holder.getFrequency();
    // Mark that we are crafting so changes to the slots below don't force a bunch of recalculations to take place
    craftingStarted(player);
    // Figure out the base of the result stack after crafting (onCreated can adjust it slightly)
    ItemStack result = outputSlot.getStack().copy();
    Item resultItem = result.getItem();
    resultItem.onCraftedBy(result, world, player);
    Stat<Item> itemCraftedStat = Stats.ITEM_CRAFTED.get(resultItem);
    int maxToCraft = calculateMaxCraftAmount(result, frequency);
    int amountPerCraft = result.getCount();
    // Note: We initialized crafted here instead of in the for loop so that we can query how much was actually crafted
    int crafted = 0;
    remainderHelper.reset();
    replacementHelper.reset();
    boolean recheckOutput = false;
    LastInsertTarget lastInsertTarget = new LastInsertTarget();
    NonNullList<ItemStack> remaining = lastRecipe.getRemainingItems(craftingInventory);
    for (; crafted < maxToCraft; crafted += amountPerCraft) {
        if (recheckOutput && changedWhileCrafting) {
            // If our inputs changed while crafting, and we are supposed to recheck the output,
            // update the contents of the output slot and the recipe that we are performing as
            // if there is an NBT sensitive recipe, the output may have changed
            recheckOutput = false;
            changedWhileCrafting = false;
            ICraftingRecipe oldRecipe = lastRecipe;
            updateOutputSlot(world);
            if (oldRecipe != lastRecipe) {
                // is enabled, and they only have access to one of the crafting recipes
                break;
            }
            ItemStack updatedOutput = outputSlot.getStack();
            if (updatedOutput.isEmpty() || updatedOutput.getItem() != resultItem) {
                // If we can't craft anymore or the resulting item changed entirely, stop crafting
                break;
            }
            // If they may still be compatible, copy the stack, and apply the onCreated to it so that
            // we can adjust the NBT if it needs adjusting
            ItemStack potentialUpdatedOutput = updatedOutput.copy();
            resultItem.onCraftedBy(potentialUpdatedOutput, world, player);
            if (!ItemStack.matches(result, potentialUpdatedOutput)) {
                // This also has a side effect of not requiring us to then recalculate the value of maxToCraft
                break;
            }
            // We also need to make sure to update the remaining items as even though the recipe still outputs the same result
            // the remaining items may have changed such as durability of a container item, and we want to make sure to use
            // the proper remaining stacks
            remaining = lastRecipe.getRemainingItems(craftingInventory);
        }
        // Simulate insertion into hotbar and then main inventory, allowing for inserting into empty slots,
        // as we just want to do a quick general check to see if there is room for the result, we will do
        // the secondary checks afterwards while working on actually inserting into it
        // The reason this is needed is that if we only have space for two more items, but our crafting recipe will
        // produce three more, then we won't have room for that singular extra item and need to exit
        ItemStack simulatedRemainder = MekanismContainer.insertItemCheckAll(hotBarSlots, result, windowData, Action.SIMULATE);
        simulatedRemainder = MekanismContainer.insertItemCheckAll(mainInventorySlots, simulatedRemainder, windowData, Action.SIMULATE);
        if (!simulatedRemainder.isEmpty()) {
            // some contents ended up in their storage system instead
            break;
        }
        // Actually transfer the output to the player's inventory now that we know it will fit
        ItemStack toInsert = lastInsertTarget.tryInserting(hotBarSlots, mainInventorySlots, windowData, result);
        if (!toInsert.isEmpty()) {
            // If something went horribly wrong adding it to the player's inventory given we calculated there was room
            // and suddenly a few lines down there is no longer room, then just drop the items as the player
            player.drop(toInsert, false);
        }
        boolean stopCrafting = false;
        // Update slots with remaining contents
        for (int index = 0; index < remaining.size(); index++) {
            ItemStack remainder = remaining.get(index);
            CraftingWindowInventorySlot inputSlot = inputSlots[index];
            if (inputSlot.getCount() > 1) {
                // If the input slot contains an item that is stacked, reduce the size of it by one
                // Note: We "ignore" the fact that the container item may still be valid for the recipe, if the input is stacked
                useInput(inputSlot);
            } else if (inputSlot.getCount() == 1) {
                // Else if the input slot only has a single item in it, try removing from the frequency
                if (frequency == null || remainderHelper.isStackStillValid(world, remainder, index)) {
                    // If the remaining item is still valid for the recipe in that slot, or we don't have a frequency, and it is the
                    // last stack in the slot, remove the stack from the slot
                    useInput(inputSlot);
                    // and mark that we should recheck our output as the recipe output may have changed, or we may
                    // no longer have enough inputs to craft an output
                    recheckOutput = true;
                } else {
                    // Otherwise, try and remove the stack from the QIO frequency
                    ItemStack current = inputSlot.getStack();
                    ItemStack removed = frequency.removeItem(current, 1);
                    if (removed.isEmpty()) {
                        // If we were not able to remove any from the frequency, remove it from the crafting grid
                        useInput(inputSlot);
                        // see if we have another valid input stored in the frequency and replace it with it if we do
                        replacementHelper.findEquivalentItem(world, frequency, inputSlot, index, current);
                        // and stop crafting even if we have another valid item for that spot, as we want to give the player a chance
                        // to notice the item it will be using changed in case it got replaced with some very expensive alternative
                        stopCrafting = true;
                    }
                }
            } else if (!remainder.isEmpty()) {
                // Otherwise, if the slot is empty, but we don't have an empty remaining stack because of a mod doing odd things
                // or having some edge case behavior that creates items in a slot, mark that we need to recheck our output.
                // Technically we maybe would fail to add the item to the slot, but given that is highly unlikely we just
                // recheck anyway
                recheckOutput = true;
            }
            addRemainingItem(player, frequency, inputSlot, remainder, true);
        }
        if (stopCrafting) {
            // Note: We need to increment the amount crafted here, as breaking will skip the increment
            // that happens at the end of the loop
            crafted += amountPerCraft;
            break;
        }
    }
    if (crafted > 0) {
        // Add to the stat how much of the item the player crafted that the player crafted the item
        player.awardStat(itemCraftedStat, crafted);
    // Note: We don't fire a crafting event as we don't want to allow for people to modify the output
    // stack or more importantly the input inventory during crafting
    // TODO: If this ends up causing major issues with some weird way another mod ends up doing crafting
    // we can evaluate how we want to handle it then/try to integrate support for firing it.
    // BasicEventHooks.firePlayerCraftingEvent(player, result, craftingInventory);
    }
    // Mark that we are done crafting
    craftingFinished(world);
}
Also used : Item(net.minecraft.item.Item) HashedItem(mekanism.common.lib.inventory.HashedItem) ICraftingRecipe(net.minecraft.item.crafting.ICraftingRecipe) World(net.minecraft.world.World) ItemStack(net.minecraft.item.ItemStack) CraftingWindowInventorySlot(mekanism.common.inventory.slot.CraftingWindowInventorySlot)

Example 3 with CraftingWindowInventorySlot

use of mekanism.common.inventory.slot.CraftingWindowInventorySlot in project Mekanism by mekanism.

the class QIOServerCraftingTransferHandler method bail.

/**
 * Bails out if something went horribly wrong and didn't get caught by simulations, and send the various items back to the inventory.
 */
private void bail(Byte2ObjectMap<ItemStack> targetContents, Byte2ObjectMap<ItemStack> remainingCraftingGridContents, String format, Object... args) {
    Mekanism.logger.warn(format, args);
    SelectedWindowData windowData = craftingWindow.getWindowData();
    for (ItemStack stack : targetContents.values()) {
        // We don't attempt to try and return the contents being moved to the crafting inventory to their original slots
        // as we don't keep track of that data and in theory unless something goes majorly wrong we should never end
        // up bailing anyways
        // TODO: Eventually we may want to try and make it first try to return to the same slots it came from but it doesn't matter that much
        returnItem(stack, windowData);
    }
    // Put the items that were in the crafting window in the player's inventory
    for (Byte2ObjectMap.Entry<ItemStack> entry : remainingCraftingGridContents.byte2ObjectEntrySet()) {
        ItemStack stack = entry.getValue();
        CraftingWindowInventorySlot inputSlot = craftingWindow.getInputSlot(entry.getByteKey());
        if (ItemHandlerHelper.canItemStacksStack(inputSlot.getStack(), stack)) {
            stack = inputSlot.insertItem(stack, Action.EXECUTE, AutomationType.MANUAL);
            if (stack.isEmpty()) {
                continue;
            }
        }
        returnItem(stack, windowData);
    }
}
Also used : Byte2ObjectMap(it.unimi.dsi.fastutil.bytes.Byte2ObjectMap) ItemStack(net.minecraft.item.ItemStack) SelectedWindowData(mekanism.common.inventory.container.SelectedWindowData) CraftingWindowInventorySlot(mekanism.common.inventory.slot.CraftingWindowInventorySlot)

Example 4 with CraftingWindowInventorySlot

use of mekanism.common.inventory.slot.CraftingWindowInventorySlot in project Mekanism by mekanism.

the class QIOServerCraftingTransferHandler method tryTransfer.

private void tryTransfer(ICraftingRecipe recipe, Byte2ObjectMap<List<SingularHashedItemSource>> sources) {
    // need to be able to extract the contents afterwards anyway
    for (byte slot = 0; slot < 9; slot++) {
        CraftingWindowInventorySlot inputSlot = craftingWindow.getInputSlot(slot);
        if (!inputSlot.isEmpty()) {
            ItemStack available = inputSlot.extractItem(inputSlot.getCount(), Action.SIMULATE, AutomationType.INTERNAL);
            if (available.getCount() < inputSlot.getCount()) {
                // TODO: Eventually it would be nice if we added in some support so that if an item is staying put in its crafting slot
                // we don't actually need to do any validation of if it can be extracted from when it will just end up in the same spot anyways
                // but for now this isn't that major of a concern as our slots don't actually have any restrictions on them in regards to extracting
                Mekanism.logger.warn("Received transfer request from: {}, for: {}, and was unable to extract all items from crafting input slot: {}.", player, recipeID, slot);
                return;
            }
            availableItems.put(slot, new SlotData(available));
        }
    }
    for (Byte2ObjectMap.Entry<List<SingularHashedItemSource>> entry : sources.byte2ObjectEntrySet()) {
        byte targetSlot = entry.getByteKey();
        if (targetSlot < 0 || targetSlot >= 9) {
            Mekanism.logger.warn("Received transfer request from: {}, for: {}, with an invalid target slot id: {}.", player, recipeID, targetSlot);
            return;
        }
        int stackSize = 0;
        List<SingularHashedItemSource> singleSources = entry.getValue();
        for (Iterator<SingularHashedItemSource> iter = singleSources.iterator(); iter.hasNext(); ) {
            SingularHashedItemSource source = iter.next();
            byte slot = source.getSlot();
            int used;
            if (slot == -1) {
                used = simulateQIOSource(targetSlot, source.getQioSource(), source.getUsed(), stackSize);
            } else {
                used = simulateSlotSource(targetSlot, slot, source.getUsed(), stackSize);
            }
            if (used == -1) {
                // Error occurred and was logged, exit
                return;
            } else if (used == 0) {
                // Unable to use any of this source due to it not stacking with an earlier one for example
                // remove this source
                iter.remove();
            } else {
                if (used < source.getUsed()) {
                    // If we used less than we were expected to (most likely due to stack sizes) then we need
                    // to decrease the amount of the source being used
                    source.setUsed(used);
                }
                stackSize += used;
            }
        }
        if (singleSources.isEmpty()) {
            // There should always be at least one (the first source) that didn't get removed, but in case something went wrong,
            // and it got removed anyway, then we catch it here and fail
            Mekanism.logger.warn("Received transfer request from: {}, for: {}, that had no valid sources, this should not be possible.", player, recipeID);
            return;
        }
        ItemStack resultItem = recipeToTest.get(targetSlot);
        if (!resultItem.isEmpty() && resultItem.getMaxStackSize() < stackSize) {
            // Note: This should never happen as if it would happen it should be caught in the above simulation and have the amount used reduced to not happen
            Mekanism.logger.warn("Received transfer request from: {}, for: {}, that tried to transfer more items into: {} than can stack ({}) in one slot.", player, recipeID, targetSlot, resultItem.getMaxStackSize());
            return;
        }
    }
    CraftingInventory dummy = MekanismUtils.getDummyCraftingInv();
    for (int slot = 0; slot < 9; slot++) {
        dummy.setItem(slot, StackUtils.size(recipeToTest.get(slot), 1));
    }
    if (!recipe.matches(dummy, player.level)) {
        Mekanism.logger.warn("Received transfer request from: {}, but source items aren't valid for the requested recipe: {}.", player, recipeID);
    } else if (!hasRoomToShuffle()) {
        // Note: Uses debug logging level as there are a couple cases this might not be 100% accurate on the client side
        Mekanism.logger.debug("Received transfer request from: {}, but there is not enough room to shuffle items around for the requested recipe: {}.", player, recipeID);
    } else {
        transferItems(sources);
    }
}
Also used : CraftingInventory(net.minecraft.inventory.CraftingInventory) SingularHashedItemSource(mekanism.common.content.qio.QIOCraftingTransferHelper.SingularHashedItemSource) Byte2ObjectMap(it.unimi.dsi.fastutil.bytes.Byte2ObjectMap) ArrayList(java.util.ArrayList) NonNullList(net.minecraft.util.NonNullList) List(java.util.List) ItemStack(net.minecraft.item.ItemStack) CraftingWindowInventorySlot(mekanism.common.inventory.slot.CraftingWindowInventorySlot)

Example 5 with CraftingWindowInventorySlot

use of mekanism.common.inventory.slot.CraftingWindowInventorySlot in project Mekanism by mekanism.

the class QIOCraftingWindow method performCraft.

@Nonnull
public ItemStack performCraft(@Nonnull PlayerEntity player, @Nonnull ItemStack result, int amountCrafted) {
    // Maybe for now an IQIOIntegratedCraftingRecipe or something like that that we can call?
    if (amountCrafted == 0 || lastRecipe == null || result.isEmpty()) {
        // Note: lastRecipe will always null on the client, so we can assume we are server side below
        return ItemStack.EMPTY;
    }
    World world = holder.getHolderWorld();
    if (!validateAndUnlockRecipe(world, player)) {
        // If the recipe isn't valid, fail
        return ItemStack.EMPTY;
    }
    QIOFrequency frequency = holder.getFrequency();
    // Mark that we are crafting so changes to the slots below don't force a bunch of recalculations to take place
    craftingStarted(player);
    // Craft the result
    result.onCraftedBy(world, player, amountCrafted);
    // Note: We don't fire a crafting event as we don't want to allow for people to modify the output
    // stack or more importantly the input inventory during crafting
    // TODO: If this ends up causing major issues with some weird way another mod ends up doing crafting
    // we can evaluate how we want to handle it then/try to integrate support for firing it.
    // BasicEventHooks.firePlayerCraftingEvent(player, result, craftingInventory);
    NonNullList<ItemStack> remaining = lastRecipe.getRemainingItems(craftingInventory);
    remainderHelper.reset();
    replacementHelper.reset();
    // Update slots with remaining contents
    for (int index = 0; index < remaining.size(); index++) {
        ItemStack remainder = remaining.get(index);
        CraftingWindowInventorySlot inputSlot = inputSlots[index];
        if (inputSlot.getCount() > 1) {
            // If the input slot contains an item that is stacked, reduce the size of it by one
            // Note: We "ignore" the fact that the container item may still be valid for the recipe, if the input is stacked
            useInput(inputSlot);
        } else if (inputSlot.getCount() == 1) {
            // Else if the input slot only has a single item in it, try removing from the frequency
            if (frequency == null || remainderHelper.isStackStillValid(world, remainder, index)) {
                // If we have no frequency or the remaining item is still valid for the recipe in that slot,
                // remove from the crafting window
                useInput(inputSlot);
            } else {
                // Otherwise, try and remove the stack from the QIO frequency
                ItemStack current = inputSlot.getStack();
                ItemStack removed = frequency.removeItem(current, 1);
                if (removed.isEmpty()) {
                    // If we were not able to remove any from the frequency, remove it from the crafting grid
                    useInput(inputSlot);
                    // see if we have another valid input stored in the frequency and replace it with it if we do
                    replacementHelper.findEquivalentItem(world, frequency, inputSlot, index, current);
                }
            }
        }
        // Note: No special handling needed here for if the remainder is empty
        addRemainingItem(player, frequency, inputSlot, remainder, false);
    }
    // Mark that we are done crafting
    craftingFinished(world);
    return result;
}
Also used : World(net.minecraft.world.World) ItemStack(net.minecraft.item.ItemStack) CraftingWindowInventorySlot(mekanism.common.inventory.slot.CraftingWindowInventorySlot) Nonnull(javax.annotation.Nonnull)

Aggregations

CraftingWindowInventorySlot (mekanism.common.inventory.slot.CraftingWindowInventorySlot)7 ItemStack (net.minecraft.item.ItemStack)6 Byte2ObjectMap (it.unimi.dsi.fastutil.bytes.Byte2ObjectMap)4 ArrayList (java.util.ArrayList)3 List (java.util.List)3 SingularHashedItemSource (mekanism.common.content.qio.QIOCraftingTransferHelper.SingularHashedItemSource)3 HashedItem (mekanism.common.lib.inventory.HashedItem)3 Byte2ObjectArrayMap (it.unimi.dsi.fastutil.bytes.Byte2ObjectArrayMap)2 UUID (java.util.UUID)2 Nonnull (javax.annotation.Nonnull)2 SelectedWindowData (mekanism.common.inventory.container.SelectedWindowData)2 CraftingInventory (net.minecraft.inventory.CraftingInventory)2 ByteArrayList (it.unimi.dsi.fastutil.bytes.ByteArrayList)1 ByteArraySet (it.unimi.dsi.fastutil.bytes.ByteArraySet)1 ByteIterator (it.unimi.dsi.fastutil.bytes.ByteIterator)1 ByteList (it.unimi.dsi.fastutil.bytes.ByteList)1 ByteSet (it.unimi.dsi.fastutil.bytes.ByteSet)1 Object2BooleanArrayMap (it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap)1 Object2BooleanMap (it.unimi.dsi.fastutil.objects.Object2BooleanMap)1 Object2IntArrayMap (it.unimi.dsi.fastutil.objects.Object2IntArrayMap)1