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;
}
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;
}
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);
}
}
}
}
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);
}
}
}
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;
}
Aggregations