/** * **************************************************************************************************************** * Authors: SanAndreasP * Copyright: SanAndreasP * License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International * http://creativecommons.org/licenses/by-nc-sa/4.0/ * ***************************************************************************************************************** */ package de.sanandrew.core.manpack.util.helpers; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.MathHelper; import net.minecraftforge.oredict.OreDictionary; import java.util.ArrayList; import java.util.Comparator; import java.util.List; /** * A helper class for Item manipulations */ public final class ItemUtils { private static final Comparator<NBTTagCompound> STD_NBT_COMPARATOR = new Comparator<NBTTagCompound>() { @Override public int compare(NBTTagCompound o1, NBTTagCompound o2) { if( o1 != null ) { if( !o1.equals(o2) ) { return 1; } } else if( o2 != null ) { return -1; } return 0; } }; /** * Decreases the size of the given stack by the amount. * * @param is the ItemStack whose size should be decreased * @param amount the amount the size will be decreased * @return the stack with decreased size or null, if the size is <= 0 */ public static ItemStack decrStackSize(ItemStack is, int amount) { is.stackSize -= amount; if( is.stackSize <= 0 ) { return null; } return is; } /** * Compares the two given stacks and checks for their equality.<br> * <p>They are considered equal if either: * <ul> * <li>They are both null: Either the instances themselves or their items are both {@code null}</li> * <li>They have the same item instance and: * <ul> * <li>If {@code checkNbt == true}, the NBT of those 2 items is either null or {@code is1.nbt.equals(is2.nbt) == true}, otherwise NBT isn't checked</li> * <li>Their damage value is the same <i>or</i> either of their damage value has the value of {@link OreDictionary#WILDCARD_VALUE}</li> * </ul> * </li> * </ul> * </p> * * @param is1 the first stack * @param is2 the second stack * @param checkNbt true, if the NBT should be checked as well * @return true, if the stacks are equal, false otherwise. */ public static boolean areStacksEqual(ItemStack is1, ItemStack is2, boolean checkNbt) { return areStacksEqual(is1, is2, checkNbt ? STD_NBT_COMPARATOR : null); } /** * Compares the two given stacks and checks for their equality.<br> * <p>They are considered equal if either: * <ul> * <li>They are both null: Either the instances themselves or their items are both {@code null}</li> * <li>They have the same item instance and: * <ul> * <li>If the given comparator is either null or its {@code .compare(nbt1, nbt2)} method returns 0</li> * <li>Their damage value is the same <i>or</i> either of their damage value has the value of {@link OreDictionary#WILDCARD_VALUE}</li> * </ul> * </li> * </ul> * </p> * * @param is1 the first stack * @param is2 the second stack * @param nbtCheck A comparator for the NBTs of those 2 stacks, can be null to avoid checking for NBT * @return true, if the stacks are equal, false otherwise. */ public static boolean areStacksEqual(ItemStack is1, ItemStack is2, Comparator<NBTTagCompound> nbtCheck) { if( is1 == null || is2 == null ) { return is1 == is2; } if( is1.getItem() == null || is2.getItem() == null ) { return is1.getItem() == is2.getItem(); } if( is1.getItem() == is2.getItem() ) { if( nbtCheck != null ) { if( nbtCheck.compare(is1.getTagCompound(), is2.getTagCompound()) != 0 ) { return false; } } return is1.getItemDamage() == OreDictionary.WILDCARD_VALUE || is2.getItemDamage() == OreDictionary.WILDCARD_VALUE || is1.getItemDamage() == is2.getItemDamage(); } return false; } /** * Splits the given stack, which has a size > it's max. allowed, into "good" stacks with sizes <= max. allowed. * * @param is the stack which should be split * @return an Array of all "good" stacks. If {@code is.stackSize <= 0}, then a zero-length array is returned. */ public static ItemStack[] getGoodItemStacks(ItemStack is) { int maxStackSize = is.getMaxStackSize(); if( is.stackSize <= maxStackSize && is.stackSize > 0 ) { return new ItemStack[] { is }; } else if( is.stackSize > 0 ) { int maxFullStackCnt = MathHelper.floor_float(is.stackSize / (float) maxStackSize); List<ItemStack> isMap = new ArrayList<>(MathHelper.ceiling_float_int(is.stackSize / (float) maxStackSize)); ItemStack isNew; for( int i = 0; i < maxFullStackCnt; i++ ) { isNew = is.copy(); isNew.stackSize = maxStackSize; isMap.add(isNew); } isNew = is.copy(); if( (isNew.stackSize -= maxStackSize * maxFullStackCnt) > 0 ) { isMap.add(isNew); } return isMap.toArray(new ItemStack[isMap.size()]); } return new ItemStack[0]; } /** * Checks if the ItemStack given can be found inside the array.<br> * Comparison rules are like {@link ItemUtils#areStacksEqual(ItemStack, ItemStack, boolean)}. * * @param stack the stack to be searched inside the array * @param checkNbt true, if the NBT should be checked as well * @param stackArray the array to be searched * @return true, if the stack was found, false otherwise */ public static boolean isItemStackInArray(ItemStack stack, boolean checkNbt, ItemStack... stackArray) { for( ItemStack stackElem : stackArray ) { if( areStacksEqual(stack, stackElem, checkNbt) ) { return true; } } return false; } /** * Checks if the ItemStack given can be found inside the array.<br> * Comparison rules are like {@link ItemUtils#areStacksEqual(ItemStack, ItemStack, Comparator)}. * * @param stack the stack to be searched inside the array * @param nbtCheck A comparator for the NBTs of those 2 stacks, can be null to avoid checking for NBT * @param stackArray the array to be searched * @return true, if the stack was found, false otherwise */ public static boolean isItemStackInArray(ItemStack stack, Comparator<NBTTagCompound> nbtCheck, ItemStack... stackArray) { for( ItemStack stackElem : stackArray ) { if( areStacksEqual(stack, stackElem, nbtCheck) ) { return true; } } return false; } }