From ff600295b04c6e055827674b868cb7028fe80468 Mon Sep 17 00:00:00 2001 From: Kli Kli Date: Tue, 20 Aug 2024 19:40:37 +0200 Subject: [PATCH] feat: make vats not accept ingredients if there are already ingredients of another recipe present --- .../digestionvat/DigestionCachedCheck.java | 40 +++++++++++++++++ .../DigestionCraftingBehaviour.java | 27 ++++++++++++ .../FermentationCachedCheck.java | 44 +++++++++++++++++++ .../FermentationCraftingBehaviour.java | 28 ++++++++++++ 4 files changed, 139 insertions(+) diff --git a/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCachedCheck.java b/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCachedCheck.java index 261f512a..cdb3ce8e 100644 --- a/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCachedCheck.java +++ b/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCachedCheck.java @@ -5,6 +5,7 @@ package com.klikli_dev.theurgy.content.apparatus.digestionvat; import com.klikli_dev.theurgy.content.recipe.DigestionRecipe; +import com.klikli_dev.theurgy.content.recipe.FermentationRecipe; import com.klikli_dev.theurgy.content.recipe.input.ItemHandlerWithFluidRecipeInput; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -15,6 +16,7 @@ import net.neoforged.neoforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; +import java.util.Collection; import java.util.Optional; /** @@ -32,6 +34,29 @@ public DigestionCachedCheck(RecipeType type) { this.internal = RecipeManager.createCheck(type); } + private boolean matchesRecipe(RecipeHolder recipe, Collection input) { + var ingredients = recipe.value().getIngredients(); + + // Check if every input ItemStack matches at least one ingredient in the recipe + return input.stream().allMatch(stack -> + ingredients.stream().anyMatch(ingredient -> ingredient.test(stack)) + ); + } + + private Optional> getRecipeFor(Collection input, Level level, @Nullable ResourceLocation lastRecipe) { + var recipeManager = level.getRecipeManager(); + + if (lastRecipe != null) { + var recipe = recipeManager.byKeyTyped(this.type, lastRecipe); + //test only the ingredient without the (separate) fluid ingredient check that the recipe.matches() would. + if (recipe != null && this.matchesRecipe(recipe, input)) { + return Optional.of(recipe); + } + } + + return recipeManager.byType(this.type).stream().filter((entry) -> this.matchesRecipe(entry, input)).findFirst(); + } + private Optional> getRecipeFor(ItemStack stack, Level level, @Nullable ResourceLocation lastRecipe) { var recipeManager = level.getRecipeManager(); if (lastRecipe != null) { @@ -60,6 +85,21 @@ private Optional> getRecipeFor(FluidStack stack, L return recipeManager.byType(this.type).stream().filter((entry) -> entry.value().getFluid().ingredient().test(stack)).findFirst(); } + + /** + * This only checks ingredients, including ingredients already present, not fluids + */ + public Optional> getRecipeFor(Collection input, Level level) { + var optional = this.getRecipeFor(input, level, this.lastRecipe); + if (optional.isPresent()) { + var recipeHolder = optional.get(); + this.lastRecipe = recipeHolder.id(); + return optional; + } else { + return Optional.empty(); + } + } + /** * This only checks ingredients, not fluids */ diff --git a/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCraftingBehaviour.java b/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCraftingBehaviour.java index a1f41c34..114247ef 100644 --- a/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCraftingBehaviour.java +++ b/src/main/java/com/klikli_dev/theurgy/content/apparatus/digestionvat/DigestionCraftingBehaviour.java @@ -19,6 +19,8 @@ import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.IntStream; +import java.util.stream.Stream; public class DigestionCraftingBehaviour extends CraftingBehaviour { @@ -34,6 +36,31 @@ public DigestionCraftingBehaviour(BlockEntity blockEntity, Supplier ingredient.test(stack)); + } + + var ingredientsList = Stream.concat( + IntStream.range(0, this.inputInventorySupplier.get().getSlots()).filter(i -> !this.inputInventorySupplier.get().getStackInSlot(i).isEmpty()).mapToObj(i -> this.inputInventorySupplier.get().getStackInSlot(i)), + Stream.of(stack) + ).toList(); + + if (ingredientsList.size() > 1) { + //if we have any items in the input inventory (= more simulated ingredients than one, which is the one we are checking), we can only process items that share a recipe with already existing items + return this.recipeCachedCheck.getRecipeFor(ingredientsList, this.blockEntity.getLevel()).isPresent(); + } + + //finally if we have an empty inventory we do a simple check if the item is an ingredient of any recipe + return this.isIngredient(stack); + } + @Override public boolean isIngredient(ItemStack stack) { return this.recipeCachedCheck.getRecipeFor(stack, this.blockEntity.getLevel()).isPresent(); diff --git a/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCachedCheck.java b/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCachedCheck.java index 8561babe..a9800c2f 100644 --- a/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCachedCheck.java +++ b/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCachedCheck.java @@ -13,9 +13,16 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.items.IItemHandlerModifiable; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.List; import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; /** * A custom cached check @@ -32,6 +39,29 @@ public FermentationCachedCheck(RecipeType type) { this.internal = RecipeManager.createCheck(type); } + private boolean matchesRecipe(RecipeHolder recipe, Collection input) { + var ingredients = recipe.value().getIngredients(); + + // Check if every input ItemStack matches at least one ingredient in the recipe + return input.stream().allMatch(stack -> + ingredients.stream().anyMatch(ingredient -> ingredient.test(stack)) + ); + } + + private Optional> getRecipeFor(Collection input, Level level, @Nullable ResourceLocation lastRecipe) { + var recipeManager = level.getRecipeManager(); + + if (lastRecipe != null) { + var recipe = recipeManager.byKeyTyped(this.type, lastRecipe); + //test only the ingredient without the (separate) fluid ingredient check that the recipe.matches() would. + if (recipe != null && this.matchesRecipe(recipe, input)) { + return Optional.of(recipe); + } + } + + return recipeManager.byType(this.type).stream().filter((entry) -> this.matchesRecipe(entry, input)).findFirst(); + } + private Optional> getRecipeFor(ItemStack stack, Level level, @Nullable ResourceLocation lastRecipe) { var recipeManager = level.getRecipeManager(); if (lastRecipe != null) { @@ -60,6 +90,20 @@ private Optional> getRecipeFor(FluidStack stack return recipeManager.byType(this.type).stream().filter((entry) -> entry.value().getFluid().ingredient().test(stack)).findFirst(); } + /** + * This only checks ingredients, including ingredients already present, not fluids + */ + public Optional> getRecipeFor(Collection input, Level level) { + var optional = this.getRecipeFor(input, level, this.lastRecipe); + if (optional.isPresent()) { + var recipeHolder = optional.get(); + this.lastRecipe = recipeHolder.id(); + return optional; + } else { + return Optional.empty(); + } + } + /** * This only checks ingredients, not fluids */ diff --git a/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCraftingBehaviour.java b/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCraftingBehaviour.java index 6276e73b..7c47bf32 100644 --- a/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCraftingBehaviour.java +++ b/src/main/java/com/klikli_dev/theurgy/content/apparatus/fermentationvat/FermentationCraftingBehaviour.java @@ -18,6 +18,9 @@ import net.neoforged.neoforge.items.ItemHandlerHelper; import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; public class FermentationCraftingBehaviour extends CraftingBehaviour { @@ -33,6 +36,31 @@ public FermentationCraftingBehaviour(BlockEntity blockEntity, Supplier ingredient.test(stack)); + } + + var ingredientsList = Stream.concat( + IntStream.range(0, this.inputInventorySupplier.get().getSlots()).filter(i -> !this.inputInventorySupplier.get().getStackInSlot(i).isEmpty()).mapToObj(i -> this.inputInventorySupplier.get().getStackInSlot(i)), + Stream.of(stack) + ).toList(); + + if (ingredientsList.size() > 1) { + //if we have any items in the input inventory (= more simulated ingredients than one, which is the one we are checking), we can only process items that share a recipe with already existing items + return this.recipeCachedCheck.getRecipeFor(ingredientsList, this.blockEntity.getLevel()).isPresent(); + } + + //finally if we have an empty inventory we do a simple check if the item is an ingredient of any recipe + return this.isIngredient(stack); + } + @Override public boolean isIngredient(ItemStack stack) { return this.recipeCachedCheck.getRecipeFor(stack, this.blockEntity.getLevel()).isPresent();