From b4cca9227e275d4c78ae28b5e3b89692ed67909b Mon Sep 17 00:00:00 2001 From: Len <40720638+destro174@users.noreply.github.com> Date: Fri, 26 Dec 2025 00:14:22 +0100 Subject: [PATCH] Add ItemMatcher.java --- .../alttd/playershops/utils/ItemMatcher.java | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 src/main/java/com/alttd/playershops/utils/ItemMatcher.java diff --git a/src/main/java/com/alttd/playershops/utils/ItemMatcher.java b/src/main/java/com/alttd/playershops/utils/ItemMatcher.java new file mode 100644 index 0000000..dafdb3a --- /dev/null +++ b/src/main/java/com/alttd/playershops/utils/ItemMatcher.java @@ -0,0 +1,335 @@ +package com.alttd.playershops.utils; + +import org.bukkit.attribute.Attribute; +import org.bukkit.block.BlockState; +import org.bukkit.block.ShulkerBox; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.*; +import org.bukkit.map.MapView; +import org.bukkit.potion.PotionEffect; + +import java.util.*; + +public class ItemMatcher { + + private final static List matcherList = new ArrayList<>(); + + static { + // DisplayName + matcherList.add( + (meta1, meta2) -> + Objects.equals(meta1.displayName(), meta2.displayName()) + ); + // Damage + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof Damageable damageable1 && meta2 instanceof Damageable damageable2) { + return damageable1.getDamage() == damageable2.getDamage(); + } + return true; + } + ); + // Enchants + matcherList.add( + (meta1, meta2) -> { + if (meta1.hasEnchants() != meta2.hasEnchants()) { + return false; + } + + if (meta1.hasEnchants()) { + final Map enchants1 = meta1.getEnchants(); + final Map enchants2 = meta2.getEnchants(); + return listMatches(enchants1.entrySet(), enchants2.entrySet()); + } + + return true; + } + ); + // Potions + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof PotionMeta potion1 && meta2 instanceof PotionMeta potion2) { + if (potion1.hasColor() != potion2.hasColor()) { + return false; + } + + if (potion1.hasColor() && !Objects.equals(potion1.getColor(), potion2.getColor())) { + return false; + } + + if (potion1.hasCustomEffects() != potion2.hasCustomEffects()) { + return false; + } + + if (potion1.hasCustomEffects() && !Arrays.deepEquals(potion1.getCustomEffects().toArray(), potion2.getCustomEffects().toArray())) { + return false; + } + + if (potion1.getBasePotionType() != null && potion2.getBasePotionType() != null) { + List effects1 = new ArrayList<>(); + List effects2 = new ArrayList<>(); + + if (potion1.getBasePotionType() != null) { + effects1.addAll(potion1.getBasePotionType().getPotionEffects()); + } + if (potion1.hasCustomEffects()) { + effects1.addAll(potion1.getCustomEffects()); + } + if (potion2.getBasePotionType() != null) { + effects2.addAll(potion2.getBasePotionType().getPotionEffects()); + } + if (potion2.hasCustomEffects()) { + effects2.addAll(potion2.getCustomEffects()); + } + return listMatches(effects1, effects2); + } + + } + return true; + } + ); + // Attributes + matcherList.add( + (meta1, meta2) -> { + if (meta1.hasAttributeModifiers() != meta2.hasAttributeModifiers()) { + return false; + } + if (meta1.hasAttributeModifiers() && meta2.hasAttributeModifiers()) { + final Set set1 = Objects.requireNonNull(meta1.getAttributeModifiers()).keySet(); + final Set set2 = Objects.requireNonNull(meta2.getAttributeModifiers()).keySet(); + for(final Attribute att : set1) { + if(!set2.contains(att)) { + return false; + } else if(!meta1.getAttributeModifiers().get(att).equals(meta2.getAttributeModifiers().get(att))) { + return false; + } + } + } + return true; + } + ); + // Itemflags + matcherList.add( + (meta1, meta2) -> { + return Arrays.deepEquals(meta1.getItemFlags().toArray(), meta2.getItemFlags().toArray()); + } + ); + // Books + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof BookMeta bookMeta1 && meta2 instanceof BookMeta bookMeta2) { + if (bookMeta1.hasTitle() != bookMeta2.hasTitle()) { + return false; + } + if (bookMeta1.hasTitle() && !Objects.equals(bookMeta1.getTitle(), bookMeta2.getTitle())) { + return false; + } + if (bookMeta1.hasPages() != bookMeta2.hasPages()) { + return false; + } + if (bookMeta1.hasPages() && !bookMeta1.getPages().equals(bookMeta2.getPages())) { + return false; + } + if (bookMeta1.hasAuthor() != bookMeta2.hasAuthor()) { + return false; + } + if (bookMeta1.hasAuthor() && !Objects.equals(bookMeta1.getAuthor(), bookMeta2.getAuthor())) { + return false; + } + if (bookMeta1.hasGeneration() != bookMeta2.hasGeneration()) { + return false; + } + return !bookMeta1.hasGeneration() || Objects.equals(bookMeta1.getGeneration(), bookMeta2.getGeneration()); + } + return true; + } + ); + // Fireworks + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof FireworkMeta fireworkMeta1 && meta2 instanceof FireworkMeta fireworkMeta2) { + if (fireworkMeta1.hasEffects() != fireworkMeta2.hasEffects()) { + return false; + } + if (!fireworkMeta1.getEffects().equals(fireworkMeta2.getEffects())) { + return false; + } + return fireworkMeta1.getPower() == fireworkMeta2.getPower(); + } + return true; + } + ); + // Banners + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof BannerMeta bannerMeta1 && meta2 instanceof BannerMeta bannerMeta2) { + if (bannerMeta1.numberOfPatterns() != bannerMeta2.numberOfPatterns()) { + return false; + } + return new HashSet<>(bannerMeta1.getPatterns()).containsAll(bannerMeta2.getPatterns()); + } + return true; + } + ); + // Skulls/heads + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof SkullMeta skullMeta1 && meta2 instanceof SkullMeta skullMeta2) { + return Objects.equals(skullMeta1.getOwningPlayer(), skullMeta2.getOwningPlayer()); + } + return true; + } + ); + // Bundles + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof BundleMeta bundleMeta1 && meta2 instanceof BundleMeta bundleMeta2) { + if (bundleMeta1.hasItems() != bundleMeta2.hasItems()) { + return false; + } + if (bundleMeta1.hasItems()) { + return listMatches(bundleMeta1.getItems(), bundleMeta2.getItems()); + } + } + return true; + } + ); + // Maps + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof MapMeta mapMeta1 && meta2 instanceof MapMeta mapMeta2) { + if (mapMeta1.hasMapView() != mapMeta2.hasMapView()) { + return false; + } + // TODO -- do we need checks on color? +// mapMeta1.getColor() + MapView mapView1 = mapMeta1.getMapView(); + MapView mapView2 = mapMeta2.getMapView(); + if (mapView1 == null || mapView2 == null) + return false; + + if (mapView1.getId() == mapView2.getId()) + return true; + } + return true; + } + ); + // Leather + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof LeatherArmorMeta leatherArmorMeta1 && meta2 instanceof LeatherArmorMeta leatherArmorMeta2) { + return leatherArmorMeta1.getColor().equals(leatherArmorMeta2.getColor()); + } + return true; + } + ); + // Tropical fishes + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof TropicalFishBucketMeta tropicalFishBucketMeta1 && meta2 instanceof TropicalFishBucketMeta tropicalFishBucketMeta2) { + if (tropicalFishBucketMeta1.hasVariant() != tropicalFishBucketMeta2.hasVariant()) { + return false; + } + return !tropicalFishBucketMeta1.hasVariant() + || (tropicalFishBucketMeta1.getPattern() == tropicalFishBucketMeta2.getPattern() + && tropicalFishBucketMeta1.getBodyColor().equals(tropicalFishBucketMeta2.getBodyColor()) + && tropicalFishBucketMeta1.getPatternColor().equals(tropicalFishBucketMeta2.getPatternColor())); + } + return true; + } + ); + // Axolotls + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof AxolotlBucketMeta axolotlBucketMeta1 && meta2 instanceof AxolotlBucketMeta axolotlBucketMeta2) { + return axolotlBucketMeta1.getVariant() == axolotlBucketMeta2.getVariant(); + } + return true; + } + ); + // Shulkerboxes + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof BlockStateMeta blockStateMeta1 && meta2 instanceof BlockStateMeta blockStateMeta2) { + // extra heavy - Banners, Shulkerboxes, beehive and more? + BlockState blockState1 = blockStateMeta1.getBlockState(); + BlockState blockState2 = blockStateMeta2.getBlockState(); + + if (blockState1 instanceof ShulkerBox shulkerBox1 && blockState2 instanceof ShulkerBox shulkerBox2) { + if (shulkerBox1.getColor() != shulkerBox2.getColor()) + return false; // not the same color + + // Do we need all of the above checks inside the shulker? + if (Arrays.equals(shulkerBox1.getInventory().getContents(), shulkerBox2.getInventory().getContents())) + return true; // same content + } + } + return true; + } + ); + // Suspicious stews + matcherList.add( + (meta1, meta2) -> { + if (meta1 instanceof SuspiciousStewMeta suspiciousStewMeta1 && meta2 instanceof SuspiciousStewMeta suspiciousStewMeta2) { + if (suspiciousStewMeta1.hasCustomEffects() != suspiciousStewMeta2.hasCustomEffects()) { + return false; + } + if (suspiciousStewMeta1.hasCustomEffects()) { + return listMatches(suspiciousStewMeta1.getCustomEffects(), suspiciousStewMeta2.getCustomEffects()); + } + } + return true; + } + ); + } + + public static boolean matches(ItemStack item1, ItemStack item2) { + if (item1 == null && item2 == null) { + return true; + } + + if (item1 == null || item2 == null) { + return true; + } + + if (!item1.getType().equals(item2.getType())) { + return false; + } + + if(item1.isSimilar(item2)) { + return true; + } + + if (item1.hasItemMeta() && item2.hasItemMeta()) { + return metaMatches(item1, item2); + } + + return !item1.hasItemMeta() && !item1.hasItemMeta(); + } + + protected static boolean metaMatches(ItemStack item1, ItemStack item2) { + ItemMeta meta1 = item1.getItemMeta(); + ItemMeta meta2 = item2.getItemMeta(); + + if (meta1 != null && meta2 != null) { + for (Matcher matcher : matcherList) { + boolean result = matcher.match(meta1, meta2); + if (!result) { + return false; + } + } + return true; + } + return meta1 == null && meta2 == null; + } + + private static boolean listMatches(Collection list1, Collection list2) { + return list1.containsAll(list2) && list2.containsAll(list1); + } + + public static interface Matcher { + + boolean match(ItemMeta meta1, ItemMeta meta2); + } +}