Remove use MPDB & internal migrator;

TODO: create migration plugin;
feat/data-edit-commands
HarvelsX 3 years ago
parent 32a5004fc7
commit 50af023d41

@ -7,7 +7,6 @@ dependencies {
implementation 'org.bstats:bstats-bukkit:2.2.1' implementation 'org.bstats:bstats-bukkit:2.2.1'
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT' implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
compileOnly 'net.craftersland.data:bridge:4.0.1'
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT' compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
} }

@ -6,7 +6,6 @@ import me.william278.husksync.bukkit.config.ConfigLoader;
import me.william278.husksync.bukkit.data.BukkitDataCache; import me.william278.husksync.bukkit.data.BukkitDataCache;
import me.william278.husksync.bukkit.listener.BukkitRedisListener; import me.william278.husksync.bukkit.listener.BukkitRedisListener;
import me.william278.husksync.bukkit.listener.BukkitEventListener; import me.william278.husksync.bukkit.listener.BukkitEventListener;
import me.william278.husksync.bukkit.migrator.MPDBDeserializer;
import me.william278.husksync.redis.RedisMessage; import me.william278.husksync.redis.RedisMessage;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -104,14 +103,6 @@ public final class HuskSyncBukkit extends JavaPlugin {
new BukkitUpdateChecker().logToConsole(); new BukkitUpdateChecker().logToConsole();
} }
// Check if MySqlPlayerDataBridge is installed
Plugin mySqlPlayerDataBridge = Bukkit.getPluginManager().getPlugin("MySqlPlayerDataBridge");
if (mySqlPlayerDataBridge != null) {
isMySqlPlayerDataBridgeInstalled = mySqlPlayerDataBridge.isEnabled();
MPDBDeserializer.setMySqlPlayerDataBridge();
getLogger().info("MySQLPlayerDataBridge detected! Disabled data synchronisation to prevent data loss. To perform a migration, run \"husksync migrate\" in your Proxy (Bungeecord, Waterfall, etc) server console.");
}
// Initialize last data update UUID cache // Initialize last data update UUID cache
bukkitCache = new BukkitDataCache(); bukkitCache = new BukkitDataCache();

@ -8,8 +8,6 @@ import me.william278.husksync.Settings;
import me.william278.husksync.bukkit.config.ConfigLoader; import me.william278.husksync.bukkit.config.ConfigLoader;
import me.william278.husksync.bukkit.data.DataViewer; import me.william278.husksync.bukkit.data.DataViewer;
import me.william278.husksync.bukkit.util.PlayerSetter; import me.william278.husksync.bukkit.util.PlayerSetter;
import me.william278.husksync.bukkit.migrator.MPDBDeserializer;
import me.william278.husksync.migrator.MPDBPlayerData;
import me.william278.husksync.redis.RedisListener; import me.william278.husksync.redis.RedisListener;
import me.william278.husksync.redis.RedisMessage; import me.william278.husksync.redis.RedisMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -89,24 +87,6 @@ public class BukkitRedisListener extends RedisListener {
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, HuskSyncBukkit::establishRedisHandshake, 20); Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, HuskSyncBukkit::establishRedisHandshake, 20);
} }
} }
case DECODE_MPDB_DATA -> {
UUID serverUUID = UUID.fromString(message.getMessageDataElements()[0]);
String encodedData = message.getMessageDataElements()[1];
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
if (serverUUID.equals(HuskSyncBukkit.serverUUID)) {
try {
MPDBPlayerData data = (MPDBPlayerData) RedisMessage.deserialize(encodedData);
new RedisMessage(RedisMessage.MessageType.DECODED_MPDB_DATA_SET,
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null, Settings.cluster),
RedisMessage.serialize(MPDBDeserializer.convertMPDBData(data)),
data.playerName)
.send();
} catch (IOException | ClassNotFoundException e) {
log(Level.SEVERE, "Failed to serialize encoded MPDB data");
}
}
});
}
case RELOAD_CONFIG -> { case RELOAD_CONFIG -> {
plugin.reloadConfig(); plugin.reloadConfig();
ConfigLoader.loadSettings(plugin.getConfig()); ConfigLoader.loadSettings(plugin.getConfig());

@ -1,100 +0,0 @@
package me.william278.husksync.bukkit.migrator;
import me.william278.husksync.HuskSyncBukkit;
import me.william278.husksync.PlayerData;
import me.william278.husksync.bukkit.util.PlayerSetter;
import me.william278.husksync.bukkit.data.DataSerializer;
import me.william278.husksync.migrator.MPDBPlayerData;
import net.craftersland.data.bridge.PD;
import org.bukkit.Bukkit;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
public class MPDBDeserializer {
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
// Instance of MySqlPlayerDataBridge
private static PD mySqlPlayerDataBridge;
public static void setMySqlPlayerDataBridge() {
mySqlPlayerDataBridge = (PD) Bukkit.getPluginManager().getPlugin("MySqlPlayerDataBridge");
}
/**
* Convert MySqlPlayerDataBridge ({@link MPDBPlayerData}) data to HuskSync's {@link PlayerData}
*
* @param mpdbPlayerData The {@link MPDBPlayerData} to convert
* @return The converted {@link PlayerData}
*/
public static PlayerData convertMPDBData(MPDBPlayerData mpdbPlayerData) {
PlayerData playerData = PlayerData.DEFAULT_PLAYER_DATA(mpdbPlayerData.playerUUID);
playerData.useDefaultData = false;
if (!HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled) {
plugin.getLogger().log(Level.SEVERE, "MySqlPlayerDataBridge is not installed, failed to serialize data!");
return null;
}
// Convert the data
try {
// Set inventory contents
Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER);
if (!mpdbPlayerData.inventoryData.isEmpty() && !mpdbPlayerData.inventoryData.equalsIgnoreCase("none")) {
PlayerSetter.setInventory(inventory, getItemStackArrayFromMPDBBase64String(mpdbPlayerData.inventoryData));
}
// Set armor (if there is data; MPDB stores empty data with literally the word "none". Obviously.)
int armorSlot = 36;
if (!mpdbPlayerData.armorData.isEmpty() && !mpdbPlayerData.armorData.equalsIgnoreCase("none")) {
ItemStack[] armorItems = getItemStackArrayFromMPDBBase64String(mpdbPlayerData.armorData);
for (ItemStack armorPiece : armorItems) {
if (armorPiece != null) {
inventory.setItem(armorSlot, armorPiece);
}
armorSlot++;
}
}
// Now apply the contents and clear the temporary inventory variable
playerData.setSerializedInventory(DataSerializer.serializeInventory(inventory.getContents()));
// Set ender chest (again, if there is data)
ItemStack[] enderChestData;
if (!mpdbPlayerData.enderChestData.isEmpty() && !mpdbPlayerData.enderChestData.equalsIgnoreCase("none")) {
enderChestData = getItemStackArrayFromMPDBBase64String(mpdbPlayerData.enderChestData);
} else {
enderChestData = new ItemStack[0];
}
playerData.setSerializedEnderChest(DataSerializer.serializeInventory(enderChestData));
// Set experience
playerData.setExpLevel(mpdbPlayerData.expLevel);
playerData.setExpProgress(mpdbPlayerData.expProgress);
playerData.setTotalExperience(mpdbPlayerData.totalExperience);
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING, "Failed to convert MPDB data to HuskSync's format!");
e.printStackTrace();
}
return playerData;
}
/**
* Returns an ItemStack array from a decoded base 64 string in MySQLPlayerDataBridge's format
*
* @param data The encoded ItemStack[] string from MySQLPlayerDataBridge
* @return The {@link ItemStack[]} array
* @throws InvocationTargetException If an error occurs during decoding
* @throws IllegalAccessException If an error occurs during decoding
*/
public static ItemStack[] getItemStackArrayFromMPDBBase64String(String data) throws InvocationTargetException, IllegalAccessException {
if (data.isEmpty()) {
return new ItemStack[0];
}
return mySqlPlayerDataBridge.getItemStackSerializer().fromBase64(data);
}
}

@ -9,7 +9,6 @@ import me.william278.husksync.bungeecord.data.sql.MySQL;
import me.william278.husksync.bungeecord.data.sql.SQLite; import me.william278.husksync.bungeecord.data.sql.SQLite;
import me.william278.husksync.bungeecord.listener.BungeeEventListener; import me.william278.husksync.bungeecord.listener.BungeeEventListener;
import me.william278.husksync.bungeecord.listener.BungeeRedisListener; import me.william278.husksync.bungeecord.listener.BungeeRedisListener;
import me.william278.husksync.bungeecord.migrator.MPDBMigrator;
import me.william278.husksync.bungeecord.util.BungeeUpdateChecker; import me.william278.husksync.bungeecord.util.BungeeUpdateChecker;
import me.william278.husksync.redis.RedisMessage; import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
@ -53,8 +52,6 @@ public final class HuskSyncBungeeCord extends Plugin {
return clusterDatabases.get(clusterId).getConnection(); return clusterDatabases.get(clusterId).getConnection();
} }
public static MPDBMigrator mpdbMigrator;
@Override @Override
public void onLoad() { public void onLoad() {
instance = this; instance = this;
@ -120,9 +117,6 @@ public final class HuskSyncBungeeCord extends Plugin {
// Register command // Register command
getProxy().getPluginManager().registerCommand(this, new HuskSyncCommand()); getProxy().getPluginManager().registerCommand(this, new HuskSyncCommand());
// Prepare the migrator for use if needed
mpdbMigrator = new MPDBMigrator();
// Initialize bStats metrics // Initialize bStats metrics
try { try {
new Metrics(this, METRICS_ID); new Metrics(this, METRICS_ID);

@ -9,7 +9,6 @@ import me.william278.husksync.Settings;
import me.william278.husksync.bungeecord.config.ConfigLoader; import me.william278.husksync.bungeecord.config.ConfigLoader;
import me.william278.husksync.bungeecord.config.ConfigManager; import me.william278.husksync.bungeecord.config.ConfigManager;
import me.william278.husksync.bungeecord.data.DataManager; import me.william278.husksync.bungeecord.data.DataManager;
import me.william278.husksync.bungeecord.migrator.MPDBMigrator;
import me.william278.husksync.redis.RedisMessage; import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
@ -191,123 +190,6 @@ public class HuskSyncCommand extends Command implements TabExecutor {
} else { } else {
sendAboutInformation(player); sendAboutInformation(player);
} }
} else {
// Database migration wizard
if (args.length >= 1) {
if (args[0].equalsIgnoreCase("migrate")) {
if (args.length == 1) {
sender.sendMessage(new MineDown(
"""
=== MySQLPlayerDataBridge Migration Wizard ==========
This will migrate data from the MySQLPlayerDataBridge
plugin to HuskSync.
Data that will be migrated:
- Inventories
- Ender Chests
- Experience points
Other non-vital data, such as current health, hunger
& potion effects will not be migrated to ensure that
migration does not take an excessive amount of time.
To do this, you need to have MySqlPlayerDataBridge
and HuskSync installed on one Spigot server as well
as HuskSync installed on the proxy (which you have)
>To proceed, type: husksync migrate setup""").toComponent());
} else {
switch (args[1].toLowerCase()) {
case "setup" -> sender.sendMessage(new MineDown(
"""
=== MySQLPlayerDataBridge Migration Wizard ==========
The following database settings will be used.
Please make sure they match the correct settings to
access your MySQLPlayerDataBridge Data
sourceHost: %1%
sourcePort: %2%
sourceDatabase: %3%
sourceUsername: %4%
sourcePassword: %5%
sourceInventoryTableName: %6%
sourceEnderChestTableName: %7%
sourceExperienceTableName: %8%
targetCluster: %9%
To change a setting, type:
husksync migrate setting <settingName> <value>
Please ensure no players are logged in to the network
and that at least one Spigot server is online with
both HuskSync AND MySqlPlayerDataBridge installed AND
that the server has been configured with the correct
Redis credentials.
Warning: Data will be saved to your configured data
source, which is currently a %10% database.
Please make sure you are happy with this, or stop
the proxy server and edit this in config.yml
Warning: Migration will overwrite any current data
saved by HuskSync. It will not, however, delete any
data from the source MySQLPlayerDataBridge database.
>When done, type: husksync migrate start"""
.replaceAll("%1%", MPDBMigrator.migrationSettings.sourceHost)
.replaceAll("%2%", String.valueOf(MPDBMigrator.migrationSettings.sourcePort))
.replaceAll("%3%", MPDBMigrator.migrationSettings.sourceDatabase)
.replaceAll("%4%", MPDBMigrator.migrationSettings.sourceUsername)
.replaceAll("%5%", MPDBMigrator.migrationSettings.sourcePassword)
.replaceAll("%6%", MPDBMigrator.migrationSettings.inventoryDataTable)
.replaceAll("%7%", MPDBMigrator.migrationSettings.enderChestDataTable)
.replaceAll("%8%", MPDBMigrator.migrationSettings.expDataTable)
.replaceAll("%9%", MPDBMigrator.migrationSettings.targetCluster)
.replaceAll("%10%", Settings.dataStorageType.toString())
).toComponent());
case "setting" -> {
if (args.length == 4) {
String value = args[3];
switch (args[2]) {
case "sourceHost", "host" -> MPDBMigrator.migrationSettings.sourceHost = value;
case "sourcePort", "port" -> {
try {
MPDBMigrator.migrationSettings.sourcePort = Integer.parseInt(value);
} catch (NumberFormatException e) {
sender.sendMessage(new MineDown("Error: Invalid value; port must be a number").toComponent());
return;
}
}
case "sourceDatabase", "database" -> MPDBMigrator.migrationSettings.sourceDatabase = value;
case "sourceUsername", "username" -> MPDBMigrator.migrationSettings.sourceUsername = value;
case "sourcePassword", "password" -> MPDBMigrator.migrationSettings.sourcePassword = value;
case "sourceInventoryTableName", "inventoryTableName", "inventoryTable" -> MPDBMigrator.migrationSettings.inventoryDataTable = value;
case "sourceEnderChestTableName", "enderChestTableName", "enderChestTable" -> MPDBMigrator.migrationSettings.enderChestDataTable = value;
case "sourceExperienceTableName", "experienceTableName", "experienceTable" -> MPDBMigrator.migrationSettings.expDataTable = value;
case "targetCluster", "cluster" -> MPDBMigrator.migrationSettings.targetCluster = value;
default -> {
sender.sendMessage(new MineDown("Error: Invalid setting; please use \"husksync migrate setup\" to view a list").toComponent());
return;
}
}
sender.sendMessage(new MineDown("Successfully updated setting: \"" + args[2] + "\" --> \"" + value + "\"").toComponent());
} else {
sender.sendMessage(new MineDown("Error: Invalid usage. Syntax: husksync migrate setting <settingName> <value>").toComponent());
}
}
case "start" -> {
sender.sendMessage(new MineDown("Starting MySQLPlayerDataBridge migration!...").toComponent());
HuskSyncBungeeCord.mpdbMigrator.start();
}
default -> sender.sendMessage(new MineDown("Error: Invalid argument for migration. Use \"husksync migrate\" to start the process").toComponent());
}
}
return;
}
}
sender.sendMessage(new MineDown("Error: Invalid syntax. Usage: husksync migrate <args>").toComponent());
} }
} }

@ -6,7 +6,6 @@ import me.william278.husksync.util.MessageManager;
import me.william278.husksync.PlayerData; import me.william278.husksync.PlayerData;
import me.william278.husksync.Settings; import me.william278.husksync.Settings;
import me.william278.husksync.bungeecord.data.DataManager; import me.william278.husksync.bungeecord.data.DataManager;
import me.william278.husksync.bungeecord.migrator.MPDBMigrator;
import me.william278.husksync.redis.RedisListener; import me.william278.husksync.redis.RedisListener;
import me.william278.husksync.redis.RedisMessage; import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
@ -168,31 +167,6 @@ public class BungeeRedisListener extends RedisListener {
HuskSyncBungeeCord.synchronisedServers.remove(serverToRemove); HuskSyncBungeeCord.synchronisedServers.remove(serverToRemove);
log(Level.INFO, "Terminated the handshake with " + bukkitBrand + " server (" + serverUUID + ")"); log(Level.INFO, "Terminated the handshake with " + bukkitBrand + " server (" + serverUUID + ")");
} }
case DECODED_MPDB_DATA_SET -> {
// Deserialize the PlayerData received
PlayerData playerData;
final String serializedPlayerData = message.getMessageDataElements()[0];
final String playerName = message.getMessageDataElements()[1];
try {
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
} catch (IOException | ClassNotFoundException e) {
log(Level.SEVERE, "Failed to deserialize PlayerData when handling incoming decoded MPDB data");
e.printStackTrace();
return;
}
// Add the incoming data to the data to be saved
MPDBMigrator.incomingPlayerData.put(playerData, playerName);
// Increment players migrated
MPDBMigrator.playersMigrated++;
plugin.getLogger().log(Level.INFO, "Migrated " + MPDBMigrator.playersMigrated + "/" + MPDBMigrator.migratedDataSent + " players.");
// When all the data has been received, save it
if (MPDBMigrator.migratedDataSent == MPDBMigrator.playersMigrated) {
MPDBMigrator.loadIncomingData(MPDBMigrator.incomingPlayerData);
}
}
} }
} }

@ -1,302 +0,0 @@
package me.william278.husksync.bungeecord.migrator;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.PlayerData;
import me.william278.husksync.Settings;
import me.william278.husksync.bungeecord.data.DataManager;
import me.william278.husksync.bungeecord.data.sql.Database;
import me.william278.husksync.bungeecord.data.sql.MySQL;
import me.william278.husksync.migrator.MPDBPlayerData;
import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.ProxyServer;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.UUID;
import java.util.logging.Level;
/**
* Class to handle migration of data from MySQLPlayerDataBridge
* <p>
* The migrator accesses and decodes MPDB's format directly.
* It does this by establishing a connection
*/
public class MPDBMigrator {
public static int migratedDataSent = 0;
public static int playersMigrated = 0;
private static final HuskSyncBungeeCord plugin = HuskSyncBungeeCord.getInstance();
public static HashMap<PlayerData, String> incomingPlayerData;
public static MigrationSettings migrationSettings = new MigrationSettings();
private static Settings.SynchronisationCluster targetCluster;
private static Database sourceDatabase;
private static HashSet<MPDBPlayerData> mpdbPlayerData;
public void start() {
if (ProxyServer.getInstance().getPlayers().size() > 0) {
plugin.getLogger().log(Level.WARNING, "Failed to start migration because there are players online. " +
"Your network has to be empty to migrate data for safety reasons.");
return;
}
int synchronisedServersWithMpdb = 0;
for (HuskSyncBungeeCord.Server server : HuskSyncBungeeCord.synchronisedServers) {
if (server.hasMySqlPlayerDataBridge()) {
synchronisedServersWithMpdb++;
}
}
if (synchronisedServersWithMpdb < 1) {
plugin.getLogger().log(Level.WARNING, "Failed to start migration because at least one Spigot server with both HuskSync and MySqlPlayerDataBridge installed is not online. " +
"Please start one Spigot server with HuskSync installed to begin migration.");
return;
}
for (Settings.SynchronisationCluster cluster : Settings.clusters) {
if (migrationSettings.targetCluster.equals(cluster.clusterId())) {
targetCluster = cluster;
break;
}
}
if (targetCluster == null) {
plugin.getLogger().log(Level.WARNING, "Failed to start migration because the target cluster could not be found. " +
"Please ensure the target cluster is correct, configured in the proxy config file, then try again");
return;
}
migratedDataSent = 0;
playersMigrated = 0;
mpdbPlayerData = new HashSet<>();
incomingPlayerData = new HashMap<>();
final MigrationSettings settings = migrationSettings;
// Get connection to source database
sourceDatabase = new MigratorMySQL(plugin, settings.sourceHost, settings.sourcePort,
settings.sourceDatabase, settings.sourceUsername, settings.sourcePassword, targetCluster);
sourceDatabase.load();
if (sourceDatabase.isInactive()) {
plugin.getLogger().log(Level.WARNING, "Failed to establish connection to the origin MySQL database. " +
"Please check you have input the correct connection details and try again.");
return;
}
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
prepareTargetDatabase();
getInventoryData();
getEnderChestData();
getExperienceData();
sendEncodedData();
});
}
// Clear the new database out of current data
private void prepareTargetDatabase() {
plugin.getLogger().log(Level.INFO, "Preparing target database...");
try (Connection connection = HuskSyncBungeeCord.getConnection(targetCluster.clusterId())) {
try (PreparedStatement statement = connection.prepareStatement("DELETE FROM " + targetCluster.playerTableName() + ";")) {
statement.executeUpdate();
}
try (PreparedStatement statement = connection.prepareStatement("DELETE FROM " + targetCluster.dataTableName() + ";")) {
statement.executeUpdate();
}
} catch (SQLException e) {
plugin.getLogger().log(Level.SEVERE, "An exception occurred preparing the target database", e);
} finally {
plugin.getLogger().log(Level.INFO, "Finished preparing target database!");
}
}
private void getInventoryData() {
plugin.getLogger().log(Level.INFO, "Getting inventory data from MySQLPlayerDataBridge...");
try (Connection connection = sourceDatabase.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + migrationSettings.inventoryDataTable + ";")) {
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
final UUID playerUUID = UUID.fromString(resultSet.getString("player_uuid"));
final String playerName = resultSet.getString("player_name");
MPDBPlayerData data = new MPDBPlayerData(playerUUID, playerName);
data.inventoryData = resultSet.getString("inventory");
data.armorData = resultSet.getString("armor");
mpdbPlayerData.add(data);
}
}
} catch (SQLException e) {
plugin.getLogger().log(Level.SEVERE, "An exception occurred getting inventory data", e);
} finally {
plugin.getLogger().log(Level.INFO, "Finished getting inventory data from MySQLPlayerDataBridge");
}
}
private void getEnderChestData() {
plugin.getLogger().log(Level.INFO, "Getting ender chest data from MySQLPlayerDataBridge...");
try (Connection connection = sourceDatabase.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + migrationSettings.enderChestDataTable + ";")) {
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
final UUID playerUUID = UUID.fromString(resultSet.getString("player_uuid"));
for (MPDBPlayerData data : mpdbPlayerData) {
if (data.playerUUID.equals(playerUUID)) {
data.enderChestData = resultSet.getString("enderchest");
break;
}
}
}
}
} catch (SQLException e) {
plugin.getLogger().log(Level.SEVERE, "An exception occurred getting ender chest data", e);
} finally {
plugin.getLogger().log(Level.INFO, "Finished getting ender chest data from MySQLPlayerDataBridge");
}
}
private void getExperienceData() {
plugin.getLogger().log(Level.INFO, "Getting experience data from MySQLPlayerDataBridge...");
try (Connection connection = sourceDatabase.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + migrationSettings.expDataTable + ";")) {
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
final UUID playerUUID = UUID.fromString(resultSet.getString("player_uuid"));
for (MPDBPlayerData data : mpdbPlayerData) {
if (data.playerUUID.equals(playerUUID)) {
data.expLevel = resultSet.getInt("exp_lvl");
data.expProgress = resultSet.getFloat("exp");
data.totalExperience = resultSet.getInt("total_exp");
break;
}
}
}
}
} catch (SQLException e) {
plugin.getLogger().log(Level.SEVERE, "An exception occurred getting experience data", e);
} finally {
plugin.getLogger().log(Level.INFO, "Finished getting experience data from MySQLPlayerDataBridge");
}
}
private void sendEncodedData() {
for (HuskSyncBungeeCord.Server processingServer : HuskSyncBungeeCord.synchronisedServers) {
if (processingServer.hasMySqlPlayerDataBridge()) {
for (MPDBPlayerData data : mpdbPlayerData) {
try {
new RedisMessage(RedisMessage.MessageType.DECODE_MPDB_DATA,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null, null),
processingServer.serverUUID().toString(),
RedisMessage.serialize(data))
.send();
migratedDataSent++;
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to serialize encoded MPDB data", e);
}
}
plugin.getLogger().log(Level.INFO, "Finished dispatching encoded data for " + migratedDataSent + " players; please wait for conversion to finish");
}
return;
}
}
/**
* Loads all incoming decoded MPDB data to the cache and database
*
* @param dataToLoad HashMap of the {@link PlayerData} to player Usernames that will be loaded
*/
public static void loadIncomingData(HashMap<PlayerData, String> dataToLoad) {
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
int playersSaved = 0;
plugin.getLogger().log(Level.INFO, "Saving data for " + playersMigrated + " players...");
for (PlayerData playerData : dataToLoad.keySet()) {
String playerName = dataToLoad.get(playerData);
// Add the player to the MySQL table
DataManager.ensurePlayerExists(playerData.getPlayerUUID(), playerName);
// Update the data in the cache and SQL
for (Settings.SynchronisationCluster cluster : Settings.clusters) {
DataManager.updatePlayerData(playerData, cluster);
break;
}
playersSaved++;
plugin.getLogger().log(Level.INFO, "Saved data for " + playersSaved + "/" + playersMigrated + " players");
}
// Mark as done when done
plugin.getLogger().log(Level.INFO, """
=== MySQLPlayerDataBridge Migration Wizard ==========
Migration complete!
Successfully migrated data for %1%/%2% players.
You should now uninstall MySQLPlayerDataBridge from
the rest of the Spigot servers, then restart them.
""".replaceAll("%1%", Integer.toString(MPDBMigrator.playersMigrated))
.replaceAll("%2%", Integer.toString(MPDBMigrator.migratedDataSent)));
sourceDatabase.close(); // Close source database
});
}
/**
* Class used to hold settings for the MPDB migration
*/
public static class MigrationSettings {
public String sourceHost;
public int sourcePort;
public String sourceDatabase;
public String sourceUsername;
public String sourcePassword;
public String inventoryDataTable;
public String enderChestDataTable;
public String expDataTable;
public String targetCluster;
public MigrationSettings() {
sourceHost = "localhost";
sourcePort = 3306;
sourceDatabase = "mpdb";
sourceUsername = "root";
sourcePassword = "pa55w0rd";
targetCluster = "main";
inventoryDataTable = "mpdb_inventory";
enderChestDataTable = "mpdb_enderchest";
expDataTable = "mpdb_experience";
}
}
/**
* MySQL class used for importing data from MPDB
*/
public static class MigratorMySQL extends MySQL {
public MigratorMySQL(HuskSyncBungeeCord instance, String host, int port, String database, String username, String password, Settings.SynchronisationCluster cluster) {
super(instance, cluster);
super.host = host;
super.port = port;
super.database = database;
super.username = username;
super.password = password;
super.params = "?useSSL=false";
super.dataPoolName = super.dataPoolName + "Migrator";
}
}
}

@ -1,35 +0,0 @@
package me.william278.husksync.migrator;
import java.io.Serializable;
import java.util.UUID;
/**
* A class that stores player data taken from MPDB's database, that can then be converted into HuskSync's format
*/
public class MPDBPlayerData implements Serializable {
/*
* Player information
*/
public final UUID playerUUID;
public final String playerName;
/*
* Inventory, ender chest and armor data
*/
public String inventoryData;
public String armorData;
public String enderChestData;
/*
* Experience data
*/
public int expLevel;
public float expProgress;
public int totalExperience;
public MPDBPlayerData(UUID playerUUID, String playerName) {
this.playerUUID = playerUUID;
this.playerName = playerName;
}
}
Loading…
Cancel
Save