package pneumaticCraft.common.util;
import net.minecraft.block.Block;
import net.minecraft.block.BlockChest;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
/*
* This file is part of Blue Power.
*
* Blue Power is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Blue Power is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Blue Power. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @author MineMaarten
* @author Dynious
*/
public class IOHelper{
public static IInventory getInventoryForTE(TileEntity te){
if(te instanceof IInventory) {
IInventory inv = (IInventory)te;
Block block = te.getBlockType();
if(block instanceof BlockChest) {
inv = ((BlockChest)block).func_149951_m(te.getWorldObj(), te.xCoord, te.yCoord, te.zCoord);
}
return inv;
} else {
return null;
}
}
public static TileEntity getNeighbor(TileEntity te, ForgeDirection dir){
return te.getWorldObj().getTileEntity(te.xCoord + dir.offsetX, te.yCoord + dir.offsetY, te.zCoord + dir.offsetZ);
}
/**
* Extracts an exact amount on all sides
* @param tile
* @param itemStack
* @param simulate
* @return
*/
public static ItemStack extract(TileEntity tile, ItemStack itemStack, boolean simulate){
ItemStack extracted = null;
for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
extracted = extract(tile, d, itemStack, true, simulate);
if(extracted != null) return extracted;
}
return null;
}
public static ItemStack extract(TileEntity inventory, ForgeDirection direction, boolean simulate){
IInventory inv = getInventoryForTE(inventory);
if(inv != null) return extract(inv, direction, simulate);
return null;
}
public static ItemStack extract(IInventory inventory, ForgeDirection direction, boolean simulate){
if(inventory instanceof ISidedInventory) {
ISidedInventory isidedinventory = (ISidedInventory)inventory;
int[] accessibleSlotsFromSide = isidedinventory.getAccessibleSlotsFromSide(direction.ordinal());
for(int anAccessibleSlotsFromSide : accessibleSlotsFromSide) {
ItemStack stack = extract(inventory, direction, anAccessibleSlotsFromSide, simulate);
if(stack != null) return stack;
}
} else {
int j = inventory.getSizeInventory();
for(int k = 0; k < j; ++k) {
ItemStack stack = extract(inventory, direction, k, simulate);
if(stack != null) return stack;
}
}
return null;
}
public static ItemStack extract(IInventory inventory, ForgeDirection direction, int slot, boolean simulate){
ItemStack itemstack = inventory.getStackInSlot(slot);
if(itemstack != null && canExtractItemFromInventory(inventory, itemstack, slot, direction.ordinal())) {
if(!simulate) inventory.setInventorySlotContents(slot, null);
return itemstack;
}
return null;
}
public static ItemStack extract(TileEntity tile, ForgeDirection direction, ItemStack requestedStack, boolean useItemCount, boolean simulate){
return extract(tile, direction, requestedStack, useItemCount, simulate, 0);
}
public static int[] getAccessibleSlotsForInventory(IInventory inv, ForgeDirection side){
int[] accessibleSlots;
if(inv != null) {
if(inv instanceof ISidedInventory) {
accessibleSlots = ((ISidedInventory)inv).getAccessibleSlotsFromSide(side.ordinal());
} else {
accessibleSlots = new int[inv.getSizeInventory()];
for(int i = 0; i < accessibleSlots.length; i++)
accessibleSlots[i] = i;
}
return accessibleSlots;
} else {
return new int[0];
}
}
/**
* Retrieves an item from the specified inventory. This item can be specified.
*
* @param tile
* @param direction
* @param requestedStack
* @param useItemCount
* if true, it'll only retrieve the stack of the exact item count given. it'll look in multiple slots of the inventory. if false, the
* first matching stack, ignoring item count, will be returned.
* @param simulate
* @param fuzzySetting
* ,
* @return
*/
public static ItemStack extract(TileEntity tile, ForgeDirection direction, ItemStack requestedStack, boolean useItemCount, boolean simulate, int fuzzySetting){
if(requestedStack == null) return requestedStack;
IInventory inv = getInventoryForTE(tile);
if(inv != null) {
int[] accessibleSlots;
if(inv instanceof ISidedInventory) {
accessibleSlots = ((ISidedInventory)inv).getAccessibleSlotsFromSide(direction.ordinal());
} else {
accessibleSlots = new int[inv.getSizeInventory()];
for(int i = 0; i < accessibleSlots.length; i++)
accessibleSlots[i] = i;
}
int itemsFound = 0;
for(int slot : accessibleSlots) {
ItemStack stack = inv.getStackInSlot(slot);
if(stack != null && stack.stackSize > 0 && stack.isItemEqual(requestedStack) && IOHelper.canExtractItemFromInventory(inv, stack, slot, direction.ordinal())) {
if(!useItemCount) {
if(!simulate) {
inv.setInventorySlotContents(slot, null);
}
return stack;
}
itemsFound += stack.stackSize;
}
}
if(itemsFound >= requestedStack.stackSize) {
ItemStack exportedStack = null;
int itemsNeeded = requestedStack.stackSize;
for(int slot : accessibleSlots) {
ItemStack stack = inv.getStackInSlot(slot);
if(stack != null && stack.isItemEqual(requestedStack) && IOHelper.canExtractItemFromInventory(inv, stack, slot, direction.ordinal())) {
int itemsSubstracted = Math.min(itemsNeeded, stack.stackSize);
if(itemsSubstracted > 0) exportedStack = stack;
itemsNeeded -= itemsSubstracted;
if(!simulate) {
stack.stackSize -= itemsSubstracted;
if(stack.stackSize == 0) {
inv.setInventorySlotContents(slot, null);
}
tile.markDirty();
}
}
}
exportedStack = exportedStack.copy();
exportedStack.stackSize = requestedStack.stackSize;
return exportedStack;
}
}
return null;
}
public static ItemStack extractOneItem(TileEntity tile, ForgeDirection dir, boolean simulate){
IInventory inv = getInventoryForTE(tile);
if(inv != null) {
int[] accessibleSlots;
if(inv instanceof ISidedInventory) {
accessibleSlots = ((ISidedInventory)inv).getAccessibleSlotsFromSide(dir.ordinal());
} else {
accessibleSlots = new int[inv.getSizeInventory()];
for(int i = 0; i < accessibleSlots.length; i++)
accessibleSlots[i] = i;
}
for(int slot : accessibleSlots) {
ItemStack stack = inv.getStackInSlot(slot);
if(stack != null && stack.stackSize > 0 && IOHelper.canExtractItemFromInventory(inv, stack, slot, dir.ordinal())) {
if(simulate) {
ItemStack ret = stack.copy();
ret.stackSize = 1;
return ret;
}
ItemStack ret = stack.splitStack(1);
if(stack.stackSize == 0) inv.setInventorySlotContents(slot, null);
tile.markDirty();
return ret;
}
}
}
return null;
}
/**
* Inserts on all sides
* @param tile
* @param itemStack
* @param simulate
* @return
*/
public static ItemStack insert(TileEntity tile, ItemStack itemStack, boolean simulate){
IInventory inv = getInventoryForTE(tile);
ItemStack insertingStack = itemStack.copy();
for(int i = 0; i < 6; i++) {
insertingStack = insert(inv, insertingStack, i, simulate);
if(insertingStack == null || insertingStack.stackSize != itemStack.stackSize) return insertingStack;
}
return insertingStack;
}
public static ItemStack insert(TileEntity tile, ItemStack itemStack, ForgeDirection direction, boolean simulate){
IInventory inv = getInventoryForTE(tile);
if(inv != null) return insert(inv, itemStack, direction.ordinal(), simulate);
return itemStack;
}
public static ItemStack insert(IInventory inventory, ItemStack itemStack, int side, boolean simulate){
if(inventory instanceof ISidedInventory && side > -1) {
ISidedInventory isidedinventory = (ISidedInventory)inventory;
int[] aint = isidedinventory.getAccessibleSlotsFromSide(side);
for(int j = 0; j < aint.length && itemStack != null && itemStack.stackSize > 0; ++j) {
itemStack = insert(inventory, itemStack, aint[j], side, simulate);
}
} else if(inventory != null) {
int k = inventory.getSizeInventory();
for(int l = 0; l < k && itemStack != null && itemStack.stackSize > 0; ++l) {
itemStack = insert(inventory, itemStack, l, side, simulate);
}
}
if(itemStack != null && itemStack.stackSize == 0) {
itemStack = null;
}
return itemStack;
}
public static ItemStack insert(IInventory inventory, ItemStack itemStack, int slot, int side, boolean simulate){
ItemStack itemstack1 = inventory.getStackInSlot(slot);
if(canInsertItemToInventory(inventory, itemStack, slot, side)) {
boolean flag = false;
if(itemstack1 == null) {
int max = Math.min(itemStack.getMaxStackSize(), inventory.getInventoryStackLimit());
if(max >= itemStack.stackSize) {
if(!simulate) {
inventory.setInventorySlotContents(slot, itemStack);
flag = true;
}
itemStack = null;
} else {
if(!simulate) {
inventory.setInventorySlotContents(slot, itemStack.splitStack(max));
flag = true;
} else {
itemStack.splitStack(max);
}
}
} else if(itemstack1.isItemEqual(itemStack) && ItemStack.areItemStackTagsEqual(itemstack1, itemStack)) {
int max = Math.min(itemStack.getMaxStackSize(), inventory.getInventoryStackLimit());
if(max > itemstack1.stackSize) {
int l = Math.min(itemStack.stackSize, max - itemstack1.stackSize);
itemStack.stackSize -= l;
if(!simulate) {
itemstack1.stackSize += l;
flag = l > 0;
}
}
}
if(flag) {
inventory.markDirty();
}
}
return itemStack;
}
public static boolean canInsertItemToInventory(IInventory inventory, ItemStack itemStack, int slot, boolean[] sides){
for(int i = 0; i < sides.length; i++) {
if(sides[i] && canInsertItemToInventory(inventory, itemStack, slot, i)) return true;
}
return false;
}
public static boolean canExtractItemFromInventory(IInventory inventory, ItemStack itemStack, int slot, boolean[] sides){
for(int i = 0; i < sides.length; i++) {
if(sides[i] && canExtractItemFromInventory(inventory, itemStack, slot, i)) return true;
}
return false;
}
public static boolean canInsertItemToInventory(IInventory inventory, ItemStack itemStack, int slot, int side){
return inventory.isItemValidForSlot(slot, itemStack) && (!(inventory instanceof ISidedInventory) || ((ISidedInventory)inventory).canInsertItem(slot, itemStack, side));
}
public static boolean canExtractItemFromInventory(IInventory inventory, ItemStack itemStack, int slot, int side){
return !(inventory instanceof ISidedInventory) || ((ISidedInventory)inventory).canExtractItem(slot, itemStack, side);
}
public static void dropInventory(World world, int x, int y, int z){
TileEntity tileEntity = world.getTileEntity(x, y, z);
if(!(tileEntity instanceof IInventory)) {
return;
}
IInventory inventory = (IInventory)tileEntity;
for(int i = 0; i < inventory.getSizeInventory(); i++) {
ItemStack itemStack = inventory.getStackInSlot(i);
if(itemStack != null && itemStack.stackSize > 0) {
spawnItemInWorld(world, itemStack, x, y, z);
}
}
}
public static void spawnItemInWorld(World world, ItemStack itemStack, double x, double y, double z){
if(world.isRemote) return;
float dX = world.rand.nextFloat() * 0.8F + 0.1F;
float dY = world.rand.nextFloat() * 0.8F + 0.1F;
float dZ = world.rand.nextFloat() * 0.8F + 0.1F;
EntityItem entityItem = new EntityItem(world, x + dX, y + dY, z + dZ, new ItemStack(itemStack.getItem(), itemStack.stackSize, itemStack.getItemDamage()));
if(itemStack.hasTagCompound()) {
entityItem.getEntityItem().setTagCompound((NBTTagCompound)itemStack.getTagCompound().copy());
}
float factor = 0.05F;
entityItem.motionX = world.rand.nextGaussian() * factor;
entityItem.motionY = world.rand.nextGaussian() * factor + 0.2F;
entityItem.motionZ = world.rand.nextGaussian() * factor;
world.spawnEntityInWorld(entityItem);
itemStack.stackSize = 0;
}
public static boolean canInterfaceWith(TileEntity tile, ForgeDirection direction){
if(tile instanceof IInventory) {
return !(tile instanceof ISidedInventory) || ((ISidedInventory)tile).getAccessibleSlotsFromSide(direction.ordinal()).length > 0;
}
return false;
}
}