diff --git a/src/main/java/codechicken/nei/LayoutManager.java b/src/main/java/codechicken/nei/LayoutManager.java index ed284a99..9aae9380 100644 --- a/src/main/java/codechicken/nei/LayoutManager.java +++ b/src/main/java/codechicken/nei/LayoutManager.java @@ -136,10 +136,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH @Override public void onPreDraw(GuiContainer gui) { - if (!isHidden() && isEnabled() && gui instanceof InventoryEffectRenderer) // Reset the gui to the center of the - // screen, for potion effect offsets - // etc - { + // Reset the gui to the center of the screen, for potion effect offsets etc + if (isEnabled() && gui instanceof InventoryEffectRenderer) { gui.guiLeft = (gui.width - gui.xSize) / 2; gui.guiTop = (gui.height - gui.ySize) / 2; diff --git a/src/main/java/codechicken/nei/NEIClientConfig.java b/src/main/java/codechicken/nei/NEIClientConfig.java index 71578151..e7ed989f 100644 --- a/src/main/java/codechicken/nei/NEIClientConfig.java +++ b/src/main/java/codechicken/nei/NEIClientConfig.java @@ -746,7 +746,8 @@ public class NEIClientConfig { API.addHashBind("gui.remove_recipe", Keyboard.KEY_A + NEIClientUtils.SHIFT_HASH); API.addKeyBind("gui.bookmark_pull_items", Keyboard.KEY_V); API.addKeyBind("gui.overlay", Keyboard.KEY_S); - API.addHashBind("gui.craft", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH); + API.addHashBind("gui.craft_all", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH); + API.addHashBind("gui.craft_missing", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH + NEIKeyboardUtils.CTRL_HASH); API.addHashBind("gui.hide_bookmarks", Keyboard.KEY_B); API.addKeyBind("gui.getprevioussearch", Keyboard.KEY_UP); API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN); diff --git a/src/main/java/codechicken/nei/NEIServerUtils.java b/src/main/java/codechicken/nei/NEIServerUtils.java index d6e076c2..adff7e14 100644 --- a/src/main/java/codechicken/nei/NEIServerUtils.java +++ b/src/main/java/codechicken/nei/NEIServerUtils.java @@ -46,9 +46,22 @@ import codechicken.nei.PacketIDs.S2C; import codechicken.nei.util.NBTHelper; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.ReflectionHelper; public class NEIServerUtils { + private static Class gtMetaBaseItem; + + static { + try { + final ClassLoader loader = NEIServerUtils.class.getClassLoader(); + NEIServerUtils.gtMetaBaseItem = ReflectionHelper + .getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item"); + } catch (Exception ignored) { + /* Do nothing */ + } + } + public static boolean isRaining(World world) { return world.getWorldInfo().isRaining(); } @@ -146,7 +159,7 @@ public class NEIServerUtils { /** * NBT-friendly version of {@link #areStacksSameType(ItemStack, ItemStack)} - * + * * @param stack1 The {@link ItemStack} being compared. * @param stack2 The {@link ItemStack} to compare to. * @return whether the two items are the same in terms of itemID, damage and NBT. @@ -177,19 +190,27 @@ public class NEIServerUtils { /** * NBT-friendly version of {@link #areStacksSameTypeCrafting(ItemStack, ItemStack)} - * + * * @param stack1 The {@link ItemStack} being compared. * @param stack2 The {@link ItemStack} to compare to. * @return whether the two items are the same from the perspective of a crafting inventory. */ public static boolean areStacksSameTypeCraftingWithNBT(ItemStack stack1, ItemStack stack2) { - return stack1 != null && stack2 != null - && stack1.getItem() == stack2.getItem() - && (stack1.getItemDamage() == stack2.getItemDamage() - || stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE - || stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE - || stack1.getItem().isDamageable()) - && NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound()); + + if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) { + if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true; + + return (isItemTool(stack1) || stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1) + && (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null); + } + + return false; + } + + public static boolean isItemTool(ItemStack stack) { + // GT Items don't have any NBT set for the recipe, so if either of the stacks has a NULL nbt, and the other + // doesn't, pretend they stack + return NEIServerUtils.gtMetaBaseItem != null && NEIServerUtils.gtMetaBaseItem.isInstance(stack.getItem()); } /** diff --git a/src/main/java/codechicken/nei/api/IStackStringifyHandler.java b/src/main/java/codechicken/nei/api/IStackStringifyHandler.java index 9d73f5bf..6b5e538f 100644 --- a/src/main/java/codechicken/nei/api/IStackStringifyHandler.java +++ b/src/main/java/codechicken/nei/api/IStackStringifyHandler.java @@ -1,14 +1,27 @@ package codechicken.nei.api; +import java.util.Optional; + import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fluids.FluidStack; public interface IStackStringifyHandler { - public NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize); + default NBTTagCompound convertItemStackToNBT(ItemStack stack, boolean saveStackSize) { + return null; + } - public ItemStack convertNBTToItemStack(NBTTagCompound nbtTag); + default ItemStack convertNBTToItemStack(NBTTagCompound nbtTag) { + return null; + } + + default FluidStack getFluid(ItemStack stack) { + return null; + } + + default Optional getContainerItem(ItemStack stack) { + return null; + } - public FluidStack getFluid(ItemStack stack); } diff --git a/src/main/java/codechicken/nei/api/ShortcutInputHandler.java b/src/main/java/codechicken/nei/api/ShortcutInputHandler.java index 6cbd75f6..c030a611 100644 --- a/src/main/java/codechicken/nei/api/ShortcutInputHandler.java +++ b/src/main/java/codechicken/nei/api/ShortcutInputHandler.java @@ -9,6 +9,7 @@ import java.util.Map; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraftforge.oredict.OreDictionary; @@ -65,11 +66,24 @@ public abstract class ShortcutInputHandler { return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey()); } - if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId) - && NEIClientConfig.isKeyHashDown("gui.craft")) { - AutoCraftingManager - .runProcessing(ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId)); - return true; + if (NEIClientConfig.autocraftingEnabled() + && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) { + final boolean ignoreInventory = NEIClientConfig.isKeyHashDown("gui.craft_all"); + + if (ignoreInventory || NEIClientConfig.isKeyHashDown("gui.craft_missing")) { + final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId); + + if (math != null) { + + if (ignoreInventory) { + autocraftingIgnoreInventory(math); + } + + AutoCraftingManager.runProcessing(math); + return true; + } + } + } } @@ -107,8 +121,12 @@ public abstract class ShortcutInputHandler { return pullRecipeItems(stackover, NEIClientUtils.shiftKey()); } - if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft")) { - return runAutoCrafting(stackover); + if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_missing")) { + return runAutoCrafting(stackover, false); + } + + if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_all")) { + return runAutoCrafting(stackover, true); } return false; @@ -156,7 +174,7 @@ public abstract class ShortcutInputHandler { return true; } - private static boolean runAutoCrafting(ItemStack stackover) { + private static boolean runAutoCrafting(ItemStack stackover, boolean ignoreInventory) { final RecipeId recipeId = GuiCraftingRecipe.getRecipeId(NEIClientUtils.getGuiContainer(), stackover); if (recipeId != null) { @@ -184,6 +202,11 @@ public abstract class ShortcutInputHandler { } if (math != null) { + + if (ignoreInventory) { + autocraftingIgnoreInventory(math); + } + AutoCraftingManager.runProcessing(math); return true; } @@ -334,7 +357,12 @@ public abstract class ShortcutInputHandler { } if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) { - hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("bookmark.group.craft")); + hotkeys.put( + NEIClientConfig.getKeyName("gui.craft_missing"), + NEIClientUtils.translate("bookmark.group.craft_missing")); + hotkeys.put( + NEIClientConfig.getKeyName("gui.craft_all"), + NEIClientUtils.translate("bookmark.group.craft_all")); } } @@ -430,7 +458,12 @@ public abstract class ShortcutInputHandler { } if (NEIClientConfig.autocraftingEnabled()) { - hotkeys.put(NEIClientConfig.getKeyName("gui.craft"), NEIClientUtils.translate("itempanel.craft")); + hotkeys.put( + NEIClientConfig.getKeyName("gui.craft_missing"), + NEIClientUtils.translate("itempanel.craft_missing")); + hotkeys.put( + NEIClientConfig.getKeyName("gui.craft_all"), + NEIClientUtils.translate("itempanel.craft_all")); } } @@ -439,6 +472,28 @@ public abstract class ShortcutInputHandler { return hotkeys; } + private static void autocraftingIgnoreInventory(RecipeChainMath math) { + final GuiContainer guiContainer = NEIClientUtils.getGuiContainer(); + final InventoryPlayer playerInventory = guiContainer.mc.thePlayer.inventory; + final RecipeId rootRecipeId = math.createMasterRoot(); + + for (BookmarkItem item : math.recipeIngredients) { + if (item.amount > 0 && rootRecipeId.equals(item.recipeId)) { + long amount = 0; + + for (ItemStack stack : playerInventory.mainInventory) { + if (stack != null && NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, item.itemStack)) { + amount += StackInfo.getAmount(stack); + } + } + + if (amount >= item.amount) { + item.factor = item.amount = amount + item.amount - (amount % item.amount); + } + } + } + } + private static RecipeId getHotkeyRecipeId(GuiContainer gui, int mousex, int mousey, ItemStack stack, BookmarksGridSlot slot) { diff --git a/src/main/java/codechicken/nei/bookmark/BookmarkGrid.java b/src/main/java/codechicken/nei/bookmark/BookmarkGrid.java index 53384f40..dee644b5 100644 --- a/src/main/java/codechicken/nei/bookmark/BookmarkGrid.java +++ b/src/main/java/codechicken/nei/bookmark/BookmarkGrid.java @@ -1024,8 +1024,7 @@ public class BookmarkGrid extends ItemsGrid 0 && bookmarkItem.equalsRecipe(getCalculatedItem(sortedIndexes.get(sortIndex - 1)))) { sortIndex--; } @@ -1055,7 +1054,8 @@ public class BookmarkGrid extends ItemsGrid fuzzyPermutations = new HashMap<>(); + public int groupId; public long amount = 0L; @@ -120,13 +123,23 @@ public class BookmarkItem { return Collections.singletonMap(getItemGUID(stack), stack); } - private static String getItemGUID(ItemStack stack) { + private static synchronized String getItemGUID(ItemStack stack) { final FluidStack fluidStack = StackInfo.getFluid(stack); if (fluidStack != null) { return fluidStack.getFluid().getName() + ":" + fluidStack.tag; } else { - return StackInfo.getItemStackGUID(stack); + + for (Map.Entry entry : BookmarkItem.fuzzyPermutations.entrySet()) { + if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) { + return entry.getValue(); + } + } + + final String stackGUID = StackInfo.getItemStackGUID(stack); + BookmarkItem.fuzzyPermutations.put(stack, stackGUID); + + return stackGUID; } } diff --git a/src/main/java/codechicken/nei/bookmark/RecipeChainDetails.java b/src/main/java/codechicken/nei/bookmark/RecipeChainDetails.java index 445ff145..3bc635f0 100644 --- a/src/main/java/codechicken/nei/bookmark/RecipeChainDetails.java +++ b/src/main/java/codechicken/nei/bookmark/RecipeChainDetails.java @@ -142,7 +142,9 @@ public class RecipeChainDetails { if (collapsedRecipes.isEmpty()) { for (BookmarkItem item : math.recipeResults) { - generateResult(math, item, sortingChainItems.get(item)); + if (sortingChainItems.containsKey(item)) { + generateResult(math, item, sortingChainItems.get(item)); + } } for (BookmarkItem item : math.recipeIngredients) { diff --git a/src/main/java/codechicken/nei/recipe/AutoCraftingManager.java b/src/main/java/codechicken/nei/recipe/AutoCraftingManager.java index 47c0af83..bcefefc5 100644 --- a/src/main/java/codechicken/nei/recipe/AutoCraftingManager.java +++ b/src/main/java/codechicken/nei/recipe/AutoCraftingManager.java @@ -2,14 +2,11 @@ package codechicken.nei.recipe; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.item.ItemStack; import codechicken.nei.ItemStackAmount; import codechicken.nei.NEIClientUtils; @@ -25,16 +22,11 @@ public class AutoCraftingManager { private static final RestartableTask task = new RestartableTask("NEI Bookmark AutoCraft Processing") { - private static final ItemStack ROOT_ITEM = new ItemStack(Blocks.fire); - private static final RecipeId ROOT_RECIPE_ID = RecipeId - .of(ROOT_ITEM, "recipe-autocrafting", Collections.emptyList()); - @Override public void execute() { final GuiContainer guiContainer = NEIClientUtils.getGuiContainer(); final InventoryPlayer playerInventory = guiContainer.mc.thePlayer.inventory; final ItemStackAmount inventory = ItemStackAmount.of(Arrays.asList(playerInventory.mainInventory)); - final RecipeChainMath math = createMasterRoot(AutoCraftingManager.math); final List initialItems = prepareInitialItems(math, inventory); boolean processed = false; boolean changed = false; @@ -91,31 +83,6 @@ public class AutoCraftingManager { return interrupted() || guiContainer != NEIClientUtils.getGuiContainer(); } - private RecipeChainMath createMasterRoot(RecipeChainMath math) { - final List rootIngredients = new ArrayList<>(); - - for (BookmarkItem item : math.recipeResults) { - if (math.outputRecipes.containsKey(item.recipeId)) { - long amount = item.factor * math.outputRecipes.get(item.recipeId); - rootIngredients.add( - BookmarkItem.of( - -1, - item.getItemStack(amount), - item.getStackSize(amount), - ROOT_RECIPE_ID, - true, - BookmarkItem.generatePermutations(item.itemStack, null))); - } - } - - math.outputRecipes.clear(); - math.outputRecipes.put(ROOT_RECIPE_ID, 1L); - math.recipeResults.add(BookmarkItem.of(-1, ROOT_ITEM, 1, ROOT_RECIPE_ID, false)); - math.recipeIngredients.addAll(rootIngredients); - - return math; - } - private List prepareInitialItems(RecipeChainMath math, ItemStackAmount inventory) { final List initialItems = new ArrayList<>(); @@ -139,6 +106,7 @@ public class AutoCraftingManager { AutoCraftingManager.math = math; if (AutoCraftingManager.math != null) { + math.createMasterRoot(); task.restart(); } } diff --git a/src/main/java/codechicken/nei/recipe/DefaultOverlayHandler.java b/src/main/java/codechicken/nei/recipe/DefaultOverlayHandler.java index edaa98e1..9e45b390 100644 --- a/src/main/java/codechicken/nei/recipe/DefaultOverlayHandler.java +++ b/src/main/java/codechicken/nei/recipe/DefaultOverlayHandler.java @@ -17,26 +17,11 @@ import net.minecraft.item.ItemStack; import codechicken.lib.inventory.InventoryUtils; import codechicken.nei.FastTransferManager; import codechicken.nei.NEIClientUtils; -import codechicken.nei.NEIServerUtils; import codechicken.nei.PositionedStack; import codechicken.nei.api.IOverlayHandler; -import codechicken.nei.util.NBTHelper; -import cpw.mods.fml.relauncher.ReflectionHelper; public class DefaultOverlayHandler implements IOverlayHandler { - private static Class gtItem; - - static { - try { - final ClassLoader loader = DefaultOverlayHandler.class.getClassLoader(); - gtItem = ReflectionHelper - .getClass(loader, "gregtech.api.items.MetaBaseItem", "gregtech.api.items.GT_MetaBase_Item"); - } catch (Exception ignored) { - /* Do nothing */ - } - } - public static class DistributedIngred { public DistributedIngred(ItemStack item) { @@ -353,16 +338,6 @@ public class DefaultOverlayHandler implements IOverlayHandler { protected boolean canStack(ItemStack stack1, ItemStack stack2) { if (stack1 == null || stack2 == null) return true; - if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) { - if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true; - - // GT Items don't have any NBT set for the recipe, so if either of the stacks has a NULL nbt, and the other - // doesn't, pretend they stack - if (((gtItem != null && gtItem.isInstance(stack1.getItem())) - || (stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1)) - && (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null)) - return true; - } - return false; + return NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack1, stack2); } } diff --git a/src/main/java/codechicken/nei/recipe/StackInfo.java b/src/main/java/codechicken/nei/recipe/StackInfo.java index aed47ee1..4ed24bca 100644 --- a/src/main/java/codechicken/nei/recipe/StackInfo.java +++ b/src/main/java/codechicken/nei/recipe/StackInfo.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; @@ -73,6 +74,16 @@ public class StackInfo { return stack; } + public static Optional getContainerItem(ItemStack stack) { + Optional result = null; + + for (int i = stackStringifyHandlers.size() - 1; i >= 0 && result == null; i--) { + result = stackStringifyHandlers.get(i).getContainerItem(stack); + } + + return result; + } + public static ItemStack withAmount(ItemStack stack, long customCount) { if (stack == null) return null; final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack); diff --git a/src/main/java/codechicken/nei/recipe/chain/RecipeChainMath.java b/src/main/java/codechicken/nei/recipe/chain/RecipeChainMath.java index aec1fb81..6ba1eff1 100644 --- a/src/main/java/codechicken/nei/recipe/chain/RecipeChainMath.java +++ b/src/main/java/codechicken/nei/recipe/chain/RecipeChainMath.java @@ -6,8 +6,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import codechicken.nei.ItemStackAmount; @@ -19,6 +22,10 @@ import codechicken.nei.recipe.StackInfo; public class RecipeChainMath { + private static final ItemStack ROOT_ITEM = new ItemStack(Blocks.fire); + private static final RecipeId ROOT_RECIPE_ID = RecipeId + .of(ROOT_ITEM, "recipe-autocrafting", Collections.emptyList()); + public final Map outputRecipes = new HashMap<>(); public final List initialItems = new ArrayList<>(); @@ -27,6 +34,7 @@ public class RecipeChainMath { public final Map preferredItems = new HashMap<>(); public final Map requiredAmount = new HashMap<>(); + public final Map requiredContainerItem = new HashMap<>(); private RecipeChainMath(List recipeItems, Set collapsedRecipes) { final Map recipeState = new HashMap<>(); @@ -43,7 +51,17 @@ public class RecipeChainMath { if (recipeState.getOrDefault(item.recipeId, 0) != 3) { this.initialItems.add(item.copy()); } else if (item.isIngredient) { + final Optional containerItem = StackInfo.getContainerItem(item.getItemStack(1)); this.recipeIngredients.add(item.copyWithAmount(0)); + + if (containerItem != null && containerItem.isPresent()) { + final ItemStack stack = containerItem.get(); + + if (Item.getIdFromItem(item.itemStack.getItem()) != Item.getIdFromItem(stack.getItem())) { + this.recipeResults.add(BookmarkItem.of(-2, stack, 1, item.recipeId, false).copyWithAmount(0)); + } + } + } else { this.recipeResults.add(item.copyWithAmount(0)); multipliers.put( @@ -70,7 +88,8 @@ public class RecipeChainMath { if (!this.outputRecipes.containsKey(recipeId) && this.preferredItems.values().stream() .noneMatch(resItem -> resItem.recipeId.equals(recipeId))) { final Map references = new HashMap<>(this.preferredItems); - final int depth = collectPreferredItems(recipeId, references, new HashSet<>()); + collectPreferredItems(recipeId, references, new HashSet<>()); + final int depth = getMaxDepth(recipeId, references); if (maxDepth < depth || maxDepth == depth && entry.getValue() > maxMultiplier) { maxMultiplier = entry.getValue(); @@ -104,9 +123,9 @@ public class RecipeChainMath { } } - private int collectPreferredItems(RecipeId recipeId, Map preferredItems, + private void collectPreferredItems(RecipeId recipeId, Map preferredItems, Set visited) { - int maxDepth = 0; + visited.add(recipeId); for (BookmarkItem ingrItem : this.recipeIngredients) { @@ -122,16 +141,57 @@ public class RecipeChainMath { if (prefItem != null) { preferredItems.put(ingrItem, prefItem); - maxDepth = Math - .max(maxDepth, collectPreferredItems(prefItem.recipeId, preferredItems, visited) + 1); + collectPreferredItems(prefItem.recipeId, preferredItems, visited); } } } visited.remove(recipeId); + } + + private int getMaxDepth(RecipeId recipeId, Map preferredItems) { + int maxDepth = 0; + + for (BookmarkItem ingrItem : this.recipeIngredients) { + if (ingrItem.factor > 0 && recipeId.equals(ingrItem.recipeId) && preferredItems.containsKey(ingrItem)) { + maxDepth = Math.max(maxDepth, getMaxDepth(preferredItems.get(ingrItem).recipeId, preferredItems) + 1); + } + } + return maxDepth; } + public RecipeId createMasterRoot() { + final List rootIngredients = new ArrayList<>(); + + for (BookmarkItem item : this.recipeResults) { + if (item.groupId != -2 && this.outputRecipes.containsKey(item.recipeId) + && !ROOT_RECIPE_ID.equals(item.recipeId)) { + final long amount = item.factor * this.outputRecipes.get(item.recipeId); + rootIngredients.add( + BookmarkItem.of( + -1, + item.getItemStack(amount), + item.getStackSize(amount), + ROOT_RECIPE_ID, + true, + BookmarkItem.generatePermutations(item.itemStack, null))); + } + } + + this.outputRecipes.clear(); + this.outputRecipes.put(ROOT_RECIPE_ID, 1L); + this.recipeResults.removeIf(item -> ROOT_RECIPE_ID.equals(item.recipeId)); + this.recipeResults.add(BookmarkItem.of(-1, ROOT_ITEM, 1, ROOT_RECIPE_ID, false)); + this.recipeIngredients.addAll(rootIngredients); + + return ROOT_RECIPE_ID; + } + + public boolean hasMasterRoot() { + return this.outputRecipes.containsKey(ROOT_RECIPE_ID); + } + public static RecipeChainMath of(List chainItems, Set collapsedRecipes) { return new RecipeChainMath(chainItems, collapsedRecipes); } @@ -200,6 +260,7 @@ public class RecipeChainMath { this.preferredItems.clear(); this.requiredAmount.clear(); + this.requiredContainerItem.clear(); for (RecipeId recipeId : this.outputRecipes.keySet()) { collectPreferredItems(recipeId, this.preferredItems, new HashSet<>()); @@ -243,11 +304,11 @@ public class RecipeChainMath { final BookmarkItem prefItem = this.preferredItems.get(ingrItem); if (prefItem == null) { - this.requiredAmount.put(ingrItem, this.requiredAmount.getOrDefault(ingrItem, 0L) + ingrAmount); + addRequiredAmount(ingrItem, ingrAmount); } else if (visited.contains(prefItem.recipeId)) { - this.requiredAmount.put(prefItem, this.requiredAmount.getOrDefault(prefItem, 0L) + ingrAmount); + addRequiredAmount(prefItem, ingrAmount); } else { - this.requiredAmount.put(prefItem, this.requiredAmount.getOrDefault(prefItem, 0L) + ingrAmount); + addRequiredAmount(prefItem, ingrAmount); final long shift = (long) Math .ceil((this.requiredAmount.get(prefItem) - prefItem.amount) / (double) prefItem.factor); @@ -262,15 +323,71 @@ public class RecipeChainMath { } + private void addRequiredAmount(BookmarkItem prefItem, long ingrAmount) { + long amount = this.requiredAmount.getOrDefault(prefItem, 0L); + + if (prefItem.itemStack.getItem().hasContainerItem(prefItem.itemStack)) { + amount += calculateContainerItemCount(prefItem, ingrAmount); + } else { + amount += ingrAmount; + } + + this.requiredAmount.put(prefItem, amount); + } + + private long calculateContainerItemCount(BookmarkItem item, long amount) { + final int itemId = Item.getIdFromItem(item.itemStack.getItem()); + ItemStack aStack = this.requiredContainerItem.get(item); + long result = 0; + + for (int i = 0; i < amount; i++) { + + if (aStack == null) { + aStack = item.getItemStack(1); + result++; + } + + final Optional containerItem = StackInfo.getContainerItem(aStack); + + if (containerItem != null && containerItem.isPresent()) { + aStack = containerItem.get(); + + if (itemId != Item.getIdFromItem(aStack.getItem())) { + aStack = null; + } + } else { + aStack = null; + } + + } + + this.requiredContainerItem.put(item, aStack); + + return result; + } + private long prepareAmount(BookmarkItem ingrItem, long ingrAmount) { if (ingrAmount == 0) return 0; for (BookmarkItem item : this.initialItems) { if (item.containsItems(ingrItem)) { - long initAmount = Math.min(ingrAmount, item.amount - this.requiredAmount.getOrDefault(item, 0L)); + long amount = this.requiredAmount.getOrDefault(item, 0L); + + if (item.itemStack.getItem().hasContainerItem(item.itemStack) + && ((item.amount - amount) > 0 || this.requiredContainerItem.get(item) != null)) { + ingrAmount = calculateContainerItemCount(item, ingrAmount); + } + + long initAmount = Math.min(ingrAmount, item.amount - amount); + if (initAmount > 0) { this.requiredAmount.put(item, this.requiredAmount.getOrDefault(item, 0L) + initAmount); ingrAmount -= initAmount; + + if ((item.amount - amount - initAmount) < 0) { + this.requiredContainerItem.put(item, null); + } + if (ingrAmount == 0) break; } } diff --git a/src/main/java/codechicken/nei/recipe/chain/RecipeChainTooltipLineHandler.java b/src/main/java/codechicken/nei/recipe/chain/RecipeChainTooltipLineHandler.java index cb27e261..377bd8ad 100644 --- a/src/main/java/codechicken/nei/recipe/chain/RecipeChainTooltipLineHandler.java +++ b/src/main/java/codechicken/nei/recipe/chain/RecipeChainTooltipLineHandler.java @@ -95,7 +95,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler { final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L); if (amount > 0) { - if (math.outputRecipes.containsKey(item.recipeId)) { + if (math.outputRecipes.containsKey(item.recipeId) && item.groupId != -2) { outputs.add(item.getItemStack(amount)); } else if (lastShiftKey) { remainder.add(item.getItemStack(amount)); @@ -103,6 +103,14 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler { } } + if (lastShiftKey) { + for (ItemStack stack : math.requiredContainerItem.values()) { + if (stack != null) { + remainder.add(stack.copy()); + } + } + } + } else if (lastShiftKey) { for (BookmarkItem item : this.math.initialItems) { diff --git a/src/main/java/codechicken/nei/recipe/stackinfo/DefaultStackStringifyHandler.java b/src/main/java/codechicken/nei/recipe/stackinfo/DefaultStackStringifyHandler.java index 049f1f3f..0383f166 100644 --- a/src/main/java/codechicken/nei/recipe/stackinfo/DefaultStackStringifyHandler.java +++ b/src/main/java/codechicken/nei/recipe/stackinfo/DefaultStackStringifyHandler.java @@ -1,5 +1,7 @@ package codechicken.nei.recipe.stackinfo; +import java.util.Optional; + import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -55,4 +57,15 @@ public class DefaultStackStringifyHandler implements IStackStringifyHandler { return fluidStack; } + + @Override + public Optional getContainerItem(ItemStack stack) { + + if (stack.getItem().hasContainerItem(stack)) { + return Optional.ofNullable(stack.getItem().getContainerItem(stack)); + } + + return null; + } + } diff --git a/src/main/java/codechicken/nei/recipe/stackinfo/GTFluidStackStringifyHandler.java b/src/main/java/codechicken/nei/recipe/stackinfo/GTFluidStackStringifyHandler.java index 491de8c3..47637494 100644 --- a/src/main/java/codechicken/nei/recipe/stackinfo/GTFluidStackStringifyHandler.java +++ b/src/main/java/codechicken/nei/recipe/stackinfo/GTFluidStackStringifyHandler.java @@ -1,6 +1,7 @@ package codechicken.nei.recipe.stackinfo; import java.lang.reflect.Method; +import java.util.Optional; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -19,6 +20,8 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler { protected static Method getFluidDisplayStack = null; protected static Method getFluidFromDisplayStack = null; public static boolean replaceAE2FCFluidDrop = false; + private static Class gtMetaGeneratedTool = null; + private static Method getContainerItem = null; static { try { @@ -32,6 +35,11 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler { "gregtech.common.items.GT_FluidDisplayItem"); getFluidFromDisplayStack = gtUtility.getMethod("getFluidFromDisplayStack", ItemStack.class); getFluidDisplayStack = gtUtility.getMethod("getFluidDisplayStack", FluidStack.class, boolean.class); + + gtMetaGeneratedTool = ReflectionHelper.getClass(loader, "gregtech.api.items.MetaGeneratedTool"); + getContainerItem = gtMetaGeneratedTool + .getDeclaredMethod("getContainerItem", ItemStack.class, boolean.class, boolean.class); + getContainerItem.setAccessible(true); } catch (Exception ignored) { /* Do nothing */ } @@ -104,4 +112,17 @@ public class GTFluidStackStringifyHandler implements IStackStringifyHandler { return null; } + + @Override + public Optional getContainerItem(ItemStack stack) { + + if (getContainerItem != null && gtMetaGeneratedTool.isInstance(stack.getItem()) + && stack.getItem().hasContainerItem(stack)) { + try { + return Optional.ofNullable((ItemStack) getContainerItem.invoke(stack.getItem(), stack, false, true)); + } catch (Exception ex) {} + } + + return null; + } } diff --git a/src/main/resources/assets/nei/lang/en_US.lang b/src/main/resources/assets/nei/lang/en_US.lang index bc672e67..055791fd 100644 --- a/src/main/resources/assets/nei/lang/en_US.lang +++ b/src/main/resources/assets/nei/lang/en_US.lang @@ -30,7 +30,8 @@ nei.bookmark.group.sorting=Move Position nei.bookmark.group.remove_recipe=Remove Group nei.bookmark.group.pull_items=Pull all Items nei.bookmark.group.pull_items_shift=Pull missing Items -nei.bookmark.group.craft=Craft Group +nei.bookmark.group.craft_missing=Craft Missing Items +nei.bookmark.group.craft_all=Craft Items nei.bookmark.item.sorting=Move Position nei.bookmark.remove_recipe=Remove Recipe nei.bookmark.remove_item=Remove Item @@ -54,7 +55,8 @@ nei.itempanel.collapsed.button.tip=Collapse/Expand All Collapsible Items nei.itempanel.collapsed.hint.expand=Expand Group (%d items) nei.itempanel.collapsed.hint.collapse=Collapse Group (%d items) nei.itempanel.overlay_recipe=Overlay Recipe -nei.itempanel.craft=Craft Recipe +nei.itempanel.craft_missing=Craft Missing Items +nei.itempanel.craft_all=Craft Items nei.itempanel.fill_crafting_grid=Fill Crafting Grid nei.itempanel.fill_crafting_grid_quantity=Fill Crafting Grid With Quantity nei.itempanel.open_crafting=Recipe to make this item @@ -170,7 +172,8 @@ nei.options.keys.gui.getprevioussearch=Previous Search nei.options.keys.gui.getnextsearch=Next Search nei.options.keys.gui.next_tooltip=Next Tooltip nei.options.keys.gui.copy_name=Copy Item Name -nei.options.keys.gui.craft=Craft Recipe +nei.options.keys.gui.craft_missing=Craft Missing Items +nei.options.keys.gui.craft_all=Craft Items nei.options.keys.gui.copy_oredict=Copy Item OreDictionary nei.options.keys.gui.itemzoom_toggle=Toggle Item Zoom nei.options.keys.gui.itemzoom_hold=Hold to Display Item Zoom