mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-11-03 02:23:44 +01:00 
			
		
		
		
	@@ -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,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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,4 +1,4 @@
 | 
			
		||||
package com.gmail.nossr50.util.compat.layers.persistentdata;
 | 
			
		||||
package com.gmail.nossr50.metadata;
 | 
			
		||||
 | 
			
		||||
public enum MobMetaFlagType {
 | 
			
		||||
    MOB_SPAWNER_MOB,
 | 
			
		||||
							
								
								
									
										187
									
								
								src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/main/java/com/gmail/nossr50/metadata/MobMetadataService.java
									
									
									
									
									
										Normal file
									
								
							@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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,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();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user