mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-19 14:59:21 +00:00
Now fully reliable and added support for health, max health, etc
This commit is contained in:
@@ -11,8 +11,6 @@ dependencies {
|
|||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
|
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
|
||||||
relocate 'org.bstats', 'me.William278.crossserversync.libraries.plan'
|
relocate 'org.bstats', 'me.William278.crossserversync.libraries.plan'
|
||||||
relocate 'org.apache.commons', 'me.William278.crossserversync.libraries.apache-commons'
|
|
||||||
relocate 'org.slf4j', 'me.William278.crossserversync.libraries.slf4j'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('prepareKotlinBuildScriptModel'){}
|
tasks.register('prepareKotlinBuildScriptModel'){}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.crossserversync.bukkit;
|
package me.william278.crossserversync;
|
||||||
|
|
||||||
import me.william278.crossserversync.bukkit.config.ConfigLoader;
|
import me.william278.crossserversync.bukkit.config.ConfigLoader;
|
||||||
import me.william278.crossserversync.bukkit.data.LastDataUpdateUUIDCache;
|
import me.william278.crossserversync.bukkit.data.LastDataUpdateUUIDCache;
|
||||||
@@ -34,12 +34,12 @@ public final class CrossServerSyncBukkit extends JavaPlugin {
|
|||||||
// Initialize last data update UUID cache
|
// Initialize last data update UUID cache
|
||||||
lastDataUpdateUUIDCache = new LastDataUpdateUUIDCache();
|
lastDataUpdateUUIDCache = new LastDataUpdateUUIDCache();
|
||||||
|
|
||||||
// Initialize the redis listener
|
|
||||||
new BukkitRedisListener();
|
|
||||||
|
|
||||||
// Initialize event listener
|
// Initialize event listener
|
||||||
getServer().getPluginManager().registerEvents(new EventListener(), this);
|
getServer().getPluginManager().registerEvents(new EventListener(), this);
|
||||||
|
|
||||||
|
// Initialize the redis listener
|
||||||
|
new BukkitRedisListener();
|
||||||
|
|
||||||
// Log to console
|
// Log to console
|
||||||
getLogger().info("Enabled CrossServerSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
getLogger().info("Enabled CrossServerSync (" + getServer().getName() + ") v" + getDescription().getVersion());
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.william278.crossserversync.bukkit;
|
package me.william278.crossserversync.bukkit;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||||
@@ -19,8 +19,9 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author efindus
|
* @author efindus
|
||||||
* @author graywolf336
|
* @author graywolf336
|
||||||
|
* @author William278
|
||||||
*/
|
*/
|
||||||
public final class InventorySerializer {
|
public final class DataSerializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the player inventory to a Base64 encoded string.
|
* Converts the player inventory to a Base64 encoded string.
|
||||||
@@ -46,35 +47,33 @@ public final class InventorySerializer {
|
|||||||
return itemStackArrayToBase64(player.getEnderChest().getContents());
|
return itemStackArrayToBase64(player.getEnderChest().getContents());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static String getSerializedEffectData(Player player) {
|
||||||
* Sets a player's inventory from a set of {@link ItemStack}s
|
PotionEffect[] potionEffects = new PotionEffect[player.getActivePotionEffects().size()];
|
||||||
*
|
int x = 0;
|
||||||
* @param player The player to set the inventory of
|
for (PotionEffect effect : player.getActivePotionEffects()) {
|
||||||
* @param items The array of {@link ItemStack}s to set
|
potionEffects[x] = effect;
|
||||||
*/
|
x++;
|
||||||
public static void setPlayerItems(Player player, ItemStack[] items) {
|
}
|
||||||
setInventoryItems(player.getInventory(), items);
|
return effectArrayToBase64(potionEffects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static String effectArrayToBase64(PotionEffect[] effects) {
|
||||||
* Sets a player's ender chest from a set of {@link ItemStack}s
|
try {
|
||||||
*
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
* @param player The player to set the inventory of
|
try (BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
|
||||||
* @param items The array of {@link ItemStack}s to set
|
dataOutput.writeInt(effects.length);
|
||||||
*/
|
|
||||||
public static void setPlayerEnderChest(Player player, ItemStack[] items) {
|
|
||||||
setInventoryItems(player.getEnderChest(), items);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clears, then fills an inventory's items correctly.
|
for (PotionEffect effect : effects) {
|
||||||
private static void setInventoryItems(Inventory inventory, ItemStack[] items) {
|
if (effect != null) {
|
||||||
inventory.clear();
|
dataOutput.writeObject(effect.serialize());
|
||||||
int index = 0;
|
} else {
|
||||||
for (ItemStack item : items) {
|
dataOutput.writeObject(null);
|
||||||
if (item != null) {
|
}
|
||||||
inventory.setItem(index, item);
|
}
|
||||||
}
|
}
|
||||||
index++;
|
return Base64Coder.encodeLines(outputStream.toByteArray());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Unable to save potion effects.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,4 +136,30 @@ public final class InventorySerializer {
|
|||||||
throw new IOException("Unable to decode class type.", e);
|
throw new IOException("Unable to decode class type.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PotionEffect[] potionEffectArrayFromBase64(String data) throws IOException {
|
||||||
|
// Return an empty PotionEffect[] if the data is empty
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
return new PotionEffect[0];
|
||||||
|
}
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data))) {
|
||||||
|
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
|
||||||
|
PotionEffect[] items = new PotionEffect[dataInput.readInt()];
|
||||||
|
|
||||||
|
for (int Index = 0; Index < items.length; Index++) {
|
||||||
|
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
|
||||||
|
Map<String, Object> effect = (Map<String, Object>) dataInput.readObject();
|
||||||
|
|
||||||
|
if (effect != null) {
|
||||||
|
items[Index] = new PotionEffect(effect);
|
||||||
|
} else {
|
||||||
|
items[Index] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new IOException("Unable to decode class type.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package me.william278.crossserversync.bukkit;
|
||||||
|
|
||||||
|
import me.william278.crossserversync.CrossServerSyncBukkit;
|
||||||
|
import me.william278.crossserversync.PlayerData;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class PlayerSetter {
|
||||||
|
|
||||||
|
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.getInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a player from their PlayerData
|
||||||
|
*
|
||||||
|
* @param player The {@link Player} to set
|
||||||
|
* @param data The {@link PlayerData} to assign to the player
|
||||||
|
*/
|
||||||
|
public static void setPlayerFrom(Player player, PlayerData data) {
|
||||||
|
try {
|
||||||
|
setPlayerInventory(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedInventory()));
|
||||||
|
setPlayerEnderChest(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedEnderChest()));
|
||||||
|
player.setHealth(data.getHealth());
|
||||||
|
player.setMaxHealth(data.getMaxHealth());
|
||||||
|
player.setFoodLevel(data.getHunger());
|
||||||
|
player.setSaturation(data.getSaturation());
|
||||||
|
player.getInventory().setHeldItemSlot(data.getSelectedSlot());
|
||||||
|
//todo potion effects not working
|
||||||
|
setPlayerPotionEffects(player, DataSerializer.potionEffectArrayFromBase64(data.getSerializedEffectData()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Failed to deserialize PlayerData", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player's ender chest from a set of {@link ItemStack}s
|
||||||
|
*
|
||||||
|
* @param player The player to set the inventory of
|
||||||
|
* @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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a player's inventory from a set of {@link ItemStack}s
|
||||||
|
*
|
||||||
|
* @param player The player to set the inventory of
|
||||||
|
* @param items The array of {@link ItemStack}s to set
|
||||||
|
*/
|
||||||
|
private static void setPlayerInventory(Player player, ItemStack[] items) {
|
||||||
|
player.getInventory().clear();
|
||||||
|
int index = 0;
|
||||||
|
for (ItemStack item : items) {
|
||||||
|
if (item != null) {
|
||||||
|
player.getInventory().setItem(index, item);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a player's current potion effects from a set of {@link PotionEffect[]}
|
||||||
|
* @param player The player to set the potion effects of
|
||||||
|
* @param effects The array of {@link PotionEffect}s to set
|
||||||
|
*/
|
||||||
|
private static void setPlayerPotionEffects(Player player, PotionEffect[] effects) {
|
||||||
|
player.getActivePotionEffects().clear();
|
||||||
|
for (PotionEffect effect : effects) {
|
||||||
|
player.getActivePotionEffects().add(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package me.william278.crossserversync.bukkit.listener;
|
package me.william278.crossserversync.bukkit.listener;
|
||||||
|
|
||||||
import me.william278.crossserversync.bukkit.InventorySerializer;
|
|
||||||
import me.william278.crossserversync.PlayerData;
|
import me.william278.crossserversync.PlayerData;
|
||||||
import me.william278.crossserversync.Settings;
|
import me.william278.crossserversync.Settings;
|
||||||
import me.william278.crossserversync.bukkit.CrossServerSyncBukkit;
|
import me.william278.crossserversync.CrossServerSyncBukkit;
|
||||||
|
import me.william278.crossserversync.bukkit.PlayerSetter;
|
||||||
import me.william278.crossserversync.redis.RedisListener;
|
import me.william278.crossserversync.redis.RedisListener;
|
||||||
import me.william278.crossserversync.redis.RedisMessage;
|
import me.william278.crossserversync.redis.RedisMessage;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@@ -29,20 +29,19 @@ public class BukkitRedisListener extends RedisListener {
|
|||||||
@Override
|
@Override
|
||||||
public void handleMessage(RedisMessage message) {
|
public void handleMessage(RedisMessage message) {
|
||||||
// Ignore messages for proxy servers
|
// Ignore messages for proxy servers
|
||||||
if (message.getMessageTarget().targetServerType() != Settings.ServerType.BUKKIT) {
|
if (!message.getMessageTarget().targetServerType().equals(Settings.ServerType.BUKKIT)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Handle the message for the player
|
// Handle the message for the player
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (player.getUniqueId() == message.getMessageTarget().targetPlayerName()) {
|
if (player.getUniqueId().equals(message.getMessageTarget().targetPlayerUUID())) {
|
||||||
if (message.getMessageType() == RedisMessage.MessageType.PLAYER_DATA_REPLY) {
|
if (message.getMessageType().equals(RedisMessage.MessageType.PLAYER_DATA_REPLY)) {
|
||||||
try {
|
try {
|
||||||
// Deserialize the received PlayerData
|
// Deserialize the received PlayerData
|
||||||
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageData());
|
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageData());
|
||||||
|
|
||||||
// Set the player's data //todo do more stuff like health etc
|
// Set the player's data
|
||||||
InventorySerializer.setPlayerItems(player, InventorySerializer.itemStackArrayFromBase64(data.getSerializedInventory()));
|
PlayerSetter.setPlayerFrom(player, data);
|
||||||
InventorySerializer.setPlayerEnderChest(player, InventorySerializer.itemStackArrayFromBase64(data.getSerializedEnderChest()));
|
|
||||||
|
|
||||||
// Update last loaded data UUID
|
// Update last loaded data UUID
|
||||||
CrossServerSyncBukkit.lastDataUpdateUUIDCache.setVersionUUID(player.getUniqueId(), data.getDataVersionUUID());
|
CrossServerSyncBukkit.lastDataUpdateUUIDCache.setVersionUUID(player.getUniqueId(), data.getDataVersionUUID());
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package me.william278.crossserversync.bukkit.listener;
|
package me.william278.crossserversync.bukkit.listener;
|
||||||
|
|
||||||
|
import me.william278.crossserversync.CrossServerSyncBukkit;
|
||||||
import me.william278.crossserversync.PlayerData;
|
import me.william278.crossserversync.PlayerData;
|
||||||
import me.william278.crossserversync.Settings;
|
import me.william278.crossserversync.Settings;
|
||||||
import me.william278.crossserversync.bukkit.CrossServerSyncBukkit;
|
import me.william278.crossserversync.bukkit.DataSerializer;
|
||||||
import me.william278.crossserversync.bukkit.InventorySerializer;
|
|
||||||
import me.william278.crossserversync.redis.RedisMessage;
|
import me.william278.crossserversync.redis.RedisMessage;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@@ -27,8 +27,14 @@ public class EventListener implements Listener {
|
|||||||
*/
|
*/
|
||||||
private static String getNewSerializedPlayerData(Player player) throws IOException {
|
private static String getNewSerializedPlayerData(Player player) throws IOException {
|
||||||
return RedisMessage.serialize(new PlayerData(player.getUniqueId(),
|
return RedisMessage.serialize(new PlayerData(player.getUniqueId(),
|
||||||
InventorySerializer.getSerializedInventoryContents(player),
|
DataSerializer.getSerializedInventoryContents(player),
|
||||||
InventorySerializer.getSerializedEnderChestContents(player)));
|
DataSerializer.getSerializedEnderChestContents(player),
|
||||||
|
player.getHealth(),
|
||||||
|
player.getMaxHealth(),
|
||||||
|
player.getFoodLevel(),
|
||||||
|
player.getSaturation(),
|
||||||
|
player.getInventory().getHeldItemSlot(),
|
||||||
|
DataSerializer.getSerializedEffectData(player)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -42,15 +48,16 @@ public class EventListener implements Listener {
|
|||||||
if (lastUpdatedDataVersion == null) return; // Return if the player has not been properly updated.
|
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
|
// Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData
|
||||||
|
final String serializedPlayerData = getNewSerializedPlayerData(player);
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
|
||||||
lastUpdatedDataVersion.toString(), getNewSerializedPlayerData(player)).send();
|
serializedPlayerData).send();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
|
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
// When a player joins a Bukkit server
|
// When a player joins a Bukkit server
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ shadowJar {
|
|||||||
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
|
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
|
||||||
relocate 'com.zaxxer', 'me.William278.crossserversync.libraries.hikari'
|
relocate 'com.zaxxer', 'me.William278.crossserversync.libraries.hikari'
|
||||||
relocate 'org.bstats', 'me.William278.crossserversync.libraries.plan'
|
relocate 'org.bstats', 'me.William278.crossserversync.libraries.plan'
|
||||||
relocate 'org.apache.commons', 'me.William278.crossserversync.libraries.apache-commons'
|
|
||||||
relocate 'org.slf4j', 'me.William278.crossserversync.libraries.slf4j'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('prepareKotlinBuildScriptModel'){}
|
tasks.register('prepareKotlinBuildScriptModel'){}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package me.william278.crossserversync.bungeecord;
|
package me.william278.crossserversync;
|
||||||
|
|
||||||
import me.william278.crossserversync.Settings;
|
|
||||||
import me.william278.crossserversync.bungeecord.config.ConfigLoader;
|
import me.william278.crossserversync.bungeecord.config.ConfigLoader;
|
||||||
import me.william278.crossserversync.bungeecord.config.ConfigManager;
|
import me.william278.crossserversync.bungeecord.config.ConfigManager;
|
||||||
import me.william278.crossserversync.bungeecord.data.DataManager;
|
import me.william278.crossserversync.bungeecord.data.DataManager;
|
||||||
@@ -50,7 +49,7 @@ public final class CrossServerSyncBungeeCord extends Plugin {
|
|||||||
database.load();
|
database.load();
|
||||||
|
|
||||||
// Setup player data cache
|
// Setup player data cache
|
||||||
DataManager.setupCache();
|
DataManager.playerDataCache = new DataManager.PlayerDataCache();
|
||||||
|
|
||||||
// Initialize PreLoginEvent listener
|
// Initialize PreLoginEvent listener
|
||||||
getProxy().getPluginManager().registerListener(this, new BungeeEventListener());
|
getProxy().getPluginManager().registerListener(this, new BungeeEventListener());
|
||||||
@@ -26,7 +26,6 @@ public class ConfigLoader {
|
|||||||
Settings.hikariMaximumLifetime = config.getLong("data_storage_settings.hikari_pool_settings.maximum_lifetime", 1800000);
|
Settings.hikariMaximumLifetime = config.getLong("data_storage_settings.hikari_pool_settings.maximum_lifetime", 1800000);
|
||||||
Settings.hikariKeepAliveTime = config.getLong("data_storage_settings.hikari_pool_settings.keepalive_time", 10);
|
Settings.hikariKeepAliveTime = config.getLong("data_storage_settings.hikari_pool_settings.keepalive_time", 10);
|
||||||
Settings.hikariConnectionTimeOut = config.getLong("data_storage_settings.hikari_pool_settings.connection_timeout", 5000);
|
Settings.hikariConnectionTimeOut = config.getLong("data_storage_settings.hikari_pool_settings.connection_timeout", 5000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.crossserversync.bungeecord.config;
|
package me.william278.crossserversync.bungeecord.config;
|
||||||
|
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
import net.md_5.bungee.config.ConfigurationProvider;
|
import net.md_5.bungee.config.ConfigurationProvider;
|
||||||
import net.md_5.bungee.config.YamlConfiguration;
|
import net.md_5.bungee.config.YamlConfiguration;
|
||||||
@@ -23,7 +23,8 @@ public class ConfigManager {
|
|||||||
}
|
}
|
||||||
File configFile = new File(plugin.getDataFolder(), "config.yml");
|
File configFile = new File(plugin.getDataFolder(), "config.yml");
|
||||||
if (!configFile.exists()) {
|
if (!configFile.exists()) {
|
||||||
Files.copy(plugin.getResourceAsStream("bungee_config.yml"), configFile.toPath());
|
Files.copy(plugin.getResourceAsStream("bungee-config.yml"), configFile.toPath());
|
||||||
|
plugin.getLogger().info("Created CrossServerSync bungee-config.yml file");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
plugin.getLogger().log(Level.CONFIG, "An exception occurred loading the configuration file", e);
|
plugin.getLogger().log(Level.CONFIG, "An exception occurred loading the configuration file", e);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.crossserversync.bungeecord.data;
|
package me.william278.crossserversync.bungeecord.data;
|
||||||
|
|
||||||
import me.william278.crossserversync.PlayerData;
|
import me.william278.crossserversync.PlayerData;
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
import me.william278.crossserversync.bungeecord.data.sql.Database;
|
import me.william278.crossserversync.bungeecord.data.sql.Database;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
@@ -15,10 +15,6 @@ public class DataManager {
|
|||||||
private static final CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
|
private static final CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
|
||||||
public static PlayerDataCache playerDataCache;
|
public static PlayerDataCache playerDataCache;
|
||||||
|
|
||||||
public static void setupCache() {
|
|
||||||
playerDataCache = new PlayerDataCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the player is registered on the database; register them if not.
|
* Checks if the player is registered on the database; register them if not.
|
||||||
*
|
*
|
||||||
@@ -75,11 +71,12 @@ public class DataManager {
|
|||||||
final String serializedEnderChest = resultSet.getString("ender_chest");
|
final String serializedEnderChest = resultSet.getString("ender_chest");
|
||||||
final double health = resultSet.getDouble("health");
|
final double health = resultSet.getDouble("health");
|
||||||
final double maxHealth = resultSet.getDouble("max_health");
|
final double maxHealth = resultSet.getDouble("max_health");
|
||||||
final double hunger = resultSet.getDouble("hunger");
|
final int hunger = resultSet.getInt("hunger");
|
||||||
final double saturation = resultSet.getDouble("saturation");
|
final float saturation = resultSet.getFloat("saturation");
|
||||||
|
final int selectedSlot = resultSet.getInt("selected_slot");
|
||||||
final String serializedStatusEffects = resultSet.getString("status_effects");
|
final String serializedStatusEffects = resultSet.getString("status_effects");
|
||||||
|
|
||||||
return new PlayerData(playerUUID, dataVersionUUID, serializedInventory, serializedEnderChest, health, maxHealth, hunger, saturation, serializedStatusEffects);
|
return new PlayerData(playerUUID, dataVersionUUID, serializedInventory, serializedEnderChest, health, maxHealth, hunger, saturation, selectedSlot, serializedStatusEffects);
|
||||||
} else {
|
} else {
|
||||||
return PlayerData.EMPTY_PLAYER_DATA(playerUUID);
|
return PlayerData.EMPTY_PLAYER_DATA(playerUUID);
|
||||||
}
|
}
|
||||||
@@ -90,41 +87,35 @@ public class DataManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updatePlayerData(PlayerData playerData, UUID lastDataUUID) {
|
public static void updatePlayerData(PlayerData playerData) {
|
||||||
// Ignore if the Spigot server didn't properly sync the previous data
|
// Ignore if the Spigot server didn't properly sync the previous data
|
||||||
PlayerData oldPlayerData = playerDataCache.getPlayer(playerData.getPlayerUUID());
|
|
||||||
if (oldPlayerData != null) {
|
|
||||||
if (oldPlayerData.getDataVersionUUID() != lastDataUUID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the new player data to the cache
|
// Add the new player data to the cache
|
||||||
playerDataCache.updatePlayer(playerData);
|
playerDataCache.updatePlayer(playerData);
|
||||||
|
|
||||||
// SQL: If the player has cached data, update it, otherwise insert new data.
|
// SQL: If the player has cached data, update it, otherwise insert new data.
|
||||||
if (playerHasCachedData(playerData.getPlayerUUID())) {
|
if (playerHasCachedData(playerData.getPlayerUUID())) {
|
||||||
updatePlayerData(playerData);
|
updatePlayerSQLData(playerData);
|
||||||
} else {
|
} else {
|
||||||
insertPlayerData(playerData);
|
insertPlayerData(playerData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updatePlayerData(PlayerData playerData) {
|
private static void updatePlayerSQLData(PlayerData playerData) {
|
||||||
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
|
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
|
||||||
try (PreparedStatement statement = connection.prepareStatement(
|
try (PreparedStatement statement = connection.prepareStatement(
|
||||||
"UPDATE " + Database.DATA_TABLE_NAME + " SET `version_uuid`=?, `timestamp`=?, `inventory`=?, `ender_chest`=?, `health`=?, `max_health`=?, `hunger`=?, `saturation`=?, `status_effects`=? WHERE `player_id`=(SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?);")) {
|
"UPDATE " + Database.DATA_TABLE_NAME + " SET `version_uuid`=?, `timestamp`=?, `inventory`=?, `ender_chest`=?, `health`=?, `max_health`=?, `hunger`=?, `saturation`=?, `selected_slot`=?, `status_effects`=? WHERE `player_id`=(SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?);")) {
|
||||||
statement.setString(1, playerData.getDataVersionUUID().toString());
|
statement.setString(1, playerData.getDataVersionUUID().toString());
|
||||||
statement.setTimestamp(2, new Timestamp(Instant.now().getEpochSecond()));
|
statement.setTimestamp(2, new Timestamp(Instant.now().getEpochSecond()));
|
||||||
statement.setString(3, playerData.getSerializedInventory());
|
statement.setString(3, playerData.getSerializedInventory());
|
||||||
statement.setString(4, playerData.getSerializedEnderChest());
|
statement.setString(4, playerData.getSerializedEnderChest());
|
||||||
statement.setDouble(5, 20D); // Health
|
statement.setDouble(5, playerData.getHealth()); // Health
|
||||||
statement.setDouble(6, 20D); // Max health
|
statement.setDouble(6, playerData.getMaxHealth()); // Max health
|
||||||
statement.setDouble(7, 20D); // Hunger
|
statement.setInt(7, playerData.getHunger()); // Hunger
|
||||||
statement.setDouble(8, 20D); // Saturation
|
statement.setFloat(8, playerData.getSaturation()); // Saturation
|
||||||
statement.setString(9, ""); // Status effects
|
statement.setInt(9, playerData.getSelectedSlot());
|
||||||
|
statement.setString(10, playerData.getSerializedEffectData()); // Status effects
|
||||||
statement.setString(10, playerData.getPlayerUUID().toString());
|
statement.setString(11, playerData.getPlayerUUID().toString());
|
||||||
statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -135,17 +126,18 @@ public class DataManager {
|
|||||||
private static void insertPlayerData(PlayerData playerData) {
|
private static void insertPlayerData(PlayerData playerData) {
|
||||||
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
|
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
|
||||||
try (PreparedStatement statement = connection.prepareStatement(
|
try (PreparedStatement statement = connection.prepareStatement(
|
||||||
"INSERT INTO " + Database.DATA_TABLE_NAME + " (`player_id`,`version_uuid`,`timestamp`,`inventory`,`ender_chest`,`health`,`max_health`,`hunger`,`saturation`,`status_effects`) VALUES((SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?),?,?,?,?,?,?,?,?,?);")) {
|
"INSERT INTO " + Database.DATA_TABLE_NAME + " (`player_id`,`version_uuid`,`timestamp`,`inventory`,`ender_chest`,`health`,`max_health`,`hunger`,`saturation`,`selected_slot`,`status_effects`) VALUES((SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?),?,?,?,?,?,?,?,?,?,?);")) {
|
||||||
statement.setString(1, playerData.getPlayerUUID().toString());
|
statement.setString(1, playerData.getPlayerUUID().toString());
|
||||||
statement.setString(2, playerData.getDataVersionUUID().toString());
|
statement.setString(2, playerData.getDataVersionUUID().toString());
|
||||||
statement.setTimestamp(3, new Timestamp(Instant.now().getEpochSecond()));
|
statement.setTimestamp(3, new Timestamp(Instant.now().getEpochSecond()));
|
||||||
statement.setString(4, playerData.getSerializedInventory());
|
statement.setString(4, playerData.getSerializedInventory());
|
||||||
statement.setString(5, playerData.getSerializedEnderChest());
|
statement.setString(5, playerData.getSerializedEnderChest());
|
||||||
statement.setDouble(6, 20D); // Health
|
statement.setDouble(6, playerData.getHealth()); // Health
|
||||||
statement.setDouble(7, 20D); // Max health
|
statement.setDouble(7, playerData.getMaxHealth()); // Max health
|
||||||
statement.setDouble(8, 20D); // Hunger
|
statement.setInt(8, playerData.getHunger()); // Hunger
|
||||||
statement.setDouble(9, 20D); // Saturation
|
statement.setFloat(9, playerData.getSaturation()); // Saturation
|
||||||
statement.setString(10, ""); // Status effects
|
statement.setInt(10, playerData.getSelectedSlot());
|
||||||
|
statement.setString(11, playerData.getSerializedEffectData()); // Status effects
|
||||||
|
|
||||||
statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
}
|
}
|
||||||
@@ -178,7 +170,6 @@ public class DataManager {
|
|||||||
* A cache of PlayerData
|
* A cache of PlayerData
|
||||||
*/
|
*/
|
||||||
public static class PlayerDataCache {
|
public static class PlayerDataCache {
|
||||||
|
|
||||||
// The cached player data
|
// The cached player data
|
||||||
public HashSet<PlayerData> playerData;
|
public HashSet<PlayerData> playerData;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.crossserversync.bungeecord.data.sql;
|
package me.william278.crossserversync.bungeecord.data.sql;
|
||||||
|
|
||||||
import me.william278.crossserversync.Settings;
|
import me.william278.crossserversync.Settings;
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package me.william278.crossserversync.bungeecord.data.sql;
|
|||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import me.william278.crossserversync.Settings;
|
import me.william278.crossserversync.Settings;
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -27,8 +27,9 @@ public class MySQL extends Database {
|
|||||||
"`ender_chest` longtext NOT NULL," +
|
"`ender_chest` longtext NOT NULL," +
|
||||||
"`health` double NOT NULL," +
|
"`health` double NOT NULL," +
|
||||||
"`max_health` double NOT NULL," +
|
"`max_health` double NOT NULL," +
|
||||||
"`hunger` double NOT NULL," +
|
"`hunger` integer NOT NULL," +
|
||||||
"`saturation` double NOT NULL," +
|
"`saturation` float NOT NULL," +
|
||||||
|
"`selected_slot` integer NOT NULL," +
|
||||||
"`status_effects` longtext NOT NULL," +
|
"`status_effects` longtext NOT NULL," +
|
||||||
|
|
||||||
"PRIMARY KEY (`player_id`,`uuid`)," +
|
"PRIMARY KEY (`player_id`,`uuid`)," +
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.crossserversync.bungeecord.data.sql;
|
package me.william278.crossserversync.bungeecord.data.sql;
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -23,28 +23,25 @@ public class SQLite extends Database {
|
|||||||
"PRAGMA encoding = 'UTF-8';",
|
"PRAGMA encoding = 'UTF-8';",
|
||||||
|
|
||||||
"CREATE TABLE IF NOT EXISTS " + PLAYER_TABLE_NAME + " (" +
|
"CREATE TABLE IF NOT EXISTS " + PLAYER_TABLE_NAME + " (" +
|
||||||
"`id` integer NOT NULL AUTO_INCREMENT," +
|
"`id` integer PRIMARY KEY," +
|
||||||
"`uuid` char(36) NOT NULL UNIQUE," +
|
"`uuid` char(36) NOT NULL UNIQUE" +
|
||||||
|
|
||||||
"PRIMARY KEY (`id`)" +
|
|
||||||
");",
|
");",
|
||||||
|
|
||||||
"CREATE TABLE IF NOT EXISTS " + DATA_TABLE_NAME + " (" +
|
"CREATE TABLE IF NOT EXISTS " + DATA_TABLE_NAME + " (" +
|
||||||
"`player_id` integer NOT NULL," +
|
"`player_id` integer NOT NULL REFERENCES " + PLAYER_TABLE_NAME + "(`id`)," +
|
||||||
"`version_uuid` char(36) NOT NULL UNIQUE," +
|
"`version_uuid` char(36) NOT NULL UNIQUE," +
|
||||||
"`timestamp` datetime NOT NULL," +
|
"`timestamp` datetime NOT NULL," +
|
||||||
"`inventory` longtext NOT NULL," +
|
"`inventory` longtext NOT NULL," +
|
||||||
"`ender_chest` longtext NOT NULL," +
|
"`ender_chest` longtext NOT NULL," +
|
||||||
"`health` double NOT NULL," +
|
"`health` double NOT NULL," +
|
||||||
"`max_health` double NOT NULL," +
|
"`max_health` double NOT NULL," +
|
||||||
"`hunger` double NOT NULL," +
|
"`hunger` integer NOT NULL," +
|
||||||
"`saturation` double NOT NULL," +
|
"`saturation` float NOT NULL," +
|
||||||
|
"`selected_slot` integer NOT NULL," +
|
||||||
"`status_effects` longtext NOT NULL," +
|
"`status_effects` longtext NOT NULL," +
|
||||||
|
|
||||||
"PRIMARY KEY (`player_id`,`uuid`)," +
|
"PRIMARY KEY (`player_id`,`version_uuid`)" +
|
||||||
"FOREIGN KEY (`player_id`) REFERENCES " + PLAYER_TABLE_NAME + "(`id`)" +
|
|
||||||
");"
|
");"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "CrossServerSyncData";
|
private static final String DATABASE_NAME = "CrossServerSyncData";
|
||||||
@@ -80,9 +77,10 @@ public class SQLite extends Database {
|
|||||||
createDatabaseFileIfNotExist();
|
createDatabaseFileIfNotExist();
|
||||||
|
|
||||||
// Create new HikariCP data source
|
// Create new HikariCP data source
|
||||||
final String jdbcUrl = "jdbc:sqlite:" + plugin.getDataFolder().getAbsolutePath() + "/" + DATABASE_NAME + ".db";
|
final String jdbcUrl = "jdbc:sqlite:" + plugin.getDataFolder().getAbsolutePath() + File.separator + DATABASE_NAME + ".db";
|
||||||
dataSource = new HikariDataSource();
|
dataSource = new HikariDataSource();
|
||||||
dataSource.setJdbcUrl(jdbcUrl);
|
dataSource.setDataSourceClassName("org.sqlite.SQLiteDataSource");
|
||||||
|
dataSource.addDataSourceProperty("url", jdbcUrl);
|
||||||
|
|
||||||
// Set various additional parameters
|
// Set various additional parameters
|
||||||
dataSource.setMaximumPoolSize(hikariMaximumPoolSize);
|
dataSource.setMaximumPoolSize(hikariMaximumPoolSize);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.william278.crossserversync.bungeecord.listener;
|
package me.william278.crossserversync.bungeecord.listener;
|
||||||
|
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
|
import me.william278.crossserversync.PlayerData;
|
||||||
import me.william278.crossserversync.bungeecord.data.DataManager;
|
import me.william278.crossserversync.bungeecord.data.DataManager;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
@@ -20,16 +20,12 @@ public class BungeeEventListener implements Listener {
|
|||||||
// Ensure the player has data on SQL
|
// Ensure the player has data on SQL
|
||||||
DataManager.ensurePlayerExists(player.getUniqueId());
|
DataManager.ensurePlayerExists(player.getUniqueId());
|
||||||
|
|
||||||
|
// Get the player's data from SQL
|
||||||
|
final PlayerData data = DataManager.getPlayerData(player.getUniqueId());
|
||||||
|
|
||||||
// Update the player's data from SQL onto the cache
|
// Update the player's data from SQL onto the cache
|
||||||
DataManager.playerDataCache.updatePlayer(DataManager.getPlayerData(player.getUniqueId()));
|
DataManager.playerDataCache.updatePlayer(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onDisconnect(PlayerDisconnectEvent event) {
|
|
||||||
final ProxiedPlayer player = event.getPlayer();
|
|
||||||
|
|
||||||
// Remove the player's data from the cache
|
|
||||||
DataManager.playerDataCache.removePlayer(player.getUniqueId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package me.william278.crossserversync.bungeecord.listener;
|
package me.william278.crossserversync.bungeecord.listener;
|
||||||
|
|
||||||
|
import me.william278.crossserversync.CrossServerSyncBungeeCord;
|
||||||
import me.william278.crossserversync.PlayerData;
|
import me.william278.crossserversync.PlayerData;
|
||||||
import me.william278.crossserversync.Settings;
|
import me.william278.crossserversync.Settings;
|
||||||
import me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord;
|
|
||||||
import me.william278.crossserversync.bungeecord.data.DataManager;
|
import me.william278.crossserversync.bungeecord.data.DataManager;
|
||||||
import me.william278.crossserversync.redis.RedisListener;
|
import me.william278.crossserversync.redis.RedisListener;
|
||||||
import me.william278.crossserversync.redis.RedisMessage;
|
import me.william278.crossserversync.redis.RedisMessage;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -66,17 +64,11 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case PLAYER_DATA_UPDATE -> {
|
case PLAYER_DATA_UPDATE -> {
|
||||||
// Get the update data
|
// Deserialize the PlayerData received
|
||||||
final String[] updateData = message.getMessageDataSeparated();
|
|
||||||
|
|
||||||
// Get UUID of the last-updated data on the spigot
|
|
||||||
final UUID lastDataUpdateUUID = UUID.fromString(updateData[0]);
|
|
||||||
|
|
||||||
// Deserialize the PlayerData
|
|
||||||
PlayerData playerData;
|
PlayerData playerData;
|
||||||
final String serializedPlayerData = updateData[1];
|
final String serializedPlayerData = message.getMessageData();
|
||||||
try (ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(serializedPlayerData.getBytes()))) {
|
try {
|
||||||
playerData = (PlayerData) stream.readObject();
|
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
log(Level.SEVERE, "Failed to deserialize PlayerData when handling a player update request");
|
log(Level.SEVERE, "Failed to deserialize PlayerData when handling a player update request");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -84,7 +76,7 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the data in the cache and SQL
|
// Update the data in the cache and SQL
|
||||||
DataManager.updatePlayerData(playerData, lastDataUpdateUUID);
|
DataManager.updatePlayerData(playerData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,4 @@ shadowJar {
|
|||||||
|
|
||||||
// Relocations
|
// Relocations
|
||||||
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
|
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
|
||||||
relocate 'org.apache.commons', 'me.William278.crossserversync.libraries.apache-commons'
|
|
||||||
relocate 'org.slf4j', 'me.William278.crossserversync.libraries.slf4j'
|
|
||||||
}
|
}
|
||||||
@@ -15,41 +15,59 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private final UUID dataVersionUUID;
|
private final UUID dataVersionUUID;
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialized inventory data
|
|
||||||
*/
|
|
||||||
private final String serializedInventory;
|
|
||||||
|
|
||||||
/**
|
// Player data
|
||||||
* Serialized ender chest data
|
private final String serializedInventory;
|
||||||
*/
|
|
||||||
private final String serializedEnderChest;
|
private final String serializedEnderChest;
|
||||||
|
private final double health;
|
||||||
|
private final double maxHealth;
|
||||||
|
private final int hunger;
|
||||||
|
private final float saturation;
|
||||||
|
private final int selectedSlot;
|
||||||
|
private final String serializedEffectData;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new PlayerData object; a random data version UUID will be selected.
|
* Create a new PlayerData object; a random data version UUID will be selected.
|
||||||
*
|
* @param playerUUID UUID of the player
|
||||||
* @param playerUUID The UUID of the player
|
* @param serializedInventory Serialized inventory data
|
||||||
* @param serializedInventory The player's serialized inventory data
|
* @param serializedEnderChest Serialized ender chest data
|
||||||
|
* @param health Player health
|
||||||
|
* @param maxHealth Player max health
|
||||||
|
* @param hunger Player hunger
|
||||||
|
* @param saturation Player saturation
|
||||||
|
* @param selectedSlot Player selected slot
|
||||||
|
* @param serializedStatusEffects Serialized status effect data
|
||||||
*/
|
*/
|
||||||
//todo add more stuff, like player health, max health, hunger, saturation and status effects
|
public PlayerData(UUID playerUUID, String serializedInventory, String serializedEnderChest, double health, double maxHealth, int hunger, float saturation, int selectedSlot, String serializedStatusEffects) {
|
||||||
public PlayerData(UUID playerUUID, String serializedInventory, String serializedEnderChest) {
|
|
||||||
this.dataVersionUUID = UUID.randomUUID();
|
this.dataVersionUUID = UUID.randomUUID();
|
||||||
this.playerUUID = playerUUID;
|
this.playerUUID = playerUUID;
|
||||||
this.serializedInventory = serializedInventory;
|
this.serializedInventory = serializedInventory;
|
||||||
this.serializedEnderChest = serializedEnderChest;
|
this.serializedEnderChest = serializedEnderChest;
|
||||||
|
this.health = health;
|
||||||
|
this.maxHealth = maxHealth;
|
||||||
|
this.hunger = hunger;
|
||||||
|
this.saturation = saturation;
|
||||||
|
this.selectedSlot = selectedSlot;
|
||||||
|
this.serializedEffectData = serializedStatusEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerData(UUID playerUUID, UUID dataVersionUUID, String serializedInventory, String serializedEnderChest, double health, double maxHealth, double hunger, double saturation, String serializedStatusEffects) {
|
public PlayerData(UUID playerUUID, UUID dataVersionUUID, String serializedInventory, String serializedEnderChest, double health, double maxHealth, int hunger, float saturation, int selectedSlot, String serializedStatusEffects) {
|
||||||
this.playerUUID = playerUUID;
|
this.playerUUID = playerUUID;
|
||||||
this.dataVersionUUID = dataVersionUUID;
|
this.dataVersionUUID = dataVersionUUID;
|
||||||
this.serializedInventory = serializedInventory;
|
this.serializedInventory = serializedInventory;
|
||||||
this.serializedEnderChest = serializedEnderChest;
|
this.serializedEnderChest = serializedEnderChest;
|
||||||
|
this.health = health;
|
||||||
//todo Incorporate more of these
|
this.maxHealth = maxHealth;
|
||||||
|
this.hunger = hunger;
|
||||||
|
this.saturation = saturation;
|
||||||
|
this.selectedSlot = selectedSlot;
|
||||||
|
this.serializedEffectData = serializedStatusEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlayerData EMPTY_PLAYER_DATA(UUID playerUUID) {
|
public static PlayerData EMPTY_PLAYER_DATA(UUID playerUUID) {
|
||||||
return new PlayerData(playerUUID, "", "");
|
return new PlayerData(playerUUID, "", "", 20,
|
||||||
|
20, 20, 20, 0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getPlayerUUID() {
|
public UUID getPlayerUUID() {
|
||||||
@@ -67,4 +85,28 @@ public class PlayerData implements Serializable {
|
|||||||
public String getSerializedEnderChest() {
|
public String getSerializedEnderChest() {
|
||||||
return serializedEnderChest;
|
return serializedEnderChest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getHealth() {
|
||||||
|
return health;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getMaxHealth() {
|
||||||
|
return maxHealth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHunger() {
|
||||||
|
return hunger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSaturation() {
|
||||||
|
return saturation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedSlot() {
|
||||||
|
return selectedSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSerializedEffectData() {
|
||||||
|
return serializedEffectData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,10 +71,6 @@ public class RedisMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getMessageDataSeparated() {
|
|
||||||
return messageData.split(MESSAGE_DATA_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessageData() {
|
public String getMessageData() {
|
||||||
return messageData;
|
return messageData;
|
||||||
}
|
}
|
||||||
@@ -90,7 +86,7 @@ public class RedisMessage {
|
|||||||
/**
|
/**
|
||||||
* Defines the type of the message
|
* Defines the type of the message
|
||||||
*/
|
*/
|
||||||
public enum MessageType {
|
public enum MessageType implements Serializable {
|
||||||
/**
|
/**
|
||||||
* Sent by Bukkit servers to proxy when a player disconnects with a player's updated data, alongside the UUID of the last loaded {@link PlayerData} for the user
|
* Sent by Bukkit servers to proxy when a player disconnects with a player's updated data, alongside the UUID of the last loaded {@link PlayerData} for the user
|
||||||
*/
|
*/
|
||||||
@@ -111,7 +107,7 @@ public class RedisMessage {
|
|||||||
* A record that defines the target of a plugin message; a spigot server or the proxy server(s).
|
* A record that defines the target of a plugin message; a spigot server or the proxy server(s).
|
||||||
* For Bukkit servers, the name of the server must also be specified
|
* For Bukkit servers, the name of the server must also be specified
|
||||||
*/
|
*/
|
||||||
public record MessageTarget(Settings.ServerType targetServerType, UUID targetPlayerName) implements Serializable { }
|
public record MessageTarget(Settings.ServerType targetServerType, UUID targetPlayerUUID) implements Serializable { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize an object from a Base64 string
|
* Deserialize an object from a Base64 string
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
name: CrossServerSync
|
name: CrossServerSync
|
||||||
version: @version@
|
version: @version@
|
||||||
main: me.william278.crossserversync.bungeecord.CrossServerSyncBungeeCord
|
main: me.william278.crossserversync.CrossServerSyncBungeeCord
|
||||||
author: William278
|
author: William278
|
||||||
description: 'Synchronize data cross-server'
|
description: 'Synchronize data cross-server'
|
||||||
|
libraries:
|
||||||
|
- mysql:mysql-connector-java:8.0.25
|
||||||
|
- org.xerial:sqlite-jdbc:3.36.0.3
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
name: CrossServerSync
|
name: CrossServerSync
|
||||||
version: @version@
|
version: @version@
|
||||||
main: me.william278.crossserversync.bukkit.CrossServerSyncBukkit
|
main: me.william278.crossserversync.CrossServerSyncBukkit
|
||||||
api-version: 1.16
|
api-version: 1.16
|
||||||
author: William278
|
author: William278
|
||||||
description: 'Synchronize data cross-server'
|
description: 'Synchronize data cross-server'
|
||||||
Reference in New Issue
Block a user