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-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
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
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";
}
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);
+ }
}
}
}