From f596531798c7afd8a63fd404c557c7ba7f06493c Mon Sep 17 00:00:00 2001 From: Anton Bulakh Date: Sat, 12 Jun 2021 17:58:35 +0300 Subject: [PATCH] Fix pattern cache (#3010) * Fix pattern cache * Address review comments --- .../storage/tracker/ItemStorageTracker.java | 32 ++++--------------- .../refinedstorage/item/PatternItem.java | 16 +++++++--- .../refinedstorage/util/ItemStackKey.java | 26 +++++++++++++++ 3 files changed, 45 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/refinedmods/refinedstorage/util/ItemStackKey.java diff --git a/src/main/java/com/refinedmods/refinedstorage/apiimpl/storage/tracker/ItemStorageTracker.java b/src/main/java/com/refinedmods/refinedstorage/apiimpl/storage/tracker/ItemStorageTracker.java index 407b09732..18fc55b60 100644 --- a/src/main/java/com/refinedmods/refinedstorage/apiimpl/storage/tracker/ItemStorageTracker.java +++ b/src/main/java/com/refinedmods/refinedstorage/apiimpl/storage/tracker/ItemStorageTracker.java @@ -2,7 +2,7 @@ package com.refinedmods.refinedstorage.apiimpl.storage.tracker; import com.refinedmods.refinedstorage.api.storage.tracker.IStorageTracker; import com.refinedmods.refinedstorage.api.storage.tracker.StorageTrackerEntry; -import com.refinedmods.refinedstorage.apiimpl.API; +import com.refinedmods.refinedstorage.util.ItemStackKey; import com.refinedmods.refinedstorage.util.StackUtils; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; @@ -17,7 +17,7 @@ public class ItemStorageTracker implements IStorageTracker { private static final String NBT_NAME = "Name"; private static final String NBT_TIME = "Time"; - private final Map changes = new HashMap<>(); + private final Map changes = new HashMap<>(); private final Runnable listener; public ItemStorageTracker(Runnable listener) { @@ -26,14 +26,14 @@ public class ItemStorageTracker implements IStorageTracker { @Override public void changed(PlayerEntity player, ItemStack stack) { - changes.put(new Key(stack), new StorageTrackerEntry(System.currentTimeMillis(), player.getName().getString())); + changes.put(new ItemStackKey(stack), new StorageTrackerEntry(System.currentTimeMillis(), player.getName().getString())); listener.run(); } @Override public StorageTrackerEntry get(ItemStack stack) { - return changes.get(new Key(stack)); + return changes.get(new ItemStackKey(stack)); } public void readFromNbt(ListNBT list) { @@ -43,7 +43,7 @@ public class ItemStorageTracker implements IStorageTracker { ItemStack stack = StackUtils.deserializeStackFromNbt(tag.getCompound(NBT_STACK)); if (!stack.isEmpty()) { - changes.put(new Key(stack), new StorageTrackerEntry(tag.getLong(NBT_TIME), tag.getString(NBT_NAME))); + changes.put(new ItemStackKey(stack), new StorageTrackerEntry(tag.getLong(NBT_TIME), tag.getString(NBT_NAME))); } } } @@ -51,34 +51,16 @@ public class ItemStorageTracker implements IStorageTracker { public ListNBT serializeNbt() { ListNBT list = new ListNBT(); - for (Map.Entry entry : changes.entrySet()) { + for (Map.Entry entry : changes.entrySet()) { CompoundNBT tag = new CompoundNBT(); tag.putLong(NBT_TIME, entry.getValue().getTime()); tag.putString(NBT_NAME, entry.getValue().getName()); - tag.put(NBT_STACK, StackUtils.serializeStackToNbt(entry.getKey().stack)); + tag.put(NBT_STACK, StackUtils.serializeStackToNbt(entry.getKey().getStack())); list.add(tag); } return list; } - - private static class Key { - private final ItemStack stack; - - public Key(ItemStack stack) { - this.stack = stack; - } - - @Override - public boolean equals(Object other) { - return other instanceof Key && API.instance().getComparer().isEqualNoQuantity(stack, ((Key) other).stack); - } - - @Override - public int hashCode() { - return API.instance().getItemStackHashCode(stack); - } - } } diff --git a/src/main/java/com/refinedmods/refinedstorage/item/PatternItem.java b/src/main/java/com/refinedmods/refinedstorage/item/PatternItem.java index 17d69a4b8..1e7522bd0 100644 --- a/src/main/java/com/refinedmods/refinedstorage/item/PatternItem.java +++ b/src/main/java/com/refinedmods/refinedstorage/item/PatternItem.java @@ -10,6 +10,7 @@ import com.refinedmods.refinedstorage.apiimpl.autocrafting.CraftingPattern; import com.refinedmods.refinedstorage.apiimpl.autocrafting.CraftingPatternFactory; import com.refinedmods.refinedstorage.render.Styles; import com.refinedmods.refinedstorage.render.tesr.PatternItemStackTileRenderer; +import com.refinedmods.refinedstorage.util.ItemStackKey; import com.refinedmods.refinedstorage.util.RenderUtils; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.ITooltipFlag; @@ -35,7 +36,7 @@ import java.util.Set; import java.util.stream.Collectors; public class PatternItem extends Item implements ICraftingPatternProvider { - private static final Map CACHE = new HashMap<>(); + private static final Map CACHE = new HashMap<>(); private static final String NBT_VERSION = "Version"; private static final String NBT_INPUT_SLOT = "Input_%d"; @@ -53,11 +54,18 @@ public class PatternItem extends Item implements ICraftingPatternProvider { } public static ICraftingPattern fromCache(World world, ItemStack stack) { - if (!CACHE.containsKey(stack)) { - CACHE.put(stack, CraftingPatternFactory.INSTANCE.create(world, null, stack)); + ICraftingPattern pattern = CACHE.computeIfAbsent( + new ItemStackKey(stack), + s -> CraftingPatternFactory.INSTANCE.create(world, null, s.getStack()) + ); + + // A number that is not too crazy but hopefully is not normally reachable, + // just reset the cache to keep its size limited so this is not a memory leak + if (CACHE.size() > 16384) { + CACHE.clear(); } - return CACHE.get(stack); + return pattern; } @Override diff --git a/src/main/java/com/refinedmods/refinedstorage/util/ItemStackKey.java b/src/main/java/com/refinedmods/refinedstorage/util/ItemStackKey.java new file mode 100644 index 000000000..c4b461a94 --- /dev/null +++ b/src/main/java/com/refinedmods/refinedstorage/util/ItemStackKey.java @@ -0,0 +1,26 @@ +package com.refinedmods.refinedstorage.util; + +import com.refinedmods.refinedstorage.apiimpl.API; +import net.minecraft.item.ItemStack; + +public final class ItemStackKey { + private final ItemStack stack; + + public ItemStackKey(ItemStack stack) { + this.stack = stack; + } + + public ItemStack getStack() { + return stack; + } + + @Override + public boolean equals(Object other) { + return other instanceof ItemStackKey && API.instance().getComparer().isEqualNoQuantity(stack, ((ItemStackKey) other).stack); + } + + @Override + public int hashCode() { + return API.instance().getItemStackHashCode(stack); + } +}