فهرست منبع

Rewrite how mob/item/block metadata is tracked/retrieved
Fixes #4720

nossr50 3 سال پیش
والد
کامیت
3be15d3f65
19فایلهای تغییر یافته به همراه477 افزوده شده و 600 حذف شده
  1. 5 0
      Changelog.txt
  2. 1 1
      src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java
  3. 14 14
      src/main/java/com/gmail/nossr50/listeners/EntityListener.java
  4. 10 1
      src/main/java/com/gmail/nossr50/mcMMO.java
  5. 49 0
      src/main/java/com/gmail/nossr50/metadata/BlockMetadataService.java
  6. 110 0
      src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java
  7. 71 0
      src/main/java/com/gmail/nossr50/metadata/MetadataService.java
  8. 1 1
      src/main/java/com/gmail/nossr50/metadata/MobMetaFlagType.java
  9. 187 0
      src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java
  10. 2 2
      src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java
  11. 1 1
      src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java
  12. 1 6
      src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java
  13. 1 22
      src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java
  14. 0 137
      src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/AbstractPersistentDataLayer.java
  15. 0 172
      src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/SpigotPersistentDataLayer_1_13.java
  16. 0 220
      src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/SpigotPersistentDataLayer_1_14.java
  17. 10 10
      src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java
  18. 12 11
      src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
  19. 2 2
      src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java

+ 5 - 0
Changelog.txt

@@ -1,4 +1,9 @@
 Version 2.1.210
+    Fixed a memory leak involving mob metadata
+
+    NOTES:
+    There was a big rewrite in this update relating to how various types of metadata were being tracked/stored/retrieved
+    If you run into issues with this version of mcMMO, please post about it on GitHub
 
 Version 2.1.209
     Fixed a bug where some config files did not get trimmed completely

+ 1 - 1
src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config;
 
-import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
+import com.gmail.nossr50.metadata.MobMetaFlagType;
 
 public class PersistentDataConfig extends BukkitConfig {
     private static PersistentDataConfig instance;

+ 14 - 14
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -10,6 +10,8 @@ import com.gmail.nossr50.events.fake.FakeEntityDamageEvent;
 import com.gmail.nossr50.events.fake.FakeEntityTameEvent;
 import com.gmail.nossr50.events.skills.rupture.McMMOEntityDamageByRuptureEvent;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.metadata.MobMetaFlagType;
+import com.gmail.nossr50.metadata.MobMetadataService;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.runnables.TravelingBlockMetaCleanup;
 import com.gmail.nossr50.skills.archery.Archery;
@@ -19,8 +21,6 @@ import com.gmail.nossr50.skills.taming.Taming;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.util.*;
-import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
-import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
@@ -51,7 +51,7 @@ import org.jetbrains.annotations.NotNull;
 
 public class EntityListener implements Listener {
     private final mcMMO pluginRef;
-    private final @NotNull AbstractPersistentDataLayer persistentDataLayer;
+    private final @NotNull MobMetadataService mobMetadataService;
 
     /**
      * We can use this {@link NamespacedKey} for {@link Enchantment} comparisons to
@@ -61,7 +61,7 @@ public class EntityListener implements Listener {
 
     public EntityListener(final mcMMO pluginRef) {
         this.pluginRef = pluginRef;
-        persistentDataLayer = mcMMO.getCompatibilityManager().getPersistentDataLayer();
+        mobMetadataService = mcMMO.getMetadataService().getMobMetadataService();
     }
 
 //    @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@@ -94,11 +94,11 @@ public class EntityListener implements Listener {
             LivingEntity livingEntity = (LivingEntity) event.getEntity();
 
             //Transfer metadata keys from mob-spawned mobs to new mobs
-            if(persistentDataLayer.hasMobFlags(livingEntity)) {
+            if(mobMetadataService.hasMobFlags(livingEntity)) {
                 for(Entity entity : event.getTransformedEntities()) {
                     if(entity instanceof LivingEntity) {
                         LivingEntity transformedEntity = (LivingEntity) entity;
-                        persistentDataLayer.addMobFlags(livingEntity, transformedEntity);
+                        mobMetadataService.addMobFlags(livingEntity, transformedEntity);
                     }
                 }
             }
@@ -122,8 +122,8 @@ public class EntityListener implements Listener {
             if(event.getEntity() instanceof Enderman) {
                 Enderman enderman = (Enderman) event.getEntity();
 
-                if(!persistentDataLayer.hasMobFlag(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman)) {
-                    persistentDataLayer.flagMetadata(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman);
+                if(!mobMetadataService.hasMobFlag(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman)) {
+                    mobMetadataService.flagMetadata(MobMetaFlagType.EXPLOITED_ENDERMEN, enderman);
                 }
             }
         }
@@ -729,11 +729,11 @@ public class EntityListener implements Listener {
     }
 
     private void trackSpawnedAndPassengers(LivingEntity livingEntity, MobMetaFlagType mobMetaFlagType) {
-        persistentDataLayer.flagMetadata(mobMetaFlagType, livingEntity);
+        mobMetadataService.flagMetadata(mobMetaFlagType, livingEntity);
 
         for(Entity passenger : livingEntity.getPassengers()) {
             if(passenger != null) {
-                persistentDataLayer.flagMetadata(mobMetaFlagType, livingEntity);
+                mobMetadataService.flagMetadata(mobMetaFlagType, livingEntity);
             }
         }
     }
@@ -741,7 +741,7 @@ public class EntityListener implements Listener {
     @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
     public void onEntityBreed(EntityBreedEvent event) {
         if(ExperienceConfig.getInstance().isCOTWBreedingPrevented()) {
-            if(persistentDataLayer.hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getFather()) || persistentDataLayer.hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getMother())) {
+            if(mobMetadataService.hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getFather()) || mobMetadataService.hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, event.getMother())) {
                 event.setCancelled(true);
                 Animals mom = (Animals) event.getMother();
                 Animals father = (Animals) event.getFather();
@@ -1007,12 +1007,12 @@ public class EntityListener implements Listener {
 
         if (!UserManager.hasPlayerDataKey(player)
                 || (ExperienceConfig.getInstance().isNPCInteractionPrevented() && Misc.isNPCEntityExcludingVillagers(livingEntity))
-                || persistentDataLayer.hasMobFlag(MobMetaFlagType.EGG_MOB, livingEntity)
-                || persistentDataLayer.hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, livingEntity)) {
+                || mobMetadataService.hasMobFlag(MobMetaFlagType.EGG_MOB, livingEntity)
+                || mobMetadataService.hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, livingEntity)) {
             return;
         }
 
-        persistentDataLayer.flagMetadata(MobMetaFlagType.PLAYER_TAMED_MOB, livingEntity);
+        mobMetadataService.flagMetadata(MobMetaFlagType.PLAYER_TAMED_MOB, livingEntity);
 
         //Profile not loaded
         if(UserManager.getPlayer(player) == null)

+ 10 - 1
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -18,6 +18,7 @@ import com.gmail.nossr50.database.DatabaseManagerFactory;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.subskills.acrobatics.Roll;
 import com.gmail.nossr50.listeners.*;
+import com.gmail.nossr50.metadata.MetadataService;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.runnables.SaveTimerTask;
 import com.gmail.nossr50.runnables.backups.CleanBackupsTask;
@@ -77,8 +78,9 @@ import java.util.List;
 public class mcMMO extends JavaPlugin {
 
 
-    /* Managers */
+    /* Managers & Services */
     private static PlatformManager platformManager;
+    private static MetadataService metadataService;
     private static ChunkManager       placeStore;
     private static RepairableManager  repairableManager;
     private static SalvageableManager salvageableManager;
@@ -175,6 +177,9 @@ public class mcMMO extends JavaPlugin {
             //Platform Manager
             platformManager = new PlatformManager();
 
+            //metadata service
+            metadataService = new MetadataService(this);
+
             //Filter out any debug messages (if debug/verbose logging is not enabled)
             getLogger().setFilter(new LogFilter(this));
 
@@ -466,6 +471,10 @@ public class mcMMO extends JavaPlugin {
         return platformManager.getCompatibilityManager();
     }
 
+    public static MetadataService getMetadataService() {
+        return metadataService;
+    }
+
     @Deprecated
     public static void setDatabaseManager(DatabaseManager databaseManager) {
         mcMMO.databaseManager = databaseManager;

+ 49 - 0
src/main/java/com/gmail/nossr50/metadata/BlockMetadataService.java

@@ -0,0 +1,49 @@
+package com.gmail.nossr50.metadata;
+
+import com.gmail.nossr50.mcMMO;
+import org.bukkit.block.Furnace;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataHolder;
+import org.bukkit.persistence.PersistentDataType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.UUID;
+
+import static com.gmail.nossr50.metadata.MetadataService.NSK_FURNACE_UUID_LEAST_SIG;
+import static com.gmail.nossr50.metadata.MetadataService.NSK_FURNACE_UUID_MOST_SIG;
+
+public class BlockMetadataService {
+
+    private final @NotNull mcMMO pluginRef;
+
+    public BlockMetadataService(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
+    }
+
+    public @Nullable UUID getFurnaceOwner(@NotNull Furnace furnace) {
+        //Get container from entity
+        PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer();
+
+        //Too lazy to make a custom data type for this stuff
+        Long mostSigBits = dataContainer.get(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG);
+        Long leastSigBits = dataContainer.get(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG);
+
+        if (mostSigBits != null && leastSigBits != null) {
+            return new UUID(mostSigBits, leastSigBits);
+        } else {
+            return null;
+        }
+    }
+
+    public void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid) {
+        PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer();
+
+        dataContainer.set(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG, uuid.getMostSignificantBits());
+        dataContainer.set(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG, uuid.getLeastSignificantBits());
+
+        furnace.update();
+    }
+
+
+}

+ 110 - 0
src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java

@@ -0,0 +1,110 @@
+package com.gmail.nossr50.metadata;
+
+import com.gmail.nossr50.mcMMO;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+import static com.gmail.nossr50.metadata.MetadataService.NSK_SUPER_ABILITY_BOOSTED_ITEM;
+
+public class ItemMetadataService {
+
+    public final @NotNull String LEGACY_ABILITY_TOOL_LORE = "mcMMO Ability Tool";
+    public final @NotNull mcMMO pluginRef;
+
+    public ItemMetadataService(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
+    }
+
+    public void setSuperAbilityBoostedItem(@NotNull ItemStack itemStack, int originalDigSpeed) {
+        if (itemStack.getItemMeta() == null) {
+            mcMMO.p.getLogger().severe("Can not assign persistent data to an item with null item metadata");
+            return;
+        }
+
+        ItemMeta itemMeta = itemStack.getItemMeta();
+        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
+
+        dataContainer.set(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER, originalDigSpeed);
+
+        itemStack.setItemMeta(itemMeta);
+    }
+
+    public boolean isSuperAbilityBoosted(@NotNull ItemStack itemStack) {
+        if (itemStack.getItemMeta() == null)
+            return false;
+
+        ItemMeta itemMeta = itemStack.getItemMeta();
+        //Get container from entity
+        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
+
+        //If this value isn't null, then the tool can be considered dig speed boosted
+        Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER);
+
+        return boostValue != null;
+    }
+
+    public int getSuperAbilityToolOriginalDigSpeed(@NotNull ItemStack itemStack) {
+        //Get container from entity
+        ItemMeta itemMeta = itemStack.getItemMeta();
+
+        if (itemMeta == null)
+            return 0;
+
+        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
+
+        if (dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER) == null) {
+            mcMMO.p.getLogger().severe("Value should never be null for a boosted item");
+            return 0;
+        } else {
+            //Too lazy to make a custom data type for this stuff
+            Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER);
+            return Math.max(boostValue, 0);
+        }
+    }
+
+    public void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack) {
+        int originalSpeed = getSuperAbilityToolOriginalDigSpeed(itemStack);
+        ItemMeta itemMeta = itemStack.getItemMeta();
+
+        if(itemMeta != null) {
+            //TODO: can be optimized
+            if (itemMeta.hasEnchant(Enchantment.DIG_SPEED)) {
+                itemMeta.removeEnchant(Enchantment.DIG_SPEED);
+            }
+
+            if (originalSpeed > 0) {
+                itemMeta.addEnchant(Enchantment.DIG_SPEED, originalSpeed, true);
+            }
+
+            PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
+            dataContainer.remove(NSK_SUPER_ABILITY_BOOSTED_ITEM); //Remove persistent data
+
+            //TODO: needed?
+            itemStack.setItemMeta(itemMeta);
+        }
+    }
+
+    public boolean isLegacyAbilityTool(@NotNull ItemStack itemStack) {
+        ItemMeta itemMeta = itemStack.getItemMeta();
+
+        if (itemMeta == null)
+            return false;
+
+        List<String> lore = itemMeta.getLore();
+
+        if (lore == null || lore.isEmpty())
+            return false;
+
+        return lore.contains(LEGACY_ABILITY_TOOL_LORE);
+    }
+
+    public @NotNull String getLegacyAbilityToolLore() {
+        return LEGACY_ABILITY_TOOL_LORE;
+    }
+}

+ 71 - 0
src/main/java/com/gmail/nossr50/metadata/MetadataService.java

@@ -0,0 +1,71 @@
+package com.gmail.nossr50.metadata;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.MetadataConstants;
+import org.bukkit.NamespacedKey;
+import org.jetbrains.annotations.NotNull;
+
+public class MetadataService {
+    private final @NotNull mcMMO pluginRef;
+
+    protected static final @NotNull NamespacedKey NSK_SUPER_ABILITY_BOOSTED_ITEM;
+    protected static final @NotNull NamespacedKey NSK_MOB_SPAWNER_MOB;
+    protected static final @NotNull NamespacedKey NSK_EGG_MOB;
+    protected static final @NotNull NamespacedKey NSK_NETHER_GATE_MOB;
+    protected static final @NotNull NamespacedKey NSK_COTW_SUMMONED_MOB;
+    protected static final @NotNull NamespacedKey NSK_PLAYER_BRED_MOB;
+    protected static final @NotNull NamespacedKey NSK_PLAYER_TAMED_MOB;
+    protected static final @NotNull NamespacedKey NSK_VILLAGER_TRADE_ORIGIN_ITEM;
+    protected static final @NotNull NamespacedKey NSK_EXPLOITED_ENDERMEN;
+    protected static final @NotNull NamespacedKey NSK_FURNACE_UUID_MOST_SIG;
+    protected static final @NotNull NamespacedKey NSK_FURNACE_UUID_LEAST_SIG;
+
+    static {
+        NSK_SUPER_ABILITY_BOOSTED_ITEM = getNamespacedKey(MetadataConstants.METADATA_KEY_SUPER_ABILITY_BOOSTED_ITEM);
+        NSK_MOB_SPAWNER_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB);
+        NSK_EGG_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_EGG_MOB);
+        NSK_NETHER_GATE_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB);
+        NSK_COTW_SUMMONED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB);
+        NSK_PLAYER_BRED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB);
+        NSK_PLAYER_TAMED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB);
+        NSK_VILLAGER_TRADE_ORIGIN_ITEM = getNamespacedKey(MetadataConstants.METADATA_KEY_VILLAGER_TRADE_ORIGIN_ITEM);
+        NSK_EXPLOITED_ENDERMEN = getNamespacedKey(MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN);
+        NSK_FURNACE_UUID_MOST_SIG = getNamespacedKey(MetadataConstants.METADATA_KEY_FURNACE_UUID_MOST_SIG);
+        NSK_FURNACE_UUID_LEAST_SIG = getNamespacedKey(MetadataConstants.METADATA_KEY_FURNACE_UUID_LEAST_SIG);
+    }
+
+    private final @NotNull ItemMetadataService itemMetadataService;
+    private final @NotNull MobMetadataService mobMetadataService;
+    private final @NotNull BlockMetadataService blockMetadataService;
+
+    public MetadataService(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
+
+        blockMetadataService = new BlockMetadataService(pluginRef);
+        mobMetadataService = new MobMetadataService(pluginRef);
+        itemMetadataService = new ItemMetadataService(pluginRef);
+    }
+
+    /**
+     * Helper method to simplify generating namespaced keys
+     *
+     * @param key the {@link String} value of the key
+     *
+     * @return the generated {@link NamespacedKey}
+     */
+    public static @NotNull NamespacedKey getNamespacedKey(@NotNull String key) {
+        return new NamespacedKey(mcMMO.p, key);
+    }
+
+    public @NotNull ItemMetadataService getItemMetadataService() {
+        return itemMetadataService;
+    }
+
+    public @NotNull MobMetadataService getMobMetadataService() {
+        return mobMetadataService;
+    }
+
+    public @NotNull BlockMetadataService getBlockMetadataService() {
+        return blockMetadataService;
+    }
+}

+ 1 - 1
src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/MobMetaFlagType.java → src/main/java/com/gmail/nossr50/metadata/MobMetaFlagType.java

@@ -1,4 +1,4 @@
-package com.gmail.nossr50.util.compat.layers.persistentdata;
+package com.gmail.nossr50.metadata;
 
 public enum MobMetaFlagType {
     MOB_SPAWNER_MOB,

+ 187 - 0
src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java

@@ -0,0 +1,187 @@
+package com.gmail.nossr50.metadata;
+
+import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
+import com.gmail.nossr50.config.PersistentDataConfig;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.MetadataConstants;
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.WeakHashMap;
+
+import static com.gmail.nossr50.metadata.MetadataService.*;
+
+public class MobMetadataService {
+    private final @NotNull WeakHashMap<Entity, HashSet<MobMetaFlagType>> mobRegistry; //transient data
+    private final @NotNull EnumMap<MobMetaFlagType, NamespacedKey> mobFlagKeyMap; //used for persistent data
+    private final @NotNull mcMMO pluginRef;
+    private boolean isUsingPersistentData = false;
+
+    public MobMetadataService(@NotNull mcMMO pluginRef) {
+        this.pluginRef = pluginRef;
+        mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class);
+        mobRegistry = new WeakHashMap<>();
+        initMobFlagKeyMap();
+
+        for (MobMetaFlagType metaFlagType : MobMetaFlagType.values()) {
+            if (PersistentDataConfig.getInstance().isMobPersistent(metaFlagType))
+                isUsingPersistentData = true;
+        }
+    }
+
+    /**
+     * Registers the namespaced keys required by the API (CB/Spigot)
+     * Used primarily for persistent data
+     */
+    private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister {
+        for (MobMetaFlagType mobMetaFlagType : MobMetaFlagType.values()) {
+            switch (mobMetaFlagType) {
+                case MOB_SPAWNER_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_MOB_SPAWNER_MOB);
+                case EGG_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_EGG_MOB);
+                case NETHER_PORTAL_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_NETHER_GATE_MOB);
+                case COTW_SUMMONED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_COTW_SUMMONED_MOB);
+                case PLAYER_BRED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_BRED_MOB);
+                case EXPLOITED_ENDERMEN -> mobFlagKeyMap.put(mobMetaFlagType, NSK_EXPLOITED_ENDERMEN);
+                case PLAYER_TAMED_MOB -> mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_TAMED_MOB);
+                default -> throw new IncompleteNamespacedKeyRegister("missing namespaced key register for type: " + mobMetaFlagType);
+            }
+        }
+    }
+
+    /**
+     * Helper method to simplify generating namespaced keys
+     *
+     * @param key the {@link String} value of the key
+     *
+     * @return the generated {@link NamespacedKey}
+     */
+    private @NotNull NamespacedKey getNamespacedKey(@NotNull String key) {
+        return new NamespacedKey(mcMMO.p, key);
+    }
+
+    /**
+     * Whether or not a target {@link LivingEntity} has a specific mcMMO mob flags
+     *
+     * @param flag         the type of mob flag to check for
+     * @param livingEntity the living entity to check for metadata
+     *
+     * @return true if the mob has metadata values for target {@link MobMetaFlagType}
+     */
+    public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
+        if (PersistentDataConfig.getInstance().isMobPersistent(flag)) {
+            return livingEntity.getPersistentDataContainer().has(mobFlagKeyMap.get(flag), PersistentDataType.BYTE);
+        } else {
+            if (mobRegistry.containsKey(livingEntity)) {
+                return mobRegistry.get(livingEntity).contains(flag);
+            }
+
+            return false;
+        }
+    }
+
+    /**
+     * Whether or not a target {@link LivingEntity} has any mcMMO mob flags
+     *
+     * @param livingEntity the living entity to check for metadata
+     *
+     * @return true if the mob has any mcMMO mob related metadata values
+     */
+    public boolean hasMobFlags(@NotNull LivingEntity livingEntity) {
+        if (isUsingPersistentData) {
+            for (MobMetaFlagType metaFlagType : MobMetaFlagType.values()) {
+                if (hasMobFlag(metaFlagType, livingEntity))
+                    return true;
+            }
+
+            return false;
+        } else {
+            return mobRegistry.containsKey(livingEntity) && mobRegistry.get(livingEntity).size() > 0;
+        }
+    }
+
+    /**
+     * Copies all mcMMO mob flags from one {@link LivingEntity} to another {@link LivingEntity}
+     * This does not clear existing mcMMO mob flags on the target
+     *
+     * @param sourceEntity entity to copy from
+     * @param targetEntity entity to copy to
+     */
+    public void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity) {
+        if (!hasMobFlags(sourceEntity))
+            return;
+
+        if (isUsingPersistentData) {
+            for (MobMetaFlagType flag : MobMetaFlagType.values()) {
+                if (hasMobFlag(flag, sourceEntity)) {
+                    flagMetadata(flag, targetEntity);
+                }
+            }
+        } else {
+            HashSet<MobMetaFlagType> flags = new HashSet<>(mobRegistry.get(sourceEntity));
+            mobRegistry.put(targetEntity, flags);
+        }
+    }
+
+    /**
+     * Adds a mob flag to a {@link LivingEntity} which effectively acts a true/false boolean
+     * Existence of the flag can be considered a true value, non-existence can be considered false for all intents and purposes
+     *
+     * @param flag         the desired flag to assign
+     * @param livingEntity the target living entity
+     */
+    public void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
+        if (PersistentDataConfig.getInstance().isMobPersistent(flag)) {
+            if (!hasMobFlag(flag, livingEntity)) {
+                PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer();
+                persistentDataContainer.set(mobFlagKeyMap.get(flag), PersistentDataType.BYTE, MetadataConstants.SIMPLE_FLAG_VALUE);
+            }
+        } else {
+            HashSet<MobMetaFlagType> flags = mobRegistry.getOrDefault(livingEntity, new HashSet<>());
+            flags.add(flag); // add the new flag
+            mobRegistry.put(livingEntity, flags); //update registry
+        }
+    }
+
+    /**
+     * Removes a specific mob flag from target {@link LivingEntity}
+     *
+     * @param flag         desired flag to remove
+     * @param livingEntity the target living entity
+     */
+    public void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
+        if (PersistentDataConfig.getInstance().isMobPersistent(flag)) {
+            if (hasMobFlag(flag, livingEntity)) {
+                PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer();
+                persistentDataContainer.remove(mobFlagKeyMap.get(flag));
+            }
+        } else {
+            if (mobRegistry.containsKey(livingEntity)) {
+                mobRegistry.get(livingEntity).remove(flag);
+
+                if (mobRegistry.get(livingEntity).size() == 0)
+                    mobRegistry.remove(livingEntity);
+            }
+        }
+    }
+
+    /**
+     * Remove all mcMMO related mob flags from the target {@link LivingEntity}
+     *
+     * @param livingEntity target entity
+     */
+    public void removeMobFlags(@NotNull LivingEntity livingEntity) {
+        if (isUsingPersistentData) {
+            for (MobMetaFlagType flag : MobMetaFlagType.values()) {
+                removeMobFlag(flag, livingEntity);
+            }
+        } else {
+            mobRegistry.remove(livingEntity);
+        }
+    }
+}

+ 2 - 2
src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java

@@ -10,10 +10,10 @@ import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
 import com.gmail.nossr50.datatypes.skills.subskills.taming.TamingSummon;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.metadata.MobMetaFlagType;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.random.RandomChanceSkillStatic;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
@@ -475,7 +475,7 @@ public class TamingManager extends SkillManager {
 
     private void applyMetaDataToCOTWEntity(LivingEntity summonedEntity) {
         //This helps identify the entity as being summoned by COTW
-        mcMMO.getCompatibilityManager().getPersistentDataLayer().flagMetadata(MobMetaFlagType.COTW_SUMMONED_MOB, summonedEntity);
+        mcMMO.getMetadataService().getMobMetadataService().flagMetadata(MobMetaFlagType.COTW_SUMMONED_MOB, summonedEntity);
     }
 
     /**

+ 1 - 1
src/main/java/com/gmail/nossr50/util/TransientEntityTracker.java

@@ -273,7 +273,7 @@ public class TransientEntityTracker {
         }
 
         //Remove our metadata
-        mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(livingEntity);
+        mcMMO.getMetadataService().getMobMetadataService().removeMobFlags(livingEntity);
 
         //Clean from trackers
         unregisterEntity(livingEntity);

+ 1 - 6
src/main/java/com/gmail/nossr50/util/TransientMetadataTools.java

@@ -18,11 +18,6 @@ public class TransientMetadataTools {
             entity.removeMetadata(MetadataConstants.METADATA_KEY_CUSTOM_NAME, pluginRef);
         }
 
-//        if(entity.hasMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY)) {
-//            CombatUtils.fixNames(entity);
-//            entity.removeMetadata(MetadataConstants.METADATA_KEY_OLD_NAME_KEY, pluginRef);
-//        }
-
         //Involved in changing mob names to hearts
         if (entity.hasMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY)) {
             entity.setCustomNameVisible(entity.getMetadata(MetadataConstants.METADATA_KEY_NAME_VISIBILITY).get(0).asBoolean());
@@ -35,7 +30,7 @@ public class TransientMetadataTools {
         }
 
         //Cleanup mob metadata
-        mcMMO.getCompatibilityManager().getPersistentDataLayer().removeMobFlags(entity);
+        mcMMO.getMetadataService().getMobMetadataService().removeMobFlags(entity);
 
         //TODO: This loop has some redundancy, this whole method needs to be rewritten
         for(String key : MetadataConstants.MOB_METADATA_KEYS) {

+ 1 - 22
src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java

@@ -5,9 +5,6 @@ import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.compat.layers.bungee.AbstractBungeeSerializerCompatibilityLayer;
 import com.gmail.nossr50.util.compat.layers.bungee.BungeeLegacySerializerCompatibilityLayer;
 import com.gmail.nossr50.util.compat.layers.bungee.BungeeModernSerializerCompatibilityLayer;
-import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
-import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_13;
-import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_14;
 import com.gmail.nossr50.util.compat.layers.skills.AbstractMasterAnglerCompatibility;
 import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer;
 import com.gmail.nossr50.util.nms.NMSVersion;
@@ -25,7 +22,7 @@ import java.util.HashMap;
  * In 2.2 we are switching to modules and that will clean things up significantly
  *
  */
-//TODO: I need to rewrite this crap
+//TODO: I need to delete this crap
 public class CompatibilityManager {
     private @NotNull HashMap<CompatibilityType, Boolean> supportedLayers;
     private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully
@@ -33,8 +30,6 @@ public class CompatibilityManager {
     private final @NotNull NMSVersion nmsVersion;
 
     /* Compatibility Layers */
-//    private PlayerAttackCooldownExploitPreventionLayer playerAttackCooldownExploitPreventionLayer;
-    private AbstractPersistentDataLayer persistentDataLayer;
     private AbstractBungeeSerializerCompatibilityLayer bungeeSerializerCompatibilityLayer;
     private AbstractMasterAnglerCompatibility masterAnglerCompatibility;
 
@@ -64,7 +59,6 @@ public class CompatibilityManager {
      * For any unsupported layers, load a dummy layer
      */
     private void initCompatibilityLayers() {
-        initPersistentDataLayer();
         initBungeeSerializerLayer();
         initMasterAnglerLayer();
 
@@ -89,17 +83,6 @@ public class CompatibilityManager {
         supportedLayers.put(CompatibilityType.BUNGEE_SERIALIZER, true);
     }
 
-    private void initPersistentDataLayer() {
-        if(minecraftGameVersion.isAtLeast(1, 14, 2)) {
-            persistentDataLayer = new SpigotPersistentDataLayer_1_14();
-        } else {
-
-            persistentDataLayer = new SpigotPersistentDataLayer_1_13();
-        }
-
-        supportedLayers.put(CompatibilityType.PERSISTENT_DATA, true);
-    }
-
     //TODO: move to text manager
     public void reportCompatibilityStatus(@NotNull CommandSender commandSender) {
         if(isFullyCompatibleServerSoftware) {
@@ -171,10 +154,6 @@ public class CompatibilityManager {
         return bungeeSerializerCompatibilityLayer;
     }
 
-    public AbstractPersistentDataLayer getPersistentDataLayer() {
-        return persistentDataLayer;
-    }
-
     public @Nullable AbstractMasterAnglerCompatibility getMasterAnglerCompatibilityLayer() {
         return masterAnglerCompatibility;
     }

+ 0 - 137
src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/AbstractPersistentDataLayer.java

@@ -1,137 +0,0 @@
-package com.gmail.nossr50.util.compat.layers.persistentdata;
-
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.MetadataConstants;
-import com.gmail.nossr50.util.compat.layers.AbstractCompatibilityLayer;
-import org.bukkit.NamespacedKey;
-import org.bukkit.block.Furnace;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-import java.util.UUID;
-
-public abstract class AbstractPersistentDataLayer extends AbstractCompatibilityLayer {
-
-    protected final @NotNull NamespacedKey NSK_SUPER_ABILITY_BOOSTED_ITEM;
-    protected final @NotNull NamespacedKey NSK_MOB_SPAWNER_MOB;
-    protected final @NotNull NamespacedKey NSK_EGG_MOB;
-    protected final @NotNull NamespacedKey NSK_NETHER_GATE_MOB;
-    protected final @NotNull NamespacedKey NSK_COTW_SUMMONED_MOB;
-    protected final @NotNull NamespacedKey NSK_PLAYER_BRED_MOB;
-    protected final @NotNull NamespacedKey NSK_PLAYER_TAMED_MOB;
-    protected final @NotNull NamespacedKey NSK_VILLAGER_TRADE_ORIGIN_ITEM;
-    protected final @NotNull NamespacedKey NSK_EXPLOITED_ENDERMEN;
-
-    protected final @NotNull NamespacedKey NSK_FURNACE_UUID_MOST_SIG;
-    protected final @NotNull NamespacedKey NSK_FURNACE_UUID_LEAST_SIG;
-
-    public final @NotNull String LEGACY_ABILITY_TOOL_LORE = "mcMMO Ability Tool";
-
-    public AbstractPersistentDataLayer() {
-        NSK_SUPER_ABILITY_BOOSTED_ITEM = getNamespacedKey(MetadataConstants.METADATA_KEY_SUPER_ABILITY_BOOSTED_ITEM);
-        NSK_MOB_SPAWNER_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB);
-        NSK_EGG_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_EGG_MOB);
-        NSK_NETHER_GATE_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB);
-        NSK_COTW_SUMMONED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB);
-        NSK_PLAYER_BRED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB);
-        NSK_PLAYER_TAMED_MOB = getNamespacedKey(MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB);
-        NSK_VILLAGER_TRADE_ORIGIN_ITEM = getNamespacedKey(MetadataConstants.METADATA_KEY_VILLAGER_TRADE_ORIGIN_ITEM);
-        NSK_EXPLOITED_ENDERMEN = getNamespacedKey(MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN);
-        NSK_FURNACE_UUID_MOST_SIG = getNamespacedKey(MetadataConstants.METADATA_KEY_FURNACE_UUID_MOST_SIG);
-        NSK_FURNACE_UUID_LEAST_SIG = getNamespacedKey(MetadataConstants.METADATA_KEY_FURNACE_UUID_LEAST_SIG);
-
-        initializeLayer();
-    }
-
-
-    /**
-     * Helper method to simplify generating namespaced keys
-     * @param key the {@link String} value of the key
-     * @return the generated {@link NamespacedKey}
-     */
-    private @NotNull NamespacedKey getNamespacedKey(@NotNull String key) {
-        return new NamespacedKey(mcMMO.p, key);
-    }
-
-    /**
-     * Whether or not a target {@link LivingEntity} has a specific mcMMO mob flags
-     * @param flag the type of mob flag to check for
-     * @param livingEntity the living entity to check for metadata
-     * @return true if the mob has metadata values for target {@link MobMetaFlagType}
-     */
-    public abstract boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity);
-
-    /**
-     * Whether or not a target {@link LivingEntity} has any mcMMO mob flags
-     * @param livingEntity the living entity to check for metadata
-     * @return true if the mob has any mcMMO mob related metadata values
-     */
-    public abstract boolean hasMobFlags(@NotNull LivingEntity livingEntity);
-
-    /**
-     * Copies all mcMMO mob flags from one {@link LivingEntity} to another {@link LivingEntity}
-     * This does not clear existing mcMMO mob flags on the target
-     * @param sourceEntity entity to copy from
-     * @param targetEntity entity to copy to
-     */
-    public abstract void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity);
-
-    /**
-     * Adds a mob flag to a {@link LivingEntity} which effectively acts a true/false boolean
-     * Existence of the flag can be considered a true value, non-existence can be considered false for all intents and purposes
-     * @param flag the desired flag to assign
-     * @param livingEntity the target living entity
-     */
-    public abstract void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity);
-
-    /**
-     * Removes a specific mob flag from target {@link LivingEntity}
-     * @param flag desired flag to remove
-     * @param livingEntity the target living entity
-     */
-    public abstract void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity);
-
-    /**
-     * Remove all mcMMO related mob flags from the target {@link LivingEntity}
-     * @param livingEntity target entity
-     */
-    public void removeMobFlags(@NotNull LivingEntity livingEntity) {
-        for(MobMetaFlagType flag : MobMetaFlagType.values()) {
-            removeMobFlag(flag, livingEntity);
-        }
-    }
-
-    public abstract @Nullable UUID getFurnaceOwner(@NotNull Furnace furnace);
-
-    public abstract void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid);
-
-    public abstract void setSuperAbilityBoostedItem(@NotNull ItemStack itemStack, int originalDigSpeed);
-
-    public abstract boolean isSuperAbilityBoosted(@NotNull ItemStack itemStack);
-
-    public abstract int getSuperAbilityToolOriginalDigSpeed(@NotNull ItemStack itemStack);
-
-    public abstract void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack);
-
-    public boolean isLegacyAbilityTool(@NotNull ItemStack itemStack) {
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        if(itemMeta == null)
-            return false;
-
-        List<String> lore = itemMeta.getLore();
-
-        if(lore == null || lore.isEmpty())
-            return false;
-
-        return lore.contains(LEGACY_ABILITY_TOOL_LORE);
-    }
-
-    public @NotNull String getLegacyAbilityToolLore() {
-        return LEGACY_ABILITY_TOOL_LORE;
-    }
-}

+ 0 - 172
src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/SpigotPersistentDataLayer_1_13.java

@@ -1,172 +0,0 @@
-package com.gmail.nossr50.util.compat.layers.persistentdata;
-
-import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
-import com.gmail.nossr50.datatypes.meta.UUIDMeta;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.MetadataConstants;
-import org.bukkit.block.Furnace;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
-import org.bukkit.inventory.meta.tags.ItemTagType;
-import org.bukkit.metadata.Metadatable;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.EnumMap;
-import java.util.UUID;
-
-/**
- * Persistent Data API is unavailable
- */
-public class SpigotPersistentDataLayer_1_13 extends AbstractPersistentDataLayer {
-
-    private final @NotNull String KEY_FURNACE_OWNER = "mcMMO_furnace_owner";
-    private final @NotNull EnumMap<MobMetaFlagType, String> mobFlagKeyMap;
-
-    public SpigotPersistentDataLayer_1_13() {
-        mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class);
-        initMobFlagKeyMap();
-    }
-
-    @Override
-    public boolean initializeLayer() {
-        return true;
-    }
-
-    private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister {
-        for(MobMetaFlagType flagType : MobMetaFlagType.values()) {
-            switch (flagType) {
-                case MOB_SPAWNER_MOB -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_MOB_SPAWNER_MOB);
-                case EGG_MOB -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_EGG_MOB);
-                case NETHER_PORTAL_MOB -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_NETHER_PORTAL_MOB);
-                case COTW_SUMMONED_MOB -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_COTW_SUMMONED_MOB);
-                case PLAYER_BRED_MOB -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_PLAYER_BRED_MOB);
-                case PLAYER_TAMED_MOB -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_PLAYER_TAMED_MOB);
-                case EXPLOITED_ENDERMEN -> mobFlagKeyMap.put(flagType, MetadataConstants.METADATA_KEY_EXPLOITED_ENDERMEN);
-                default -> throw new IncompleteNamespacedKeyRegister("Missing flag register for: " + flagType);
-            }
-        }
-    }
-
-    @Override
-    public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
-        return livingEntity.hasMetadata(mobFlagKeyMap.get(flag));
-    }
-
-    @Override
-    public boolean hasMobFlags(@NotNull LivingEntity livingEntity) {
-        for(String currentKey : mobFlagKeyMap.values()) {
-            if(livingEntity.hasMetadata(currentKey)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity) {
-        for(MobMetaFlagType flag : MobMetaFlagType.values()) {
-            if(hasMobFlag(flag, sourceEntity)) {
-                flagMetadata(flag, targetEntity);
-            }
-        }
-    }
-
-    @Override
-    public void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
-        if(!hasMobFlag(flag, livingEntity)) {
-            livingEntity.setMetadata(mobFlagKeyMap.get(flag), MetadataConstants.MCMMO_METADATA_VALUE);
-        }
-    }
-
-    @Override
-    public void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
-        if(hasMobFlag(flag, livingEntity)) {
-            livingEntity.removeMetadata(mobFlagKeyMap.get(flag), mcMMO.p);
-        }
-    }
-
-    @Override
-    public UUID getFurnaceOwner(@NotNull Furnace furnace) {
-        if(furnace.getMetadata(KEY_FURNACE_OWNER).size() > 0) {
-            UUIDMeta uuidMeta = (UUIDMeta) ((Metadatable) furnace).getMetadata(KEY_FURNACE_OWNER).get(0);
-            return (UUID) uuidMeta.value();
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid) {
-
-        if(furnace.getMetadata(KEY_FURNACE_OWNER).size() > 0) {
-            furnace.removeMetadata(KEY_FURNACE_OWNER, mcMMO.p);
-        }
-
-        furnace.setMetadata(KEY_FURNACE_OWNER, new UUIDMeta(mcMMO.p, uuid));
-    }
-
-    @Override
-    public void setSuperAbilityBoostedItem(@NotNull ItemStack itemStack, int originalDigSpeed) {
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        if(itemMeta == null) {
-            mcMMO.p.getLogger().severe("Item meta should never be null for a super boosted item!");
-            return;
-        }
-
-        itemMeta.getCustomTagContainer().setCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER, originalDigSpeed);
-        itemStack.setItemMeta(itemMeta);
-    }
-
-    @Override
-    public boolean isSuperAbilityBoosted(@NotNull ItemStack itemStack) {
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        if(itemMeta == null)
-            return false;
-
-        CustomItemTagContainer tagContainer = itemMeta.getCustomTagContainer();
-        return tagContainer.hasCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER);
-    }
-
-    @Override
-    public int getSuperAbilityToolOriginalDigSpeed(@NotNull ItemStack itemStack) {
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        if(itemMeta == null)
-            return 0;
-
-        CustomItemTagContainer tagContainer = itemMeta.getCustomTagContainer();
-
-        if(tagContainer.hasCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER)) {
-            return tagContainer.getCustomTag(NSK_SUPER_ABILITY_BOOSTED_ITEM, ItemTagType.INTEGER);
-        } else {
-            return 0;
-        }
-    }
-
-    @Override
-    public void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack) {
-        int originalSpeed = getSuperAbilityToolOriginalDigSpeed(itemStack);
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        if(itemMeta == null)
-            return;
-
-        if(itemMeta.hasEnchant(Enchantment.DIG_SPEED)) {
-            itemMeta.removeEnchant(Enchantment.DIG_SPEED);
-        }
-
-
-        if(originalSpeed > 0) {
-            itemMeta.addEnchant(Enchantment.DIG_SPEED, originalSpeed, true);
-        }
-
-        //TODO: needed?
-        itemStack.setItemMeta(itemMeta);
-    }
-}

+ 0 - 220
src/main/java/com/gmail/nossr50/util/compat/layers/persistentdata/SpigotPersistentDataLayer_1_14.java

@@ -1,220 +0,0 @@
-package com.gmail.nossr50.util.compat.layers.persistentdata;
-
-import com.gmail.nossr50.api.exceptions.IncompleteNamespacedKeyRegister;
-import com.gmail.nossr50.config.PersistentDataConfig;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.MetadataConstants;
-import org.bukkit.NamespacedKey;
-import org.bukkit.block.Furnace;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.persistence.PersistentDataContainer;
-import org.bukkit.persistence.PersistentDataHolder;
-import org.bukkit.persistence.PersistentDataType;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.EnumMap;
-import java.util.UUID;
-
-public class SpigotPersistentDataLayer_1_14 extends AbstractPersistentDataLayer {
-
-    private final @NotNull EnumMap<MobMetaFlagType, NamespacedKey> mobFlagKeyMap;
-    private final @NotNull SpigotPersistentDataLayer_1_13 transientLayer;
-
-    public SpigotPersistentDataLayer_1_14() {
-        mobFlagKeyMap = new EnumMap<>(MobMetaFlagType.class);
-        initMobFlagKeyMap();
-        transientLayer = new SpigotPersistentDataLayer_1_13(); //For disabled persistent types
-    }
-
-    @Override
-    public boolean initializeLayer() {
-        return true;
-    }
-
-    /**
-     * Registers the namespaced keys required by the API (CB/Spigot)
-     */
-    private void initMobFlagKeyMap() throws IncompleteNamespacedKeyRegister {
-        for(MobMetaFlagType mobMetaFlagType : MobMetaFlagType.values()) {
-            switch(mobMetaFlagType) {
-                case MOB_SPAWNER_MOB:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_MOB_SPAWNER_MOB);
-                    break;
-                case EGG_MOB:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_EGG_MOB);
-                    break;
-                case NETHER_PORTAL_MOB:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_NETHER_GATE_MOB);
-                    break;
-                case COTW_SUMMONED_MOB:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_COTW_SUMMONED_MOB);
-                    break;
-                case PLAYER_BRED_MOB:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_BRED_MOB);
-                    break;
-                case EXPLOITED_ENDERMEN:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_EXPLOITED_ENDERMEN);
-                    break;
-                case PLAYER_TAMED_MOB:
-                    mobFlagKeyMap.put(mobMetaFlagType, NSK_PLAYER_TAMED_MOB);
-                    break;
-                default:
-                    throw new IncompleteNamespacedKeyRegister("missing namespaced key register for type: "+ mobMetaFlagType.toString());
-            }
-        }
-    }
-
-    @Override
-    public boolean hasMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
-        if(PersistentDataConfig.getInstance().isMobPersistent(flag)) {
-            return livingEntity.getPersistentDataContainer().has(mobFlagKeyMap.get(flag), PersistentDataType.BYTE);
-        } else {
-            return transientLayer.hasMobFlag(flag, livingEntity);
-        }
-    }
-
-    @Override
-    public boolean hasMobFlags(@NotNull LivingEntity livingEntity) {
-        for(MobMetaFlagType currentFlag : MobMetaFlagType.values()) {
-            if(hasMobFlag(currentFlag, livingEntity)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public void addMobFlags(@NotNull LivingEntity sourceEntity, @NotNull LivingEntity targetEntity) {
-        for(MobMetaFlagType flag : MobMetaFlagType.values()) {
-            if(hasMobFlag(flag, sourceEntity)) {
-                flagMetadata(flag, targetEntity);
-            }
-        }
-    }
-
-    @Override
-    public void flagMetadata(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
-        if(PersistentDataConfig.getInstance().isMobPersistent(flag)) {
-            if(!hasMobFlag(flag, livingEntity)) {
-                PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer();
-                persistentDataContainer.set(mobFlagKeyMap.get(flag), PersistentDataType.BYTE, MetadataConstants.SIMPLE_FLAG_VALUE);
-            }
-        } else {
-            transientLayer.flagMetadata(flag, livingEntity);
-        }
-    }
-
-    @Override
-    public void removeMobFlag(@NotNull MobMetaFlagType flag, @NotNull LivingEntity livingEntity) {
-        if(PersistentDataConfig.getInstance().isMobPersistent(flag)) {
-            if(hasMobFlag(flag, livingEntity)) {
-                PersistentDataContainer persistentDataContainer = livingEntity.getPersistentDataContainer();
-                persistentDataContainer.remove(mobFlagKeyMap.get(flag));
-            }
-        } else {
-            transientLayer.removeMobFlag(flag, livingEntity);
-        }
-    }
-
-    @Override
-    public @Nullable UUID getFurnaceOwner(@NotNull Furnace furnace) {
-        //Get container from entity
-        PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer();
-
-        //Too lazy to make a custom data type for this stuff
-        Long mostSigBits = dataContainer.get(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG);
-        Long leastSigBits = dataContainer.get(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG);
-
-        if(mostSigBits != null && leastSigBits != null) {
-            return new UUID(mostSigBits, leastSigBits);
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void setFurnaceOwner(@NotNull Furnace furnace, @NotNull UUID uuid) {
-        PersistentDataContainer dataContainer = ((PersistentDataHolder) furnace).getPersistentDataContainer();
-
-        dataContainer.set(NSK_FURNACE_UUID_MOST_SIG, PersistentDataType.LONG, uuid.getMostSignificantBits());
-        dataContainer.set(NSK_FURNACE_UUID_LEAST_SIG, PersistentDataType.LONG, uuid.getLeastSignificantBits());
-
-        furnace.update();
-    }
-
-    @Override
-    public void setSuperAbilityBoostedItem(@NotNull ItemStack itemStack, int originalDigSpeed) {
-        if(itemStack.getItemMeta() == null) {
-            mcMMO.p.getLogger().severe("Can not assign persistent data to an item with null item metadata");
-            return;
-        }
-
-        ItemMeta itemMeta = itemStack.getItemMeta();
-        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
-
-        dataContainer.set(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER, originalDigSpeed);
-
-        itemStack.setItemMeta(itemMeta);
-    }
-
-    @Override
-    public boolean isSuperAbilityBoosted(@NotNull ItemStack itemStack) {
-        if(itemStack.getItemMeta() == null)
-            return false;
-
-        ItemMeta itemMeta = itemStack.getItemMeta();
-        //Get container from entity
-        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
-
-        //If this value isn't null, then the tool can be considered dig speed boosted
-        Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER);
-
-        return boostValue != null;
-    }
-
-    @Override
-    public int getSuperAbilityToolOriginalDigSpeed(@NotNull ItemStack itemStack) {
-        //Get container from entity
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        if(itemMeta == null)
-            return 0;
-
-        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
-
-        if(dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER) == null) {
-            mcMMO.p.getLogger().severe("Value should never be null for a boosted item");
-            return 0;
-        } else {
-            //Too lazy to make a custom data type for this stuff
-            Integer boostValue = dataContainer.get(NSK_SUPER_ABILITY_BOOSTED_ITEM, PersistentDataType.INTEGER);
-            return Math.max(boostValue, 0);
-        }
-    }
-
-    @Override
-    public void removeBonusDigSpeedOnSuperAbilityTool(@NotNull ItemStack itemStack) {
-        int originalSpeed = getSuperAbilityToolOriginalDigSpeed(itemStack);
-        ItemMeta itemMeta = itemStack.getItemMeta();
-
-        //TODO: can be optimized
-        if(itemMeta.hasEnchant(Enchantment.DIG_SPEED)) {
-            itemMeta.removeEnchant(Enchantment.DIG_SPEED);
-        }
-
-        if(originalSpeed > 0) {
-            itemMeta.addEnchant(Enchantment.DIG_SPEED, originalSpeed, true);
-        }
-
-        PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();
-        dataContainer.remove(NSK_SUPER_ABILITY_BOOSTED_ITEM); //Remove persistent data
-
-        //TODO: needed?
-        itemStack.setItemMeta(itemMeta);
-    }
-}

+ 10 - 10
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -10,6 +10,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent;
 import com.gmail.nossr50.events.fake.FakeEntityDamageEvent;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.metadata.MobMetaFlagType;
+import com.gmail.nossr50.metadata.MobMetadataService;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.runnables.skills.AwardCombatXpTask;
 import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
@@ -19,8 +21,6 @@ import com.gmail.nossr50.skills.swords.SwordsManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.util.*;
-import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
-import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.google.common.collect.ImmutableMap;
@@ -50,8 +50,8 @@ public final class CombatUtils {
 
     private CombatUtils() {}
 
-    private static @NotNull AbstractPersistentDataLayer getPersistentData() {
-        return mcMMO.getCompatibilityManager().getPersistentDataLayer();
+    private static @NotNull MobMetadataService getMobMetadataService() {
+        return mcMMO.getMetadataService().getMobMetadataService();
     }
 
     //Likely.. because who knows what plugins are throwing around
@@ -801,17 +801,17 @@ public final class CombatUtils {
                 }
             }
 
-            if(getPersistentData().hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, target)) {
+            if(getMobMetadataService().hasMobFlag(MobMetaFlagType.COTW_SUMMONED_MOB, target)) {
                 baseXP = 0;
-            } else if(getPersistentData().hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, target) || target.hasMetadata("ES")) {
+            } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.MOB_SPAWNER_MOB, target) || target.hasMetadata("ES")) {
                 baseXP *= ExperienceConfig.getInstance().getSpawnedMobXpMultiplier();
-            } else if(getPersistentData().hasMobFlag(MobMetaFlagType.NETHER_PORTAL_MOB, target)) {
+            } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.NETHER_PORTAL_MOB, target)) {
                 baseXP *= ExperienceConfig.getInstance().getNetherPortalXpMultiplier();
-            } else if(getPersistentData().hasMobFlag(MobMetaFlagType.EGG_MOB, target)) {
+            } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.EGG_MOB, target)) {
                 baseXP *= ExperienceConfig.getInstance().getEggXpMultiplier();
-            } else if (getPersistentData().hasMobFlag(MobMetaFlagType.PLAYER_BRED_MOB, target)) {
+            } else if (getMobMetadataService().hasMobFlag(MobMetaFlagType.PLAYER_BRED_MOB, target)) {
                 baseXP *= ExperienceConfig.getInstance().getBredMobXpMultiplier();
-            } else if(getPersistentData().hasMobFlag(MobMetaFlagType.PLAYER_TAMED_MOB, target)) {
+            } else if(getMobMetadataService().hasMobFlag(MobMetaFlagType.PLAYER_TAMED_MOB, target)) {
                 baseXP *= ExperienceConfig.getInstance().getTamedMobXpMultiplier();
             }
 

+ 12 - 11
src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java

@@ -10,9 +10,9 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.metadata.ItemMetadataService;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Misc;
-import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.text.StringUtils;
@@ -156,8 +156,7 @@ public final class SkillUtils {
             ItemUtils.addDigSpeedToItem(heldItem, heldItem.getEnchantmentLevel(Enchantment.DIG_SPEED));
 
             //1.13.2+ will have persistent metadata for this item
-            AbstractPersistentDataLayer compatLayer = mcMMO.getCompatibilityManager().getPersistentDataLayer();
-            compatLayer.setSuperAbilityBoostedItem(heldItem, originalDigSpeed);
+            mcMMO.getMetadataService().getItemMetadataService().setSuperAbilityBoostedItem(heldItem, originalDigSpeed);
         } else {
             int duration = 0;
             int amplifier = 0;
@@ -214,20 +213,22 @@ public final class SkillUtils {
 
 
         //1.13.2+ will have persistent metadata for this itemStack
-        AbstractPersistentDataLayer compatLayer = mcMMO.getCompatibilityManager().getPersistentDataLayer();
+        ItemMetadataService itemMetadataService = mcMMO.getMetadataService().getItemMetadataService();
 
-        if(compatLayer.isLegacyAbilityTool(itemStack)) {
+        if(itemMetadataService.isLegacyAbilityTool(itemStack)) {
             ItemMeta itemMeta = itemStack.getItemMeta();
 
-            // This is safe to call without prior checks.
-            itemMeta.removeEnchant(Enchantment.DIG_SPEED);
+            if(itemMeta != null) {
+                // This is safe to call without prior checks.
+                itemMeta.removeEnchant(Enchantment.DIG_SPEED);
 
-            itemStack.setItemMeta(itemMeta);
-            ItemUtils.removeAbilityLore(itemStack);
+                itemStack.setItemMeta(itemMeta);
+                ItemUtils.removeAbilityLore(itemStack);
+            }
         }
 
-        if(compatLayer.isSuperAbilityBoosted(itemStack)) {
-            compatLayer.removeBonusDigSpeedOnSuperAbilityTool(itemStack);
+        if(itemMetadataService.isSuperAbilityBoosted(itemStack)) {
+            itemMetadataService.removeBonusDigSpeedOnSuperAbilityTool(itemStack);
         }
     }
 

+ 2 - 2
src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java

@@ -34,7 +34,7 @@ public class SmeltingTracker {
     }
 
     private void setFurnaceOwner(Furnace furnace, Player player) {
-        mcMMO.getCompatibilityManager().getPersistentDataLayer().setFurnaceOwner(furnace, player.getUniqueId());
+        mcMMO.getMetadataService().getBlockMetadataService().setFurnaceOwner(furnace, player.getUniqueId());
     }
 
     private void printOwnershipGainDebug(Furnace furnace, McMMOPlayer mcMMOPlayer) {
@@ -65,7 +65,7 @@ public class SmeltingTracker {
     }
 
     public @Nullable OfflinePlayer getFurnaceOwner(Furnace furnace) {
-        UUID uuid = mcMMO.getCompatibilityManager().getPersistentDataLayer().getFurnaceOwner(furnace);
+        UUID uuid = mcMMO.getMetadataService().getBlockMetadataService().getFurnaceOwner(furnace);
 
         if(uuid != null) {
             return Bukkit.getOfflinePlayer(uuid);