From 2f64594ee406966e17e0b811fa283272df1851aa Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Thu, 19 Jun 2025 01:29:36 +0200 Subject: [PATCH 1/8] feat: 1.21.6 support feat: convert nbt into readable json binary --- .github/workflows/buildtools.sh | 3 +- zip-nms/pom.xml | 1 + zip-nms/zip-nms-v1_21_R5/pom.xml | 70 ++++++ .../zip/nms/v1_21_R5/ZipNmsManager.java | 230 ++++++++++++++++++ 4 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 zip-nms/zip-nms-v1_21_R5/pom.xml create mode 100644 zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 13cad4c..c5da7e3 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -35,4 +35,5 @@ checkVersion "1.20.6" "21" checkVersion "1.21" "21" checkVersion "1.21.3" "21" checkVersion "1.21.4" "21" -checkVersion "1.21.5" "21" \ No newline at end of file +checkVersion "1.21.5" "21" +checkVersion "1.21.6" "21" \ No newline at end of file diff --git a/zip-nms/pom.xml b/zip-nms/pom.xml index 2409ce8..a064cdc 100644 --- a/zip-nms/pom.xml +++ b/zip-nms/pom.xml @@ -23,5 +23,6 @@ zip-nms-v1_21_R2 zip-nms-v1_21_R3 zip-nms-v1_21_R4 + zip-nms-v1_21_R5 \ No newline at end of file diff --git a/zip-nms/zip-nms-v1_21_R5/pom.xml b/zip-nms/zip-nms-v1_21_R5/pom.xml new file mode 100644 index 0000000..2e6e44e --- /dev/null +++ b/zip-nms/zip-nms-v1_21_R5/pom.xml @@ -0,0 +1,70 @@ + + 4.0.0 + + + net.imprex + zip-nms + ${revision} + + + zip-nms-v1_21_R5 + + + + net.imprex + zip-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 1.21.6-R0.1-SNAPSHOT + remapped-mojang + provided + + + + + + + net.md-5 + specialsource-maven-plugin + ${plugin.specialsource.version} + + + package + + remap + + remap-obf + + + org.spigotmc:minecraft-server:1.21.6-R0.1-SNAPSHOT:txt:maps-mojang + true + + org.spigotmc:spigot:1.21.6-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + + org.spigotmc:minecraft-server:1.21.6-R0.1-SNAPSHOT:csrg:maps-spigot + + org.spigotmc:spigot:1.21.6-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + \ No newline at end of file diff --git a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java new file mode 100644 index 0000000..80f43c3 --- /dev/null +++ b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java @@ -0,0 +1,230 @@ +package net.imprex.zip.nms.v1_21_R5; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.function.BiConsumer; + +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; + +import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.component.ResolvableProfile; + +public class ZipNmsManager implements NmsManager { + + private static final BiConsumer SET_PROFILE; + + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().dataVersion().version(); + + private static final Gson GSON = new Gson(); + + private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); + private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); + + static { + NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); + + BiConsumer setProfile = (meta, profile) -> { + throw new NullPointerException("Unable to find 'setProfile' method!"); + }; + + Class craftMetaSkullClass = new ItemStack(Material.PLAYER_HEAD) + .getItemMeta() + .getClass(); + + Method setResolvableProfileMethod = ReflectionUtil.searchMethod(craftMetaSkullClass, void.class, ResolvableProfile.class); + if (setResolvableProfileMethod != null) { + setProfile = (meta, profile) -> { + try { + setResolvableProfileMethod.invoke(meta, new ResolvableProfile(profile)); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + }; + } else { + Method setProfileMethod = ReflectionUtil.searchMethod(craftMetaSkullClass, void.class, GameProfile.class); + if (setProfileMethod != null) { + setProfile = (meta, profile) -> { + try { + setProfileMethod.invoke(meta, profile); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + }; + } + } + + SET_PROFILE = setProfile; + } + + public byte[] nbtToBinary(CompoundTag compound) { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + NbtIo.writeCompressed(compound, outputStream); + return outputStream.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public CompoundTag binaryToNBT(byte[] binary) { + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (Exception e) { + e.printStackTrace(); + } + return new CompoundTag(); + } + + @Override + public byte[] itemstackToBinary(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty("Slot", slot); + jsonItems.add(resultJson); + } + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty("ZIPVersion", 2); + outputJson.addProperty("DataVersion", DATA_VERSION); + outputJson.addProperty("ContainerSize", items.length); + outputJson.add("Items", jsonItems); + + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { + GSON.toJson(outputJson, outputStreamWriter); + return outputStream.toByteArray(); + } catch (IOException e) { + throw new IllegalStateException("Unable to convert ItemStack into json", e); + } + } + + @Override + public List binaryToItemStack(byte[] binary) { + try { + // parse new version (JSON) + JsonObject inputJson; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { + inputJson = GSON.fromJson(inputStreamReader, JsonObject.class); + } + + // check if current version the same + if (inputJson.get("ZIPVersion").getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = inputJson.get("DataVersion").getAsInt(); + int containerSize = inputJson.get("ContainerSize").getAsInt(); + + // convert json into bukkit item + List items = new ArrayList<>(containerSize); + JsonArray jsonItems = inputJson.get("Items").getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer().update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get("Slot").getAsInt(); + items.set(slot, bukkitItem); + } + + return items; + } catch (Exception e) { + // parse outdated version (NBT) + CompoundTag compound = binaryToNBT(binary); + ListTag list = compound.getListOrEmpty("i"); + if (list.isEmpty()) { + return Collections.emptyList(); + } + + List items = new ArrayList<>(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id").orElse(""); + if (itemType.equals("minecraft:air")) { + items.add(new ItemStack(Material.AIR)); + } else { + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + items.add(bukkitItem); + } + } + } + return items; + } + } + + @Override + public void setSkullProfile(SkullMeta meta, String texture) { + try { + GameProfile gameProfile = new GameProfile(UUID.randomUUID(), ""); + gameProfile.getProperties().put("textures", new Property("textures", texture)); + + SET_PROFILE.accept(meta, gameProfile); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public boolean isAir(Material material) { + return material == null || material == Material.AIR; + } +} \ No newline at end of file From 301b6aa7e2af79440af17f1fcc57000df7861c9e Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Thu, 19 Jun 2025 02:17:18 +0200 Subject: [PATCH 2/8] fix: missing version reference --- .../main/java/net/imprex/zip/common/MinecraftVersion.java | 1 + zip-plugin/pom.xml | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java b/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java index 3e3cfb9..cf3cc73 100644 --- a/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java +++ b/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java @@ -19,6 +19,7 @@ private static final class NmsMapping { private static final List MAPPINGS = new ArrayList<>(); static { + MAPPINGS.add(new NmsMapping("1.21.6", "v1_21_R5")); MAPPINGS.add(new NmsMapping("1.21.5", "v1_21_R4")); MAPPINGS.add(new NmsMapping("1.21.4", "v1_21_R3")); MAPPINGS.add(new NmsMapping("1.21.3", "v1_21_R2")); diff --git a/zip-plugin/pom.xml b/zip-plugin/pom.xml index e52f7a3..7aa6882 100644 --- a/zip-plugin/pom.xml +++ b/zip-plugin/pom.xml @@ -113,5 +113,11 @@ ${revision} compile + + net.imprex + zip-nms-v1_21_R5 + ${revision} + compile + \ No newline at end of file From 0d3ef9029f51ac37d1fd97678d0f632a7f6f564b Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Sun, 22 Jun 2025 04:43:04 +0200 Subject: [PATCH 3/8] feat: moved from binary format to json feat: added migrate command for converting all existing backpacks at once fix: giveUnsueableContent is now saving after the payer recived there items --- .../java/net/imprex/zip/api/ZIPHandler.java | 2 + .../java/net/imprex/zip/common/BPKey.java | 16 ++ .../imprex/zip/common/ItemStackWithSlot.java | 6 + .../net/imprex/zip/common}/ZIPLogger.java | 2 +- .../net/imprex/zip/nms/api/NmsManager.java | 10 +- .../zip/nms/v1_19_R1/ZipNmsManager.java | 197 +++++++++++++--- .../zip/nms/v1_19_R2/ZipNmsManager.java | 197 +++++++++++++--- .../zip/nms/v1_19_R3/ZipNmsManager.java | 197 +++++++++++++--- .../zip/nms/v1_20_R1/ZipNmsManager.java | 197 +++++++++++++--- .../zip/nms/v1_20_R2/ZipNmsManager.java | 197 +++++++++++++--- .../zip/nms/v1_20_R3/ZipNmsManager.java | 197 +++++++++++++--- .../zip/nms/v1_20_R4/ZipNmsManager.java | 209 ++++++++++++----- .../zip/nms/v1_21_R1/ZipNmsManager.java | 213 ++++++++++++----- .../zip/nms/v1_21_R2/ZipNmsManager.java | 213 ++++++++++++----- zip-nms/zip-nms-v1_21_R3/pom.xml | 6 +- .../zip/nms/v1_21_R3/ZipNmsManager.java | 213 ++++++++++++----- .../zip/nms/v1_21_R4/ZipNmsManager.java | 216 ++++++++++++----- .../zip/nms/v1_21_R5/ZipNmsManager.java | 221 ++++++++++-------- .../main/java/net/imprex/zip/Backpack.java | 29 ++- .../java/net/imprex/zip/BackpackHandler.java | 67 ++++-- .../java/net/imprex/zip/BackpackListener.java | 5 +- .../java/net/imprex/zip/BackpackMigrator.java | 74 ++++++ .../java/net/imprex/zip/BackpackPlugin.java | 2 +- .../java/net/imprex/zip/BackpackRegistry.java | 2 +- .../main/java/net/imprex/zip/NmsInstance.java | 17 +- .../java/net/imprex/zip/UpdateSystem.java | 2 +- .../imprex/zip/command/BackpackCommand.java | 1 + .../imprex/zip/command/MigrateCommand.java | 80 +++++++ .../net/imprex/zip/config/MessageConfig.java | 2 +- .../net/imprex/zip/config/MessageKey.java | 8 +- .../net/imprex/zip/config/RecipeConfig.java | 2 +- zip-plugin/src/main/resources/lang/en_US.yml | 8 +- zip-plugin/src/main/resources/plugin.yml | 4 +- 33 files changed, 2188 insertions(+), 624 deletions(-) create mode 100644 zip-common/src/main/java/net/imprex/zip/common/BPKey.java create mode 100644 zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java rename {zip-plugin/src/main/java/net/imprex/zip/util => zip-common/src/main/java/net/imprex/zip/common}/ZIPLogger.java (96%) create mode 100644 zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java create mode 100644 zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java diff --git a/zip-api/src/main/java/net/imprex/zip/api/ZIPHandler.java b/zip-api/src/main/java/net/imprex/zip/api/ZIPHandler.java index f29e5fd..be4c32f 100644 --- a/zip-api/src/main/java/net/imprex/zip/api/ZIPHandler.java +++ b/zip-api/src/main/java/net/imprex/zip/api/ZIPHandler.java @@ -16,4 +16,6 @@ public interface ZIPHandler { ZIPBackpackType getBackpackType(ItemStack item); boolean isBackpack(ItemStack item); + + ZIPUniqueId getUniqueId(ItemStack item); } diff --git a/zip-common/src/main/java/net/imprex/zip/common/BPKey.java b/zip-common/src/main/java/net/imprex/zip/common/BPKey.java new file mode 100644 index 0000000..62fd9c6 --- /dev/null +++ b/zip-common/src/main/java/net/imprex/zip/common/BPKey.java @@ -0,0 +1,16 @@ +package net.imprex.zip.common; + +public class BPKey { + + public static final String VERSION = "version"; + + public static final String ID = "id"; + public static final String TYPE_RAW = "typeRaw"; + public static final String INVENTORY = "inventory"; + + public static final String INVENTORY_VERSION = "version"; + public static final String INVENTORY_DATA_VERSION = "dataVersion"; + public static final String INVENTORY_ITEMS = "items"; + public static final String INVENTORY_ITEMS_SIZE = "itemsSize"; + public static final String INVENTORY_SLOT = "ZIPslot"; +} diff --git a/zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java b/zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java new file mode 100644 index 0000000..31bdd3c --- /dev/null +++ b/zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java @@ -0,0 +1,6 @@ +package net.imprex.zip.common; + +import org.bukkit.inventory.ItemStack; + +public record ItemStackWithSlot(ItemStack item, int slot) { +} diff --git a/zip-plugin/src/main/java/net/imprex/zip/util/ZIPLogger.java b/zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java similarity index 96% rename from zip-plugin/src/main/java/net/imprex/zip/util/ZIPLogger.java rename to zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java index 83fd3a5..6c3c2b3 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/util/ZIPLogger.java +++ b/zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java @@ -1,4 +1,4 @@ -package net.imprex.zip.util; +package net.imprex.zip.common; import java.util.logging.Level; import java.util.logging.Logger; diff --git a/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java index 7bcaa4e..9a8bbe9 100644 --- a/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java +++ b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java @@ -1,16 +1,18 @@ package net.imprex.zip.nms.api; -import java.util.List; - import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonObject; + public interface NmsManager { - byte[] itemstackToBinary(ItemStack[] items); + JsonObject itemstackToJsonElement(ItemStack[] items); - List binaryToItemStack(byte[] binary); + ItemStack[] jsonElementToItemStack(JsonObject jsonElement); + + JsonObject migrateToJsonElement(byte[] binary); void setSkullProfile(SkullMeta meta, String texture); diff --git a/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java index 2e1ebd5..010d656 100644 --- a/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java @@ -1,9 +1,11 @@ package net.imprex.zip.nms.v1_19_R1; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -12,15 +14,31 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -28,51 +46,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final DynamicOps DYNAMIC_OPS_NBT = RegistryOps.create(NbtOps.INSTANCE, DEFAULT_REGISTRY); + private static final DynamicOps DYNAMIC_OPS_JSON = RegistryOps.create(JsonOps.INSTANCE, DEFAULT_REGISTRY); @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - list.add(craftItem.save(new CompoundTag())); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag) { - items.add(CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of((CompoundTag) base))); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(false, error -> {}); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; } } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(false, error -> {}); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java index 4b80fb1..0910343 100644 --- a/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java @@ -1,9 +1,11 @@ package net.imprex.zip.nms.v1_19_R2; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -12,15 +14,31 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -28,51 +46,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final DynamicOps DYNAMIC_OPS_NBT = RegistryOps.create(NbtOps.INSTANCE, DEFAULT_REGISTRY); + private static final DynamicOps DYNAMIC_OPS_JSON = RegistryOps.create(JsonOps.INSTANCE, DEFAULT_REGISTRY); @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - list.add(craftItem.save(new CompoundTag())); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag) { - items.add(CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of((CompoundTag) base))); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(false, error -> {}); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; } } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(false, error -> {}); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java index 33b2dd1..e9b23ae 100644 --- a/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java @@ -1,9 +1,11 @@ package net.imprex.zip.nms.v1_19_R3; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -12,15 +14,31 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -28,51 +46,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final DynamicOps DYNAMIC_OPS_NBT = RegistryOps.create(NbtOps.INSTANCE, DEFAULT_REGISTRY); + private static final DynamicOps DYNAMIC_OPS_JSON = RegistryOps.create(JsonOps.INSTANCE, DEFAULT_REGISTRY); @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - list.add(craftItem.save(new CompoundTag())); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag) { - items.add(CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of((CompoundTag) base))); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(false, error -> {}); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; } } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(false, error -> {}); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java index ecc1f92..555a558 100644 --- a/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java @@ -1,9 +1,11 @@ package net.imprex.zip.nms.v1_20_R1; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -12,15 +14,31 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -28,51 +46,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final DynamicOps DYNAMIC_OPS_NBT = RegistryOps.create(NbtOps.INSTANCE, DEFAULT_REGISTRY); + private static final DynamicOps DYNAMIC_OPS_JSON = RegistryOps.create(JsonOps.INSTANCE, DEFAULT_REGISTRY); @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - list.add(craftItem.save(new CompoundTag())); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag) { - items.add(CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of((CompoundTag) base))); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(false, error -> {}); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; } } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(false, error -> {}); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java index aa53f74..56317e8 100644 --- a/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java @@ -1,9 +1,11 @@ package net.imprex.zip.nms.v1_20_R2; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -12,15 +14,31 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -28,51 +46,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final DynamicOps DYNAMIC_OPS_NBT = RegistryOps.create(NbtOps.INSTANCE, DEFAULT_REGISTRY); + private static final DynamicOps DYNAMIC_OPS_JSON = RegistryOps.create(JsonOps.INSTANCE, DEFAULT_REGISTRY); @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - list.add(craftItem.save(new CompoundTag())); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag) { - items.add(CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of((CompoundTag) base))); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(false, error -> {}); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; } } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(false, error -> {}); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java index 3cab8ee..9c50fc9 100644 --- a/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java @@ -1,9 +1,11 @@ package net.imprex.zip.nms.v1_20_R3; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -12,16 +14,32 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -29,51 +47,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + + private static final DynamicOps DYNAMIC_OPS_NBT = RegistryOps.create(NbtOps.INSTANCE, DEFAULT_REGISTRY); + private static final DynamicOps DYNAMIC_OPS_JSON = RegistryOps.create(JsonOps.INSTANCE, DEFAULT_REGISTRY); @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - list.add(craftItem.save(new CompoundTag())); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag) { - items.add(CraftItemStack.asBukkitCopy(net.minecraft.world.item.ItemStack.of((CompoundTag) base))); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(false, error -> {}); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; } } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(false, error -> {}); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java index 73b2f24..7fe0201 100644 --- a/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java @@ -1,30 +1,44 @@ package net.imprex.zip.nms.v1_20_R4; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.UUID; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_20_R4.CraftRegistry; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; public class ZipNmsManager implements NmsManager { @@ -32,71 +46,162 @@ public class ZipNmsManager implements NmsManager { private static final Method CRAFTMETASKULL_SET_PROFILE = ReflectionUtil.getMethod(CRAFTMETASKULL_CLASS, "setProfile", GameProfile.class); - private static final RegistryAccess DEFAULT_REGISTRY = CraftRegistry.getMinecraftRegistry(); + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); - static { - NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); - } + private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); + private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); + @Override + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - return new CompoundTag(); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - if (itemStack == null || itemStack.getType() == Material.AIR) { - list.add(NBT_EMPTY_ITEMSTACK); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); } else { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - Tag tag = craftItem.save(DEFAULT_REGISTRY); - list.add(tag); + items[slot] = bukkitItem; } } - inventory.put("i", list); - return nbtToBinary(inventory); - } - - @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag itemTag) { - if (itemTag.getString("id").equals("minecraft:air")) { - items.add(new ItemStack(Material.AIR)); - } else { - Optional optional = net.minecraft.world.item.ItemStack.parse(DEFAULT_REGISTRY, itemTag); - if (optional.isPresent()) { - items.add(CraftItemStack.asBukkitCopy(optional.get())); - } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; } } } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java index 36248a6..c7edd26 100644 --- a/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java @@ -1,45 +1,61 @@ package net.imprex.zip.nms.v1_21_R1; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.component.ResolvableProfile; public class ZipNmsManager implements NmsManager { - private static final BiConsumer SET_PROFILE; - - private static final RegistryAccess DEFAULT_REGISTRY = CraftRegistry.getMinecraftRegistry(); + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); + private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); + + private static final BiConsumer SET_PROFILE; + static { - NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); - BiConsumer setProfile = (meta, profile) -> { throw new NullPointerException("Unable to find 'setProfile' method!"); }; @@ -73,63 +89,154 @@ public class ZipNmsManager implements NmsManager { SET_PROFILE = setProfile; } - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); + @Override + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - return new CompoundTag(); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - if (itemStack == null || itemStack.getType() == Material.AIR) { - list.add(NBT_EMPTY_ITEMSTACK); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); } else { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - Tag tag = craftItem.save(DEFAULT_REGISTRY); - list.add(tag); + items[slot] = bukkitItem; } } - inventory.put("i", list); - return nbtToBinary(inventory); - } - - @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag itemTag) { - if (itemTag.getString("id").equals("minecraft:air")) { - items.add(new ItemStack(Material.AIR)); - } else { - Optional optional = net.minecraft.world.item.ItemStack.parse(DEFAULT_REGISTRY, itemTag); - if (optional.isPresent()) { - items.add(CraftItemStack.asBukkitCopy(optional.get())); - } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; } } } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java index bd63f72..2e0e917 100644 --- a/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java @@ -1,45 +1,61 @@ package net.imprex.zip.nms.v1_21_R2; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_21_R2.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R2.inventory.CraftItemStack; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.component.ResolvableProfile; public class ZipNmsManager implements NmsManager { - private static final BiConsumer SET_PROFILE; - - private static final RegistryAccess DEFAULT_REGISTRY = CraftRegistry.getMinecraftRegistry(); + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); + private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); + + private static final BiConsumer SET_PROFILE; + static { - NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); - BiConsumer setProfile = (meta, profile) -> { throw new NullPointerException("Unable to find 'setProfile' method!"); }; @@ -73,63 +89,154 @@ public class ZipNmsManager implements NmsManager { SET_PROFILE = setProfile; } - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); + @Override + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - return new CompoundTag(); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - if (itemStack == null || itemStack.getType() == Material.AIR) { - list.add(NBT_EMPTY_ITEMSTACK); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); } else { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - Tag tag = craftItem.save(DEFAULT_REGISTRY); - list.add(tag); + items[slot] = bukkitItem; } } - inventory.put("i", list); - return nbtToBinary(inventory); - } - - @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag itemTag) { - if (itemTag.getString("id").equals("minecraft:air")) { - items.add(new ItemStack(Material.AIR)); - } else { - Optional optional = net.minecraft.world.item.ItemStack.parse(DEFAULT_REGISTRY, itemTag); - if (optional.isPresent()) { - items.add(CraftItemStack.asBukkitCopy(optional.get())); - } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; } } } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_21_R3/pom.xml b/zip-nms/zip-nms-v1_21_R3/pom.xml index 89e6386..61e819d 100644 --- a/zip-nms/zip-nms-v1_21_R3/pom.xml +++ b/zip-nms/zip-nms-v1_21_R3/pom.xml @@ -1,7 +1,5 @@ - - 4.0.0 + + 4.0.0 net.imprex diff --git a/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java index 7c2a710..00966f7 100644 --- a/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java @@ -1,45 +1,61 @@ package net.imprex.zip.nms.v1_21_R3; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_21_R3.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R3.inventory.CraftItemStack; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.component.ResolvableProfile; public class ZipNmsManager implements NmsManager { - private static final BiConsumer SET_PROFILE; - - private static final RegistryAccess DEFAULT_REGISTRY = CraftRegistry.getMinecraftRegistry(); + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); + private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); + + private static final BiConsumer SET_PROFILE; + static { - NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); - BiConsumer setProfile = (meta, profile) -> { throw new NullPointerException("Unable to find 'setProfile' method!"); }; @@ -73,63 +89,154 @@ public class ZipNmsManager implements NmsManager { SET_PROFILE = setProfile; } - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); + @Override + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; + } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - return new CompoundTag(); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - if (itemStack == null || itemStack.getType() == Material.AIR) { - list.add(NBT_EMPTY_ITEMSTACK); + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); } else { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - Tag tag = craftItem.save(DEFAULT_REGISTRY); - list.add(tag); + items[slot] = bukkitItem; } } - inventory.put("i", list); - return nbtToBinary(inventory); - } - - @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i", 9)) { - ListTag list = nbt.getList("i", 10); - for (Tag base : list) { - if (base instanceof CompoundTag itemTag) { - if (itemTag.getString("id").equals("minecraft:air")) { - items.add(new ItemStack(Material.AIR)); - } else { - Optional optional = net.minecraft.world.item.ItemStack.parse(DEFAULT_REGISTRY, itemTag); - if (optional.isPresent()) { - items.add(CraftItemStack.asBukkitCopy(optional.get())); - } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; } } } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getList("i", 10); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id"); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java index 4c51c9e..33796a9 100644 --- a/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java @@ -1,45 +1,61 @@ package net.imprex.zip.nms.v1_21_R4; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_21_R4.CraftRegistry; import org.bukkit.craftbukkit.v1_21_R4.inventory.CraftItemStack; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; +import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtAccounter; import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.component.ResolvableProfile; public class ZipNmsManager implements NmsManager { - private static final BiConsumer SET_PROFILE; - - private static final RegistryAccess DEFAULT_REGISTRY = CraftRegistry.getMinecraftRegistry(); + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + @SuppressWarnings("deprecation") + private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); + private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); + private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); + + private static final BiConsumer SET_PROFILE; + static { - NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); - BiConsumer setProfile = (meta, profile) -> { throw new NullPointerException("Unable to find 'setProfile' method!"); }; @@ -73,68 +89,154 @@ public class ZipNmsManager implements NmsManager { SET_PROFILE = setProfile; } - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } - @Override - public byte[] itemstackToBinary(ItemStack[] items) { - CompoundTag inventory = new CompoundTag(); - ListTag list = new ListTag(); - for (ItemStack itemStack : items) { - if (itemStack == null || itemStack.getType() == Material.AIR) { - list.add(NBT_EMPTY_ITEMSTACK); - } else { - net.minecraft.world.item.ItemStack craftItem = CraftItemStack.asNMSCopy(itemStack); - Tag tag = craftItem.save(DEFAULT_REGISTRY); - list.add(tag); + public JsonObject itemstackToJsonElement(ItemStack[] items) { + JsonArray jsonItems = new JsonArray(); + for (int slot = 0; slot < items.length; slot++) { + ItemStack item = items[slot]; + if (item == null || item.getType() == Material.AIR) { + continue; } + net.minecraft.world.item.ItemStack minecraftItem = CraftItemStack.asNMSCopy(item); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + jsonItems.add(resultJson); } - inventory.put("i", list); - return nbtToBinary(inventory); + + JsonObject outputJson = new JsonObject(); + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - CompoundTag nbt = binaryToNBT(binary); - List items = new ArrayList<>(); - if (nbt.contains("i")) { - Optional list = nbt.getList("i"); - if (list.isEmpty()) { - return items; + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); + + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); + + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); + + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; } - for (Tag base : list.get()) { - if (base instanceof CompoundTag itemTag) { - String itemType = itemTag.getString("id").orElse(""); - if (itemType.equals("minecraft:air")) { - items.add(new ItemStack(Material.AIR)); - } else { - Optional optional = net.minecraft.world.item.ItemStack.parse(DEFAULT_REGISTRY, itemTag); - if (optional.isPresent()) { - items.add(CraftItemStack.asBukkitCopy(optional.get())); - } + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; + } + } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; } } } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } } + return items; } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getListOrEmpty("i"); + + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id").orElse(""); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; + } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; + } @Override public void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java index 80f43c3..6d04582 100644 --- a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java @@ -1,15 +1,12 @@ package net.imprex.zip.nms.v1_21_R5; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -19,7 +16,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; -import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -30,7 +26,9 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -47,23 +45,17 @@ public class ZipNmsManager implements NmsManager { - private static final BiConsumer SET_PROFILE; + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().dataVersion().version(); @SuppressWarnings("deprecation") private static final RegistryAccess DEFAULT_REGISTRY = MinecraftServer.getServer().registryAccess(); - private static final CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); - - private static final int DATA_VERSION = SharedConstants.getCurrentVersion().dataVersion().version(); - - private static final Gson GSON = new Gson(); - private static final DynamicOps DYNAMIC_OPS_NBT = DEFAULT_REGISTRY.createSerializationContext(NbtOps.INSTANCE); private static final DynamicOps DYNAMIC_OPS_JSON = DEFAULT_REGISTRY.createSerializationContext(JsonOps.INSTANCE); - static { - NBT_EMPTY_ITEMSTACK.putString("id", "minecraft:air"); + private static final BiConsumer SET_PROFILE; + static { BiConsumer setProfile = (meta, profile) -> { throw new NullPointerException("Unable to find 'setProfile' method!"); }; @@ -97,27 +89,8 @@ public class ZipNmsManager implements NmsManager { SET_PROFILE = setProfile; } - public byte[] nbtToBinary(CompoundTag compound) { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - NbtIo.writeCompressed(compound, outputStream); - return outputStream.toByteArray(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public CompoundTag binaryToNBT(byte[] binary) { - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { - return NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); - } catch (Exception e) { - e.printStackTrace(); - } - return new CompoundTag(); - } - @Override - public byte[] itemstackToBinary(ItemStack[] items) { + public JsonObject itemstackToJsonElement(ItemStack[] items) { JsonArray jsonItems = new JsonArray(); for (int slot = 0; slot < items.length; slot++) { ItemStack item = items[slot]; @@ -129,86 +102,140 @@ public byte[] itemstackToBinary(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty("Slot", slot); + resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty("ZIPVersion", 2); - outputJson.addProperty("DataVersion", DATA_VERSION); - outputJson.addProperty("ContainerSize", items.length); - outputJson.add("Items", jsonItems); - - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { - GSON.toJson(outputJson, outputStreamWriter); - return outputStream.toByteArray(); - } catch (IOException e) { - throw new IllegalStateException("Unable to convert ItemStack into json", e); - } + outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); + outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + return outputJson; } @Override - public List binaryToItemStack(byte[] binary) { - try { - // parse new version (JSON) - JsonObject inputJson; - try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary); - InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - inputJson = GSON.fromJson(inputStreamReader, JsonObject.class); - } + public ItemStack[] jsonElementToItemStack(JsonObject json) { + // check if current version the same + if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); + } + + int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + + // convert json into bukkit item + ItemStack[] items = new ItemStack[itemsSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + for (JsonElement item : jsonItems) { + Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); + Dynamic dynamicItemFixed = DataFixers.getDataFixer() + .update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); - // check if current version the same - if (inputJson.get("ZIPVersion").getAsInt() != 2) { - throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); - } + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) + .getOrThrow(); - int dataVersion = inputJson.get("DataVersion").getAsInt(); - int containerSize = inputJson.get("ContainerSize").getAsInt(); + ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - // convert json into bukkit item - List items = new ArrayList<>(containerSize); - JsonArray jsonItems = inputJson.get("Items").getAsJsonArray(); - for (JsonElement item : jsonItems) { - Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); - Dynamic dynamicItemFixed = DataFixers.getDataFixer().update(References.ITEM_STACK, dynamicItem, dataVersion, DATA_VERSION); - net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC - .parse(DYNAMIC_OPS_JSON, dynamicItemFixed.getValue()) - .getOrThrow(); + if (itemsSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(bukkitItem); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + } else { + items[slot] = bukkitItem; + } + } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); - ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get("Slot").getAsInt(); - items.set(slot, bukkitItem); + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } } - return items; - } catch (Exception e) { - // parse outdated version (NBT) - CompoundTag compound = binaryToNBT(binary); - ListTag list = compound.getListOrEmpty("i"); - if (list.isEmpty()) { - return Collections.emptyList(); + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; } + } + + return items; + } + + @Override + public JsonObject migrateToJsonElement(byte[] binary) { + CompoundTag compound; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(binary)) { + compound = NbtIo.readCompressed(inputStream, NbtAccounter.unlimitedHeap()); + } catch (IOException e) { + throw new IllegalStateException("Unable to parse binary to nbt", e); + } + + ListTag list = compound.getListOrEmpty("i"); - List items = new ArrayList<>(); - for (Tag base : list) { - if (base instanceof CompoundTag itemTag) { - String itemType = itemTag.getString("id").orElse(""); - if (itemType.equals("minecraft:air")) { - items.add(new ItemStack(Material.AIR)); - } else { - Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); - net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC - .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) - .getOrThrow(); - - ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - items.add(bukkitItem); - } + int currentSlot = 0; + + JsonArray jsonItems = new JsonArray(); + for (Tag base : list) { + if (base instanceof CompoundTag itemTag) { + String itemType = itemTag.getString("id").orElse(""); + if (itemType.equals("minecraft:air")) { + currentSlot++; + continue; } + + Dynamic dynamicItem = new Dynamic<>(NbtOps.INSTANCE, itemTag); + net.minecraft.world.item.ItemStack minecraftItem = net.minecraft.world.item.ItemStack.CODEC + .parse(DYNAMIC_OPS_NBT, dynamicItem.getValue()) + .getOrThrow(); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; } - return items; } + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.INVENTORY_VERSION, 2); + json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPKey.INVENTORY_ITEMS, jsonItems); + return json; } @Override diff --git a/zip-plugin/src/main/java/net/imprex/zip/Backpack.java b/zip-plugin/src/main/java/net/imprex/zip/Backpack.java index 4a2c20f..57a7b89 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/Backpack.java +++ b/zip-plugin/src/main/java/net/imprex/zip/Backpack.java @@ -13,13 +13,18 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; +import com.google.gson.Gson; +import com.google.gson.JsonObject; + import net.imprex.zip.api.ZIPBackpack; -import net.imprex.zip.common.Ingrim4Buffer; +import net.imprex.zip.common.BPKey; import net.imprex.zip.common.UniqueId; import net.imprex.zip.config.MessageConfig; import net.imprex.zip.config.MessageKey; public class Backpack implements ZIPBackpack { + + static final Gson GSON = new Gson(); private final BackpackHandler backpackHandler; private final MessageConfig messageConfig; @@ -55,7 +60,7 @@ public Backpack(BackpackPlugin plugin, BackpackType type, UniqueId id) { this.save(); } - public Backpack(BackpackPlugin plugin, UniqueId id, Ingrim4Buffer buffer) { + public Backpack(BackpackPlugin plugin, UniqueId id, JsonObject json) { this.backpackHandler = plugin.getBackpackHandler(); this.messageConfig = plugin.getBackpackConfig().message(); this.identifierKey = plugin.getBackpackIdentifierKey(); @@ -65,14 +70,15 @@ public Backpack(BackpackPlugin plugin, UniqueId id, Ingrim4Buffer buffer) { * Load backpack id from buffer but don't use it! * Just for later migration to SQL */ - buffer.readByteArray(); + + this.id = id; - this.typeRaw = buffer.readString(); + this.typeRaw = json.get(BPKey.TYPE_RAW).getAsString(); this.type = plugin.getBackpackRegistry().getTypeByName(this.typeRaw); - byte[] contentAsByteArray = buffer.readByteArray(); - ItemStack[] content = NmsInstance.binaryToItemStack(contentAsByteArray).toArray(ItemStack[]::new); + JsonObject contentAsJson = json.getAsJsonObject(BPKey.INVENTORY); + ItemStack[] content = NmsInstance.jsonElementToItemStack(contentAsJson); this.content = content; if (this.type != null) { @@ -98,7 +104,7 @@ public Backpack(BackpackPlugin plugin, UniqueId id, Ingrim4Buffer buffer) { this.backpackHandler.registerBackpack(this); } - public void save(Ingrim4Buffer buffer) { + public void save(JsonObject json) { if (this.inventory != null) { for (int i = 0; i < this.inventory.getSize(); i++) { this.content[i] = this.inventory.getItem(i); @@ -107,9 +113,10 @@ public void save(Ingrim4Buffer buffer) { throw new NullPointerException("content can not be null"); } - buffer.writeByteArray(this.id.toByteArray()); - buffer.writeString(this.typeRaw); - buffer.writeByteArray(NmsInstance.itemstackToBinary(this.content)); + json.addProperty(BPKey.VERSION, 2); + json.addProperty(BPKey.ID, this.id.toString()); + json.addProperty(BPKey.TYPE_RAW, this.typeRaw); + json.add(BPKey.INVENTORY, NmsInstance.itemstackToJsonElement(this.content)); } @Override @@ -203,6 +210,8 @@ public boolean giveUnsueableContent(Player player) { this.content[i] = null; } } + + this.save(); return empty; } diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java index 5dd7c2d..bd627c9 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java @@ -3,6 +3,9 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -17,16 +20,14 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; -import com.google.common.io.ByteStreams; +import com.google.gson.JsonObject; -import io.netty.buffer.Unpooled; import net.imprex.zip.api.ZIPBackpack; import net.imprex.zip.api.ZIPBackpackType; import net.imprex.zip.api.ZIPHandler; import net.imprex.zip.api.ZIPUniqueId; -import net.imprex.zip.common.Ingrim4Buffer; import net.imprex.zip.common.UniqueId; -import net.imprex.zip.util.ZIPLogger; +import net.imprex.zip.common.ZIPLogger; public class BackpackHandler implements ZIPHandler { @@ -65,17 +66,25 @@ public void disable() { } private Backpack loadBackpack(UniqueId id) { - Path file = this.folderPath.resolve(id.toString()); + Path file = this.getPathForId(id); if (!Files.isRegularFile(file)) { - return null; + // migrate backpack to json + if (!BackpackMigrator.migrate(this.folderPath, id)) { + return null; + } + + // backpack was successful migrated } - try (FileInputStream inputStream = new FileInputStream(file.toFile())) { - byte[] data = ByteStreams.toByteArray(inputStream); - Ingrim4Buffer buffer = new Ingrim4Buffer(Unpooled.wrappedBuffer(data)); - - Backpack backpack = new Backpack(this.plugin, id, buffer); + try { + JsonObject json; + try (FileInputStream inputStream = new FileInputStream(file.toFile()); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { + json = Backpack.GSON.fromJson(inputStreamReader, JsonObject.class); + } + + Backpack backpack = new Backpack(this.plugin, id, json); return backpack; } catch (Exception e) { ZIPLogger.error("Unable to load backpack for id '" + file.getFileName().toString() + "'", e); @@ -92,15 +101,14 @@ public void save(ZIPBackpack backpack) { e.printStackTrace(); } } + + JsonObject json = new JsonObject(); + ((Backpack) backpack).save(json); - Path file = this.folderPath.resolve(backpack.getId().toString()); - try (FileOutputStream outputStream = new FileOutputStream(file.toFile())) { - Ingrim4Buffer buffer = new Ingrim4Buffer(Unpooled.buffer()); - ((Backpack) backpack).save(buffer); - - byte[] bytes = new byte[buffer.readableBytes()]; - buffer.readBytes(bytes); - outputStream.write(bytes); + Path file = this.getPathForId(backpack.getId()); + try (FileOutputStream outputStream = new FileOutputStream(file.toFile()); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { + Backpack.GSON.toJson(json, outputStreamWriter); } catch (IOException e) { e.printStackTrace(); } @@ -154,7 +162,7 @@ public Backpack getBackpack(ItemStack item) { } } - if (dataContainer.has(this.backpackIdentifierKey, PersistentDataType.STRING)) { + if (!this.loadingIssue.contains(uniqueId) && dataContainer.has(this.backpackIdentifierKey, PersistentDataType.STRING)) { String backpackIdentifier = dataContainer.get(this.backpackIdentifierKey, PersistentDataType.STRING); BackpackType backpackType = this.registry.getTypeByName(backpackIdentifier); if (backpackType == null) { @@ -201,4 +209,23 @@ public boolean isBackpack(ItemStack item) { return false; } + + @Override + public UniqueId getUniqueId(ItemStack item) { + if (item != null && item.hasItemMeta()) { + ItemMeta meta = item.getItemMeta(); + PersistentDataContainer dataContainer = meta.getPersistentDataContainer(); + + if (dataContainer.has(this.backpackStorageKey, PersistentDataType.BYTE_ARRAY)) { + byte[] storageKey = dataContainer.get(this.backpackStorageKey, PersistentDataType.BYTE_ARRAY); + return UniqueId.fromByteArray(storageKey); + } + } + + return null; + } + + private Path getPathForId(ZIPUniqueId id) { + return this.folderPath.resolve(id.toString() + ".json"); + } } \ No newline at end of file diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackListener.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackListener.java index da489c0..7bc4d03 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackListener.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackListener.java @@ -19,6 +19,7 @@ import org.bukkit.inventory.ItemStack; import net.imprex.zip.api.ZIPBackpackType; +import net.imprex.zip.common.UniqueId; import net.imprex.zip.config.MessageConfig; import net.imprex.zip.config.MessageKey; @@ -114,7 +115,9 @@ public void onPlayerInteract(PlayerInteractEvent event) { if (backpack != null) { backpack.open(event.getPlayer()); } else { - this.messageConfig.send(event.getPlayer(), MessageKey.UnableToLoadBackpack); + UniqueId id = this.backpackHandler.getUniqueId(event.getItem()); + String idString = id != null ? id.toString() : "NOT READABLE"; + this.messageConfig.send(event.getPlayer(), MessageKey.UnableToLoadBackpack, idString); } } } diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java new file mode 100644 index 0000000..f281a58 --- /dev/null +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java @@ -0,0 +1,74 @@ +package net.imprex.zip; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import com.google.common.io.ByteStreams; +import com.google.gson.JsonObject; + +import io.netty.buffer.Unpooled; +import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.Ingrim4Buffer; +import net.imprex.zip.common.UniqueId; +import net.imprex.zip.common.ZIPLogger; + +public class BackpackMigrator { + + /* + * Previous implementation + * + * LOAD + * read id buffer.readByteArray(); + * read typeRaw buffer.readString(); + * read content buffer.readByteArray(); + * + * SAVE + * buffer.writeByteArray(this.id.toByteArray()); + * buffer.writeString(this.typeRaw); + * buffer.writeByteArray(NmsInstance.itemstackToBinary(this.content)); + */ + + public static boolean migrate(Path folderPath, UniqueId id) { + try { + Path previousFile = folderPath.resolve(id.toString()); + + if (!Files.isRegularFile(previousFile)) { + return false; + } + + Ingrim4Buffer buffer; + try (FileInputStream inputStream = new FileInputStream(previousFile.toFile())) { + byte[] data = ByteStreams.toByteArray(inputStream); + buffer = new Ingrim4Buffer(Unpooled.wrappedBuffer(data)); + } + + byte[] previousId = buffer.readByteArray(); + String previousRawType = buffer.readString(); + byte[] previousContent = buffer.readByteArray(); + + JsonObject json = new JsonObject(); + json.addProperty(BPKey.VERSION, 2); + json.addProperty(BPKey.ID, UniqueId.fromByteArray(previousId).toString()); + json.addProperty(BPKey.TYPE_RAW, previousRawType); + json.add(BPKey.INVENTORY, NmsInstance.migrateToJsonElement(previousContent)); + + Path newFile = folderPath.resolve(id.toString() + ".json"); + try (FileOutputStream outputStream = new FileOutputStream(newFile.toFile()); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { + Backpack.GSON.toJson(json, outputStreamWriter); + } + + Files.deleteIfExists(previousFile); + + ZIPLogger.info("Successful migrated backpack id '" + id.toString() + "'"); + return true; + } catch (Exception e) { + ZIPLogger.error("Unable to migrate backpack id '" + id.toString() + "'", e); + } + return false; + } +} diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java index 2d4d5a2..d6bd935 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java @@ -17,8 +17,8 @@ import net.imprex.zip.api.ZIPService; import net.imprex.zip.command.BackpackCommand; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.config.BackpackConfig; -import net.imprex.zip.util.ZIPLogger; public class BackpackPlugin extends JavaPlugin implements Listener, ZIPService { diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackRegistry.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackRegistry.java index fb90f96..9a0f8c0 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackRegistry.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackRegistry.java @@ -12,10 +12,10 @@ import net.imprex.zip.api.ZIPBackpackType; import net.imprex.zip.api.ZIPRecipe; import net.imprex.zip.api.ZIPRegistry; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.config.BackpackConfig; import net.imprex.zip.config.BackpackTypeConfig; import net.imprex.zip.config.BackpackTypeListConfig; -import net.imprex.zip.util.ZIPLogger; public class BackpackRegistry implements ZIPRegistry { diff --git a/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java b/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java index d4afe3e..0e34f5a 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java +++ b/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java @@ -2,15 +2,16 @@ package net.imprex.zip; import java.lang.reflect.Constructor; -import java.util.List; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import com.google.gson.JsonObject; + import net.imprex.zip.common.MinecraftVersion; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.nms.api.NmsManager; -import net.imprex.zip.util.ZIPLogger; public class NmsInstance { @@ -38,12 +39,16 @@ public static void initialize() { ZIPLogger.info("NMS adapter for server version \"" + nmsVersion + "\" found!"); } - public static byte[] itemstackToBinary(ItemStack[] items) { - return instance.itemstackToBinary(items); + public static JsonObject itemstackToJsonElement(ItemStack[] items) { + return instance.itemstackToJsonElement(items); + } + + public static ItemStack[] jsonElementToItemStack(JsonObject jsonElement) { + return instance.jsonElementToItemStack(jsonElement); } - public static List binaryToItemStack(byte[] binary) { - return instance.binaryToItemStack(binary); + public static JsonObject migrateToJsonElement(byte[] binary) { + return instance.migrateToJsonElement(binary); } public static void setSkullProfile(SkullMeta meta, String texture) { diff --git a/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java b/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java index b650306..109af5f 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java +++ b/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java @@ -14,10 +14,10 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.config.GeneralConfig; import net.imprex.zip.config.MessageConfig; import net.imprex.zip.config.MessageKey; -import net.imprex.zip.util.ZIPLogger; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ComponentBuilder; diff --git a/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java b/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java index 5a7b2d6..1d6d42d 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java +++ b/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java @@ -34,6 +34,7 @@ public BackpackCommand(BackpackPlugin plugin) { this.registerSubCommand(new PickupCommand(plugin)); this.registerSubCommand(new TypeCommand(plugin)); this.registerSubCommand(new LoreCommand(plugin)); + this.registerSubCommand(new MigrateCommand(plugin)); this.buildHelpMessage(); } diff --git a/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java b/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java new file mode 100644 index 0000000..32623e7 --- /dev/null +++ b/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java @@ -0,0 +1,80 @@ +package net.imprex.zip.command; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import net.imprex.zip.BackpackMigrator; +import net.imprex.zip.BackpackPlugin; +import net.imprex.zip.common.UniqueId; +import net.imprex.zip.config.MessageKey; + +public class MigrateCommand extends BackpackSubCommand { + + public MigrateCommand(BackpackPlugin plugin) { + super(plugin, MessageKey.CommandHelpMigrate, "zeroinventoryproblems.migrate", "migrate"); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + Player player = this.isPlayer(sender); + if (player == null) { + return; + } + + if (!(args.length == 1 && args[0].equalsIgnoreCase("confirm"))) { + this.messageConfig.send(sender, MessageKey.CommandMigrateUsage); + return; + } + + long startTime = System.currentTimeMillis(); + int statisticSuccessful = 0; + int statisticFailed = 0; + + this.messageConfig.send(sender, MessageKey.CommandMigrateOperationStartet); + + Path folderPath = Path.of(plugin.getDataFolder().getAbsolutePath(), "storage"); + try (Stream stream = Files.walk(folderPath, 1)) { + Path[] paths = stream + .filter(file -> !Files.isDirectory(file)) + .filter(file -> Files.isRegularFile(file)) + .filter(file -> !file.getFileName().toString().endsWith(".json")) + .toArray(Path[]::new); + + this.messageConfig.send(sender, MessageKey.CommandMigrateOperationFound, paths.length); + + for (Path file : paths) { + try { + UniqueId id = UniqueId.fromString(file.getFileName().toString()); + if (BackpackMigrator.migrate(folderPath, id)) { + statisticSuccessful++; + } else { + statisticFailed++; + } + } catch (Exception e) { + e.printStackTrace(); + statisticFailed++; + } + } + + this.messageConfig.send(sender, + MessageKey.CommandMigrateOperationDone, + paths.length, + statisticSuccessful, + statisticFailed, + Math.round((System.currentTimeMillis() - startTime) / 1000)); + } catch (IOException e) { + e.printStackTrace(); + this.messageConfig.send(sender, MessageKey.CommandMigrateOperationFailed); + } + } + + @Override + public void onTabComplete(CommandSender sender, String[] args, List result) { + } +} \ No newline at end of file diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/MessageConfig.java b/zip-plugin/src/main/java/net/imprex/zip/config/MessageConfig.java index aa40f5a..bf81c99 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/MessageConfig.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/MessageConfig.java @@ -20,7 +20,7 @@ import org.bukkit.configuration.file.YamlConfiguration; import net.imprex.zip.BackpackPlugin; -import net.imprex.zip.util.ZIPLogger; +import net.imprex.zip.common.ZIPLogger; import net.md_5.bungee.api.ChatColor; public class MessageConfig { diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java index 50e99e5..e55ad38 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java @@ -15,6 +15,7 @@ public enum MessageKey { CommandHelpGive("commandHelpGive", "§8/§7zip §egive §7[§etype§7] §7<§eplayer§7> §8| §7Give yourself a backpack§8."), CommandHelpType("commandHelpType", "§8/§7zip §etype §8| §7Get a list of all backpacks§8."), CommandHelpLore("commandHelpLore", "§8/§7zip §elore §8| §7Write a custom lore§8."), + CommandHelpMigrate("commandHelpMigrate", "§8/§7zip §emigrate §8| §7Migrate all existing backpacks to the new format§8."), CommandHelpEnd("commandHelpEnd", "§8[]§7========== §eZeroInventoryProblems §7==========§8[]"), CommandTypeStart("commandTypeStart", "§8[]§7========== §eZeroInventoryProblems Types §7==========§8[]"), CommandTypeContent("commandTypeContent", " §8-§e{0}"), @@ -60,7 +61,12 @@ public enum MessageKey { LoreLineChange("loreLineChange", "The lore line {0} was changed"), LoreLineDelete("loreLineDelete", "The lore line {0} was deleted"), MaxLoreCountReached("maxLoreCountReached", "You have reached the max lore count of {0}"), - UnableToLoadBackpack("unableToLoadBackpack", "Backpack can't be loaded!"); + UnableToLoadBackpack("unableToLoadBackpack", "Backpack id §8\"§e{0}§8\" §7can't be loaded!"), + CommandMigrateUsage("commandMigrateUsage", "Use: §8/§7zip migrate §econfirm"), + CommandMigrateOperationStartet("commandMigrateOperationStartet", "Starting migrating process, this coudt freeze the server for a moment"), + CommandMigrateOperationFound("commandMigrateOperationFound", "Migration found §e{0} §7outdated backpacks. Starting converting..."), + CommandMigrateOperationDone("commandMigrateOperationDone", "Migration finished. §e{0}§8/§e{1} §7backpacks migrated and §e{2} §7failed to migrate in §e{3} §7seconds."), + CommandMigrateOperationFailed("commandMigrateOperationFailed", "Migration failed. Look inside the console for more info"); public static MessageKey findByKey(String key) { for (MessageKey messageKey : values()) { diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/RecipeConfig.java b/zip-plugin/src/main/java/net/imprex/zip/config/RecipeConfig.java index 99d4d3c..67c335b 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/RecipeConfig.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/RecipeConfig.java @@ -6,7 +6,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; -import net.imprex.zip.util.ZIPLogger; +import net.imprex.zip.common.ZIPLogger; public class RecipeConfig { diff --git a/zip-plugin/src/main/resources/lang/en_US.yml b/zip-plugin/src/main/resources/lang/en_US.yml index 22be703..cbca6a6 100644 --- a/zip-plugin/src/main/resources/lang/en_US.yml +++ b/zip-plugin/src/main/resources/lang/en_US.yml @@ -11,6 +11,7 @@ commandHelpLink: "&8/&7zip &elink &7<&ecancel&7> &8| &7Link multiple backpacks o commandHelpGive: "&8/&7zip &egive &7[&etype&7] &7<&eplayer&7> &8| &7Give yourself a backpack&8." commandHelpType: "&8/&7zip &etype &8| &7Get a list of all backpacks&8." commandHelpLore: "&8/&7zip &elore &8| &7Write a custom lore&8." +CommandHelpMigrate: "&8/&7zip &emigrate &8| &7Migrate all existing backpacks to the new format&8." commandHelpEnd: "&8[]&7========== &eZeroInventoryProblems &7==========&8[]" commandTypeStart: "&8[]&7========== &eZeroInventoryProblems Types &7==========&8[]" commandTypeContent: " &8-&e{0}" @@ -51,4 +52,9 @@ loreLineCreate: "The lore line {0} was added" loreLineChange: "The lore line {0} was changed" loreLineDelete: "The lore line {0} was deleted" maxLoreCountReached: "You have reached the max lore count of {0}" -unableToLoadBackpack: "Backpack can't be loaded!" \ No newline at end of file +unableToLoadBackpack: "Backpack id &8\"&e{0}&8\" &7can't be loaded!" +commandMigrateUsage: "Use: &8/&7zip migrate &econfirm" +commandMigrateOperationStartet: "Starting migrating process, this coudt freeze the server for a moment" +commandMigrateOperationFound: "Migration found &e{0} &7outdated backpacks. Starting converting..." +commandMigrateOperationDone: "Migration finished. &e{0}&8/&e{1} &7backpacks migrated and &e{2} &7failed to migrate in &e{3} &7seconds" +commandMigrateOperationFailed: "Migration failed. Look inside the console for more info" \ No newline at end of file diff --git a/zip-plugin/src/main/resources/plugin.yml b/zip-plugin/src/main/resources/plugin.yml index e6e74b8..ea27ebc 100644 --- a/zip-plugin/src/main/resources/plugin.yml +++ b/zip-plugin/src/main/resources/plugin.yml @@ -31,6 +31,6 @@ permissions: zeroinventoryproblems.type: default: op description: A list of all backpack types - zeroinventoryproblems.lore: + zeroinventoryproblems.migrate: default: op - description: Change the lore of your current backpack \ No newline at end of file + description: Migrate all existing backpacks to the new format \ No newline at end of file From be16f5ea76ca0d11e37dd1545b393ec8e4c43b84 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Sun, 22 Jun 2025 05:05:56 +0200 Subject: [PATCH 4/8] feat: update UpdateSystem form Orebfuscator chore: remove unused class --- .../imprex/zip/common/ItemStackWithSlot.java | 6 - .../imprex/zip/common/MinecraftVersion.java | 128 ++-------- .../java/net/imprex/zip/common/Version.java | 107 +++++++++ .../java/net/imprex/zip/common/ZIPLogger.java | 8 + .../java/net/imprex/zip/UpdateSystem.java | 224 ++++++++++-------- .../imprex/zip/util/AbstractHttpService.java | 56 +++++ .../java/net/imprex/zip/util/ConsoleUtil.java | 115 +++++++++ 7 files changed, 426 insertions(+), 218 deletions(-) delete mode 100644 zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java create mode 100644 zip-common/src/main/java/net/imprex/zip/common/Version.java create mode 100644 zip-plugin/src/main/java/net/imprex/zip/util/AbstractHttpService.java create mode 100644 zip-plugin/src/main/java/net/imprex/zip/util/ConsoleUtil.java diff --git a/zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java b/zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java deleted file mode 100644 index 31bdd3c..0000000 --- a/zip-common/src/main/java/net/imprex/zip/common/ItemStackWithSlot.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.imprex.zip.common; - -import org.bukkit.inventory.ItemStack; - -public record ItemStackWithSlot(ItemStack item, int slot) { -} diff --git a/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java b/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java index cf3cc73..408c70f 100644 --- a/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java +++ b/zip-common/src/main/java/net/imprex/zip/common/MinecraftVersion.java @@ -1,18 +1,17 @@ +/** + * @author Imprex-Development + * @see MinecraftVersion.java + */ package net.imprex.zip.common; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.bukkit.Bukkit; -/** - * @author Imprex-Development - * @see https://github.com/Imprex-Development/orebfuscator/blob/master/orebfuscator-common/src/main/java/net/imprex/orebfuscator/util/MinecraftVersion.java - */ -public final class MinecraftVersion implements Comparable { +public final class MinecraftVersion { private static final class NmsMapping { @@ -27,11 +26,11 @@ private static final class NmsMapping { MAPPINGS.add(new NmsMapping("1.20.5", "v1_20_R4")); } - public static String get(MinecraftVersion version) { + public static String get(Version version) { for (NmsMapping mapping : MAPPINGS) { if (version.isAtOrAbove(mapping.version)) { if (mapping.version.minor() != version.minor()) { - System.out.println(String.format("Using nms mapping with mismatched minor versions: %s - %s", + ZIPLogger.warn(String.format("Using nms mapping with mismatched minor versions: %s - %s", mapping.version, version)); } @@ -42,19 +41,17 @@ public static String get(MinecraftVersion version) { throw new RuntimeException("Can't get nms package version for minecraft version: " + version); } - private final MinecraftVersion version; + private final Version version; private final String nmsVersion; public NmsMapping(String version, String nmsVersion) { - this.version = new MinecraftVersion(version); + this.version = Version.parse(version); this.nmsVersion = nmsVersion; } } - private static final Pattern VERSION_PATTERN = Pattern.compile("(?\\d+)(?:\\.(?\\d+))(?:\\.(?\\d+))?"); private static final Pattern PACKAGE_PATTERN = Pattern.compile("org\\.bukkit\\.craftbukkit\\.(v\\d+_\\d+_R\\d+)"); - - private static final MinecraftVersion CURRENT_VERSION = new MinecraftVersion(Bukkit.getBukkitVersion()); + private static final Version CURRENT_VERSION = Version.parse(Bukkit.getBukkitVersion()); private static String NMS_VERSION; @@ -73,118 +70,35 @@ public static String nmsVersion() { return NMS_VERSION; } + public static Version current() { + return CURRENT_VERSION; + } + public static int majorVersion() { - return CURRENT_VERSION.major; + return CURRENT_VERSION.major(); } public static int minorVersion() { - return CURRENT_VERSION.minor; + return CURRENT_VERSION.minor(); } public static int patchVersion() { - return CURRENT_VERSION.patch; + return CURRENT_VERSION.patch(); } public static boolean isAbove(String version) { - return CURRENT_VERSION.isAbove(new MinecraftVersion(version)); + return CURRENT_VERSION.isAbove(Version.parse(version)); } public static boolean isAtOrAbove(String version) { - return CURRENT_VERSION.isAtOrAbove(new MinecraftVersion(version)); + return CURRENT_VERSION.isAtOrAbove(Version.parse(version)); } public static boolean isAtOrBelow(String version) { - return CURRENT_VERSION.isAtOrBelow(new MinecraftVersion(version)); + return CURRENT_VERSION.isAtOrBelow(Version.parse(version)); } public static boolean isBelow(String version) { - return CURRENT_VERSION.isBelow(new MinecraftVersion(version)); - } - - private final int major; - private final int minor; - private final int patch; - - public MinecraftVersion(String version) { - Matcher matcher = VERSION_PATTERN.matcher(version); - - if (!matcher.find()) { - throw new IllegalArgumentException("can't parse minecraft version: " + version); - } - - this.major = Integer.parseInt(matcher.group("major")); - this.minor = Integer.parseInt(matcher.group("minor")); - - String patch = matcher.group("patch"); - if (patch != null) { - this.patch = Integer.parseInt(patch); - } else { - this.patch = 0; - } - } - - public int major() { - return this.major; - } - - public int minor() { - return this.minor; - } - - public int patch() { - return this.patch; - } - - public boolean isAbove(MinecraftVersion version) { - return this.compareTo(version) > 0; - } - - public boolean isAtOrAbove(MinecraftVersion version) { - return this.compareTo(version) >= 0; - } - - public boolean isAtOrBelow(MinecraftVersion version) { - return this.compareTo(version) <= 0; - } - - public boolean isBelow(MinecraftVersion version) { - return this.compareTo(version) < 0; - } - - @Override - public int compareTo(MinecraftVersion other) { - int major = Integer.compare(this.major, other.major); - if (major != 0) { - return major; - } - - int minor = Integer.compare(this.minor, other.minor); - if (minor != 0) { - return minor; - } - - return Integer.compare(this.patch, other.patch); - } - - @Override - public int hashCode() { - return Objects.hash(major, minor, patch); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof MinecraftVersion)) { - return false; - } - MinecraftVersion other = (MinecraftVersion) obj; - return major == other.major && minor == other.minor && patch == other.patch; - } - - @Override - public String toString() { - return String.format("%s.%s.%s", this.major, this.minor, this.patch); + return CURRENT_VERSION.isBelow(Version.parse(version)); } } \ No newline at end of file diff --git a/zip-common/src/main/java/net/imprex/zip/common/Version.java b/zip-common/src/main/java/net/imprex/zip/common/Version.java new file mode 100644 index 0000000..729f905 --- /dev/null +++ b/zip-common/src/main/java/net/imprex/zip/common/Version.java @@ -0,0 +1,107 @@ +/** + * @author Imprex-Development + * @see Version.java + */ +package net.imprex.zip.common; + +import java.io.IOException; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +public record Version(int major, int minor, int patch) implements Comparable { + + private static final Pattern VERSION_PATTERN = Pattern.compile("(?\\d+)(?:\\.(?\\d+))?(?:\\.(?\\d+))?"); + + public static Version parse(String version) { + Matcher matcher = VERSION_PATTERN.matcher(version); + + if (!matcher.find()) { + throw new IllegalArgumentException("can't parse version: " + version); + } + + int major = Integer.parseInt(matcher.group("major")); + + String minorGroup = matcher.group("minor"); + int minor = minorGroup != null + ? Integer.parseInt(minorGroup) + : 0; + + String patchGroup = matcher.group("patch"); + int patch = patchGroup != null + ? Integer.parseInt(patchGroup) + : 0; + + return new Version(major, minor, patch); + } + + public boolean isAbove(Version version) { + return this.compareTo(version) > 0; + } + + public boolean isAtOrAbove(Version version) { + return this.compareTo(version) >= 0; + } + + public boolean isAtOrBelow(Version version) { + return this.compareTo(version) <= 0; + } + + public boolean isBelow(Version version) { + return this.compareTo(version) < 0; + } + + @Override + public int compareTo(Version other) { + int major = Integer.compare(this.major, other.major); + if (major != 0) { + return major; + } + + int minor = Integer.compare(this.minor, other.minor); + if (minor != 0) { + return minor; + } + + return Integer.compare(this.patch, other.patch); + } + + @Override + public int hashCode() { + return Objects.hash(major, minor, patch); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Version)) { + return false; + } + Version other = (Version) obj; + return major == other.major && minor == other.minor && patch == other.patch; + } + + @Override + public String toString() { + return String.format("%s.%s.%s", this.major, this.minor, this.patch); + } + + public static final class Json extends TypeAdapter { + + @Override + public void write(JsonWriter out, Version value) throws IOException { + out.value(value.toString()); + } + + @Override + public Version read(JsonReader in) throws IOException { + return Version.parse(in.nextString()); + } + } +} \ No newline at end of file diff --git a/zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java b/zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java index 6c3c2b3..9d8a693 100644 --- a/zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java +++ b/zip-common/src/main/java/net/imprex/zip/common/ZIPLogger.java @@ -16,6 +16,10 @@ public static void setVerbose(boolean verbose) { ZIPLogger.verbose = verbose; } + public static void log(Level level, String message) { + ZIPLogger.logger.log(level, LOG_PREFIX + message); + } + public static void debug(String message) { if (ZIPLogger.verbose) { ZIPLogger.logger.log(Level.FINE, LOG_DEBUG_PREFIX + message); @@ -30,6 +34,10 @@ public static void warn(String message) { ZIPLogger.logger.log(Level.WARNING, LOG_PREFIX + message); } + public static void warn(String message, Throwable throwable) { + ZIPLogger.logger.log(Level.WARNING, LOG_PREFIX + message, throwable); + } + public static void error(String message, Throwable throwable) { ZIPLogger.logger.log(Level.SEVERE, LOG_PREFIX + message, throwable); } diff --git a/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java b/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java index 109af5f..a8cc6f4 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java +++ b/zip-plugin/src/main/java/net/imprex/zip/UpdateSystem.java @@ -1,59 +1,66 @@ +/** + * @author Imprex-Development + * @see UpdateSystem.java + */ package net.imprex.zip; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; + +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.google.gson.annotations.SerializedName; +import net.imprex.zip.common.MinecraftVersion; +import net.imprex.zip.common.Version; import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.config.GeneralConfig; import net.imprex.zip.config.MessageConfig; import net.imprex.zip.config.MessageKey; +import net.imprex.zip.util.AbstractHttpService; +import net.imprex.zip.util.ConsoleUtil; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.hover.content.Text; -/** - * @author Imprex-Development - * @see UpdateSystem.java - */ -public class UpdateSystem { - - private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-b(\\d+))?"); +public class UpdateSystem extends AbstractHttpService { - private static final String API_LATEST = "https://api.github.com/repos/Imprex-Development/zero-inventory-problems/releases/latest"; - private static final long UPDATE_COOLDOWN = 1_800_000L; // 30min + private static final Pattern DEV_VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-b(?\\d+))?"); - private static final String repeatString(String message, int repeat) { - StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < repeat; i++) { - stringBuilder.append(message); - } - return stringBuilder.toString(); + private static boolean isDevVersion(String version) { + Matcher matcher = DEV_VERSION_PATTERN.matcher(version); + return matcher.find() && matcher.group("build") != null; } - private final Lock lock = new ReentrantLock(); + private static final String API_URI = "https://api.modrinth.com/v2/project/zero-inventory-problems-zip-backpacks/version?loaders=%s&game_versions=%s"; + private static final String DOWNLOAD_URI = "https://modrinth.com/plugin/zero-inventory-problems-zip-backpacks/version/%s"; + + private static final Duration CACHE_DURATION = Duration.ofMinutes(10L); private final BackpackPlugin plugin; private final GeneralConfig generalConfig; private final MessageConfig messageConfig; - private JsonObject releaseData; - private long updateCooldown = -1; - private int failedAttempts = 0; + private final AtomicReference validUntil = new AtomicReference<>(); + private final AtomicReference>> latestVersion = new AtomicReference<>(); public UpdateSystem(BackpackPlugin plugin) { + super(plugin); + this.plugin = plugin; this.generalConfig = plugin.getBackpackConfig().general(); this.messageConfig = plugin.getBackpackConfig().message(); @@ -61,98 +68,105 @@ public UpdateSystem(BackpackPlugin plugin) { this.checkForUpdates(); } - private JsonObject getReleaseData() { - this.lock.lock(); - try { - long systemTime = System.currentTimeMillis(); - - if (this.failedAttempts < 5) { - - if (this.releaseData != null || systemTime - this.updateCooldown > UPDATE_COOLDOWN) { - try { - URL url = new URL(API_LATEST); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - try (InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream())) { - this.releaseData = JsonParser.parseReader(inputStreamReader).getAsJsonObject(); - this.updateCooldown = systemTime; - } - } catch (IOException e) { - ZIPLogger.warn("Unable to fetch latest update from: " + API_LATEST); - ZIPLogger.warn(e.toString()); - - if (++this.failedAttempts == 5) { - this.updateCooldown = systemTime; - } - } - } - - } else if (systemTime - this.updateCooldown > UPDATE_COOLDOWN) { - this.failedAttempts = 0; - this.updateCooldown = -1; - return this.getReleaseData(); - } - - return this.releaseData; - } finally { - this.lock.unlock(); + private CompletableFuture> requestLatestVersion() { + String installedVersion = this.plugin.getDescription().getVersion(); + if (!this.generalConfig.checkForUpdates || isDevVersion(installedVersion)) { + ZIPLogger.debug("UpdateSystem - Update check disabled or dev version detected; skipping"); + return CompletableFuture.completedFuture(Optional.empty()); } - } - private String getTagName() { - JsonObject releaseData = this.getReleaseData(); - if (releaseData != null && releaseData.has("tag_name")) { - return releaseData.getAsJsonPrimitive("tag_name").getAsString(); - } - return null; + var uri = String.format(API_URI, "bukkit", MinecraftVersion.current()); + return HTTP.sendAsync(request(uri).build(), json(ModrinthVersion[].class)).thenApply(request -> { + var version = Version.parse(installedVersion); + var latestVersion = Arrays.stream(request.body()) + .filter(e -> Objects.equals(e.versionType, "release")) + .filter(e -> Objects.equals(e.status, "listed")) + .sorted(Comparator.reverseOrder()) + .findFirst(); + + latestVersion.ifPresentOrElse( + v -> ZIPLogger.debug("UpdateSystem - Fetched latest version " + v.version), + () -> ZIPLogger.debug("UpdateSystem - Couldn't fetch latest version")); + + return latestVersion.map(v -> version.isBelow(v.version) ? v : null); + }).exceptionally(throwable -> { + ZIPLogger.warn("UpdateSystem - Unable to fetch latest version", throwable); + return Optional.empty(); + }); } - private String getHtmlUrl() { - JsonObject releaseData = this.getReleaseData(); - if (releaseData != null && releaseData.has("html_url")) { - return releaseData.getAsJsonPrimitive("html_url").getAsString(); + private CompletableFuture> getLatestVersion() { + Instant validUntil = this.validUntil.get(); + if (validUntil != null && validUntil.compareTo(Instant.now()) < 0 && this.validUntil.compareAndSet(validUntil, null)) { + ZIPLogger.debug("UpdateSystem - Cleared latest cached version"); + this.latestVersion.set(null); } - return null; - } - private boolean isDevVersion(String version) { - Matcher matcher = VERSION_PATTERN.matcher(version); - return matcher.find() && matcher.groupCount() == 4; + CompletableFuture> existingFuture = this.latestVersion.get(); + if (existingFuture != null) { + return existingFuture; + } + + CompletableFuture> newFuture = new CompletableFuture<>(); + if (this.latestVersion.compareAndSet(null, newFuture)) { + ZIPLogger.debug("UpdateSystem - Starting to check for updates"); + this.requestLatestVersion().thenAccept(version -> { + this.validUntil.set(Instant.now().plus(CACHE_DURATION)); + newFuture.complete(version); + }); + return newFuture; + } else { + return this.latestVersion.get(); + } } - private boolean isUpdateAvailable() { - String version = this.plugin.getDescription().getVersion(); - if (this.generalConfig.checkForUpdates && !this.isDevVersion(version)) { - String tagName = this.getTagName(); - return tagName != null && !version.equals(tagName); - } - return false; + private void ifNewerVersionAvailable(Consumer consumer) { + this.getLatestVersion().thenAccept(o -> o.ifPresent(consumer)); } private void checkForUpdates() { - Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { - if (this.isUpdateAvailable()) { - String url = " " + this.getHtmlUrl() + " "; - int lineLength = (int) Math.ceil((url.length() - 18) / 2d); - String line = repeatString("=", lineLength); - - ZIPLogger.warn(line + " Update available " + line); - ZIPLogger.warn(url); - ZIPLogger.warn(repeatString("=", lineLength * 2 + 18)); - } + this.ifNewerVersionAvailable(version -> { + String downloadUri = String.format(DOWNLOAD_URI, version.version); + ConsoleUtil.printBox(Level.WARNING, "UPDATE AVAILABLE", "", downloadUri); }); } public void checkForUpdates(Player player) { - Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { - if (this.isUpdateAvailable()) { - BaseComponent[] components = new ComponentBuilder(String.format("%s%s ", this.messageConfig.get(MessageKey.ANewReleaseIsAvailable))) - .append(this.messageConfig.getWithoutPrefix(MessageKey.ClickHere)) - .event(new ClickEvent(ClickEvent.Action.OPEN_URL, this.getHtmlUrl())) - .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(this.messageConfig.getWithoutPrefix(MessageKey.ClickHereToSeeTheLatestRelease)))).create(); - Bukkit.getScheduler().runTask(this.plugin, () -> { - player.spigot().sendMessage(components); - }); - } + this.ifNewerVersionAvailable(version -> { + String downloadUri = String.format(DOWNLOAD_URI, version.version); + BaseComponent[] components = new ComponentBuilder(String.format("%s%s ", this.messageConfig.get(MessageKey.ANewReleaseIsAvailable))) + .append(this.messageConfig.getWithoutPrefix(MessageKey.ClickHere)) + .event(new ClickEvent(ClickEvent.Action.OPEN_URL, downloadUri)) + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder(this.messageConfig.getWithoutPrefix(MessageKey.ClickHereToSeeTheLatestRelease)).create()))).create(); + Bukkit.getScheduler().runTask(this.plugin, () -> { + player.spigot().sendMessage(components); + }); }); } -} \ No newline at end of file + + public static class ModrinthVersion implements Comparable { + + private static final Comparator COMPARATOR = + Comparator.comparing(e -> e.version, Comparator.nullsLast(Version::compareTo)); + + @SerializedName("version_number") + public Version version; + + @SerializedName("game_versions") + public List gameVersions; + + @SerializedName("version_type") + public String versionType; + + @SerializedName("loaders") + public List loaders; + + @SerializedName("status") + public String status; + + @Override + public int compareTo(ModrinthVersion other) { + return COMPARATOR.compare(this, other); + } + } +} diff --git a/zip-plugin/src/main/java/net/imprex/zip/util/AbstractHttpService.java b/zip-plugin/src/main/java/net/imprex/zip/util/AbstractHttpService.java new file mode 100644 index 0000000..2c0fee8 --- /dev/null +++ b/zip-plugin/src/main/java/net/imprex/zip/util/AbstractHttpService.java @@ -0,0 +1,56 @@ +/** + * @author Imprex-Development + * @see AbstractHttpService.java + */ +package net.imprex.zip.util; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandler; +import java.net.http.HttpResponse.BodySubscribers; + +import org.bukkit.plugin.PluginDescriptionFile; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import net.imprex.zip.BackpackPlugin; +import net.imprex.zip.common.Version; + +public abstract class AbstractHttpService { + + public static final Gson GSON = new GsonBuilder().setPrettyPrinting() + .registerTypeAdapter(Version.class, new Version.Json()) + .create(); + + public static final HttpClient HTTP = HttpClient.newHttpClient(); + + protected final String userAgent; + + public AbstractHttpService(BackpackPlugin plugin) { + PluginDescriptionFile pluginDescription = plugin.getDescription(); + this.userAgent = String.format("%s/%s", pluginDescription.getName(), pluginDescription.getVersion()); + } + + protected HttpRequest.Builder request(String url) { + return HttpRequest.newBuilder(URI.create(url)) + .header("User-Agent", userAgent) + .header("Accept", "application/json"); + } + + protected static BodyHandler json(Class target) { + return (responseInfo) -> responseInfo.statusCode() == 200 + ? BodySubscribers.mapping(BodySubscribers.ofInputStream(), inputStream -> { + try (InputStreamReader reader = new InputStreamReader(inputStream)) { + return GSON.fromJson(new InputStreamReader(inputStream), target); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + }) + : BodySubscribers.replacing(null); + } +} diff --git a/zip-plugin/src/main/java/net/imprex/zip/util/ConsoleUtil.java b/zip-plugin/src/main/java/net/imprex/zip/util/ConsoleUtil.java new file mode 100644 index 0000000..733aa52 --- /dev/null +++ b/zip-plugin/src/main/java/net/imprex/zip/util/ConsoleUtil.java @@ -0,0 +1,115 @@ +/** + * @author Imprex-Development + * @see ConsoleUtil.java + */ +package net.imprex.zip.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; + +import org.bukkit.ChatColor; + +import net.imprex.zip.common.ZIPLogger; + +public final class ConsoleUtil { + + private static final int BOX_PADDING = 3; + private static final int BOX_PREFERRED_WIDTH = 48; + + private ConsoleUtil() { + } + + public static String replaceAnsiColorWithChatColor(String value) { + value = value.replaceAll("\u001B\\[m", ChatColor.RESET.toString()); + value = value.replaceAll("\u001B\\[31;1m", ChatColor.RED.toString()); + value = value.replaceAll("\u001B\\[33;1m", ChatColor.YELLOW.toString()); + return value; + } + + public static void printBox(Level level, String...lines) { + for (String line : createBox(lines)) { + ZIPLogger.log(level, line); + } + } + + /** + * Creates a ASCII box around the given lines + */ + public static Iterable createBox(String...lines) { + + List wrappedLines = new ArrayList<>(); + for (String line : lines) { + line = line.trim(); + + while (line.length() > BOX_PREFERRED_WIDTH) { + + int splitLength = 0; + for (int i = 0; i < line.length(); i++) { + if (Character.isWhitespace(line.charAt(i))) { + if (i <= BOX_PREFERRED_WIDTH) { + splitLength = i; + } else { + break; + } + } + } + + // can't split line no whitespace character found + if (splitLength == 0) { + break; + } + + // split line at latest word that fit length + wrappedLines.add(line.substring(0, splitLength)); + line = line.substring(splitLength, line.length()).trim(); + } + + // add remainder + wrappedLines.add(line); + } + + // get max line width + int width = 0; + for (String line : wrappedLines) { + width = Math.max(width, line.length()); + } + + // add padding + int totalWidth = width + BOX_PADDING * 2; + + // create top/bottom lines + String bottomTopLine = repeat('-', totalWidth); + String topLine = String.format("+%s+", bottomTopLine); + String bottomLine = String.format("+%s+", bottomTopLine); + + // create box + List box = new ArrayList<>(wrappedLines.size() + 2); + box.add(topLine); + + for (String line : wrappedLines) { + int space = totalWidth - line.length(); + + // center line + String leftPadding, rightPadding; + if (space % 2 == 0) { + leftPadding = rightPadding = repeat(' ', space / 2); + } else { + leftPadding = repeat(' ', space / 2 + 1); + rightPadding = repeat(' ', space / 2); + } + + box.add(String.format("|%s%s%s|", leftPadding, line, rightPadding)); + } + + box.add(bottomLine); + return box; + } + + private static String repeat(char character, int length) { + char[] string = new char[length]; + Arrays.fill(string, character); + return new String(string); + } +} From 41e6ef0997c8ce6246998e3340f70b8c975b61a6 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Sun, 22 Jun 2025 05:13:18 +0200 Subject: [PATCH 5/8] fix: #3 linking multiply items at the same time --- .../src/main/java/net/imprex/zip/command/LinkCommand.java | 3 +++ zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java | 1 + zip-plugin/src/main/resources/lang/en_US.yml | 1 + 3 files changed, 5 insertions(+) diff --git a/zip-plugin/src/main/java/net/imprex/zip/command/LinkCommand.java b/zip-plugin/src/main/java/net/imprex/zip/command/LinkCommand.java index 49dbe18..da4f1e3 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/command/LinkCommand.java +++ b/zip-plugin/src/main/java/net/imprex/zip/command/LinkCommand.java @@ -71,6 +71,9 @@ public void onCommand(CommandSender sender, String[] args) { } else if (linkingBackpack.equals(backpack)) { this.messageConfig.send(player, MessageKey.ThisBackpackIsAlreadyLinkedThoThat); return; + } else if (item.getAmount() > 1) { + this.messageConfig.send(player, MessageKey.StackedBackpacksCanNotBeLinked); + return; } linkingBackpack.applyOnItem(item); diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java index e55ad38..42a2bab 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java @@ -55,6 +55,7 @@ public enum MessageKey { YourBackpackLinkRequestWasCancelled("yourBackpackLinkRequestWasCancelled", "Your backpack link request was cancelled"), BothBackpacksNeedToBeTheSameType("bothBackpacksNeedToBeTheSameType", "Both Backpacks need to be the same type"), ThisBackpackIsAlreadyLinkedThoThat("thisBackpackIsAlreadyLinkedThoThat", "This backpack is already linked to that backpack"), + StackedBackpacksCanNotBeLinked("stackedBackpacksCanNotBeLinked", "Stacked backpacks can not be linked at the same time"), PleaseEnterANumber("pleaseEnterANumber", "Please enter a number"), EnterANumberBetweenArgsAndArgs("enterANumberBetweenArgsAndArgs", "Please enter a number between {0} and {1}"), LoreLineCreate("loreLineCreate", "The lore line {0} was added"), diff --git a/zip-plugin/src/main/resources/lang/en_US.yml b/zip-plugin/src/main/resources/lang/en_US.yml index cbca6a6..2e576f1 100644 --- a/zip-plugin/src/main/resources/lang/en_US.yml +++ b/zip-plugin/src/main/resources/lang/en_US.yml @@ -46,6 +46,7 @@ youNeedToLinkABackpackFirst: "You need to link a backpack at first" yourBackpackLinkRequestWasCancelled: "Your backpack link request was cancelled" bothBackpacksNeedToBeTheSameType: "Both Backpacks need to be the same type" thisBackpackIsAlreadyLinkedThoThat: "This backpack is already linked to that backpack" +stackedBackpacksCanNotBeLinked: "Stacked backpacks can not be linked at the same time" pleaseEnterANumber: "Please enter a number" enterANumberBetweenArgsAndArgs: "Please enter a number between {0} and {1}" loreLineCreate: "The lore line {0} was added" From 52ddf1ab497610c9106f1d438380d8a105c59d7d Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Sun, 22 Jun 2025 05:24:44 +0200 Subject: [PATCH 6/8] fix: misselled words --- .../main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java | 4 ++-- .../main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java | 4 ++-- .../src/main/java/net/imprex/zip/command/MigrateCommand.java | 2 +- .../src/main/java/net/imprex/zip/config/MessageKey.java | 2 +- zip-plugin/src/main/resources/lang/en_US.yml | 2 +- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java index 010d656..cf5324b 100644 --- a/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java @@ -110,7 +110,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -123,7 +123,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java index 0910343..f0f024f 100644 --- a/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java @@ -110,7 +110,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -123,7 +123,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java index e9b23ae..f32a059 100644 --- a/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java @@ -110,7 +110,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -123,7 +123,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java index 555a558..97e91b4 100644 --- a/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java @@ -110,7 +110,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -123,7 +123,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java index 56317e8..96d9f2b 100644 --- a/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java @@ -110,7 +110,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -123,7 +123,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java index 9c50fc9..8670d6c 100644 --- a/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java @@ -111,7 +111,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -124,7 +124,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java index 7fe0201..37c759b 100644 --- a/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java @@ -110,7 +110,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -123,7 +123,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java index c7edd26..28e09f9 100644 --- a/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java @@ -145,7 +145,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -158,7 +158,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java index 2e0e917..adcfd53 100644 --- a/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java @@ -145,7 +145,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -158,7 +158,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java index 00966f7..a62bc35 100644 --- a/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java @@ -145,7 +145,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -158,7 +158,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java index 33796a9..ca54aa2 100644 --- a/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java @@ -145,7 +145,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -158,7 +158,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java index 6d04582..a1e5461 100644 --- a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java @@ -145,7 +145,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { if (itemsSize <= slot) { // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); ItemStack[] newItems = new ItemStack[slot + 1]; System.arraycopy(items, 0, newItems, 0, items.length); @@ -158,7 +158,7 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { duplicateSlot = new ArrayList<>(); } duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this shoudt not happen. Do not change the slot number inside the config manuel!?"); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); } else { items[slot] = bukkitItem; } diff --git a/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java b/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java index 32623e7..3b68283 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java +++ b/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java @@ -36,7 +36,7 @@ public void onCommand(CommandSender sender, String[] args) { int statisticSuccessful = 0; int statisticFailed = 0; - this.messageConfig.send(sender, MessageKey.CommandMigrateOperationStartet); + this.messageConfig.send(sender, MessageKey.CommandMigrateOperationStarted); Path folderPath = Path.of(plugin.getDataFolder().getAbsolutePath(), "storage"); try (Stream stream = Files.walk(folderPath, 1)) { diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java index 42a2bab..5bce715 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java @@ -64,7 +64,7 @@ public enum MessageKey { MaxLoreCountReached("maxLoreCountReached", "You have reached the max lore count of {0}"), UnableToLoadBackpack("unableToLoadBackpack", "Backpack id §8\"§e{0}§8\" §7can't be loaded!"), CommandMigrateUsage("commandMigrateUsage", "Use: §8/§7zip migrate §econfirm"), - CommandMigrateOperationStartet("commandMigrateOperationStartet", "Starting migrating process, this coudt freeze the server for a moment"), + CommandMigrateOperationStarted("commandMigrateOperationStarted", "Starting migrating process, this could freeze the server for a moment"), CommandMigrateOperationFound("commandMigrateOperationFound", "Migration found §e{0} §7outdated backpacks. Starting converting..."), CommandMigrateOperationDone("commandMigrateOperationDone", "Migration finished. §e{0}§8/§e{1} §7backpacks migrated and §e{2} §7failed to migrate in §e{3} §7seconds."), CommandMigrateOperationFailed("commandMigrateOperationFailed", "Migration failed. Look inside the console for more info"); diff --git a/zip-plugin/src/main/resources/lang/en_US.yml b/zip-plugin/src/main/resources/lang/en_US.yml index 2e576f1..d0773e2 100644 --- a/zip-plugin/src/main/resources/lang/en_US.yml +++ b/zip-plugin/src/main/resources/lang/en_US.yml @@ -55,7 +55,7 @@ loreLineDelete: "The lore line {0} was deleted" maxLoreCountReached: "You have reached the max lore count of {0}" unableToLoadBackpack: "Backpack id &8\"&e{0}&8\" &7can't be loaded!" commandMigrateUsage: "Use: &8/&7zip migrate &econfirm" -commandMigrateOperationStartet: "Starting migrating process, this coudt freeze the server for a moment" +commandMigrateOperationStarted: "Starting migrating process, this could freeze the server for a moment" commandMigrateOperationFound: "Migration found &e{0} &7outdated backpacks. Starting converting..." commandMigrateOperationDone: "Migration finished. &e{0}&8/&e{1} &7backpacks migrated and &e{2} &7failed to migrate in &e{3} &7seconds" commandMigrateOperationFailed: "Migration failed. Look inside the console for more info" \ No newline at end of file From f4508df46bf7d8f8636cceb934e107216e2431a3 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Sun, 22 Jun 2025 19:30:09 +0200 Subject: [PATCH 7/8] feat: remove migrate command and migrate all on startup --- .../net/imprex/zip/common/BPConstants.java | 19 ++++ .../java/net/imprex/zip/common/BPKey.java | 16 ---- .../zip/nms/api/ItemStackContainerResult.java | 6 ++ .../imprex/zip/nms/api/ItemStackWithSlot.java | 6 ++ .../net/imprex/zip/nms/api/NmsManager.java | 2 +- .../zip/nms/v1_19_R1/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_19_R2/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_19_R3/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_20_R1/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_20_R2/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_20_R3/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_20_R4/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_21_R1/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_21_R2/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_21_R3/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_21_R4/ZipNmsManager.java | 93 +++++-------------- .../zip/nms/v1_21_R5/ZipNmsManager.java | 93 +++++-------------- .../main/java/net/imprex/zip/Backpack.java | 86 +++++++++++++++-- .../java/net/imprex/zip/BackpackHandler.java | 16 +++- .../java/net/imprex/zip/BackpackMigrator.java | 61 +++++++++++- .../java/net/imprex/zip/BackpackPlugin.java | 2 + .../main/java/net/imprex/zip/NmsInstance.java | 3 +- .../imprex/zip/command/BackpackCommand.java | 1 - .../imprex/zip/command/MigrateCommand.java | 80 ---------------- .../net/imprex/zip/config/MessageKey.java | 7 +- zip-plugin/src/main/resources/lang/en_US.yml | 7 +- 26 files changed, 450 insertions(+), 978 deletions(-) create mode 100644 zip-common/src/main/java/net/imprex/zip/common/BPConstants.java delete mode 100644 zip-common/src/main/java/net/imprex/zip/common/BPKey.java create mode 100644 zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackContainerResult.java create mode 100644 zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackWithSlot.java delete mode 100644 zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java diff --git a/zip-common/src/main/java/net/imprex/zip/common/BPConstants.java b/zip-common/src/main/java/net/imprex/zip/common/BPConstants.java new file mode 100644 index 0000000..a7f1cc1 --- /dev/null +++ b/zip-common/src/main/java/net/imprex/zip/common/BPConstants.java @@ -0,0 +1,19 @@ +package net.imprex.zip.common; + +public class BPConstants { + + public static final int VERSION = 2; + public static final int INVENTORY_VERSION = 2; + + public static final String KEY_VERSION = "version"; + + public static final String KEY_ID = "id"; + public static final String KEY_TYPE_RAW = "typeRaw"; + public static final String KEY_INVENTORY = "inventory"; + + public static final String KEY_INVENTORY_VERSION = "version"; + public static final String KEY_INVENTORY_DATA_VERSION = "dataVersion"; + public static final String KEY_INVENTORY_ITEMS = "items"; + public static final String KEY_INVENTORY_ITEMS_SIZE = "itemsSize"; + public static final String KEY_INVENTORY_SLOT = "ZIPslot"; +} diff --git a/zip-common/src/main/java/net/imprex/zip/common/BPKey.java b/zip-common/src/main/java/net/imprex/zip/common/BPKey.java deleted file mode 100644 index 62fd9c6..0000000 --- a/zip-common/src/main/java/net/imprex/zip/common/BPKey.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.imprex.zip.common; - -public class BPKey { - - public static final String VERSION = "version"; - - public static final String ID = "id"; - public static final String TYPE_RAW = "typeRaw"; - public static final String INVENTORY = "inventory"; - - public static final String INVENTORY_VERSION = "version"; - public static final String INVENTORY_DATA_VERSION = "dataVersion"; - public static final String INVENTORY_ITEMS = "items"; - public static final String INVENTORY_ITEMS_SIZE = "itemsSize"; - public static final String INVENTORY_SLOT = "ZIPslot"; -} diff --git a/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackContainerResult.java b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackContainerResult.java new file mode 100644 index 0000000..3e5390d --- /dev/null +++ b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackContainerResult.java @@ -0,0 +1,6 @@ +package net.imprex.zip.nms.api; + +import java.util.List; + +public record ItemStackContainerResult(int containerSize, List items) { +} diff --git a/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackWithSlot.java b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackWithSlot.java new file mode 100644 index 0000000..d1bdc29 --- /dev/null +++ b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/ItemStackWithSlot.java @@ -0,0 +1,6 @@ +package net.imprex.zip.nms.api; + +import org.bukkit.inventory.ItemStack; + +public record ItemStackWithSlot(int slot, ItemStack item) { +} diff --git a/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java index 9a8bbe9..01c789d 100644 --- a/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java +++ b/zip-nms/zip-nms-api/src/main/java/net/imprex/zip/nms/api/NmsManager.java @@ -10,7 +10,7 @@ public interface NmsManager { JsonObject itemstackToJsonElement(ItemStack[] items); - ItemStack[] jsonElementToItemStack(JsonObject jsonElement); + ItemStackContainerResult jsonElementToItemStack(JsonObject jsonElement); JsonObject migrateToJsonElement(byte[] binary); diff --git a/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java index cf5324b..36fae81 100644 --- a/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R1/src/main/java/net/imprex/zip/nms/v1_19_R1/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -67,35 +66,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -106,56 +101,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(false, error -> {}); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -188,7 +139,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -196,10 +147,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java index f0f024f..3410dfc 100644 --- a/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R2/src/main/java/net/imprex/zip/nms/v1_19_R2/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -67,35 +66,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -106,56 +101,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(false, error -> {}); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -188,7 +139,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -196,10 +147,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java index f32a059..2afcf22 100644 --- a/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_19_R3/src/main/java/net/imprex/zip/nms/v1_19_R3/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -67,35 +66,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -106,56 +101,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(false, error -> {}); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -188,7 +139,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -196,10 +147,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java index 97e91b4..5b72e6a 100644 --- a/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R1/src/main/java/net/imprex/zip/nms/v1_20_R1/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -67,35 +66,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -106,56 +101,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(false, error -> {}); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -188,7 +139,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -196,10 +147,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java index 96d9f2b..4b9eb75 100644 --- a/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R2/src/main/java/net/imprex/zip/nms/v1_20_R2/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -67,35 +66,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -106,56 +101,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(false, error -> {}); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -188,7 +139,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -196,10 +147,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java index 8670d6c..ac7c775 100644 --- a/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R3/src/main/java/net/imprex/zip/nms/v1_20_R3/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -68,35 +67,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -107,56 +102,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(false, error -> {}); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -189,7 +140,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow(false, error -> {}).getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -197,10 +148,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java b/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java index 37c759b..b168ca8 100644 --- a/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_20_R4/src/main/java/net/imprex/zip/nms/v1_20_R4/ZipNmsManager.java @@ -4,8 +4,6 @@ import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -24,9 +22,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -67,35 +66,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -106,56 +101,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -188,7 +139,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -196,10 +147,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java index 28e09f9..dac5638 100644 --- a/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R1/src/main/java/net/imprex/zip/nms/v1_21_R1/ZipNmsManager.java @@ -5,8 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -26,9 +24,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -102,35 +101,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -141,56 +136,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -223,7 +174,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -231,10 +182,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java index adcfd53..391ce46 100644 --- a/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R2/src/main/java/net/imprex/zip/nms/v1_21_R2/ZipNmsManager.java @@ -5,8 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -26,9 +24,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -102,35 +101,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -141,56 +136,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -223,7 +174,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -231,10 +182,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java index a62bc35..bc8d73e 100644 --- a/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java @@ -5,8 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -26,9 +24,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -102,35 +101,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -141,56 +136,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -223,7 +174,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -231,10 +182,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java index ca54aa2..063907b 100644 --- a/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R4/src/main/java/net/imprex/zip/nms/v1_21_R4/ZipNmsManager.java @@ -5,8 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -26,9 +24,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -102,35 +101,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -141,56 +136,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -223,7 +174,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -231,10 +182,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java index a1e5461..41a9020 100644 --- a/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java +++ b/zip-nms/zip-nms-v1_21_R5/src/main/java/net/imprex/zip/nms/v1_21_R5/ZipNmsManager.java @@ -5,8 +5,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; @@ -26,9 +24,10 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.ReflectionUtil; -import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; import net.imprex.zip.nms.api.NmsManager; import net.minecraft.SharedConstants; import net.minecraft.core.RegistryAccess; @@ -102,35 +101,31 @@ public JsonObject itemstackToJsonElement(ItemStack[] items) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, slot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); jsonItems.add(resultJson); } JsonObject outputJson = new JsonObject(); - outputJson.addProperty(BPKey.INVENTORY_VERSION, 2); - outputJson.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - outputJson.addProperty(BPKey.INVENTORY_ITEMS_SIZE, items.length); - outputJson.add(BPKey.INVENTORY_ITEMS, jsonItems); + outputJson.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + outputJson.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, items.length); + outputJson.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return outputJson; } @Override - public ItemStack[] jsonElementToItemStack(JsonObject json) { + public ItemStackContainerResult jsonElementToItemStack(JsonObject json) { // check if current version the same - if (json.get(BPKey.INVENTORY_VERSION).getAsInt() != 2) { + if (json.get(BPConstants.KEY_INVENTORY_VERSION).getAsInt() != BPConstants.INVENTORY_VERSION) { throw new IllegalStateException("Unable to convert binary to itemstack because zip version is missmatching"); } - int dataVersion = json.get(BPKey.INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPKey.INVENTORY_ITEMS_SIZE).getAsInt(); + int dataVersion = json.get(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - // convert json into bukkit item - ItemStack[] items = new ItemStack[itemsSize]; - Arrays.fill(items, new ItemStack(Material.AIR)); + List items = new ArrayList<>(); - List duplicateSlot = null; - - JsonArray jsonItems = json.get(BPKey.INVENTORY_ITEMS).getAsJsonArray(); + JsonArray jsonItems = json.get(BPConstants.KEY_INVENTORY_ITEMS).getAsJsonArray(); for (JsonElement item : jsonItems) { Dynamic dynamicItem = new Dynamic<>(JsonOps.INSTANCE, item); Dynamic dynamicItemFixed = DataFixers.getDataFixer() @@ -141,56 +136,12 @@ public ItemStack[] jsonElementToItemStack(JsonObject json) { .getOrThrow(); ItemStack bukkitItem = CraftItemStack.asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPKey.INVENTORY_SLOT).getAsInt(); - - if (itemsSize <= slot) { - // something went wrong !? maybe user modified it him self - ZIPLogger.warn("Slot size was extended from " + itemsSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - - ItemStack[] newItems = new ItemStack[slot + 1]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - if (items[slot].getType() != Material.AIR) { - if (duplicateSlot == null) { - duplicateSlot = new ArrayList<>(); - } - duplicateSlot.add(bukkitItem); - ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); - } else { - items[slot] = bukkitItem; - } - } - - // fill existing empty slots with duplicate item - while (duplicateSlot != null && !duplicateSlot.isEmpty()) { - outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { - ItemStack itemStack = (ItemStack) iterator.next(); - - for (int i = 0; i < items.length; i++) { - if (items[i].getType() == Material.AIR) { - items[i] = itemStack; - iterator.remove(); - break; - } else if (i == items.length - 1) { - break outher; - } - } - } - - // extend slot limit and try again - if (!duplicateSlot.isEmpty()) { - int extendedSlots = items.length + duplicateSlot.size(); - ItemStack[] newItems = new ItemStack[extendedSlots]; - System.arraycopy(items, 0, newItems, 0, items.length); - Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); - items = newItems; - } + items.add(new ItemStackWithSlot(slot, bukkitItem)); } - return items; + return new ItemStackContainerResult(itemsSize, items); } @Override @@ -223,7 +174,7 @@ public JsonObject migrateToJsonElement(byte[] binary) { DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - resultJson.addProperty(BPKey.INVENTORY_SLOT, currentSlot); + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, currentSlot); jsonItems.add(resultJson); currentSlot++; @@ -231,10 +182,10 @@ public JsonObject migrateToJsonElement(byte[] binary) { } JsonObject json = new JsonObject(); - json.addProperty(BPKey.INVENTORY_VERSION, 2); - json.addProperty(BPKey.INVENTORY_DATA_VERSION, DATA_VERSION); - json.addProperty(BPKey.INVENTORY_ITEMS_SIZE, list.size()); - json.add(BPKey.INVENTORY_ITEMS, jsonItems); + json.addProperty(BPConstants.KEY_INVENTORY_VERSION, BPConstants.INVENTORY_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_DATA_VERSION, DATA_VERSION); + json.addProperty(BPConstants.KEY_INVENTORY_ITEMS_SIZE, list.size()); + json.add(BPConstants.KEY_INVENTORY_ITEMS, jsonItems); return json; } diff --git a/zip-plugin/src/main/java/net/imprex/zip/Backpack.java b/zip-plugin/src/main/java/net/imprex/zip/Backpack.java index 57a7b89..0ae87ce 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/Backpack.java +++ b/zip-plugin/src/main/java/net/imprex/zip/Backpack.java @@ -1,5 +1,9 @@ package net.imprex.zip; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -17,10 +21,13 @@ import com.google.gson.JsonObject; import net.imprex.zip.api.ZIPBackpack; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.UniqueId; +import net.imprex.zip.common.ZIPLogger; import net.imprex.zip.config.MessageConfig; import net.imprex.zip.config.MessageKey; +import net.imprex.zip.nms.api.ItemStackContainerResult; +import net.imprex.zip.nms.api.ItemStackWithSlot; public class Backpack implements ZIPBackpack { @@ -74,11 +81,12 @@ public Backpack(BackpackPlugin plugin, UniqueId id, JsonObject json) { this.id = id; - this.typeRaw = json.get(BPKey.TYPE_RAW).getAsString(); + this.typeRaw = json.get(BPConstants.KEY_TYPE_RAW).getAsString(); this.type = plugin.getBackpackRegistry().getTypeByName(this.typeRaw); - JsonObject contentAsJson = json.getAsJsonObject(BPKey.INVENTORY); - ItemStack[] content = NmsInstance.jsonElementToItemStack(contentAsJson); + JsonObject contentAsJson = json.getAsJsonObject(BPConstants.KEY_INVENTORY); + ItemStackContainerResult contentResult = NmsInstance.jsonElementToItemStack(contentAsJson); + ItemStack[] content = this.parseItemStackList(contentResult); this.content = content; if (this.type != null) { @@ -103,6 +111,68 @@ public Backpack(BackpackPlugin plugin, UniqueId id, JsonObject json) { this.backpackHandler.registerBackpack(this); } + + private ItemStack[] parseItemStackList(ItemStackContainerResult result) { + int containerSize = result.containerSize(); + + ItemStack[] items = new ItemStack[containerSize]; + Arrays.fill(items, new ItemStack(Material.AIR)); + + List duplicateSlot = null; + + for (ItemStackWithSlot itemWithSlot : result.items()) { + ItemStack item = itemWithSlot.item(); + int slot = itemWithSlot.slot(); + + if (containerSize <= slot) { + // something went wrong !? maybe user modified it him self + ZIPLogger.warn("Slot size was extended from " + containerSize + " to " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); + + ItemStack[] newItems = new ItemStack[slot + 1]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + + if (items[slot].getType() != Material.AIR) { + if (duplicateSlot == null) { + duplicateSlot = new ArrayList<>(); + } + duplicateSlot.add(item); + ZIPLogger.warn("Duplicate item found on slot " + slot + " this should not happen. Do not change the slot number inside the config manually!?"); + } else { + items[slot] = item; + } + } + + // fill existing empty slots with duplicate item + while (duplicateSlot != null && !duplicateSlot.isEmpty()) { + outher: for (Iterator iterator = duplicateSlot.iterator(); iterator.hasNext();) { + ItemStack itemStack = (ItemStack) iterator.next(); + + for (int i = 0; i < items.length; i++) { + if (items[i].getType() == Material.AIR) { + items[i] = itemStack; + iterator.remove(); + break; + } else if (i == items.length - 1) { + break outher; + } + } + } + + // extend slot limit and try again + if (!duplicateSlot.isEmpty()) { + int extendedSlots = items.length + duplicateSlot.size(); + ItemStack[] newItems = new ItemStack[extendedSlots]; + System.arraycopy(items, 0, newItems, 0, items.length); + Arrays.fill(newItems, items.length, newItems.length, new ItemStack(Material.AIR)); + items = newItems; + } + } + + return items; + } public void save(JsonObject json) { if (this.inventory != null) { @@ -113,10 +183,10 @@ public void save(JsonObject json) { throw new NullPointerException("content can not be null"); } - json.addProperty(BPKey.VERSION, 2); - json.addProperty(BPKey.ID, this.id.toString()); - json.addProperty(BPKey.TYPE_RAW, this.typeRaw); - json.add(BPKey.INVENTORY, NmsInstance.itemstackToJsonElement(this.content)); + json.addProperty(BPConstants.KEY_VERSION, BPConstants.VERSION); + json.addProperty(BPConstants.KEY_ID, this.id.toString()); + json.addProperty(BPConstants.KEY_TYPE_RAW, this.typeRaw); + json.add(BPConstants.KEY_INVENTORY, NmsInstance.itemstackToJsonElement(this.content)); } @Override diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java index bd627c9..a39970c 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackHandler.java @@ -103,7 +103,11 @@ public void save(ZIPBackpack backpack) { } JsonObject json = new JsonObject(); - ((Backpack) backpack).save(json); + if (backpack instanceof Backpack internalBackpack) { + internalBackpack.save(json); + } else { + throw new IllegalArgumentException("Backpack object is not a ZIPBackpack"); + } Path file = this.getPathForId(backpack.getId()); try (FileOutputStream outputStream = new FileOutputStream(file.toFile()); @@ -162,7 +166,11 @@ public Backpack getBackpack(ItemStack item) { } } - if (!this.loadingIssue.contains(uniqueId) && dataContainer.has(this.backpackIdentifierKey, PersistentDataType.STRING)) { + if (this.loadingIssue.contains(uniqueId)) { + return null; + } + + if (dataContainer.has(this.backpackIdentifierKey, PersistentDataType.STRING)) { String backpackIdentifier = dataContainer.get(this.backpackIdentifierKey, PersistentDataType.STRING); BackpackType backpackType = this.registry.getTypeByName(backpackIdentifier); if (backpackType == null) { @@ -228,4 +236,8 @@ public UniqueId getUniqueId(ItemStack item) { private Path getPathForId(ZIPUniqueId id) { return this.folderPath.resolve(id.toString() + ".json"); } + + public Path getFolderPath() { + return this.folderPath; + } } \ No newline at end of file diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java index f281a58..774906d 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackMigrator.java @@ -1,17 +1,20 @@ package net.imprex.zip; +import java.awt.geom.IllegalPathStateException; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.stream.Stream; import com.google.common.io.ByteStreams; import com.google.gson.JsonObject; import io.netty.buffer.Unpooled; -import net.imprex.zip.common.BPKey; +import net.imprex.zip.common.BPConstants; import net.imprex.zip.common.Ingrim4Buffer; import net.imprex.zip.common.UniqueId; import net.imprex.zip.common.ZIPLogger; @@ -31,6 +34,50 @@ public class BackpackMigrator { * buffer.writeString(this.typeRaw); * buffer.writeByteArray(NmsInstance.itemstackToBinary(this.content)); */ + + public static void checkForMigrations(Path folderPath) { + long startTime = System.currentTimeMillis(); + int statisticSuccessful = 0; + int statisticFailed = 0; + + ZIPLogger.info("Checking for migration data..."); + + try (Stream stream = Files.walk(folderPath, 1)) { + Path[] paths = stream + .filter(file -> !Files.isDirectory(file)) + .filter(file -> Files.isRegularFile(file)) + .filter(file -> !file.getFileName().toString().endsWith(".json")) + .toArray(Path[]::new); + + ZIPLogger.info("Migration found " + paths.length + " outdated backpacks."); + + if (paths.length == 0) { + return; + } + + for (Path file : paths) { + try { + UniqueId id = UniqueId.fromString(file.getFileName().toString()); + if (BackpackMigrator.migrate(folderPath, id)) { + statisticSuccessful++; + } else { + statisticFailed++; + } + } catch (Exception e) { + e.printStackTrace(); + statisticFailed++; + } + } + + ZIPLogger.info(String.format("Migration finished. %d/%d backpacks migrated and %d failed to migrate in %d seconds.", + paths.length, + statisticSuccessful, + statisticFailed, + Math.round((System.currentTimeMillis() - startTime) / 1000))); + } catch (IOException e) { + ZIPLogger.error("Error when migrating backpacks", e); + } + } public static boolean migrate(Path folderPath, UniqueId id) { try { @@ -51,12 +98,16 @@ public static boolean migrate(Path folderPath, UniqueId id) { byte[] previousContent = buffer.readByteArray(); JsonObject json = new JsonObject(); - json.addProperty(BPKey.VERSION, 2); - json.addProperty(BPKey.ID, UniqueId.fromByteArray(previousId).toString()); - json.addProperty(BPKey.TYPE_RAW, previousRawType); - json.add(BPKey.INVENTORY, NmsInstance.migrateToJsonElement(previousContent)); + json.addProperty(BPConstants.KEY_VERSION, BPConstants.VERSION); + json.addProperty(BPConstants.KEY_ID, UniqueId.fromByteArray(previousId).toString()); + json.addProperty(BPConstants.KEY_TYPE_RAW, previousRawType); + json.add(BPConstants.KEY_INVENTORY, NmsInstance.migrateToJsonElement(previousContent)); Path newFile = folderPath.resolve(id.toString() + ".json"); + if (Files.exists(newFile)) { + throw new IllegalPathStateException("File path for migration " + id.toString() + " already exist!"); + } + try (FileOutputStream outputStream = new FileOutputStream(newFile.toFile()); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { Backpack.GSON.toJson(json, outputStreamWriter); diff --git a/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java b/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java index d6bd935..2f9fdb5 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java +++ b/zip-plugin/src/main/java/net/imprex/zip/BackpackPlugin.java @@ -45,6 +45,8 @@ public void onLoad() { public void onEnable() { try { NmsInstance.initialize(); + + BackpackMigrator.checkForMigrations(this.backpackHandler.getFolderPath()); this.backpackConfig.deserialize(); diff --git a/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java b/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java index 0e34f5a..1232970 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java +++ b/zip-plugin/src/main/java/net/imprex/zip/NmsInstance.java @@ -11,6 +11,7 @@ import net.imprex.zip.common.MinecraftVersion; import net.imprex.zip.common.ZIPLogger; +import net.imprex.zip.nms.api.ItemStackContainerResult; import net.imprex.zip.nms.api.NmsManager; public class NmsInstance { @@ -43,7 +44,7 @@ public static JsonObject itemstackToJsonElement(ItemStack[] items) { return instance.itemstackToJsonElement(items); } - public static ItemStack[] jsonElementToItemStack(JsonObject jsonElement) { + public static ItemStackContainerResult jsonElementToItemStack(JsonObject jsonElement) { return instance.jsonElementToItemStack(jsonElement); } diff --git a/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java b/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java index 1d6d42d..5a7b2d6 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java +++ b/zip-plugin/src/main/java/net/imprex/zip/command/BackpackCommand.java @@ -34,7 +34,6 @@ public BackpackCommand(BackpackPlugin plugin) { this.registerSubCommand(new PickupCommand(plugin)); this.registerSubCommand(new TypeCommand(plugin)); this.registerSubCommand(new LoreCommand(plugin)); - this.registerSubCommand(new MigrateCommand(plugin)); this.buildHelpMessage(); } diff --git a/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java b/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java deleted file mode 100644 index 3b68283..0000000 --- a/zip-plugin/src/main/java/net/imprex/zip/command/MigrateCommand.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.imprex.zip.command; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.stream.Stream; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import net.imprex.zip.BackpackMigrator; -import net.imprex.zip.BackpackPlugin; -import net.imprex.zip.common.UniqueId; -import net.imprex.zip.config.MessageKey; - -public class MigrateCommand extends BackpackSubCommand { - - public MigrateCommand(BackpackPlugin plugin) { - super(plugin, MessageKey.CommandHelpMigrate, "zeroinventoryproblems.migrate", "migrate"); - } - - @Override - public void onCommand(CommandSender sender, String[] args) { - Player player = this.isPlayer(sender); - if (player == null) { - return; - } - - if (!(args.length == 1 && args[0].equalsIgnoreCase("confirm"))) { - this.messageConfig.send(sender, MessageKey.CommandMigrateUsage); - return; - } - - long startTime = System.currentTimeMillis(); - int statisticSuccessful = 0; - int statisticFailed = 0; - - this.messageConfig.send(sender, MessageKey.CommandMigrateOperationStarted); - - Path folderPath = Path.of(plugin.getDataFolder().getAbsolutePath(), "storage"); - try (Stream stream = Files.walk(folderPath, 1)) { - Path[] paths = stream - .filter(file -> !Files.isDirectory(file)) - .filter(file -> Files.isRegularFile(file)) - .filter(file -> !file.getFileName().toString().endsWith(".json")) - .toArray(Path[]::new); - - this.messageConfig.send(sender, MessageKey.CommandMigrateOperationFound, paths.length); - - for (Path file : paths) { - try { - UniqueId id = UniqueId.fromString(file.getFileName().toString()); - if (BackpackMigrator.migrate(folderPath, id)) { - statisticSuccessful++; - } else { - statisticFailed++; - } - } catch (Exception e) { - e.printStackTrace(); - statisticFailed++; - } - } - - this.messageConfig.send(sender, - MessageKey.CommandMigrateOperationDone, - paths.length, - statisticSuccessful, - statisticFailed, - Math.round((System.currentTimeMillis() - startTime) / 1000)); - } catch (IOException e) { - e.printStackTrace(); - this.messageConfig.send(sender, MessageKey.CommandMigrateOperationFailed); - } - } - - @Override - public void onTabComplete(CommandSender sender, String[] args, List result) { - } -} \ No newline at end of file diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java index 5bce715..fd8c8e4 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java @@ -62,12 +62,7 @@ public enum MessageKey { LoreLineChange("loreLineChange", "The lore line {0} was changed"), LoreLineDelete("loreLineDelete", "The lore line {0} was deleted"), MaxLoreCountReached("maxLoreCountReached", "You have reached the max lore count of {0}"), - UnableToLoadBackpack("unableToLoadBackpack", "Backpack id §8\"§e{0}§8\" §7can't be loaded!"), - CommandMigrateUsage("commandMigrateUsage", "Use: §8/§7zip migrate §econfirm"), - CommandMigrateOperationStarted("commandMigrateOperationStarted", "Starting migrating process, this could freeze the server for a moment"), - CommandMigrateOperationFound("commandMigrateOperationFound", "Migration found §e{0} §7outdated backpacks. Starting converting..."), - CommandMigrateOperationDone("commandMigrateOperationDone", "Migration finished. §e{0}§8/§e{1} §7backpacks migrated and §e{2} §7failed to migrate in §e{3} §7seconds."), - CommandMigrateOperationFailed("commandMigrateOperationFailed", "Migration failed. Look inside the console for more info"); + UnableToLoadBackpack("unableToLoadBackpack", "Backpack id §8\"§e{0}§8\" §7can't be loaded!"); public static MessageKey findByKey(String key) { for (MessageKey messageKey : values()) { diff --git a/zip-plugin/src/main/resources/lang/en_US.yml b/zip-plugin/src/main/resources/lang/en_US.yml index d0773e2..afee2d1 100644 --- a/zip-plugin/src/main/resources/lang/en_US.yml +++ b/zip-plugin/src/main/resources/lang/en_US.yml @@ -53,9 +53,4 @@ loreLineCreate: "The lore line {0} was added" loreLineChange: "The lore line {0} was changed" loreLineDelete: "The lore line {0} was deleted" maxLoreCountReached: "You have reached the max lore count of {0}" -unableToLoadBackpack: "Backpack id &8\"&e{0}&8\" &7can't be loaded!" -commandMigrateUsage: "Use: &8/&7zip migrate &econfirm" -commandMigrateOperationStarted: "Starting migrating process, this could freeze the server for a moment" -commandMigrateOperationFound: "Migration found &e{0} &7outdated backpacks. Starting converting..." -commandMigrateOperationDone: "Migration finished. &e{0}&8/&e{1} &7backpacks migrated and &e{2} &7failed to migrate in &e{3} &7seconds" -commandMigrateOperationFailed: "Migration failed. Look inside the console for more info" \ No newline at end of file +unableToLoadBackpack: "Backpack id &8\"&e{0}&8\" &7can't be loaded!" \ No newline at end of file From c0b0584ae73129e1f456dcb584a83ba70716c496 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Sun, 22 Jun 2025 20:00:03 +0200 Subject: [PATCH 8/8] chore: remove unused translations --- zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java | 1 - zip-plugin/src/main/resources/lang/en_US.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java index fd8c8e4..bf4bfeb 100644 --- a/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java +++ b/zip-plugin/src/main/java/net/imprex/zip/config/MessageKey.java @@ -15,7 +15,6 @@ public enum MessageKey { CommandHelpGive("commandHelpGive", "§8/§7zip §egive §7[§etype§7] §7<§eplayer§7> §8| §7Give yourself a backpack§8."), CommandHelpType("commandHelpType", "§8/§7zip §etype §8| §7Get a list of all backpacks§8."), CommandHelpLore("commandHelpLore", "§8/§7zip §elore §8| §7Write a custom lore§8."), - CommandHelpMigrate("commandHelpMigrate", "§8/§7zip §emigrate §8| §7Migrate all existing backpacks to the new format§8."), CommandHelpEnd("commandHelpEnd", "§8[]§7========== §eZeroInventoryProblems §7==========§8[]"), CommandTypeStart("commandTypeStart", "§8[]§7========== §eZeroInventoryProblems Types §7==========§8[]"), CommandTypeContent("commandTypeContent", " §8-§e{0}"), diff --git a/zip-plugin/src/main/resources/lang/en_US.yml b/zip-plugin/src/main/resources/lang/en_US.yml index afee2d1..5190ed2 100644 --- a/zip-plugin/src/main/resources/lang/en_US.yml +++ b/zip-plugin/src/main/resources/lang/en_US.yml @@ -11,7 +11,6 @@ commandHelpLink: "&8/&7zip &elink &7<&ecancel&7> &8| &7Link multiple backpacks o commandHelpGive: "&8/&7zip &egive &7[&etype&7] &7<&eplayer&7> &8| &7Give yourself a backpack&8." commandHelpType: "&8/&7zip &etype &8| &7Get a list of all backpacks&8." commandHelpLore: "&8/&7zip &elore &8| &7Write a custom lore&8." -CommandHelpMigrate: "&8/&7zip &emigrate &8| &7Migrate all existing backpacks to the new format&8." commandHelpEnd: "&8[]&7========== &eZeroInventoryProblems &7==========&8[]" commandTypeStart: "&8[]&7========== &eZeroInventoryProblems Types &7==========&8[]" commandTypeContent: " &8-&e{0}"