From 4ba45a0ac7f360e95c33cf04cd3a3ce71650c968 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 23 Sep 2026 22:06:44 +0000 Subject: [PATCH 1/5] chore: use latest config file --- .../dev/imprex/zip/config/BackpackConfig.java | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java b/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java index c7b245f..a214643 100644 --- a/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java +++ b/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java @@ -1,14 +1,26 @@ package dev.imprex.zip.config; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; - +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; - + import dev.imprex.zip.BackpackPlugin; import dev.imprex.zip.common.MinecraftVersion; +import dev.imprex.zip.common.Version; +import dev.imprex.zip.common.ZIPLogger; public class BackpackConfig { @@ -28,15 +40,10 @@ public void deserialize() { Path configPath = dataFolder.resolve("config.yml"); if (Files.notExists(configPath)) { - String configVersion = MinecraftVersion.majorVersion() + "." + MinecraftVersion.minorVersion(); - - if (Files.notExists(dataFolder)) { - Files.createDirectories(dataFolder); - } - - Files.copy(BackpackPlugin.class.getResourceAsStream("/config/config-" + configVersion + ".yml"), configPath); + Files.createDirectories(dataFolder); + this.copyDefaultConfig(configPath); } - } catch (IOException e) { + } catch (IOException | URISyntaxException e) { throw new RuntimeException("unable to create config", e); } @@ -51,6 +58,39 @@ public void deserialize() { this.messageConfig = new MessageConfig(this.plugin); } + private void copyDefaultConfig(Path target) throws IOException, URISyntaxException { + URI resource = BackpackPlugin.class.getResource("").toURI(); + Version current = MinecraftVersion.current(); + + try (FileSystem fileSystem = FileSystems.newFileSystem(resource, Collections.emptyMap()); + Stream files = Files.list(fileSystem.getPath("/config"))) { + + TreeMap configs = new TreeMap<>(); + files.forEach(file -> { + Matcher matcher = CONFIG_FILE_PATTERN.matcher(file.getFileName().toString()); + if (matcher.matches()) { + configs.put(Version.parse(matcher.group(1)), file); + } + }); + + Map.Entry entry = configs.floorEntry(current); + if (entry == null) { + throw new IllegalStateException(String.format( + "no default config for minecraft version %s found (available: %s)", + current, configs.keySet())); + } + + Version configVersion = entry.getKey(); + if (configVersion.major() != current.major() || configVersion.minor() != current.minor()) { + ZIPLogger.warn(String.format( + "No dedicated config for minecraft version %s, falling back to config for %s", + current, configVersion)); + } + + Files.copy(entry.getValue(), target); + } + } + public GeneralConfig general() { return this.generalConfig; } From 0f4b84af3872c929cfed4408272c172311d912d6 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 23 Sep 2026 22:52:37 +0000 Subject: [PATCH 2/5] fix: missing global setting --- .../src/main/java/dev/imprex/zip/config/BackpackConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java b/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java index a214643..aa56709 100644 --- a/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java +++ b/zip-plugin/src/main/java/dev/imprex/zip/config/BackpackConfig.java @@ -24,6 +24,8 @@ public class BackpackConfig { + private static final Pattern CONFIG_FILE_PATTERN = Pattern.compile("config-(\\d+(?:\\.\\d+){0,2})\\.yml"); + private final BackpackPlugin plugin; private GeneralConfig generalConfig; From d2e6605ea1045830a7328066805ee678157588af Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 23 Sep 2026 23:41:29 +0000 Subject: [PATCH 3/5] chore: add 26.3 support chore: update action versions --- .github/workflows/build.yml | 14 +- .github/workflows/buildtools.sh | 3 +- .github/workflows/release.yml | 11 +- .../imprex/zip/common/MinecraftVersion.java | 1 + zip-nms/pom.xml | 1 + zip-nms/zip-nms-v26_3/pom.xml | 26 +++ .../imprex/zip/nms/v26_3/ZipNmsManager.java | 213 ++++++++++++++++++ zip-plugin/pom.xml | 6 + 8 files changed, 262 insertions(+), 13 deletions(-) create mode 100644 zip-nms/zip-nms-v26_3/pom.xml create mode 100644 zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5cd6004..4849bec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,21 +11,21 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 - name: Set BUILD_VERSION run: echo "BUILD_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1))-b$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - name: Restore Maven cache id: cache-restore - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v6 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}- - - name: Set up JDK 17/25 - uses: actions/setup-java@v4 + - name: Set up JDK 17/21/25 + uses: actions/setup-java@v6 with: distribution: 'temurin' java-version: | @@ -37,16 +37,16 @@ jobs: bash ./.github/workflows/buildtools.sh - name: Build run: | - mvn clean package -pl zip-plugin --batch-mode --also-make -Drevision=$BUILD_VERSION + mvn package -pl zip-plugin --batch-mode --also-make -Drevision=$BUILD_VERSION mv zip-plugin/target/zip-*.jar ./ - name: Save Maven cache if: always() && steps.cache-restore.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 + uses: actions/cache/save@v6 with: path: ~/.m2/repository key: ${{ steps.cache-restore.outputs.cache-primary-key }} - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: zero-inventory-problems-plugin path: ./zip-*.jar diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 41ae5eb..e07f38c 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -32,7 +32,7 @@ checkVersion "1.20.1" "R0.1" "17" checkVersion "1.20.2" "R0.1" "17" checkVersion "1.20.4" "R0.1" "17" checkVersion "1.20.6" "R0.1" "21" -checkVersion "1.21" "R0.1" "21" +checkVersion "1.21.1" "R0.1" "21" checkVersion "1.21.3" "R0.1" "21" checkVersion "1.21.4" "R0.1" "21" checkVersion "1.21.5" "R0.1" "21" @@ -41,3 +41,4 @@ checkVersion "1.21.10" "R0.1" "21" checkVersion "1.21.11" "R0.2" "21" checkVersion "26.1.2" "R0.1" "25" checkVersion "26.2" "R0.1" "25" +checkVersion "26.3" "R0.1" "25" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b08671f..35a778b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,23 +8,25 @@ on: jobs: release: runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: fetch-depth: 0 - name: Set RELEASE_VERSION run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Maven cache - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}- - - name: Set up JDK 17/25 - uses: actions/setup-java@v4 + - name: Set up JDK 17/21/25 + uses: actions/setup-java@v6 with: distribution: 'temurin' java-version: | @@ -42,4 +44,3 @@ jobs: with: artifacts: "zip-*.jar" name: Release ${{ env.RELEASE_VERSION }} - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java b/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java index 9cf0112..fd9a498 100644 --- a/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java +++ b/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java @@ -18,6 +18,7 @@ private static final class NmsMapping { private static final List MAPPINGS = new ArrayList<>(); static { + MAPPINGS.add(new NmsMapping("26.3", "v26_3")); MAPPINGS.add(new NmsMapping("26.2", "v26_2")); MAPPINGS.add(new NmsMapping("1.26.0", "v26_1")); MAPPINGS.add(new NmsMapping("1.21.11", "v1_21_R7")); diff --git a/zip-nms/pom.xml b/zip-nms/pom.xml index 8edaecd..73d15b9 100644 --- a/zip-nms/pom.xml +++ b/zip-nms/pom.xml @@ -28,5 +28,6 @@ zip-nms-v1_21_R7 zip-nms-v26_1 zip-nms-v26_2 + zip-nms-v26_3 \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_3/pom.xml b/zip-nms/zip-nms-v26_3/pom.xml new file mode 100644 index 0000000..14b7c50 --- /dev/null +++ b/zip-nms/zip-nms-v26_3/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + + dev.imprex + zip-nms + ${revision} + + + zip-nms-v26_3 + + + + dev.imprex + zip-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 26.3-R0.1-SNAPSHOT + provided + + + \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java b/zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java new file mode 100644 index 0000000..ca2a8bc --- /dev/null +++ b/zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java @@ -0,0 +1,213 @@ +package dev.imprex.zip.nms.v26_3; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.function.BiConsumer; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +import com.google.common.collect.Multimaps; +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.authlib.properties.PropertyMap; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; + +import dev.imprex.zip.common.BPConstants; +import dev.imprex.zip.common.ReflectionUtil; +import dev.imprex.zip.nms.api.ItemStackContainerResult; +import dev.imprex.zip.nms.api.ItemStackWithSlot; +import dev.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 extends NmsManager { + + private static final int DATA_VERSION = SharedConstants.getCurrentVersion().dataVersion().version(); + + @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 { + 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, ResolvableProfile.createResolved(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; + } + + @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 = asNmsCopy(item, net.minecraft.world.item.ItemStack.class); + + DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); + JsonObject resultJson = result.getOrThrow().getAsJsonObject(); + + resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); + jsonItems.add(resultJson); + } + + JsonObject outputJson = new JsonObject(); + 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 ItemStackContainerResult jsonElementToItemStack(JsonObject json) { + // check if current version the same + 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(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); + int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); + + List items = new ArrayList<>(); + + JsonArray jsonItems = json.get(BPConstants.KEY_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 = asCraftMirror(minecraftItem); + int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); + + items.add(new ItemStackWithSlot(slot, bukkitItem)); + } + + return new ItemStackContainerResult(itemsSize, 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(BPConstants.KEY_INVENTORY_SLOT, currentSlot); + jsonItems.add(resultJson); + + currentSlot++; + } + } + + JsonObject json = new JsonObject(); + 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; + } + + @Override + public void setSkullProfile(SkullMeta meta, String texture) { + try { + HashMap properties = new HashMap<>(); + properties.put("textures", new Property("textures", texture)); + + PropertyMap propertyMap = new PropertyMap(Multimaps.forMap(properties)); + GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "", propertyMap); + + 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 diff --git a/zip-plugin/pom.xml b/zip-plugin/pom.xml index ee9315c..cb16208 100644 --- a/zip-plugin/pom.xml +++ b/zip-plugin/pom.xml @@ -241,5 +241,11 @@ ${revision} compile + + dev.imprex + zip-nms-v26_3 + ${revision} + compile + \ No newline at end of file From 409a22530e5374e2241b01824dcac3821610c15b Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 23 Sep 2026 23:54:19 +0000 Subject: [PATCH 4/5] fix: paper support --- .../imprex/zip/common/MinecraftVersion.java | 1 - zip-nms/pom.xml | 1 - .../dev/imprex/zip/nms/api/NmsManager.java | 6 + zip-nms/zip-nms-v26_3/pom.xml | 26 --- .../imprex/zip/nms/v26_3/ZipNmsManager.java | 213 ------------------ zip-plugin/pom.xml | 6 - 6 files changed, 6 insertions(+), 247 deletions(-) delete mode 100644 zip-nms/zip-nms-v26_3/pom.xml delete mode 100644 zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java diff --git a/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java b/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java index fd9a498..9cf0112 100644 --- a/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java +++ b/zip-common/src/main/java/dev/imprex/zip/common/MinecraftVersion.java @@ -18,7 +18,6 @@ private static final class NmsMapping { private static final List MAPPINGS = new ArrayList<>(); static { - MAPPINGS.add(new NmsMapping("26.3", "v26_3")); MAPPINGS.add(new NmsMapping("26.2", "v26_2")); MAPPINGS.add(new NmsMapping("1.26.0", "v26_1")); MAPPINGS.add(new NmsMapping("1.21.11", "v1_21_R7")); diff --git a/zip-nms/pom.xml b/zip-nms/pom.xml index 73d15b9..8edaecd 100644 --- a/zip-nms/pom.xml +++ b/zip-nms/pom.xml @@ -28,6 +28,5 @@ zip-nms-v1_21_R7 zip-nms-v26_1 zip-nms-v26_2 - zip-nms-v26_3 \ No newline at end of file diff --git a/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java b/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java index 48ffabd..cb8ad54 100644 --- a/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java +++ b/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java @@ -51,6 +51,12 @@ protected static ItemStack asCraftMirror(T minecraftItem) { CRAFT_ITEM_STACK_CLASS, CRAFT_ITEM_STACK_CLASS, minecraftItem.getClass()); + + // Paper 26.3+ support + if (method == null) { + method = CRAFT_ITEM_STACK_CLASS.getMethod("asBukkitMirror", minecraftItem.getClass()); + } + method.setAccessible(true); craftItemStackAsCraftMirror = method; } diff --git a/zip-nms/zip-nms-v26_3/pom.xml b/zip-nms/zip-nms-v26_3/pom.xml deleted file mode 100644 index 14b7c50..0000000 --- a/zip-nms/zip-nms-v26_3/pom.xml +++ /dev/null @@ -1,26 +0,0 @@ - - 4.0.0 - - - dev.imprex - zip-nms - ${revision} - - - zip-nms-v26_3 - - - - dev.imprex - zip-nms-api - ${revision} - provided - - - org.spigotmc - spigot - 26.3-R0.1-SNAPSHOT - provided - - - \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java b/zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java deleted file mode 100644 index ca2a8bc..0000000 --- a/zip-nms/zip-nms-v26_3/src/main/java/dev/imprex/zip/nms/v26_3/ZipNmsManager.java +++ /dev/null @@ -1,213 +0,0 @@ -package dev.imprex.zip.nms.v26_3; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; -import java.util.function.BiConsumer; - -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.SkullMeta; - -import com.google.common.collect.Multimaps; -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.authlib.properties.PropertyMap; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.Dynamic; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.JsonOps; - -import dev.imprex.zip.common.BPConstants; -import dev.imprex.zip.common.ReflectionUtil; -import dev.imprex.zip.nms.api.ItemStackContainerResult; -import dev.imprex.zip.nms.api.ItemStackWithSlot; -import dev.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 extends NmsManager { - - private static final int DATA_VERSION = SharedConstants.getCurrentVersion().dataVersion().version(); - - @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 { - 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, ResolvableProfile.createResolved(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; - } - - @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 = asNmsCopy(item, net.minecraft.world.item.ItemStack.class); - - DataResult result = net.minecraft.world.item.ItemStack.CODEC.encodeStart(DYNAMIC_OPS_JSON, minecraftItem); - JsonObject resultJson = result.getOrThrow().getAsJsonObject(); - - resultJson.addProperty(BPConstants.KEY_INVENTORY_SLOT, slot); - jsonItems.add(resultJson); - } - - JsonObject outputJson = new JsonObject(); - 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 ItemStackContainerResult jsonElementToItemStack(JsonObject json) { - // check if current version the same - 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(BPConstants.KEY_INVENTORY_DATA_VERSION).getAsInt(); - int itemsSize = json.get(BPConstants.KEY_INVENTORY_ITEMS_SIZE).getAsInt(); - - List items = new ArrayList<>(); - - JsonArray jsonItems = json.get(BPConstants.KEY_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 = asCraftMirror(minecraftItem); - int slot = item.getAsJsonObject().get(BPConstants.KEY_INVENTORY_SLOT).getAsInt(); - - items.add(new ItemStackWithSlot(slot, bukkitItem)); - } - - return new ItemStackContainerResult(itemsSize, 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(BPConstants.KEY_INVENTORY_SLOT, currentSlot); - jsonItems.add(resultJson); - - currentSlot++; - } - } - - JsonObject json = new JsonObject(); - 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; - } - - @Override - public void setSkullProfile(SkullMeta meta, String texture) { - try { - HashMap properties = new HashMap<>(); - properties.put("textures", new Property("textures", texture)); - - PropertyMap propertyMap = new PropertyMap(Multimaps.forMap(properties)); - GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "", propertyMap); - - 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 diff --git a/zip-plugin/pom.xml b/zip-plugin/pom.xml index cb16208..ee9315c 100644 --- a/zip-plugin/pom.xml +++ b/zip-plugin/pom.xml @@ -241,11 +241,5 @@ ${revision} compile - - dev.imprex - zip-nms-v26_3 - ${revision} - compile - \ No newline at end of file From 88bff7218868c2a2a21fe163aefbbf85aee55000 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 23 Sep 2026 23:56:44 +0000 Subject: [PATCH 5/5] fix: paper support --- .github/workflows/buildtools.sh | 1 - .../src/main/java/dev/imprex/zip/nms/api/NmsManager.java | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index e07f38c..a6ad648 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -41,4 +41,3 @@ checkVersion "1.21.10" "R0.1" "21" checkVersion "1.21.11" "R0.2" "21" checkVersion "26.1.2" "R0.1" "25" checkVersion "26.2" "R0.1" "25" -checkVersion "26.3" "R0.1" "25" diff --git a/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java b/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java index cb8ad54..17780a6 100644 --- a/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java +++ b/zip-nms/zip-nms-api/src/main/java/dev/imprex/zip/nms/api/NmsManager.java @@ -62,6 +62,8 @@ protected static ItemStack asCraftMirror(T minecraftItem) { } return (ItemStack) craftItemStackAsCraftMirror.invoke(null, minecraftItem); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Unable to find a CraftItemStack mirror method for " + minecraftItem.getClass().getName(), e); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new IllegalStateException(e); }