Autocrafting Improvement (#655)

This commit is contained in:
slprime authored and GitHub committed 2025-06-27 08:32:54 -05:00
1 parent e23e542aac
commit 77fa3bafd6
10 files changed
+332 -189

No files matched your search

@@ -746,8 +746,7 @@ 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_all", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH);
API.addHashBind("gui.craft_missing", Keyboard.KEY_C + NEIClientUtils.SHIFT_HASH + NEIKeyboardUtils.CTRL_HASH);
API.addKeyBind("gui.craft_items", Keyboard.KEY_C);
API.addHashBind("gui.hide_bookmarks", Keyboard.KEY_B);
API.addKeyBind("gui.getprevioussearch", Keyboard.KEY_UP);
API.addKeyBind("gui.getnextsearch", Keyboard.KEY_DOWN);
@@ -199,17 +199,25 @@ public class NEIServerUtils {
if (NEIServerUtils.areStacksSameTypeCrafting(stack2, stack1)) {
if (NBTHelper.matchTag(stack1.getTagCompound(), stack2.getTagCompound())) return true;
return (isItemTool(stack1) || stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1)
if (isItemTool(stack1)
&& (stack1.stackTagCompound == null || stack1.stackTagCompound.hasKey("GT.ToolStats"))
&& (stack2.stackTagCompound == null || stack2.stackTagCompound.hasKey("GT.ToolStats")))
return true;
return stack1.getMaxStackSize() == 1 && stack2.getMaxStackSize() == 1
&& (stack1.stackTagCompound == null ^ stack2.stackTagCompound == null);
}
return false;
}
/**
* 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
*
* @param ItemStack stack
* @return
*/
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());
}
@@ -66,24 +66,20 @@ public abstract class ShortcutInputHandler {
return ItemPanels.bookmarkPanel.pullBookmarkItems(groupId, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled()
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()
&& ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
final boolean ignoreInventory = NEIClientConfig.isKeyHashDown("gui.craft_all");
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
if (ignoreInventory || NEIClientConfig.isKeyHashDown("gui.craft_missing")) {
final RecipeChainMath math = ItemPanels.bookmarkPanel.getGrid().createRecipeChainMath(groupId);
if (math != null) {
if (math != null) {
if (ignoreInventory) {
autocraftingIgnoreInventory(math);
}
AutoCraftingManager.runProcessing(math);
return true;
if (!NEIClientUtils.controlKey()) {
autocraftingIgnoreInventory(math);
}
}
AutoCraftingManager.runProcessing(math);
return true;
}
}
}
@@ -121,12 +117,9 @@ public abstract class ShortcutInputHandler {
return pullRecipeItems(stackover, NEIClientUtils.shiftKey());
}
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_missing")) {
return runAutoCrafting(stackover, false);
}
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_all")) {
return runAutoCrafting(stackover, true);
if (NEIClientConfig.autocraftingEnabled() && NEIClientConfig.isKeyHashDown("gui.craft_items")
&& NEIClientUtils.shiftKey()) {
return runAutoCrafting(stackover, !NEIClientUtils.controlKey());
}
return false;
@@ -358,10 +351,11 @@ public abstract class ShortcutInputHandler {
if (NEIClientConfig.autocraftingEnabled() && ItemPanels.bookmarkPanel.getGrid().isCraftingMode(groupId)) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_missing"),
NEIClientConfig
.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("bookmark.group.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_all"),
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("bookmark.group.craft_all"));
}
}
@@ -459,10 +453,12 @@ public abstract class ShortcutInputHandler {
if (NEIClientConfig.autocraftingEnabled()) {
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_missing"),
NEIClientConfig.getKeyName(
"gui.craft_items",
NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH),
NEIClientUtils.translate("itempanel.craft_missing"));
hotkeys.put(
NEIClientConfig.getKeyName("gui.craft_all"),
NEIClientConfig.getKeyName("gui.craft_items", NEIClientUtils.SHIFT_HASH),
NEIClientUtils.translate("itempanel.craft_all"));
}
}
@@ -132,6 +132,7 @@ public class BookmarkItem {
for (Map.Entry<ItemStack, String> entry : BookmarkItem.fuzzyPermutations.entrySet()) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, entry.getKey())) {
BookmarkItem.fuzzyPermutations.put(stack, entry.getValue());
return entry.getValue();
}
}
@@ -142,9 +142,7 @@ public class RecipeChainDetails {
if (collapsedRecipes.isEmpty()) {
for (BookmarkItem item : math.recipeResults) {
if (sortingChainItems.containsKey(item)) {
generateResult(math, item, sortingChainItems.get(item));
}
generateResult(math, item, sortingChainItems.get(item));
}
for (BookmarkItem item : math.recipeIngredients) {
@@ -6,9 +6,11 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
@@ -33,6 +35,7 @@ public class DefaultOverlayHandler implements IOverlayHandler {
public int distributed;
public int numSlots;
public int recipeAmount;
public boolean isContainerItem = false;
}
public static class IngredientDistribution {
@@ -137,67 +140,103 @@ public class DefaultOverlayHandler implements IOverlayHandler {
}
}
return true;
return dropOffMouseStack(thePlayer, gui);
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int multiplier) {
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0) continue;
final EntityClientPlayerMP thePlayer = NEIClientUtils.mc().thePlayer;
ItemStack pstack = distrib.permutation;
int transferCap = multiplier * pstack.stackSize;
int transferred = 0;
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot instanceof SlotCrafting || !slot.getHasStack()
|| !canMoveFrom(slot, gui)
|| !slot.canTakeStack(thePlayer))
continue;
ItemStack stack = slot.getStack();
int slotTransferCap = stack.getMaxStackSize();
int destSlotIndex = 0;
Slot dest = distrib.slots[0];
int slotTransferred = 0;
int slotTransferCap = pstack.getMaxStackSize();
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0 || !slot.getHasStack() || !canStack(distrib.permutation, stack)) continue;
int transferCap = Math.min(slotTransferCap, multiplier * distrib.permutation.stackSize);
int stackSize = slot.getStack().stackSize;
boolean pickup = false;
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (!slot.getHasStack() || !canMoveFrom(slot, gui)) continue;
for (Slot dest : distrib.slots) {
int amount = Math
.min(transferCap - (dest.getHasStack() ? dest.getStack().stackSize : 0), stackSize);
ItemStack stack = slot.getStack();
if (!canStack(pstack, stack)) continue;
if (stackSize <= amount) {
int amount = Math.min(transferCap - transferred, stack.stackSize);
FastTransferManager.clickSlot(gui, slot.slotNumber);
for (int c = 0; c < amount; c++) {
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
transferred++;
slotTransferred++;
if (slotTransferred >= slotTransferCap) {
destSlotIndex++;
if (destSlotIndex == distrib.slots.length) {
dest = null;
break;
if (!pickup) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
FastTransferManager.clickSlot(gui, dest.slotNumber);
break;
} else {
for (int c = 0; c < amount; c++) {
if (pickup != (pickup = true)) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
stackSize--;
}
dest = distrib.slots[destSlotIndex];
slotTransferred = 0;
}
}
FastTransferManager.clickSlot(gui, slot.slotNumber);
if (transferred >= transferCap || dest == null) break;
if (thePlayer.inventory.getItemStack() != null) {
FastTransferManager.clickSlot(gui, slot.slotNumber);
}
}
}
}
protected boolean dropOffMouseStack(EntityPlayer entityPlayer, GuiContainer gui) {
if (entityPlayer.inventory.getItemStack() == null) {
return true;
}
for (int i = 0; i < gui.inventorySlots.inventorySlots.size(); i++) {
Slot slot = gui.inventorySlots.inventorySlots.get(i);
if (slot.inventory == entityPlayer.inventory) {
ItemStack mouseItem = entityPlayer.inventory.getItemStack();
ItemStack slotStack = slot.getStack();
if (slotStack == null || NEIClientUtils.areStacksSameType(mouseItem, slotStack)) {
FastTransferManager.clickSlot(gui, i, 0, 0);
}
if (entityPlayer.inventory.getItemStack() == null) {
return true;
}
}
}
return entityPlayer.inventory.getItemStack() == null;
}
private int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
int quantity = Integer.MAX_VALUE;
for (IngredientDistribution distrib : assignedIngredients) {
DistributedIngred istack = distrib.distrib;
final DistributedIngred istack = distrib.distrib;
if (istack.numSlots == 0) return 0;
final int maxStackSize = istack.stack.getMaxStackSize();
int allSlots = istack.invAmount;
if (allSlots / istack.numSlots > maxStackSize) allSlots = istack.numSlots * maxStackSize;
final int newQuantity = allSlots / istack.distributed;
if (maxStackSize == 1) {
if (maxStackSize == 1 && istack.isContainerItem) {
// If non-stackable, fill up as much as possible of the other ingredients
continue;
}
quantity = Math.min(quantity, newQuantity);
final int allSlots = Math.min(istack.invAmount, istack.numSlots * maxStackSize);
quantity = Math.min(quantity, allSlots / istack.distributed);
}
if (quantity == Integer.MAX_VALUE) {
@@ -292,9 +331,20 @@ public class DefaultOverlayHandler implements IOverlayHandler {
private void findInventoryQuantities(GuiContainer gui, List<DistributedIngred> ingredStacks) {
for (Slot slot : gui.inventorySlots.inventorySlots) /* work out how much we have to go round */ {
if (slot.getHasStack() && canMoveFrom(slot, gui)) {
ItemStack pstack = slot.getStack();
DistributedIngred istack = findIngred(ingredStacks, pstack);
if (istack != null) istack.invAmount += pstack.stackSize;
final ItemStack pstack = slot.getStack();
final DistributedIngred istack = findIngred(ingredStacks, pstack);
if (istack != null) {
istack.invAmount += pstack.stackSize;
if (!istack.isContainerItem && pstack.getMaxStackSize() == 1
&& pstack.getItem().hasContainerItem(pstack)) {
final Optional<ItemStack> containerItem = StackInfo.getContainerItem(pstack);
if (containerItem != null && containerItem.isPresent()) {
istack.isContainerItem = pstack.getItem() == containerItem.get().getItem();
}
}
}
}
}
}
@@ -14,6 +14,7 @@ import codechicken.nei.recipe.Recipe.RecipeId;
public class RecipeHandlerRef {
private static final LRUCache<Class<?>, Boolean> transferAlghoritmCache = new LRUCache<>(200);
private static final LRUCache<RecipeId, RecipeHandlerRef> recipeRefCache = new LRUCache<>(200);
public final IRecipeHandler handler;
public final int recipeIndex;
@@ -139,20 +140,36 @@ public class RecipeHandlerRef {
public boolean allowedTransferAlghoritm(GuiContainer gui) {
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
if (overlayHandler != null) {
try {
return !overlayHandler.getClass()
.getDeclaredMethod(
"transferRecipe",
GuiContainer.class,
IRecipeHandler.class,
int.class,
int.class)
.isDefault();
} catch (NoSuchMethodException e) {}
if (overlayHandler == null) {
return false;
}
return false;
return transferAlghoritmCache.computeIfAbsent(overlayHandler.getClass(), clazz -> {
try {
if (overlayHandler instanceof DefaultOverlayHandler) {
final Class<?> overlayRecipeClazz = overlayHandler.getClass()
.getMethod(
"overlayRecipe",
GuiContainer.class,
IRecipeHandler.class,
int.class,
boolean.class)
.getDeclaringClass();
if (overlayRecipeClazz.equals(DefaultOverlayHandler.class)) {
return true;
}
}
return !overlayHandler.getClass()
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class)
.isDefault();
} catch (NoSuchMethodException e) {}
return false;
});
}
public IRecipeOverlayRenderer getRecipeOverlayRenderer(GuiContainer gui) {
@@ -10,10 +10,10 @@ 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;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.recipe.Recipe;
import codechicken.nei.recipe.Recipe.RecipeId;
@@ -34,7 +34,8 @@ public class RecipeChainMath {
public final Map<BookmarkItem, BookmarkItem> preferredItems = new HashMap<>();
public final Map<BookmarkItem, Long> requiredAmount = new HashMap<>();
public final Map<BookmarkItem, ItemStack> requiredContainerItem = new HashMap<>();
public final List<ItemStack> containerItems = new ArrayList<>();
private final List<ItemStack> containerItemsBlacklist = new ArrayList<>();
private RecipeChainMath(List<BookmarkItem> recipeItems, Set<RecipeId> collapsedRecipes) {
final Map<RecipeId, Integer> recipeState = new HashMap<>();
@@ -51,17 +52,7 @@ public class RecipeChainMath {
if (recipeState.getOrDefault(item.recipeId, 0) != 3) {
this.initialItems.add(item.copy());
} else if (item.isIngredient) {
final Optional<ItemStack> 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(
@@ -165,8 +156,7 @@ public class RecipeChainMath {
final List<BookmarkItem> rootIngredients = new ArrayList<>();
for (BookmarkItem item : this.recipeResults) {
if (item.groupId != -2 && this.outputRecipes.containsKey(item.recipeId)
&& !ROOT_RECIPE_ID.equals(item.recipeId)) {
if (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(
@@ -260,23 +250,36 @@ public class RecipeChainMath {
this.preferredItems.clear();
this.requiredAmount.clear();
this.requiredContainerItem.clear();
this.containerItems.clear();
this.containerItemsBlacklist.clear();
for (RecipeId recipeId : this.outputRecipes.keySet()) {
collectPreferredItems(recipeId, this.preferredItems, new HashSet<>());
}
}
public RecipeChainMath refresh() {
resetCalculation();
if (this.outputRecipes.containsKey(ROOT_RECIPE_ID)) {
for (BookmarkItem ingrItem : this.recipeIngredients) {
if (ROOT_RECIPE_ID.equals(ingrItem.recipeId)
&& ingrItem.itemStack.getItem().hasContainerItem(ingrItem.itemStack)) {
this.containerItemsBlacklist.add(ingrItem.itemStack);
}
}
}
for (BookmarkItem prefItem : this.recipeResults) {
if (prefItem.factor > 0 && this.outputRecipes.containsKey(prefItem.recipeId)) {
final long prefAmount = prefItem.factor * this.outputRecipes.get(prefItem.recipeId);
if (prefItem.itemStack.getItem().hasContainerItem(prefItem.itemStack)) {
this.containerItemsBlacklist.add(prefItem.itemStack);
}
this.preferredItems.put(prefItem, prefItem);
calculateSuitableRecipe(prefItem, prepareAmount(prefItem, prefAmount), new ArrayList<>());
calculateSuitableRecipe(prefItem, prefAmount, new ArrayList<>());
this.preferredItems.remove(prefItem);
}
}
@@ -295,7 +298,7 @@ public class RecipeChainMath {
private void prepareIngredients(RecipeId recipeId, long stepShift, List<RecipeId> visited) {
for (BookmarkItem item : this.recipeIngredients) {
if (item.factor > 0 && recipeId.equals(item.recipeId)) {
calculateSuitableRecipe(item, prepareAmount(item, item.factor * stepShift), visited);
calculateSuitableRecipe(item, item.factor * stepShift, visited);
}
}
}
@@ -303,18 +306,41 @@ public class RecipeChainMath {
private void calculateSuitableRecipe(BookmarkItem ingrItem, long ingrAmount, List<RecipeId> visited) {
final BookmarkItem prefItem = this.preferredItems.get(ingrItem);
// calculate existing containers
if (ingrAmount > 0) {
for (ItemStack stack : ingrItem.permutations.values()) {
if (hasContainerItem(stack)) {
final long stackSize = ingrItem.getStackSize(ingrAmount);
final long shiftSize = shiftContainerItems(stack, stackSize);
if (stackSize != shiftSize && (ingrAmount = shiftSize * ingrItem.fluidCellAmount) == 0) {
break;
}
}
}
}
// calculate existing initial items
if (ingrAmount > 0) {
for (BookmarkItem item : this.initialItems) {
if (item.containsItems(ingrItem)
&& (ingrAmount = addRequiredAmount(item, ingrAmount, item.amount)) == 0) {
break;
}
}
}
// shift amount
if (prefItem == null) {
addRequiredAmount(ingrItem, ingrAmount);
addRequiredAmount(ingrItem, ingrAmount, Long.MAX_VALUE);
} else if (visited.contains(prefItem.recipeId)) {
addRequiredAmount(prefItem, ingrAmount);
addRequiredAmount(prefItem, ingrAmount, Long.MAX_VALUE);
} else {
addRequiredAmount(prefItem, ingrAmount);
addRequiredAmount(prefItem, ingrAmount, Long.MAX_VALUE);
final long shift = (long) Math
.ceil((this.requiredAmount.get(prefItem) - prefItem.amount) / (double) prefItem.factor);
if (shift > 0) {
addShift(prefItem.recipeId, shift);
visited.add(prefItem.recipeId);
prepareIngredients(prefItem.recipeId, shift, visited);
visited.remove(prefItem.recipeId);
@@ -323,79 +349,85 @@ public class RecipeChainMath {
}
private void addRequiredAmount(BookmarkItem prefItem, long ingrAmount) {
long amount = this.requiredAmount.getOrDefault(prefItem, 0L);
private long addRequiredAmount(BookmarkItem prefItem, long ingrAmount, long maxAmount) {
long shiftAmount = this.requiredAmount.getOrDefault(prefItem, 0L);
if (hasContainerItem(prefItem.itemStack)) {
ItemStack itemStack = prefItem.itemStack;
while (ingrAmount > 0 && shiftAmount < maxAmount) {
itemStack = itemStack.copy();
itemStack.stackSize = 1;
this.containerItems.add(itemStack);
ingrAmount = shiftContainerItems(itemStack, prefItem.getStackSize(ingrAmount))
* prefItem.fluidCellAmount;
shiftAmount += prefItem.fluidCellAmount;
}
if (prefItem.itemStack.getItem().hasContainerItem(prefItem.itemStack)) {
amount += calculateContainerItemCount(prefItem, ingrAmount);
} else {
amount += ingrAmount;
long initAmount = Math.min(ingrAmount, maxAmount - shiftAmount);
shiftAmount += initAmount;
ingrAmount -= initAmount;
}
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<ItemStack> 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 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;
}
}
}
this.requiredAmount.put(prefItem, shiftAmount);
return ingrAmount;
}
private long shiftContainerItems(ItemStack aStack, long steps) {
for (int i = 0; i < this.containerItems.size() && steps > 0; i++) {
ItemStack bStack = this.containerItems.get(i);
if (bStack != null && NEIClientUtils.areStacksSameTypeCraftingWithNBT(aStack, bStack)) {
while (bStack != null && steps > 0) {
final Optional<ItemStack> containerItem = StackInfo.getContainerItem(bStack);
steps--;
if (containerItem != null && containerItem.isPresent()) {
bStack = containerItem.get();
if (aStack.getItem() != bStack.getItem()) {
this.containerItems.add(bStack);
bStack = null;
}
} else {
bStack = null;
}
}
this.containerItems.set(i, bStack);
}
}
this.containerItems.removeIf(stack -> stack == null);
return steps;
}
private boolean hasContainerItem(ItemStack aStack) {
if (aStack.getItem().hasContainerItem(aStack)) {
for (ItemStack bStack : this.containerItemsBlacklist) {
if (NEIClientUtils.areStacksSameTypeCraftingWithNBT(aStack, bStack)) {
return false;
}
}
return true;
}
return false;
}
private void addShift(RecipeId recipeId, long shift) {
for (BookmarkItem item : this.recipeIngredients) {
if (recipeId.equals(item.recipeId)) {
@@ -2,10 +2,15 @@ package codechicken.nei.recipe.chain;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
@@ -17,6 +22,7 @@ import codechicken.nei.ItemsTooltipLineHandler;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.bookmark.BookmarkItem;
import codechicken.nei.recipe.Recipe.RecipeId;
import codechicken.nei.recipe.StackInfo;
public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
@@ -25,12 +31,14 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
public final boolean crafting;
protected final RecipeChainMath math;
protected final List<BookmarkItem> initialItems;
protected final Map<RecipeId, Long> outputRecipes;
protected ItemsTooltipLineHandler available;
protected ItemsTooltipLineHandler inputs;
protected ItemsTooltipLineHandler outputs;
protected ItemsTooltipLineHandler remainder;
protected boolean lastShiftKey = false;
protected boolean lastControlKey = false;
protected Dimension size = new Dimension();
@@ -39,6 +47,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
this.crafting = crafting;
this.math = math;
this.initialItems = new ArrayList<>(this.math.initialItems);
this.outputRecipes = new HashMap<>(this.math.outputRecipes);
}
private void onUpdate() {
@@ -47,22 +56,52 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
final List<ItemStack> outputs = new ArrayList<>();
final List<ItemStack> remainder = new ArrayList<>();
final ItemStackAmount inventory = new ItemStackAmount();
final GuiContainer currentGui = NEIClientUtils.getGuiContainer();
final EntityClientPlayerMP thePlayer = currentGui.mc.thePlayer;
if (lastShiftKey) {
inventory.addAll(Arrays.asList(NEIClientUtils.mc().thePlayer.inventory.mainInventory));
if (this.lastShiftKey) {
for (Slot slot : currentGui.inventorySlots.inventorySlots) {
if (slot.getHasStack() && !(slot instanceof SlotCrafting) && slot.canTakeStack(thePlayer)) {
inventory.add(slot.getStack());
}
}
}
if (!this.math.outputRecipes.isEmpty()) {
this.math.initialItems.clear();
this.math.outputRecipes.clear();
this.math.outputRecipes.putAll(this.outputRecipes);
if (lastShiftKey) {
for (ItemStack stack : inventory.values()) {
final long invStackSize = inventory.get(stack);
if (this.lastShiftKey) {
if (invStackSize > 0) {
this.math.initialItems.add(BookmarkItem.of(-1, stack.copy()));
if (!this.lastControlKey) {
final List<ItemStack> items = inventory.values();
for (BookmarkItem item : math.recipeResults) {
if (item.factor > 0 && this.math.outputRecipes.containsKey(item.recipeId)) {
long amount = 0;
for (ItemStack stack : items) {
if (stack != null
&& NEIClientUtils.areStacksSameTypeCraftingWithNBT(stack, item.itemStack)) {
amount += StackInfo.getAmount(stack);
}
}
if (amount >= item.amount) {
final long itemAmount = item.factor * this.math.outputRecipes.get(item.recipeId);
amount += itemAmount - amount % itemAmount;
this.math.outputRecipes.put(
item.recipeId,
Math.max(this.math.outputRecipes.get(item.recipeId), amount / item.factor));
}
}
}
}
for (ItemStack stack : inventory.values()) {
this.math.initialItems.add(BookmarkItem.of(-1, stack.copy()));
}
} else {
this.math.initialItems.addAll(initialItems);
}
@@ -73,7 +112,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
final long amount = math.requiredAmount.getOrDefault(item, 0L);
if (amount > 0) {
if (lastShiftKey) {
if (this.lastShiftKey) {
available.add(item.getItemStack(amount));
} else {
inputs.add(item.getItemStack(amount));
@@ -95,23 +134,23 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
final long amount = item.amount - math.requiredAmount.getOrDefault(item, 0L);
if (amount > 0) {
if (math.outputRecipes.containsKey(item.recipeId) && item.groupId != -2) {
if (math.outputRecipes.containsKey(item.recipeId)) {
outputs.add(item.getItemStack(amount));
} else if (lastShiftKey) {
} else if (this.lastShiftKey) {
remainder.add(item.getItemStack(amount));
}
}
}
if (lastShiftKey) {
for (ItemStack stack : math.requiredContainerItem.values()) {
if (this.lastShiftKey) {
for (ItemStack stack : math.containerItems) {
if (stack != null) {
remainder.add(stack.copy());
}
}
}
} else if (lastShiftKey) {
} else if (this.lastShiftKey) {
for (BookmarkItem item : this.math.initialItems) {
if (inventory.contains(item.itemStack)) {
@@ -143,7 +182,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
.thenComparing(ItemSorter.instance));
this.inputs = new ItemsTooltipLineHandler(
lastShiftKey ? NEIClientUtils.translate("bookmark.crafting_chain.missing")
this.lastShiftKey ? NEIClientUtils.translate("bookmark.crafting_chain.missing")
: NEIClientUtils.translate("bookmark.crafting_chain.input"),
inputs,
true,
@@ -167,7 +206,7 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
true,
Integer.MAX_VALUE);
if (lastShiftKey) {
if (this.lastShiftKey) {
this.inputs.setLabelColor(EnumChatFormatting.RED);
this.available.setLabelColor(EnumChatFormatting.GREEN);
}
@@ -197,7 +236,11 @@ public class RecipeChainTooltipLineHandler implements ITooltipLineHandler {
@Override
public Dimension getSize() {
if (this.lastShiftKey != (this.lastShiftKey = NEIClientUtils.shiftKey()) || this.outputs == null) {
boolean update = this.outputs == null;
update = this.lastShiftKey != (this.lastShiftKey = NEIClientUtils.shiftKey()) || update;
update = this.lastControlKey != (this.lastControlKey = NEIClientUtils.controlKey()) || update;
if (update) {
onUpdate();
}
return this.size;