diff --git a/.github/workflows/buildtools.sh b/.github/workflows/buildtools.sh index a512230..6905ff8 100644 --- a/.github/workflows/buildtools.sh +++ b/.github/workflows/buildtools.sh @@ -33,4 +33,5 @@ checkVersion "1.20.2" "17" checkVersion "1.20.4" "17" checkVersion "1.20.6" "21" checkVersion "1.21" "21" -checkVersion "1.21.3" "21" \ No newline at end of file +checkVersion "1.21.3" "21" +checkVersion "1.21.4" "21" \ No newline at end of file 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 ba93bf1..af92975 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.4", "v1_21_R3")); MAPPINGS.add(new NmsMapping("1.21.3", "v1_21_R2")); MAPPINGS.add(new NmsMapping("1.21", "v1_21_R1")); MAPPINGS.add(new NmsMapping("1.20.5", "v1_20_R4")); diff --git a/zip-nms/pom.xml b/zip-nms/pom.xml index 486a581..2c1e80b 100644 --- a/zip-nms/pom.xml +++ b/zip-nms/pom.xml @@ -21,5 +21,6 @@ zip-nms-v1_20_R4 zip-nms-v1_21_R1 zip-nms-v1_21_R2 + zip-nms-v1_21_R3 \ No newline at end of file diff --git a/zip-nms/zip-nms-v1_21_R3/pom.xml b/zip-nms/zip-nms-v1_21_R3/pom.xml new file mode 100644 index 0000000..89e6386 --- /dev/null +++ b/zip-nms/zip-nms-v1_21_R3/pom.xml @@ -0,0 +1,72 @@ + + 4.0.0 + + + net.imprex + zip-nms + ${revision} + + + zip-nms-v1_21_R3 + + + + net.imprex + zip-nms-api + ${revision} + provided + + + org.spigotmc + spigot + 1.21.4-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.4-R0.1-SNAPSHOT:txt:maps-mojang + true + + org.spigotmc:spigot:1.21.4-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.4-R0.1-SNAPSHOT:csrg:maps-spigot + + org.spigotmc:spigot:1.21.4-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + \ No newline at end of file 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 new file mode 100644 index 0000000..7c2a710 --- /dev/null +++ b/zip-nms/zip-nms-v1_21_R3/src/main/java/net/imprex/zip/nms/v1_21_R3/ZipNmsManager.java @@ -0,0 +1,150 @@ +package net.imprex.zip.nms.v1_21_R3; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +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.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; + +import net.imprex.zip.common.ReflectionUtil; +import net.imprex.zip.nms.api.NmsManager; +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.Tag; +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 CompoundTag NBT_EMPTY_ITEMSTACK = new CompoundTag(); + + 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) { + 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); + } + } + 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())); + } + } + } + } + } + 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 diff --git a/zip-plugin/pom.xml b/zip-plugin/pom.xml index 0b06ae0..967eac7 100644 --- a/zip-plugin/pom.xml +++ b/zip-plugin/pom.xml @@ -101,5 +101,11 @@ ${revision} compile + + net.imprex + zip-nms-v1_21_R3 + ${revision} + compile + \ No newline at end of file