From 79d4df87ce074a6921d581e5384a4490bb25e441 Mon Sep 17 00:00:00 2001 From: lordIcocain <62835225+lordIcocain@users.noreply.github.com> Date: Sun, 12 Jan 2025 18:05:06 +0200 Subject: [PATCH] Cribs super recipe check (#3608) Co-authored-by: Martin Robertz Co-authored-by: Maya <10861407+serenibyss@users.noreply.github.com> --- .../api/logic/AbstractProcessingLogic.java | 2 + .../gregtech/api/logic/ProcessingLogic.java | 48 ++++++++++++ .../implementations/MTEMultiBlockBase.java | 19 +++-- .../gregtech/api/objects/GTDualInputs.java | 10 +++ .../machines/IDualInputHatch.java | 6 ++ .../machines/IDualInputInventory.java | 7 ++ .../machines/MTEHatchCraftingInputME.java | 76 ++++++++++++++++++- .../machines/MTEHatchCraftingInputSlave.java | 11 +++ .../machines/multi/MTEMultiSolidifier.java | 15 ++-- 9 files changed, 179 insertions(+), 15 deletions(-) create mode 100644 src/main/java/gregtech/api/objects/GTDualInputs.java 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..3a381ee2041 100644 --- a/src/main/java/gregtech/api/logic/ProcessingLogic.java +++ b/src/main/java/gregtech/api/logic/ProcessingLogic.java @@ -1,6 +1,10 @@ package gregtech.api.logic; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -10,6 +14,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 +22,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 +35,8 @@ public class ProcessingLogic extends AbstractProcessingLogic { protected ItemStack[] inputItems; protected FluidStack[] inputFluids; protected boolean isRecipeLocked; + protected IDualInputInventory craftingPattern; + protected Map> craftingPatternRecipeCache = new HashMap<>(); public ProcessingLogic() {} @@ -63,6 +71,33 @@ public ProcessingLogic setSpecialSlotItem(ItemStack specialSlotItem) { return getThis(); } + public boolean craftingPatternHandler(IDualInputInventory slot) { + if (needWipeCraftingPatternRecipeCache) { + craftingPatternRecipeCache.clear(); + needWipeCraftingPatternRecipeCache = false; + } + + if (craftingPatternRecipeCache.containsKey(slot)) { + craftingPattern = slot; + return true; + } else { + GTDualInputs inputs = slot.getPatternInputs(); + setInputItems(inputs.inputItems); + setInputFluids(inputs.inputFluid); + Set recipes = findRecipeMatches(preProcess()).collect(Collectors.toSet()); + if (!recipes.isEmpty()) { + craftingPatternRecipeCache.put(slot, recipes); + craftingPattern = slot; + return true; + } + return false; + } + } + + public void removeEntryCraftingPatternRecipeCache(IDualInputInventory slot) { + craftingPatternRecipeCache.remove(slot); + } + /** * Enables single recipe locking mode. */ @@ -85,6 +120,7 @@ public ProcessingLogic clear() { this.calculatedEut = 0; this.duration = 0; this.calculatedParallels = 0; + this.craftingPattern = null; return getThis(); } @@ -106,6 +142,18 @@ public CheckRecipeResult process() { inputFluids = new FluidStack[0]; } + if (craftingPattern != null) { + Set matchedRecipes = craftingPatternRecipeCache.get(craftingPattern); + for (GTRecipe matchedRecipe : matchedRecipes) { + if (matchedRecipe.maxParallelCalculatedByInputs(1, inputFluids, inputItems) == 1) { + CalculationResult foundResult = validateAndCalculateRecipe(matchedRecipe); + return foundResult.checkRecipeResult; + } + } + craftingPattern = null; + 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..755b023b24b 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) { 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..fd7d291c29d 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; @@ -116,6 +119,7 @@ public interface SharedItemGetter { private final List itemInventory; private final List fluidInventory; private final SharedItemGetter sharedItemGetter; + private final GTUtility.ItemId itemId; public PatternSlot(ItemStack pattern, World world, SharedItemGetter getter) { this.pattern = pattern; @@ -124,6 +128,7 @@ public PatternSlot(ItemStack pattern, World world, SharedItemGetter getter) { this.itemInventory = new ArrayList<>(); this.fluidInventory = new ArrayList<>(); this.sharedItemGetter = getter; + this.itemId = GTUtility.ItemId.create(pattern); } public PatternSlot(ItemStack pattern, NBTTagCompound nbt, World world, SharedItemGetter getter) { @@ -133,6 +138,7 @@ public PatternSlot(ItemStack pattern, NBTTagCompound nbt, World world, SharedIte this.itemInventory = new ArrayList<>(); this.fluidInventory = new ArrayList<>(); this.sharedItemGetter = getter; + this.itemId = GTUtility.ItemId.create(pattern); NBTTagList inv = nbt.getTagList("inventory", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < inv.tagCount(); i++) { NBTTagCompound tagItemStack = inv.getCompoundTagAt(i); @@ -198,14 +204,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 +225,43 @@ public ICraftingPatternDetails getPatternDetails() { return patternDetails; } + @Override + 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; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PatternSlot that = (PatternSlot) o; + return Objects.equals(pattern, that.pattern); + } + + @Override + public int hashCode() { + return itemId.hashCode(); + } + public void refund(AENetworkProxy proxy, BaseActionSource src) throws GridAccessException { IMEMonitor sg = proxy.getStorage() .getItemInventory(); @@ -324,6 +368,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound nbt) { private static final int MANUAL_SLOT_WINDOW = 10; private BaseActionSource requestSource = null; private @Nullable AENetworkProxy gridProxy = null; + public List processingLogics = new ArrayList<>(); // holds all internal inventories private final PatternSlot[] internalInventory = new PatternSlot[MAX_PATTERN_COUNT]; @@ -785,6 +830,9 @@ private void onPatternChange(int index, ItemStack newItem) { if (originalPattern.hasChanged(newItem, world)) { try { originalPattern.refund(getProxy(), getRequest()); + for (ProcessingLogic pl : processingLogics) { + pl.removeEntryCraftingPatternRecipeCache(originalPattern); + } } catch (GridAccessException ignored) {} internalInventory[index] = null; needPatternSync = true; @@ -803,6 +851,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 +859,22 @@ public ItemStack[] getSharedItems() { return ArrayExt.withoutNulls(sharedItems, ItemStack[]::new); } + @Override + public void setProcessingLogic(ProcessingLogic pl) { + if (!processingLogics.contains(pl)) { + processingLogics.add(Objects.requireNonNull(pl)); + } + } + + private void resetCraftingInputRecipeMap() { + for (ProcessingLogic pl : processingLogics) { + for (PatternSlot sl : internalInventory) { + if (sl == null) continue; + pl.removeEntryCraftingPatternRecipeCache(sl); + } + } + } + @Override public void getWailaBody(ItemStack itemStack, List currenttip, IWailaDataAccessor accessor, IWailaConfigHandler config) { @@ -982,6 +1047,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 +1086,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;