package openmods.inventory.legacy;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import openmods.inventory.GenericInventory;
import openmods.utils.BlockUtils;
import openmods.utils.InventoryUtils;
// TODO Legacy methods, replace with something sane
public class ItemDistribution {
public static boolean consumeFirstInventoryItem(IInventory inventory, ItemStack stack) {
int slotWithStack = InventoryUtils.getFirstSlotWithStack(inventory, stack);
if (slotWithStack > -1) {
ItemStack stackInSlot = inventory.getStackInSlot(slotWithStack);
stackInSlot.stackSize--;
if (stackInSlot.stackSize == 0) {
inventory.setInventorySlotContents(slotWithStack, null);
}
return true;
}
return false;
}
public static boolean insertItemIntoInventory(IInventory inventory, ItemStack stack) {
return insertItemIntoInventory(inventory, stack, ForgeDirection.UNKNOWN, -1);
}
public static boolean insertItemIntoInventory(IInventory inventory, ItemStack stack, ForgeDirection side, int intoSlot) {
return insertItemIntoInventory(inventory, stack, side, intoSlot, true);
}
public static boolean insertItemIntoInventory(IInventory inventory, ItemStack stack, ForgeDirection side, int intoSlot, boolean doMove) {
return insertItemIntoInventory(inventory, stack, side, intoSlot, doMove, true);
}
public static boolean insertItemIntoInventory(IInventory inventory, ItemStack stack, ForgeDirection side, int intoSlot, boolean doMove, boolean canStack) {
if (stack == null) return false;
final int sideId = side.ordinal();
IInventory targetInventory = inventory;
// if we're not meant to move, make a clone of the inventory
if (!doMove) {
GenericInventory copy = new GenericInventory("temporary.inventory", false, targetInventory.getSizeInventory());
copy.copyFrom(inventory);
targetInventory = copy;
}
final Set<Integer> attemptSlots = Sets.newTreeSet();
// if it's a sided inventory, get all the accessible slots
final boolean isSidedInventory = inventory instanceof ISidedInventory && side != ForgeDirection.UNKNOWN;
if (isSidedInventory) {
int[] accessibleSlots = ((ISidedInventory)inventory).getAccessibleSlotsFromSide(sideId);
for (int slot : accessibleSlots)
attemptSlots.add(slot);
} else {
// if it's just a standard inventory, get all slots
for (int a = 0; a < inventory.getSizeInventory(); a++) {
attemptSlots.add(a);
}
}
if (intoSlot > -1) attemptSlots.retainAll(ImmutableSet.of(intoSlot));
if (attemptSlots.isEmpty()) return false;
boolean result = false;
for (Integer slot : attemptSlots) {
if (stack.stackSize <= 0) break;
if (isSidedInventory && !((ISidedInventory)inventory).canInsertItem(slot, stack, sideId)) continue;
result |= tryInsertStack(targetInventory, slot, stack, canStack);
}
return result;
}
public static int moveItemInto(IInventory fromInventory, int fromSlot, CustomSinks.ICustomSink sink, int maxAmount, ForgeDirection direction, boolean doMove) {
fromInventory = InventoryUtils.getInventory(fromInventory);
ItemStack sourceStack = fromInventory.getStackInSlot(fromSlot);
if (sourceStack == null || maxAmount <= 0) return 0;
if (fromInventory instanceof ISidedInventory
&& !((ISidedInventory)fromInventory).canExtractItem(fromSlot, sourceStack, direction.ordinal()))
return 0;
final int amountToMove = Math.min(sourceStack.stackSize, maxAmount);
ItemStack clonedSourceStack = InventoryUtils.copyAndChange(sourceStack, amountToMove);
final int inserted = sink.accept(clonedSourceStack, doMove, direction);
if (doMove) InventoryUtils.removeFromSlot(fromInventory, fromSlot, inserted);
return inserted;
}
public static boolean insertItemInto(ItemStack stack, CustomSinks.ICustomSink sink, ForgeDirection intoSide, boolean doMove) {
ItemStack clonedSourceStack = stack.copy();
final int inserted = sink.accept(clonedSourceStack, doMove, intoSide);
if (inserted > 0) {
stack.stackSize -= inserted;
return true;
}
return false;
}
public static int moveItemInto(IInventory fromInventory, int fromSlot, IInventory target, int intoSlot, int maxAmount, ForgeDirection direction, boolean doMove) {
return moveItemInto(fromInventory, fromSlot, target, intoSlot, maxAmount, direction, doMove, true);
}
/***
* Move an item from the fromInventory, into the target. The target can be
* an inventory or pipe.
* Double checks are automagically wrapped. If you're not bothered what slot
* you insert into, pass -1 for intoSlot. If you're passing false for
* doMove, it'll create a dummy inventory and its calculations on that
* instead
*
* @param fromInventory
* the inventory the item is coming from
* @param fromSlot
* the slot the item is coming from
* @param toInventory
* the inventory you want the item to be put into. can be BC pipe
* or IInventory
* @param intoSlot
* the target slot. Pass -1 for any slot
* @param maxAmount
* The maximum amount you wish to pass
* @param direction
* The direction of the move. Pass UNKNOWN if not applicable
* @param doMove
* @param canStack
* @return The amount of items moved
*/
public static int moveItemInto(IInventory fromInventory, int fromSlot, IInventory toInventory, int intoSlot, int maxAmount, ForgeDirection direction, boolean doMove, boolean canStack) {
fromInventory = InventoryUtils.getInventory(fromInventory);
ItemStack sourceStack = fromInventory.getStackInSlot(fromSlot);
if (sourceStack == null || maxAmount <= 0) return 0;
if (fromInventory instanceof ISidedInventory
&& !((ISidedInventory)fromInventory).canExtractItem(fromSlot, sourceStack, direction.ordinal()))
return 0;
final int amountToMove = Math.min(sourceStack.stackSize, maxAmount);
ItemStack insertedStack = InventoryUtils.copyAndChange(sourceStack, amountToMove);
IInventory targetInventory = InventoryUtils.getInventory(toInventory);
ForgeDirection side = direction.getOpposite();
// try insert the item into the target inventory. this'll reduce the
// stackSize of our stack
insertItemIntoInventory(targetInventory, insertedStack, side, intoSlot, doMove, canStack);
int inserted = amountToMove - insertedStack.stackSize;
if (doMove) InventoryUtils.removeFromSlot(fromInventory, fromSlot, inserted);
return inserted;
}
public static int moveItemInto(IInventory fromInventory, int fromSlot, TileEntity te, ForgeDirection intoSide, int maxAmount, boolean doMove) {
if (te == null) return 0;
if (te instanceof IInventory) {
final IInventory toInventory = (IInventory)te;
final int moved = moveItemInto(fromInventory, fromSlot, toInventory, -1, maxAmount, intoSide, doMove);
if (moved > 0) toInventory.markDirty(); // we are losing info here, so must commit
return moved;
} else {
CustomSinks.ICustomSink adapter = CustomSinks.createSink(te);
if (adapter != null) return moveItemInto(fromInventory, fromSlot, adapter, maxAmount, intoSide, doMove);
}
return 0;
}
public static boolean insertItemInto(ItemStack stack, TileEntity te, ForgeDirection intoSide, boolean doMove) {
if (te == null) return false;
if (te instanceof IInventory) {
final IInventory toInventory = (IInventory)te;
boolean changed = insertItemIntoInventory(toInventory, stack, intoSide, -1, doMove);
if (changed) toInventory.markDirty(); // we are losing info here, so must commit
return changed;
} else {
CustomSinks.ICustomSink adapter = CustomSinks.createSink(te);
if (adapter != null) return insertItemInto(stack, adapter, intoSide, doMove);
}
return false;
}
public static int moveItemsFromOneOfSides(TileEntity te, IInventory inv, int maxAmount, int intoSlot, Iterable<ForgeDirection> sides, boolean randomize) {
return moveItemsFromOneOfSides(te, inv, null, maxAmount, intoSlot, sides, randomize);
}
public static int moveItemsFromOneOfSides(TileEntity te, IInventory inv, ItemStack filterStack, int maxAmount, int intoSlot, Iterable<ForgeDirection> sides, boolean randomize) {
if (randomize) {
List<ForgeDirection> shuffledSides = Lists.newArrayList(sides);
Collections.shuffle(shuffledSides);
sides = shuffledSides;
}
IInventory ourInventory = InventoryUtils.getInventory(inv);
// loop through the shuffled sides
for (ForgeDirection dir : sides) {
TileEntity tileOnSurface = BlockUtils.getTileInDirection(te, dir);
// if it's an inventory
if (tileOnSurface instanceof IInventory) {
final IInventory neighbor = (IInventory)tileOnSurface;
Set<Integer> slots = filterStack == null? InventoryUtils.getAllSlots(neighbor) : InventoryUtils.getAllSlotsWithStack(neighbor, filterStack);
for (Integer slot : slots) {
int moved = moveItemInto(neighbor, slot, ourInventory, intoSlot, maxAmount, dir.getOpposite(), true);
if (moved > 0) {
// information is lost after leaving this method, so must commit here
ourInventory.markDirty();
neighbor.markDirty();
return moved;
}
}
}
}
return 0;
}
public static int moveItemsToOneOfSides(TileEntity te, IInventory inv, int fromSlot, int maxAmount, Iterable<ForgeDirection> sides, boolean randomize) {
final IInventory inventory = InventoryUtils.getInventory(inv);
// if we've not got a stack in that slot, we dont care.
if (inventory.getStackInSlot(fromSlot) == null) return 0;
// shuffle the sides that have been passed in
if (randomize) {
List<ForgeDirection> shuffledSides = Lists.newArrayList(sides);
Collections.shuffle(shuffledSides);
sides = shuffledSides;
}
for (ForgeDirection dir : sides) {
// grab the tile in the current direction
TileEntity tileOnSurface = BlockUtils.getTileInDirection(te, dir);
int inserted = moveItemInto(inventory, fromSlot, tileOnSurface, dir, maxAmount, true);
if (inserted > 0) return inserted;
}
return 0;
}
public static ItemStack removeFromFirstNonEmptySlot(IInventory invent) {
int nextFilledSlot = InventoryUtils.getFirstNonEmptySlot(invent);
if (nextFilledSlot > -1) {
ItemStack copy = invent.getStackInSlot(nextFilledSlot).copy();
invent.setInventorySlotContents(nextFilledSlot, null);
return copy;
}
return null;
}
/**
* Tests to see if an item stack can be inserted in to an inventory Does not
* perform the insertion, only tests the possibility
*
* @param inventory
* The inventory to insert the stack into
* @param item
* the stack to insert
* @return the amount of items that could be put in to the stack
*/
public static int testInventoryInsertion(IInventory inventory, ItemStack item) {
if (item == null || item.stackSize == 0) return 0;
if (inventory == null) return 0;
int slotCount = inventory.getSizeInventory();
/*
* Allows counting down the item size, without cloning or changing the
* object
*/
int itemSizeCounter = item.stackSize;
for (int i = 0; i < slotCount && itemSizeCounter > 0; i++) {
if (!inventory.isItemValidForSlot(i, item)) continue;
ItemStack inventorySlot = inventory.getStackInSlot(i);
/*
* If the slot is empty, dump the biggest stack we can, taking in to
* consideration, the remaining amount of stack
*/
if (inventorySlot == null) {
itemSizeCounter -= Math.min(Math.min(itemSizeCounter, inventory.getInventoryStackLimit()), item.getMaxStackSize());
}
/* If the slot is not empty, check that these items stack */
else if (InventoryUtils.areMergeCandidates(item, inventorySlot)) {
/* If they stack, decrement by the amount of space that remains */
int space = inventorySlot.getMaxStackSize() - inventorySlot.stackSize;
itemSizeCounter -= Math.min(itemSizeCounter, space);
}
}
// itemSizeCounter might be less than zero here. It shouldn't be, but I
// don't trust me. -NC
if (itemSizeCounter != item.stackSize) {
itemSizeCounter = Math.max(itemSizeCounter, 0);
return item.stackSize - itemSizeCounter;
}
return 0;
}
/***
* Try to merge the supplied stack into the supplied slot in the target
* inventory
*
* @param targetInventory
* Although it doesn't return anything, it'll REDUCE the stack
* size of the stack that you pass in
*
* @param slot
* @param stack
*/
public static boolean tryInsertStack(IInventory targetInventory, int slot, ItemStack stack, boolean canMerge) {
if (targetInventory.isItemValidForSlot(slot, stack)) {
ItemStack targetStack = targetInventory.getStackInSlot(slot);
if (targetStack == null) {
int limit = targetInventory.getInventoryStackLimit();
if (limit < stack.stackSize) {
targetInventory.setInventorySlotContents(slot, stack.splitStack(limit));
} else {
targetInventory.setInventorySlotContents(slot, stack.copy());
stack.stackSize = 0;
}
return true;
} else if (canMerge) {
if (targetInventory.isItemValidForSlot(slot, stack) &&
InventoryUtils.areMergeCandidates(stack, targetStack)) {
int space = targetStack.getMaxStackSize() - targetStack.stackSize;
int mergeAmount = Math.min(space, stack.stackSize);
ItemStack copy = targetStack.copy();
copy.stackSize += mergeAmount;
targetInventory.setInventorySlotContents(slot, copy);
stack.stackSize -= mergeAmount;
return true;
}
}
}
return false;
}
}