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;