diff --git a/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java b/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java
index 57fbf227006..d4f0e96a36b 100644
--- a/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java
+++ b/src/main/java/gregtech/api/logic/AbstractProcessingLogic.java
@@ -43,6 +43,7 @@ public abstract class AbstractProcessingLogic
preProcess() {
recipeMap = recipeMapSupplier.get();
}
if (lastRecipeMap != recipeMap) {
+ if (lastRecipeMap != null) needWipeCraftingPatternRecipeCache = true;
lastRecipe = null;
lastRecipeMap = recipeMap;
}
diff --git a/src/main/java/gregtech/api/logic/ProcessingLogic.java b/src/main/java/gregtech/api/logic/ProcessingLogic.java
index 63c8f6494e4..6e5cf5ae56d 100644
--- a/src/main/java/gregtech/api/logic/ProcessingLogic.java
+++ b/src/main/java/gregtech/api/logic/ProcessingLogic.java
@@ -1,6 +1,11 @@
package gregtech.api.logic;
+import static java.util.stream.Collectors.toList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
@@ -10,6 +15,7 @@
import net.minecraftforge.fluids.FluidStack;
import gregtech.api.interfaces.tileentity.IRecipeLockable;
+import gregtech.api.objects.GTDualInputs;
import gregtech.api.recipe.RecipeMap;
import gregtech.api.recipe.check.CheckRecipeResult;
import gregtech.api.recipe.check.CheckRecipeResultRegistry;
@@ -17,6 +23,7 @@
import gregtech.api.util.GTRecipe;
import gregtech.api.util.OverclockCalculator;
import gregtech.api.util.ParallelHelper;
+import gregtech.common.tileentities.machines.IDualInputInventory;
/**
* Logic class to calculate result of recipe check from inputs, based on recipemap.
@@ -29,6 +36,8 @@ public class ProcessingLogic extends AbstractProcessingLogic {
protected ItemStack[] inputItems;
protected FluidStack[] inputFluids;
protected boolean isRecipeLocked;
+ protected int craftingPatternHash;
+ protected Map> craftingPatternRecipeCache = new HashMap<>();
public ProcessingLogic() {}
@@ -63,6 +72,37 @@ public ProcessingLogic setSpecialSlotItem(ItemStack specialSlotItem) {
return getThis();
}
+ public boolean craftingPatternHandler(IDualInputInventory slot) {
+ int hash = slot.hashCode();
+ if (needWipeCraftingPatternRecipeCache) {
+ craftingPatternRecipeCache.clear();
+ needWipeCraftingPatternRecipeCache = false;
+ }
+ if (!craftingPatternRecipeCache.containsKey(hash)) {
+ GTDualInputs inputs = slot.getPatternInputs();
+ setInputItems(inputs.inputItems);
+ setInputFluids(inputs.inputFluid);
+ List recipes = new ArrayList<>();
+ for (GTRecipe recipe : findRecipeMatches(preProcess()).collect(toList())) {
+ if (!recipes.contains(recipe)) {
+ recipes.add(recipe);
+ }
+ }
+ if (!recipes.isEmpty()) {
+ craftingPatternRecipeCache.put(hash, recipes);
+ craftingPatternHash = hash;
+ return true;
+ }
+ return false;
+ }
+ craftingPatternHash = hash;
+ return true;
+ }
+
+ public void removeEntryCraftingPatternRecipeCache(int hash) {
+ craftingPatternRecipeCache.remove(hash);
+ }
+
/**
* Enables single recipe locking mode.
*/
@@ -85,6 +125,7 @@ public ProcessingLogic clear() {
this.calculatedEut = 0;
this.duration = 0;
this.calculatedParallels = 0;
+ this.craftingPatternHash = 0;
return getThis();
}
@@ -106,6 +147,18 @@ public CheckRecipeResult process() {
inputFluids = new FluidStack[0];
}
+ if (craftingPatternHash != 0) {
+ List matchedRecipes = craftingPatternRecipeCache.get(craftingPatternHash);
+ for (GTRecipe matchedRecipe : matchedRecipes) {
+ if (matchedRecipe.maxParallelCalculatedByInputs(1, inputFluids, inputItems) == 1) {
+ CalculationResult foundResult = validateAndCalculateRecipe(matchedRecipe);
+ return foundResult.checkRecipeResult;
+ }
+ }
+ craftingPatternHash = 0;
+ return CheckRecipeResultRegistry.NO_RECIPE;
+ }
+
if (isRecipeLocked && recipeLockableMachine != null && recipeLockableMachine.getSingleRecipeCheck() != null) {
// Recipe checker is already built, we'll use it
SingleRecipeCheck singleRecipeCheck = recipeLockableMachine.getSingleRecipeCheck();
diff --git a/src/main/java/gregtech/api/metatileentity/implementations/MTEMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/MTEMultiBlockBase.java
index 823576d7cb2..38df2158f5f 100644
--- a/src/main/java/gregtech/api/metatileentity/implementations/MTEMultiBlockBase.java
+++ b/src/main/java/gregtech/api/metatileentity/implementations/MTEMultiBlockBase.java
@@ -883,16 +883,18 @@ protected boolean supportsCraftingMEBuffer() {
@Nonnull
protected CheckRecipeResult doCheckRecipe() {
CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE;
+
// check crafting input hatches first
- if (supportsCraftingMEBuffer()) {
- for (IDualInputHatch dualInputHatch : mDualInputHatches) {
- for (var it = dualInputHatch.inventories(); it.hasNext();) {
- IDualInputInventory slot = it.next();
- // Reverse order of input items for consistent behavior with standard input buses.
- ItemStack[] inputItems = slot.getItemInputs();
- ArrayUtils.reverse(inputItems);
- processingLogic.setInputItems(inputItems);
+ for (IDualInputHatch dualInputHatch : mDualInputHatches) {
+ ItemStack[] sharedItems = dualInputHatch.getSharedItems();
+ for (var it = dualInputHatch.inventories(); it.hasNext();) {
+ IDualInputInventory slot = it.next();
+
+ if (!slot.isEmpty() && processingLogic.craftingPatternHandler(slot)) {
+
+ processingLogic.setInputItems(ArrayUtils.addAll(sharedItems, slot.getItemInputs()));
processingLogic.setInputFluids(slot.getFluidInputs());
+
CheckRecipeResult foundResult = processingLogic.process();
if (foundResult.wasSuccessful()) {
return foundResult;
@@ -1720,6 +1722,7 @@ public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasing
}
if (aMetaTileEntity instanceof IDualInputHatch hatch) {
hatch.updateCraftingIcon(this.getMachineCraftingIcon());
+ hatch.setProcessingLogic(processingLogic);
return mDualInputHatches.add(hatch);
}
if (aMetaTileEntity instanceof ISmartInputHatch hatch) {
@@ -2049,12 +2052,8 @@ public void getWailaBody(ItemStack itemStack, List currentTip, IWailaDat
}
}
}
- currentTip.add(
- GTWaila.getMachineProgressString(
- isActive,
- tag.getBoolean("isAllowedToWork"),
- tag.getInteger("maxProgress"),
- tag.getInteger("progress")));
+ currentTip
+ .add(GTWaila.getMachineProgressString(isActive, tag.getInteger("maxProgress"), tag.getInteger("progress")));
// Show ns on the tooltip
if (GTMod.gregtechproxy.wailaAverageNS && tag.hasKey("averageNS")) {
int tAverageTime = tag.getInteger("averageNS");
@@ -2103,7 +2102,6 @@ public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompou
final IGregTechTileEntity tileEntity = getBaseMetaTileEntity();
if (tileEntity != null) {
tag.setBoolean("isActive", tileEntity.isActive());
- tag.setBoolean("isAllowedToWork", tileEntity.isAllowedToWork());
if (tileEntity.isActive()) {
if (mEUt < 0) tag.setLong("energyUsage", getActualEnergyUsage());
else tag.setLong("energyUsage", (long) -mEUt * mEfficiency / 10000);
diff --git a/src/main/java/gregtech/api/objects/GTDualInputs.java b/src/main/java/gregtech/api/objects/GTDualInputs.java
new file mode 100644
index 00000000000..368892fb8a9
--- /dev/null
+++ b/src/main/java/gregtech/api/objects/GTDualInputs.java
@@ -0,0 +1,10 @@
+package gregtech.api.objects;
+
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.fluids.FluidStack;
+
+public class GTDualInputs {
+
+ public ItemStack[] inputItems;
+ public FluidStack[] inputFluid;
+}
diff --git a/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java b/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java
index 0660f6b1a1b..31e09d8f461 100644
--- a/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java
+++ b/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java
@@ -5,6 +5,8 @@
import net.minecraft.item.ItemStack;
+import gregtech.api.logic.ProcessingLogic;
+
public interface IDualInputHatch {
boolean justUpdated();
@@ -18,4 +20,8 @@ public interface IDualInputHatch {
Optional getFirstNonEmptyInventory();
boolean supportsFluids();
+
+ ItemStack[] getSharedItems();
+
+ void setProcessingLogic(ProcessingLogic pl);
}
diff --git a/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java b/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java
index 01649fe1817..56fedf5e41e 100644
--- a/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java
+++ b/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java
@@ -3,9 +3,16 @@
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
+import gregtech.api.objects.GTDualInputs;
+
public interface IDualInputInventory {
+ boolean isEmpty();
+
ItemStack[] getItemInputs();
FluidStack[] getFluidInputs();
+
+ GTDualInputs getPatternInputs();
+
}
diff --git a/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputME.java b/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputME.java
index 79c683f4610..ee415771f90 100644
--- a/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputME.java
+++ b/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputME.java
@@ -41,6 +41,7 @@
import org.apache.commons.lang3.ArrayUtils;
import org.jetbrains.annotations.NotNull;
+import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.common.item.ItemFluidPacket;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizons.modularui.api.math.Alignment;
@@ -91,8 +92,10 @@
import gregtech.api.interfaces.modularui.IAddGregtechLogo;
import gregtech.api.interfaces.modularui.IAddUIWidgets;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.metatileentity.implementations.MTEHatchInputBus;
+import gregtech.api.objects.GTDualInputs;
import gregtech.api.render.TextureFactory;
import gregtech.api.util.GTUtility;
import gregtech.api.util.extensions.ArrayExt;
@@ -198,14 +201,15 @@ public boolean isFluidEmpty() {
return fluidInventory.isEmpty();
}
+ @Override
public boolean isEmpty() {
return isItemEmpty() && isFluidEmpty();
}
@Override
public ItemStack[] getItemInputs() {
- if (isEmpty()) return new ItemStack[0];
- return ArrayUtils.addAll(itemInventory.toArray(new ItemStack[0]), sharedItemGetter.getSharedItem());
+ if (isItemEmpty()) return new ItemStack[0];
+ return itemInventory.toArray(new ItemStack[0]);
}
@Override
@@ -218,6 +222,34 @@ public ICraftingPatternDetails getPatternDetails() {
return patternDetails;
}
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(patternDetails);
+ }
+
+ public GTDualInputs getPatternInputs() {
+ GTDualInputs dualInputs = new GTDualInputs();
+
+ ItemStack[] inputItems = this.sharedItemGetter.getSharedItem();
+ FluidStack[] inputFluids = new FluidStack[0];
+
+ for (IAEItemStack singleInput : this.getPatternDetails()
+ .getInputs()) {
+ if (singleInput == null) continue;
+ ItemStack singleInputItemStack = singleInput.getItemStack();
+ if (singleInputItemStack.getItem() instanceof ItemFluidDrop) {
+ FluidStack fluidStack = ItemFluidDrop.getFluidStack(singleInputItemStack);
+ if (fluidStack != null) inputFluids = ArrayUtils.addAll(inputFluids, fluidStack);
+ } else {
+ inputItems = ArrayUtils.addAll(inputItems, singleInputItemStack);
+ }
+ }
+
+ dualInputs.inputItems = inputItems;
+ dualInputs.inputFluid = inputFluids;
+ return dualInputs;
+ }
+
public void refund(AENetworkProxy proxy, BaseActionSource src) throws GridAccessException {
IMEMonitor sg = proxy.getStorage()
.getItemInventory();
@@ -324,6 +356,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
private static final int MANUAL_SLOT_WINDOW = 10;
private BaseActionSource requestSource = null;
private @Nullable AENetworkProxy gridProxy = null;
+ public ArrayList processingLogics = new ArrayList<>();
// holds all internal inventories
private final PatternSlot[] internalInventory = new PatternSlot[MAX_PATTERN_COUNT];
@@ -803,6 +836,7 @@ private void onPatternChange(int index, ItemStack newItem) {
needPatternSync = true;
}
+ @Override
public ItemStack[] getSharedItems() {
ItemStack[] sharedItems = new ItemStack[SLOT_MANUAL_SIZE + 1];
sharedItems[0] = mInventory[SLOT_CIRCUIT];
@@ -810,6 +844,23 @@ public ItemStack[] getSharedItems() {
return ArrayExt.withoutNulls(sharedItems, ItemStack[]::new);
}
+ @Override
+ public void setProcessingLogic(ProcessingLogic pl) {
+ if (!processingLogics.contains(pl)) {
+ processingLogics.add(pl);
+ }
+ }
+
+ private void resetCraftingInputRecipeMap() {
+ for (ProcessingLogic pl : processingLogics) {
+ if (pl == null) continue;
+ for (PatternSlot slot : internalInventory) {
+ if (slot == null) continue;
+ pl.removeEntryCraftingPatternRecipeCache(slot.hashCode());
+ }
+ }
+ }
+
@Override
public void getWailaBody(ItemStack itemStack, List currenttip, IWailaDataAccessor accessor,
IWailaConfigHandler config) {
@@ -982,6 +1033,12 @@ public ItemStack getCrafterIcon() {
return getMachineCraftingIcon();
}
+ @Override
+ public void markDirty() {
+ super.markDirty();
+ resetCraftingInputRecipeMap();
+ }
+
private boolean postMEPatternChange() {
// don't post until it's active
if (!getProxy().isActive()) return false;
@@ -1015,6 +1072,7 @@ protected ModularWindow createSlotManualWindow(final EntityPlayer player) {
.endAtSlot(SLOT_MANUAL_START + SLOT_MANUAL_SIZE - 1)
.phantom(false)
.background(getGUITextureSet().getItemSlot())
+ .widgetCreator(slot -> new SlotWidget(slot).setChangeListener(this::resetCraftingInputRecipeMap))
.build()
.setPos(7, 7));
return builder.build();
diff --git a/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputSlave.java b/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputSlave.java
index 35db434a32a..73216f46743 100644
--- a/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputSlave.java
+++ b/src/main/java/gregtech/common/tileentities/machines/MTEHatchCraftingInputSlave.java
@@ -23,6 +23,7 @@
import gregtech.api.interfaces.IDataCopyable;
import gregtech.api.interfaces.ITexture;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.logic.ProcessingLogic;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.metatileentity.implementations.MTEHatchInputBus;
import gregtech.api.render.TextureFactory;
@@ -163,6 +164,11 @@ public boolean supportsFluids() {
return getMaster() != null && getMaster().supportsFluids();
}
+ @Override
+ public ItemStack[] getSharedItems() {
+ return getMaster() != null ? getMaster().getSharedItems() : new ItemStack[0];
+ }
+
@Override
public boolean justUpdated() {
return getMaster() != null && getMaster().justUpdated();
@@ -291,4 +297,9 @@ public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompou
public List getItemsForHoloGlasses() {
return getMaster() != null ? getMaster().getItemsForHoloGlasses() : null;
}
+
+ @Override
+ public void setProcessingLogic(ProcessingLogic pl) {
+ if (getMaster() != null) getMaster().setProcessingLogic(pl);
+ }
}
diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/MTEMultiSolidifier.java b/src/main/java/gregtech/common/tileentities/machines/multi/MTEMultiSolidifier.java
index 65061575a23..ef409934211 100644
--- a/src/main/java/gregtech/common/tileentities/machines/multi/MTEMultiSolidifier.java
+++ b/src/main/java/gregtech/common/tileentities/machines/multi/MTEMultiSolidifier.java
@@ -32,6 +32,7 @@
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.FluidStack;
+import org.apache.commons.lang3.ArrayUtils;
import org.jetbrains.annotations.NotNull;
import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
@@ -435,12 +436,16 @@ protected CheckRecipeResult doCheckRecipe() {
CheckRecipeResult result = CheckRecipeResultRegistry.NO_RECIPE;
// check crafting input hatches first
- if (supportsCraftingMEBuffer()) {
- for (IDualInputHatch dualInputHatch : mDualInputHatches) {
- for (var it = dualInputHatch.inventories(); it.hasNext();) {
- IDualInputInventory slot = it.next();
- processingLogic.setInputItems(slot.getItemInputs());
+ for (IDualInputHatch dualInputHatch : mDualInputHatches) {
+ ItemStack[] sharedItems = dualInputHatch.getSharedItems();
+ for (var it = dualInputHatch.inventories(); it.hasNext();) {
+ IDualInputInventory slot = it.next();
+
+ if (!slot.isEmpty() && processingLogic.craftingPatternHandler(slot)) {
+
+ processingLogic.setInputItems(ArrayUtils.addAll(sharedItems, slot.getItemInputs()));
processingLogic.setInputFluids(slot.getFluidInputs());
+
CheckRecipeResult foundResult = processingLogic.process();
if (foundResult.wasSuccessful()) {
return foundResult;