From 088c795ede5e16b38f254a502800e7ae97c75b58 Mon Sep 17 00:00:00 2001 From: Jules Date: Thu, 16 Oct 2025 16:57:20 +0200 Subject: [PATCH] Player data load refactor --- .../manager/data/PlayerDataManager.java | 9 ++ .../data/sql/MMOCoreDataSynchronizer.java | 140 ------------------ .../data/sql/PlayerDataTableUpdater.java | 6 +- .../manager/data/sql/SQLDataHandler.java | 129 +++++++++++++++- .../data/sql/SQLOfflinePlayerData.java | 2 +- .../data/yaml/YAMLPlayerDataHandler.java | 11 +- 6 files changed, 139 insertions(+), 158 deletions(-) delete mode 100644 MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/MMOCoreDataSynchronizer.java 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 b32648d6..550845b9 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 @@ -1,13 +1,16 @@ package net.Indyuce.mmocore.manager.data; +import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.data.SynchronizedDataManager; import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.event.PlayerLevelChangeEvent; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.comp.profile.MMOCoreProfileDataModule; import net.Indyuce.mmocore.manager.data.yaml.YAMLPlayerDataHandler; import net.Indyuce.mmocore.player.DefaultPlayerData; import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.NotNull; public class PlayerDataManager extends SynchronizedDataManager { private DefaultPlayerData defaultData = DefaultPlayerData.DEFAULT; @@ -30,6 +33,12 @@ public class PlayerDataManager extends SynchronizedDataManager { - public MMOCoreDataSynchronizer(SQLDataHandler handler, PlayerData data) { - super("mmocore_playerdata", "uuid", handler.getDataSource(), data); - } - - @Override - public void loadData(ResultSet result) throws SQLException { - - // Reset stats linked to triggers - getData().resetTriggerStats(); - - getData().setClassPoints(result.getInt("class_points")); - getData().setSkillPoints(result.getInt("skill_points")); - getData().setSkillReallocationPoints(result.getInt("skill_reallocation_points")); - getData().setSkillTreeReallocationPoints(result.getInt("skill_tree_reallocation_points")); - getData().setAttributePoints(result.getInt("attribute_points")); - getData().setAttributeReallocationPoints(result.getInt("attribute_realloc_points")); - getData().setLevel(result.getInt("level"), PlayerLevelChangeEvent.Reason.CHOOSE_PROFILE); - getData().setExperience(result.getDouble("experience")); - - if (!isEmpty(result.getString("class"))) - getData().setClass(MMOCore.plugin.classManager.get(result.getString("class"))); - - if (!isEmpty(result.getString("times_claimed"))) { - JsonObject json = MythicLib.plugin.getGson().fromJson(result.getString("times_claimed"), JsonObject.class); - json.entrySet().forEach(entry -> getData().getItemClaims().put(entry.getKey(), entry.getValue().getAsInt())); - } - if (!isEmpty(result.getString("skill_tree_points"))) { - JsonObject json = MythicLib.plugin.getGson().fromJson(result.getString("skill_tree_points"), JsonObject.class); - for (SkillTree skillTree : MMOCore.plugin.skillTreeManager.getAll()) { - getData().setSkillTreePoints(skillTree.getId(), json.has(skillTree.getId()) ? json.get(skillTree.getId()).getAsInt() : 0); - } - getData().setSkillTreePoints("global", json.has("global") ? json.get("global").getAsInt() : 0); - } - - if (!isEmpty(result.getString("skill_tree_levels"))) { - JsonObject json = MythicLib.plugin.getGson().fromJson(result.getString("skill_tree_levels"), JsonObject.class); - for (SkillTreeNode skillTreeNode : MMOCore.plugin.skillTreeManager.getAllNodes()) { - getData().setNodeLevel(skillTreeNode, json.has(skillTreeNode.getFullId()) ? json.get(skillTreeNode.getFullId()).getAsInt() : 0); - } - } - Set unlockedItems = new HashSet<>(); - if (!isEmpty(result.getString("unlocked_items"))) { - JsonArray unlockedItemsArray = MythicLib.plugin.getGson().fromJson(result.getString("unlocked_items"), JsonArray.class); - for (JsonElement item : unlockedItemsArray) - unlockedItems.add(item.getAsString()); - } - getData().setUnlockedItems(unlockedItems); - if (!isEmpty(result.getString("guild"))) { - final Guild guild = MMOCore.plugin.nativeGuildManager.getGuild(result.getString("guild")); - if (guild != null && guild.hasMember(getData().getUniqueId())) getData().setGuild(guild); - } - if (!isEmpty(result.getString("attributes"))) getData().getAttributes().load(result.getString("attributes")); - if (getData().isOnline()) - MMOCore.plugin.attributeManager.getAll().forEach(attribute -> getData().getAttributes().getInstance(attribute).updateStats()); - if (!isEmpty(result.getString("professions"))) - getData().getCollectionSkills().load(result.getString("professions")); - if (!isEmpty(result.getString("quests"))) getData().getQuestData().load(result.getString("quests")); - getData().getQuestData().updateBossBar(); - if (!isEmpty(result.getString("waypoints"))) - getData().getWaypoints().addAll(MMOCoreUtils.jsonArrayToList(result.getString("waypoints"))); - if (!isEmpty(result.getString("friends"))) - MMOCoreUtils.jsonArrayToList(result.getString("friends")).forEach(str -> getData().getFriends().add(UUID.fromString(str))); - if (!isEmpty(result.getString("skills"))) { - JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("skills"), JsonObject.class); - for (Map.Entry entry : object.entrySet()) - getData().setSkillLevel(entry.getKey(), entry.getValue().getAsInt()); - } - if (!isEmpty(result.getString("bound_skills"))) { - JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("bound_skills"), JsonObject.class); - for (Map.Entry entry : object.entrySet()) { - ClassSkill skill = getData().getProfess().getSkill(entry.getValue().getAsString()); - if (skill != null) getData().bindSkill(Integer.parseInt(entry.getKey()), skill); - } - } - if (!isEmpty(result.getString("class_info"))) { - JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("class_info"), JsonObject.class); - for (Map.Entry entry : object.entrySet()) { - try { - PlayerClass profess = MMOCore.plugin.classManager.get(entry.getKey()); - Validate.notNull(profess, "Could not find class '" + entry.getKey() + "'"); - getData().applyClassInfo(profess, new SavedClassInformation(entry.getValue().getAsJsonObject())); - } catch (IllegalArgumentException exception) { - MMOCore.log(Level.WARNING, "Could not load class info '" + entry.getKey() + "': " + exception.getMessage()); - } - } - } - - /* - * These should be loaded after to make sure that the - * MAX_MANA, MAX_STAMINA & MAX_STELLIUM stats are already loaded. - */ - getData().loadResources(result.getDouble("health"), result.getDouble("mana"), result.getDouble("stamina"), result.getDouble("stellium")); - - UtilityMethods.debug(MMOCore.plugin, "SQL", String.format("{ class: %s, level: %d }", getData().getProfess().getId(), getData().getLevel())); - } - - private boolean isEmpty(@Nullable String str) { - return str == null - || str.isEmpty() - || str.equalsIgnoreCase("null") - || str.equals("{}") - || str.equals("[]"); - } - - @Override - public void loadEmptyData() { - MMOCore.plugin.playerDataManager.getDefaultData().apply(getData(), PlayerLevelChangeEvent.Reason.CHOOSE_PROFILE); - UtilityMethods.debug(MMOCore.plugin, "SQL", "Loaded DEFAULT data for: '" + getData().getUniqueId() + "' as no saved data was found."); - } -} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/PlayerDataTableUpdater.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/PlayerDataTableUpdater.java index 8380d2eb..f5b180ff 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/PlayerDataTableUpdater.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/PlayerDataTableUpdater.java @@ -16,10 +16,6 @@ import java.sql.SQLException; import java.util.*; import java.util.logging.Level; -/** - * @deprecated Not implemented yet - */ -@Deprecated public class PlayerDataTableUpdater { private final PlayerData playerData; private final SQLDataSource provider; @@ -33,7 +29,7 @@ public class PlayerDataTableUpdater { } public void executeRequest(@NotNull SaveReason saveReason) { - final String request = "INSERT INTO mmocore_playerdata(uuid, " + formatCollection(requestMap.keySet(), false) + final String request = "INSERT INTO " + SQLDataHandler.DATA_TABLE_NAME + "(" + SQLDataHandler.UUID_FIELD_NAME + ", " + formatCollection(requestMap.keySet(), false) + ") VALUES('" + effectiveId + "'," + formatCollection(requestMap.values(), true) + ")" + " ON DUPLICATE KEY UPDATE " + formatMap() + ";"; diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/SQLDataHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/SQLDataHandler.java index 663803d6..65679ec5 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/SQLDataHandler.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/sql/SQLDataHandler.java @@ -1,25 +1,44 @@ package net.Indyuce.mmocore.manager.data.sql; +import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.UtilityMethods; +import io.lumine.mythic.lib.data.DataLoadResult; import io.lumine.mythic.lib.data.SaveReason; import io.lumine.mythic.lib.data.sql.SQLDataSource; import io.lumine.mythic.lib.data.sql.SQLSynchronizedDataHandler; import io.lumine.mythic.lib.gson.JsonArray; +import io.lumine.mythic.lib.gson.JsonElement; import io.lumine.mythic.lib.gson.JsonObject; +import io.lumine.mythic.lib.util.lang3.Validate; import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.event.PlayerLevelChangeEvent; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.SavedClassInformation; +import net.Indyuce.mmocore.api.util.MMOCoreUtils; +import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.manager.data.OfflinePlayerData; +import net.Indyuce.mmocore.skill.ClassSkill; +import net.Indyuce.mmocore.skilltree.SkillTreeNode; +import net.Indyuce.mmocore.skilltree.tree.SkillTree; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.sql.ResultSet; import java.sql.SQLException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.logging.Level; import java.util.stream.Collectors; public class SQLDataHandler extends SQLSynchronizedDataHandler { + public static final String DATA_TABLE_NAME = "mmocore_playerdata"; + public static final String UUID_FIELD_NAME = "uuid"; + public SQLDataHandler(SQLDataSource dataSource) { - super(dataSource); + super(dataSource, DATA_TABLE_NAME, UUID_FIELD_NAME); } private static final String[] NEW_COLUMNS = new String[]{ @@ -39,7 +58,8 @@ public class SQLDataHandler extends SQLSynchronizedDataHandler { + // TODO prepare + getDataSource().getResultAsync("SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = '" + DATA_TABLE_NAME + "' AND COLUMN_NAME = '" + columnName + "'", result -> { try { if (!result.next()) - getDataSource().executeUpdate("ALTER TABLE mmocore_playerdata ADD COLUMN " + columnName + " " + dataType); + getDataSource().executeUpdate("ALTER TABLE " + DATA_TABLE_NAME + " ADD COLUMN " + columnName + " " + dataType); } catch (SQLException exception) { exception.printStackTrace(); } @@ -85,12 +106,100 @@ public class SQLDataHandler extends SQLSynchronizedDataHandler playerData.getItemClaims().put(entry.getKey(), entry.getValue().getAsInt())); + } + if (!isEmpty(result.getString("skill_tree_points"))) { + JsonObject json = MythicLib.plugin.getGson().fromJson(result.getString("skill_tree_points"), JsonObject.class); + for (SkillTree skillTree : MMOCore.plugin.skillTreeManager.getAll()) { + playerData.setSkillTreePoints(skillTree.getId(), json.has(skillTree.getId()) ? json.get(skillTree.getId()).getAsInt() : 0); + } + playerData.setSkillTreePoints("global", json.has("global") ? json.get("global").getAsInt() : 0); + } + + if (!isEmpty(result.getString("skill_tree_levels"))) { + JsonObject json = MythicLib.plugin.getGson().fromJson(result.getString("skill_tree_levels"), JsonObject.class); + for (SkillTreeNode skillTreeNode : MMOCore.plugin.skillTreeManager.getAllNodes()) { + playerData.setNodeLevel(skillTreeNode, json.has(skillTreeNode.getFullId()) ? json.get(skillTreeNode.getFullId()).getAsInt() : 0); + } + } + Set unlockedItems = new HashSet<>(); + if (!isEmpty(result.getString("unlocked_items"))) { + JsonArray unlockedItemsArray = MythicLib.plugin.getGson().fromJson(result.getString("unlocked_items"), JsonArray.class); + for (JsonElement item : unlockedItemsArray) + unlockedItems.add(item.getAsString()); + } + playerData.setUnlockedItems(unlockedItems); + if (!isEmpty(result.getString("guild"))) { + final Guild guild = MMOCore.plugin.nativeGuildManager.getGuild(result.getString("guild")); + if (guild != null && guild.hasMember(playerData.getUniqueId())) playerData.setGuild(guild); + } + if (!isEmpty(result.getString("attributes"))) playerData.getAttributes().load(result.getString("attributes")); + if (playerData.isOnline()) + MMOCore.plugin.attributeManager.getAll().forEach(attribute -> playerData.getAttributes().getInstance(attribute).updateStats()); + if (!isEmpty(result.getString("professions"))) + playerData.getCollectionSkills().load(result.getString("professions")); + if (!isEmpty(result.getString("quests"))) playerData.getQuestData().load(result.getString("quests")); + playerData.getQuestData().updateBossBar(); + if (!isEmpty(result.getString("waypoints"))) + playerData.getWaypoints().addAll(MMOCoreUtils.jsonArrayToList(result.getString("waypoints"))); + if (!isEmpty(result.getString("friends"))) + MMOCoreUtils.jsonArrayToList(result.getString("friends")).forEach(str -> playerData.getFriends().add(UUID.fromString(str))); + if (!isEmpty(result.getString("skills"))) { + JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("skills"), JsonObject.class); + for (Map.Entry entry : object.entrySet()) + playerData.setSkillLevel(entry.getKey(), entry.getValue().getAsInt()); + } + if (!isEmpty(result.getString("bound_skills"))) { + JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("bound_skills"), JsonObject.class); + for (Map.Entry entry : object.entrySet()) { + ClassSkill skill = playerData.getProfess().getSkill(entry.getValue().getAsString()); + if (skill != null) playerData.bindSkill(Integer.parseInt(entry.getKey()), skill); + } + } + if (!isEmpty(result.getString("class_info"))) { + JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("class_info"), JsonObject.class); + for (Map.Entry entry : object.entrySet()) { + try { + PlayerClass profess = MMOCore.plugin.classManager.get(entry.getKey()); + Validate.notNull(profess, "Could not find class '" + entry.getKey() + "'"); + playerData.applyClassInfo(profess, new SavedClassInformation(entry.getValue().getAsJsonObject())); + } catch (IllegalArgumentException exception) { + MMOCore.log(Level.WARNING, "Could not load class info '" + entry.getKey() + "': " + exception.getMessage()); + } + } + } + + /* + * These should be loaded after to make sure that the + * MAX_MANA, MAX_STAMINA & MAX_STELLIUM stats are already loaded. + */ + playerData.loadResources(result.getDouble("health"), result.getDouble("mana"), result.getDouble("stamina"), result.getDouble("stellium")); + + UtilityMethods.debug(MMOCore.plugin, "SQL", String.format("{ class: %s, level: %d }", playerData.getProfess().getId(), playerData.getLevel())); + return new DataLoadResult(DataLoadResult.Type.SUCCESS, false, force); } @Override @@ -189,7 +298,11 @@ public class SQLDataHandler extends SQLSynchronizedDataHandler { + provider.getResult("SELECT * FROM "+DATA_TABLE_NAME+" WHERE uuid = '" + uuid + "';", (result) -> { try { MythicLib.debug("MMOCoreSQL", "Loading OFFLINE data for '" + uuid + "'."); if (!result.next()) { diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataHandler.java index de65e7ba..c02c3ca9 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataHandler.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataHandler.java @@ -1,6 +1,8 @@ package net.Indyuce.mmocore.manager.data.yaml; +import io.lumine.mythic.lib.data.DataLoadResult; import io.lumine.mythic.lib.data.yaml.YAMLSynchronizedDataHandler; +import io.lumine.mythic.lib.module.MMOPlugin; import io.lumine.mythic.lib.util.lang3.Validate; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.event.PlayerLevelChangeEvent; @@ -13,7 +15,6 @@ import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skilltree.SkillTreeNode; import net.Indyuce.mmocore.skilltree.tree.SkillTree; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -22,7 +23,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; public class YAMLPlayerDataHandler extends YAMLSynchronizedDataHandler { - public YAMLPlayerDataHandler(Plugin owning) { + public YAMLPlayerDataHandler(MMOPlugin owning) { super(owning); } @@ -37,7 +38,7 @@ public class YAMLPlayerDataHandler extends YAMLSynchronizedDataHandler