Refactor name to be HuskSync

feat/data-edit-commands
William 3 years ago
parent 520f1ea1d7
commit f842afac1e

@ -1,20 +1,20 @@
# CrossServerSync
**CrossServerSync** is a robust solution for synchronising player data (inventories, health, hunger & status effects) between servers. It was designed as a much faster alternative to MySQLPlayerDataBridge,
# HuskSync
**HuskSync** is a robust solution for synchronising player data (inventories, health, hunger & status effects) between servers. It was designed as a much faster alternative to MySQLPlayerDataBridge,
### Installation
Install CrossServerSync in the `/plugins/` folder of your Spigot (and derivatives) servers and Proxy (BungeeCord and derivatives) server.
## Installation
Install HuskSync in the `/plugins/` folder of your Spigot (and derivatives) servers and Proxy (BungeeCord and derivatives) server.
Start your servers, then stop them again to allow the configuration files to generate.
Navigate to the generated config.yml files on your Spigot server and Proxy (located in `/plugins/CrossServerSync/`) and fill in the credentials of your redis server. On the Proxy server, you can additionally configure a MySQL database to save player data in, as by default the plugin will create a SQLite database for this.
Navigate to the generated config.yml files on your Spigot server and Proxy (located in `/plugins/HuskSync/`) and fill in the credentials of your redis server. On the Proxy server, you can additionally configure a MySQL database to save player data in, as by default the plugin will create a SQLite database for this.
If you have multiple proxy servers (i.e. via RedisBungee), you need to install the plugin on all of them and make use of the MySQL option and ensure the proxies are using the same database.
### How it works
## How it works
![Flow chart showing different processes of how the plugin works](images/flow-chart.png)
CrossServerSync synchronises player data between servers using Redis to transfer cached data, loaded from a central database as necessary.
HuskSync synchronises player data between servers using Redis to transfer cached data, loaded from a central database as necessary.
### Building
To build CrossServerSync, run the following in the root of the repository:
## Building
To build HuskSync, run the following in the root of the repository:
```
./gradlew clean build
```

@ -18,7 +18,7 @@ allprojects {
javadoc { options.encoding = 'UTF-8' }
}
logger.lifecycle('Building CrossServerSync v' + version.toString())
logger.lifecycle('Building HuskSync v' + version.toString())
subprojects {
apply plugin: 'com.github.johnrengelman.shadow'

@ -10,9 +10,9 @@ dependencies {
}
shadowJar {
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
relocate 'org.bstats', 'me.William278.crossserversync.libraries.plan'
relocate 'de.themoep', 'me.William278.crossserversync.libraries.minedown'
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
relocate 'org.bstats', 'me.William278.husksync.libraries.plan'
relocate 'de.themoep', 'me.William278.husksync.libraries.minedown'
}
tasks.register('prepareKotlinBuildScriptModel'){}

@ -1,15 +1,15 @@
package me.william278.crossserversync;
package me.william278.husksync;
import me.william278.crossserversync.bukkit.config.ConfigLoader;
import me.william278.crossserversync.bukkit.data.BukkitDataCache;
import me.william278.crossserversync.bukkit.listener.BukkitRedisListener;
import me.william278.crossserversync.bukkit.listener.EventListener;
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 org.bukkit.plugin.java.JavaPlugin;
public final class CrossServerSyncBukkit extends JavaPlugin {
public final class HuskSyncBukkit extends JavaPlugin {
private static CrossServerSyncBukkit instance;
public static CrossServerSyncBukkit getInstance() {
private static HuskSyncBukkit instance;
public static HuskSyncBukkit getInstance() {
return instance;
}
@ -41,12 +41,12 @@ public final class CrossServerSyncBukkit extends JavaPlugin {
new BukkitRedisListener();
// Log to console
getLogger().info("Enabled CrossServerSync (" + getServer().getName() + ") v" + getDescription().getVersion());
getLogger().info("Enabled HuskSync (" + getServer().getName() + ") v" + getDescription().getVersion());
}
@Override
public void onDisable() {
// Plugin shutdown logic
getLogger().info("Disabled CrossServerSync (" + getServer().getName() + ") v" + getDescription().getVersion());
getLogger().info("Disabled HuskSync (" + getServer().getName() + ") v" + getDescription().getVersion());
}
}

@ -1,6 +1,6 @@
package me.william278.crossserversync.bukkit;
package me.william278.husksync.bukkit;
import me.william278.crossserversync.redis.RedisMessage;
import me.william278.husksync.redis.RedisMessage;
import org.bukkit.*;
import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress;
@ -175,7 +175,7 @@ public final class DataSerializer {
return null;
}
try {
return (PlayerLocation) RedisMessage.deserialize(serializedLocationData);
return (PlayerLocation) me.william278.husksync.redis.RedisMessage.deserialize(serializedLocationData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
@ -183,7 +183,7 @@ public final class DataSerializer {
public static String getSerializedLocation(Player player) throws IOException {
final Location playerLocation = player.getLocation();
return RedisMessage.serialize(new PlayerLocation(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ(),
return me.william278.husksync.redis.RedisMessage.serialize(new PlayerLocation(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ(),
playerLocation.getYaw(), playerLocation.getPitch(), player.getWorld().getName(), player.getWorld().getEnvironment()));
}
@ -197,7 +197,7 @@ public final class DataSerializer {
return new ArrayList<>();
}
try {
return (ArrayList<AdvancementRecord>) RedisMessage.deserialize(serializedAdvancementData);
return (ArrayList<AdvancementRecord>) me.william278.husksync.redis.RedisMessage.deserialize(serializedAdvancementData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
@ -214,7 +214,7 @@ public final class DataSerializer {
advancementData.add(new AdvancementRecord(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria));
}
return RedisMessage.serialize(advancementData);
return me.william278.husksync.redis.RedisMessage.serialize(advancementData);
}
public record AdvancementRecord(String advancementKey,
@ -226,7 +226,7 @@ public final class DataSerializer {
return new StatisticData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
}
try {
return (StatisticData) RedisMessage.deserialize(serializedStatisticData);
return (StatisticData) me.william278.husksync.redis.RedisMessage.deserialize(serializedStatisticData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}

@ -1,10 +1,10 @@
package me.william278.crossserversync.bukkit;
package me.william278.husksync.bukkit;
import de.themoep.minedown.MineDown;
import me.william278.crossserversync.CrossServerSyncBukkit;
import me.william278.crossserversync.MessageStrings;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.Settings;
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 org.bukkit.*;
import org.bukkit.advancement.Advancement;
@ -23,7 +23,7 @@ import java.util.logging.Level;
public class PlayerSetter {
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.getInstance();
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
/**
* Set a player from their PlayerData, based on settings

@ -1,6 +1,6 @@
package me.william278.crossserversync.bukkit.config;
package me.william278.husksync.bukkit.config;
import me.william278.crossserversync.Settings;
import me.william278.husksync.Settings;
import org.bukkit.configuration.file.FileConfiguration;
public class ConfigLoader {

@ -1,34 +1,19 @@
package me.william278.crossserversync.bukkit.data;
package me.william278.husksync.bukkit.data;
import java.util.HashMap;
import java.util.HashSet;
import java.util.UUID;
public class BukkitDataCache {
/**
* Map of Player UUIDs to last-updated PlayerData version UUIDs
*/
private static HashMap<UUID, UUID> bukkitDataCache;
/**
* Map of Player UUIDs to request on join
*/
private static HashSet<UUID> requestOnJoin;
public BukkitDataCache() {
bukkitDataCache = new HashMap<>();
requestOnJoin = new HashSet<>();
}
public UUID getVersionUUID(UUID playerUUID) {
return bukkitDataCache.get(playerUUID);
}
public void setVersionUUID(UUID playerUUID, UUID dataVersionUUID) {
bukkitDataCache.put(playerUUID, dataVersionUUID);
}
public boolean isPlayerRequestingOnJoin(UUID uuid) {
return requestOnJoin.contains(uuid);
}

@ -1,13 +1,13 @@
package me.william278.crossserversync.bukkit.listener;
package me.william278.husksync.bukkit.listener;
import de.themoep.minedown.MineDown;
import me.william278.crossserversync.MessageStrings;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.CrossServerSyncBukkit;
import me.william278.crossserversync.bukkit.PlayerSetter;
import me.william278.crossserversync.redis.RedisListener;
import me.william278.crossserversync.redis.RedisMessage;
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.Settings;
import me.william278.husksync.redis.RedisMessage;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -17,7 +17,7 @@ import java.util.logging.Level;
public class BukkitRedisListener extends RedisListener {
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.getInstance();
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
// Initialize the listener on the bukkit server
public BukkitRedisListener() {
@ -25,12 +25,12 @@ public class BukkitRedisListener extends RedisListener {
}
/**
* Handle an incoming {@link RedisMessage}
* Handle an incoming {@link me.william278.husksync.redis.RedisMessage}
*
* @param message The {@link RedisMessage} to handle
* @param message The {@link me.william278.husksync.redis.RedisMessage} to handle
*/
@Override
public void handleMessage(RedisMessage message) {
public void handleMessage(me.william278.husksync.redis.RedisMessage message) {
// Ignore messages for proxy servers
if (!message.getMessageTarget().targetServerType().equals(Settings.ServerType.BUKKIT)) {
return;
@ -39,11 +39,11 @@ public class BukkitRedisListener extends RedisListener {
// Handle the message for the player
if (message.getMessageTarget().targetPlayerUUID() == null) {
if (message.getMessageType() == RedisMessage.MessageType.REQUEST_DATA_ON_JOIN) {
if (message.getMessageType() == me.william278.husksync.redis.RedisMessage.MessageType.REQUEST_DATA_ON_JOIN) {
UUID playerUUID = UUID.fromString(message.getMessageDataElements()[1]);
switch (RedisMessage.RequestOnJoinUpdateType.valueOf(message.getMessageDataElements()[0])) {
case ADD_REQUESTER -> CrossServerSyncBukkit.bukkitCache.setRequestOnJoin(playerUUID);
case REMOVE_REQUESTER -> CrossServerSyncBukkit.bukkitCache.removeRequestOnJoin(playerUUID);
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);
}
}
} else {
@ -55,9 +55,6 @@ public class BukkitRedisListener extends RedisListener {
// Deserialize the received PlayerData
PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageData());
// Update last loaded data UUID
CrossServerSyncBukkit.bukkitCache.setVersionUUID(player.getUniqueId(), data.getDataVersionUUID());
// Set the player's data
PlayerSetter.setPlayerFrom(player, data);
} catch (IOException | ClassNotFoundException e) {

@ -1,10 +1,10 @@
package me.william278.crossserversync.bukkit.listener;
package me.william278.husksync.bukkit.listener;
import me.william278.crossserversync.CrossServerSyncBukkit;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.bukkit.DataSerializer;
import me.william278.crossserversync.redis.RedisMessage;
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.redis.RedisMessage;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -18,7 +18,7 @@ import java.util.logging.Level;
public class EventListener implements Listener {
private static final CrossServerSyncBukkit plugin = CrossServerSyncBukkit.getInstance();
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
/**
* Returns the new serialized PlayerData for a player.
@ -28,7 +28,7 @@ public class EventListener implements Listener {
* @throws IOException If the serialization fails
*/
private static String getNewSerializedPlayerData(Player player) throws IOException {
return RedisMessage.serialize(new PlayerData(player.getUniqueId(),
return me.william278.husksync.redis.RedisMessage.serialize(new PlayerData(player.getUniqueId(),
DataSerializer.getSerializedInventoryContents(player),
DataSerializer.getSerializedEnderChestContents(player),
player.getHealth(),
@ -53,15 +53,11 @@ public class EventListener implements Listener {
// 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.bukkitCache.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
try {
final String serializedPlayerData = getNewSerializedPlayerData(player);
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
new RedisMessage.MessageTarget(Settings.ServerType.BUNGEECORD, null),
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),
serializedPlayerData).send();
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
@ -70,9 +66,6 @@ public class EventListener implements Listener {
// Clear player inventory and ender chest
player.getInventory().clear();
player.getEnderChest().clear();
// Set data version ID to null
CrossServerSyncBukkit.bukkitCache.setVersionUUID(player.getUniqueId(), null);
}
@EventHandler
@ -84,10 +77,10 @@ public class EventListener implements Listener {
player.getInventory().clear();
player.getEnderChest().clear();
if (CrossServerSyncBukkit.bukkitCache.isPlayerRequestingOnJoin(player.getUniqueId())) {
if (HuskSyncBukkit.bukkitCache.isPlayerRequestingOnJoin(player.getUniqueId())) {
try {
// Send a redis message requesting the player data
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_REQUEST,
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();
} catch (IOException e) {

@ -10,10 +10,10 @@ dependencies {
}
shadowJar {
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
relocate 'com.zaxxer', 'me.William278.crossserversync.libraries.hikari'
relocate 'org.bstats', 'me.William278.crossserversync.libraries.plan'
relocate 'de.themoep', 'me.William278.crossserversync.libraries.minedown'
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
relocate 'com.zaxxer', 'me.William278.husksync.libraries.hikari'
relocate 'org.bstats', 'me.William278.husksync.libraries.plan'
relocate 'de.themoep', 'me.William278.husksync.libraries.minedown'
}
tasks.register('prepareKotlinBuildScriptModel'){}

@ -1,33 +0,0 @@
package me.william278.crossserversync.bungeecord.data.sql;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import java.sql.Connection;
import java.sql.SQLException;
public abstract class Database {
protected CrossServerSyncBungeeCord plugin;
public final static String DATA_POOL_NAME = "CrossServerSyncHikariPool";
public final static String PLAYER_TABLE_NAME = "crossserversync_players";
public final static String DATA_TABLE_NAME = "crossserversync_data";
public Database(CrossServerSyncBungeeCord instance) {
plugin = instance;
}
public abstract Connection getConnection() throws SQLException;
public abstract void load();
public abstract void backup();
public abstract void close();
public final int hikariMaximumPoolSize = Settings.hikariMaximumPoolSize;
public final int hikariMinimumIdle = Settings.hikariMinimumIdle;
public final long hikariMaximumLifetime = Settings.hikariMaximumLifetime;
public final long hikariKeepAliveTime = Settings.hikariKeepAliveTime;
public final long hikariConnectionTimeOut = Settings.hikariConnectionTimeOut;
}

@ -1,24 +1,24 @@
package me.william278.crossserversync;
import me.william278.crossserversync.bungeecord.command.CrossServerSyncCommand;
import me.william278.crossserversync.bungeecord.config.ConfigLoader;
import me.william278.crossserversync.bungeecord.config.ConfigManager;
import me.william278.crossserversync.bungeecord.data.DataManager;
import me.william278.crossserversync.bungeecord.data.sql.Database;
import me.william278.crossserversync.bungeecord.data.sql.MySQL;
import me.william278.crossserversync.bungeecord.data.sql.SQLite;
import me.william278.crossserversync.bungeecord.listener.BungeeEventListener;
import me.william278.crossserversync.bungeecord.listener.BungeeRedisListener;
package me.william278.husksync;
import me.william278.husksync.bungeecord.command.HuskSyncCommand;
import me.william278.husksync.bungeecord.config.ConfigLoader;
import me.william278.husksync.bungeecord.config.ConfigManager;
import me.william278.husksync.bungeecord.data.DataManager;
import me.william278.husksync.bungeecord.data.sql.Database;
import me.william278.husksync.bungeecord.data.sql.MySQL;
import me.william278.husksync.bungeecord.data.sql.SQLite;
import me.william278.husksync.bungeecord.listener.BungeeEventListener;
import me.william278.husksync.bungeecord.listener.BungeeRedisListener;
import net.md_5.bungee.api.plugin.Plugin;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;
public final class CrossServerSyncBungeeCord extends Plugin {
public final class HuskSyncBungeeCord extends Plugin {
private static CrossServerSyncBungeeCord instance;
public static CrossServerSyncBungeeCord getInstance() {
private static HuskSyncBungeeCord instance;
public static HuskSyncBungeeCord getInstance() {
return instance;
}
@ -56,13 +56,13 @@ public final class CrossServerSyncBungeeCord extends Plugin {
getProxy().getPluginManager().registerListener(this, new BungeeEventListener());
// Register command
getProxy().getPluginManager().registerCommand(this, new CrossServerSyncCommand());
getProxy().getPluginManager().registerCommand(this, new HuskSyncCommand());
// Initialize the redis listener
new BungeeRedisListener();
// Log to console
getLogger().info("Enabled CrossServerSync (" + getProxy().getName() + ") v" + getDescription().getVersion());
getLogger().info("Enabled HuskSync (" + getProxy().getName() + ") v" + getDescription().getVersion());
}
@Override
@ -73,6 +73,6 @@ public final class CrossServerSyncBungeeCord extends Plugin {
database.close();
// Log to console
getLogger().info("Disabled CrossServerSync (" + getProxy().getName() + ") v" + getDescription().getVersion());
getLogger().info("Disabled HuskSync (" + getProxy().getName() + ") v" + getDescription().getVersion());
}
}

@ -1,10 +1,10 @@
package me.william278.crossserversync.bungeecord.command;
package me.william278.husksync.bungeecord.command;
import de.themoep.minedown.MineDown;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.crossserversync.MessageStrings;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.redis.RedisMessage;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.MessageStrings;
import me.william278.husksync.Settings;
import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
@ -17,14 +17,14 @@ import java.util.Locale;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class CrossServerSyncCommand extends Command implements TabExecutor {
public class HuskSyncCommand extends Command implements TabExecutor {
private final static CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
private final static HuskSyncBungeeCord plugin = HuskSyncBungeeCord.getInstance();
private final static String[] COMMAND_TAB_ARGUMENTS = {"about", "reload"};
private final static String PERMISSION = "crossserversync.command.csc";
private final static String PERMISSION = "husksync.command.csc";
//public CrossServerSyncCommand() { super("csc", PERMISSION, "crossserversync"); }
public CrossServerSyncCommand() { super("csc"); }
//public HuskSyncCommand() { super("husksync", PERMISSION, "hs"); }
public HuskSyncCommand() { super("husksync"); }
@Override
public void execute(CommandSender sender, String[] args) {
@ -47,7 +47,7 @@ public class CrossServerSyncCommand extends Command implements TabExecutor {
*/
private void sendAboutInformation(ProxiedPlayer player) {
try {
new RedisMessage(RedisMessage.MessageType.SEND_PLUGIN_INFORMATION,
new me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.SEND_PLUGIN_INFORMATION,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, player.getUniqueId()),
plugin.getProxy().getName(), plugin.getDescription().getVersion()).send();
} catch (IOException e) {

@ -1,6 +1,6 @@
package me.william278.crossserversync.bungeecord.config;
package me.william278.husksync.bungeecord.config;
import me.william278.crossserversync.Settings;
import me.william278.husksync.Settings;
import net.md_5.bungee.config.Configuration;
public class ConfigLoader {
@ -15,16 +15,16 @@ public class ConfigLoader {
if (Settings.dataStorageType == Settings.DataStorageType.MYSQL) {
Settings.mySQLHost = config.getString("data_storage_settings.mysql_settings.host", "localhost");
Settings.mySQLPort = config.getInt("data_storage_settings.mysql_settings.port", 8123);
Settings.mySQLDatabase = config.getString("data_storage_settings.mysql_settings.database", "CrossServerSync");
Settings.mySQLUsername = config.getString("data_storage_settings.mysql_settings.username", "CrossServerSync");
Settings.mySQLPassword = config.getString("data_storage_settings.mysql_settings.password", "CrossServerSync");
Settings.mySQLParams = config.getString("data_storage_settings.mysql_settings.params", "CrossServerSync");
Settings.mySQLDatabase = config.getString("data_storage_settings.mysql_settings.database", "HuskSync");
Settings.mySQLUsername = config.getString("data_storage_settings.mysql_settings.username", "root");
Settings.mySQLPassword = config.getString("data_storage_settings.mysql_settings.password", "pa55w0rd");
Settings.mySQLParams = config.getString("data_storage_settings.mysql_settings.params", "?autoReconnect=true&useSSL=false");
}
Settings.hikariMaximumPoolSize = config.getInt("data_storage_settings.hikari_pool_settings.maximum_pool_size", 10);
Settings.hikariMinimumIdle = config.getInt("data_storage_settings.hikari_pool_settings.minimum_idle", 10);
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", 0);
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.husksync.bungeecord.config;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.husksync.HuskSyncBungeeCord;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
@ -12,19 +12,19 @@ import java.util.logging.Level;
public class ConfigManager {
private static final CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
private static final HuskSyncBungeeCord plugin = HuskSyncBungeeCord.getInstance();
public static void loadConfig() {
try {
if (!plugin.getDataFolder().exists()) {
if (plugin.getDataFolder().mkdir()) {
plugin.getLogger().info("Created CrossServerSync data folder");
plugin.getLogger().info("Created HuskSync data folder");
}
}
File configFile = new File(plugin.getDataFolder(), "config.yml");
if (!configFile.exists()) {
Files.copy(plugin.getResourceAsStream("bungee-config.yml"), configFile.toPath());
plugin.getLogger().info("Created CrossServerSync bungee-config.yml file");
plugin.getLogger().info("Created HuskSync bungee-config.yml file");
}
} catch (Exception e) {
plugin.getLogger().log(Level.CONFIG, "An exception occurred loading the configuration file", e);

@ -1,8 +1,8 @@
package me.william278.crossserversync.bungeecord.data;
package me.william278.husksync.bungeecord.data;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.crossserversync.bungeecord.data.sql.Database;
import me.william278.husksync.PlayerData;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.bungeecord.data.sql.Database;
import java.sql.*;
import java.time.Instant;
@ -12,7 +12,7 @@ import java.util.logging.Level;
public class DataManager {
private static final CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
private static final HuskSyncBungeeCord plugin = HuskSyncBungeeCord.getInstance();
public static PlayerDataCache playerDataCache;
/**
@ -33,7 +33,7 @@ public class DataManager {
* @return {@code true} if the player is on the player table
*/
private static boolean playerExists(UUID playerUUID) {
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
try (Connection connection = HuskSyncBungeeCord.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?;")) {
statement.setString(1, playerUUID.toString());
@ -47,7 +47,7 @@ public class DataManager {
}
private static void createPlayerEntry(UUID playerUUID) {
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
try (Connection connection = HuskSyncBungeeCord.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(
"INSERT INTO " + Database.PLAYER_TABLE_NAME + " (`uuid`) VALUES(?);")) {
statement.setString(1, playerUUID.toString());
@ -59,7 +59,7 @@ public class DataManager {
}
public static PlayerData getPlayerData(UUID playerUUID) {
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
try (Connection connection = HuskSyncBungeeCord.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM " + Database.DATA_TABLE_NAME + " WHERE `player_id`=(SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?);")) {
statement.setString(1, playerUUID.toString());
@ -115,7 +115,7 @@ public class DataManager {
}
private static void updatePlayerSQLData(PlayerData playerData) {
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
try (Connection connection = HuskSyncBungeeCord.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(
"UPDATE " + Database.DATA_TABLE_NAME + " SET `version_uuid`=?, `timestamp`=?, `inventory`=?, `ender_chest`=?, `health`=?, `max_health`=?, `hunger`=?, `saturation`=?, `saturation_exhaustion`=?, `selected_slot`=?, `status_effects`=?, `total_experience`=?, `exp_level`=?, `exp_progress`=?, `game_mode`=?, `statistics`=?, `is_flying`=?, `advancements`=?, `location`=? WHERE `player_id`=(SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?);")) {
statement.setString(1, playerData.getDataVersionUUID().toString());
@ -147,7 +147,7 @@ public class DataManager {
}
private static void insertPlayerData(PlayerData playerData) {
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
try (Connection connection = HuskSyncBungeeCord.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(
"INSERT INTO " + Database.DATA_TABLE_NAME + " (`player_id`,`version_uuid`,`timestamp`,`inventory`,`ender_chest`,`health`,`max_health`,`hunger`,`saturation`,`saturation_exhaustion`,`selected_slot`,`status_effects`,`total_experience`,`exp_level`,`exp_progress`,`game_mode`,`statistics`,`is_flying`,`advancements`,`location`) VALUES((SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);")) {
statement.setString(1, playerData.getPlayerUUID().toString());
@ -185,7 +185,7 @@ public class DataManager {
* @return {@code true} if the player has an entry in the data table
*/
private static boolean playerHasCachedData(UUID playerUUID) {
try (Connection connection = CrossServerSyncBungeeCord.getConnection()) {
try (Connection connection = HuskSyncBungeeCord.getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM " + Database.DATA_TABLE_NAME + " WHERE `player_id`=(SELECT `id` FROM " + Database.PLAYER_TABLE_NAME + " WHERE `uuid`=?);")) {
statement.setString(1, playerUUID.toString());

@ -0,0 +1,33 @@
package me.william278.husksync.bungeecord.data.sql;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.Settings;
import java.sql.Connection;
import java.sql.SQLException;
public abstract class Database {
protected HuskSyncBungeeCord plugin;
public final static String DATA_POOL_NAME = "HuskSyncHikariPool";
public final static String PLAYER_TABLE_NAME = "husksync_players";
public final static String DATA_TABLE_NAME = "husksync_data";
public Database(HuskSyncBungeeCord instance) {
plugin = instance;
}
public abstract Connection getConnection() throws SQLException;
public abstract void load();
public abstract void backup();
public abstract void close();
public final int hikariMaximumPoolSize = me.william278.husksync.Settings.hikariMaximumPoolSize;
public final int hikariMinimumIdle = me.william278.husksync.Settings.hikariMinimumIdle;
public final long hikariMaximumLifetime = me.william278.husksync.Settings.hikariMaximumLifetime;
public final long hikariKeepAliveTime = me.william278.husksync.Settings.hikariKeepAliveTime;
public final long hikariConnectionTimeOut = Settings.hikariConnectionTimeOut;
}

@ -1,8 +1,8 @@
package me.william278.crossserversync.bungeecord.data.sql;
package me.william278.husksync.bungeecord.data.sql;
import com.zaxxer.hikari.HikariDataSource;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.Settings;
import java.sql.Connection;
import java.sql.SQLException;
@ -47,16 +47,16 @@ public class MySQL extends Database {
};
final String host = Settings.mySQLHost;
final int port = Settings.mySQLPort;
final String database = Settings.mySQLDatabase;
final String username = Settings.mySQLUsername;
final String password = Settings.mySQLPassword;
final String host = me.william278.husksync.Settings.mySQLHost;
final int port = me.william278.husksync.Settings.mySQLPort;
final String database = me.william278.husksync.Settings.mySQLDatabase;
final String username = me.william278.husksync.Settings.mySQLUsername;
final String password = me.william278.husksync.Settings.mySQLPassword;
final String params = Settings.mySQLParams;
private HikariDataSource dataSource;
public MySQL(CrossServerSyncBungeeCord instance) {
public MySQL(HuskSyncBungeeCord instance) {
super(instance);
}

@ -1,7 +1,7 @@
package me.william278.crossserversync.bungeecord.data.sql;
package me.william278.husksync.bungeecord.data.sql;
import com.zaxxer.hikari.HikariDataSource;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.husksync.HuskSyncBungeeCord;
import java.io.File;
import java.io.IOException;
@ -53,11 +53,11 @@ public class SQLite extends Database {
");"
};
private static final String DATABASE_NAME = "CrossServerSyncData";
private static final String DATABASE_NAME = "HuskSyncData";
private HikariDataSource dataSource;
public SQLite(CrossServerSyncBungeeCord instance) {
public SQLite(HuskSyncBungeeCord instance) {
super(instance);
}
@ -127,7 +127,7 @@ public class SQLite extends Database {
.format(Instant.now()).replaceAll(" ", "-") + ".db";
final File databaseFile = new File(plugin.getDataFolder(), DATABASE_NAME + ".db");
if (new File(plugin.getDataFolder(), BACKUPS_FOLDER_NAME).mkdirs()) {
plugin.getLogger().info("Created backups directory in CrossServerSync plugin data folder.");
plugin.getLogger().info("Created backups directory in HuskSync plugin data folder.");
}
final File backUpFile = new File(plugin.getDataFolder(), BACKUPS_FOLDER_NAME + File.separator + backupFileName);
try {

@ -1,10 +1,10 @@
package me.william278.crossserversync.bungeecord.listener;
package me.william278.husksync.bungeecord.listener;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.bungeecord.data.DataManager;
import me.william278.crossserversync.redis.RedisMessage;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.PlayerData;
import me.william278.husksync.bungeecord.data.DataManager;
import me.william278.husksync.Settings;
import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PostLoginEvent;
@ -16,7 +16,7 @@ import java.util.logging.Level;
public class BungeeEventListener implements Listener {
private static final CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
private static final HuskSyncBungeeCord plugin = HuskSyncBungeeCord.getInstance();
@EventHandler
public void onPostLogin(PostLoginEvent event) {
@ -33,8 +33,8 @@ public class BungeeEventListener implements Listener {
// Send a message asking the bukkit to request data on join
try {
new RedisMessage(RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null),
new me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
new me.william278.husksync.redis.RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null),
RedisMessage.RequestOnJoinUpdateType.ADD_REQUESTER.toString(), player.getUniqueId().toString()).send();
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to serialize request data on join message data");

@ -1,11 +1,11 @@
package me.william278.crossserversync.bungeecord.listener;
package me.william278.husksync.bungeecord.listener;
import me.william278.crossserversync.CrossServerSyncBungeeCord;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.Settings;
import me.william278.crossserversync.bungeecord.data.DataManager;
import me.william278.crossserversync.redis.RedisListener;
import me.william278.crossserversync.redis.RedisMessage;
import me.william278.husksync.HuskSyncBungeeCord;
import me.william278.husksync.PlayerData;
import me.william278.husksync.bungeecord.data.DataManager;
import me.william278.husksync.redis.RedisListener;
import me.william278.husksync.Settings;
import me.william278.husksync.redis.RedisMessage;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -15,7 +15,7 @@ import java.util.logging.Level;
public class BungeeRedisListener extends RedisListener {
private static final CrossServerSyncBungeeCord plugin = CrossServerSyncBungeeCord.getInstance();
private static final HuskSyncBungeeCord plugin = HuskSyncBungeeCord.getInstance();
// Initialize the listener on the bungee
public BungeeRedisListener() {
@ -38,14 +38,14 @@ public class BungeeRedisListener extends RedisListener {
}
/**
* Handle an incoming {@link RedisMessage}
* Handle an incoming {@link me.william278.husksync.redis.RedisMessage}
*
* @param message The {@link RedisMessage} to handle
* @param message The {@link me.william278.husksync.redis.RedisMessage} to handle
*/
@Override
public void handleMessage(RedisMessage message) {
public void handleMessage(me.william278.husksync.redis.RedisMessage message) {
// Ignore messages destined for Bukkit servers
if (message.getMessageTarget().targetServerType() != Settings.ServerType.BUNGEECORD) {
if (message.getMessageTarget().targetServerType() != me.william278.husksync.Settings.ServerType.BUNGEECORD) {
return;
}
@ -56,15 +56,15 @@ public class BungeeRedisListener extends RedisListener {
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
try {
// Send the reply, serializing the message data
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, requestingPlayerUUID),
RedisMessage.serialize(getPlayerCachedData(requestingPlayerUUID)))
new me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.PLAYER_DATA_SET,
new me.william278.husksync.redis.RedisMessage.MessageTarget(me.william278.husksync.Settings.ServerType.BUKKIT, requestingPlayerUUID),
me.william278.husksync.redis.RedisMessage.serialize(getPlayerCachedData(requestingPlayerUUID)))
.send();
// Send an update to all bukkit servers removing the player from the requester cache
new RedisMessage(RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null),
RedisMessage.RequestOnJoinUpdateType.REMOVE_REQUESTER.toString(), requestingPlayerUUID.toString())
new me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
new me.william278.husksync.redis.RedisMessage.MessageTarget(me.william278.husksync.Settings.ServerType.BUKKIT, null),
me.william278.husksync.redis.RedisMessage.RequestOnJoinUpdateType.REMOVE_REQUESTER.toString(), requestingPlayerUUID.toString())
.send();
} catch (IOException e) {
log(Level.SEVERE, "Failed to serialize data when replying to a data request");
@ -77,7 +77,7 @@ public class BungeeRedisListener extends RedisListener {
PlayerData playerData;
final String serializedPlayerData = message.getMessageData();
try {
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
playerData = (PlayerData) me.william278.husksync.redis.RedisMessage.deserialize(serializedPlayerData);
} catch (IOException | ClassNotFoundException e) {
log(Level.SEVERE, "Failed to deserialize PlayerData when handling a player update request");
e.printStackTrace();
@ -92,8 +92,8 @@ public class BungeeRedisListener extends RedisListener {
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(playerData.getPlayerUUID());
if (player != null) {
if (player.isConnected()) {
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID()),
new me.william278.husksync.redis.RedisMessage(me.william278.husksync.redis.RedisMessage.MessageType.PLAYER_DATA_SET,
new me.william278.husksync.redis.RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID()),
RedisMessage.serialize(playerData))
.send();
}

@ -7,10 +7,10 @@ data_storage_settings:
mysql_settings:
host: 'localhost'
port: 8123
database: 'CrossServerSync'
database: 'HuskSync'
username: 'root'
password: 'pa55w0rd'
params: ''
params: '?autoReconnect=true&useSSL=false'
hikari_pool_settings:
maximum_pool_size: 10
minimum_idle: 10

@ -26,5 +26,5 @@ shadowJar {
exclude "module-info.class"
// Relocations
relocate 'redis.clients', 'me.William278.crossserversync.libraries.jedis'
relocate 'redis.clients', 'me.William278.husksync.libraries.jedis'
}

@ -1,12 +1,12 @@
package me.william278.crossserversync;
package me.william278.husksync;
public class MessageStrings {
public static final StringBuilder PLUGIN_INFORMATION = new StringBuilder().append("[CrossServerSync](#00fb9a bold) [| %proxy_brand% Version %proxy_version% (%bukkit_brand% v%bukkit_version%)](#00fb9a)\n")
public static final StringBuilder PLUGIN_INFORMATION = new StringBuilder().append("[HuskSync](#00fb9a bold) [| %proxy_brand% Version %proxy_version% (%bukkit_brand% v%bukkit_version%)](#00fb9a)\n")
.append("[%plugin_description%](gray)\n")
.append("[• Author:](white) [William278](gray show_text=&7Click to pay a visit open_url=https://youtube.com/William27528)\n")
.append("[• Help Wiki:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/CrossServerSync/wiki/)\n")
.append("[• Report Issues:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/CrossServerSync/issues)\n")
.append("[• Help Wiki:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/wiki/)\n")
.append("[• Report Issues:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/issues)\n")
.append("[• Support Discord:](white) [[Link]](#00fb9a show_text=&7Click to join open_url=https://discord.gg/tVYhJfyDWG)");
public static final String ERROR_INVALID_SYNTAX = "[Error:](#ff3300) [Incorrect syntax. Usage: %1%](#ff7e5e)";

@ -1,4 +1,4 @@
package me.william278.crossserversync;
package me.william278.husksync;
import java.io.*;
import java.util.UUID;

@ -1,5 +1,8 @@
package me.william278.crossserversync;
package me.william278.husksync;
/**
* Settings class, holds values loaded from the plugin config (either Bukkit or Bungee)
*/
public class Settings {
/*

@ -1,6 +1,6 @@
package me.william278.crossserversync.redis;
package me.william278.husksync.redis;
import me.william278.crossserversync.Settings;
import me.william278.husksync.Settings;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
@ -37,7 +37,7 @@ public abstract class RedisListener {
new Thread(() -> jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// Only accept messages to the CrossServerSync channel
// Only accept messages to the HuskSync channel
if (!channel.equals(RedisMessage.REDIS_CHANNEL)) {
return;
}

@ -1,7 +1,7 @@
package me.william278.crossserversync.redis;
package me.william278.husksync.redis;
import me.william278.crossserversync.PlayerData;
import me.william278.crossserversync.Settings;
import me.william278.husksync.PlayerData;
import me.william278.husksync.Settings;
import redis.clients.jedis.Jedis;
import java.io.*;
@ -11,7 +11,7 @@ import java.util.UUID;
public class RedisMessage {
public static String REDIS_CHANNEL = "CrossServerSync";
public static String REDIS_CHANNEL = "HuskSync";
public static String MESSAGE_META_SEPARATOR = "♦";
public static String MESSAGE_DATA_SEPARATOR = "♣";

@ -1,6 +1,6 @@
name: CrossServerSync
name: HuskSync
version: @version@
main: me.william278.crossserversync.CrossServerSyncBungeeCord
main: me.william278.husksync.HuskSyncBungeeCord
author: William278
description: 'Synchronize data cross-server'
libraries:

@ -1,6 +1,6 @@
name: CrossServerSync
version: @version@
main: me.william278.crossserversync.CrossServerSyncBukkit
main: me.william278.husksync.HuskSyncBukkit
api-version: 1.16
author: William278
description: 'Synchronize data cross-server'

@ -6,7 +6,7 @@ dependencies {
shadowJar {
destinationDirectory.set(file("$rootDir/target/"))
archiveBaseName.set('CrossServerSync')
archiveBaseName.set('HuskSync')
archiveClassifier.set('')
build {
@ -18,7 +18,7 @@ publishing {
publications {
mavenJava(MavenPublication) {
groupId = 'me.William278'
artifactId = 'CrossServerSync-plugin'
artifactId = 'HuskSync-plugin'
version = "$project.version"
artifact shadowJar

@ -4,7 +4,7 @@ pluginManagement {
}
}
rootProject.name = 'CrossServerSync'
rootProject.name = 'HuskSync'
include 'common'
include 'bukkit'

Loading…
Cancel
Save