mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-25 17:49:20 +00:00
Finish initial implementation of plan
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
package me.william278.crossserversync.bukkit;
|
||||
|
||||
import me.william278.crossserversync.Settings;
|
||||
import me.william278.crossserversync.redis.RedisListener;
|
||||
import me.william278.crossserversync.redis.RedisMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BukkitRedisListener extends RedisListener {
|
||||
|
||||
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.getInstance();
|
||||
|
||||
// Initialize the listener on the bukkit server
|
||||
public BukkitRedisListener() {
|
||||
listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming {@link RedisMessage}
|
||||
*
|
||||
* @param message The {@link RedisMessage} to handle
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(RedisMessage message) {
|
||||
// Ignore messages for proxy servers
|
||||
if (message.getMessageTarget().targetServerType() != Settings.ServerType.BUKKIT) {
|
||||
return;
|
||||
}
|
||||
// Handle the message for the player
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.getUniqueId() == message.getMessageTarget().targetPlayerName()) {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to console
|
||||
*
|
||||
* @param level The {@link Level} to log
|
||||
* @param message Message to log
|
||||
*/
|
||||
@Override
|
||||
public void log(Level level, String message) {
|
||||
plugin.getLogger().log(level, message);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package me.william278.crossserversync.bukkit;
|
||||
|
||||
import me.william278.crossserversync.bukkit.config.ConfigLoader;
|
||||
import me.william278.crossserversync.bukkit.data.LastDataUpdateUUIDCache;
|
||||
import me.william278.crossserversync.bukkit.listener.BukkitRedisListener;
|
||||
import me.william278.crossserversync.bukkit.listener.EventListener;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class CrossServerSyncBukkit extends JavaPlugin {
|
||||
@@ -10,6 +13,8 @@ public final class CrossServerSyncBukkit extends JavaPlugin {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static LastDataUpdateUUIDCache lastDataUpdateUUIDCache;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
@@ -26,12 +31,22 @@ public final class CrossServerSyncBukkit extends JavaPlugin {
|
||||
reloadConfig();
|
||||
ConfigLoader.loadSettings(getConfig());
|
||||
|
||||
// Initialize last data update UUID cache
|
||||
lastDataUpdateUUIDCache = new LastDataUpdateUUIDCache();
|
||||
|
||||
// Initialize the redis listener
|
||||
new BukkitRedisListener();
|
||||
|
||||
// Initialize event listener
|
||||
getServer().getPluginManager().registerEvents(new EventListener(), this);
|
||||
|
||||
// Log to console
|
||||
getLogger().info("Enabled CrossServerSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
// Plugin shutdown logic
|
||||
getLogger().info("Disabled CrossServerSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package me.william278.crossserversync.bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||
@@ -107,13 +106,17 @@ public final class InventorySerializer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of ItemStacks from Base64 string.
|
||||
* Gets an array of ItemStacks from a Base64 string.
|
||||
*
|
||||
* @param data Base64 string to convert to ItemStack array.
|
||||
* @return ItemStack array created from the Base64 string.
|
||||
* @throws IOException in the event the class type cannot be decoded
|
||||
*/
|
||||
public static ItemStack[] itemStackArrayFromBase64(String data) throws IOException {
|
||||
// Return an empty ItemStack[] if the data is empty
|
||||
if (data.isEmpty()) {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data))) {
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
|
||||
ItemStack[] items = new ItemStack[dataInput.readInt()];
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package me.william278.crossserversync.bukkit.data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LastDataUpdateUUIDCache {
|
||||
|
||||
/**
|
||||
* Map of Player UUIDs to last-updated PlayerData version UUIDs
|
||||
*/
|
||||
private static HashMap<UUID, UUID> lastUpdatedPlayerDataUUIDs;
|
||||
|
||||
public LastDataUpdateUUIDCache() {
|
||||
lastUpdatedPlayerDataUUIDs = new HashMap<>();
|
||||
}
|
||||
|
||||
public UUID getVersionUUID(UUID playerUUID) {
|
||||
return lastUpdatedPlayerDataUUIDs.get(playerUUID);
|
||||
}
|
||||
|
||||
public void setVersionUUID(UUID playerUUID, UUID dataVersionUUID) {
|
||||
lastUpdatedPlayerDataUUIDs.put(playerUUID, dataVersionUUID);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package me.william278.crossserversync.bukkit.listener;
|
||||
|
||||
import me.william278.crossserversync.bukkit.InventorySerializer;
|
||||
import me.william278.crossserversync.PlayerData;
|
||||
import me.william278.crossserversync.Settings;
|
||||
import me.william278.crossserversync.bukkit.CrossServerSyncBukkit;
|
||||
import me.william278.crossserversync.redis.RedisListener;
|
||||
import me.william278.crossserversync.redis.RedisMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BukkitRedisListener extends RedisListener {
|
||||
|
||||
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.getInstance();
|
||||
|
||||
// Initialize the listener on the bukkit server
|
||||
public BukkitRedisListener() {
|
||||
listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming {@link RedisMessage}
|
||||
*
|
||||
* @param message The {@link RedisMessage} to handle
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(RedisMessage message) {
|
||||
// Ignore messages for proxy servers
|
||||
if (message.getMessageTarget().targetServerType() != Settings.ServerType.BUKKIT) {
|
||||
return;
|
||||
}
|
||||
// Handle the message for the player
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.getUniqueId() == message.getMessageTarget().targetPlayerName()) {
|
||||
if (message.getMessageType() == RedisMessage.MessageType.PLAYER_DATA_REPLY) {
|
||||
try {
|
||||
// Deserialize the received PlayerData
|
||||
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageData());
|
||||
|
||||
// Set the player's data //todo do more stuff like health etc
|
||||
InventorySerializer.setPlayerItems(player, InventorySerializer.itemStackArrayFromBase64(data.getSerializedInventory()));
|
||||
InventorySerializer.setPlayerEnderChest(player, InventorySerializer.itemStackArrayFromBase64(data.getSerializedEnderChest()));
|
||||
|
||||
// Update last loaded data UUID
|
||||
CrossServerSyncBukkit.lastDataUpdateUUIDCache.setVersionUUID(player.getUniqueId(), data.getDataVersionUUID());
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log(Level.SEVERE, "Failed to deserialize PlayerData when handling a reply from the proxy with PlayerData");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to console
|
||||
*
|
||||
* @param level The {@link Level} to log
|
||||
* @param message Message to log
|
||||
*/
|
||||
@Override
|
||||
public void log(Level level, String message) {
|
||||
plugin.getLogger().log(level, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package me.william278.crossserversync.bukkit.listener;
|
||||
|
||||
import me.william278.crossserversync.PlayerData;
|
||||
import me.william278.crossserversync.Settings;
|
||||
import me.william278.crossserversync.bukkit.CrossServerSyncBukkit;
|
||||
import me.william278.crossserversync.bukkit.InventorySerializer;
|
||||
import me.william278.crossserversync.redis.RedisMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class EventListener implements Listener {
|
||||
|
||||
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.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(),
|
||||
InventorySerializer.getSerializedInventoryContents(player),
|
||||
InventorySerializer.getSerializedEnderChestContents(player)));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
// When a player leaves a Bukkit server
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
try {
|
||||
// Get the player's last updated PlayerData version UUID
|
||||
final UUID lastUpdatedDataVersion = CrossServerSyncBukkit.lastDataUpdateUUIDCache.getVersionUUID(player.getUniqueId());
|
||||
if (lastUpdatedDataVersion == null) return; // Return if the player has not been properly updated.
|
||||
|
||||
// Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData
|
||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
lastUpdatedDataVersion.toString(), getNewSerializedPlayerData(player)).send();
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
// When a player joins a Bukkit server
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
try {
|
||||
// Send a redis message requesting the player data
|
||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_REQUEST,
|
||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||
player.getUniqueId().toString()).send();
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user