22
33import it .unimi .dsi .fastutil .Hash ;
44import it .unimi .dsi .fastutil .objects .ObjectOpenCustomHashSet ;
5+ import it .unimi .dsi .fastutil .objects .Reference2ObjectMaps ;
6+ import net .minecraft .world .item .ItemStack ;
57import net .minecraft .world .item .ItemStackLinkedSet ;
68import net .minecraft .world .item .crafting .Ingredient ;
9+ import org .embeddedt .modernfix .neoforge .mixin .perf .ingredient_item_deduplication .PatchedDataComponentMapAccessor ;
710
811/**
912 * @author embeddedt (original inspiration from Uncandango's AllTheLeaks mod)
@@ -15,9 +18,54 @@ public int hashCode(Ingredient.ItemValue o) {
1518 return o == null ? 0 : ItemStackLinkedSet .TYPE_AND_TAG .hashCode (o .item ());
1619 }
1720
21+ private boolean areComponentsSame (ItemStack a , ItemStack b ) {
22+ // Compare using stricter logic than vanilla: require the prototype maps to be identity-equal, and require
23+ // the values in the patch to also be identity-equal. This works around Neo allowing Holder.Reference objects
24+ // made with the server & client registries to be considered equal.
25+ if (a .getComponents () instanceof PatchedDataComponentMapAccessor aComps && b .getComponents () instanceof PatchedDataComponentMapAccessor bComps ) {
26+ if (aComps .mfix$getPrototype () != bComps .mfix$getPrototype ()) {
27+ return false ;
28+ }
29+ var aPatch = aComps .mfix$getPatch ();
30+ var bPatch = bComps .mfix$getPatch ();
31+ if (aPatch != bPatch ) {
32+ if (aPatch .size () != bPatch .size ()) {
33+ return false ;
34+ }
35+ for (var entry : Reference2ObjectMaps .fastIterable (aPatch )) {
36+ var value = bPatch .get (entry .getKey ());
37+ if (value == null ) {
38+ return false ;
39+ }
40+ if (value .isPresent () != entry .getValue ().isPresent ()) {
41+ return false ;
42+ } else if (value .isPresent () && value .get () != entry .getValue ().get ()) {
43+ return false ;
44+ }
45+ }
46+ }
47+ return true ;
48+ } else {
49+ return a .getComponents () == b .getComponents ();
50+ }
51+ }
52+
53+ private boolean areStacksSame (ItemStack a , ItemStack b ) {
54+ if (!a .is (b .getItem ())) {
55+ return false ;
56+ }
57+ if (a .isEmpty () != b .isEmpty ()) {
58+ return false ;
59+ }
60+ if (!areComponentsSame (a , b )) {
61+ return false ;
62+ }
63+ return a .getCount () == b .getCount ();
64+ }
65+
1866 @ Override
1967 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 ( );
68+ return a == b || a != null && b != null && areStacksSame (a .item (), b .item ());
2169 }
2270 });
2371
0 commit comments