From cbcf5aa458a571ea7a4ef381073d7b90e3b166cf Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Fri, 1 May 2026 17:00:00 +0200 Subject: [PATCH 1/6] feat: update to 26.1 --- .github/workflows/build.yml | 7 +- .github/workflows/buildtools.sh | 3 +- .github/workflows/release.yml | 7 +- pom.xml | 6 +- .../imprex/zip/common/MinecraftVersion.java | 7 +- zip-nms/pom.xml | 1 + zip-nms/zip-nms-v26_1/pom.xml | 26 +++ .../imprex/zip/nms/v26_1/ZipNmsManager.java | 213 ++++++++++++++++++ zip-plugin/pom.xml | 6 + 9 files changed, 267 insertions(+), 9 deletions(-) create mode 100644 zip-nms/zip-nms-v26_1/pom.xml create mode 100644 zip-nms/zip-nms-v26_1/src/main/java/dev/imprex/zip/nms/v26_1/ZipNmsManager.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 459cd9c..a2c7ff0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,11 +23,14 @@ jobs: key: ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}- - - name: Set up JDK 21 + - name: Set up JDK 17/25 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: 21 + java-version: | + 17 + 21 + 25 - name: Run BuildTools run: | bash ./.github/workflows/buildtools.sh diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 4c348b0..2fb2329 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -38,4 +38,5 @@ checkVersion "1.21.4" "21" checkVersion "1.21.5" "21" checkVersion "1.21.6" "21" checkVersion "1.21.10" "21" -checkVersion "1.21.11" "21" \ No newline at end of file +checkVersion "1.21.11" "21" +checkVersion "26.1" "25" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0f0a327..a1b3de9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,11 +23,14 @@ jobs: key: ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}- - - name: Set up JDK 21 + - name: Set up JDK 17/25 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: 21 + java-version: | + 17 + 21 + 25 - name: Run BuildTools run: | bash ./.github/workflows/buildtools.sh diff --git a/pom.xml b/pom.xml index 54fdcfb..d695a69 100644 --- a/pom.xml +++ b/pom.xml @@ -24,9 +24,9 @@ 1.5.25 3.0.0 - 3.10.1 - 3.4.0 - 3.4.2 + 3.15.0 + 3.6.2 + 3.5.0 1.2.7 2.0.2 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 25ea700..245a5d9 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("1.26.0", "v26_1")); MAPPINGS.add(new NmsMapping("1.21.11", "v1_21_R7")); MAPPINGS.add(new NmsMapping("1.21.10", "v1_21_R6")); MAPPINGS.add(new NmsMapping("1.21.6", "v1_21_R5")); @@ -53,11 +54,15 @@ public NmsMapping(String version, String nmsVersion) { } private static final Pattern PACKAGE_PATTERN = Pattern.compile("org\\.bukkit\\.craftbukkit\\.(v\\d+_\\d+_R\\d+)"); - private static final Version CURRENT_VERSION = Version.parse(Bukkit.getBukkitVersion()); + private static final Version CURRENT_VERSION; private static String NMS_VERSION; static { + // remove SNAPSHOT suffix of bukkit + var version = Version.parse(Bukkit.getBukkitVersion()); + CURRENT_VERSION = new Version(version.major(), version.minor(), version.patch()); + String craftBukkitPackage = Bukkit.getServer().getClass().getPackage().getName(); Matcher matcher = PACKAGE_PATTERN.matcher(craftBukkitPackage); diff --git a/zip-nms/pom.xml b/zip-nms/pom.xml index d09fe53..373456b 100644 --- a/zip-nms/pom.xml +++ b/zip-nms/pom.xml @@ -26,5 +26,6 @@ zip-nms-v1_21_R5 zip-nms-v1_21_R6 zip-nms-v1_21_R7 + zip-nms-v26_1 \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_1/pom.xml b/zip-nms/zip-nms-v26_1/pom.xml new file mode 100644 index 0000000..0bf0b79 --- /dev/null +++ b/zip-nms/zip-nms-v26_1/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + + dev.imprex + zip-nms + ${revision} + + + zip-nms-v26_1 + + + + dev.imprex + zip-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 26.1.2-R0.1-SNAPSHOT + provided + + + \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_1/src/main/java/dev/imprex/zip/nms/v26_1/ZipNmsManager.java b/zip-nms/zip-nms-v26_1/src/main/java/dev/imprex/zip/nms/v26_1/ZipNmsManager.java new file mode 100644 index 0000000..39881cd --- /dev/null +++ b/zip-nms/zip-nms-v26_1/src/main/java/dev/imprex/zip/nms/v26_1/ZipNmsManager.java @@ -0,0 +1,213 @@ +package dev.imprex.zip.nms.v26_1; + +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 9cc4e80..fbd6d53 100644 --- a/zip-plugin/pom.xml +++ b/zip-plugin/pom.xml @@ -229,5 +229,11 @@ mojang-mapped compile + + dev.imprex + zip-nms-v26_1 + ${revision} + compile + \ No newline at end of file From 03e320c5789f35cb46d77914884737ba45f21e60 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Fri, 1 May 2026 19:16:09 +0200 Subject: [PATCH 2/6] feat: update to 26.1 --- zip-nms/zip-nms-v1_21_R7/pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zip-nms/zip-nms-v1_21_R7/pom.xml b/zip-nms/zip-nms-v1_21_R7/pom.xml index 2cc87be..2c33259 100644 --- a/zip-nms/zip-nms-v1_21_R7/pom.xml +++ b/zip-nms/zip-nms-v1_21_R7/pom.xml @@ -19,7 +19,7 @@ org.spigotmc spigot - 1.21.11-R0.1-SNAPSHOT + 1.21.11-R0.2-SNAPSHOT remapped-mojang provided @@ -54,10 +54,10 @@ remap-obf - org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:txt:maps-mojang + org.spigotmc:minecraft-server:1.21.11-R0.2-SNAPSHOT:txt:maps-mojang true - org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-mojang + org.spigotmc:spigot:1.21.11-R0.2-SNAPSHOT:jar:remapped-mojang true remapped-obf @@ -72,9 +72,9 @@ ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.21.11-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:minecraft-server:1.21.11-R0.2-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.21.11-R0.1-SNAPSHOT:jar:remapped-obf + org.spigotmc:spigot:1.21.11-R0.2-SNAPSHOT:jar:remapped-obf From 67ec7a83018c591d7febd47b33cb9035972c430d Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Fri, 1 May 2026 20:10:44 +0200 Subject: [PATCH 3/6] feat: update to 26.1 --- zip-plugin/src/main/java/dev/imprex/zip/NmsInstance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zip-plugin/src/main/java/dev/imprex/zip/NmsInstance.java b/zip-plugin/src/main/java/dev/imprex/zip/NmsInstance.java index 17b13ea..e286b0c 100644 --- a/zip-plugin/src/main/java/dev/imprex/zip/NmsInstance.java +++ b/zip-plugin/src/main/java/dev/imprex/zip/NmsInstance.java @@ -26,7 +26,7 @@ public static void initialize() { } String nmsVersion = MinecraftVersion.nmsVersion(); - if (ServerVersion.isMojangMapped()) { + if (ServerVersion.isMojangMapped() && MinecraftVersion.isBelow("26.0.0")) { nmsVersion += "_mojang"; } From 593d74764efce5a73d4b31b32bac8606cf371d22 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Fri, 1 May 2026 20:45:41 +0200 Subject: [PATCH 4/6] feat: update to 26.1 --- .../main/java/dev/imprex/zip/command/LoreCommand.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/zip-plugin/src/main/java/dev/imprex/zip/command/LoreCommand.java b/zip-plugin/src/main/java/dev/imprex/zip/command/LoreCommand.java index 8e8115f..b91877c 100644 --- a/zip-plugin/src/main/java/dev/imprex/zip/command/LoreCommand.java +++ b/zip-plugin/src/main/java/dev/imprex/zip/command/LoreCommand.java @@ -235,10 +235,13 @@ public void onTabComplete(CommandSender sender, String[] args, List resu String value = args[1]; ItemMeta meta = item.getItemMeta(); - for (int line = 1; line < meta.getLore().size() + 1; line++) { - String lineAsString = String.valueOf(line); - if (lineAsString.startsWith(value)) { - result.add(lineAsString); + List lore = meta.getLore(); + if (lore != null) { + for (int line = 1; line < lore.size() + 1; line++) { + String lineAsString = String.valueOf(line); + if (lineAsString.startsWith(value)) { + result.add(lineAsString); + } } } } From ce1feb3a268012134fa01620874dd607eb7ad68e Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 17 Jun 2026 01:08:50 +0200 Subject: [PATCH 5/6] feat: support 26.2 --- .github/workflows/build.yml | 15 +- .github/workflows/buildtools.sh | 61 ++--- .github/workflows/release.yml | 4 +- .../imprex/zip/common/MinecraftVersion.java | 1 + zip-nms/pom.xml | 1 + zip-nms/zip-nms-v26_2/pom.xml | 26 +++ .../imprex/zip/nms/v26_2/ZipNmsManager.java | 213 ++++++++++++++++++ zip-plugin/pom.xml | 6 + .../src/main/resources/config/config-26.2.yml | 66 ++++++ 9 files changed, 359 insertions(+), 34 deletions(-) create mode 100644 zip-nms/zip-nms-v26_2/pom.xml create mode 100644 zip-nms/zip-nms-v26_2/src/main/java/dev/imprex/zip/nms/v26_2/ZipNmsManager.java create mode 100644 zip-plugin/src/main/resources/config/config-26.2.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a2c7ff0..5cd6004 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,13 +16,14 @@ jobs: 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: Maven cache - uses: actions/cache@v4 + - name: Restore Maven cache + id: cache-restore + uses: actions/cache/restore@v4 with: path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} + key: ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | - ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}- + ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}- - name: Set up JDK 17/25 uses: actions/setup-java@v4 with: @@ -38,6 +39,12 @@ jobs: run: | mvn clean 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 + with: + path: ~/.m2/repository + key: ${{ steps.cache-restore.outputs.cache-primary-key }} - name: Upload artifacts uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 2fb2329..2f036ef 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -2,41 +2,46 @@ # Source: https://github.com/Imprex-Development/orebfuscator/blob/master/.github/workflows/buildtools.sh build () { - JAVA_PATH=$"JAVA_HOME_$2_X64" - export JAVA_HOME=${!JAVA_PATH} + JAVA_PATH=$"JAVA_HOME_$2_X64" + export JAVA_HOME=${!JAVA_PATH} - echo "Building v$1 with java-$2 ($JAVA_HOME)" + echo "Building v$1 with java-$2 ($JAVA_HOME)" - rm -rf $1 - mkdir $1 - cd $1 + rm -rf $1 + mkdir $1 + cd $1 - curl -o BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar - "$JAVA_HOME/bin/java" -jar BuildTools.jar --rev $1 --remapped + curl -o BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + "$JAVA_HOME/bin/java" -jar BuildTools.jar --rev $1 --remapped - cd .. + cd .. } checkVersion () { - echo Checking version $1 + echo Checking version $1 - if [ ! -d ~/.m2/repository/org/spigotmc/spigot/$1-R0.1-SNAPSHOT ]; then - build $1 $2 - fi + if [ ! -d ~/.m2/repository/org/spigotmc/spigot/$1-$2-SNAPSHOT ]; then + build $1 $3 + fi } -checkVersion "1.19" "17" -checkVersion "1.19.3" "17" -checkVersion "1.19.4" "17" -checkVersion "1.20.1" "17" -checkVersion "1.20.2" "17" -checkVersion "1.20.4" "17" -checkVersion "1.20.6" "21" -checkVersion "1.21" "21" -checkVersion "1.21.3" "21" -checkVersion "1.21.4" "21" -checkVersion "1.21.5" "21" -checkVersion "1.21.6" "21" -checkVersion "1.21.10" "21" -checkVersion "1.21.11" "21" -checkVersion "26.1" "25" \ No newline at end of file +checkVersion "1.16.5" "R0.1" "8" +checkVersion "1.17.1" "R0.1" "17" +checkVersion "1.18.1" "R0.1" "17" +checkVersion "1.18.2" "R0.1" "17" +checkVersion "1.19.2" "R0.1" "17" +checkVersion "1.19.3" "R0.1" "17" +checkVersion "1.19.4" "R0.1" "17" +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.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" +checkVersion "1.21.8" "R0.1" "21" +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" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1b3de9..b08671f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,9 +20,9 @@ jobs: uses: actions/cache@v4 with: path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} + key: ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}-${{ hashFiles('./.github/workflows/buildtools.sh') }} restore-keys: | - ${{ runner.os }}-maven-${{ env.CACHE_VERSION }}- + ${{ runner.os }}-maven-${{ secrets.CACHE_VERSION }}- - name: Set up JDK 17/25 uses: actions/setup-java@v4 with: 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 245a5d9..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,6 +18,7 @@ private static final class NmsMapping { private static final List MAPPINGS = new ArrayList<>(); static { + 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")); MAPPINGS.add(new NmsMapping("1.21.10", "v1_21_R6")); diff --git a/zip-nms/pom.xml b/zip-nms/pom.xml index 373456b..8edaecd 100644 --- a/zip-nms/pom.xml +++ b/zip-nms/pom.xml @@ -27,5 +27,6 @@ zip-nms-v1_21_R6 zip-nms-v1_21_R7 zip-nms-v26_1 + zip-nms-v26_2 \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_2/pom.xml b/zip-nms/zip-nms-v26_2/pom.xml new file mode 100644 index 0000000..428c4ab --- /dev/null +++ b/zip-nms/zip-nms-v26_2/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + + dev.imprex + zip-nms + ${revision} + + + zip-nms-v26_2 + + + + dev.imprex + zip-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 26.2-R0.1-SNAPSHOT + provided + + + \ No newline at end of file diff --git a/zip-nms/zip-nms-v26_2/src/main/java/dev/imprex/zip/nms/v26_2/ZipNmsManager.java b/zip-nms/zip-nms-v26_2/src/main/java/dev/imprex/zip/nms/v26_2/ZipNmsManager.java new file mode 100644 index 0000000..16b7472 --- /dev/null +++ b/zip-nms/zip-nms-v26_2/src/main/java/dev/imprex/zip/nms/v26_2/ZipNmsManager.java @@ -0,0 +1,213 @@ +package dev.imprex.zip.nms.v26_2; + +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 fbd6d53..ee9315c 100644 --- a/zip-plugin/pom.xml +++ b/zip-plugin/pom.xml @@ -235,5 +235,11 @@ ${revision} compile + + dev.imprex + zip-nms-v26_2 + ${revision} + compile + \ No newline at end of file diff --git a/zip-plugin/src/main/resources/config/config-26.2.yml b/zip-plugin/src/main/resources/config/config-26.2.yml new file mode 100644 index 0000000..53d8bee --- /dev/null +++ b/zip-plugin/src/main/resources/config/config-26.2.yml @@ -0,0 +1,66 @@ +general: + checkForUpdates: true + verbose: false + locale: en_US +type: + big: + uniqueName: 'big' + displayName: '&7Big &eBackpack' + inventoryRows: 6 + customModelData: 3 + texture: 'ewogICJ0aW1lc3RhbXAiIDogMTYzMzg2MjQwNTg4NSwKICAicHJvZmlsZUlkIiA6ICI1NjY3NWIyMjMyZjA0ZWUwODkxNzllOWM5MjA2Y2ZlOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVJbmRyYSIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9kYTMzMTY5YjcyY2Y4OTE4YjgyYzViZDI3Y2JhOWVlNmMwZWI4OTE2NDA0MDQ4MGJiMjdmODUzNGUwZmE1ODA3IiwKICAgICAgIm1ldGFkYXRhIiA6IHsKICAgICAgICAibW9kZWwiIDogInNsaW0iCiAgICAgIH0KICAgIH0KICB9Cn0=' + lore: + - '&aA Big Backpack' + recipe: + discover: true + group: 'null' + patternOne: 'LCL' + patternTwo: 'ECE' + patternThree: 'DCD' + patternMapping: + L: LEATHER + E: LEAD + C: CHEST + D: DIAMOND + craftingPermission: 'zeroinventoryproblems.crafting.big' + medium: + uniqueName: 'medium' + displayName: '&7Medium &eBackpack' + inventoryRows: 3 + customModelData: 2 + texture: 'ewogICJ0aW1lc3RhbXAiIDogMTY3NDM0NDQ0MzY4NywKICAicHJvZmlsZUlkIiA6ICIxMzdmMjg3MjUwOTE0ZmI4YjA0ZTYwYjg4MWUwZWE2YiIsCiAgInByb2ZpbGVOYW1lIiA6ICJub3JtYWxpc2luZyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9lZjhlZDY4NWIzYzNjYWI4NDM1ZDBmNmIwZDJkZGI0NmRmYTNhYzk2ZmUyZjlhNmQ3NDhmNzExOTFjMGI1MjJiIgogICAgfQogIH0KfQ==' + lore: + - '&aA Medium Backpack' + recipe: + discover: true + group: 'null' + patternOne: 'LSL' + patternTwo: 'ECE' + patternThree: 'ICI' + patternMapping: + L: LEATHER + S: STICK + E: LEAD + C: CHEST + I: IRON_INGOT + craftingPermission: 'zeroinventoryproblems.crafting.medium' + small: + uniqueName: 'small' + displayName: '&7Small &eBackpack' + inventoryRows: 1 + customModelData: 1 + texture: 'ewogICJ0aW1lc3RhbXAiIDogMTYxMzM4Nzk2NDUxNSwKICAicHJvZmlsZUlkIiA6ICJkZTU3MWExMDJjYjg0ODgwOGZlN2M5ZjQ0OTZlY2RhZCIsCiAgInByb2ZpbGVOYW1lIiA6ICJNSEZfTWluZXNraW4iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGFlMTg3MTQ1ZWU3MzJlN2MwMDkwNWE5YzE2ZWQxZTQzYmE4OGQ1NjI0YTZmNGFmODI5ZjEwNDUzZmNjOTE2NSIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9' + lore: + - '&aA Small Backpack' + recipe: + discover: true + group: 'null' + patternOne: 'LSL' + patternTwo: 'ECE' + patternThree: 'LLL' + patternMapping: + L: LEATHER + S: STICK + E: LEAD + C: CHEST + craftingPermission: 'zeroinventoryproblems.crafting.small' \ No newline at end of file From 6e446a3c122b1ddbdb70f9579d3731d7ee31ee58 Mon Sep 17 00:00:00 2001 From: Nils Gereke Date: Wed, 17 Jun 2026 01:10:54 +0200 Subject: [PATCH 6/6] chore: remove unused buildtools versions --- .github/workflows/buildtools.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index 2f036ef..a8bf04b 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -25,22 +25,18 @@ checkVersion () { fi } -checkVersion "1.16.5" "R0.1" "8" -checkVersion "1.17.1" "R0.1" "17" -checkVersion "1.18.1" "R0.1" "17" -checkVersion "1.18.2" "R0.1" "17" -checkVersion "1.19.2" "R0.1" "17" +checkVersion "1.19" "R0.1" "17" checkVersion "1.19.3" "R0.1" "17" checkVersion "1.19.4" "R0.1" "17" 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.1" "R0.1" "21" +checkVersion "1.21" "R0.1" "21" checkVersion "1.21.3" "R0.1" "21" checkVersion "1.21.4" "R0.1" "21" checkVersion "1.21.5" "R0.1" "21" -checkVersion "1.21.8" "R0.1" "21" +checkVersion "1.21.6" "R0.1" "21" checkVersion "1.21.10" "R0.1" "21" checkVersion "1.21.11" "R0.2" "21" checkVersion "26.1.2" "R0.1" "25"