diff --git a/src/main/java/appeng/items/misc/ItemEncodedPattern.java b/src/main/java/appeng/items/misc/ItemEncodedPattern.java index 71b2baaf6..fc0d655ea 100644 --- a/src/main/java/appeng/items/misc/ItemEncodedPattern.java +++ b/src/main/java/appeng/items/misc/ItemEncodedPattern.java @@ -29,6 +29,8 @@ import appeng.helpers.InvalidPatternHelper; import appeng.helpers.PatternHelper; import appeng.items.AEBaseItem; import appeng.util.Platform; +import appeng.util.item.ItemStackHashStrategy; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; @@ -45,12 +47,12 @@ import net.minecraftforge.fml.relauncher.SideOnly; import java.util.List; import java.util.Map; -import java.util.WeakHashMap; - public class ItemEncodedPattern extends AEBaseItem implements ICraftingPatternItem { + + private static final ItemStackHashStrategy hashStrategy = ItemStackHashStrategy.comparingAllButCount(); // rather simple client side caching. - private static final Map SIMPLE_CACHE = new WeakHashMap<>(); + private static final Map SIMPLE_CACHE = new Object2ObjectOpenCustomHashMap<>(hashStrategy); public ItemEncodedPattern() { this.setMaxStackSize(64); @@ -70,6 +72,7 @@ public class ItemEncodedPattern extends AEBaseItem implements ICraftingPatternIt private boolean clearPattern(final ItemStack stack, final EntityPlayer player) { if (player.isSneaking()) { + SIMPLE_CACHE.remove(stack); if (Platform.isClient()) { return false; } diff --git a/src/main/java/appeng/util/item/ItemStackHashStrategy.java b/src/main/java/appeng/util/item/ItemStackHashStrategy.java new file mode 100644 index 000000000..66cfdb30a --- /dev/null +++ b/src/main/java/appeng/util/item/ItemStackHashStrategy.java @@ -0,0 +1,101 @@ +package appeng.util.item; + +import it.unimi.dsi.fastutil.Hash; +import net.minecraft.item.ItemStack; + +import javax.annotation.Nullable; +import java.util.Objects; + +/** + * Original code by Eutro, butchered by Prototypetrousers. + * A configurable generator of hashing strategies, allowing for consideration of select properties of ItemStacks when + * considering equality. + */ +public interface ItemStackHashStrategy extends Hash.Strategy { + /** + * @return a builder object for producing a custom ItemStackHashStrategy. + */ + static ItemStackHashStrategyBuilder builder() { + return new ItemStackHashStrategyBuilder(); + } + + /** + * Generates an ItemStackHash configured to compare every aspect of ItemStacks except the number + * of items in the stack. + * + * @return the ItemStackHashStrategy as described above. + */ + static ItemStackHashStrategy comparingAllButCount() { + return builder().compareItem(true) + .compareDamage(true) + .compareTag(true) + .build(); + } + + /** + * Builder pattern class for generating customized ItemStackHashStrategy + */ + class ItemStackHashStrategyBuilder { + private boolean item, damage, tag; + + /** + * Defines whether the Item type should be considered for equality. + * + * @param choice {@code true} to consider this property, {@code false} to ignore it. + * @return {@code this} + */ + public ItemStackHashStrategyBuilder compareItem(boolean choice) { + item = choice; + return this; + } + + /** + * Defines whether damage values should be considered for equality. + * + * @param choice {@code true} to consider this property, {@code false} to ignore it. + * @return {@code this} + */ + public ItemStackHashStrategyBuilder compareDamage(boolean choice) { + damage = choice; + return this; + } + + /** + * Defines whether NBT Tags should be considered for equality. + * + * @param choice {@code true} to consider this property, {@code false} to ignore it. + * @return {@code this} + */ + public ItemStackHashStrategyBuilder compareTag(boolean choice) { + tag = choice; + return this; + } + + /** + * @return the ItemStackHashStrategy as configured by "compare" methods. + */ + public ItemStackHashStrategy build() { + return new ItemStackHashStrategy() { + @Override + public int hashCode(@Nullable ItemStack o) { + return o == null || o.isEmpty() ? 0 : Objects.hash( + item ? o.getItem() : null, + damage ? o.getItemDamage() : null, + tag ? o.getTagCompound() : null + ); + } + + @Override + public boolean equals(@Nullable ItemStack a, @Nullable ItemStack b) { + if (a == null || a.isEmpty()) return b == null || b.isEmpty(); + if (b == null || b.isEmpty()) return false; + + return (!item || a.getItem() == b.getItem()) && + (!damage || a.getItemDamage() == b.getItemDamage()) && + (!tag || Objects.equals(a.getTagCompound(), b.getTagCompound())); + } + }; + } + } +} +