diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java new file mode 100644 index 00000000..34b6debf --- /dev/null +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/ingredient_item_deduplication/IngredientItemValueMixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.neoforge.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/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java new file mode 100644 index 00000000..3d8129bb --- /dev/null +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/ingredient_item_deduplication/IngredientMixin.java @@ -0,0 +1,17 @@ +package org.embeddedt.modernfix.neoforge.mixin.perf.ingredient_item_deduplication; + +import net.minecraft.world.item.crafting.Ingredient; +import org.embeddedt.modernfix.neoforge.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 = "(Ljava/util/stream/Stream;)V", at = @At("HEAD"), argsOnly = true, ordinal = 0) + private static Stream injectDeduplicationPass(Stream stream) { + return stream.map(IngredientValueDeduplicator::deduplicate); + } +} diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/recipe/IngredientValueDeduplicator.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/recipe/IngredientValueDeduplicator.java new file mode 100644 index 00000000..d83ac167 --- /dev/null +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/recipe/IngredientValueDeduplicator.java @@ -0,0 +1,33 @@ +package org.embeddedt.modernfix.neoforge.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; + } + } +}