MPDB Migration Fixes, server shutdown synchronisation fixes and polish

feat/data-edit-commands
William 3 years ago
parent 049d92364f
commit 72d38fd443

@ -0,0 +1,39 @@
package me.william278.husksync.api.events;
import me.william278.husksync.PlayerData;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Represents an event that will be fired when a {@link Player} has finished
* being synchronised with the correct {@link PlayerData}.
*/
public class SyncCompleteEvent extends PlayerEvent {
private static final HandlerList HANDLER_LIST = new HandlerList();
private final PlayerData data;
public SyncCompleteEvent(Player player, PlayerData data) {
super(player);
this.data = data;
}
/**
* Returns the {@link PlayerData} which has just been set on the {@link Player}
* @return The {@link PlayerData} that has been set
*/
public PlayerData getData() {
return data;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

@ -0,0 +1,73 @@
package me.william278.husksync.api.events;
import me.william278.husksync.PlayerData;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Represents an event that will be fired before a {@link Player} is about
* to be synchronised with their {@link PlayerData}.
*/
public class SyncEvent extends PlayerEvent implements Cancellable {
private boolean cancelled;
private static final HandlerList HANDLER_LIST = new HandlerList();
private PlayerData data;
public SyncEvent(Player player, PlayerData data) {
super(player);
this.data = data;
}
/**
* Returns the {@link PlayerData} which has just been set on the {@link Player}
* @return The {@link PlayerData} that has been set
*/
public PlayerData getData() {
return data;
}
/**
* Sets the {@link PlayerData} to be synchronised to this player
* @param data The {@link PlayerData} to set to the player
*/
public void setData(PlayerData data) {
this.data = data;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
/**
* Gets the cancellation state of this event. A cancelled event will not
* be executed in the server, but will still pass to other plugins
*
* @return true if this event is cancelled
*/
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* Sets the cancellation state of this event. A cancelled event will not
* be executed in the server, but will still pass to other plugins.
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

@ -1,9 +1,10 @@
dependencies {
compileOnly project(':common')
compileOnly project(':api')
implementation project(path: ':common', configuration: 'shadow')
compileOnly 'redis.clients:jedis:3.7.0'
implementation 'org.bstats:bstats-bukkit:2.2.1'
implementation 'redis.clients:jedis:3.7.0'
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
compileOnly 'net.craftersland.data:bridge:3.36.3'
@ -11,7 +12,6 @@ dependencies {
}
shadowJar {
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
relocate 'org.bstats', 'me.William278.husksync.libraries.plan'
relocate 'de.themoep', 'me.William278.husksync.libraries.minedown'
}

@ -1,12 +1,15 @@
package me.william278.husksync;
import me.william278.husksync.bukkit.PlayerSetter;
import me.william278.husksync.bukkit.config.ConfigLoader;
import me.william278.husksync.bukkit.data.BukkitDataCache;
import me.william278.husksync.bukkit.listener.BukkitRedisListener;
import me.william278.husksync.bukkit.listener.EventListener;
import me.william278.husksync.bukkit.migrator.MPDBDeserializer;
import me.william278.husksync.redis.RedisMessage;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
@ -17,8 +20,9 @@ import java.util.logging.Level;
public final class HuskSyncBukkit extends JavaPlugin {
private static HuskSyncBukkit instance;
private static final int METRICS_ID = 13140;
private static HuskSyncBukkit instance;
public static HuskSyncBukkit getInstance() {
return instance;
}
@ -52,7 +56,8 @@ public final class HuskSyncBukkit extends JavaPlugin {
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
serverUUID.toString(),
Boolean.toString(isMySqlPlayerDataBridgeInstalled),
Bukkit.getName()).send();
Bukkit.getName())
.send();
attempts[0]++;
if (attempts[0] == 10) {
getInstance().getLogger().log(Level.WARNING, "Failed to complete handshake with the Proxy server; Please make sure your Proxy server is online and has HuskSync installed in its' /plugins/ folder. HuskSync will continue to try and establish a connection.");
@ -64,6 +69,7 @@ public final class HuskSyncBukkit extends JavaPlugin {
}
private void closeRedisHandshake() {
if (!handshakeCompleted) return;
try {
new RedisMessage(RedisMessage.MessageType.TERMINATE_HANDSHAKE,
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
@ -114,12 +120,29 @@ public final class HuskSyncBukkit extends JavaPlugin {
// Ensure redis is connected; establish a handshake
establishRedisHandshake();
// Initialize bStats metrics
try {
new Metrics(this, METRICS_ID);
} catch (Exception e) {
getLogger().info("Skipped metrics initialization");
}
// Log to console
getLogger().info("Enabled HuskSync (" + getServer().getName() + ") v" + getDescription().getVersion());
}
@Override
public void onDisable() {
// Update player data for disconnecting players
if (HuskSyncBukkit.handshakeCompleted && !HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled && Bukkit.getOnlinePlayers().size() > 0) {
getLogger().info("Saving data for remaining online players...");
for (Player player : Bukkit.getOnlinePlayers()) {
PlayerSetter.updatePlayerData(player);
}
getLogger().info("Data save complete!");
}
// Send termination handshake to proxy
closeRedisHandshake();

@ -3,6 +3,8 @@ package me.william278.husksync.bukkit;
import me.william278.husksync.HuskSyncBukkit;
import me.william278.husksync.PlayerData;
import me.william278.husksync.Settings;
import me.william278.husksync.api.events.SyncCompleteEvent;
import me.william278.husksync.api.events.SyncEvent;
import me.william278.husksync.bukkit.data.DataSerializer;
import me.william278.husksync.redis.RedisMessage;
import org.bukkit.*;
@ -26,6 +28,60 @@ public class PlayerSetter {
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
/**
* Returns the new serialized PlayerData for a player.
*
* @param player The {@link Player} to get the new serialized PlayerData for
* @return The {@link PlayerData}, serialized as a {@link String}
* @throws IOException If the serialization fails
*/
private static String getNewSerializedPlayerData(Player player) throws IOException {
return RedisMessage.serialize(new PlayerData(player.getUniqueId(),
DataSerializer.getSerializedInventoryContents(player.getInventory()),
DataSerializer.getSerializedEnderChestContents(player),
player.getHealth(),
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue(),
player.getHealthScale(),
player.getFoodLevel(),
player.getSaturation(),
player.getExhaustion(),
player.getInventory().getHeldItemSlot(),
DataSerializer.getSerializedEffectData(player),
player.getTotalExperience(),
player.getLevel(),
player.getExp(),
player.getGameMode().toString(),
DataSerializer.getSerializedStatisticData(player),
player.isFlying(),
DataSerializer.getSerializedAdvancements(player),
DataSerializer.getSerializedLocation(player)));
}
/**
* Update a {@link Player}'s data, sending it to the proxy
* @param player {@link Player} to send data to proxy
*/
public static void updatePlayerData(Player player) {
// Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData
try {
final String serializedPlayerData = getNewSerializedPlayerData(player);
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
serializedPlayerData).send();
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
}
// Clear player inventory and ender chest
player.getInventory().clear();
player.getEnderChest().clear();
}
/**
* Request a {@link Player}'s data from the proxy
* @param playerUUID The {@link UUID} of the {@link Player} to fetch PlayerData from
* @throws IOException If the request Redis message data fails to serialize
*/
public static void requestPlayerData(UUID playerUUID) throws IOException {
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_REQUEST,
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
@ -35,26 +91,34 @@ public class PlayerSetter {
/**
* Set a player from their PlayerData, based on settings
*
* @param player The {@link Player} to set
* @param data The {@link PlayerData} to assign to the player
* @param player The {@link Player} to set
* @param dataToSet The {@link PlayerData} to assign to the player
*/
public static void setPlayerFrom(Player player, PlayerData data) {
// If the data is flagged as being default data, skip setting
if (data.isUseDefaultData()) {
HuskSyncBukkit.bukkitCache.removeAwaitingDataFetch(player.getUniqueId());
return;
}
public static void setPlayerFrom(Player player, PlayerData dataToSet) {
Bukkit.getScheduler().runTask(plugin, () -> {
// Handle the SyncEvent
SyncEvent syncEvent = new SyncEvent(player, dataToSet);
Bukkit.getPluginManager().callEvent(syncEvent);
final PlayerData data = syncEvent.getData();
if (syncEvent.isCancelled()) {
return;
}
// Clear player
player.getInventory().clear();
player.getEnderChest().clear();
player.setExp(0);
player.setLevel(0);
// If the data is flagged as being default data, skip setting
if (data.isUseDefaultData()) {
HuskSyncBukkit.bukkitCache.removeAwaitingDataFetch(player.getUniqueId());
return;
}
HuskSyncBukkit.bukkitCache.removeAwaitingDataFetch(player.getUniqueId());
// Clear player
player.getInventory().clear();
player.getEnderChest().clear();
player.setExp(0);
player.setLevel(0);
// Set the player's data from the PlayerData
Bukkit.getScheduler().runTask(plugin, () -> {
HuskSyncBukkit.bukkitCache.removeAwaitingDataFetch(player.getUniqueId());
// Set the player's data from the PlayerData
try {
if (Settings.syncAdvancements) {
setPlayerAdvancements(player, DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements()), data);
@ -67,7 +131,7 @@ public class PlayerSetter {
setPlayerEnderChest(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedEnderChest()));
}
if (Settings.syncHealth) {
player.setHealthScale(data.getHealthScale() > 0 ? data.getHealthScale() : 0D);
player.setHealthScale(data.getHealthScale() <= 0 ? data.getHealthScale() : 20D);
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(data.getMaxHealth());
player.setHealth(data.getHealth());
}
@ -93,6 +157,9 @@ public class PlayerSetter {
player.setFlying(player.getAllowFlight() && data.isFlying());
setPlayerLocation(player, DataSerializer.deserializePlayerLocationData(data.getSerializedLocation()));
}
// Handle the SyncCompleteEvent
Bukkit.getPluginManager().callEvent(new SyncCompleteEvent(player, data));
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to deserialize PlayerData", e);
}

@ -40,7 +40,7 @@ public class BukkitRedisListener extends RedisListener {
return;
}
// Handle the message for the player
// Handle the incoming redis message; either for a specific player or the system
if (message.getMessageTarget().targetPlayerUUID() == null) {
switch (message.getMessageType()) {
case REQUEST_DATA_ON_JOIN -> {
@ -81,18 +81,20 @@ public class BukkitRedisListener extends RedisListener {
case DECODE_MPDB_DATA -> {
UUID serverUUID = UUID.fromString(message.getMessageDataElements()[0]);
String encodedData = message.getMessageDataElements()[1];
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),
RedisMessage.serialize(MPDBDeserializer.convertMPDBData(data)),
data.playerName)
.send();
} catch (IOException | ClassNotFoundException e) {
log(Level.SEVERE, "Failed to serialize encoded MPDB data");
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),
RedisMessage.serialize(MPDBDeserializer.convertMPDBData(data)),
data.playerName)
.send();
} catch (IOException | ClassNotFoundException e) {
log(Level.SEVERE, "Failed to serialize encoded MPDB data");
}
}
}
});
}
case RELOAD_CONFIG -> {
plugin.reloadConfig();

@ -28,35 +28,6 @@ public class EventListener implements Listener {
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
/**
* Returns the new serialized PlayerData for a player.
*
* @param player The {@link Player} to get the new serialized PlayerData for
* @return The {@link PlayerData}, serialized as a {@link String}
* @throws IOException If the serialization fails
*/
private static String getNewSerializedPlayerData(Player player) throws IOException {
return RedisMessage.serialize(new PlayerData(player.getUniqueId(),
DataSerializer.getSerializedInventoryContents(player.getInventory()),
DataSerializer.getSerializedEnderChestContents(player),
player.getHealth(),
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue(),
player.getHealthScale(),
player.getFoodLevel(),
player.getSaturation(),
player.getExhaustion(),
player.getInventory().getHeldItemSlot(),
DataSerializer.getSerializedEffectData(player),
player.getTotalExperience(),
player.getLevel(),
player.getExp(),
player.getGameMode().toString(),
DataSerializer.getSerializedStatisticData(player),
player.isFlying(),
DataSerializer.getSerializedAdvancements(player),
DataSerializer.getSerializedLocation(player)));
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
// When a player leaves a Bukkit server
@ -70,19 +41,8 @@ public class EventListener implements Listener {
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled) return; // If the plugin has not been initialized correctly
// Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData
try {
final String serializedPlayerData = getNewSerializedPlayerData(player);
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
serializedPlayerData).send();
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
}
// Clear player inventory and ender chest
player.getInventory().clear();
player.getEnderChest().clear();
// Update the player's data
PlayerSetter.updatePlayerData(player);
}
@EventHandler

@ -21,6 +21,7 @@ public class MPDBDeserializer {
// Instance of MySqlPlayerDataBridge
private static PD mySqlPlayerDataBridge;
public static void setMySqlPlayerDataBridge() {
mySqlPlayerDataBridge = (PD) Bukkit.getPluginManager().getPlugin("MySqlPlayerDataBridge");
}
@ -41,16 +42,36 @@ public class MPDBDeserializer {
// Convert the data
try {
// Set inventory
// Set inventory contents
Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER);
PlayerSetter.setInventory(inventory, getItemStackArrayFromMPDBBase64String(mpdbPlayerData.inventoryData));
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.getSerializedInventoryContents(inventory));
inventory.clear();
// Set ender chest
playerData.setSerializedEnderChest(DataSerializer.itemStackArrayToBase64(
getItemStackArrayFromMPDBBase64String(mpdbPlayerData.enderChestData)));
// 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.itemStackArrayToBase64(enderChestData));
// Set experience
playerData.setExpLevel(mpdbPlayerData.expLevel);

@ -2,7 +2,8 @@ dependencies {
compileOnly project(':common')
implementation project(path: ':common', configuration: 'shadow')
implementation 'redis.clients:jedis:3.7.0'
compileOnly 'redis.clients:jedis:3.7.0'
implementation 'org.bstats:bstats-bungeecord:2.2.1'
implementation 'com.zaxxer:HikariCP:5.0.0'
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
@ -10,7 +11,6 @@ dependencies {
}
shadowJar {
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
relocate 'com.zaxxer', 'me.William278.husksync.libraries.hikari'
relocate 'org.bstats', 'me.William278.husksync.libraries.plan'
relocate 'de.themoep', 'me.William278.husksync.libraries.minedown'

@ -13,6 +13,7 @@ import me.william278.husksync.bungeecord.migrator.MPDBMigrator;
import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import org.bstats.bungeecord.Metrics;
import java.io.IOException;
import java.sql.Connection;
@ -24,6 +25,8 @@ import java.util.logging.Level;
public final class HuskSyncBungeeCord extends Plugin {
private static final int METRICS_ID = 13141;
private static HuskSyncBungeeCord instance;
public static HuskSyncBungeeCord getInstance() {
return instance;
@ -58,10 +61,10 @@ public final class HuskSyncBungeeCord extends Plugin {
ConfigLoader.loadSettings(Objects.requireNonNull(ConfigManager.getConfig()));
// Load messages
ConfigManager.loadMessages(Settings.language);
ConfigManager.loadMessages();
// Load locales from messages
ConfigLoader.loadMessages(Objects.requireNonNull(ConfigManager.getMessages(Settings.language)));
ConfigLoader.loadMessageStrings(Objects.requireNonNull(ConfigManager.getMessages()));
// Initialize the database
database = switch (Settings.dataStorageType) {
@ -95,6 +98,13 @@ public final class HuskSyncBungeeCord extends Plugin {
// Prepare the migrator for use if needed
mpdbMigrator = new MPDBMigrator();
// Initialize bStats metrics
try {
new Metrics(this, METRICS_ID);
} catch (Exception e) {
getLogger().info("Skipped metrics initialization");
}
// Log to console
getLogger().info("Enabled HuskSync (" + getProxy().getName() + ") v" + getDescription().getVersion());
}

@ -97,8 +97,9 @@ public class HuskSyncCommand extends Command implements TabExecutor {
}
ConfigManager.loadConfig();
ConfigLoader.loadSettings(Objects.requireNonNull(ConfigManager.getConfig()));
ConfigManager.loadMessages(Settings.language);
ConfigLoader.loadMessages(Objects.requireNonNull(ConfigManager.getMessages(Settings.language)));
ConfigManager.loadMessages();
ConfigLoader.loadMessageStrings(Objects.requireNonNull(ConfigManager.getMessages()));
// Send reload request to all bukkit servers
try {

@ -9,6 +9,8 @@ import java.util.HashMap;
public class ConfigLoader {
public static void loadSettings(Configuration config) throws IllegalArgumentException {
Settings.language = config.getString("language", "en-gb");
Settings.serverType = Settings.ServerType.BUNGEECORD;
Settings.redisHost = config.getString("redis_settings.host", "localhost");
Settings.redisPort = config.getInt("redis_settings.port", 6379);
@ -31,7 +33,7 @@ public class ConfigLoader {
Settings.hikariConnectionTimeOut = config.getLong("data_storage_settings.hikari_pool_settings.connection_timeout", 5000);
}
public static void loadMessages(Configuration config) {
public static void loadMessageStrings(Configuration config) {
final HashMap<String,String> messages = new HashMap<>();
for (String messageId : config.getKeys()) {
messages.put(messageId, config.getString(messageId));

@ -1,6 +1,7 @@
package me.william278.husksync.bungeecord.config;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.Settings;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
@ -31,16 +32,16 @@ public class ConfigManager {
}
}
public static void loadMessages(String language) {
public static void loadMessages() {
try {
if (!plugin.getDataFolder().exists()) {
if (plugin.getDataFolder().mkdir()) {
plugin.getLogger().info("Created HuskSync data folder");
}
}
File messagesFile = new File(plugin.getDataFolder(), "messages_ " + language + ".yml");
File messagesFile = new File(plugin.getDataFolder(), "messages_" + Settings.language + ".yml");
if (!messagesFile.exists()) {
Files.copy(plugin.getResourceAsStream("languages" + File.separator + language + ".yml"), messagesFile.toPath());
Files.copy(plugin.getResourceAsStream("languages/" + Settings.language + ".yml"), messagesFile.toPath());
plugin.getLogger().info("Created HuskSync messages file");
}
} catch (Exception e) {
@ -58,9 +59,9 @@ public class ConfigManager {
}
}
public static Configuration getMessages(String language) {
public static Configuration getMessages() {
try {
File configFile = new File(plugin.getDataFolder(), "messages-" + language + ".yml");
File configFile = new File(plugin.getDataFolder(), "messages_" + Settings.language + ".yml");
return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
} catch (IOException e) {
plugin.getLogger().log(Level.CONFIG, "An IOException occurred fetching the messages file", e);

@ -9,6 +9,7 @@ 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.RedisMessage;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -70,7 +71,7 @@ public class BungeeRedisListener extends RedisListener {
// Send synchronisation complete message
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(requestingPlayerUUID);
if (player.isConnected()) {
player.sendMessage(new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
player.sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
}
} catch (IOException e) {
log(Level.SEVERE, "Failed to serialize data when replying to a data request");
@ -104,7 +105,7 @@ public class BungeeRedisListener extends RedisListener {
.send();
// Send synchronisation complete message
player.sendMessage(new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
player.sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
}
}
} catch (IOException e) {

@ -54,8 +54,9 @@ public class MPDBMigrator {
}
}
if (synchronisedServersWithMpdb < 1) {
plugin.getLogger().log(Level.WARNING, "Failed to start migration because at least one Spigot server must be online and have both HuskSync and MySqlPlayerDataBridge installed. " +
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;
}
migratedDataSent = 0;
@ -144,7 +145,7 @@ public class MPDBMigrator {
}
}
} catch (SQLException e) {
plugin.getLogger().log(Level.SEVERE, "An exception occurred getting ender chest", 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");
}
@ -161,7 +162,7 @@ public class MPDBMigrator {
for (MPDBPlayerData data : mpdbPlayerData) {
if (data.playerUUID.equals(playerUUID)) {
data.expLevel = resultSet.getInt("exp_lvl");
data.expProgress = resultSet.getInt("exp");
data.expProgress = resultSet.getFloat("exp");
data.totalExperience = resultSet.getInt("total_exp");
break;
}
@ -169,7 +170,7 @@ public class MPDBMigrator {
}
}
} catch (SQLException e) {
plugin.getLogger().log(Level.SEVERE, "An exception occurred getting ender chest", 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");
}
@ -229,6 +230,7 @@ public class MPDBMigrator {
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
});
}

@ -1,3 +1,4 @@
language: 'en-gb'
redis_settings:
host: 'localhost'
port: 6379
@ -16,4 +17,5 @@ data_storage_settings:
minimum_idle: 10
maximum_lifetime: 1800000
keepalive_time: 0
connection_timeout: 5000
connection_timeout: 5000
config_file_version: 1.0

@ -24,7 +24,4 @@ shadowJar {
// Exclude some unnecessary files
exclude "**/module-info.class"
exclude "module-info.class"
// Relocations
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
}

@ -140,7 +140,7 @@ public class PlayerData implements Serializable {
*/
public static PlayerData DEFAULT_PLAYER_DATA(UUID playerUUID) {
PlayerData data = new PlayerData(playerUUID, "", "", 20,
20, 0, 20, 10, 1, 0,
20, 20, 20, 10, 1, 0,
"", 0, 0, 0, "SURVIVAL",
"", false, "", "");
data.useDefaultData = true;

@ -2,7 +2,7 @@ name: HuskSync
version: @version@
main: me.william278.husksync.HuskSyncBungeeCord
author: William278
description: 'A modern, cross-server player data synchronisation system'
description: 'A modern, cross-server player data synchronization system'
libraries:
- mysql:mysql-connector-java:8.0.25
- org.xerial:sqlite-jdbc:3.36.0.3

@ -3,5 +3,5 @@ version: @version@
main: me.william278.husksync.HuskSyncBukkit
api-version: 1.16
author: William278
description: 'A modern, cross-server player data synchronisation system'
description: 'A modern, cross-server player data synchronization system'
softdepend: [MysqlPlayerDataBridge]

@ -1,10 +1,14 @@
dependencies {
implementation project(path: ":common", configuration: 'shadow')
implementation project(path: ":api", configuration: 'shadow')
implementation project(path: ":bukkit", configuration: 'shadow')
implementation project(path: ":bungeecord", configuration: 'shadow')
}
shadowJar {
// Relocations
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
destinationDirectory.set(file("$rootDir/target/"))
archiveBaseName.set('HuskSync')
archiveClassifier.set('')

@ -7,6 +7,7 @@ pluginManagement {
rootProject.name = 'HuskSync'
include 'common'
include 'api'
include 'bukkit'
include 'bungeecord'
include 'plugin'
Loading…
Cancel
Save