Files
NotEnoughItems/src/main/java/codechicken/nei/recipe/DefaultOverlayHandler.java
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

313 lines
12 KiB
Java
Raw Normal View History

2014-04-29 10:54:20 +10:00
package codechicken.nei.recipe;
2019-12-30 20:19:16 -08:00
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
2023-09-25 00:35:24 +02:00
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import codechicken.lib.inventory.InventoryUtils;
import codechicken.nei.FastTransferManager;
import codechicken.nei.PositionedStack;
import codechicken.nei.api.IOverlayHandler;
import cpw.mods.fml.relauncher.ReflectionHelper;
2023-09-25 00:35:24 +02:00
2021-04-10 20:26:01 -07:00
public class DefaultOverlayHandler implements IOverlayHandler {
private static Class<?> gtItem;
2021-04-10 20:26:01 -07:00
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 */
2021-04-10 20:26:01 -07:00
}
}
2021-04-10 20:26:01 -07:00
public static class DistributedIngred {
public DistributedIngred(ItemStack item) {
2014-04-29 10:54:20 +10:00
stack = InventoryUtils.copyStack(item, 1);
}
public ItemStack stack;
2014-04-29 10:54:20 +10:00
public int invAmount;
public int distributed;
public int numSlots;
public int recipeAmount;
}
2021-04-10 20:26:01 -07:00
public static class IngredientDistribution {
2021-04-10 20:26:01 -07:00
public IngredientDistribution(DistributedIngred distrib, ItemStack permutation) {
2014-04-29 10:54:20 +10:00
this.distrib = distrib;
this.permutation = permutation;
}
2014-04-29 10:54:20 +10:00
public DistributedIngred distrib;
public ItemStack permutation;
public Slot[] slots;
}
2021-04-10 20:26:01 -07:00
public DefaultOverlayHandler(int x, int y) {
2014-04-29 10:54:20 +10:00
offsetx = x;
offsety = y;
}
public DefaultOverlayHandler() {
2014-04-29 10:54:20 +10:00
this(5, 11);
}
public int offsetx;
public int offsety;
2014-04-29 10:54:20 +10:00
@Override
2021-04-10 20:26:01 -07:00
public void overlayRecipe(GuiContainer gui, IRecipeHandler recipe, int recipeIndex, boolean shift) {
2014-04-29 10:54:20 +10:00
List<PositionedStack> ingredients = recipe.getIngredientStacks(recipeIndex);
List<DistributedIngred> ingredStacks = getPermutationIngredients(ingredients);
if (!clearIngredients(gui, ingredients)) return;
2014-04-29 10:54:20 +10:00
findInventoryQuantities(gui, ingredStacks);
2014-04-29 10:54:20 +10:00
List<IngredientDistribution> assignedIngredients = assignIngredients(ingredients, ingredStacks);
if (assignedIngredients == null) return;
2014-04-29 10:54:20 +10:00
assignIngredSlots(gui, ingredients, assignedIngredients);
int quantity = calculateRecipeQuantity(assignedIngredients);
if (quantity != 0) moveIngredients(gui, assignedIngredients, quantity);
2014-04-29 10:54:20 +10:00
}
2014-04-29 10:54:20 +10:00
private boolean clearIngredients(GuiContainer gui, List<PositionedStack> ingreds) {
for (PositionedStack pstack : ingreds) {
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.xDisplayPosition == pstack.relx + offsetx && slot.yDisplayPosition == pstack.rely + offsety) {
if (!slot.getHasStack()) continue;
FastTransferManager.clickSlot(gui, slot.slotNumber, 0, 1);
if (slot.getHasStack()) return false;
}
2014-04-29 10:54:20 +10:00
}
}
2014-04-29 10:54:20 +10:00
return true;
}
private void moveIngredients(GuiContainer gui, List<IngredientDistribution> assignedIngredients, int quantity) {
for (IngredientDistribution distrib : assignedIngredients) {
if (distrib.slots.length == 0) continue;
2014-04-29 10:54:20 +10:00
ItemStack pstack = distrib.permutation;
int transferCap = quantity * pstack.stackSize;
2014-04-29 10:54:20 +10:00
int transferred = 0;
2014-04-29 10:54:20 +10:00
int destSlotIndex = 0;
Slot dest = distrib.slots[0];
int slotTransferred = 0;
int slotTransferCap = pstack.getMaxStackSize();
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (!slot.getHasStack() || !canMoveFrom(slot, gui)) continue;
2014-04-29 10:54:20 +10:00
ItemStack stack = slot.getStack();
if (!canStack(stack, pstack)) continue;
int amount = Math.min(transferCap - transferred, stack.stackSize);
FastTransferManager.clickSlot(gui, slot.slotNumber);
for (int c = 0; c < amount; c++) {
2014-04-29 10:54:20 +10:00
FastTransferManager.clickSlot(gui, dest.slotNumber, 1);
transferred++;
slotTransferred++;
if (slotTransferred >= slotTransferCap) {
2014-04-29 10:54:20 +10:00
destSlotIndex++;
if (destSlotIndex == distrib.slots.length) {
2014-04-29 10:54:20 +10:00
dest = null;
break;
}
dest = distrib.slots[destSlotIndex];
slotTransferred = 0;
}
}
FastTransferManager.clickSlot(gui, slot.slotNumber);
if (transferred >= transferCap || dest == null) break;
2014-04-29 10:54:20 +10:00
}
}
2014-04-29 10:54:20 +10:00
}
2021-04-10 20:26:01 -07:00
private int calculateRecipeQuantity(List<IngredientDistribution> assignedIngredients) {
2014-04-29 10:54:20 +10:00
int quantity = Integer.MAX_VALUE;
for (IngredientDistribution distrib : assignedIngredients) {
2014-04-29 10:54:20 +10:00
DistributedIngred istack = distrib.distrib;
if (istack.numSlots == 0) return 0;
final int maxStackSize = istack.stack.getMaxStackSize();
2014-04-29 10:54:20 +10:00
int allSlots = istack.invAmount;
if (allSlots / istack.numSlots > maxStackSize) allSlots = istack.numSlots * maxStackSize;
final int newQuantity = allSlots / istack.distributed;
if (maxStackSize == 1) {
// If non-stackable, fill up as much as possible of the other ingredients
continue;
}
quantity = Math.min(quantity, newQuantity);
}
if (quantity == Integer.MAX_VALUE) {
// Only possible if all ingredients were non-stackable
quantity = 1;
2014-04-29 10:54:20 +10:00
}
2014-04-29 10:54:20 +10:00
return quantity;
}
private Slot[][] assignIngredSlots(GuiContainer gui, List<PositionedStack> ingredients,
List<IngredientDistribution> assignedIngredients) {
Slot[][] recipeSlots = mapIngredSlots(gui, ingredients); // setup the slot map
2019-12-30 20:19:16 -08:00
HashMap<Slot, Integer> distribution = new HashMap<>();
for (Slot[] recipeSlot : recipeSlots)
for (Slot slot : recipeSlot) if (!distribution.containsKey(slot)) distribution.put(slot, -1);
2019-12-30 20:19:16 -08:00
HashSet<Slot> avaliableSlots = new HashSet<>(distribution.keySet());
HashSet<Integer> remainingIngreds = new HashSet<>();
ArrayList<LinkedList<Slot>> assignedSlots = new ArrayList<>();
for (int i = 0; i < ingredients.size(); i++) {
2014-04-29 10:54:20 +10:00
remainingIngreds.add(i);
2019-12-30 20:19:16 -08:00
assignedSlots.add(new LinkedList<>());
2014-04-29 10:54:20 +10:00
}
while (!avaliableSlots.isEmpty() && !remainingIngreds.isEmpty()) {
for (Iterator<Integer> iterator = remainingIngreds.iterator(); iterator.hasNext();) {
2014-04-29 10:54:20 +10:00
int i = iterator.next();
boolean assigned = false;
DistributedIngred istack = assignedIngredients.get(i).distrib;
for (Slot slot : recipeSlots[i]) {
if (avaliableSlots.contains(slot)) {
2014-04-29 10:54:20 +10:00
avaliableSlots.remove(slot);
if (slot.getHasStack()) continue;
2014-04-29 10:54:20 +10:00
istack.numSlots++;
assignedSlots.get(i).add(slot);
assigned = true;
break;
}
}
if (!assigned || istack.numSlots * istack.stack.getMaxStackSize() >= istack.invAmount) {
2014-04-29 10:54:20 +10:00
iterator.remove();
}
2014-04-29 10:54:20 +10:00
}
}
for (int i = 0; i < ingredients.size(); i++)
2014-04-29 10:54:20 +10:00
assignedIngredients.get(i).slots = assignedSlots.get(i).toArray(new Slot[0]);
return recipeSlots;
}
private List<IngredientDistribution> assignIngredients(List<PositionedStack> ingredients,
List<DistributedIngred> ingredStacks) {
2019-12-30 20:19:16 -08:00
ArrayList<IngredientDistribution> assignedIngredients = new ArrayList<>();
for (PositionedStack posstack : ingredients) // assign what we need and have
2014-04-29 10:54:20 +10:00
{
DistributedIngred biggestIngred = null;
ItemStack permutation = null;
int biggestSize = 0;
for (ItemStack pstack : posstack.items) {
2019-12-30 20:19:16 -08:00
for (DistributedIngred istack : ingredStacks) {
if (!canStack(pstack, istack.stack) || istack.invAmount - istack.distributed < pstack.stackSize
|| istack.recipeAmount == 0
|| pstack.stackSize == 0)
continue;
2019-12-30 20:19:16 -08:00
int relsize = (istack.invAmount - istack.invAmount / istack.recipeAmount * istack.distributed)
/ pstack.stackSize;
2019-12-30 20:19:16 -08:00
if (relsize > biggestSize) {
2014-04-29 10:54:20 +10:00
biggestSize = relsize;
biggestIngred = istack;
permutation = pstack;
break;
}
}
}
if (biggestIngred == null) // not enough ingreds
return null;
biggestIngred.distributed += permutation.stackSize;
2014-04-29 10:54:20 +10:00
assignedIngredients.add(new IngredientDistribution(biggestIngred, permutation));
}
2014-04-29 10:54:20 +10:00
return assignedIngredients;
}
2021-04-10 20:26:01 -07:00
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)) {
2014-04-29 10:54:20 +10:00
ItemStack pstack = slot.getStack();
DistributedIngred istack = findIngred(ingredStacks, pstack);
if (istack != null) istack.invAmount += pstack.stackSize;
2014-04-29 10:54:20 +10:00
}
}
}
2021-04-10 20:26:01 -07:00
private List<DistributedIngred> getPermutationIngredients(List<PositionedStack> ingredients) {
2019-12-30 20:19:16 -08:00
ArrayList<DistributedIngred> ingredStacks = new ArrayList<>();
for (PositionedStack posstack : ingredients) /* work out what we need */ {
for (ItemStack pstack : posstack.items) {
2014-04-29 10:54:20 +10:00
DistributedIngred istack = findIngred(ingredStacks, pstack);
if (istack == null) ingredStacks.add(istack = new DistributedIngred(pstack));
istack.recipeAmount += pstack.stackSize;
2014-04-29 10:54:20 +10:00
}
}
return ingredStacks;
}
2014-08-07 12:28:02 +10:00
public boolean canMoveFrom(Slot slot, GuiContainer gui) {
return slot.inventory instanceof InventoryPlayer;
}
public Slot[][] mapIngredSlots(GuiContainer gui, List<PositionedStack> ingredients) {
2014-04-29 10:54:20 +10:00
Slot[][] recipeSlotList = new Slot[ingredients.size()][];
for (int i = 0; i < ingredients.size(); i++) /* identify slots */ {
2019-12-30 20:19:16 -08:00
LinkedList<Slot> recipeSlots = new LinkedList<>();
2014-04-29 10:54:20 +10:00
PositionedStack pstack = ingredients.get(i);
for (Slot slot : gui.inventorySlots.inventorySlots) {
if (slot.xDisplayPosition == pstack.relx + offsetx && slot.yDisplayPosition == pstack.rely + offsety) {
2014-04-29 10:54:20 +10:00
recipeSlots.add(slot);
break;
}
}
recipeSlotList[i] = recipeSlots.toArray(new Slot[0]);
}
return recipeSlotList;
}
2021-04-10 20:26:01 -07:00
public DistributedIngred findIngred(List<DistributedIngred> ingredStacks, ItemStack pstack) {
for (DistributedIngred istack : ingredStacks) if (canStack(pstack, istack.stack)) return istack;
2014-04-29 10:54:20 +10:00
return null;
}
protected boolean canStack(ItemStack stack1, ItemStack stack2) {
if (stack1 == null || stack2 == null) return true;
if (stack1.getItem() == stack2.getItem() && stack1.getItemDamage() == stack2.getItemDamage()) {
2021-04-10 20:26:01 -07:00
if (ItemStack.areItemStackTagsEqual(stack2, stack1)) 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;
2021-04-10 20:26:01 -07:00
}
return false;
}
2014-04-29 10:54:20 +10:00
}