diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index d063b67b..12ee5628 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -5,7 +5,7 @@ # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle -name: Java CI with Gradle +name: Build and Upload Artifact on: push: @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up JDK 21 + - name: Set up JDK 25 uses: actions/setup-java@v4.2.1 with: java-version: '21' diff --git a/build.gradle.kts b/build.gradle.kts index 246bf5a6..d3555c77 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,15 +1,17 @@ plugins { id("java") - id("com.gradleup.shadow") version "8.3.6" + id("com.gradleup.shadow") version "9.3.0" } // Version of HungerGames val projectVersion = "5.0.0-beta4" +// Minimum version of Minecraft that HungerGames supports +val apiVersion = "1.21.10" // Where this builds on the server -val serverLocation = "1-21-5" +val serverLocation = "26-1" // Minecraft version to build against -val minecraftVersion = "1.21.10" +val minecraftVersion = "26.1.2" -java.sourceCompatibility = JavaVersion.VERSION_21 +java.sourceCompatibility = JavaVersion.VERSION_25 repositories { mavenCentral() @@ -26,7 +28,7 @@ repositories { // MythicMobs maven("https://mvn.lumine.io/repository/maven-public/") { - content { includeGroup("io.lumine") } + content { includeGroup("io.lumine") } } // Papi @@ -38,22 +40,22 @@ repositories { dependencies { // Paper - compileOnly("io.papermc.paper:paper-api:${minecraftVersion}-R0.1-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:${minecraftVersion}.build.+") // Command Api - implementation("dev.jorel:commandapi-paper-shade:11.0.1-SNAPSHOT") + implementation("dev.jorel:commandapi-paper-shade:11.2.0") // bStats - implementation("org.bstats:bstats-bukkit:3.1.0") + implementation("org.bstats:bstats-bukkit:3.2.0") // MythicMobs compileOnly("io.lumine:Mythic-Dist:5.6.1") // Papi - compileOnly("me.clip:placeholderapi:2.11.6") + compileOnly("me.clip:placeholderapi:2.12.2") // NBT-API - implementation("de.tr7zw:item-nbt-api:2.15.3") { + implementation("de.tr7zw:item-nbt-api:2.15.7") { isTransitive = false } @@ -71,18 +73,20 @@ tasks { dependsOn("shadowJar") from("build/libs") { include("HungerGames-*.jar") - destinationDir = file("/Users/ShaneBee/Desktop/Server/${serverLocation}/plugins/") + destinationDir = file("/Users/ShaneBee/Desktop/Server/Minecraft/${serverLocation}/plugins/") } } processResources { val prop = ("version" to projectVersion) + val prop2 = ("apiversion" to apiVersion) filesMatching("paper-plugin.yml") { - expand(prop) + expand(prop, prop2) } + } compileJava { - options.release = 21 + options.release = 25 options.compilerArgs.add("-Xlint:unchecked") options.compilerArgs.add("-Xlint:deprecation") } @@ -98,14 +102,21 @@ tasks { } shadowJar { + archiveFileName = "HungerGames-${projectVersion}.jar" + archiveClassifier.set("") relocate("fr.mrmicky.fastboard", "com.shanebeestudios.hg.shaded-api.fastboard") relocate("dev.jorel.commandapi", "com.shanebeestudios.hg.shaded-api.commandapi") relocate("de.tr7zw.changeme.nbtapi", "com.shanebeestudios.hg.shaded-api.nbt") relocate("org.bstats", "com.shanebeestudios.hg.api.metrics") - archiveFileName = "HungerGames-${projectVersion}.jar" } jar { + enabled = false dependsOn(shadowJar) - archiveFileName.set("HungerGames.jar") + } + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } + withSourcesJar() } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975c..d997cfc6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793..c61a118f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf93008..739907df 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a218..c4bdd3ab 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/java/com/shanebeestudios/hg/api/command/CustomArg.java b/src/main/java/com/shanebeestudios/hg/api/command/CustomArg.java index 75a9fc3a..9e51ea68 100644 --- a/src/main/java/com/shanebeestudios/hg/api/command/CustomArg.java +++ b/src/main/java/com/shanebeestudios/hg/api/command/CustomArg.java @@ -17,7 +17,6 @@ import org.jetbrains.annotations.ApiStatus; import java.util.List; -import java.util.Locale; import java.util.concurrent.CompletableFuture; public abstract class CustomArg { @@ -46,7 +45,7 @@ public static void init(HungerGames plugin, GameManager gameManager) { @Override public Argument get(String name) { return new CustomArgument<>(new StringArgument(name), info -> { - String gameName = info.input().toLowerCase(Locale.ROOT); + String gameName = info.input(); Game game = GAME_MANAGER.getGame(gameName); if (game == null) { String msg = LANG.command_base_invalid_game.replace("", gameName); diff --git a/src/main/java/com/shanebeestudios/hg/api/util/NBTApi.java b/src/main/java/com/shanebeestudios/hg/api/util/NBTApi.java index bd8dd674..b4eb9ed4 100644 --- a/src/main/java/com/shanebeestudios/hg/api/util/NBTApi.java +++ b/src/main/java/com/shanebeestudios/hg/api/util/NBTApi.java @@ -1,14 +1,18 @@ package com.shanebeestudios.hg.api.util; import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.NBTCompound; import de.tr7zw.changeme.nbtapi.NBTContainer; +import de.tr7zw.changeme.nbtapi.NBTItem; import de.tr7zw.changeme.nbtapi.NbtApiException; import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; +import org.bukkit.Bukkit; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -16,7 +20,7 @@ * NBT class for adding NBT to items *

(Mainly for internal use)

*/ -@SuppressWarnings("CallToPrintStackTrace") +@SuppressWarnings({"CallToPrintStackTrace", "DataFlowIssue"}) public class NBTApi { private static boolean ENABLED; @@ -100,24 +104,70 @@ public static void applyNBTToEntity(Entity entity, String nbtString) { } } - // Cache these classes/methods to prevent retrieving them too often - private static final Class ICHAT_BASE_COMPONENT_CLASS = ReflectionUtils.getNMSClass("net.minecraft.network.chat.IChatBaseComponent"); + // Classes + private static Class CRAFT_ITEM_STACK_CLASS; + private static final Class NMS_COMPONENT_CLASS = ReflectionUtils.getNMSClass("net.minecraft.network.chat.Component"); private static final Class CRAFT_CHAT_MESSAGE_CLASS = ReflectionUtils.getOBCClass("util.CraftChatMessage"); - private static final Class TEXT_TAG_VISITOR_CLASS; - private static final Class NBT_BASE_CLASS = ReflectionUtils.getNMSClass("net.minecraft.nbt.NBTBase"); + private static final Class TEXT_TAG_VISITOR_CLASS = ReflectionUtils.getNMSClass("net.minecraft.nbt.TextComponentTagVisitor"); + private static final Class NBT_TAG_CLASS = ReflectionUtils.getNMSClass("net.minecraft.nbt.Tag"); + + // Fields/Objects + private static Object CODEC; + private static Object REGISTRY_ACCESS; + private static Object NBT_OPS_INSTANCE; + + // Methods + private static Method GET_COMPONENTS_METHOD; + private static Method ENCODE_METHOD; + private static Method GET_OR_ELSE; + private static Method CREATE_SERIALIZER_METHOD; private static final Method FROM_COMPONENT; private static final Method VISIT_METHOD; - private static final boolean IS_RUNNING_1_20_5 = Util.isRunningMinecraft(1, 20, 5); + + // Constructors + private static Constructor NBT_COMPOUND_CONSTRUCTOR; static { - TEXT_TAG_VISITOR_CLASS = ReflectionUtils.getNMSClass("net.minecraft.nbt.TextComponentTagVisitor"); + try { + // Classes + CRAFT_ITEM_STACK_CLASS = ReflectionUtils.getOBCClass("inventory.CraftItemStack"); + Class compoundTag = ReflectionUtils.getNMSClass("net.minecraft.nbt.CompoundTag"); + Class craftWorld = ReflectionUtils.getOBCClass("CraftWorld"); + Class dataComponentMap = ReflectionUtils.getNMSClass("net.minecraft.core.component.DataComponentMap"); + Class dataResult = ReflectionUtils.getNMSClass("com.mojang.serialization.DataResult"); + Class dynamicOps = ReflectionUtils.getNMSClass("com.mojang.serialization.DynamicOps"); + Class encoder = ReflectionUtils.getNMSClass("com.mojang.serialization.Encoder"); + Class holderLookup = ReflectionUtils.getNMSClass("net.minecraft.core.HolderLookup$Provider"); + Class itemStack = ReflectionUtils.getNMSClass("net.minecraft.world.item.ItemStack"); + Class level = ReflectionUtils.getNMSClass("net.minecraft.world.level.Level"); + Class nbtOps = ReflectionUtils.getNMSClass("net.minecraft.nbt.NbtOps"); + + // Fields/Objects + CODEC = ReflectionUtils.getField("CODEC", dataComponentMap, null); + Object nmsWorld = craftWorld.getDeclaredMethod("getHandle").invoke(Bukkit.getWorlds().get(0)); + REGISTRY_ACCESS = level.getDeclaredMethod("registryAccess").invoke(nmsWorld); + NBT_OPS_INSTANCE = ReflectionUtils.getField("INSTANCE", nbtOps, null); + + // Methods + GET_COMPONENTS_METHOD = itemStack.getDeclaredMethod("getComponents"); + ENCODE_METHOD = encoder.getMethod("encode", Object.class, dynamicOps, Object.class); + GET_OR_ELSE = dataResult.getDeclaredMethod("getOrThrow"); + CREATE_SERIALIZER_METHOD = holderLookup.getDeclaredMethod("createSerializationContext", dynamicOps); + + // Constructors + NBT_COMPOUND_CONSTRUCTOR = compoundTag.getDeclaredConstructor(); + + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + Method from_comp = null; Method visit = null; try { assert TEXT_TAG_VISITOR_CLASS != null; assert CRAFT_CHAT_MESSAGE_CLASS != null; - visit = TEXT_TAG_VISITOR_CLASS.getDeclaredMethod("visit", NBT_BASE_CLASS); - from_comp = CRAFT_CHAT_MESSAGE_CLASS.getMethod("fromComponent", ICHAT_BASE_COMPONENT_CLASS); + visit = TEXT_TAG_VISITOR_CLASS.getDeclaredMethod("visit", NBT_TAG_CLASS); + from_comp = CRAFT_CHAT_MESSAGE_CLASS.getMethod("fromComponent", NMS_COMPONENT_CLASS); } catch (NoSuchMethodException e) { e.printStackTrace(); } @@ -125,27 +175,47 @@ public static void applyNBTToEntity(Entity entity, String nbtString) { VISIT_METHOD = visit; } + /** + * Get the vanilla version of NBT of an item + *
This will show components which don't normally show in NBT + * + * @param itemStack Item to grab NBT from + * @return Vanilla NBT of item + */ + @SuppressWarnings({"deprecation"}) + public static NBTCompound getVanillaNBT(ItemStack itemStack) { + try { + Object nmsItem = ReflectionUtils.getField("handle", CRAFT_ITEM_STACK_CLASS, itemStack); + Object components = GET_COMPONENTS_METHOD.invoke(nmsItem); + Object serial = CREATE_SERIALIZER_METHOD.invoke(REGISTRY_ACCESS, NBT_OPS_INSTANCE); + Object newNBTCompound = NBT_COMPOUND_CONSTRUCTOR.newInstance(); + + Object encoded = ENCODE_METHOD.invoke(CODEC, components, serial, newNBTCompound); + Object nmsNbt = GET_OR_ELSE.invoke(encoded); + NBTCompound itemNbt = NBTItem.convertItemtoNBT(itemStack); + itemNbt.getOrCreateCompound("components").mergeCompound(new NBTContainer(nmsNbt)); + return itemNbt; + } catch (IllegalAccessException | InvocationTargetException | InstantiationException ignore) { + return new NBTContainer(); + } + } + /** * Get a pretty NBT string *

This is the same as what vanilla Minecraft outputs when using the '/data' command

* - * @param nbtString NBT string to convert to pretty - * @param split When null NBT will print on one long line, if not null NBT compound will be - * split into lines with JSON style, and this string will start each line off - * (usually spaces) + * @param compound Compound to convert to pretty + * @param split When null NBT will print on one long line, if not null NBT compound will be + * split into lines with JSON style, and this string will start each line off + * (usually spaces) * @return Pretty string of NBTCompound */ @SuppressWarnings("deprecation") - public static @Nullable String getPrettyNBT(String nbtString, String split) { - Object nmsNBT = new NBTContainer(nbtString).getCompound(); + public static @Nullable String getPrettyNBT(NBTCompound compound, String split) { + Object nmsNBT = new NBTContainer(compound.toString()).getCompound(); String s = split != null ? split : ""; try { - Object tagVisitorInstance; - if (IS_RUNNING_1_20_5) { - tagVisitorInstance = TEXT_TAG_VISITOR_CLASS.getConstructor(String.class).newInstance(s); - } else { - tagVisitorInstance = TEXT_TAG_VISITOR_CLASS.getConstructor(String.class, int.class).newInstance(s, 0); - } + Object tagVisitorInstance = TEXT_TAG_VISITOR_CLASS.getConstructor(String.class).newInstance(s); Object prettyComponent = VISIT_METHOD.invoke(tagVisitorInstance, nmsNBT); return ((String) FROM_COMPONENT.invoke(CRAFT_CHAT_MESSAGE_CLASS, prettyComponent)); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | diff --git a/src/main/java/com/shanebeestudios/hg/plugin/commands/NBTCommand.java b/src/main/java/com/shanebeestudios/hg/plugin/commands/NBTCommand.java index c9f20b2e..9a96f108 100644 --- a/src/main/java/com/shanebeestudios/hg/plugin/commands/NBTCommand.java +++ b/src/main/java/com/shanebeestudios/hg/plugin/commands/NBTCommand.java @@ -5,6 +5,7 @@ import com.shanebeestudios.hg.plugin.HungerGames; import com.shanebeestudios.hg.plugin.permission.Permissions; import de.tr7zw.changeme.nbtapi.NBT; +import de.tr7zw.changeme.nbtapi.NBTCompound; import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; import dev.jorel.commandapi.arguments.Argument; import dev.jorel.commandapi.arguments.LiteralArgument; @@ -38,7 +39,7 @@ protected Argument register() { NBT.getComponents(itemStack, readableNBT -> { Util.sendPrefixedMessage(player, "NBT of held item sent to console!"); Util.log("NBT: %s", readableNBT.toString()); - String pretty = NBTApi.getPrettyNBT(readableNBT.toString(), " "); + String pretty = NBTApi.getPrettyNBT((NBTCompound) readableNBT, " "); if (pretty != null) { Util.log("Pretty NBT:"); Bukkit.getConsoleSender().sendMessage(System.lineSeparator() + pretty); @@ -59,7 +60,7 @@ protected Argument register() { ReadWriteNBT nbtCopy = NBT.parseNBT(snapshot.getAsString()); Util.sendPrefixedMessage(player, "NBT of target entity sent to console!"); Util.log("NBT: %s", nbtCopy.toString()); - String pretty = NBTApi.getPrettyNBT(nbtCopy.toString(), " "); + String pretty = NBTApi.getPrettyNBT((NBTCompound) nbtCopy, " "); if (pretty != null) { Util.log("Pretty NBT:"); Bukkit.getConsoleSender().sendMessage(System.lineSeparator() + pretty); diff --git a/src/main/java/com/shanebeestudios/hg/plugin/managers/GameManager.java b/src/main/java/com/shanebeestudios/hg/plugin/managers/GameManager.java index ee135913..17f673cb 100755 --- a/src/main/java/com/shanebeestudios/hg/plugin/managers/GameManager.java +++ b/src/main/java/com/shanebeestudios/hg/plugin/managers/GameManager.java @@ -277,7 +277,17 @@ public Game getGame(Location location) { * @return The game */ public Game getGame(String name) { - return this.games.get(name); + Game game = this.games.get(name); + if (game != null) { + return game; + } + // Try match without case + for (String key : this.games.keySet()) { + if (key.equalsIgnoreCase(name)) { + return this.games.get(key); + } + } + return null; } /** diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index 71c8a155..3fa84337 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -2,9 +2,9 @@ name: HungerGames main: com.shanebeestudios.hg.plugin.HungerGames authors: [ShaneBee] description: 'A Simple, fun, PvP arena plugin' -version: '${version}' +version: '$version' website: 'https://github.com/ShaneBeeStudios/HungerGames' -api-version: '1.21.4' +api-version: '$apiversion' dependencies: server: Vault: