mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-26 10:09:10 +00:00
Finish initial implementation of plan
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package me.william278.crossserversync;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.*;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerData implements Serializable {
|
||||
@@ -25,13 +25,13 @@ public class PlayerData implements Serializable {
|
||||
*/
|
||||
private final String serializedEnderChest;
|
||||
|
||||
//todo add more stuff, like ender chest, player health, max health, hunger and status effects, et cetera
|
||||
|
||||
/**
|
||||
* Create a new PlayerData object; a random data version UUID will be selected.
|
||||
* @param playerUUID The UUID of the player
|
||||
*
|
||||
* @param playerUUID The UUID of the player
|
||||
* @param serializedInventory The player's serialized inventory data
|
||||
*/
|
||||
//todo add more stuff, like player health, max health, hunger, saturation and status effects
|
||||
public PlayerData(UUID playerUUID, String serializedInventory, String serializedEnderChest) {
|
||||
this.dataVersionUUID = UUID.randomUUID();
|
||||
this.playerUUID = playerUUID;
|
||||
@@ -39,6 +39,19 @@ public class PlayerData implements Serializable {
|
||||
this.serializedEnderChest = serializedEnderChest;
|
||||
}
|
||||
|
||||
public PlayerData(UUID playerUUID, UUID dataVersionUUID, String serializedInventory, String serializedEnderChest, double health, double maxHealth, double hunger, double saturation, String serializedStatusEffects) {
|
||||
this.playerUUID = playerUUID;
|
||||
this.dataVersionUUID = dataVersionUUID;
|
||||
this.serializedInventory = serializedInventory;
|
||||
this.serializedEnderChest = serializedEnderChest;
|
||||
|
||||
//todo Incorporate more of these
|
||||
}
|
||||
|
||||
public static PlayerData EMPTY_PLAYER_DATA(UUID playerUUID) {
|
||||
return new PlayerData(playerUUID, "", "");
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import me.william278.crossserversync.Settings;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPubSub;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class RedisListener {
|
||||
@@ -42,7 +43,11 @@ public abstract class RedisListener {
|
||||
}
|
||||
|
||||
// Handle the message
|
||||
handleMessage(new RedisMessage(message));
|
||||
try {
|
||||
handleMessage(new RedisMessage(message));
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log(Level.SEVERE, "Failed to deserialize message target");
|
||||
}
|
||||
}
|
||||
}, RedisMessage.REDIS_CHANNEL), "Redis Subscriber").start();
|
||||
} else {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package me.william278.crossserversync.redis;
|
||||
|
||||
import me.william278.crossserversync.PlayerData;
|
||||
import me.william278.crossserversync.Settings;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.*;
|
||||
import java.util.Base64;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -41,32 +40,27 @@ public class RedisMessage {
|
||||
* Get a new RedisMessage from an incoming message string
|
||||
* @param messageString The message string to parse
|
||||
*/
|
||||
public RedisMessage(String messageString) {
|
||||
public RedisMessage(String messageString) throws IOException, ClassNotFoundException {
|
||||
String[] messageMetaElements = messageString.split(MESSAGE_META_SEPARATOR);
|
||||
messageType = MessageType.valueOf(messageMetaElements[0]);
|
||||
messageTarget = (MessageTarget) RedisMessage.deserialize(messageMetaElements[1]);
|
||||
messageData = messageMetaElements[2];
|
||||
|
||||
try (ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(messageMetaElements[1].getBytes()))) {
|
||||
messageTarget = (MessageTarget) stream.readObject();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full, formatted message string with type, target & data
|
||||
* @return The fully formatted message
|
||||
*/
|
||||
private String getFullMessage() {
|
||||
private String getFullMessage() throws IOException {
|
||||
return new StringJoiner(MESSAGE_META_SEPARATOR)
|
||||
.add(messageType.toString()).add(messageTarget.toString()).add(messageData)
|
||||
.add(messageType.toString()).add(RedisMessage.serialize(messageTarget)).add(messageData)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the redis message
|
||||
*/
|
||||
public void send() {
|
||||
public void send() throws IOException {
|
||||
try (Jedis publisher = new Jedis(Settings.redisHost, Settings.redisPort)) {
|
||||
final String jedisPassword = Settings.redisPassword;
|
||||
if (!jedisPassword.equals("")) {
|
||||
@@ -77,6 +71,10 @@ public class RedisMessage {
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getMessageDataSeparated() {
|
||||
return messageData.split(MESSAGE_DATA_SEPARATOR);
|
||||
}
|
||||
|
||||
public String getMessageData() {
|
||||
return messageData;
|
||||
}
|
||||
@@ -94,17 +92,17 @@ public class RedisMessage {
|
||||
*/
|
||||
public enum MessageType {
|
||||
/**
|
||||
* Sent by Bukkit servers to proxy when a player disconnects with a player's updated data, alongside the UUID of the last loaded {@link me.william278.crossserversync.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
|
||||
*/
|
||||
PLAYER_DATA_UPDATE,
|
||||
|
||||
/**
|
||||
* Sent by Bukkit servers to proxy to request {@link me.william278.crossserversync.PlayerData} from the proxy.
|
||||
* Sent by Bukkit servers to proxy to request {@link PlayerData} from the proxy.
|
||||
*/
|
||||
PLAYER_DATA_REQUEST,
|
||||
|
||||
/**
|
||||
* Sent by the Proxy to reply to a {@code MessageType.PLAYER_DATA_REQUEST}, contains the latest {@link me.william278.crossserversync.PlayerData} for the requester.
|
||||
* Sent by the Proxy to reply to a {@code MessageType.PLAYER_DATA_REQUEST}, contains the latest {@link PlayerData} for the requester.
|
||||
*/
|
||||
PLAYER_DATA_REPLY
|
||||
}
|
||||
@@ -114,4 +112,25 @@ public class RedisMessage {
|
||||
* For Bukkit servers, the name of the server must also be specified
|
||||
*/
|
||||
public record MessageTarget(Settings.ServerType targetServerType, UUID targetPlayerName) implements Serializable { }
|
||||
|
||||
/**
|
||||
* Deserialize an object from a Base64 string
|
||||
*/
|
||||
public static Object deserialize(String s) throws IOException, ClassNotFoundException {
|
||||
byte[] data = Base64.getDecoder().decode(s);
|
||||
try (ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data))) {
|
||||
return objectInputStream.readObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize an object to a Base64 string
|
||||
*/
|
||||
public static String serialize(Serializable o) throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
|
||||
objectOutputStream.writeObject(o);
|
||||
}
|
||||
return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user