mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-26 01:59:20 +00:00
1.0 release progress
This commit is contained in:
@@ -4,17 +4,76 @@ 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.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public final class HuskSyncBukkit extends JavaPlugin {
|
||||
|
||||
private static HuskSyncBukkit instance;
|
||||
|
||||
public static HuskSyncBukkit getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static BukkitDataCache bukkitCache;
|
||||
|
||||
// Used for establishing a handshake with redis
|
||||
public static UUID serverUUID;
|
||||
|
||||
// Has a handshake been established with the Bungee?
|
||||
public static boolean handshakeCompleted = false;
|
||||
|
||||
// THe handshake task to execute
|
||||
private static BukkitTask handshakeTask;
|
||||
|
||||
// Whether MySqlPlayerDataBridge is installed
|
||||
public static boolean isMySqlPlayerDataBridgeInstalled;
|
||||
|
||||
// Establish the handshake with the proxy
|
||||
public static void establishRedisHandshake() {
|
||||
serverUUID = UUID.randomUUID();
|
||||
getInstance().getLogger().log(Level.INFO, "Executing handshake with Proxy server...");
|
||||
final int[] attempts = {0}; // How many attempts to establish communication have been made
|
||||
handshakeTask = Bukkit.getScheduler().runTaskTimerAsynchronously(getInstance(), () -> {
|
||||
if (handshakeCompleted) {
|
||||
handshakeTask.cancel();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
new RedisMessage(RedisMessage.MessageType.CONNECTION_HANDSHAKE,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
serverUUID.toString(),
|
||||
Boolean.toString(isMySqlPlayerDataBridgeInstalled),
|
||||
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.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
getInstance().getLogger().log(Level.SEVERE, "Failed to serialize Redis message for handshake establishment", e);
|
||||
}
|
||||
}, 0, 60);
|
||||
}
|
||||
|
||||
private void closeRedisHandshake() {
|
||||
try {
|
||||
new RedisMessage(RedisMessage.MessageType.TERMINATE_HANDSHAKE,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
serverUUID.toString(),
|
||||
Bukkit.getName()).send();
|
||||
} catch (IOException e) {
|
||||
getInstance().getLogger().log(Level.SEVERE, "Failed to serialize Redis message for handshake termination", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
@@ -31,6 +90,14 @@ public final class HuskSyncBukkit extends JavaPlugin {
|
||||
reloadConfig();
|
||||
ConfigLoader.loadSettings(getConfig());
|
||||
|
||||
// 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
|
||||
bukkitCache = new BukkitDataCache();
|
||||
|
||||
@@ -38,7 +105,14 @@ public final class HuskSyncBukkit extends JavaPlugin {
|
||||
getServer().getPluginManager().registerEvents(new EventListener(), this);
|
||||
|
||||
// Initialize the redis listener
|
||||
new BukkitRedisListener();
|
||||
if (!new BukkitRedisListener().isActiveAndEnabled) {
|
||||
getPluginLoader().disablePlugin(this);
|
||||
getLogger().severe("Failed to initialize Redis; disabling HuskSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure redis is connected; establish a handshake
|
||||
establishRedisHandshake();
|
||||
|
||||
// Log to console
|
||||
getLogger().info("Enabled HuskSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
||||
@@ -46,6 +120,9 @@ public final class HuskSyncBukkit extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
// Send termination handshake to proxy
|
||||
closeRedisHandshake();
|
||||
|
||||
// Plugin shutdown logic
|
||||
getLogger().info("Disabled HuskSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package me.william278.husksync.bukkit;
|
||||
|
||||
import de.themoep.minedown.MineDown;
|
||||
import me.william278.husksync.HuskSyncBukkit;
|
||||
import me.william278.husksync.MessageStrings;
|
||||
import me.william278.husksync.PlayerData;
|
||||
import me.william278.husksync.Settings;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import me.william278.husksync.bukkit.data.DataSerializer;
|
||||
import me.william278.husksync.redis.RedisMessage;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.advancement.AdvancementProgress;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
@@ -19,12 +19,19 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class PlayerSetter {
|
||||
|
||||
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
|
||||
|
||||
public static void requestPlayerData(UUID playerUUID) throws IOException {
|
||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_REQUEST,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
playerUUID.toString()).send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a player from their PlayerData, based on settings
|
||||
*
|
||||
@@ -34,15 +41,23 @@ public class PlayerSetter {
|
||||
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;
|
||||
}
|
||||
|
||||
// Clear player
|
||||
player.getInventory().clear();
|
||||
player.getEnderChest().clear();
|
||||
player.setExp(0);
|
||||
player.setLevel(0);
|
||||
|
||||
HuskSyncBukkit.bukkitCache.removeAwaitingDataFetch(player.getUniqueId());
|
||||
|
||||
// Set the player's data from the PlayerData
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
try {
|
||||
if (Settings.syncAdvancements) {
|
||||
// Sync advancements first so that any rewards will be overridden
|
||||
setPlayerAdvancements(player, DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements()));
|
||||
setPlayerAdvancements(player, DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements()), data);
|
||||
}
|
||||
if (Settings.syncInventories) {
|
||||
setPlayerInventory(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedInventory()));
|
||||
@@ -52,6 +67,7 @@ public class PlayerSetter {
|
||||
setPlayerEnderChest(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedEnderChest()));
|
||||
}
|
||||
if (Settings.syncHealth) {
|
||||
player.setHealthScale(data.getHealthScale() > 0 ? data.getHealthScale() : 0D);
|
||||
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(data.getMaxHealth());
|
||||
player.setHealth(data.getHealth());
|
||||
}
|
||||
@@ -61,9 +77,8 @@ public class PlayerSetter {
|
||||
player.setExhaustion(data.getSaturationExhaustion());
|
||||
}
|
||||
if (Settings.syncExperience) {
|
||||
player.setTotalExperience(data.getTotalExperience());
|
||||
player.setLevel(data.getExpLevel());
|
||||
player.setExp(data.getExpProgress());
|
||||
// This is also handled when syncing advancements to ensure its correct
|
||||
setPlayerExperience(player, data);
|
||||
}
|
||||
if (Settings.syncPotionEffects) {
|
||||
setPlayerPotionEffects(player, DataSerializer.potionEffectArrayFromBase64(data.getSerializedEffectData()));
|
||||
@@ -78,9 +93,6 @@ public class PlayerSetter {
|
||||
player.setFlying(player.getAllowFlight() && data.isFlying());
|
||||
setPlayerLocation(player, DataSerializer.deserializePlayerLocationData(data.getSerializedLocation()));
|
||||
}
|
||||
|
||||
// Send action bar synchronisation message
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageStrings.SYNCHRONISATION_COMPLETE).toComponent());
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to deserialize PlayerData", e);
|
||||
}
|
||||
@@ -94,14 +106,7 @@ public class PlayerSetter {
|
||||
* @param items The array of {@link ItemStack}s to set
|
||||
*/
|
||||
private static void setPlayerEnderChest(Player player, ItemStack[] items) {
|
||||
player.getEnderChest().clear();
|
||||
int index = 0;
|
||||
for (ItemStack item : items) {
|
||||
if (item != null) {
|
||||
player.getEnderChest().setItem(index, item);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
setInventory(player.getEnderChest(), items);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,11 +116,21 @@ public class PlayerSetter {
|
||||
* @param items The array of {@link ItemStack}s to set
|
||||
*/
|
||||
private static void setPlayerInventory(Player player, ItemStack[] items) {
|
||||
player.getInventory().clear();
|
||||
setInventory(player.getInventory(), items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an inventory's contents from an array of {@link ItemStack}s
|
||||
*
|
||||
* @param inventory The inventory to set
|
||||
* @param items The {@link ItemStack}s to fill it with
|
||||
*/
|
||||
public static void setInventory(Inventory inventory, ItemStack[] items) {
|
||||
inventory.clear();
|
||||
int index = 0;
|
||||
for (ItemStack item : items) {
|
||||
if (item != null) {
|
||||
player.getInventory().setItem(index, item);
|
||||
inventory.setItem(index, item);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
@@ -142,7 +157,7 @@ public class PlayerSetter {
|
||||
* @param player The player to set the advancements of
|
||||
* @param advancementData The ArrayList of {@link DataSerializer.AdvancementRecord}s to set
|
||||
*/
|
||||
private static void setPlayerAdvancements(Player player, ArrayList<DataSerializer.AdvancementRecord> advancementData) {
|
||||
private static void setPlayerAdvancements(Player player, ArrayList<DataSerializer.AdvancementRecord> advancementData, PlayerData data) {
|
||||
// Temporarily disable advancement announcing if needed
|
||||
boolean announceAdvancementUpdate = false;
|
||||
if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) {
|
||||
@@ -153,36 +168,39 @@ public class PlayerSetter {
|
||||
|
||||
// Run async because advancement loading is very slow
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
|
||||
// Apply the advancements to the player
|
||||
Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
|
||||
while (serverAdvancements.hasNext()) {
|
||||
while (serverAdvancements.hasNext()) { // Iterate through all advancements
|
||||
boolean correctExperienceCheck = false; // Determines whether the experience might have changed warranting an update
|
||||
Advancement advancement = serverAdvancements.next();
|
||||
AdvancementProgress playerProgress = player.getAdvancementProgress(advancement);
|
||||
boolean hasAdvancement = false;
|
||||
for (DataSerializer.AdvancementRecord record : advancementData) {
|
||||
// If the advancement is one on the data
|
||||
if (record.advancementKey().equals(advancement.getKey().getNamespace() + ":" + advancement.getKey().getKey())) {
|
||||
hasAdvancement = true;
|
||||
|
||||
// Save the experience before granting the advancement
|
||||
final int expLevel = player.getLevel();
|
||||
final float expProgress = player.getExp();
|
||||
|
||||
// Grant advancement criteria if the player does not have it
|
||||
// Award all criteria that the player does not have that they do on the cache
|
||||
ArrayList<String> currentlyAwardedCriteria = new ArrayList<>(playerProgress.getAwardedCriteria());
|
||||
for (String awardCriteria : record.awardedAdvancementCriteria()) {
|
||||
if (!playerProgress.getAwardedCriteria().contains(awardCriteria)) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> player.getAdvancementProgress(advancement).awardCriteria(awardCriteria));
|
||||
correctExperienceCheck = true;
|
||||
}
|
||||
currentlyAwardedCriteria.remove(awardCriteria);
|
||||
}
|
||||
|
||||
// Set experience back to before granting advancement; nullify exp gained from it
|
||||
player.setLevel(expLevel);
|
||||
player.setExp(expProgress);
|
||||
// Revoke all criteria that the player does have but should not
|
||||
for (String awardCriteria : currentlyAwardedCriteria) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> player.getAdvancementProgress(advancement).revokeCriteria(awardCriteria));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasAdvancement) {
|
||||
for (String awardCriteria : playerProgress.getAwardedCriteria()) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> player.getAdvancementProgress(advancement).revokeCriteria(awardCriteria));
|
||||
|
||||
// Update the player's experience in case the advancement changed that
|
||||
if (correctExperienceCheck) {
|
||||
if (Settings.syncExperience) {
|
||||
setPlayerExperience(player, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,6 +248,18 @@ public class PlayerSetter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a player's exp level, exp points & score
|
||||
*
|
||||
* @param player The {@link Player} to set
|
||||
* @param data The {@link PlayerData} to set them
|
||||
*/
|
||||
private static void setPlayerExperience(Player player, PlayerData data) {
|
||||
player.setTotalExperience(data.getTotalExperience());
|
||||
player.setLevel(data.getExpLevel());
|
||||
player.setExp(data.getExpProgress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a player's location from {@link DataSerializer.PlayerLocation} data
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.william278.husksync.bukkit.data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -10,10 +11,6 @@ public class BukkitDataCache {
|
||||
*/
|
||||
private static HashSet<UUID> requestOnJoin;
|
||||
|
||||
public BukkitDataCache() {
|
||||
requestOnJoin = new HashSet<>();
|
||||
}
|
||||
|
||||
public boolean isPlayerRequestingOnJoin(UUID uuid) {
|
||||
return requestOnJoin.contains(uuid);
|
||||
}
|
||||
@@ -25,4 +22,53 @@ public class BukkitDataCache {
|
||||
public void removeRequestOnJoin(UUID uuid) {
|
||||
requestOnJoin.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of Player UUIDs whose data has not been set yet
|
||||
*/
|
||||
private static HashSet<UUID> awaitingDataFetch;
|
||||
|
||||
public boolean isAwaitingDataFetch(UUID uuid) {
|
||||
return awaitingDataFetch.contains(uuid);
|
||||
}
|
||||
|
||||
public void setAwaitingDataFetch(UUID uuid) {
|
||||
awaitingDataFetch.add(uuid);
|
||||
}
|
||||
|
||||
public void removeAwaitingDataFetch(UUID uuid) {
|
||||
awaitingDataFetch.remove(uuid);
|
||||
}
|
||||
|
||||
public HashSet<UUID> getAwaitingDataFetch() {
|
||||
return awaitingDataFetch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of data being viewed by players
|
||||
*/
|
||||
private static HashMap<UUID, DataViewer.DataView> viewingPlayerData;
|
||||
|
||||
public void setViewing(UUID uuid, DataViewer.DataView dataView) {
|
||||
viewingPlayerData.put(uuid, dataView);
|
||||
}
|
||||
|
||||
public void removeViewing(UUID uuid) {
|
||||
viewingPlayerData.remove(uuid);
|
||||
}
|
||||
|
||||
public boolean isViewing(UUID uuid) {
|
||||
return viewingPlayerData.containsKey(uuid);
|
||||
}
|
||||
|
||||
public DataViewer.DataView getViewing(UUID uuid) {
|
||||
return viewingPlayerData.get(uuid);
|
||||
}
|
||||
|
||||
// Cache object
|
||||
public BukkitDataCache() {
|
||||
requestOnJoin = new HashSet<>();
|
||||
viewingPlayerData = new HashMap<>();
|
||||
awaitingDataFetch = new HashSet<>();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.william278.husksync.bukkit;
|
||||
package me.william278.husksync.bukkit.data;
|
||||
|
||||
import me.william278.husksync.redis.RedisMessage;
|
||||
import org.bukkit.*;
|
||||
@@ -6,6 +6,7 @@ import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.advancement.AdvancementProgress;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
@@ -33,19 +34,19 @@ public final class DataSerializer {
|
||||
/**
|
||||
* Converts the player inventory to a Base64 encoded string.
|
||||
*
|
||||
* @param player whose inventory will be turned into an array of strings.
|
||||
* @param inventory the inventory to convert to Base64.
|
||||
* @return string with serialized Inventory
|
||||
* @throws IllegalStateException in the event the item stacks cannot be saved
|
||||
*/
|
||||
public static String getSerializedInventoryContents(Player player) throws IllegalStateException {
|
||||
public static String getSerializedInventoryContents(Inventory inventory) throws IllegalStateException {
|
||||
// This contains contents, armor and offhand (contents are indexes 0 - 35, armor 36 - 39, offhand - 40)
|
||||
return itemStackArrayToBase64(player.getInventory().getContents());
|
||||
return itemStackArrayToBase64(inventory.getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the player inventory to a Base64 encoded string.
|
||||
*
|
||||
* @param player whose Ender Chest will be turned into an array of strings.
|
||||
* @param player whose Ender Chest will be turned into Base64.
|
||||
* @return string with serialized Ender Chest
|
||||
* @throws IllegalStateException in the event the item stacks cannot be saved
|
||||
*/
|
||||
@@ -0,0 +1,115 @@
|
||||
package me.william278.husksync.bukkit.data;
|
||||
|
||||
import me.william278.husksync.HuskSyncBukkit;
|
||||
import me.william278.husksync.PlayerData;
|
||||
import me.william278.husksync.Settings;
|
||||
import me.william278.husksync.bukkit.PlayerSetter;
|
||||
import me.william278.husksync.redis.RedisMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Class used for managing viewing inventories using inventory-see command
|
||||
*/
|
||||
public class DataViewer {
|
||||
|
||||
/**
|
||||
* Show a viewer's data to a viewer
|
||||
*
|
||||
* @param viewer The viewing {@link Player} who will see the data
|
||||
* @param data The {@link DataView} to show the viewer
|
||||
* @throws IOException If an exception occurred deserializing item data
|
||||
*/
|
||||
public static void showData(Player viewer, DataView data) throws IOException {
|
||||
// Show an inventory with the viewer's inventory and equipment
|
||||
viewer.closeInventory();
|
||||
viewer.openInventory(createInventory(viewer, data));
|
||||
|
||||
// Set the viewer as viewing
|
||||
HuskSyncBukkit.bukkitCache.setViewing(viewer.getUniqueId(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles what happens after a data viewer finishes viewing data
|
||||
*
|
||||
* @param viewer The viewing {@link Player} who was looking at data
|
||||
* @param inventory The {@link Inventory} that was being viewed
|
||||
* @throws IOException If an exception occurred serializing item data
|
||||
*/
|
||||
public static void stopShowing(Player viewer, Inventory inventory) throws IOException {
|
||||
// Get the DataView the player was looking at
|
||||
DataView dataView = HuskSyncBukkit.bukkitCache.getViewing(viewer.getUniqueId());
|
||||
|
||||
// Set the player as no longer viewing an inventory
|
||||
HuskSyncBukkit.bukkitCache.removeViewing(viewer.getUniqueId());
|
||||
|
||||
// Get and update the PlayerData with the new item data
|
||||
PlayerData playerData = dataView.playerData();
|
||||
String serializedItemData = DataSerializer.itemStackArrayToBase64(inventory.getContents());
|
||||
switch (dataView.inventoryType()) {
|
||||
case INVENTORY -> playerData.setSerializedInventory(serializedItemData);
|
||||
case ENDER_CHEST -> playerData.setSerializedEnderChest(serializedItemData);
|
||||
}
|
||||
|
||||
// Send a redis message with the updated data after the viewing
|
||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
RedisMessage.serialize(playerData))
|
||||
.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the inventory object that the viewer will see
|
||||
*
|
||||
* @param viewer The {@link Player} who will view the data
|
||||
* @param data The {@link DataView} data to view
|
||||
* @return The {@link Inventory} that the viewer will see
|
||||
* @throws IOException If an exception occurred deserializing item data
|
||||
*/
|
||||
private static Inventory createInventory(Player viewer, DataView data) throws IOException {
|
||||
Inventory inventory = switch (data.inventoryType) {
|
||||
case INVENTORY -> Bukkit.createInventory(viewer, 45, data.ownerName + "'s Inventory");
|
||||
case ENDER_CHEST -> Bukkit.createInventory(viewer, 27, data.ownerName + "'s Ender Chest");
|
||||
};
|
||||
PlayerSetter.setInventory(inventory, data.getDeserializedData());
|
||||
return inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents Player Data being viewed by a {@link Player}
|
||||
*/
|
||||
public record DataView(PlayerData playerData, String ownerName, InventoryType inventoryType) {
|
||||
/**
|
||||
* What kind of item data is being viewed
|
||||
*/
|
||||
public enum InventoryType {
|
||||
/**
|
||||
* A player's inventory
|
||||
*/
|
||||
INVENTORY,
|
||||
|
||||
/**
|
||||
* A player's ender chest
|
||||
*/
|
||||
ENDER_CHEST
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the deserialized data currently being viewed
|
||||
*
|
||||
* @return The deserialized item data, as an {@link ItemStack[]} array
|
||||
* @throws IOException If an exception occurred deserializing item data
|
||||
*/
|
||||
public ItemStack[] getDeserializedData() throws IOException {
|
||||
return switch (inventoryType) {
|
||||
case INVENTORY -> DataSerializer.itemStackArrayFromBase64(playerData.getSerializedInventory());
|
||||
case ENDER_CHEST -> DataSerializer.itemStackArrayFromBase64(playerData.getSerializedEnderChest());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
package me.william278.husksync.bukkit.listener;
|
||||
|
||||
import de.themoep.minedown.MineDown;
|
||||
import me.william278.husksync.PlayerData;
|
||||
import me.william278.husksync.HuskSyncBukkit;
|
||||
import me.william278.husksync.bukkit.PlayerSetter;
|
||||
import me.william278.husksync.redis.RedisListener;
|
||||
import me.william278.husksync.MessageStrings;
|
||||
import me.william278.husksync.MessageManager;
|
||||
import me.william278.husksync.PlayerData;
|
||||
import me.william278.husksync.Settings;
|
||||
import me.william278.husksync.bukkit.config.ConfigLoader;
|
||||
import me.william278.husksync.bukkit.data.DataViewer;
|
||||
import me.william278.husksync.bukkit.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.RedisMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -25,25 +29,74 @@ public class BukkitRedisListener extends RedisListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming {@link me.william278.husksync.redis.RedisMessage}
|
||||
* Handle an incoming {@link RedisMessage}
|
||||
*
|
||||
* @param message The {@link me.william278.husksync.redis.RedisMessage} to handle
|
||||
* @param message The {@link RedisMessage} to handle
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(me.william278.husksync.redis.RedisMessage message) {
|
||||
public void handleMessage(RedisMessage message) {
|
||||
// Ignore messages for proxy servers
|
||||
if (!message.getMessageTarget().targetServerType().equals(Settings.ServerType.BUKKIT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Handle the message for the player
|
||||
if (message.getMessageTarget().targetPlayerUUID() == null) {
|
||||
if (message.getMessageType() == me.william278.husksync.redis.RedisMessage.MessageType.REQUEST_DATA_ON_JOIN) {
|
||||
UUID playerUUID = UUID.fromString(message.getMessageDataElements()[1]);
|
||||
switch (me.william278.husksync.redis.RedisMessage.RequestOnJoinUpdateType.valueOf(message.getMessageDataElements()[0])) {
|
||||
case ADD_REQUESTER -> HuskSyncBukkit.bukkitCache.setRequestOnJoin(playerUUID);
|
||||
case REMOVE_REQUESTER -> HuskSyncBukkit.bukkitCache.removeRequestOnJoin(playerUUID);
|
||||
switch (message.getMessageType()) {
|
||||
case REQUEST_DATA_ON_JOIN -> {
|
||||
UUID playerUUID = UUID.fromString(message.getMessageDataElements()[1]);
|
||||
switch (me.william278.husksync.redis.RedisMessage.RequestOnJoinUpdateType.valueOf(message.getMessageDataElements()[0])) {
|
||||
case ADD_REQUESTER -> HuskSyncBukkit.bukkitCache.setRequestOnJoin(playerUUID);
|
||||
case REMOVE_REQUESTER -> HuskSyncBukkit.bukkitCache.removeRequestOnJoin(playerUUID);
|
||||
}
|
||||
}
|
||||
case CONNECTION_HANDSHAKE -> {
|
||||
UUID serverUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
||||
String proxyBrand = message.getMessageDataElements()[1];
|
||||
if (serverUUID.equals(HuskSyncBukkit.serverUUID)) {
|
||||
HuskSyncBukkit.handshakeCompleted = true;
|
||||
log(Level.INFO, "Completed handshake with " + proxyBrand + " proxy (" + serverUUID + ")");
|
||||
|
||||
// If there are any players awaiting a data update, request it
|
||||
for (UUID uuid : HuskSyncBukkit.bukkitCache.getAwaitingDataFetch()) {
|
||||
try {
|
||||
PlayerSetter.requestPlayerData(uuid);
|
||||
} catch (IOException e) {
|
||||
log(Level.SEVERE, "Failed to serialize handshake message data");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case TERMINATE_HANDSHAKE -> {
|
||||
UUID serverUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
||||
String proxyBrand = message.getMessageDataElements()[1];
|
||||
if (serverUUID.equals(HuskSyncBukkit.serverUUID)) {
|
||||
HuskSyncBukkit.handshakeCompleted = false;
|
||||
log(Level.WARNING, proxyBrand + " proxy has terminated communications; attempting to re-establish (" + serverUUID + ")");
|
||||
|
||||
// Attempt to re-establish communications via another handshake
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, HuskSyncBukkit::establishRedisHandshake, 20);
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
case RELOAD_CONFIG -> {
|
||||
plugin.reloadConfig();
|
||||
ConfigLoader.loadSettings(plugin.getConfig());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -51,6 +104,7 @@ public class BukkitRedisListener extends RedisListener {
|
||||
if (player.getUniqueId().equals(message.getMessageTarget().targetPlayerUUID())) {
|
||||
switch (message.getMessageType()) {
|
||||
case PLAYER_DATA_SET -> {
|
||||
if (HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled) return;
|
||||
try {
|
||||
// Deserialize the received PlayerData
|
||||
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageData());
|
||||
@@ -58,7 +112,7 @@ public class BukkitRedisListener extends RedisListener {
|
||||
// Set the player's data
|
||||
PlayerSetter.setPlayerFrom(player, data);
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log(Level.SEVERE, "Failed to deserialize PlayerData when handling a reply from the proxy with PlayerData");
|
||||
log(Level.SEVERE, "Failed to deserialize PlayerData when handling data from the proxy");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -66,7 +120,7 @@ public class BukkitRedisListener extends RedisListener {
|
||||
String proxyBrand = message.getMessageDataElements()[0];
|
||||
String proxyVersion = message.getMessageDataElements()[1];
|
||||
assert plugin.getDescription().getDescription() != null;
|
||||
player.spigot().sendMessage(new MineDown(MessageStrings.PLUGIN_INFORMATION.toString()
|
||||
player.spigot().sendMessage(new MineDown(MessageManager.PLUGIN_INFORMATION.toString()
|
||||
.replaceAll("%plugin_description%", plugin.getDescription().getDescription())
|
||||
.replaceAll("%proxy_brand%", proxyBrand)
|
||||
.replaceAll("%proxy_version%", proxyVersion)
|
||||
@@ -74,6 +128,42 @@ public class BukkitRedisListener extends RedisListener {
|
||||
.replaceAll("%bukkit_version%", plugin.getDescription().getVersion()))
|
||||
.toComponent());
|
||||
}
|
||||
case OPEN_INVENTORY -> {
|
||||
// Get the name of the inventory owner
|
||||
String inventoryOwnerName = message.getMessageDataElements()[0];
|
||||
|
||||
// Synchronously do inventory setting, etc
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
try {
|
||||
// Get that player's data
|
||||
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageDataElements()[1]);
|
||||
|
||||
// Show the data to the player
|
||||
DataViewer.showData(player, new DataViewer.DataView(data, inventoryOwnerName, DataViewer.DataView.InventoryType.INVENTORY));
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log(Level.SEVERE, "Failed to deserialize PlayerData when handling inventory-see data from the proxy");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
case OPEN_ENDER_CHEST -> {
|
||||
// Get the name of the inventory owner
|
||||
String enderChestOwnerName = message.getMessageDataElements()[0];
|
||||
|
||||
// Synchronously do inventory setting, etc
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
try {
|
||||
// Get that player's data
|
||||
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageDataElements()[1]);
|
||||
|
||||
// Show the data to the player
|
||||
DataViewer.showData(player, new DataViewer.DataView(data, enderChestOwnerName, DataViewer.DataView.InventoryType.ENDER_CHEST));
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log(Level.SEVERE, "Failed to deserialize PlayerData when handling ender chest-see data from the proxy");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,22 @@ package me.william278.husksync.bukkit.listener;
|
||||
import me.william278.husksync.HuskSyncBukkit;
|
||||
import me.william278.husksync.PlayerData;
|
||||
import me.william278.husksync.Settings;
|
||||
import me.william278.husksync.bukkit.DataSerializer;
|
||||
import me.william278.husksync.bukkit.data.DataSerializer;
|
||||
import me.william278.husksync.bukkit.data.DataViewer;
|
||||
import me.william278.husksync.bukkit.PlayerSetter;
|
||||
import me.william278.husksync.redis.RedisMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.player.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
@@ -28,11 +36,12 @@ public class EventListener implements Listener {
|
||||
* @throws IOException If the serialization fails
|
||||
*/
|
||||
private static String getNewSerializedPlayerData(Player player) throws IOException {
|
||||
return me.william278.husksync.redis.RedisMessage.serialize(new PlayerData(player.getUniqueId(),
|
||||
DataSerializer.getSerializedInventoryContents(player),
|
||||
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(),
|
||||
@@ -53,11 +62,19 @@ public class EventListener implements Listener {
|
||||
// When a player leaves a Bukkit server
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
// If the player was awaiting data fetch, remove them and prevent data from being overwritten
|
||||
if (HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(player.getUniqueId())) {
|
||||
HuskSyncBukkit.bukkitCache.removeAwaitingDataFetch(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
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 me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||
new me.william278.husksync.redis.RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
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);
|
||||
@@ -70,22 +87,101 @@ public class EventListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (!plugin.isEnabled()) return; // If the plugin has not been initialized correctly
|
||||
|
||||
// When a player joins a Bukkit server
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
// Clear player inventory and ender chest
|
||||
player.getInventory().clear();
|
||||
player.getEnderChest().clear();
|
||||
// Mark the player as awaiting data fetch
|
||||
HuskSyncBukkit.bukkitCache.setAwaitingDataFetch(player.getUniqueId());
|
||||
|
||||
if (!HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled) return; // If the data handshake has not been completed yet (or MySqlPlayerDataBridge is installed)
|
||||
|
||||
// Send a redis message requesting the player data (if they need to)
|
||||
if (HuskSyncBukkit.bukkitCache.isPlayerRequestingOnJoin(player.getUniqueId())) {
|
||||
try {
|
||||
// Send a redis message requesting the player data
|
||||
new me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.PLAYER_DATA_REQUEST,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
player.getUniqueId().toString()).send();
|
||||
PlayerSetter.requestPlayerData(player.getUniqueId());
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
||||
}
|
||||
} else {
|
||||
// If the player's data wasn't set after 10 ticks, ensure it will be
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
if (player.isOnline()) {
|
||||
try {
|
||||
if (HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(player.getUniqueId())) {
|
||||
PlayerSetter.requestPlayerData(player.getUniqueId());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
||||
}
|
||||
}
|
||||
}, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(event.getPlayer().getUniqueId())) return; // If the plugin has not been initialized correctly
|
||||
|
||||
// When a player closes an Inventory
|
||||
final Player player = (Player) event.getPlayer();
|
||||
|
||||
// Handle a player who has finished viewing a player's item data
|
||||
if (HuskSyncBukkit.bukkitCache.isViewing(player.getUniqueId())) {
|
||||
try {
|
||||
DataViewer.stopShowing(player, event.getInventory());
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to serialize updated item data", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Events to cancel if the player has not been set yet
|
||||
*/
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onDropItem(PlayerDropItemEvent event) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(event.getPlayer().getUniqueId())) {
|
||||
event.setCancelled(true); // If the plugin / player has not been set
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPickupItem(EntityPickupItemEvent event) {
|
||||
if (event.getEntity() instanceof Player player) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(player.getUniqueId())) {
|
||||
event.setCancelled(true); // If the plugin / player has not been set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(event.getPlayer().getUniqueId())) {
|
||||
event.setCancelled(true); // If the plugin / player has not been set
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(event.getPlayer().getUniqueId())) {
|
||||
event.setCancelled(true); // If the plugin / player has not been set
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(event.getPlayer().getUniqueId())) {
|
||||
event.setCancelled(true); // If the plugin / player has not been set
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onInventoryOpen(InventoryOpenEvent event) {
|
||||
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(event.getPlayer().getUniqueId())) {
|
||||
event.setCancelled(true); // If the plugin / player has not been set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package me.william278.husksync.bukkit.migrator;
|
||||
|
||||
import me.william278.husksync.HuskSyncBukkit;
|
||||
import me.william278.husksync.PlayerData;
|
||||
import me.william278.husksync.bukkit.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.io.IOException;
|
||||
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
|
||||
Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER);
|
||||
PlayerSetter.setInventory(inventory, getItemStackArrayFromMPDBBase64String(mpdbPlayerData.inventoryData));
|
||||
|
||||
playerData.setSerializedInventory(DataSerializer.getSerializedInventoryContents(inventory));
|
||||
inventory.clear();
|
||||
|
||||
// Set ender chest
|
||||
playerData.setSerializedEnderChest(DataSerializer.itemStackArrayToBase64(
|
||||
getItemStackArrayFromMPDBBase64String(mpdbPlayerData.enderChestData)));
|
||||
|
||||
// Set experience
|
||||
playerData.setExpLevel(mpdbPlayerData.expLevel);
|
||||
playerData.setExpProgress(mpdbPlayerData.expProgress);
|
||||
playerData.setTotalExperience(mpdbPlayerData.totalExperience);
|
||||
} catch (IOException | InvocationTargetException | IllegalAccessException 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 IOException If an error occurs during decoding
|
||||
* @throws InvocationTargetException If an error occurs during decoding
|
||||
* @throws IllegalAccessException If an error occurs during decoding
|
||||
*/
|
||||
public static ItemStack[] getItemStackArrayFromMPDBBase64String(String data) throws IOException, InvocationTargetException, IllegalAccessException {
|
||||
if (data.isEmpty()) {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
return mySqlPlayerDataBridge.getItemStackSerializer().fromBase64(data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user