Remove proprietary code

feat/data-edit-commands
William 3 years ago
parent e35cebe0e4
commit 2a34c5baa7

@ -11,7 +11,7 @@ plugins {
allprojects {
group 'me.William278'
version '1.0.1'
version '1.0.2'
compileJava { options.encoding = 'UTF-8' }
tasks.withType(JavaCompile) { options.encoding = 'UTF-8' }

@ -1,277 +0,0 @@
package me.william278.husksync.bukkit.data;
import me.william278.husksync.redis.RedisMessage;
import org.bukkit.*;
import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
/**
* Class for serializing and deserializing player inventories and Ender Chests contents ({@link ItemStack[]}) as base64 strings.
* Based on https://gist.github.com/graywolf336/8153678 by graywolf336
* Modified for 1.16 via https://gist.github.com/graywolf336/8153678#gistcomment-3551376 by efindus
*
* @author efindus
* @author graywolf336
* @author William278
*/
public final class DataSerializer {
/**
* Converts the player inventory to a Base64 encoded string.
*
* @param inventory the inventory to convert to Base64.
* @return string with serialized Inventory
* @throws IllegalStateException in the event the item stacks cannot be saved
*/
public static String getSerializedInventoryContents(Inventory inventory) throws IllegalStateException {
// This contains contents, armor and offhand (contents are indexes 0 - 35, armor 36 - 39, offhand - 40)
return itemStackArrayToBase64(inventory.getContents());
}
/**
* Converts the player inventory to a Base64 encoded string.
*
* @param player whose Ender Chest will be turned into Base64.
* @return string with serialized Ender Chest
* @throws IllegalStateException in the event the item stacks cannot be saved
*/
public static String getSerializedEnderChestContents(Player player) throws IllegalStateException {
// This contains all slots (0-27) in the player's Ender Chest
return itemStackArrayToBase64(player.getEnderChest().getContents());
}
public static String getSerializedEffectData(Player player) {
PotionEffect[] potionEffects = new PotionEffect[player.getActivePotionEffects().size()];
int x = 0;
for (PotionEffect effect : player.getActivePotionEffects()) {
potionEffects[x] = effect;
x++;
}
return effectArrayToBase64(potionEffects);
}
public static String effectArrayToBase64(PotionEffect[] effects) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
dataOutput.writeInt(effects.length);
for (PotionEffect effect : effects) {
if (effect != null) {
dataOutput.writeObject(effect.serialize());
} else {
dataOutput.writeObject(null);
}
}
}
return Base64Coder.encodeLines(outputStream.toByteArray());
} catch (Exception e) {
throw new IllegalStateException("Unable to save potion effects.", e);
}
}
/**
* A method to serialize an {@link ItemStack} array to Base64 String.
*
* @param items to turn into a Base64 String.
* @return Base64 string of the items.
* @throws IllegalStateException in the event the item stacks cannot be saved
*/
public static String itemStackArrayToBase64(ItemStack[] items) throws IllegalStateException {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
dataOutput.writeInt(items.length);
for (ItemStack item : items) {
if (item != null) {
dataOutput.writeObject(item.serialize());
} else {
dataOutput.writeObject(null);
}
}
}
return Base64Coder.encodeLines(outputStream.toByteArray());
} catch (Exception e) {
throw new IllegalStateException("Unable to save item stacks.", e);
}
}
/**
* Gets an array of ItemStacks from a Base64 string.
*
* @param data Base64 string to convert to ItemStack array.
* @return ItemStack array created from the Base64 string.
* @throws IOException in the event the class type cannot be decoded
*/
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
public static ItemStack[] itemStackArrayFromBase64(String data) throws IOException {
// Return an empty ItemStack[] if the data is empty
if (data.isEmpty()) {
return new ItemStack[0];
}
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data))) {
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
ItemStack[] items = new ItemStack[dataInput.readInt()];
for (int Index = 0; Index < items.length; Index++) {
Map<String, Object> stack = (Map<String, Object>) dataInput.readObject();
if (stack != null) {
items[Index] = ItemStack.deserialize(stack);
} else {
items[Index] = null;
}
}
return items;
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
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++) {
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);
}
}
public static PlayerLocation deserializePlayerLocationData(String serializedLocationData) throws IOException {
if (serializedLocationData.isEmpty()) {
return null;
}
try {
return (PlayerLocation) me.william278.husksync.redis.RedisMessage.deserialize(serializedLocationData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
public static String getSerializedLocation(Player player) throws IOException {
final Location playerLocation = player.getLocation();
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()));
}
public record PlayerLocation(double x, double y, double z, float yaw, float pitch,
String worldName, World.Environment environment) implements Serializable {
}
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
public static ArrayList<AdvancementRecord> deserializeAdvancementData(String serializedAdvancementData) throws IOException {
if (serializedAdvancementData.isEmpty()) {
return new ArrayList<>();
}
try {
return (ArrayList<AdvancementRecord>) me.william278.husksync.redis.RedisMessage.deserialize(serializedAdvancementData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
public static String getSerializedAdvancements(Player player) throws IOException {
Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
ArrayList<AdvancementRecord> advancementData = new ArrayList<>();
while (serverAdvancements.hasNext()) {
final AdvancementProgress progress = player.getAdvancementProgress(serverAdvancements.next());
final NamespacedKey advancementKey = progress.getAdvancement().getKey();
final ArrayList<String> awardedCriteria = new ArrayList<>(progress.getAwardedCriteria());
advancementData.add(new AdvancementRecord(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria));
}
return me.william278.husksync.redis.RedisMessage.serialize(advancementData);
}
public record AdvancementRecord(String advancementKey,
ArrayList<String> awardedAdvancementCriteria) implements Serializable {
}
public static StatisticData deserializeStatisticData(String serializedStatisticData) throws IOException {
if (serializedStatisticData.isEmpty()) {
return new StatisticData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
}
try {
return (StatisticData) me.william278.husksync.redis.RedisMessage.deserialize(serializedStatisticData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
public static String getSerializedStatisticData(Player player) throws IOException {
HashMap<Statistic, Integer> untypedStatisticValues = new HashMap<>();
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues = new HashMap<>();
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues = new HashMap<>();
HashMap<Statistic, HashMap<EntityType, Integer>> entityStatisticValues = new HashMap<>();
for (Statistic statistic : Statistic.values()) {
switch (statistic.getType()) {
case ITEM -> {
HashMap<Material, Integer> itemValues = new HashMap<>();
for (Material itemMaterial : Arrays.stream(Material.values()).filter(Material::isItem).collect(Collectors.toList())) {
itemValues.put(itemMaterial, player.getStatistic(statistic, itemMaterial));
}
itemStatisticValues.put(statistic, itemValues);
}
case BLOCK -> {
HashMap<Material, Integer> blockValues = new HashMap<>();
for (Material blockMaterial : Arrays.stream(Material.values()).filter(Material::isBlock).collect(Collectors.toList())) {
blockValues.put(blockMaterial, player.getStatistic(statistic, blockMaterial));
}
blockStatisticValues.put(statistic, blockValues);
}
case ENTITY -> {
HashMap<EntityType, Integer> entityValues = new HashMap<>();
for (EntityType type : Arrays.stream(EntityType.values()).filter(EntityType::isAlive).collect(Collectors.toList())) {
entityValues.put(type, player.getStatistic(statistic, type));
}
entityStatisticValues.put(statistic, entityValues);
}
case UNTYPED -> untypedStatisticValues.put(statistic, player.getStatistic(statistic));
}
}
StatisticData statisticData = new StatisticData(untypedStatisticValues, blockStatisticValues, itemStatisticValues, entityStatisticValues);
return RedisMessage.serialize(statisticData);
}
public record StatisticData(HashMap<Statistic, Integer> untypedStatisticValues,
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues,
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues,
HashMap<Statistic, HashMap<EntityType, Integer>> entityStatisticValues) implements Serializable {
}
}

@ -24,7 +24,7 @@ public class DataViewer {
* @param data The {@link DataView} to show the viewer
* @throws IOException If an exception occurred deserializing item data
*/
public static void showData(Player viewer, DataView data) throws IOException {
public static void showData(Player viewer, DataView data) throws IOException, ClassNotFoundException {
// Show an inventory with the viewer's inventory and equipment
viewer.closeInventory();
viewer.openInventory(createInventory(viewer, data));
@ -49,7 +49,7 @@ public class DataViewer {
// Get and update the PlayerData with the new item data
PlayerData playerData = dataView.playerData();
String serializedItemData = DataSerializer.itemStackArrayToBase64(inventory.getContents());
String serializedItemData = PlayerSerializer.serializeInventory(inventory.getContents());
switch (dataView.inventoryType()) {
case INVENTORY -> playerData.setSerializedInventory(serializedItemData);
case ENDER_CHEST -> playerData.setSerializedEnderChest(serializedItemData);
@ -70,7 +70,7 @@ public class DataViewer {
* @return The {@link Inventory} that the viewer will see
* @throws IOException If an exception occurred deserializing item data
*/
private static Inventory createInventory(Player viewer, DataView data) throws IOException {
private static Inventory createInventory(Player viewer, DataView data) throws IOException, ClassNotFoundException {
Inventory inventory = switch (data.inventoryType) {
case INVENTORY -> Bukkit.createInventory(viewer, 45, data.ownerName + "'s Inventory");
case ENDER_CHEST -> Bukkit.createInventory(viewer, 27, data.ownerName + "'s Ender Chest");
@ -104,10 +104,10 @@ public class DataViewer {
* @return The deserialized item data, as an {@link ItemStack[]} array
* @throws IOException If an exception occurred deserializing item data
*/
public ItemStack[] getDeserializedData() throws IOException {
public ItemStack[] getDeserializedData() throws IOException, ClassNotFoundException {
return switch (inventoryType) {
case INVENTORY -> DataSerializer.itemStackArrayFromBase64(playerData.getSerializedInventory());
case ENDER_CHEST -> DataSerializer.itemStackArrayFromBase64(playerData.getSerializedEnderChest());
case INVENTORY -> PlayerSerializer.deserializeInventory(playerData.getSerializedInventory());
case ENDER_CHEST -> PlayerSerializer.deserializeInventory(playerData.getSerializedEnderChest());
};
}
}

@ -0,0 +1,288 @@
package me.william278.husksync.bukkit.data;
import me.william278.husksync.redis.RedisMessage;
import org.bukkit.*;
import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
public class PlayerSerializer {
/**
* Returns a serialized array of {@link ItemStack}s
*
* @param inventoryContents The contents of the inventory
* @return The serialized inventory contents
*/
public static String serializeInventory(ItemStack[] inventoryContents) {
// Create an output stream that will be encoded into base 64
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
try (BukkitObjectOutputStream bukkitOutputStream = new BukkitObjectOutputStream(byteOutputStream)) {
// Define the length of the inventory array to serialize
bukkitOutputStream.writeInt(inventoryContents.length);
// Write each serialize each ItemStack to the output stream
for (ItemStack inventoryItem : inventoryContents) {
bukkitOutputStream.writeObject(serializeItemStack(inventoryItem));
}
// Return encoded data, using the encoder from SnakeYaml to get a ByteArray conversion
return Base64Coder.encodeLines(byteOutputStream.toByteArray());
} catch (IOException e) {
throw new IllegalArgumentException("Failed to serialize item stack data");
}
}
/**
* Returns an array of ItemStacks from serialized inventory data
*
* @param inventoryData The serialized {@link ItemStack[]} array
* @return The inventory contents as an array of {@link ItemStack}s
* @throws IOException If the deserialization fails reading data from the InputStream
* @throws ClassNotFoundException If the deserialization class cannot be found
*/
public static ItemStack[] deserializeInventory(String inventoryData) throws IOException, ClassNotFoundException {
// Return empty array if there is no inventory data (set the player as having an empty inventory)
if (inventoryData.isEmpty()) {
return new ItemStack[0];
}
// Create a byte input stream to read the serialized data
try (ByteArrayInputStream byteInputStream = new ByteArrayInputStream(Base64Coder.decodeLines(inventoryData))) {
try (BukkitObjectInputStream bukkitInputStream = new BukkitObjectInputStream(byteInputStream)) {
// Read the length of the Bukkit input stream and set the length of the array to this value
ItemStack[] inventoryContents = new ItemStack[bukkitInputStream.readInt()];
// Set the ItemStacks in the array from deserialized ItemStack data
int slotIndex = 0;
for (ItemStack ignored : inventoryContents) {
inventoryContents[slotIndex] = deserializeItemStack(bukkitInputStream.readObject());
slotIndex++;
}
// Return the finished, serialized inventory contents
return inventoryContents;
}
}
}
/**
* Returns the serialized version of an {@link ItemStack} as a string to object Map
*
* @param item The {@link ItemStack} to serialize
* @return The serialized {@link ItemStack}
*/
private static Map<String, Object> serializeItemStack(ItemStack item) {
return item != null ? item.serialize() : null;
}
/**
* Returns the deserialized {@link ItemStack} from the Object read from the {@link BukkitObjectInputStream}
*
* @param serializedItemStack The serialized item stack; a String-Object map
* @return The deserialized {@link ItemStack}
*/
@SuppressWarnings("unchecked") // Ignore the "Unchecked cast" warning
private static ItemStack deserializeItemStack(Object serializedItemStack) {
return serializedItemStack != null ? ItemStack.deserialize((Map<String, Object>) serializedItemStack) : null;
}
/**
* Returns a serialized array of {@link PotionEffect}s
*
* @param potionEffects The potion effect array
* @return The serialized potion effects
*/
public static String serializePotionEffects(PotionEffect[] potionEffects) {
// Create an output stream that will be encoded into base 64
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
try (BukkitObjectOutputStream bukkitOutputStream = new BukkitObjectOutputStream(byteOutputStream)) {
// Define the length of the potion effect array to serialize
bukkitOutputStream.writeInt(potionEffects.length);
// Write each serialize each PotionEffect to the output stream
for (PotionEffect potionEffect : potionEffects) {
bukkitOutputStream.writeObject(serializePotionEffect(potionEffect));
}
// Return encoded data, using the encoder from SnakeYaml to get a ByteArray conversion
return Base64Coder.encodeLines(byteOutputStream.toByteArray());
} catch (IOException e) {
throw new IllegalArgumentException("Failed to serialize potion effect data");
}
}
/**
* Returns an array of ItemStacks from serialized potion effect data
*
* @param potionEffectData The serialized {@link PotionEffect[]} array
* @return The {@link PotionEffect}s
* @throws IOException If the deserialization fails reading data from the InputStream
* @throws ClassNotFoundException If the deserialization class cannot be found
*/
public static PotionEffect[] deserializePotionEffects(String potionEffectData) throws IOException, ClassNotFoundException {
// Return empty array if there is no potion effect data (don't apply any effects to the player)
if (potionEffectData.isEmpty()) {
return new PotionEffect[0];
}
// Create a byte input stream to read the serialized data
try (ByteArrayInputStream byteInputStream = new ByteArrayInputStream(Base64Coder.decodeLines(potionEffectData))) {
try (BukkitObjectInputStream bukkitInputStream = new BukkitObjectInputStream(byteInputStream)) {
// Read the length of the Bukkit input stream and set the length of the array to this value
PotionEffect[] potionEffects = new PotionEffect[bukkitInputStream.readInt()];
// Set the potion effects in the array from deserialized PotionEffect data
int potionIndex = 0;
for (PotionEffect ignored : potionEffects) {
potionEffects[potionIndex] = deserializePotionEffect(bukkitInputStream.readObject());
potionIndex++;
}
// Return the finished, serialized potion effect array
return potionEffects;
}
}
}
/**
* Returns the serialized version of an {@link ItemStack} as a string to object Map
*
* @param potionEffect The {@link ItemStack} to serialize
* @return The serialized {@link ItemStack}
*/
private static Map<String, Object> serializePotionEffect(PotionEffect potionEffect) {
return potionEffect != null ? potionEffect.serialize() : null;
}
/**
* Returns the deserialized {@link PotionEffect} from the Object read from the {@link BukkitObjectInputStream}
*
* @param serializedPotionEffect The serialized potion effect; a String-Object map
* @return The deserialized {@link PotionEffect}
*/
@SuppressWarnings("unchecked") // Ignore the "Unchecked cast" warning
private static PotionEffect deserializePotionEffect(Object serializedPotionEffect) {
return serializedPotionEffect != null ? new PotionEffect((Map<String, Object>) serializedPotionEffect) : null;
}
public static PlayerSerializer.PlayerLocation deserializePlayerLocationData(String serializedLocationData) throws IOException {
if (serializedLocationData.isEmpty()) {
return null;
}
try {
return (PlayerSerializer.PlayerLocation) RedisMessage.deserialize(serializedLocationData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
public static String getSerializedLocation(Player player) throws IOException {
final Location playerLocation = player.getLocation();
return RedisMessage.serialize(new PlayerSerializer.PlayerLocation(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ(),
playerLocation.getYaw(), playerLocation.getPitch(), player.getWorld().getName(), player.getWorld().getEnvironment()));
}
public record PlayerLocation(double x, double y, double z, float yaw, float pitch,
String worldName, World.Environment environment) implements Serializable {
}
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
public static ArrayList<PlayerSerializer.AdvancementRecord> deserializeAdvancementData(String serializedAdvancementData) throws IOException {
if (serializedAdvancementData.isEmpty()) {
return new ArrayList<>();
}
try {
return (ArrayList<PlayerSerializer.AdvancementRecord>) RedisMessage.deserialize(serializedAdvancementData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
public static String getSerializedAdvancements(Player player) throws IOException {
Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
ArrayList<PlayerSerializer.AdvancementRecord> advancementData = new ArrayList<>();
while (serverAdvancements.hasNext()) {
final AdvancementProgress progress = player.getAdvancementProgress(serverAdvancements.next());
final NamespacedKey advancementKey = progress.getAdvancement().getKey();
final ArrayList<String> awardedCriteria = new ArrayList<>(progress.getAwardedCriteria());
advancementData.add(new PlayerSerializer.AdvancementRecord(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria));
}
return RedisMessage.serialize(advancementData);
}
public record AdvancementRecord(String advancementKey,
ArrayList<String> awardedAdvancementCriteria) implements Serializable {
}
public static PlayerSerializer.StatisticData deserializeStatisticData(String serializedStatisticData) throws IOException {
if (serializedStatisticData.isEmpty()) {
return new PlayerSerializer.StatisticData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
}
try {
return (PlayerSerializer.StatisticData) RedisMessage.deserialize(serializedStatisticData);
} catch (ClassNotFoundException e) {
throw new IOException("Unable to decode class type.", e);
}
}
public static String getSerializedStatisticData(Player player) throws IOException {
HashMap<Statistic, Integer> untypedStatisticValues = new HashMap<>();
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues = new HashMap<>();
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues = new HashMap<>();
HashMap<Statistic, HashMap<EntityType, Integer>> entityStatisticValues = new HashMap<>();
for (Statistic statistic : Statistic.values()) {
switch (statistic.getType()) {
case ITEM -> {
HashMap<Material, Integer> itemValues = new HashMap<>();
for (Material itemMaterial : Arrays.stream(Material.values()).filter(Material::isItem).collect(Collectors.toList())) {
itemValues.put(itemMaterial, player.getStatistic(statistic, itemMaterial));
}
itemStatisticValues.put(statistic, itemValues);
}
case BLOCK -> {
HashMap<Material, Integer> blockValues = new HashMap<>();
for (Material blockMaterial : Arrays.stream(Material.values()).filter(Material::isBlock).collect(Collectors.toList())) {
blockValues.put(blockMaterial, player.getStatistic(statistic, blockMaterial));
}
blockStatisticValues.put(statistic, blockValues);
}
case ENTITY -> {
HashMap<EntityType, Integer> entityValues = new HashMap<>();
for (EntityType type : Arrays.stream(EntityType.values()).filter(EntityType::isAlive).collect(Collectors.toList())) {
entityValues.put(type, player.getStatistic(statistic, type));
}
entityStatisticValues.put(statistic, entityValues);
}
case UNTYPED -> untypedStatisticValues.put(statistic, player.getStatistic(statistic));
}
}
PlayerSerializer.StatisticData statisticData = new PlayerSerializer.StatisticData(untypedStatisticValues, blockStatisticValues, itemStatisticValues, entityStatisticValues);
return RedisMessage.serialize(statisticData);
}
public record StatisticData(HashMap<Statistic, Integer> untypedStatisticValues,
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues,
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues,
HashMap<Statistic, HashMap<EntityType, Integer>> entityStatisticValues) implements Serializable {
}
}

@ -3,7 +3,7 @@ package me.william278.husksync.bukkit.migrator;
import me.william278.husksync.HuskSyncBukkit;
import me.william278.husksync.PlayerData;
import me.william278.husksync.bukkit.util.PlayerSetter;
import me.william278.husksync.bukkit.data.DataSerializer;
import me.william278.husksync.bukkit.data.PlayerSerializer;
import me.william278.husksync.migrator.MPDBPlayerData;
import net.craftersland.data.bridge.PD;
import org.bukkit.Bukkit;
@ -61,7 +61,7 @@ public class MPDBDeserializer {
}
// Now apply the contents and clear the temporary inventory variable
playerData.setSerializedInventory(DataSerializer.getSerializedInventoryContents(inventory));
playerData.setSerializedInventory(PlayerSerializer.serializeInventory(inventory.getContents()));
// Set ender chest (again, if there is data)
ItemStack[] enderChestData;
@ -70,7 +70,7 @@ public class MPDBDeserializer {
} else {
enderChestData = new ItemStack[0];
}
playerData.setSerializedEnderChest(DataSerializer.itemStackArrayToBase64(enderChestData));
playerData.setSerializedEnderChest(PlayerSerializer.serializeInventory(enderChestData));
// Set experience
playerData.setExpLevel(mpdbPlayerData.expLevel);

@ -5,7 +5,7 @@ import me.william278.husksync.PlayerData;
import me.william278.husksync.Settings;
import me.william278.husksync.api.events.SyncCompleteEvent;
import me.william278.husksync.api.events.SyncEvent;
import me.william278.husksync.bukkit.data.DataSerializer;
import me.william278.husksync.bukkit.data.PlayerSerializer;
import me.william278.husksync.redis.RedisMessage;
import org.bukkit.*;
import org.bukkit.advancement.Advancement;
@ -37,8 +37,8 @@ public class PlayerSetter {
*/
private static String getNewSerializedPlayerData(Player player) throws IOException {
return RedisMessage.serialize(new PlayerData(player.getUniqueId(),
DataSerializer.getSerializedInventoryContents(player.getInventory()),
DataSerializer.getSerializedEnderChestContents(player),
PlayerSerializer.serializeInventory(player.getInventory().getContents()),
PlayerSerializer.serializeInventory(player.getEnderChest().getContents()),
player.getHealth(),
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).getBaseValue(),
player.getHealthScale(),
@ -46,15 +46,31 @@ public class PlayerSetter {
player.getSaturation(),
player.getExhaustion(),
player.getInventory().getHeldItemSlot(),
DataSerializer.getSerializedEffectData(player),
PlayerSerializer.serializePotionEffects(getPlayerPotionEffects(player)),
player.getTotalExperience(),
player.getLevel(),
player.getExp(),
player.getGameMode().toString(),
DataSerializer.getSerializedStatisticData(player),
PlayerSerializer.getSerializedStatisticData(player),
player.isFlying(),
DataSerializer.getSerializedAdvancements(player),
DataSerializer.getSerializedLocation(player)));
PlayerSerializer.getSerializedAdvancements(player),
PlayerSerializer.getSerializedLocation(player)));
}
/**
* Returns a {@link Player}'s active potion effects in a {@link PotionEffect} array
*
* @param player The {@link Player} to get the effects of
* @return The {@link PotionEffect} array
*/
private static PotionEffect[] getPlayerPotionEffects(Player player) {
PotionEffect[] potionEffects = new PotionEffect[player.getActivePotionEffects().size()];
int arrayIndex = 0;
for (PotionEffect effect : player.getActivePotionEffects()) {
potionEffects[arrayIndex] = effect;
arrayIndex++;
}
return potionEffects;
}
/**
@ -123,14 +139,14 @@ public class PlayerSetter {
// Set the player's data from the PlayerData
try {
if (Settings.syncAdvancements) {
setPlayerAdvancements(player, DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements()), data);
setPlayerAdvancements(player, PlayerSerializer.deserializeAdvancementData(data.getSerializedAdvancements()), data);
}
if (Settings.syncInventories) {
setPlayerInventory(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedInventory()));
setPlayerInventory(player, PlayerSerializer.deserializeInventory(data.getSerializedInventory()));
player.getInventory().setHeldItemSlot(data.getSelectedSlot());
}
if (Settings.syncEnderChests) {
setPlayerEnderChest(player, DataSerializer.itemStackArrayFromBase64(data.getSerializedEnderChest()));
setPlayerEnderChest(player, PlayerSerializer.deserializeInventory(data.getSerializedEnderChest()));
}
if (Settings.syncHealth) {
player.setHealthScale(data.getHealthScale() <= 0 ? data.getHealthScale() : 20D);
@ -147,22 +163,22 @@ public class PlayerSetter {
setPlayerExperience(player, data);
}
if (Settings.syncPotionEffects) {
setPlayerPotionEffects(player, DataSerializer.potionEffectArrayFromBase64(data.getSerializedEffectData()));
setPlayerPotionEffects(player, PlayerSerializer.deserializePotionEffects(data.getSerializedEffectData()));
}
if (Settings.syncStatistics) {
setPlayerStatistics(player, DataSerializer.deserializeStatisticData(data.getSerializedStatistics()));
setPlayerStatistics(player, PlayerSerializer.deserializeStatisticData(data.getSerializedStatistics()));
}
if (Settings.syncGameMode) {
player.setGameMode(GameMode.valueOf(data.getGameMode()));
}
if (Settings.syncLocation) {
player.setFlying(player.getAllowFlight() && data.isFlying());
setPlayerLocation(player, DataSerializer.deserializePlayerLocationData(data.getSerializedLocation()));
setPlayerLocation(player, PlayerSerializer.deserializePlayerLocationData(data.getSerializedLocation()));
}
// Handle the SyncCompleteEvent
Bukkit.getPluginManager().callEvent(new SyncCompleteEvent(player, data));
} catch (IOException e) {
} catch (IOException | ClassNotFoundException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to deserialize PlayerData", e);
}
});
@ -224,9 +240,9 @@ public class PlayerSetter {
* Update a player's advancements and progress to match the advancementData
*
* @param player The player to set the advancements of
* @param advancementData The ArrayList of {@link DataSerializer.AdvancementRecord}s to set
* @param advancementData The ArrayList of {@link PlayerSerializer.AdvancementRecord}s to set
*/
private static void setPlayerAdvancements(Player player, ArrayList<DataSerializer.AdvancementRecord> advancementData, PlayerData data) {
private static void setPlayerAdvancements(Player player, ArrayList<PlayerSerializer.AdvancementRecord> advancementData, PlayerData data) {
// Temporarily disable advancement announcing if needed
boolean announceAdvancementUpdate = false;
if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) {
@ -244,7 +260,7 @@ public class PlayerSetter {
boolean correctExperienceCheck = false; // Determines whether the experience might have changed warranting an update
Advancement advancement = serverAdvancements.next();
AdvancementProgress playerProgress = player.getAdvancementProgress(advancement);
for (DataSerializer.AdvancementRecord record : advancementData) {
for (PlayerSerializer.AdvancementRecord record : advancementData) {
// If the advancement is one on the data
if (record.advancementKey().equals(advancement.getKey().getNamespace() + ":" + advancement.getKey().getKey())) {
@ -287,9 +303,9 @@ public class PlayerSetter {
* Set a player's statistics (in the Statistic menu)
*
* @param player The player to set the statistics of
* @param statisticData The {@link DataSerializer.StatisticData} to set
* @param statisticData The {@link PlayerSerializer.StatisticData} to set
*/
private static void setPlayerStatistics(Player player, DataSerializer.StatisticData statisticData) {
private static void setPlayerStatistics(Player player, PlayerSerializer.StatisticData statisticData) {
// Set untyped statistics
for (Statistic statistic : statisticData.untypedStatisticValues().keySet()) {
player.setStatistic(statistic, statisticData.untypedStatisticValues().get(statistic));
@ -330,12 +346,12 @@ public class PlayerSetter {
}
/**
* Set a player's location from {@link DataSerializer.PlayerLocation} data
* Set a player's location from {@link PlayerSerializer.PlayerLocation} data
*
* @param player The {@link Player} to teleport
* @param location The {@link DataSerializer.PlayerLocation}
* @param location The {@link PlayerSerializer.PlayerLocation}
*/
private static void setPlayerLocation(Player player, DataSerializer.PlayerLocation location) {
private static void setPlayerLocation(Player player, PlayerSerializer.PlayerLocation location) {
// Don't teleport if the location is invalid
if (location == null) {
return;

@ -3,6 +3,7 @@ package me.william278.husksync.redis;
import me.william278.husksync.Settings;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.exceptions.JedisException;
import java.io.IOException;
import java.util.logging.Level;
@ -31,34 +32,37 @@ public abstract class RedisListener {
* Start the Redis listener
*/
public final void listen() {
Jedis jedis = new Jedis(Settings.redisHost, Settings.redisPort);
final String jedisPassword = Settings.redisPassword;
if (!jedisPassword.equals("")) {
jedis.auth(jedisPassword);
}
jedis.connect();
if (jedis.isConnected()) {
isActiveAndEnabled = true;
log(Level.INFO,"Enabled Redis listener successfully!");
new Thread(() -> jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// Only accept messages to the HuskSync channel
if (!channel.equals(RedisMessage.REDIS_CHANNEL)) {
return;
}
try(Jedis jedis = new Jedis(Settings.redisHost, Settings.redisPort)) {
final String jedisPassword = Settings.redisPassword;
if (!jedisPassword.equals("")) {
jedis.auth(jedisPassword);
}
jedis.connect();
if (jedis.isConnected()) {
isActiveAndEnabled = true;
log(Level.INFO,"Enabled Redis listener successfully!");
new Thread(() -> jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// Only accept messages to the HuskSync channel
if (!channel.equals(RedisMessage.REDIS_CHANNEL)) {
return;
}
// Handle the message
try {
handleMessage(new RedisMessage(message));
} catch (IOException | ClassNotFoundException e) {
log(Level.SEVERE, "Failed to deserialize message target");
// Handle the 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 {
isActiveAndEnabled = false;
log(Level.SEVERE, "Failed to initialize the redis listener!");
}, RedisMessage.REDIS_CHANNEL), "Redis Subscriber").start();
} else {
isActiveAndEnabled = false;
log(Level.SEVERE, "Failed to initialize the redis listener!");
}
} catch (JedisException e) {
log(Level.SEVERE, "Failed to establish a connection to the Redis server!");
}
}
}

Loading…
Cancel
Save