From 1b0a3f4e719a1ffc082dda2698b9551875ee241e Mon Sep 17 00:00:00 2001 From: TheDarkDnKTv Date: Sat, 6 Feb 2021 08:29:40 +0200 Subject: [PATCH] Nearly fixed recipe matching --- .../api/interfaces/IRecipeWorkable.java | 6 +- .../examples/GT_MetaTileEntity_E_Furnace.java | 4 +- .../implementations/BasicFluidWorkable.java | 6 +- .../GT_MetaTileEntity_BasicMachine.java | 14 +- .../java/gregtechmod/api/recipe/Recipe.java | 155 +++++++++++------- .../gregtechmod/api/recipe/RecipeLogic.java | 16 +- .../gregtechmod/api/util/ItemStackKey.java | 12 +- .../common/recipe/RecipeEntry.java | 2 +- .../GT_MetaTileEntity_Centrifuge.java | 6 +- .../GT_MetaTileEntity_ChemicalReactor.java | 4 +- .../GT_MetaTileEntity_Electrolyzer.java | 6 +- .../basic/GT_MetaTileEntity_AlloySmelter.java | 2 +- 12 files changed, 146 insertions(+), 87 deletions(-) diff --git a/src/main/java/gregtechmod/api/interfaces/IRecipeWorkable.java b/src/main/java/gregtechmod/api/interfaces/IRecipeWorkable.java index b9ae2b5..d9e323f 100644 --- a/src/main/java/gregtechmod/api/interfaces/IRecipeWorkable.java +++ b/src/main/java/gregtechmod/api/interfaces/IRecipeWorkable.java @@ -1,5 +1,7 @@ package gregtechmod.api.interfaces; +import java.util.List; + import gregtechmod.api.recipe.Recipe; import net.minecraft.item.ItemStack; @@ -27,10 +29,10 @@ public interface IRecipeWorkable { /** * Array of input slot ids */ - public int[] getInputSlots(); + public List getInputItems(); /** * Array of output slot ids */ - public int[] getOutputSlots(); + public List getOutputItems(); } diff --git a/src/main/java/gregtechmod/api/metatileentity/examples/GT_MetaTileEntity_E_Furnace.java b/src/main/java/gregtechmod/api/metatileentity/examples/GT_MetaTileEntity_E_Furnace.java index 1a9af08..dc26add 100644 --- a/src/main/java/gregtechmod/api/metatileentity/examples/GT_MetaTileEntity_E_Furnace.java +++ b/src/main/java/gregtechmod/api/metatileentity/examples/GT_MetaTileEntity_E_Furnace.java @@ -97,12 +97,12 @@ public class GT_MetaTileEntity_E_Furnace extends GT_MetaTileEntity_BasicMachine } @Override - public int[] getInputSlots() { + public List getInputItems() { return new int[] {1, 2}; } @Override - public int[] getOutputSlots() { + public List getOutputItems() { return new int[] {3, 4}; } diff --git a/src/main/java/gregtechmod/api/metatileentity/implementations/BasicFluidWorkable.java b/src/main/java/gregtechmod/api/metatileentity/implementations/BasicFluidWorkable.java index ec112c9..3e184c6 100644 --- a/src/main/java/gregtechmod/api/metatileentity/implementations/BasicFluidWorkable.java +++ b/src/main/java/gregtechmod/api/metatileentity/implementations/BasicFluidWorkable.java @@ -95,7 +95,7 @@ public abstract class BasicFluidWorkable extends GT_MetaTileEntity_BasicTank imp } if (result == null) { - result = Recipe.findEqualRecipe(false, recipeLogic.recipeMap, getBaseMetaTileEntity(), getInputSlots()); + result = Recipe.findEqualRecipe(false, recipeLogic.recipeMap, getBaseMetaTileEntity(), getInputItems()); } return result; @@ -156,9 +156,9 @@ public abstract class BasicFluidWorkable extends GT_MetaTileEntity_BasicTank imp @Override public boolean spaceForOutput(Recipe recipe) { ItemStack[] outputs = recipe.getOutputs(); - if (outputs.length <= getOutputSlots().length) { + if (outputs.length <= getOutputItems().length) { List slots = new ArrayList<>(); - for (int i : getOutputSlots()) slots.add(mInventory[i]); + for (int i : getOutputItems()) slots.add(mInventory[i]); for (int i = 0; i < outputs.length && i < slots.size(); i++) { if (slots.get(i) != null && outputs[i] != null) { if (!GT_Utility.areStacksEqual(slots.get(i), outputs[i]) || slots.get(i).stackSize + outputs[i].stackSize > slots.get(i).getMaxStackSize()) { diff --git a/src/main/java/gregtechmod/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java b/src/main/java/gregtechmod/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java index b172f38..200ad66 100644 --- a/src/main/java/gregtechmod/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java +++ b/src/main/java/gregtechmod/api/metatileentity/implementations/GT_MetaTileEntity_BasicMachine.java @@ -12,7 +12,7 @@ import gregtechmod.api.recipe.RecipeLogic; import gregtechmod.api.util.GT_OreDictUnificator; import gregtechmod.api.util.GT_Utility; import gregtechmod.api.util.InfoBuilder; - +import gregtechmod.api.util.ListAdapter; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -138,9 +138,9 @@ public abstract class GT_MetaTileEntity_BasicMachine extends MetaTileEntity impl @Override public boolean spaceForOutput(Recipe recipe) { ItemStack[] outputs = recipe.getOutputs(); - if (outputs.length <= getOutputSlots().length) { + if (outputs.length <= getOutputItems().length) { List slots = new ArrayList<>(); - for (int i : getOutputSlots()) slots.add(mInventory[i]); + for (int i : getOutputItems()) slots.add(mInventory[i]); for (int i = 0; i < outputs.length && i < slots.size(); i++) { if (slots.get(i) != null && outputs[i] != null) { if (!GT_Utility.areStacksEqual(slots.get(i), outputs[i]) || slots.get(i).stackSize + outputs[i].stackSize > slots.get(i).getMaxStackSize()) { @@ -157,12 +157,12 @@ public abstract class GT_MetaTileEntity_BasicMachine extends MetaTileEntity impl return false; } - public int[] getInputSlots() { - return new int[] {1, 2}; + public List getInputItems() { + return new ListAdapter<>(mInventory, 1, 2); } - public int[] getOutputSlots() { - return new int[] {3, 4}; + public List getOutputItems() { + return new ListAdapter<>(mInventory, 3, 4); } /** Fallback to the regular Machine Outside Texture */ diff --git a/src/main/java/gregtechmod/api/recipe/Recipe.java b/src/main/java/gregtechmod/api/recipe/Recipe.java index 039803b..f1015e0 100644 --- a/src/main/java/gregtechmod/api/recipe/Recipe.java +++ b/src/main/java/gregtechmod/api/recipe/Recipe.java @@ -25,10 +25,14 @@ import java.util.Map; import java.util.Optional; import java.util.Random; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; + import com.google.common.collect.ListMultimap; +import com.google.common.collect.MultimapBuilder; import com.google.common.collect.MultimapBuilder.ListMultimapBuilder; import net.minecraft.init.Blocks; @@ -69,72 +73,109 @@ public class Recipe { this.chancedOutputs = new ArrayList<>(chancedOutputs); } - public boolean match(ItemStack...machineInputs) { - assert machineInputs != null : "Recipe check failed, machineInputs = null"; - assert machineInputs.length > 0 : "Recipe check failed, machineInputs size < 1"; - List inputs = Arrays.stream(machineInputs) - .filter(stack -> GT_Utility.isStackValid(stack)) - .collect(Collectors.toList()); - return match(null, inputs); - } - - public boolean match(boolean decrease, IGregTechTileEntity tile, int[] inputSlots) { - assert tile != null : "Recipe check failed, tile = null"; - assert inputSlots != null : "Recipe check failed, inputSlots = null"; - assert inputSlots.length > 0 : "Recipe check failed, inputSlots size < 1"; + /** + * Default match method + * @param decrease if set, itemstacks size will dercease + * @param input collection of input stacks even nulls + * @return true if recipe matches for machine input + */ + public boolean matches(boolean decrease, List input) { + assert input != null : "Input can not be null!"; + assert input.isEmpty() : "Input can not be empty!"; + assert input.size() >= inputs.size() : "Can not be less inputs of machine than recipe has!"; + + boolean result; + if (shaped) + result = checkShaped(decrease, input); + else + result = checkShapeless(decrease, input); - List decreaseList = new ArrayList<>(); - Map slotStacks = new HashMap<>(); - for (int i : inputSlots) { - ItemStack stack = tile.getStackInSlot(i); - if (stack != null) slotStacks.put(stack.copy(), i); - } - - - boolean success = this.match(key -> decreaseList.add(key), slotStacks.keySet()); - if (success && decrease) { - ListMultimap slotAligment = ListMultimapBuilder.hashKeys().arrayListValues().build(); - slotStacks.entrySet().forEach(e -> slotAligment.put(ItemStackKey.from(e.getKey()), e.getValue())); - for (ItemStackKey recipeKey : decreaseList) { - List slots = new ArrayList<>(slotAligment.values()); - tile.decrStackSize(slots.get(0), recipeKey.getStackSize()); - } - } - - return success; + return result; } /** * Matching recipe to following input, in case of successfully found item in recipe input map will execute actionPerfomer */ - private boolean match(Consumer actionPerfomer, Collection inputs) { - if (inputs.size() >= mInputs.length) { - start: - for (ItemStack[] recipeSlot : mInputs) { - List variants = Arrays.stream(recipeSlot) - .map(s -> ItemStackKey.from(s)) - .collect(Collectors.toList()); - Iterator machineSlot = new ArrayList<>(inputs).iterator(); - while (machineSlot.hasNext()) { - int idx = -1; - ItemStack slot = machineSlot.next(); - if ((idx = variants.indexOf(ItemStackKey.from(slot))) >= 0) { - if (variants.get(idx).get().stackSize <= slot.stackSize) { - if (actionPerfomer != null) - actionPerfomer.accept(variants.get(idx)); - machineSlot.remove(); - continue start; - } - } - } - - return false; + private boolean checkShapeless(boolean decrease, List inputs) { + Pair items = this.matchItems(inputs); + if (items.getKey()) { + for (int i = 0; decrease && i < inputs.size(); i++) { + ItemStack current = inputs.get(i); + int newSize = items.getValue()[i]; + if (current == null || newSize == current.stackSize) continue; + if (newSize > 0) + current.stackSize = newSize; + else + inputs.set(i, null); } - } else return false; + return true; + } + return false; + } + + /** + * Will check if recipe matches for shaped recipe + * @param actionPerfomer will calls every loop, will put in a ItemStack of slot and amount needed for recipe + */ + private boolean checkShaped(boolean decrease, List inputs) { + for (int i = 0; i < this.inputs.size(); i++) { + Ingredient ingr = this.inputs.get(i); + ItemStack current = inputs.get(i); + if (!ingr.match(current) || current.stackSize < ingr.getCount()) + return false; + } + + for (int i = 0; decrease && i < this.inputs.size(); i++) { // Check this, not sure about working + int toConsume = this.inputs.get(i).getCount(); + ItemStack current = inputs.get(i); + if (current.stackSize == toConsume) { + inputs.set(i, null); + } else { + current.stackSize -= toConsume; + } + } return true; } + /** + * @param input + * @return boolean means if it could be consumed, Integer[] is mapping of item amounts per slot to change + */ + private Pair matchItems(List input) { + Integer[] itemAmountInSlots = new Integer[input.size()]; + + for (int i = 0; i < input.size(); i++) { + ItemStack itemInSlot = input.get(i); + itemAmountInSlots[i] = itemInSlot == null ? 0 : itemInSlot.stackSize; + } + + for (Ingredient ingr : inputs) { + int ingrAmount = ingr.getCount(); + boolean consumed = false; + + if (ingrAmount == 0) { + ingrAmount = 1; + consumed = true; + } + + for (int i = 0; i < input.size(); i++) { + ItemStack inputStack = input.get(i); + if (inputStack == null || !ingr.match(inputStack)) + continue; + int toConsume = Math.min(itemAmountInSlots[i], ingrAmount); + ingrAmount -= toConsume; + if (!consumed) + itemAmountInSlots[i] -= toConsume; + if (ingrAmount == 0) + break; + } + if (ingrAmount > 0) + return Pair.of(false, itemAmountInSlots); + } + return Pair.of(true, itemAmountInSlots); + } + private final void addToMap(Map> aMap) { for (ItemStack[] tStacks : mInputs) { for (ItemStack tStack : tStacks) if (tStack != null) { @@ -200,6 +241,10 @@ public class Recipe { return EUt; } + public boolean isShaped() { + return shaped; + } + /** * @return list containing only 100% chanced outputs */ diff --git a/src/main/java/gregtechmod/api/recipe/RecipeLogic.java b/src/main/java/gregtechmod/api/recipe/RecipeLogic.java index 6acd4aa..df433bf 100644 --- a/src/main/java/gregtechmod/api/recipe/RecipeLogic.java +++ b/src/main/java/gregtechmod/api/recipe/RecipeLogic.java @@ -123,16 +123,16 @@ public class RecipeLogic { protected Recipe findRecipe() { if (customRecipeProvider == null) { - return Recipe.findEqualRecipe(true, recipeMap, getMachine().getBaseMetaTileEntity(), getMachine().getInputSlots()); + return Recipe.findEqualRecipe(true, recipeMap, getMachine().getBaseMetaTileEntity(), getMachine().getInputItems()); } else return customRecipeProvider.get(); } protected boolean match(Recipe recipe) { - return recipe.match(false, getMachine().getBaseMetaTileEntity(), getMachine().getInputSlots()); + return recipe.match(false, getMachine().getBaseMetaTileEntity(), getMachine().getInputItems()); } protected void consumeInputs(Recipe recipe) { - recipe.match(true, getMachine().getBaseMetaTileEntity(), getMachine().getInputSlots()); + recipe.match(true, getMachine().getBaseMetaTileEntity(), getMachine().getInputItems()); } protected void moveItems() { @@ -143,8 +143,8 @@ public class RecipeLogic { // Slot 4 = right Output // Slot 5 = battery Slot in most cases IInventory inv = getMachine().getBaseMetaTileEntity(); - int[] in = getMachine().getInputSlots(); - int[] out = getMachine().getOutputSlots(); + int[] in = getMachine().getInputItems(); + int[] out = getMachine().getOutputItems(); if (in.length > 1) GT_Utility.moveStackFromSlotAToSlotB(inv, inv, in[0], in[1], (byte)64, (byte)1, (byte)64, (byte)1); if (out.length > 1) GT_Utility.moveStackFromSlotAToSlotB(inv, inv, out[0], out[1], (byte)64, (byte)1, (byte)64, (byte)1); } @@ -165,9 +165,9 @@ public class RecipeLogic { protected void endRecipe(Recipe recipe) { ItemStack[] outputs = recipe.getOutputs(); - if (outputs.length <= getMachine().getOutputSlots().length) { + if (outputs.length <= getMachine().getOutputItems().length) { for (ItemStack out : outputs) { - for (int i : getMachine().getOutputSlots()) { + for (int i : getMachine().getOutputItems()) { if (out != null && getMachine().getBaseMetaTileEntity().addStackToSlot(i, out.copy())) { break; } @@ -182,7 +182,7 @@ public class RecipeLogic { } protected boolean isInputNonEmpty() { - for (int i : getMachine().getInputSlots()) { + for (int i : getMachine().getInputItems()) { ItemStack s = getMachine().getStackInSlot(i); if (s != null && s.stackSize > 0) return true; } diff --git a/src/main/java/gregtechmod/api/util/ItemStackKey.java b/src/main/java/gregtechmod/api/util/ItemStackKey.java index 0de239c..407b958 100644 --- a/src/main/java/gregtechmod/api/util/ItemStackKey.java +++ b/src/main/java/gregtechmod/api/util/ItemStackKey.java @@ -14,15 +14,23 @@ public final class ItemStackKey { public final boolean isWildcard; public static ItemStackKey from(ItemStack stack) { - return from(stack, false); + return from(stack, stack.stackSize, false); } public static ItemStackKey from(ItemStack stack, boolean isWildcard) { + return from(stack, stack.stackSize, isWildcard); + } + + public static ItemStackKey from(ItemStack stack, int count) { + return from(stack, count, false); + } + + public static ItemStackKey from(ItemStack stack, int count, boolean isWildcard) { Objects.requireNonNull(stack); Objects.requireNonNull(stack.getItem()); ItemStack stackCopy = stack.copy(); stackCopy.stackSize = 1; - return new ItemStackKey(stackCopy, isWildcard, stack.stackSize); + return new ItemStackKey(stackCopy, isWildcard, count); } private ItemStackKey(ItemStack stack, boolean isWildcard, int stackSize) { diff --git a/src/main/java/gregtechmod/common/recipe/RecipeEntry.java b/src/main/java/gregtechmod/common/recipe/RecipeEntry.java index ce5ac1a..dd6d4cc 100644 --- a/src/main/java/gregtechmod/common/recipe/RecipeEntry.java +++ b/src/main/java/gregtechmod/common/recipe/RecipeEntry.java @@ -172,7 +172,7 @@ public class RecipeEntry implements Ingredient { public boolean match(ItemStack input) { if (GT_Utility.isStackValid(input)) { for (ItemStack stack : variants) { - if (stack.getItem() == input.getItem() && + if (stack.getItem() == input.getItem() && (options.contains(Match.DAMAGE) ? stack.getItemDamage() == input.getItemDamage() : true) && (options.contains(Match.NBT) ? matchNBT(input, stack) : true)) { return true; diff --git a/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Centrifuge.java b/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Centrifuge.java index 686b337..1f70ae8 100644 --- a/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Centrifuge.java +++ b/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Centrifuge.java @@ -1,5 +1,7 @@ package gregtechmod.common.tileentities.machines; +import java.util.List; + import gregtechmod.api.interfaces.IGregTechTileEntity; import gregtechmod.api.metatileentity.MetaTileEntity; import gregtechmod.api.metatileentity.implementations.BasicFluidWorkable; @@ -39,8 +41,8 @@ public class GT_MetaTileEntity_Centrifuge extends BasicFluidWorkable { @Override public int getStackDisplaySlot() {return 6;} @Override public int getInvSize() {return 7;} @Override public void onRightclick(EntityPlayer aPlayer) {getBaseMetaTileEntity().openGUI(aPlayer, 146);} - @Override public int[] getInputSlots() { return new int[] {0, 1}; } - @Override public int[] getOutputSlots() { return new int[] {2, 3, 4, 5}; }; + @Override public List getInputItems() { return new int[] {0, 1}; } + @Override public List getOutputItems() { return new int[] {2, 3, 4, 5}; }; @Override public int getTextureIndex(byte aSide, byte aFacing, boolean aActive, boolean aRedstone) { diff --git a/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_ChemicalReactor.java b/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_ChemicalReactor.java index b11402b..54ae9d6 100644 --- a/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_ChemicalReactor.java +++ b/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_ChemicalReactor.java @@ -38,12 +38,12 @@ public class GT_MetaTileEntity_ChemicalReactor extends GT_MetaTileEntity_BasicMa } @Override - public int[] getInputSlots() { + public List getInputItems() { return new int[] {0, 1}; } @Override - public int[] getOutputSlots() { + public List getOutputItems() { return new int[] {2}; } diff --git a/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Electrolyzer.java b/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Electrolyzer.java index 7c21305..73c6ae7 100644 --- a/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Electrolyzer.java +++ b/src/main/java/gregtechmod/common/tileentities/machines/GT_MetaTileEntity_Electrolyzer.java @@ -1,5 +1,7 @@ package gregtechmod.common.tileentities.machines; +import java.util.List; + import gregtechmod.api.interfaces.IGregTechTileEntity; import gregtechmod.api.metatileentity.MetaTileEntity; import gregtechmod.api.metatileentity.implementations.BasicFluidWorkable; @@ -25,8 +27,8 @@ public class GT_MetaTileEntity_Electrolyzer extends BasicFluidWorkable { @Override public int getOutputSlot() {return 2;} @Override public int getStackDisplaySlot() {return 6;} @Override public void onRightclick(EntityPlayer aPlayer) {getBaseMetaTileEntity().openGUI(aPlayer, 109);} - @Override public int[] getInputSlots() { return new int[] {0, 1}; } - @Override public int[] getOutputSlots() { return new int[] {2, 3, 4, 5}; }; + @Override public List getInputItems() { return new int[] {0, 1}; } + @Override public List getOutputItems() { return new int[] {2, 3, 4, 5}; }; @Override public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { diff --git a/src/main/java/gregtechmod/common/tileentities/machines/basic/GT_MetaTileEntity_AlloySmelter.java b/src/main/java/gregtechmod/common/tileentities/machines/basic/GT_MetaTileEntity_AlloySmelter.java index 6492d3d..745bac6 100644 --- a/src/main/java/gregtechmod/common/tileentities/machines/basic/GT_MetaTileEntity_AlloySmelter.java +++ b/src/main/java/gregtechmod/common/tileentities/machines/basic/GT_MetaTileEntity_AlloySmelter.java @@ -30,7 +30,7 @@ public class GT_MetaTileEntity_AlloySmelter extends GT_MetaTileEntity_BasicMachi recipeLogic = new RecipeLogic(recipeMap, this) { @Override protected void moveItems() { - GT_Utility.moveStackFromSlotAToSlotB(getBaseMetaTileEntity(), getBaseMetaTileEntity(), getOutputSlots()[0], getOutputSlots()[1], (byte)64, (byte)1, (byte)64, (byte)1); + GT_Utility.moveStackFromSlotAToSlotB(getBaseMetaTileEntity(), getBaseMetaTileEntity(), getOutputItems()[0], getOutputItems()[1], (byte)64, (byte)1, (byte)64, (byte)1); } }; }