Skip to content

Commit 2e0ec6a

Browse files
committed
Add ingredient item value ItemStack deduplication
Inspired by AllTheLeaks, but done slightly differently to hopefully be compatible with more mods
1 parent a170f07 commit 2e0ec6a

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.embeddedt.modernfix.forge.mixin.perf.ingredient_item_deduplication;
2+
3+
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
4+
import net.minecraft.world.item.ItemStack;
5+
import net.minecraft.world.item.crafting.Ingredient;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
9+
@Mixin(Ingredient.ItemValue.class)
10+
public class IngredientItemValueMixin {
11+
/**
12+
* @author embeddedt
13+
* @reason Defensively copy the item so that the deduplication is not visible to most mods (unless they introspect
14+
* the item held within this object directly). This is necessary since some mods edit the returned stack.
15+
*/
16+
@ModifyExpressionValue(method = "getItems", at = @At(value = "FIELD", target = "Lnet/minecraft/world/item/crafting/Ingredient$ItemValue;item:Lnet/minecraft/world/item/ItemStack;"))
17+
private ItemStack mfix$defensiveCopy(ItemStack original) {
18+
return original.copy();
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.embeddedt.modernfix.forge.mixin.perf.ingredient_item_deduplication;
2+
3+
import net.minecraft.world.item.crafting.Ingredient;
4+
import org.embeddedt.modernfix.forge.recipe.IngredientValueDeduplicator;
5+
import org.spongepowered.asm.mixin.Mixin;
6+
import org.spongepowered.asm.mixin.injection.At;
7+
import org.spongepowered.asm.mixin.injection.ModifyVariable;
8+
9+
import java.util.stream.Stream;
10+
11+
@Mixin(Ingredient.class)
12+
public class IngredientMixin {
13+
@ModifyVariable(method = "<init>", at = @At("HEAD"), argsOnly = true, ordinal = 0)
14+
private static Stream<? extends Ingredient.Value> injectDeduplicationPass(Stream<? extends Ingredient.Value> stream) {
15+
return stream.map(IngredientValueDeduplicator::deduplicate);
16+
}
17+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.embeddedt.modernfix.forge.recipe;
2+
3+
import it.unimi.dsi.fastutil.Hash;
4+
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
5+
import net.minecraft.world.item.ItemStackLinkedSet;
6+
import net.minecraft.world.item.crafting.Ingredient;
7+
8+
/**
9+
* @author embeddedt (original inspiration from Uncandango's AllTheLeaks mod)
10+
*/
11+
public class IngredientValueDeduplicator {
12+
private static final ObjectOpenCustomHashSet<Ingredient.ItemValue> VALUES = new ObjectOpenCustomHashSet<>(new Hash.Strategy<>() {
13+
@Override
14+
public int hashCode(Ingredient.ItemValue o) {
15+
return o == null ? 0 : ItemStackLinkedSet.TYPE_AND_TAG.hashCode(o.item);
16+
}
17+
18+
@Override
19+
public boolean equals(Ingredient.ItemValue a, Ingredient.ItemValue b) {
20+
return a == b || a != null && b != null && ItemStackLinkedSet.TYPE_AND_TAG.equals(a.item, b.item) && a.item.getCount() == b.item.getCount();
21+
}
22+
});
23+
24+
public static Ingredient.Value deduplicate(Ingredient.Value value) {
25+
if (value instanceof Ingredient.ItemValue) {
26+
synchronized (VALUES) {
27+
return VALUES.addOrGet((Ingredient.ItemValue)value);
28+
}
29+
} else {
30+
return value;
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)