SavingPlayerData. Object to store all the data of an offline player. Restructuration for /mmocore admin transferdata

This commit is contained in:
Ka0rX 2022-07-27 10:53:21 +02:00
parent 8983a83bed
commit e0c3fca182
8 changed files with 461 additions and 170 deletions

View File

@ -53,8 +53,8 @@
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<source>9</source> <source>16</source>
<target>9</target> <target>16</target>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<compilerArgument>-proc:none</compilerArgument> <compilerArgument>-proc:none</compilerArgument>
</configuration> </configuration>

View File

@ -656,6 +656,8 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
refreshVanillaExp(); refreshVanillaExp();
} }
public double getExperience() { public double getExperience() {
return experience; return experience;
} }
@ -953,6 +955,34 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
combat = new CombatRunnable(this); combat = new CombatRunnable(this);
} }
/**
* @return The savingPlayerData object corresponding to the playerData
*/
public SavingPlayerData getSavingPlayerData() {
return new SavingPlayerData(
getUniqueId(),
getClassPoints(),
getSkillPoints(),
getAttributePoints(),
getAttributeReallocationPoints(),
getLevel(),
getExperience(),
getProfess().getId(),
getLastLogin(),
hasGuild() ? getGuild().getId() : null,
getWaypoints(),
getFriends(),
getBoundSkills().stream().map(skill -> skill.getSkill().getHandler().getId()).toList(),
mapSkillLevels(),
getItemClaims(),
getAttributes().toJsonString(),
getCollectionSkills().toJsonString(),
getQuestData().toJsonString(),
createClassInfoData(this).toString());
}
@Override @Override
public int hashCode() { public int hashCode() {
return mmoData.hashCode(); return mmoData.hashCode();

View File

@ -0,0 +1,42 @@
package net.Indyuce.mmocore.api.player;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.skill.ClassSkill;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* Just a container holding the basic playerData information that are needed to save it in a database.
*/
public record SavingPlayerData(
UUID uuid,
int classPoints,
int skillPoints,
int attributePoints,
int attributeReallocationPoints,
int level,
double experience,
String classId,
long lastLogin,
String guildId,
Set<String> waypoints,
List<UUID> friends,
List<String> boundSkills,
Map<String,Integer> skills,
Map<String,Integer> itemClaims,
String attributes,
String collectionsSkills,
String questData,
String classInfoData)
{
}

View File

@ -100,6 +100,7 @@ public class PlayerQuests implements Closable {
} }
} }
if (jo.has("finished")) if (jo.has("finished"))
for (Entry<String, JsonElement> entry : jo.getAsJsonObject("finished").entrySet()) for (Entry<String, JsonElement> entry : jo.getAsJsonObject("finished").entrySet())
finished.put(entry.getKey(), entry.getValue().getAsLong()); finished.put(entry.getKey(), entry.getValue().getAsLong());

View File

@ -3,6 +3,7 @@ package net.Indyuce.mmocore.command.rpg.admin;
import io.lumine.mythic.lib.command.api.CommandTreeNode; import io.lumine.mythic.lib.command.api.CommandTreeNode;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.SavingPlayerData;
import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.DataProvider; import net.Indyuce.mmocore.manager.data.DataProvider;
import net.Indyuce.mmocore.manager.data.mysql.MySQLDataProvider; import net.Indyuce.mmocore.manager.data.mysql.MySQLDataProvider;
@ -10,6 +11,14 @@ import net.Indyuce.mmocore.manager.data.yaml.YAMLDataProvider;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* This command allows to transfer data from your actual storage type * This command allows to transfer data from your actual storage type
@ -22,10 +31,35 @@ public class TransferDataTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender commandSender, String[] strings) { public CommandResult execute(CommandSender commandSender, String[] strings) {
DataProvider provider = null;
final List<UUID> playerUUIDs = new ArrayList<>();
if (MMOCore.plugin.dataProvider instanceof YAMLDataProvider) {
File folder = new File(MMOCore.plugin.getDataFolder() + "/userdata");
playerUUIDs.addAll(Arrays.stream(folder.listFiles())
.map(file -> UUID.fromString(file.getName().replace(".yml", "")))
.collect(Collectors.toList()));
} else {
((MySQLDataProvider) MMOCore.plugin.dataProvider).getResult(
"SELECT uuid from mmocore_playerdata", (result) -> {
try { try {
while (result.next()) {
playerUUIDs.add(UUID.fromString(result.getString("uuid")));
}
} catch (SQLException e) {
e.printStackTrace();
}
});
}
List<SavingPlayerData> savingPlayerDataList = new ArrayList<>();
for (UUID uuid : playerUUIDs) {
MMOCore.plugin.dataProvider.getDataManager().loadSavingPlayerData(uuid, savingPlayerDataList);
}
final DataProvider provider;
if (MMOCore.plugin.dataProvider instanceof YAMLDataProvider) { if (MMOCore.plugin.dataProvider instanceof YAMLDataProvider) {
provider = new MySQLDataProvider(MMOCore.plugin.getConfig()); provider = new MySQLDataProvider(MMOCore.plugin.getConfig());
((MySQLDataProvider) provider).load(); ((MySQLDataProvider) provider).load();
@ -33,9 +67,15 @@ public class TransferDataTreeNode extends CommandTreeNode {
provider = new YAMLDataProvider(); provider = new YAMLDataProvider();
} }
//5 seconds later we put all this data into the other data storage.
new BukkitRunnable() {
@Override
public void run() {
try {
// Save player data // Save player data
for (PlayerData data : PlayerData.getAll()) for (SavingPlayerData data : savingPlayerDataList)
if (data.isFullyLoaded())
provider.getDataManager().saveData(data); provider.getDataManager().saveData(data);
// Save guild info // Save guild info
@ -47,17 +87,18 @@ public class TransferDataTreeNode extends CommandTreeNode {
if (provider != null && provider instanceof MySQLDataProvider) { if (provider != null && provider instanceof MySQLDataProvider) {
((MySQLDataProvider) provider).close(); ((MySQLDataProvider) provider).close();
} }
return CommandResult.FAILURE;
} }
DataProvider finalProvider = provider; }
}.runTaskLater(MMOCore.plugin, 100L);
//We close the connection 10 s later to avoid memory leaks. //We close the connection 10 s later to avoid memory leaks.
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
if (finalProvider != null && finalProvider instanceof MySQLDataProvider) { if (provider != null && provider instanceof MySQLDataProvider) {
((MySQLDataProvider) finalProvider).close(); ((MySQLDataProvider) provider).close();
} }
} }
}.runTaskLater(MMOCore.plugin, 200); }.runTaskLater(MMOCore.plugin, 200);

View File

@ -8,6 +8,7 @@ import io.lumine.mythic.lib.player.TemporaryPlayerData;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.AsyncPlayerDataLoadEvent; import net.Indyuce.mmocore.api.event.AsyncPlayerDataLoadEvent;
import net.Indyuce.mmocore.api.event.PlayerDataLoadEvent; import net.Indyuce.mmocore.api.event.PlayerDataLoadEvent;
import net.Indyuce.mmocore.api.player.SavingPlayerData;
import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.OfflinePlayerData;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
@ -45,7 +46,7 @@ public abstract class PlayerDataManager {
} }
public static void loadDataFromJson(PlayerData data, String json) { public static void loadDataFromJson(@NotNull PlayerData data, String json) {
JsonObject object = MythicLib.plugin.getJson().parse(json, JsonObject.class); JsonObject object = MythicLib.plugin.getJson().parse(json, JsonObject.class);
data.setClassPoints(object.get("class_points").getAsInt()); data.setClassPoints(object.get("class_points").getAsInt());
@ -191,8 +192,12 @@ public abstract class PlayerDataManager {
/** /**
* Called when player data must be loaded from database or config. * Called when player data must be loaded from database or config.
* *
* @param data Player data to load * @param uuid The uuid to load
* @param savingPlayerDataList the list where the data will be added.
*/ */
public abstract void loadSavingPlayerData(UUID uuid,List<SavingPlayerData> savingPlayerDataList);
public abstract void loadData(PlayerData data); public abstract void loadData(PlayerData data);
/** /**
@ -202,7 +207,11 @@ public abstract class PlayerDataManager {
* *
* @param data Player data to save * @param data Player data to save
*/ */
public abstract void saveData(PlayerData data); public void saveData(PlayerData data) {
saveData(data.getSavingPlayerData());
}
public abstract void saveData(SavingPlayerData data);
public class DefaultPlayerData { public class DefaultPlayerData {
private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints; private final int level, classPoints, skillPoints, attributePoints, attrReallocPoints;

View File

@ -7,26 +7,23 @@ import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.OfflinePlayerData;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.SavingPlayerData;
import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation; import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.PlayerDataManager; import net.Indyuce.mmocore.manager.data.PlayerDataManager;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.net.Socket;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static net.Indyuce.mmocore.api.player.PlayerData.createClassInfoData;
public class MySQLPlayerDataManager extends PlayerDataManager { public class MySQLPlayerDataManager extends PlayerDataManager {
private final MySQLDataProvider provider; private final MySQLDataProvider provider;
@ -152,38 +149,39 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
return s == null || s.equalsIgnoreCase("null") || s.equalsIgnoreCase("{}") || s.equalsIgnoreCase("[]") || s.equalsIgnoreCase(""); return s == null || s.equalsIgnoreCase("null") || s.equalsIgnoreCase("{}") || s.equalsIgnoreCase("[]") || s.equalsIgnoreCase("");
} }
@Override @Override
public void saveData(PlayerData data) { public void saveData(SavingPlayerData data) {
MySQLTableEditor sql = new MySQLTableEditor(MySQLTableEditor.Table.PLAYERDATA, data.getUniqueId(),provider); MySQLTableEditor sql = new MySQLTableEditor(MySQLTableEditor.Table.PLAYERDATA, data.uuid(), provider);
MMOCore.sqlDebug("Saving data for: '" + data.getUniqueId() + "'..."); MMOCore.sqlDebug("Saving data for: '" + data.uuid() + "'...");
sql.updateData("class_points", data.getClassPoints()); sql.updateData("class_points", data.classPoints());
sql.updateData("skill_points", data.getSkillPoints()); sql.updateData("skill_points", data.skillPoints());
sql.updateData("attribute_points", data.getAttributePoints()); sql.updateData("attribute_points", data.attributePoints());
sql.updateData("attribute_realloc_points", data.getAttributeReallocationPoints()); sql.updateData("attribute_realloc_points", data.attributeReallocationPoints());
sql.updateData("level", data.getLevel()); sql.updateData("level", data.level());
sql.updateData("experience", data.getExperience()); sql.updateData("experience", data.experience());
sql.updateData("class", data.getProfess().getId()); sql.updateData("class", data.classId());
sql.updateData("last_login", data.getLastLogin()); sql.updateData("last_login", data.lastLogin());
sql.updateData("guild", data.hasGuild() ? data.getGuild().getId() : null); sql.updateData("guild", data.guildId());
sql.updateJSONArray("waypoints", data.getWaypoints()); sql.updateJSONArray("waypoints", data.waypoints());
sql.updateJSONArray("friends", data.getFriends().stream().map(UUID::toString).collect(Collectors.toList())); sql.updateJSONArray("friends", data.friends().stream().map(UUID::toString).collect(Collectors.toList()));
sql.updateJSONArray("bound_skills", data.getBoundSkills().stream().map(skill -> skill.getSkill().getHandler().getId()).collect(Collectors.toList())); sql.updateJSONArray("bound_skills", data.boundSkills());
sql.updateJSONObject("skills", data.mapSkillLevels().entrySet()); sql.updateJSONObject("skills", data.skills().entrySet());
sql.updateJSONObject("times_claimed", data.getItemClaims().entrySet()); sql.updateJSONObject("times_claimed", data.itemClaims().entrySet());
sql.updateData("attributes", data.getAttributes().toJsonString()); sql.updateData("attributes", data.attributes());
sql.updateData("professions", data.getCollectionSkills().toJsonString()); sql.updateData("professions", data.collectionsSkills());
sql.updateData("quests", data.getQuestData().toJsonString()); sql.updateData("quests", data.questData());
sql.updateData("class_info", createClassInfoData(data).toString()); sql.updateData("class_info", data.classInfoData());
sql.updateData("is_saved", 1); sql.updateData("is_saved", 1);
MMOCore.sqlDebug("Saved data for: " + data.getUniqueId()); MMOCore.sqlDebug("Saved data for: " + data.uuid());
MMOCore.sqlDebug(String.format("{ class: %s, level: %d }", data.getProfess().getId(), data.getLevel())); MMOCore.sqlDebug(String.format("{ class: %s, level: %d }", data.classId(), data.level()));
} }
@ -195,6 +193,60 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
return isLoaded(uuid) ? get(uuid) : new MySQLOfflinePlayerData(uuid); return isLoaded(uuid) ? get(uuid) : new MySQLOfflinePlayerData(uuid);
} }
@Override
public void loadSavingPlayerData(UUID uuid, List<SavingPlayerData> savingPlayerDataList) {
provider.getResult("SELECT * FROM mmocore_playerdata WHERE uuid = '" + uuid + "';", (result) -> {
try {
if (result.next()) {
Map<String, Integer> skills = new HashMap<>();
Map<String, Integer> itemClaims = new HashMap<>();
if (!isEmpty(result.getString("skills"))) {
JsonObject object = MythicLib.plugin.getJson().parse(result.getString("skills"), JsonObject.class);
for (Entry<String, JsonElement> entry : object.entrySet())
skills.put(entry.getKey(), entry.getValue().getAsInt());
}
if (!isEmpty(result.getString("times_claimed"))) {
JsonObject json = new JsonParser().parse(result.getString("times_claimed")).getAsJsonObject();
json.entrySet().forEach(entry -> itemClaims.put(entry.getKey(), entry.getValue().getAsInt()));
}
SavingPlayerData data = new SavingPlayerData(
uuid,
result.getInt("class_points"),
result.getInt("skill_points"),
result.getInt("attribute_points"),
result.getInt("attribute_realloc_points"),
result.getInt("level"),
result.getInt("experience"),
result.getString("class"),
result.getLong("last_login"),
result.getString("guild"),
MMOCoreUtils.jsonArrayToList(result.getString("waypoints")).stream().collect(Collectors.toSet()),
MMOCoreUtils.jsonArrayToList(result.getString("friends")).stream().map(str -> UUID.fromString(str)).toList(),
MMOCoreUtils.jsonArrayToList(result.getString("bound_skills")).stream().toList(),
skills,
itemClaims,
result.getString("attributes"),
result.getString("professions"),
result.getString("quests"),
result.getString("class_info"));
savingPlayerDataList.add(data);
}
} catch (SQLException e) {
e.printStackTrace();
}
});
}
public class MySQLOfflinePlayerData extends OfflinePlayerData { public class MySQLOfflinePlayerData extends OfflinePlayerData {
private int level; private int level;
@ -258,3 +310,4 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
} }

View File

@ -1,6 +1,14 @@
package net.Indyuce.mmocore.manager.data.yaml; package net.Indyuce.mmocore.manager.data.yaml;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.SavingPlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.ConfigFile; import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.OfflinePlayerData;
@ -10,12 +18,11 @@ import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.DataProvider; import net.Indyuce.mmocore.manager.data.DataProvider;
import net.Indyuce.mmocore.manager.data.PlayerDataManager; import net.Indyuce.mmocore.manager.data.PlayerDataManager;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -139,9 +146,117 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
file.save(); file.save();
} }
/**
* Used to save Data from a SavingPlayerDataInstance (Data of an offline player)
* @param data
*/
@Override
public void saveData(SavingPlayerData data) {
ConfigFile file = new ConfigFile(data.uuid());
FileConfiguration config = file.getConfig();
config.set("class-points", data.classPoints());
config.set("skill-points", data.skillPoints());
config.set("attribute-points", data.attributePoints());
// config.set("skill-realloc-points", skillReallocationPoints);
config.set("attribute-realloc-points", data.attributeReallocationPoints());
config.set("level", data.level());
config.set("experience", data.experience());
config.set("class", data.classId());
config.set("waypoints", data.waypoints());
config.set("friends", data.friends());
config.set("last-login", data.lastLogin());
config.set("guild", data.guildId());
config.set("skill", null);
data.skills().forEach((key1, value) -> config.set("skill." + key1, value));
data.itemClaims().forEach((key, times) -> config.set("times-claimed." + key, times));
List<String> boundSkills = new ArrayList<>();
data.boundSkills().forEach(skill -> boundSkills.add(skill));
config.set("bound-skills", boundSkills);
config.set("attribute", null);
Gson parser = new Gson();
JsonObject jo = parser.fromJson(data.attributes(), JsonObject.class);
for (Map.Entry<String, JsonElement> entry : jo.entrySet()) {
try {
String id = entry.getKey().toLowerCase().replace("_", "-").replace(" ", "-");
config.set("attributes." + id, entry.getValue().getAsInt());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
jo = parser.fromJson(data.collectionsSkills(), JsonObject.class);
config.createSection("profession");
ConfigurationSection section = config.getConfigurationSection("profession");
// Load profession exp and levels
for (Map.Entry<String, JsonElement> entry : jo.entrySet())
if (MMOCore.plugin.professionManager.has(entry.getKey())) {
JsonObject value = entry.getValue().getAsJsonObject();
section.set(entry.getKey() + ".exp", value.get("exp").getAsDouble());
section.set(entry.getKey() + ".level", value.get("level").getAsInt());
}
config.set("quest", null);
config.createSection("quest");
section = config.getConfigurationSection("quest");
jo = parser.fromJson(data.questData(), JsonObject.class);
if (jo.has("current")) {
JsonObject cur = jo.getAsJsonObject("current");
try {
section.set("current.id", cur.get("id").getAsString());
section.set("current.objective", cur.get("objective").getAsInt());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (jo.has("finished"))
for (Map.Entry<String, JsonElement> entry : jo.getAsJsonObject("finished").entrySet())
section.set("finished." + entry.getKey(), entry.getValue().getAsLong());
config.set("class-info", null);
jo = parser.fromJson(data.classInfoData(), JsonObject.class);
for (Map.Entry<String, JsonElement> entry : jo.entrySet()) {
try {
String key = entry.getKey();
JsonObject info = entry.getValue().getAsJsonObject();
config.set("class-info." + key + ".level", info.get("level").getAsInt());
config.set("class-info." + key + ".experience", info.get("experience").getAsDouble());
config.set("class-info." + key + ".skill-points", info.get("skill-points").getAsInt());
config.set("class-info." + key + ".attribute-points", info.get("attribute-points").getAsInt());
config.set("class-info." + key + ".attribute-realloc-points", info.get("attribute-realloc-points").getAsInt());
if (info.has("attribute"))
for (Map.Entry<String, JsonElement> attributesEntry : info.getAsJsonObject("attribute").entrySet())
config.set("class-info." + key + ".attribute." + attributesEntry.getKey(), attributesEntry.getValue().getAsInt());
if (info.has("skill"))
for (Map.Entry<String, JsonElement> skillsEntry : info.getAsJsonObject("skill").entrySet())
config.set("class-info." + key + ".skill." + skillsEntry.getKey(), skillsEntry.getValue().getAsInt());
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load class info '" + entry.getKey() + "': " + exception.getMessage());
}
}
file.save();
}
@NotNull @NotNull
@Override @Override
public OfflinePlayerData getOffline(UUID uuid) { public OfflinePlayerData getOffline(UUID uuid) {
return isLoaded(uuid) ? get(uuid) : new YAMLOfflinePlayerData(uuid); return isLoaded(uuid) ? get(uuid) : new YAMLOfflinePlayerData(uuid);
} }
@Override
public void loadSavingPlayerData(UUID uuid, List<SavingPlayerData> savingPlayerDataList) {
}
} }