mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-29 19:49:13 +00:00
feat: Minecraft 1.20.5/6 support (#295)
* feat: start 1.20.5 update testing nbt-api seems to work great already :) * feat: add DFU support for legacy upgrade Adds an optional overload to `deserialize` to support passing the MC Version of the snapshot data * refactor: `clone` ItemStack[] bukkit data arrays, close #294 Don't perform async operations on mutable player data
This commit is contained in:
@@ -66,7 +66,8 @@ public abstract class BukkitData implements Data {
|
||||
private final @Nullable ItemStack @NotNull [] contents;
|
||||
|
||||
private Items(@Nullable ItemStack @NotNull [] contents) {
|
||||
this.contents = Arrays.stream(contents)
|
||||
|
||||
this.contents = Arrays.stream(contents.clone())
|
||||
.map(i -> i == null || i.getType() == Material.AIR ? null : i)
|
||||
.toArray(ItemStack[]::new);
|
||||
}
|
||||
@@ -128,13 +129,13 @@ public abstract class BukkitData implements Data {
|
||||
@Range(from = 0, to = 8)
|
||||
private int heldItemSlot;
|
||||
|
||||
private Inventory(@NotNull ItemStack[] contents, int heldItemSlot) {
|
||||
private Inventory(@Nullable ItemStack @NotNull [] contents, int heldItemSlot) {
|
||||
super(contents);
|
||||
this.heldItemSlot = heldItemSlot;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BukkitData.Items.Inventory from(@NotNull ItemStack[] contents, int heldItemSlot) {
|
||||
public static BukkitData.Items.Inventory from(@Nullable ItemStack @NotNull [] contents, int heldItemSlot) {
|
||||
return new BukkitData.Items.Inventory(contents, heldItemSlot);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,16 +21,22 @@ package net.william278.husksync.data;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.utils.DataFixerUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.william278.desertwell.util.Version;
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.adapter.Adaptable;
|
||||
import net.william278.husksync.api.HuskSyncAPI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -52,7 +58,8 @@ public class BukkitSerializer {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public static class Inventory extends BukkitSerializer implements Serializer<BukkitData.Items.Inventory> {
|
||||
public static class Inventory extends BukkitSerializer implements Serializer<BukkitData.Items.Inventory>,
|
||||
ItemDeserializer {
|
||||
private static final String ITEMS_TAG = "items";
|
||||
private static final String HELD_ITEM_SLOT_TAG = "held_item_slot";
|
||||
|
||||
@@ -61,16 +68,21 @@ public class BukkitSerializer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitData.Items.Inventory deserialize(@NotNull String serialized) throws DeserializationException {
|
||||
public BukkitData.Items.Inventory deserialize(@NotNull String serialized, @NotNull Version dataMcVersion)
|
||||
throws DeserializationException {
|
||||
final ReadWriteNBT root = NBT.parseNBT(serialized);
|
||||
final ItemStack[] items = root.getItemStackArray(ITEMS_TAG);
|
||||
final int heldItemSlot = root.getInteger(HELD_ITEM_SLOT_TAG);
|
||||
final ReadWriteNBT items = root.hasTag(ITEMS_TAG) ? root.getCompound(ITEMS_TAG) : null;
|
||||
return BukkitData.Items.Inventory.from(
|
||||
items == null ? new ItemStack[INVENTORY_SLOT_COUNT] : items,
|
||||
heldItemSlot
|
||||
items != null ? getItems(items, dataMcVersion) : new ItemStack[INVENTORY_SLOT_COUNT],
|
||||
root.getInteger(HELD_ITEM_SLOT_TAG)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitData.Items.Inventory deserialize(@NotNull String serialized) {
|
||||
return deserialize(serialized, plugin.getMinecraftVersion());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String serialize(@NotNull BukkitData.Items.Inventory data) throws SerializationException {
|
||||
@@ -82,18 +94,25 @@ public class BukkitSerializer {
|
||||
|
||||
}
|
||||
|
||||
public static class EnderChest extends BukkitSerializer implements Serializer<BukkitData.Items.EnderChest> {
|
||||
public static class EnderChest extends BukkitSerializer implements Serializer<BukkitData.Items.EnderChest>,
|
||||
ItemDeserializer {
|
||||
|
||||
public EnderChest(@NotNull HuskSync plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitData.Items.EnderChest deserialize(@NotNull String serialized) throws DeserializationException {
|
||||
final ItemStack[] items = NBT.itemStackArrayFromNBT(NBT.parseNBT(serialized));
|
||||
public BukkitData.Items.EnderChest deserialize(@NotNull String serialized, @NotNull Version dataMcVersion)
|
||||
throws DeserializationException {
|
||||
final ItemStack[] items = getItems(NBT.parseNBT(serialized), dataMcVersion);
|
||||
return items == null ? BukkitData.Items.EnderChest.empty() : BukkitData.Items.EnderChest.adapt(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitData.Items.EnderChest deserialize(@NotNull String serialized) {
|
||||
return deserialize(serialized, plugin.getMinecraftVersion());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String serialize(@NotNull BukkitData.Items.EnderChest data) throws SerializationException {
|
||||
@@ -101,6 +120,57 @@ public class BukkitSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
// Utility interface for deserializing and upgrading item stacks from legacy versions
|
||||
private interface ItemDeserializer {
|
||||
|
||||
@Nullable
|
||||
default ItemStack[] getItems(@NotNull ReadWriteNBT tag, @NotNull Version mcVersion) {
|
||||
if (mcVersion.compareTo(getPlugin().getMinecraftVersion()) < 0) {
|
||||
return upgradeItemStack((NBTCompound) tag, mcVersion);
|
||||
}
|
||||
return NBT.itemStackArrayFromNBT(tag);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ItemStack @NotNull [] upgradeItemStack(@NotNull NBTCompound compound, @NotNull Version mcVersion) {
|
||||
final ReadWriteNBTCompoundList items = compound.getCompoundList("items");
|
||||
final ItemStack[] itemStacks = new ItemStack[compound.getInteger("size")];
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
if (items.get(i) == null) {
|
||||
itemStacks[i] = new ItemStack(Material.AIR);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
itemStacks[i] = NBT.itemStackFromNBT(upgradeItemData(items.get(i), mcVersion));
|
||||
} catch (Throwable e) {
|
||||
itemStacks[i] = new ItemStack(Material.AIR);
|
||||
}
|
||||
}
|
||||
return itemStacks;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ReadWriteNBT upgradeItemData(@NotNull ReadWriteNBT tag, @NotNull Version mcVersion)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
return DataFixerUtil.fixUpItemData(tag, getDataVersion(mcVersion), DataFixerUtil.getCurrentVersion());
|
||||
}
|
||||
|
||||
private int getDataVersion(@NotNull Version mcVersion) {
|
||||
return switch (mcVersion.toStringWithoutMetadata()) {
|
||||
case "1.16", "1.16.1", "1.16.2", "1.16.3", "1.16.4", "1.16.5" -> DataFixerUtil.VERSION1_16_5;
|
||||
case "1.17", "1.17.1" -> DataFixerUtil.VERSION1_17_1;
|
||||
case "1.18", "1.18.1", "1.18.2" -> DataFixerUtil.VERSION1_18_2;
|
||||
case "1.19", "1.19.1", "1.19.2" -> DataFixerUtil.VERSION1_19_2;
|
||||
case "1.20", "1.20.1", "1.20.2" -> DataFixerUtil.VERSION1_20_2;
|
||||
case "1.20.3", "1.20.4" -> DataFixerUtil.VERSION1_20_4;
|
||||
default -> DataFixerUtil.getCurrentVersion();
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
HuskSync getPlugin();
|
||||
}
|
||||
|
||||
public static class PotionEffects extends BukkitSerializer implements Serializer<BukkitData.PotionEffects> {
|
||||
|
||||
private static final TypeToken<List<Data.PotionEffects.Effect>> TYPE = new TypeToken<>() {
|
||||
|
||||
Reference in New Issue
Block a user