Nearly fixed recipe matching
This commit is contained in:
parent
701baaed72
commit
1b0a3f4e71
12 changed files with 146 additions and 87 deletions
|
@ -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<ItemStack> getInputItems();
|
||||
|
||||
/**
|
||||
* Array of output slot ids
|
||||
*/
|
||||
public int[] getOutputSlots();
|
||||
public List<ItemStack> getOutputItems();
|
||||
}
|
||||
|
|
|
@ -97,12 +97,12 @@ public class GT_MetaTileEntity_E_Furnace extends GT_MetaTileEntity_BasicMachine
|
|||
}
|
||||
|
||||
@Override
|
||||
public int[] getInputSlots() {
|
||||
public List<ItemStack> getInputItems() {
|
||||
return new int[] {1, 2};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getOutputSlots() {
|
||||
public List<ItemStack> getOutputItems() {
|
||||
return new int[] {3, 4};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ItemStack> 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()) {
|
||||
|
|
|
@ -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<ItemStack> 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<ItemStack> getInputItems() {
|
||||
return new ListAdapter<>(mInventory, 1, 2);
|
||||
}
|
||||
|
||||
public int[] getOutputSlots() {
|
||||
return new int[] {3, 4};
|
||||
public List<ItemStack> getOutputItems() {
|
||||
return new ListAdapter<>(mInventory, 3, 4);
|
||||
}
|
||||
|
||||
/** Fallback to the regular Machine Outside Texture */
|
||||
|
|
|
@ -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<ItemStack> inputs = Arrays.stream(machineInputs)
|
||||
.filter(stack -> GT_Utility.isStackValid(stack))
|
||||
.collect(Collectors.toList());
|
||||
return match(null, inputs);
|
||||
}
|
||||
/**
|
||||
* 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 <b>input</b>
|
||||
*/
|
||||
public boolean matches(boolean decrease, List<ItemStack> 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!";
|
||||
|
||||
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";
|
||||
boolean result;
|
||||
if (shaped)
|
||||
result = checkShaped(decrease, input);
|
||||
else
|
||||
result = checkShapeless(decrease, input);
|
||||
|
||||
List<ItemStackKey> decreaseList = new ArrayList<>();
|
||||
Map<ItemStack, Integer> 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<ItemStackKey, Integer> slotAligment = ListMultimapBuilder.hashKeys().arrayListValues().build();
|
||||
slotStacks.entrySet().forEach(e -> slotAligment.put(ItemStackKey.from(e.getKey()), e.getValue()));
|
||||
for (ItemStackKey recipeKey : decreaseList) {
|
||||
List<Integer> 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<ItemStackKey> actionPerfomer, Collection<ItemStack> inputs) {
|
||||
if (inputs.size() >= mInputs.length) {
|
||||
start:
|
||||
for (ItemStack[] recipeSlot : mInputs) {
|
||||
List<ItemStackKey> variants = Arrays.stream(recipeSlot)
|
||||
.map(s -> ItemStackKey.from(s))
|
||||
.collect(Collectors.toList());
|
||||
Iterator<ItemStack> 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;
|
||||
private boolean checkShapeless(boolean decrease, List<ItemStack> inputs) {
|
||||
Pair<Boolean, Integer[]> 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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} else 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<ItemStack> 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<Boolean, Integer[]> matchItems(List<ItemStack> 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<Integer, List<Recipe>> 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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<ItemStack> getInputItems() { return new int[] {0, 1}; }
|
||||
@Override public List<ItemStack> getOutputItems() { return new int[] {2, 3, 4, 5}; };
|
||||
|
||||
@Override
|
||||
public int getTextureIndex(byte aSide, byte aFacing, boolean aActive, boolean aRedstone) {
|
||||
|
|
|
@ -38,12 +38,12 @@ public class GT_MetaTileEntity_ChemicalReactor extends GT_MetaTileEntity_BasicMa
|
|||
}
|
||||
|
||||
@Override
|
||||
public int[] getInputSlots() {
|
||||
public List<ItemStack> getInputItems() {
|
||||
return new int[] {0, 1};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getOutputSlots() {
|
||||
public List<ItemStack> getOutputItems() {
|
||||
return new int[] {2};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ItemStack> getInputItems() { return new int[] {0, 1}; }
|
||||
@Override public List<ItemStack> getOutputItems() { return new int[] {2, 3, 4, 5}; };
|
||||
|
||||
@Override
|
||||
public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue