Search in sources :

Example 1 with IInventorySlot

use of mekanism.api.inventory.IInventorySlot in project Mekanism by mekanism.

the class QIOCraftingTransferHandler method hasRoomToShuffle.

/**
 * Loosely based on how {@link mekanism.common.content.qio.QIOServerCraftingTransferHandler}'s hasRoomToShuffle method works.
 */
private static boolean hasRoomToShuffle(QIOCraftingTransferHelper qioTransferHelper, @Nullable QIOFrequency frequency, QIOCraftingWindow craftingWindow, List<HotBarSlot> hotBarSlots, List<MainInventorySlot> mainInventorySlots, Map<HashedItemSource, List<List<SingularHashedItemSource>>> shuffleLookup) {
    // Map used to keep track of inputs while also merging identical inputs, so we can cut down
    // on how many times we have to check if things can stack
    Object2IntMap<HashedItem> leftOverInput = new Object2IntArrayMap<>(9);
    for (byte slotIndex = 0; slotIndex < 9; slotIndex++) {
        IInventorySlot slot = craftingWindow.getInputSlot(slotIndex);
        if (!slot.isEmpty()) {
            // Note: We can use raw as we are not modifying the stack or persisting the reference
            HashedItem type = HashedItem.raw(slot.getStack());
            HashedItemSource source = qioTransferHelper.getSource(type);
            if (source == null) {
                // Something went wrong, this should never be null for the things in the crafting slots
                return false;
            }
            int remaining = source.getSlotRemaining(slotIndex);
            if (remaining > 0) {
                // Don't bother adding any that we fully used
                leftOverInput.mergeInt(type, remaining, Integer::sum);
            }
        }
    }
    if (!leftOverInput.isEmpty()) {
        // If we have any leftover inputs in the crafting inventory, then get a simulated view of what the player's inventory
        // will look like after things are changed
        BaseSimulatedInventory simulatedInventory = new BaseSimulatedInventory(hotBarSlots, mainInventorySlots) {

            @Override
            protected int getRemaining(int slot, ItemStack currentStored) {
                HashedItemSource source = qioTransferHelper.getSource(HashedItem.raw(currentStored));
                if (source == null) {
                    return currentStored.getCount();
                }
                return source.getSlotRemaining((byte) (slot + 9));
            }
        };
        Object2IntMap<HashedItem> stillLeftOver = simulatedInventory.shuffleInputs(leftOverInput, frequency != null);
        if (stillLeftOver == null) {
            // If we have remaining items and no frequency then we don't have room to shuffle
            return false;
        }
        if (!stillLeftOver.isEmpty() && frequency != null) {
            // If we still have left over things try adding them to the frequency. We only are able to do a rough check and estimate
            // on if the frequency has room or not as depending on how things are stored in the drives there is a chance that we
            // do not actually have as much item space or types available, but this is the best we can do on the client side
            // Note: We validate the frequency is not null, even though it shouldn't be null if we have anything still left over
            // Note: We calculate these numbers as a difference so that it is easier to make sure none of the numbers accidentally overflow
            int availableItemTypes = frequency.getTotalItemTypeCapacity() - frequency.getTotalItemTypes(true);
            long availableItemSpace = frequency.getTotalItemCountCapacity() - frequency.getTotalItemCount();
            Object2BooleanMap<HashedItemSource> usedQIOSource = new Object2BooleanArrayMap<>(shuffleLookup.size());
            for (Map.Entry<HashedItemSource, List<List<SingularHashedItemSource>>> entry : shuffleLookup.entrySet()) {
                HashedItemSource source = entry.getKey();
                boolean usedQIO = false;
                for (List<SingularHashedItemSource> usedSources : entry.getValue()) {
                    for (SingularHashedItemSource usedSource : usedSources) {
                        UUID qioSource = usedSource.getQioSource();
                        if (qioSource != null) {
                            // Free up however much space as we used of the item
                            availableItemSpace += usedSource.getUsed();
                            if (source.getQIORemaining(qioSource) == 0) {
                                // If we used all that is available, we need to also free up an item type
                                availableItemTypes++;
                                usedQIO = true;
                            }
                        }
                    }
                }
                usedQIOSource.put(source, usedQIO);
            }
            for (Object2IntMap.Entry<HashedItem> entry : stillLeftOver.object2IntEntrySet()) {
                availableItemSpace -= entry.getIntValue();
                if (availableItemSpace <= 0) {
                    // No room for all our items, fail
                    return false;
                }
                HashedItemSource source = qioTransferHelper.getSource(entry.getKey());
                if (source == null) {
                    // Something went wrong, this should never be null for the things in the crafting slots
                    return false;
                } else if (source.hasQIOSources()) {
                    // It is stored, check to make sure it isn't a type we are removing at least one of fully
                    if (usedQIOSource.containsKey(source) && usedQIOSource.getBoolean(source)) {
                        // if it is, then we need to reclaim the item type as being available
                        availableItemTypes--;
                        if (availableItemTypes <= 0) {
                            // Not enough room for types
                            return false;
                        }
                    }
                } else {
                    // The item is not stored in the QIO frequency, we need to use an item type up
                    // Note: This is not super accurate due to the fact that we don't know for
                    // certain if our used source actually matched or differed in server side only
                    // NBT, but it is the best we can do on the client side
                    availableItemTypes--;
                    if (availableItemTypes <= 0) {
                        // Not enough room for types
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
Also used : IInventorySlot(mekanism.api.inventory.IInventorySlot) HashedItem(mekanism.common.lib.inventory.HashedItem) HashedItemSource(mekanism.common.content.qio.QIOCraftingTransferHelper.HashedItemSource) SingularHashedItemSource(mekanism.common.content.qio.QIOCraftingTransferHelper.SingularHashedItemSource) SingularHashedItemSource(mekanism.common.content.qio.QIOCraftingTransferHelper.SingularHashedItemSource) Object2IntMap(it.unimi.dsi.fastutil.objects.Object2IntMap) Object2BooleanArrayMap(it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap) Object2IntArrayMap(it.unimi.dsi.fastutil.objects.Object2IntArrayMap) BaseSimulatedInventory(mekanism.common.content.qio.QIOCraftingTransferHelper.BaseSimulatedInventory) List(java.util.List) ArrayList(java.util.ArrayList) ByteList(it.unimi.dsi.fastutil.bytes.ByteList) ByteArrayList(it.unimi.dsi.fastutil.bytes.ByteArrayList) ItemStack(net.minecraft.item.ItemStack) UUID(java.util.UUID) Object2BooleanMap(it.unimi.dsi.fastutil.objects.Object2BooleanMap) Object2IntArrayMap(it.unimi.dsi.fastutil.objects.Object2IntArrayMap) Object2BooleanArrayMap(it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap) Map(java.util.Map) Byte2ObjectArrayMap(it.unimi.dsi.fastutil.bytes.Byte2ObjectArrayMap) HashMap(java.util.HashMap) Byte2ObjectMap(it.unimi.dsi.fastutil.bytes.Byte2ObjectMap) Object2IntMap(it.unimi.dsi.fastutil.objects.Object2IntMap)

Example 2 with IInventorySlot

use of mekanism.api.inventory.IInventorySlot in project Mekanism by mekanism.

the class VirtualCraftingOutputSlot method remove.

@Nonnull
@Override
public ItemStack remove(int amount) {
    if (amount == 0) {
        return ItemStack.EMPTY;
    }
    // Simulate extraction to not actually modify the slot
    // Note: In theory even though we are "simulating" here instead of actually changing how much is
    // in the slot, this shouldn't be a problem or be a risk of duplication, as there are slots like
    // the MerchantResultSlot which effectively do the same thing. They do it slightly differently
    // by taking it and then just setting the contents again, but effectively it is just returning
    // a copy so if mods cause any duplication glitches because of how we handle this, then in theory
    // they probably also cause duplication glitches with some of vanilla's slots as well.
    // Note: We use the slot's actual amount instead of the passed in one, so that we ensure we properly
    // craft everything from the output stack instead of only producing part of the output
    IInventorySlot slot = getInventorySlot();
    ItemStack extracted = slot.extractItem(slot.getCount(), Action.SIMULATE, AutomationType.MANUAL);
    // Adjust amount crafted by the amount that would have actually been extracted
    amountCrafted += extracted.getCount();
    return extracted;
}
Also used : IInventorySlot(mekanism.api.inventory.IInventorySlot) ItemStack(net.minecraft.item.ItemStack) Nonnull(javax.annotation.Nonnull)

Example 3 with IInventorySlot

use of mekanism.api.inventory.IInventorySlot in project Mekanism by mekanism.

the class MekanismTileContainer method addSlots.

@Override
protected void addSlots() {
    super.addSlots();
    if (this instanceof IEmptyContainer) {
        // Don't include the inventory slots
        return;
    }
    if (tile.supportsUpgrades()) {
        // Add the virtual slot for the upgrade (add them before the main inventory to make sure they take priority in targeting)
        addSlot(upgradeSlot = tile.getComponent().getUpgradeSlot().createContainerSlot());
        addSlot(upgradeOutputSlot = tile.getComponent().getUpgradeOutputSlot().createContainerSlot());
    }
    if (tile.hasInventory()) {
        // Get all the inventory slots the tile has
        List<IInventorySlot> inventorySlots = tile.getInventorySlots(null);
        for (IInventorySlot inventorySlot : inventorySlots) {
            Slot containerSlot = inventorySlot.createContainerSlot();
            if (containerSlot != null) {
                addSlot(containerSlot);
            }
        }
    }
}
Also used : IInventorySlot(mekanism.api.inventory.IInventorySlot) IEmptyContainer(mekanism.common.inventory.container.IEmptyContainer) VirtualInventoryContainerSlot(mekanism.common.inventory.container.slot.VirtualInventoryContainerSlot) IInventorySlot(mekanism.api.inventory.IInventorySlot) Slot(net.minecraft.inventory.container.Slot)

Example 4 with IInventorySlot

use of mekanism.api.inventory.IInventorySlot in project Mekanism by mekanism.

the class PersonalChestItemContainer method addSlots.

@Override
protected void addSlots() {
    super.addSlots();
    // Get all the inventory slots the tile has
    List<IInventorySlot> inventorySlots = itemInventory.getInventorySlots(null);
    for (IInventorySlot inventorySlot : inventorySlots) {
        Slot containerSlot = inventorySlot.createContainerSlot();
        if (containerSlot != null) {
            addSlot(containerSlot);
        }
    }
}
Also used : IInventorySlot(mekanism.api.inventory.IInventorySlot) IInventorySlot(mekanism.api.inventory.IInventorySlot) Slot(net.minecraft.inventory.container.Slot) HotBarSlot(mekanism.common.inventory.container.slot.HotBarSlot)

Example 5 with IInventorySlot

use of mekanism.api.inventory.IInventorySlot in project Mekanism by mekanism.

the class TileEntityDigitalMiner method canInsert.

public boolean canInsert(List<ItemStack> toInsert) {
    if (toInsert.isEmpty()) {
        return true;
    }
    int slots = mainSlots.size();
    Int2ObjectMap<ItemCount> cachedStacks = new Int2ObjectOpenHashMap<>();
    for (ItemStack stackToInsert : toInsert) {
        if (stackToInsert.isEmpty()) {
            continue;
        }
        ItemStack stack = stackToInsert.copy();
        for (int i = 0; i < slots; i++) {
            IInventorySlot slot = mainSlots.get(i);
            // Try to insert the item across all slots until we inserted as much as we want to
            // We update our copies reference, to the remainder of what fit, so that we can
            // continue trying the next slots
            boolean wasEmpty = slot.isEmpty();
            if (wasEmpty && cachedStacks.containsKey(i)) {
                // If we have cached information about the slot and our slot is currently empty, so we can't simulate
                ItemCount cachedItem = cachedStacks.get(i);
                if (ItemHandlerHelper.canItemStacksStack(stack, cachedItem.stack)) {
                    // If our stack can stack with the item we already put there
                    // Increase how much we inserted up to the slot's limit for that stack type
                    // and then replace the reference to our stack with one that is of the adjusted size
                    int limit = slot.getLimit(stack);
                    int stackSize = stack.getCount();
                    int total = stackSize + cachedItem.count;
                    if (total <= limit) {
                        // It can all fit, increase the cached amount and break
                        cachedItem.count = total;
                        stack = ItemStack.EMPTY;
                        break;
                    }
                    int toAdd = total - limit;
                    if (toAdd > 0) {
                        // Otherwise, add what can fit and update the stack to be a reference of that
                        // stack with the proper size
                        cachedItem.count += toAdd;
                        stack = StackUtils.size(stack, stackSize - toAdd);
                    }
                }
            } else {
                int stackSize = stack.getCount();
                stack = slot.insertItem(stack, Action.SIMULATE, AutomationType.INTERNAL);
                int remainderSize = stack.getCount();
                if (wasEmpty && remainderSize < stackSize) {
                    // If the slot was empty, and accepted at least some item we are inserting
                    // then cache the item type that we put into that slot
                    cachedStacks.put(i, new ItemCount(stackToInsert, stackSize - remainderSize));
                }
                if (stack.isEmpty()) {
                    // Once we finished inserting this item, break and move on to the next item
                    break;
                }
            }
        }
        if (!stack.isEmpty()) {
            // so we return false to being able to insert all the items.
            return false;
        }
    }
    return true;
}
Also used : IInventorySlot(mekanism.api.inventory.IInventorySlot) Int2ObjectOpenHashMap(it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap) ItemStack(net.minecraft.item.ItemStack) SyncableItemStack(mekanism.common.inventory.container.sync.SyncableItemStack)

Aggregations

IInventorySlot (mekanism.api.inventory.IInventorySlot)22 ItemStack (net.minecraft.item.ItemStack)12 ArrayList (java.util.ArrayList)7 Nonnull (javax.annotation.Nonnull)5 SyncableItemStack (mekanism.common.inventory.container.sync.SyncableItemStack)5 HashedItem (mekanism.common.lib.inventory.HashedItem)5 ConfigInfo (mekanism.common.tile.component.config.ConfigInfo)4 List (java.util.List)3 Nullable (javax.annotation.Nullable)3 IntList (it.unimi.dsi.fastutil.ints.IntList)2 IntOpenHashSet (it.unimi.dsi.fastutil.ints.IntOpenHashSet)2 IntSet (it.unimi.dsi.fastutil.ints.IntSet)2 Object2IntMap (it.unimi.dsi.fastutil.objects.Object2IntMap)2 Object2IntOpenHashMap (it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap)2 HashMap (java.util.HashMap)2 NBTConstants (mekanism.api.NBTConstants)2 IMekanismInventory (mekanism.api.inventory.IMekanismInventory)2 FloatingLong (mekanism.api.math.FloatingLong)2 ComputerMethod (mekanism.common.integration.computer.annotation.ComputerMethod)2 TileEntityMekanism (mekanism.common.tile.base.TileEntityMekanism)2