Add ingredient item value ItemStack deduplication

Inspired by AllTheLeaks, but done slightly differently to hopefully
be compatible with more mods
This commit is contained in:
embeddedt 2025-06-04 22:53:28 -04:00
parent a170f072ff
commit 2e0ec6ae9e
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
3 changed files with 70 additions and 0 deletions

View File

@ -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();
}
}

View File

@ -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 = "<init>", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private static Stream<? extends Ingredient.Value> injectDeduplicationPass(Stream<? extends Ingredient.Value> stream) {
return stream.map(IngredientValueDeduplicator::deduplicate);
}
}

View File

@ -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<Ingredient.ItemValue> 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;
}
}
}