From 2e0ec6ae9ef2c92a5d469a34e38ae86a1b3a1424 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 4 Jun 2025 22:53:28 -0400 Subject: [PATCH] Add ingredient item value ItemStack deduplication Inspired by AllTheLeaks, but done slightly differently to hopefully be compatible with more mods --- .../IngredientItemValueMixin.java | 20 +++++++++++ .../IngredientMixin.java | 17 ++++++++++ .../recipe/IngredientValueDeduplicator.java | 33 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/recipe/IngredientValueDeduplicator.java diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java new file mode 100644 index 00000000..8e0981cc --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.forge.mixin.perf.ingredient_item_deduplication; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(Ingredient.ItemValue.class) +public class IngredientItemValueMixin { + /** + * @author embeddedt + * @reason Defensively copy the item so that the deduplication is not visible to most mods (unless they introspect + * the item held within this object directly). This is necessary since some mods edit the returned stack. + */ + @ModifyExpressionValue(method = "getItems", at = @At(value = "FIELD", target = "Lnet/minecraft/world/item/crafting/Ingredient$ItemValue;item:Lnet/minecraft/world/item/ItemStack;")) + private ItemStack mfix$defensiveCopy(ItemStack original) { + return original.copy(); + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java new file mode 100644 index 00000000..b57f221b --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java @@ -0,0 +1,17 @@ +package org.embeddedt.modernfix.forge.mixin.perf.ingredient_item_deduplication; + +import net.minecraft.world.item.crafting.Ingredient; +import org.embeddedt.modernfix.forge.recipe.IngredientValueDeduplicator; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.stream.Stream; + +@Mixin(Ingredient.class) +public class IngredientMixin { + @ModifyVariable(method = "", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private static Stream injectDeduplicationPass(Stream stream) { + return stream.map(IngredientValueDeduplicator::deduplicate); + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/recipe/IngredientValueDeduplicator.java b/forge/src/main/java/org/embeddedt/modernfix/forge/recipe/IngredientValueDeduplicator.java new file mode 100644 index 00000000..00046338 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/recipe/IngredientValueDeduplicator.java @@ -0,0 +1,33 @@ +package org.embeddedt.modernfix.forge.recipe; + +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; +import net.minecraft.world.item.ItemStackLinkedSet; +import net.minecraft.world.item.crafting.Ingredient; + +/** + * @author embeddedt (original inspiration from Uncandango's AllTheLeaks mod) + */ +public class IngredientValueDeduplicator { + private static final ObjectOpenCustomHashSet VALUES = new ObjectOpenCustomHashSet<>(new Hash.Strategy<>() { + @Override + public int hashCode(Ingredient.ItemValue o) { + return o == null ? 0 : ItemStackLinkedSet.TYPE_AND_TAG.hashCode(o.item); + } + + @Override + public boolean equals(Ingredient.ItemValue a, Ingredient.ItemValue b) { + return a == b || a != null && b != null && ItemStackLinkedSet.TYPE_AND_TAG.equals(a.item, b.item) && a.item.getCount() == b.item.getCount(); + } + }); + + public static Ingredient.Value deduplicate(Ingredient.Value value) { + if (value instanceof Ingredient.ItemValue) { + synchronized (VALUES) { + return VALUES.addOrGet((Ingredient.ItemValue)value); + } + } else { + return value; + } + } +}