forked from public-mirrors/HuskSync
Remove use MPDB & internal migrator;
TODO: create migration plugin;feat/data-edit-commands
parent
32a5004fc7
commit
50af023d41
@ -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);
|
||||
}
|
||||
}
|
@ -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…
Reference in New Issue