From 651e46697edcd48e094b06aade8313e5f5fe66b5 Mon Sep 17 00:00:00 2001 From: Jules Date: Sun, 14 May 2023 16:34:43 +0200 Subject: [PATCH] force-class-selection fixes --- MMOCore-API/pom.xml | 2 +- .../java/net/Indyuce/mmocore/MMOCore.java | 26 +-- .../mmocore/api/player/PlayerData.java | 1 + .../profile/MMOCoreProfileDataModule.java | 35 +++- .../mmocore/gui/ClassConfirmation.java | 37 +++- .../net/Indyuce/mmocore/gui/ClassSelect.java | 41 +++- .../Indyuce/mmocore/gui/SubclassSelect.java | 2 +- .../mmocore/gui/api/GeneratedInventory.java | 3 + .../mmocore/manager/ConfigManager.java | 3 +- .../manager/data/GuildDataManager.java | 180 +++++++++--------- .../manager/data/PlayerDataManager.java | 5 + .../net/Indyuce/mmocore/MMOCoreBukkit.java | 4 - .../option/ForceChooseClassListener.java | 47 ----- MMOCore-Dist/src/main/resources/config.yml | 12 +- 14 files changed, 213 insertions(+), 185 deletions(-) delete mode 100644 MMOCore-Dist/src/main/java/net/Indyuce/mmocore/listener/option/ForceChooseClassListener.java diff --git a/MMOCore-API/pom.xml b/MMOCore-API/pom.xml index 4de78a2a..5bc4fcb4 100644 --- a/MMOCore-API/pom.xml +++ b/MMOCore-API/pom.xml @@ -141,7 +141,7 @@ fr.phoenixdevt - MMOProfiles-Dist + Profile-API 1.0-SNAPSHOT provided true diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java index 03ccdf50..103362ea 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/MMOCore.java @@ -29,13 +29,13 @@ import net.Indyuce.mmocore.guild.GuildModuleType; import net.Indyuce.mmocore.guild.GuildRelationHandler; import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.guild.provided.MMOCoreGuildModule; +import net.Indyuce.mmocore.guild.provided.YAMLGuildDataManager; import net.Indyuce.mmocore.manager.*; import net.Indyuce.mmocore.manager.data.DataProvider; import net.Indyuce.mmocore.manager.data.GuildDataManager; import net.Indyuce.mmocore.manager.data.LegacyDataProvider; import net.Indyuce.mmocore.manager.data.PlayerDataManager; import net.Indyuce.mmocore.manager.data.sql.SQLDataHandler; -import net.Indyuce.mmocore.guild.provided.YAMLGuildDataManager; import net.Indyuce.mmocore.manager.profession.*; import net.Indyuce.mmocore.manager.social.BoosterManager; import net.Indyuce.mmocore.manager.social.PartyManager; @@ -258,8 +258,7 @@ public class MMOCore extends JavaPlugin { * that after registering all the professses otherwise the player datas can't * recognize what profess the player has and professes will be lost */ - playerDataManager.setupAll(); - playerDataManager.registerEvents(EventPriority.NORMAL, EventPriority.NORMAL); + playerDataManager.initialize(EventPriority.NORMAL, EventPriority.NORMAL); // load guild data after loading player data dataProvider.getGuildManager().load(); @@ -271,25 +270,6 @@ public class MMOCore extends JavaPlugin { MMOCoreCommandTreeRoot mmoCoreCommand = new MMOCoreCommandTreeRoot(); getCommand("mmocore").setExecutor(mmoCoreCommand); getCommand("mmocore").setTabCompleter(mmoCoreCommand); - - if (getConfig().getBoolean("auto-save.enabled")) - - { - int autosave = getConfig().getInt("auto-save.interval") * 20; - new BukkitRunnable() { - public void run() { - - // Save player data - for (PlayerData data : PlayerData.getAll()) - if (data.isSynchronized()) - dataProvider.getDataManager().getDataHandler().saveData(data, false); - - // Save guild info - for (Guild guild : dataProvider.getGuildManager().getAll()) - dataProvider.getGuildManager().save(guild); - } - }.runTaskTimerAsynchronously(MMOCore.plugin, autosave, autosave); - } } @Override @@ -306,8 +286,6 @@ public class MMOCore extends JavaPlugin { for (PlayerData data : PlayerData.getAll()) if (data.isSynchronized()) { data.close(); - // Saves player health before saveData as the player will be considered offline into it if it is async. - data.setHealth(data.getPlayer().getHealth()); dataProvider.getDataManager().getDataHandler().saveData(data, true); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index cafd7964..ba83c86c 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -427,6 +427,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD @Override public void close() { + // Saves player health before saveData as the player will be considered offline into it if it is async health = getPlayer().getHealth(); // Remove from party if it is MMO Party Module diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/profile/MMOCoreProfileDataModule.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/profile/MMOCoreProfileDataModule.java index 1f410f74..57f6c09b 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/profile/MMOCoreProfileDataModule.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/profile/MMOCoreProfileDataModule.java @@ -1,17 +1,26 @@ package net.Indyuce.mmocore.comp.profile; +import fr.phoenixdevt.profile.ProfileDataModule; +import fr.phoenixdevt.profile.event.ProfileCreateEvent; +import fr.phoenixdevt.profile.event.ProfileDeleteEvent; import fr.phoenixdevt.profile.placeholder.PlaceholderRequest; import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.player.MMOPlayerData; -import io.lumine.mythic.lib.comp.profile.ProfileDataModuleImpl; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; import net.Indyuce.mmocore.experience.Profession; +import net.Indyuce.mmocore.manager.InventoryManager; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; -public class MMOCoreProfileDataModule extends ProfileDataModuleImpl { - public MMOCoreProfileDataModule() { - super(MMOCore.plugin); +public class MMOCoreProfileDataModule implements ProfileDataModule, Listener { + + @Override + public JavaPlugin getOwningPlugin() { + return MMOCore.plugin; } @Override @@ -43,4 +52,22 @@ public class MMOCoreProfileDataModule extends ProfileDataModuleImpl { placeholderRequest.validate(); }); } + + @EventHandler + public void onProfileCreate(ProfileCreateEvent event) { + + // Force to choose class first + if (MMOCore.plugin.configManager.forceClassSelection) { + final PlayerData playerData = PlayerData.get(event.getPlayerData().getUniqueId()); + InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open(); + } + + // Validate event directly + else event.validate(this); + } + + @EventHandler + public void onProfileDelete(ProfileDeleteEvent event) { + event.validate(this); + } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java index fbdecc30..2d31af07 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java @@ -20,8 +20,11 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.ItemStack; +import javax.annotation.Nullable; + public class ClassConfirmation extends EditableInventory { private final PlayerClass playerClass; @@ -37,7 +40,11 @@ public class ClassConfirmation extends EditableInventory { } public GeneratedInventory newInventory(PlayerData data, PluginInventory last, boolean subclass) { - return new ClassConfirmationInventory(data, this, playerClass, last, subclass); + return newInventory(data, last, subclass, null); + } + + public GeneratedInventory newInventory(PlayerData data, PluginInventory last, boolean subclass, @Nullable Runnable profileRunnable) { + return new ClassConfirmationInventory(data, this, playerClass, last, subclass, profileRunnable); } public class UnlockedItem extends InventoryItem { @@ -105,26 +112,33 @@ public class ClassConfirmation extends EditableInventory { private final PluginInventory last; private final boolean subclass; - public ClassConfirmationInventory(PlayerData playerData, EditableInventory editable, PlayerClass profess, PluginInventory last, boolean subclass) { + @Nullable + private final Runnable profileRunnable; + + private boolean canClose; + + public ClassConfirmationInventory(PlayerData playerData, EditableInventory editable, PlayerClass profess, PluginInventory last, boolean subclass, @Nullable Runnable profileRunnable) { super(playerData, editable); this.profess = profess; this.last = last; this.subclass = subclass; + this.profileRunnable = profileRunnable; } @Override public void whenClicked(InventoryClickContext context, InventoryItem item) { - if (item.getFunction().equals("back")) + if (item.getFunction().equals("back")) { + canClose = true; last.open(); - - else if (item.getFunction().equals("yes")) { + } else if (item.getFunction().equals("yes")) { PlayerChangeClassEvent called = new PlayerChangeClassEvent(playerData, profess); Bukkit.getPluginManager().callEvent(called); if (called.isCancelled()) return; + canClose = true; playerData.giveClassPoints(-1); if (subclass) playerData.setClass(profess); @@ -134,9 +148,22 @@ public class ClassConfirmation extends EditableInventory { MMOCore.plugin.configManager.getSimpleMessage("class-select", "class", profess.getName()).send(player); MMOCore.plugin.soundManager.getSound(SoundEvent.SELECT_CLASS).playTo(player); player.closeInventory(); + if (profileRunnable != null) profileRunnable.run(); } } + @Override + public void open() { + canClose = false; + super.open(); + } + + @Override + public void whenClosed(InventoryCloseEvent event) { + if (profileRunnable != null && !canClose) + Bukkit.getScheduler().runTaskLater(MMOCore.plugin, () -> open(), 2 * 20); + } + @Override public String calculateName() { return getName().replace("{class}", profess.getName()); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java index 7ada1ba9..7ae2667c 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java @@ -16,14 +16,17 @@ import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.manager.InventoryManager; import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -41,7 +44,11 @@ public class ClassSelect extends EditableInventory { } public GeneratedInventory newInventory(PlayerData data) { - return new ProfessSelectionInventory(data, this); + return newInventory(data, null); + } + + public GeneratedInventory newInventory(PlayerData data, @Nullable Runnable profileRunnable) { + return new ProfessSelectionInventory(data, this, profileRunnable); } public class ClassItem extends SimplePlaceholderItem { @@ -51,9 +58,10 @@ public class ClassSelect extends EditableInventory { public ClassItem(ConfigurationSection config) { super(Material.BARRIER, config); - Validate.isTrue(config.getString("function").length()>6,"Couldn't find the class associated to: "+config.getString("function")); + + Validate.isTrue(config.getString("function").length() > 6, "Couldn't find the class associated to: " + config.getString("function")); String classId = UtilityMethods.enumName(config.getString("function").substring(6)); - this.playerClass = Objects.requireNonNull(MMOCore.plugin.classManager.get(classId),classId+" does not correspond to any classId."); + this.playerClass = Objects.requireNonNull(MMOCore.plugin.classManager.get(classId), classId + " does not correspond to any classId."); this.name = config.getString("name"); this.lore = config.getStringList("lore"); } @@ -93,8 +101,16 @@ public class ClassSelect extends EditableInventory { } public class ProfessSelectionInventory extends GeneratedInventory { - public ProfessSelectionInventory(PlayerData playerData, EditableInventory editable) { + + @Nullable + private final Runnable profileRunnable; + + private boolean canClose; + + public ProfessSelectionInventory(PlayerData playerData, EditableInventory editable, @Nullable Runnable profileRunnable) { super(playerData, editable); + + this.profileRunnable = profileRunnable; } @Override @@ -107,7 +123,7 @@ public class ClassSelect extends EditableInventory { if (item instanceof ClassItem) { PlayerClass profess = ((ClassItem) item).playerClass; - if (playerData.getClassPoints() < 1) { + if (profileRunnable == null && playerData.getClassPoints() < 1) { MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); new ConfigMessage("cant-choose-new-class").send(player); return; @@ -125,10 +141,23 @@ public class ClassSelect extends EditableInventory { return; } + canClose = true; final PlayerClass playerClass = findDeepestSubclass(playerData, profess); - InventoryManager.CLASS_CONFIRM.get(MMOCoreUtils.ymlName(playerClass.getId())).newInventory(playerData, this, false).open(); + InventoryManager.CLASS_CONFIRM.get(MMOCoreUtils.ymlName(playerClass.getId())).newInventory(playerData, this, false, profileRunnable).open(); } } + + @Override + public void open() { + canClose = false; + super.open(); + } + + @Override + public void whenClosed(InventoryCloseEvent event) { + if (profileRunnable != null && !canClose) + Bukkit.getScheduler().runTaskLater(MMOCore.plugin, () -> open(), 2 * 20); + } } /** diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java index ad21f793..3ccb9b4c 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java @@ -126,7 +126,7 @@ public class SubclassSelect extends EditableInventory { return; } - InventoryManager.CLASS_CONFIRM.get(classId).newInventory(playerData, this, true).open(); + InventoryManager.CLASS_CONFIRM.get(classId).newInventory(playerData, this, true, null).open(); } } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java index bbe3e3fc..daf76dd1 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java @@ -22,6 +22,7 @@ public abstract class GeneratedInventory extends PluginInventory { public GeneratedInventory(PlayerData playerData, EditableInventory editable) { super(playerData); + this.editable = editable; this.adaptor = editable.getAdaptorType().supply(this); } @@ -66,6 +67,8 @@ public abstract class GeneratedInventory extends PluginInventory { @Override public void open() { + if (!getPlayerData().isOnline()) return; + /* * Very important, in order to prevent ghost items, the loaded items map * must be cleared when the inventory is updated or open at least twice diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java index 3ebc70db..6d9bc27c 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java @@ -28,7 +28,7 @@ public class ConfigManager { public final CommandVerbose commandVerbose = new CommandVerbose(); public boolean overrideVanillaExp, canCreativeCast, passiveSkillNeedBound, cobbleGeneratorXP, saveDefaultClassInfo, splitMainExp, splitProfessionExp, disableQuestBossBar, - pvpModeEnabled, pvpModeInvulnerabilityCanDamage; + pvpModeEnabled, pvpModeInvulnerabilityCanDamage, forceClassSelection; public String partyChatPrefix, noSkillBoundPlaceholder; public ChatColor staminaFull, staminaHalf, staminaEmpty; public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown; @@ -133,6 +133,7 @@ public class ConfigManager { splitMainExp = MMOCore.plugin.getConfig().getBoolean("party.main-exp-split"); splitProfessionExp = MMOCore.plugin.getConfig().getBoolean("party.profession-exp-split"); disableQuestBossBar = MMOCore.plugin.getConfig().getBoolean("mmocore-quests.disable-boss-bar"); + forceClassSelection = MMOCore.plugin.getConfig().getBoolean("force-class-selection"); // Combat pvpModeEnabled = config.getBoolean("pvp_mode.enabled"); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/GuildDataManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/GuildDataManager.java index ef81d0ee..2bd73fc5 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/GuildDataManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/GuildDataManager.java @@ -14,117 +14,121 @@ import net.Indyuce.mmocore.guild.provided.Guild; import javax.annotation.Nullable; public abstract class GuildDataManager { - protected final Map guilds = new HashMap<>(); + protected final Map guilds = new HashMap<>(); - public Guild newRegisteredGuild(UUID owner, String name, String tag) { - Guild guild = new Guild(owner, name, tag); - registerGuild(guild); - return guild; - } + public Guild newRegisteredGuild(UUID owner, String name, String tag) { + Guild guild = new Guild(owner, name, tag); + registerGuild(guild); + return guild; + } - public void registerGuild(Guild guild) { - guilds.put(guild.getId(), guild); - } + public void registerGuild(Guild guild) { + guilds.put(guild.getId(), guild); + } - public boolean isRegistered(Guild guild) { - return guilds.containsValue(guild); - } + public boolean isRegistered(Guild guild) { + return guilds.containsValue(guild); + } - public boolean isRegistered(String tag) { - return guilds.containsKey(tag); - } + public boolean isRegistered(String tag) { + return guilds.containsKey(tag); + } - public void unregisterGuild(Guild guild) { - guild.forEachMember(member -> guild.removeMember(member, true)); - // guild.getMembers().clear(); - guilds.remove(guild.getId()); - delete(guild); - } + public void unregisterGuild(Guild guild) { + guild.forEachMember(member -> guild.removeMember(member, true)); + // guild.getMembers().clear(); + guilds.remove(guild.getId()); + delete(guild); + } - @Nullable - public Guild getGuild(String guild) { - return guilds.get(guild); - } + public void saveAll() { + for (Guild guild : guilds.values()) save(guild); + } - public Collection getAll() { - return guilds.values(); - } + @Nullable + public Guild getGuild(String guild) { + return guilds.get(guild); + } - @Deprecated - public void reload() { - for (Guild guild : guilds.values()) - save(guild); - guilds.clear(); - load(); - config = new GuildConfiguration(); - } + public Collection getAll() { + return guilds.values(); + } - public abstract void save(Guild guild); + @Deprecated + public void reload() { + for (Guild guild : guilds.values()) + save(guild); + guilds.clear(); + load(); + config = new GuildConfiguration(); + } - // TODO move to constructor, useless to handle vie abstract method - public abstract void load(); + public abstract void save(Guild guild); - public abstract void delete(Guild guild); + // TODO move to constructor, useless to handle vie abstract method + public abstract void load(); - // TODO fix this - // Shitty code for loading config values for guilds. - private GuildConfiguration config; + public abstract void delete(Guild guild); - public GuildConfiguration getConfig() { - return config == null ? config = new GuildConfiguration() : config; - } + // TODO fix this + // Shitty code for loading config values for guilds. + private GuildConfiguration config; - public static class GuildConfiguration { - private final String prefix; - private final boolean uppercaseTags; - private final NamingRules tagRules, nameRules; + public GuildConfiguration getConfig() { + return config == null ? config = new GuildConfiguration() : config; + } - public GuildConfiguration() { - FileConfiguration config = new ConfigFile("guilds").getConfig(); + public static class GuildConfiguration { + private final String prefix; + private final boolean uppercaseTags; + private final NamingRules tagRules, nameRules; - this.prefix = config.getString("chat-prefix", "*"); - this.uppercaseTags = config.getBoolean("uppercase-tags", true); - this.tagRules = new NamingRules(config.getConfigurationSection("rules.tag")); - this.nameRules = new NamingRules(config.getConfigurationSection("rules.name")); - } + public GuildConfiguration() { + FileConfiguration config = new ConfigFile("guilds").getConfig(); - public String getPrefix() { - return prefix; - } + this.prefix = config.getString("chat-prefix", "*"); + this.uppercaseTags = config.getBoolean("uppercase-tags", true); + this.tagRules = new NamingRules(config.getConfigurationSection("rules.tag")); + this.nameRules = new NamingRules(config.getConfigurationSection("rules.name")); + } - public boolean shouldUppercaseTags() { - return uppercaseTags; - } + public String getPrefix() { + return prefix; + } - public NamingRules getTagRules() { - return tagRules; - } + public boolean shouldUppercaseTags() { + return uppercaseTags; + } - public NamingRules getNameRules() { - return nameRules; - } + public NamingRules getTagRules() { + return tagRules; + } - public static class NamingRules { - private final String regex; - private final int min, max; + public NamingRules getNameRules() { + return nameRules; + } - public NamingRules(ConfigurationSection config) { - regex = config.getString("matches", "[a-zA-Z-_!?]+"); - min = config.getInt("min-length", 3); - max = config.getInt("max-length", 5); - } + public static class NamingRules { + private final String regex; + private final int min, max; - public String getRegex() { - return regex; - } + public NamingRules(ConfigurationSection config) { + regex = config.getString("matches", "[a-zA-Z-_!?]+"); + min = config.getInt("min-length", 3); + max = config.getInt("max-length", 5); + } - public int getMin() { - return min; - } + public String getRegex() { + return regex; + } - public int getMax() { - return max; - } - } - } + public int getMin() { + return min; + } + + public int getMax() { + return max; + } + } + } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java index a29131e0..b0aa2584 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/PlayerDataManager.java @@ -33,4 +33,9 @@ public class PlayerDataManager extends SynchronizedDataManager