forked from public-mirrors/HuskSync
Shrink built jar file size, work on MySQLPlayerDataBridge migrator
parent
f650db4438
commit
96c6a878c4
@ -0,0 +1,243 @@
|
|||||||
|
package net.william278.husksync.migrator;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import net.william278.husksync.BukkitHuskSync;
|
||||||
|
import net.william278.husksync.config.Settings;
|
||||||
|
import net.william278.husksync.data.*;
|
||||||
|
import net.william278.husksync.player.User;
|
||||||
|
import net.william278.mpdbconverter.MPDBConverter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class MpdbMigrator extends Migrator {
|
||||||
|
|
||||||
|
private final MPDBConverter mpdbConverter;
|
||||||
|
private String sourceHost;
|
||||||
|
private int sourcePort;
|
||||||
|
private String sourceUsername;
|
||||||
|
private String sourcePassword;
|
||||||
|
private String sourceDatabase;
|
||||||
|
private String sourceInventoryTable;
|
||||||
|
private String sourceEnderChestTable;
|
||||||
|
private String sourceExperienceTable;
|
||||||
|
|
||||||
|
public MpdbMigrator(@NotNull BukkitHuskSync plugin, @NotNull Plugin mySqlPlayerDataBridge) {
|
||||||
|
super(plugin);
|
||||||
|
this.mpdbConverter = MPDBConverter.getInstance(mySqlPlayerDataBridge);
|
||||||
|
this.sourceHost = plugin.getSettings().getStringValue(Settings.ConfigOption.DATABASE_HOST);
|
||||||
|
this.sourcePort = plugin.getSettings().getIntegerValue(Settings.ConfigOption.DATABASE_PORT);
|
||||||
|
this.sourceUsername = plugin.getSettings().getStringValue(Settings.ConfigOption.DATABASE_USERNAME);
|
||||||
|
this.sourcePassword = plugin.getSettings().getStringValue(Settings.ConfigOption.DATABASE_PASSWORD);
|
||||||
|
this.sourceDatabase = plugin.getSettings().getStringValue(Settings.ConfigOption.DATABASE_NAME);
|
||||||
|
this.sourceInventoryTable = "mpdb_inventory";
|
||||||
|
this.sourceEnderChestTable = "mpdb_enderchest";
|
||||||
|
this.sourceExperienceTable = "mpdb_experience";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Boolean> start() {
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Starting migration from MySQLPlayerDataBridge to HuskSync...");
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
// Create jdbc driver connection url
|
||||||
|
final String jdbcUrl = "jdbc:mysql://" + sourceHost + ":" + sourcePort + "/" + sourceDatabase;
|
||||||
|
|
||||||
|
// Create a new data source for the mpdb converter
|
||||||
|
try (final HikariDataSource connectionPool = new HikariDataSource()) {
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Establishing connection to MySQLPlayerDataBridge database...");
|
||||||
|
connectionPool.setJdbcUrl(jdbcUrl);
|
||||||
|
connectionPool.setUsername(sourceUsername);
|
||||||
|
connectionPool.setPassword(sourcePassword);
|
||||||
|
connectionPool.setPoolName((getIdentifier() + "_migrator_pool").toUpperCase());
|
||||||
|
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Downloading raw data from the MySQLPlayerDataBridge database...");
|
||||||
|
final List<MpdbData> dataToMigrate = new ArrayList<>();
|
||||||
|
try (final Connection connection = connectionPool.getConnection()) {
|
||||||
|
try (final PreparedStatement statement = connection.prepareStatement("""
|
||||||
|
SELECT `player_uuid`, `player_name`, `inventory`, `armor`, `enderchest`, `exp_lvl`, `exp`, `total_exp`
|
||||||
|
FROM `%source_inventory_table%`
|
||||||
|
INNER JOIN `%source_ender_chest_table%`
|
||||||
|
ON `%source_inventory_table%`.`player_uuid` = `%source_ender_chest_table%`.`player_uuid`
|
||||||
|
INNER JOIN `%source_experience_table%`
|
||||||
|
ON `%source_inventory_table%`.`player_uuid` = `%source_experience_table%`.`player_uuid`;
|
||||||
|
""".replaceAll(Pattern.quote("%source_inventory_table%"), sourceInventoryTable).replaceAll(Pattern.quote("%source_ender_chest_table%"), sourceEnderChestTable).replaceAll(Pattern.quote("%source_experience_table%"), sourceExperienceTable))) {
|
||||||
|
try (final ResultSet resultSet = statement.executeQuery()) {
|
||||||
|
int playersMigrated = 0;
|
||||||
|
while (resultSet.next()) {
|
||||||
|
dataToMigrate.add(new MpdbData(
|
||||||
|
new User(UUID.fromString(resultSet.getString("player_uuid")),
|
||||||
|
resultSet.getString("player_name")),
|
||||||
|
resultSet.getString("inventory"),
|
||||||
|
resultSet.getString("armor"),
|
||||||
|
resultSet.getString("enderchest"),
|
||||||
|
resultSet.getInt("exp_lvl"),
|
||||||
|
resultSet.getInt("exp"),
|
||||||
|
resultSet.getInt("total_exp")
|
||||||
|
));
|
||||||
|
playersMigrated++;
|
||||||
|
if (playersMigrated % 25 == 0) {
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Downloaded MySQLPlayerDataBridge data for " + playersMigrated + " players...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Completed download of " + dataToMigrate.size() + " entries from the MySQLPlayerDataBridge database!");
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Converting raw MySQLPlayerDataBridge data to HuskSync user data...");
|
||||||
|
dataToMigrate.forEach(data -> data.toUserData(mpdbConverter).thenAccept(convertedData ->
|
||||||
|
plugin.getDatabase().ensureUser(data.user()).thenRun(() ->
|
||||||
|
plugin.getDatabase().setUserData(data.user(), convertedData, DataSaveCause.MPDB_MIGRATION))));
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Migration complete for " + dataToMigrate.size() + " users in " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds!");
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLoggingAdapter().log(Level.SEVERE, "Error while migrating data: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleConfigurationCommand(@NotNull String[] args) {
|
||||||
|
if (args.length == 2) {
|
||||||
|
if (switch (args[0].toLowerCase()) {
|
||||||
|
case "host" -> {
|
||||||
|
this.sourceHost = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
case "port" -> {
|
||||||
|
try {
|
||||||
|
this.sourcePort = Integer.parseInt(args[1]);
|
||||||
|
yield true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
yield false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "username" -> {
|
||||||
|
this.sourceUsername = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
case "password" -> {
|
||||||
|
this.sourcePassword = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
case "database" -> {
|
||||||
|
this.sourceDatabase = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
case "inventory_table" -> {
|
||||||
|
this.sourceInventoryTable = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
case "ender_chest_table" -> {
|
||||||
|
this.sourceEnderChestTable = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
case "experience_table" -> {
|
||||||
|
this.sourceExperienceTable = args[1];
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
default -> false;
|
||||||
|
}) {
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, getHelpMenu());
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Successfully set " + args[0] + " to " + args[1]);
|
||||||
|
} else {
|
||||||
|
plugin.getLoggingAdapter().log(Level.INFO, "Invalid operation, could not set " + args[0] + " to " + args[1] + " (is it a valid option?)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return "mpdb";
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "MySQLPlayerDataBridge";
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String getHelpMenu() {
|
||||||
|
return """
|
||||||
|
=== MySQLPlayerDataBridge Migration Wizard ==========
|
||||||
|
This will migrate inventories, ender chests and XP
|
||||||
|
from the MySQLPlayerDataBridge plugin to HuskSync.
|
||||||
|
|
||||||
|
To prevent excessive migration times, other non-vital
|
||||||
|
data will not be transferred.
|
||||||
|
|
||||||
|
STEP 1] Please ensure no players are on the server.
|
||||||
|
|
||||||
|
STEP 2] HuskSync will need to connect to the database
|
||||||
|
used to hold the source MySQLPlayerDataBridge data.
|
||||||
|
Please check these database parameters are OK:
|
||||||
|
- host: %source_host%
|
||||||
|
- port: %source_port%
|
||||||
|
- username: %source_username%
|
||||||
|
- password: %source_password%
|
||||||
|
- database: %source_database%
|
||||||
|
- inventory_table: %source_inventory_table%
|
||||||
|
- ender_chest_table: %source_ender_chest_table%
|
||||||
|
- experience_table: %source_xp_table%
|
||||||
|
If any of these are not correct, please correct them
|
||||||
|
using the command:
|
||||||
|
"husksync migrate mpdb set <parameter> <host>"
|
||||||
|
(e.g.: "husksync migrate mpdb set host 123.456.789")
|
||||||
|
|
||||||
|
STEP 3] HuskSync will migrate data into the database
|
||||||
|
tables configures in the config.yml file of this
|
||||||
|
server. Please make sure you're happy with this
|
||||||
|
before proceeding.
|
||||||
|
|
||||||
|
STEP 4] To start the migration, please run:
|
||||||
|
"husksync migrate mpdb start"
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
|
||||||
|
private record MpdbData(@NotNull User user, @NotNull String serializedInventory,
|
||||||
|
@NotNull String serializedArmor, @NotNull String serializedEnderChest,
|
||||||
|
int expLevel, float expProgress, int totalExp) {
|
||||||
|
@NotNull
|
||||||
|
public CompletableFuture<UserData> toUserData(@NotNull MPDBConverter converter) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
// Combine inventory and armour
|
||||||
|
final Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER);
|
||||||
|
inventory.setContents(converter.getItemStackFromSerializedData(serializedInventory));
|
||||||
|
final ItemStack[] armor = converter.getItemStackFromSerializedData(serializedArmor).clone();
|
||||||
|
for (int i = 36; i < 36 + armor.length; i++) {
|
||||||
|
inventory.setItem(i, armor[i - 36]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create user data record
|
||||||
|
return new UserData(
|
||||||
|
new StatusData(20, 20, 0, 20, 10,
|
||||||
|
1, 0, totalExp, expLevel, expProgress, "SURVIVAL",
|
||||||
|
false),
|
||||||
|
new ItemData(BukkitSerializer.serializeItemStackArray(inventory.getContents()).join()),
|
||||||
|
new ItemData(BukkitSerializer.serializeItemStackArray(converter
|
||||||
|
.getItemStackFromSerializedData(serializedEnderChest)).join()),
|
||||||
|
new PotionEffectData(""), new ArrayList<>(),
|
||||||
|
new StatisticsData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>()),
|
||||||
|
new LocationData("world", UUID.randomUUID(), "NORMAL", 0, 0, 0,
|
||||||
|
0f, 0f),
|
||||||
|
new PersistentDataContainerData(new HashMap<>()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,24 +1,26 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation 'commons-io:commons-io:2.11.0'
|
implementation 'commons-io:commons-io:2.11.0'
|
||||||
implementation 'dev.dejvokep:boosted-yaml:1.2'
|
|
||||||
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
|
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
|
||||||
implementation 'com.zaxxer:HikariCP:5.0.1'
|
|
||||||
implementation 'com.google.code.gson:gson:2.9.0'
|
implementation 'com.google.code.gson:gson:2.9.0'
|
||||||
implementation 'org.xerial.snappy:snappy-java:1.1.8.4'
|
implementation('redis.clients:jedis:4.2.3') {
|
||||||
implementation 'redis.clients:jedis:4.2.3'
|
exclude module: 'slf4j-api'
|
||||||
|
}
|
||||||
|
implementation ('com.zaxxer:HikariCP:5.0.1') {
|
||||||
|
exclude module: 'slf4j-api'
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOnly 'dev.dejvokep:boosted-yaml:1.2'
|
||||||
|
compileOnly 'org.xerial.snappy:snappy-java:1.1.8.4'
|
||||||
compileOnly 'org.jetbrains:annotations:23.0.0'
|
compileOnly 'org.jetbrains:annotations:23.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'org.apache', 'net.william278.husksync.libraries'
|
relocate 'org.apache', 'net.william278.husksync.libraries'
|
||||||
relocate 'dev.dejvokep', 'net.william278.husksync.libraries'
|
|
||||||
relocate 'de.themoep', 'net.william278.husksync.libraries'
|
relocate 'de.themoep', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.jetbrains', 'net.william278.husksync.libraries'
|
relocate 'org.jetbrains', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.intellij', 'net.william278.husksync.libraries'
|
relocate 'org.intellij', 'net.william278.husksync.libraries'
|
||||||
relocate 'com.zaxxer', 'net.william278.husksync.libraries'
|
relocate 'com.zaxxer', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.slf4j', 'net.william278.husksync.libraries.slf4j'
|
|
||||||
relocate 'com.google', 'net.william278.husksync.libraries'
|
relocate 'com.google', 'net.william278.husksync.libraries'
|
||||||
//relocate 'org.xerial', 'net.william278.husksync.libraries'
|
|
||||||
relocate 'redis.clients', 'net.william278.husksync.libraries'
|
relocate 'redis.clients', 'net.william278.husksync.libraries'
|
||||||
|
relocate 'org.json', 'net.william278.husksync.libraries.json'
|
||||||
}
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package net.william278.husksync.migrator;
|
||||||
|
|
||||||
|
import net.william278.husksync.HuskSync;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
//todo: implement this
|
||||||
|
public class LegacyMigrator extends Migrator {
|
||||||
|
|
||||||
|
public LegacyMigrator(@NotNull HuskSync plugin) {
|
||||||
|
super(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Boolean> start() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleConfigurationCommand(@NotNull String[] args) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return "legacy";
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "HuskSync v1.x --> v2.x";
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String getHelpMenu() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package net.william278.husksync.migrator;
|
||||||
|
|
||||||
|
import net.william278.husksync.HuskSync;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public abstract class Migrator {
|
||||||
|
|
||||||
|
protected final HuskSync plugin;
|
||||||
|
|
||||||
|
protected Migrator(@NotNull HuskSync plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the migrator
|
||||||
|
*
|
||||||
|
* @return A future that will be completed when the migrator is done
|
||||||
|
*/
|
||||||
|
public abstract CompletableFuture<Boolean> start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a command that sets migrator configuration parameters
|
||||||
|
* @param args The command arguments
|
||||||
|
*/
|
||||||
|
public abstract void handleConfigurationCommand(@NotNull String[] args);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public abstract String getIdentifier();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public abstract String getName();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public abstract String getHelpMenu();
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue