diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 00000000..77415449 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,66 @@ +name: Java CI with Gradle and Release + +on: + push: + branches: ["master"] + +jobs: + build_and_release: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build with Gradle Wrapper + id: build + run: | + ./gradlew build + echo "::set-output name=jar_file::$(find target/bukkit -name '*.jar' -print -quit)" + + - name: Extract version from build.gradle.kts + id: extract_version + run: | + VERSION=$(grep '^version\s*=' build.gradle.kts | sed -E 's/version\s*=\s*"([^"]+)"/\1/') + echo "VERSION=$VERSION" >> $GITHUB_ENV + + - name: Determine next build number + id: build_number + run: | + git fetch --tags + TAG_PATTERN="v${VERSION}-build-" + LAST_TAG=$(git tag --list "${TAG_PATTERN}*" | sort -V | tail -n1) + if [[ $LAST_TAG =~ -build-([0-9]+)$ ]]; then + BUILD_NUMBER=$((BASH_REMATCH[1]+1)) + else + BUILD_NUMBER=1 + fi + echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_ENV + + - name: Create and push tag + run: | + git config user.name "github-actions" + git config user.email "github-actions@github.com" + NEW_TAG="v${VERSION}-build-${BUILD_NUMBER}" + git tag "$NEW_TAG" + git push origin "$NEW_TAG" + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: "v${{ env.VERSION }}-build-${{ env.BUILD_NUMBER }}" + name: "v${{ env.VERSION }}-build-${{ env.BUILD_NUMBER }}" + files: ${{ steps.build.outputs.jar_file }} + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index c766302e..f7f30529 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +From current maintainer Lumine1909: I'm considering drop support of 1.20.5- servers, so I add bstats to collect user's version info. If there aren't enough users in those legacy versions, I'll do that in roughly next minor version. Then I will rewrite the plugin to improve its performance and readability, just like what I did [here](https://github.com/Lumine1909/CustomBiomeColors_Continue). + +----- + # Panilla Panilla (the name) is a combination of the word Packet and Vanilla (as in Vanilla Minecraft). @@ -27,8 +31,7 @@ Currently Panilla supports: - Bukkit - CraftBukkit* 1.8.8 - CraftBukkit* 1.12.x-1.20.4 - - Paper 1.20.6 - - Paper 1.21-1.21.1 + - Paper 1.20.5-26.1.2 **CraftBukkit includes any CraftBukkit derivatives (Spigot, Paper, Folia, etc)* @@ -39,4 +42,4 @@ In order for you to compile Panilla, you will need to use [BuildTools, by Spigot When you run BuildTools, it will add the dependencies required (CraftBukkit/Bukkit) to your local Maven repository. From there, you can compile the project with `./gradlew build`. The output plugin jars file will located in the `target/` directory. -Java 17 is required to build Panilla. +Java 21 is required to build Panilla. diff --git a/api/src/main/java/com/ruinscraft/panilla/api/DefaultProtocolConstants.java b/api/src/main/java/com/ruinscraft/panilla/api/DefaultProtocolConstants.java index 2b75ec0d..7e8de963 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/DefaultProtocolConstants.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/DefaultProtocolConstants.java @@ -1,4 +1,5 @@ package com.ruinscraft.panilla.api; public class DefaultProtocolConstants implements IProtocolConstants { + } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/IPanillaPlayer.java b/api/src/main/java/com/ruinscraft/panilla/api/IPanillaPlayer.java index a5967223..08bc4cbf 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/IPanillaPlayer.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/IPanillaPlayer.java @@ -13,5 +13,4 @@ public interface IPanillaPlayer { boolean hasPermission(String node); boolean canBypassChecks(IPanilla panilla, PacketException e); - } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/config/PConfig.java b/api/src/main/java/com/ruinscraft/panilla/api/config/PConfig.java index e87b83ce..090399a0 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/config/PConfig.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/config/PConfig.java @@ -12,6 +12,7 @@ public abstract class PConfig { /* Defaults */ public String language = "en"; + public boolean safeMode = false; public boolean consoleLogging = true; public boolean chatLogging = false; public PStrictness strictness = PStrictness.AVERAGE; diff --git a/api/src/main/java/com/ruinscraft/panilla/api/config/PTranslations.java b/api/src/main/java/com/ruinscraft/panilla/api/config/PTranslations.java index 117b5349..98c9c6a7 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/config/PTranslations.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/config/PTranslations.java @@ -41,7 +41,7 @@ public String getTranslation(String key, String... replacements) { if (unformatted == null) { return "unknown translation: " + key; } - String formatted = String.format(translations.get(key), replacements); + String formatted = String.format(translations.get(key), (Object[]) replacements); return formatted; } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/io/IPacketInspector.java b/api/src/main/java/com/ruinscraft/panilla/api/io/IPacketInspector.java index c1bdbb3e..20140e5b 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/io/IPacketInspector.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/io/IPacketInspector.java @@ -11,7 +11,7 @@ public interface IPacketInspector { - void checkPacketPlayInClickContainer(Object packetHandle) throws NbtNotPermittedException; + void checkPacketPlayInClickContainer(Object packetHandle, IPanillaPlayer player) throws NbtNotPermittedException; void checkPacketPlayInSetCreativeSlot(Object packetHandle) throws NbtNotPermittedException; @@ -45,7 +45,7 @@ public interface IPacketInspector { default void checkPlayIn(IPanilla panilla, IPanillaPlayer player, Object packetHandle) throws PacketException { try { - checkPacketPlayInClickContainer(packetHandle); + checkPacketPlayInClickContainer(packetHandle, player); } catch (NbtNotPermittedException e) { if (!player.canBypassChecks(panilla, e)) { sendPacketPlayOutSetSlotAir(player, e.getItemSlot()); @@ -81,5 +81,4 @@ default void checkPlayOut(IPanilla panilla, Object packetHandle) throws PacketEx throw e; } } - } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/io/IPlayerInjector.java b/api/src/main/java/com/ruinscraft/panilla/api/io/IPlayerInjector.java index 43ef3af8..d9158852 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/io/IPlayerInjector.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/io/IPlayerInjector.java @@ -2,7 +2,6 @@ import com.ruinscraft.panilla.api.IPanilla; import com.ruinscraft.panilla.api.IPanillaPlayer; -import com.ruinscraft.panilla.api.io.dplx.PacketDecompressorDplx; import com.ruinscraft.panilla.api.io.dplx.PacketInspectorDplx; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_BlockEntityTag.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_BlockEntityTag.java index fd089cac..8bb3ad75 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_BlockEntityTag.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_BlockEntityTag.java @@ -98,9 +98,9 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil // signs with text if (blockEntityTag.hasKey("Text1") - || blockEntityTag.hasKey("Text2") - || blockEntityTag.hasKey("Text3") - || blockEntityTag.hasKey("Text4")) { + || blockEntityTag.hasKey("Text2") + || blockEntityTag.hasKey("Text3") + || blockEntityTag.hasKey("Text4")) { result = NbtCheckResult.FAIL; } } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_EntityTag.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_EntityTag.java index 0a8c7e10..a88a5e42 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_EntityTag.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_EntityTag.java @@ -39,6 +39,28 @@ private static FailedNbt checkItems(INbtTagList items, String nmsItemClassName, return failedNbt; } + private static NbtCheckResult checkEffectsTag(INbtTagList effectsList) { + for (int i = 0; i < effectsList.size(); i++) { + INbtTagCompound effect = effectsList.getCompound(i); + + if (effect.hasKeyOfType("amplifier", NbtDataType.BYTE)) { + short amplifier = effect.getByte("amplifier"); + if (amplifier > 32) { + return NbtCheckResult.CRITICAL; + } + } + + if (effect.hasKeyOfType("Amplifier", NbtDataType.BYTE)) { + short amplifier = effect.getByte("Amplifier"); + if (amplifier > 32) { + return NbtCheckResult.CRITICAL; + } + } + } + + return NbtCheckResult.PASS; + } + @Override public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panilla) { NbtCheckResult result = NbtCheckResult.PASS; @@ -238,26 +260,4 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil return result; } - private static NbtCheckResult checkEffectsTag(INbtTagList effectsList) { - for (int i = 0; i < effectsList.size(); i++) { - INbtTagCompound effect = effectsList.getCompound(i); - - if (effect.hasKeyOfType("amplifier", NbtDataType.BYTE)) { - short amplifier = effect.getByte("amplifier"); - if (amplifier > 32) { - return NbtCheckResult.CRITICAL; - } - } - - if (effect.hasKeyOfType("Amplifier", NbtDataType.BYTE)) { - short amplifier = effect.getByte("Amplifier"); - if (amplifier > 32) { - return NbtCheckResult.CRITICAL; - } - } - } - - return NbtCheckResult.PASS; - } - } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Fireworks.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Fireworks.java index 38fe9ba1..6eb28e37 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Fireworks.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Fireworks.java @@ -20,14 +20,14 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil int flight = fireworks.getInt("Flight"); if (flight > panilla.getProtocolConstants().maxFireworksFlight() - || flight < panilla.getProtocolConstants().minFireworksFlight()) { + || flight < panilla.getProtocolConstants().minFireworksFlight()) { result = NbtCheckResult.FAIL; } INbtTagList explosions = fireworks.getList("Explosions", NbtDataType.COMPOUND); if (explosions != null - && explosions.size() > panilla.getProtocolConstants().maxFireworksExplosions()) { + && explosions.size() > panilla.getProtocolConstants().maxFireworksExplosions()) { result = NbtCheckResult.FAIL; } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_SkullOwner.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_SkullOwner.java index ac5a09a3..fa20d10f 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_SkullOwner.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_SkullOwner.java @@ -15,14 +15,14 @@ public class NbtCheck_SkullOwner extends NbtCheck { public static final Pattern URL_MATCHER = Pattern.compile("url"); - public static UUID minecraftSerializableUuid(final int[] ints) { - return new UUID((long) ints[0] << 32 | ((long) ints[1] & 0xFFFFFFFFL), (long) ints[2] << 32 | ((long) ints[3] & 0xFFFFFFFFL)); - } - public NbtCheck_SkullOwner() { super("SkullOwner", PStrictness.LENIENT); } + public static UUID minecraftSerializableUuid(final int[] ints) { + return new UUID((long) ints[0] << 32 | ((long) ints[1] & 0xFFFFFFFFL), (long) ints[2] << 32 | ((long) ints[3] & 0xFFFFFFFFL)); + } + @Override public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panilla) { INbtTagCompound skullOwner = tag.getCompound("SkullOwner"); @@ -88,9 +88,9 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil // all lowercase, no parentheses or spaces decoded = decoded.trim() - .replace(" ", "") - .replace("\"", "") - .toLowerCase(); + .replace(" ", "") + .replace("\"", "") + .toLowerCase(); Matcher matcher = URL_MATCHER.matcher(decoded); @@ -100,7 +100,7 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil String url = decoded.substring(matcher.end() + 1); if (url.startsWith("http://textures.minecraft.net") || - url.startsWith("https://textures.minecraft.net")) { + url.startsWith("https://textures.minecraft.net")) { continue; } else { return NbtCheckResult.FAIL; diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Unbreakable.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Unbreakable.java index 1d8966e8..3f203cd9 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Unbreakable.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_Unbreakable.java @@ -7,7 +7,7 @@ public class NbtCheck_Unbreakable extends NbtCheck { public NbtCheck_Unbreakable() { - super("Unbreakable", PStrictness.LENIENT,"minecraft:unbreakable"); + super("Unbreakable", PStrictness.LENIENT, "minecraft:unbreakable"); } @Override diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_display.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_display.java index ed541434..64dd83fe 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_display.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_display.java @@ -78,12 +78,16 @@ else if (name.startsWith("{")) { } if (display.hasKeyOfType("Lore", NbtDataType.LIST)) { - INbtTagList lore = display.getList("Lore"); + INbtTagList lore = display.getList("Lore", NbtDataType.STRING); if (lore.size() > panilla.getProtocolConstants().NOT_PROTOCOL_maxLoreLines()) { return NbtCheckResult.CRITICAL; // can cause crashes } + if (lore.size() > 0 && lore.isCompound(0)) { + return NbtCheckResult.CRITICAL; // can cause crashes + } + for (int i = 0; i < lore.size(); i++) { String line = lore.getString(i); diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_pages.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_pages.java index 07d270bf..f97872d4 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_pages.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/NbtCheck_pages.java @@ -12,8 +12,8 @@ public class NbtCheck_pages extends NbtCheck { // translations in the game which (intentionally) crash the user public static final String[] MOJANG_CRASH_TRANSLATIONS = new String[]{ - "translation.test.invalid", - "translation.test.invalid2" + "translation.test.invalid", + "translation.test.invalid2" }; private static final int MINECRAFT_UNICODE_MAX = 65535; @@ -39,6 +39,37 @@ public static short[] createCharMap(String string) { return charMap; } + private static int getCharCountForItem(INbtTagCompound item) { + int charCount = 0; + + if (item.hasKey("tag")) { + INbtTagCompound tag = item.getCompound("tag"); + + if (tag.hasKey("pages")) { + INbtTagList pages = tag.getList("pages", NbtDataType.STRING); + + for (int i = 0; i < pages.size(); i++) { + final String page = pages.getString(i); + final String pageNoSpaces = page.replace(" ", ""); + charCount += pageNoSpaces.length(); + } + } + } + + return charCount; + } + + // Gets the amount of characters of books within in a list of items + public static int getCharCountForItems(INbtTagList items) { + int charCount = 0; + + for (int i = 0; i < items.size(); i++) { + charCount += getCharCountForItem(items.getCompound(i)); + } + + return charCount; + } + @Override public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panilla) { INbtTagList pages = tag.getList("pages", NbtDataType.STRING); @@ -107,35 +138,4 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil return NbtCheckResult.PASS; } - private static int getCharCountForItem(INbtTagCompound item) { - int charCount = 0; - - if (item.hasKey("tag")) { - INbtTagCompound tag = item.getCompound("tag"); - - if (tag.hasKey("pages")) { - INbtTagList pages = tag.getList("pages", NbtDataType.STRING); - - for (int i = 0; i < pages.size(); i++) { - final String page = pages.getString(i); - final String pageNoSpaces = page.replace(" ", ""); - charCount += pageNoSpaces.length(); - } - } - } - - return charCount; - } - - // Gets the amount of characters of books within in a list of items - public static int getCharCountForItems(INbtTagList items) { - int charCount = 0; - - for (int i = 0; i < items.size(); i++) { - charCount += getCharCountForItem(items.getCompound(i)); - } - - return charCount; - } - } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_EntityData.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_EntityData.java index d12738b6..093c6329 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_EntityData.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_EntityData.java @@ -41,6 +41,21 @@ private static FailedNbt checkItems(INbtTagList items, String nmsItemClassName, return failedNbt; } + private static NbtCheckResult checkEffectsTag(INbtTagList effectsList) { + for (int i = 0; i < effectsList.size(); i++) { + INbtTagCompound effect = effectsList.getCompound(i); + + if (effect.hasKeyOfType("Amplifier", NbtDataType.BYTE)) { + short amplifier = effect.getByte("Amplifier"); + if (amplifier > 32) { + return NbtCheckResult.CRITICAL; + } + } + } + + return NbtCheckResult.PASS; + } + @Override public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panilla) { NbtCheckResult result = NbtCheckResult.PASS; @@ -230,19 +245,4 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil return result; } - private static NbtCheckResult checkEffectsTag(INbtTagList effectsList) { - for (int i = 0; i < effectsList.size(); i++) { - INbtTagCompound effect = effectsList.getCompound(i); - - if (effect.hasKeyOfType("Amplifier", NbtDataType.BYTE)) { - short amplifier = effect.getByte("Amplifier"); - if (amplifier > 32) { - return NbtCheckResult.CRITICAL; - } - } - } - - return NbtCheckResult.PASS; - } - } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Fireworks.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Fireworks.java index 825b039a..7eece319 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Fireworks.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Fireworks.java @@ -21,14 +21,14 @@ public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panil int flight = fireworks.getInt("flight_duration"); if (flight > panilla.getProtocolConstants().maxFireworksFlight() - || flight < panilla.getProtocolConstants().minFireworksFlight()) { + || flight < panilla.getProtocolConstants().minFireworksFlight()) { result = NbtCheckResult.FAIL; } INbtTagList explosions = fireworks.getList("explosions", NbtDataType.COMPOUND); if (explosions != null - && explosions.size() > panilla.getProtocolConstants().maxFireworksExplosions()) { + && explosions.size() > panilla.getProtocolConstants().maxFireworksExplosions()) { result = NbtCheckResult.FAIL; } diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Lore.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Lore.java index 092f1824..6f36093f 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Lore.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_Lore.java @@ -16,12 +16,16 @@ public NbtCheck_Lore() { @Override public NbtCheckResult check(INbtTagCompound tag, String itemName, IPanilla panilla) { if (tag.hasKeyOfType(getName(), NbtDataType.LIST)) { - INbtTagList lore = tag.getList(getName()); + INbtTagList lore = tag.getList(getName(), NbtDataType.STRING); if (lore.size() > panilla.getProtocolConstants().NOT_PROTOCOL_maxLoreLines()) { return NbtCheckResult.CRITICAL; // can cause crashes } + if (lore.size() > 0 && lore.isCompound(0)) { + return NbtCheckResult.CRITICAL; // can cause crashes + } + for (int i = 0; i < lore.size(); i++) { String line = lore.getString(i); diff --git a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_SkullOwner1_20_6.java b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_SkullOwner1_20_6.java index 99669d29..368dd37d 100644 --- a/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_SkullOwner1_20_6.java +++ b/api/src/main/java/com/ruinscraft/panilla/api/nbt/checks/paper1_20_6/NbtCheck_SkullOwner1_20_6.java @@ -93,9 +93,9 @@ public NbtCheck.NbtCheckResult check(INbtTagCompound tag, String itemName, IPani // all lowercase, no parentheses or spaces decoded = decoded.trim() - .replace(" ", "") - .replace("\"", "") - .toLowerCase(); + .replace(" ", "") + .replace("\"", "") + .toLowerCase(); Matcher matcher = URL_MATCHER.matcher(decoded); @@ -105,7 +105,7 @@ public NbtCheck.NbtCheckResult check(INbtTagCompound tag, String itemName, IPani String url = decoded.substring(matcher.end() + 1); if (url.startsWith("http://textures.minecraft.net") || - url.startsWith("https://textures.minecraft.net")) { + url.startsWith("https://textures.minecraft.net")) { continue; } else { return NbtCheckResult.FAIL; diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 155b8ce4..00000000 --- a/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -allprojects { - group = 'com.ruinscraft' - version = '1.12.3' -} - -subprojects { - apply plugin: 'java' - - repositories { - mavenLocal() - mavenCentral() - maven { - url 'https://repo.codemc.io/repository/maven-public/' - } - } - - sourceCompatibility = 1.8 - targetCompatibility = 1.8 -} - -task clean { - delete './target' -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..b756694e --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,30 @@ +allprojects { + group = "com.ruinscraft" + version = "1.13.7" +} + +version = "1.13.7" + +repositories { + mavenCentral() + maven(url = "https://repo.codemc.io/repository/maven-public/") + maven(url = "https://repo.codemc.io/repository/nms-local/") + maven(url = "https://repo.codemc.io/repository/nms-remote/") + maven(url = "https://repo.papermc.io/repository/maven-public/") // Authlib, thank you PaperMC +} + +subprojects { + apply(plugin = "java") + + repositories { + mavenCentral() + maven(url = "https://repo.codemc.io/repository/maven-public/") + maven(url = "https://repo.codemc.io/repository/nms-local/") + maven(url = "https://repo.codemc.io/repository/nms-remote/") + maven(url = "https://repo.papermc.io/repository/maven-public/") // Authlib, thank you PaperMC + } +} + +tasks.register("clean") { + delete("./target") +} diff --git a/bukkit/build.gradle b/bukkit/build.gradle index 2614e697..76e1857e 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -19,6 +19,9 @@ dependencies { implementation project(':panilla-craftbukkit-v1_20_R3') implementation project(':panilla-paper-v1_20_6') implementation project(':panilla-paper-v1_21') + implementation project(':panilla-paper-v1_21_3') + implementation project(':panilla-paper-v1_21_5') + compileOnly 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // use 1.13 Bukkit API } @@ -27,7 +30,7 @@ buildscript { gradlePluginPortal() } dependencies { - classpath 'com.github.johnrengelman:shadow:8.1.1' + classpath 'com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.0.2' } } @@ -39,7 +42,7 @@ processResources { } } -apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: 'com.gradleup.shadow' shadowJar { relocate("de.tr7zw.changeme.nbtapi", "com.ruinscraft.panilla.lib.nbtapi") diff --git a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitEnchantments.java b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitEnchantments.java index d4c849dc..663ee47f 100644 --- a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitEnchantments.java +++ b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitEnchantments.java @@ -50,6 +50,9 @@ public int getStartLevel(EnchantmentCompat enchCompat) { @Override public boolean conflicting(EnchantmentCompat enchCompat, EnchantmentCompat _enchCompat) { + if (enchCompat == null || _enchCompat == null) { + return false; + } Enchantment bukkitEnchantment = getBukkitEnchantment(enchCompat); Enchantment _bukkitEnchantment = getBukkitEnchantment(_enchCompat); if (bukkitEnchantment == null || _bukkitEnchantment == null) { @@ -67,8 +70,8 @@ private Enchantment getBukkitEnchantment(EnchantmentCompat enchCompat) { try { Method getByKey = Enchantment.class.getDeclaredMethod("getByKey", NamespacedKey.class); bukkitEnchantment = (Enchantment) getByKey.invoke(null, - new NamespacedKey(enchCompat.namedKey.split(":")[0], - enchCompat.namedKey.split(":")[1])); + new NamespacedKey(enchCompat.namedKey.split(":")[0], + enchCompat.namedKey.split(":")[1])); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { diff --git a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitPanillaPlayer.java b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitPanillaPlayer.java index f367547f..c1ba8863 100644 --- a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitPanillaPlayer.java +++ b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/BukkitPanillaPlayer.java @@ -37,7 +37,8 @@ public boolean hasPermission(String node) { @Override public boolean canBypassChecks(IPanilla panilla, PacketException e) { - if (e.getFailedNbt().result == NbtCheck.NbtCheckResult.CRITICAL) { + // Only cancel them when safe mode enabled + if (panilla.getPConfig().safeMode && e.getFailedNbt().result == NbtCheck.NbtCheckResult.CRITICAL) { return false; // to prevent crash exploits } @@ -45,5 +46,4 @@ public boolean canBypassChecks(IPanilla panilla, PacketException e) { return inDisabledWorld || hasPermission(PConfig.PERMISSION_BYPASS); } - } diff --git a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/PanillaPlugin.java b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/PanillaPlugin.java index 9b12a77c..287d96d9 100644 --- a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/PanillaPlugin.java +++ b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/PanillaPlugin.java @@ -7,6 +7,11 @@ import com.ruinscraft.panilla.api.io.IPacketInspector; import com.ruinscraft.panilla.api.io.IPacketSerializer; import com.ruinscraft.panilla.api.io.IPlayerInjector; +import com.ruinscraft.panilla.bukkit.metrics.Metrics; +import com.ruinscraft.panilla.paper.v1_21.InventoryCleaner; +import com.ruinscraft.panilla.paper.v1_21.io.PacketInspector; +import com.ruinscraft.panilla.paper.v1_21.io.PlayerInjector; +import com.ruinscraft.panilla.paper.v1_21.io.dplx.PacketSerializer; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -92,6 +97,7 @@ private synchronized void loadConfig() { pConfig = new BukkitPConfig(); pConfig.language = getConfig().getString("language", pConfig.language); + pConfig.safeMode = getConfig().getBoolean("safe-mode", pConfig.safeMode); pConfig.consoleLogging = getConfig().getBoolean("logging.console", pConfig.consoleLogging); pConfig.chatLogging = getConfig().getBoolean("logging.chat", pConfig.chatLogging); pConfig.strictness = PStrictness.valueOf(getConfig().getString("strictness", pConfig.strictness.name()).toUpperCase()); @@ -151,10 +157,41 @@ public void onEnable() { @SuppressWarnings("deprecation") private void initVersion() { - System.out.println("DATA VERSION " + Bukkit.getUnsafe().getDataVersion()); + new Metrics(this, 27196); + getLogger().info("DATA VERSION " + Bukkit.getUnsafe().getDataVersion()); + + // Paper 1.21.5 - 1.21.11 + if (Bukkit.getUnsafe().getDataVersion() >= 4325) { + packetSerializerClass = com.ruinscraft.panilla.paper.v1_21_5.io.dplx.PacketSerializer.class; + protocolConstants = new IProtocolConstants() { + @Override + public int maxBookPages() { + return 100; + } + }; + playerInjector = new com.ruinscraft.panilla.paper.v1_21_5.io.PlayerInjector(); + packetInspector = new com.ruinscraft.panilla.paper.v1_21_5.io.PacketInspector(this); + containerCleaner = new com.ruinscraft.panilla.paper.v1_21_5.InventoryCleaner(this); + return; + } + + // Paper 1.21.2 + if (Bukkit.getUnsafe().getDataVersion() >= 4080) { + packetSerializerClass = com.ruinscraft.panilla.paper.v1_21_3.io.dplx.PacketSerializer.class; + protocolConstants = new IProtocolConstants() { + @Override + public int maxBookPages() { + return 100; + } + }; + playerInjector = new com.ruinscraft.panilla.paper.v1_21_3.io.PlayerInjector(); + packetInspector = new com.ruinscraft.panilla.paper.v1_21_3.io.PacketInspector(this); + containerCleaner = new com.ruinscraft.panilla.paper.v1_21_3.InventoryCleaner(this); + return; + } // Paper 1.21, 1.21.1 - if (Bukkit.getUnsafe().getDataVersion() == 3953 || Bukkit.getUnsafe().getDataVersion() == 3955) { + if (Bukkit.getUnsafe().getDataVersion() >= 3953) { packetSerializerClass = com.ruinscraft.panilla.paper.v1_21.io.dplx.PacketSerializer.class; protocolConstants = new IProtocolConstants() { @Override @@ -170,16 +207,16 @@ public int maxBookPages() { // Paper 1.20.6 if (Bukkit.getUnsafe().getDataVersion() == 3839) { - packetSerializerClass = com.ruinscraft.panilla.paper.v1_20_6.io.dplx.PacketSerializer.class; + packetSerializerClass = PacketSerializer.class; protocolConstants = new IProtocolConstants() { @Override public int maxBookPages() { return 100; } }; - playerInjector = new com.ruinscraft.panilla.paper.v1_20_6.io.PlayerInjector(); - packetInspector = new com.ruinscraft.panilla.paper.v1_20_6.io.PacketInspector(this); - containerCleaner = new com.ruinscraft.panilla.paper.v1_20_6.InventoryCleaner(this); + playerInjector = new PlayerInjector(); + packetInspector = new PacketInspector(this); + containerCleaner = new InventoryCleaner(this); return; } imp: @@ -394,5 +431,4 @@ public void onDisable() { } } } - -} +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/TileLootTableListener.java b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/TileLootTableListener.java index f30a8408..7761ea00 100644 --- a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/TileLootTableListener.java +++ b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/TileLootTableListener.java @@ -27,6 +27,27 @@ public TileLootTableListener() { } } + private static void fixLootTable(Block block) { + if (block == null) { + return; + } + + BlockState blockState = block.getState(); + + if (blockState instanceof Lootable) { + Lootable lootable = (Lootable) blockState; + + try { + if (lootable.getLootTable() != null) { + lootable.getLootTable().getKey(); + } + } catch (Exception e) { + lootable.setLootTable(null); + blockState.update(true); + } + } + } + @EventHandler public void onBlockBreak(BlockBreakEvent event) { if (checkForLootable) { @@ -71,25 +92,4 @@ public void onDispense(BlockDispenseEvent event) { } } - private static void fixLootTable(Block block) { - if (block == null) { - return; - } - - BlockState blockState = block.getState(); - - if (blockState instanceof Lootable) { - Lootable lootable = (Lootable) blockState; - - try { - if (lootable.getLootTable() != null) { - lootable.getLootTable().getKey(); - } - } catch (Exception e) { - lootable.setLootTable(null); - blockState.update(true); - } - } - } - } diff --git a/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/metrics/Metrics.java b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/metrics/Metrics.java new file mode 100644 index 00000000..9a48a842 --- /dev/null +++ b/bukkit/src/main/java/com/ruinscraft/panilla/bukkit/metrics/Metrics.java @@ -0,0 +1,905 @@ +/* + * This Metrics class was auto-generated and can be copied into your project if you are + * not using a build tool like Gradle or Maven for dependency management. + * + * IMPORTANT: You are not allowed to modify this class, except changing the package. + * + * Disallowed modifications include but are not limited to: + * - Remove the option for users to opt-out + * - Change the frequency for data submission + * - Obfuscate the code (every obfuscator should allow you to make an exception for specific files) + * - Reformat the code (if you use a linter, add an exception) + * + * Violations will result in a ban of your plugin and account from bStats. + */ +package com.ruinscraft.panilla.bukkit.metrics; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; +import javax.net.ssl.HttpsURLConnection; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class Metrics { + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public Metrics(Plugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + // Inform the server owners about bStats + config + .options() + .header( + "bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" + + "many people use their plugin and their total player count. It's recommended to keep bStats\n" + + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" + + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" + + "anonymous.") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + // Load the data + boolean enabled = config.getBoolean("enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + boolean isFolia = false; + try { + isFolia = Class.forName("io.papermc.paper.threadedregions.RegionizedServer") != null; + } catch (Exception e) { + } + metricsBase = + new // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + MetricsBase( + "bukkit", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + isFolia + ? null + : submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), + plugin::isEnabled, + (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText, + false); + } + + /** Shuts down the underlying scheduler service. */ + public void shutdown() { + metricsBase.shutdown(); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** The version of the Metrics class. */ + public static final String METRICS_VERSION = "3.1.0"; + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final ScheduledExecutorService scheduler; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. + * @param skipRelocateCheck Whether or not the relocate check should be skipped. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText, + boolean skipRelocateCheck) { + ScheduledThreadPoolExecutor scheduler = + new ScheduledThreadPoolExecutor( + 1, + task -> { + Thread thread = new Thread(task, "bStats-Metrics"); + thread.setDaemon(true); + return thread; + }); + // We want delayed tasks (non-periodic) that will execute in the future to be + // cancelled when the scheduler is shutdown. + // Otherwise, we risk preventing the server from shutting down even when + // MetricsBase#shutdown() is called + scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + this.scheduler = scheduler; + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + if (!skipRelocateCheck) { + checkRelocation(); + } + if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from + // bStats + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + public void shutdown() { + scheduler.shutdown(); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven + // distribution of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into + // the initial and second delay. + // WARNING: You must not modify and part of this Metrics class, including the + // submit delay or frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just + // don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate( + submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = + customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute( + () -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** Checks that the class was properly relocated. */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this + // little "trick" ... :D + final String defaultPackage = + new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = + new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong + // package names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject( + BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values) + .map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } +} \ No newline at end of file diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml index 911eb16e..77c1ea74 100644 --- a/bukkit/src/main/resources/config.yml +++ b/bukkit/src/main/resources/config.yml @@ -9,6 +9,10 @@ # The language option below currently does nothing. language: en +# This will be used to reject all "crashable" packets even if player has bypass permission +# For modern Paper and proper permission control, this feature is mostly useless +safe-mode: false + # Logging options logging: console: false diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index 31eb8697..22b8b16e 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -3,7 +3,9 @@ version: ${version} main: com.ruinscraft.panilla.bukkit.PanillaPlugin api-version: 1.13 folia-supported: true -author: ds58 +authors: + - ds58 + - Lumine1909 description: Prevent abusive NBT and harmful packets website: https://github.com/Ruinscraft/Panilla permissions: diff --git a/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PacketInspector.java b/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PacketInspector.java index 96b2e269..f31893fc 100644 --- a/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PacketInspector.java +++ b/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.a(); diff --git a/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PlayerInjector.java b/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PlayerInjector.java index 0407ecf4..1e765253 100644 --- a/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_12_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_12_R1/io/PlayerInjector.java @@ -36,6 +36,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PacketInspector.java b/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PacketInspector.java index a58841dd..43d569d1 100644 --- a/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PacketInspector.java +++ b/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; diff --git a/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PlayerInjector.java b/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PlayerInjector.java index f55ffc99..44e0c707 100644 --- a/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PlayerInjector.java +++ b/craftbukkit-v1_13_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_13_R2/io/PlayerInjector.java @@ -36,6 +36,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PacketInspector.java b/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PacketInspector.java index 8385c921..fb3f0863 100644 --- a/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PacketInspector.java +++ b/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); diff --git a/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PlayerInjector.java b/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PlayerInjector.java index ab8889b5..97e0d056 100644 --- a/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_14_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_14_R1/io/PlayerInjector.java @@ -36,6 +36,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PacketInspector.java b/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PacketInspector.java index 9953b1c6..0e500233 100644 --- a/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PacketInspector.java +++ b/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); diff --git a/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PlayerInjector.java b/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PlayerInjector.java index 379b0402..87354297 100644 --- a/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_15_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_15_R1/io/PlayerInjector.java @@ -39,6 +39,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PacketInspector.java b/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PacketInspector.java index 85a76abd..f8a339c5 100644 --- a/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PacketInspector.java +++ b/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); diff --git a/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PlayerInjector.java b/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PlayerInjector.java index d3c31704..b40403f9 100644 --- a/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_16_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R1/io/PlayerInjector.java @@ -39,6 +39,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PacketInspector.java b/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PacketInspector.java index f59ef5e0..70578a5c 100644 --- a/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PacketInspector.java +++ b/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); diff --git a/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PlayerInjector.java b/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PlayerInjector.java index 56eb3a75..b4e12e2c 100644 --- a/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PlayerInjector.java +++ b/craftbukkit-v1_16_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R2/io/PlayerInjector.java @@ -39,6 +39,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PacketInspector.java b/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PacketInspector.java index 7b9054b7..ccfb68f6 100644 --- a/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PacketInspector.java +++ b/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PacketInspector.java @@ -28,7 +28,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); diff --git a/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PlayerInjector.java b/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PlayerInjector.java index 85e22876..7c1c67b9 100644 --- a/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PlayerInjector.java +++ b/craftbukkit-v1_16_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_16_R3/io/PlayerInjector.java @@ -39,6 +39,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PacketInspector.java b/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PacketInspector.java index ee50b0c0..ea87172a 100644 --- a/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PacketInspector.java +++ b/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PacketInspector.java @@ -37,7 +37,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); @@ -214,9 +214,9 @@ public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { try { Class packetPlayOutSetSlotClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSetSlot"); - Class[] type = { int.class, int.class, int.class, ItemStack.class }; + Class[] type = {int.class, int.class, int.class, ItemStack.class}; Constructor constructor = packetPlayOutSetSlotClass.getConstructor(type); - Object[] params = { 0, 0, slot, new ItemStack(Blocks.a) }; + Object[] params = {0, 0, slot, new ItemStack(Blocks.a)}; Object packetPlayOutSetSlotInstance = constructor.newInstance(params); entityPlayer.b.sendPacket((Packet) packetPlayOutSetSlotInstance); } catch (ClassNotFoundException e) { diff --git a/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PlayerInjector.java b/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PlayerInjector.java index c8452348..2c6fc94c 100644 --- a/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_17_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_17_R1/io/PlayerInjector.java @@ -39,6 +39,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_18_R1/build.gradle b/craftbukkit-v1_18_R1/build.gradle index 22bb6a41..14fdc9d1 100644 --- a/craftbukkit-v1_18_R1/build.gradle +++ b/craftbukkit-v1_18_R1/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.18-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PacketInspector.java b/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PacketInspector.java index 9ce4fab5..23a2298b 100644 --- a/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PacketInspector.java +++ b/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PacketInspector.java @@ -38,7 +38,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); @@ -215,9 +215,9 @@ public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { try { Class packetPlayOutSetSlotClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSetSlot"); - Class[] type = { int.class, int.class, int.class, ItemStack.class }; + Class[] type = {int.class, int.class, int.class, ItemStack.class}; Constructor constructor = packetPlayOutSetSlotClass.getConstructor(type); - Object[] params = { 0, 0, slot, new ItemStack(Blocks.a) }; + Object[] params = {0, 0, slot, new ItemStack(Blocks.a)}; Object packetPlayOutSetSlotInstance = constructor.newInstance(params); entityPlayer.b.a((Packet) packetPlayOutSetSlotInstance); } catch (ClassNotFoundException e) { diff --git a/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PlayerInjector.java b/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PlayerInjector.java index ce470685..af18c53c 100644 --- a/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_18_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R1/io/PlayerInjector.java @@ -38,6 +38,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_18_R2/build.gradle b/craftbukkit-v1_18_R2/build.gradle index 60c3a70e..f15ea55c 100644 --- a/craftbukkit-v1_18_R2/build.gradle +++ b/craftbukkit-v1_18_R2/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.18.2-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PacketInspector.java b/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PacketInspector.java index d1e0be10..af5ca228 100644 --- a/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PacketInspector.java +++ b/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PacketInspector.java @@ -38,7 +38,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); @@ -217,9 +217,9 @@ public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { try { Class packetPlayOutSetSlotClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSetSlot"); - Class[] type = { int.class, int.class, int.class, ItemStack.class }; + Class[] type = {int.class, int.class, int.class, ItemStack.class}; Constructor constructor = packetPlayOutSetSlotClass.getConstructor(type); - Object[] params = { 0, 0, slot, new ItemStack(Blocks.a) }; + Object[] params = {0, 0, slot, new ItemStack(Blocks.a)}; Object packetPlayOutSetSlotInstance = constructor.newInstance(params); entityPlayer.b.a((Packet) packetPlayOutSetSlotInstance); } catch (ClassNotFoundException e) { diff --git a/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PlayerInjector.java b/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PlayerInjector.java index 343caa38..7ad73600 100644 --- a/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PlayerInjector.java +++ b/craftbukkit-v1_18_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_18_R2/io/PlayerInjector.java @@ -38,6 +38,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_19_R1/build.gradle b/craftbukkit-v1_19_R1/build.gradle index 01089080..d569a1f9 100644 --- a/craftbukkit-v1_19_R1/build.gradle +++ b/craftbukkit-v1_19_R1/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.19.2-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PacketInspector.java b/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PacketInspector.java index 08ab0393..de50db8b 100644 --- a/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PacketInspector.java +++ b/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PacketInspector.java @@ -32,6 +32,7 @@ import java.util.UUID; public class PacketInspector implements IPacketInspector { + private static boolean paperChunkSystem = false; private static MethodHandle getEntityLookupMethodHandle = null; private static MethodHandle getEntityMethodHandle = null; @@ -48,6 +49,12 @@ public class PacketInspector implements IPacketInspector { } } + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { try { Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer); @@ -58,14 +65,8 @@ private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { return null; } - private final IPanilla panilla; - - public PacketInspector(IPanilla panilla) { - this.panilla = panilla; - } - @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); @@ -210,12 +211,13 @@ public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { try { Class packetPlayOutSetSlotClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSetSlot"); - Class[] type = { int.class, int.class, int.class, ItemStack.class }; + Class[] type = {int.class, int.class, int.class, ItemStack.class}; Constructor constructor = packetPlayOutSetSlotClass.getConstructor(type); - Object[] params = { 0, 0, slot, new ItemStack(Blocks.a) }; + Object[] params = {0, 0, slot, new ItemStack(Blocks.a)}; Object packetPlayOutSetSlotInstance = constructor.newInstance(params); entityPlayer.b.a((Packet) packetPlayOutSetSlotInstance); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { e.printStackTrace(); } } diff --git a/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PlayerInjector.java b/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PlayerInjector.java index 38a84ad4..86756bc5 100644 --- a/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_19_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R1/io/PlayerInjector.java @@ -38,6 +38,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_19_R2/build.gradle b/craftbukkit-v1_19_R2/build.gradle index 29d0e408..3d502ac9 100644 --- a/craftbukkit-v1_19_R2/build.gradle +++ b/craftbukkit-v1_19_R2/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PacketInspector.java b/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PacketInspector.java index 4407a788..b5dcb4b5 100644 --- a/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PacketInspector.java +++ b/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PacketInspector.java @@ -32,6 +32,7 @@ import java.util.UUID; public class PacketInspector implements IPacketInspector { + private static boolean paperChunkSystem = false; private static MethodHandle getEntityLookupMethodHandle = null; private static MethodHandle getEntityMethodHandle = null; @@ -48,6 +49,12 @@ public class PacketInspector implements IPacketInspector { } } + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { try { Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer); @@ -58,14 +65,8 @@ private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { return null; } - private final IPanilla panilla; - - public PacketInspector(IPanilla panilla) { - this.panilla = panilla; - } - @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.b(); @@ -210,12 +211,13 @@ public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { try { Class packetPlayOutSetSlotClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSetSlot"); - Class[] type = { int.class, int.class, int.class, ItemStack.class }; + Class[] type = {int.class, int.class, int.class, ItemStack.class}; Constructor constructor = packetPlayOutSetSlotClass.getConstructor(type); - Object[] params = { 0, 0, slot, new ItemStack(Blocks.a) }; + Object[] params = {0, 0, slot, new ItemStack(Blocks.a)}; Object packetPlayOutSetSlotInstance = constructor.newInstance(params); entityPlayer.b.a((Packet) packetPlayOutSetSlotInstance); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { e.printStackTrace(); } } diff --git a/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PlayerInjector.java b/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PlayerInjector.java index cd92195b..b27bb8d4 100644 --- a/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PlayerInjector.java +++ b/craftbukkit-v1_19_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R2/io/PlayerInjector.java @@ -38,6 +38,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_19_R3/build.gradle b/craftbukkit-v1_19_R3/build.gradle index 0507aefc..78b84ac2 100644 --- a/craftbukkit-v1_19_R3/build.gradle +++ b/craftbukkit-v1_19_R3/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PacketInspector.java b/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PacketInspector.java index 7bba46ab..44b8389a 100644 --- a/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PacketInspector.java +++ b/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PacketInspector.java @@ -49,6 +49,12 @@ public class PacketInspector implements IPacketInspector { } } + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { try { Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer); @@ -59,14 +65,8 @@ private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { return null; } - private final IPanilla panilla; - - public PacketInspector(IPanilla panilla) { - this.panilla = panilla; - } - @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.a(); @@ -211,12 +211,13 @@ public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { try { Class packetPlayOutSetSlotClass = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutSetSlot"); - Class[] type = { int.class, int.class, int.class, ItemStack.class }; + Class[] type = {int.class, int.class, int.class, ItemStack.class}; Constructor constructor = packetPlayOutSetSlotClass.getConstructor(type); - Object[] params = { 0, 0, slot, new ItemStack(Blocks.a) }; + Object[] params = {0, 0, slot, new ItemStack(Blocks.a)}; Object packetPlayOutSetSlotInstance = constructor.newInstance(params); entityPlayer.b.a((Packet) packetPlayOutSetSlotInstance); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { e.printStackTrace(); } } diff --git a/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PlayerInjector.java b/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PlayerInjector.java index 8c1ead0d..9dec12ce 100644 --- a/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PlayerInjector.java +++ b/craftbukkit-v1_19_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_19_R3/io/PlayerInjector.java @@ -51,6 +51,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_20_R1/build.gradle b/craftbukkit-v1_20_R1/build.gradle index 5de0f48f..253a5e3d 100644 --- a/craftbukkit-v1_20_R1/build.gradle +++ b/craftbukkit-v1_20_R1/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.20.1-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PacketInspector.java b/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PacketInspector.java index 95835dd1..d9d05aa8 100644 --- a/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PacketInspector.java +++ b/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PacketInspector.java @@ -48,6 +48,12 @@ public class PacketInspector implements IPacketInspector { } } + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { try { Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer); @@ -58,14 +64,8 @@ private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { return null; } - private final IPanilla panilla; - - public PacketInspector(IPanilla panilla) { - this.panilla = panilla; - } - @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.a(); diff --git a/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PlayerInjector.java b/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PlayerInjector.java index 807f7dfd..ce5c4733 100644 --- a/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PlayerInjector.java +++ b/craftbukkit-v1_20_R1/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R1/io/PlayerInjector.java @@ -51,6 +51,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/craftbukkit-v1_20_R2/build.gradle b/craftbukkit-v1_20_R2/build.gradle index 1eb99bbe..59ca9917 100644 --- a/craftbukkit-v1_20_R2/build.gradle +++ b/craftbukkit-v1_20_R2/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.20.2-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_20_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R2/io/PacketInspector.java b/craftbukkit-v1_20_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R2/io/PacketInspector.java index f660b10c..d9925104 100644 --- a/craftbukkit-v1_20_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R2/io/PacketInspector.java +++ b/craftbukkit-v1_20_R2/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R2/io/PacketInspector.java @@ -48,6 +48,12 @@ public class PacketInspector implements IPacketInspector { } } + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { try { Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer); @@ -58,14 +64,8 @@ private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { return null; } - private final IPanilla panilla; - - public PacketInspector(IPanilla panilla) { - this.panilla = panilla; - } - @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.a(); diff --git a/craftbukkit-v1_20_R3/build.gradle b/craftbukkit-v1_20_R3/build.gradle index 2cb0d73a..1f8823e0 100644 --- a/craftbukkit-v1_20_R3/build.gradle +++ b/craftbukkit-v1_20_R3/build.gradle @@ -2,3 +2,11 @@ dependencies { compileOnly project(':panilla-api') compileOnly 'org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT' } + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/craftbukkit-v1_20_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R3/io/PacketInspector.java b/craftbukkit-v1_20_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R3/io/PacketInspector.java index a9e50135..1d84e30c 100644 --- a/craftbukkit-v1_20_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R3/io/PacketInspector.java +++ b/craftbukkit-v1_20_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_20_R3/io/PacketInspector.java @@ -8,7 +8,6 @@ import com.ruinscraft.panilla.api.exception.NbtNotPermittedException; import com.ruinscraft.panilla.api.io.IPacketInspector; import com.ruinscraft.panilla.api.nbt.INbtTagCompound; -import com.ruinscraft.panilla.api.nbt.checks.NbtCheck; import com.ruinscraft.panilla.api.nbt.checks.NbtChecks; import com.ruinscraft.panilla.craftbukkit.v1_20_R3.nbt.NbtTagCompound; import net.minecraft.nbt.NBTTagCompound; @@ -49,6 +48,12 @@ public class PacketInspector implements IPacketInspector { } } + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { try { Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer); @@ -59,14 +64,8 @@ private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) { return null; } - private final IPanilla panilla; - - public PacketInspector(IPanilla panilla) { - this.panilla = panilla; - } - @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.a(); diff --git a/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PacketInspector.java b/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PacketInspector.java index e955d43a..48ae98d2 100644 --- a/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PacketInspector.java +++ b/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PacketInspector.java @@ -25,7 +25,7 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object _packet) throws NbtNotPermittedException { + public void checkPacketPlayInClickContainer(Object _packet, IPanillaPlayer player) throws NbtNotPermittedException { if (_packet instanceof PacketPlayInWindowClick) { PacketPlayInWindowClick packet = (PacketPlayInWindowClick) _packet; int windowId = packet.a(); diff --git a/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PlayerInjector.java b/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PlayerInjector.java index d4634b26..b0ab4f61 100644 --- a/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PlayerInjector.java +++ b/craftbukkit-v1_8_R3/src/main/java/com/ruinscraft/panilla/craftbukkit/v1_8_R3/io/PlayerInjector.java @@ -36,6 +36,7 @@ public ByteToMessageDecoder getDecoder() { } private class PanillaPacketDecoder extends PacketDecoder { + public PanillaPacketDecoder(EnumProtocolDirection enumProtocolDirection) { super(enumProtocolDirection); } diff --git a/gradle.properties b/gradle.properties index 911de12e..6d0526f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G \ No newline at end of file +org.gradle.jvmargs=-Xmx2G \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..e287575c --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,5 @@ +[versions] +item-nbt-api = "2.15.7" + +[libraries] +item-nbt-api = { group = "de.tr7zw", name = "item-nbt-api", version.ref = "item-nbt-api" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c0..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 84a0b92f..c61a118f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c..739907df 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or 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. @@ -15,81 +15,114 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# 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/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9..e509b2dd 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,32 +59,33 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 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 -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/paper-v1_20_6/build.gradle b/paper-v1_20_6/build.gradle deleted file mode 100644 index 567a7df9..00000000 --- a/paper-v1_20_6/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -dependencies { - compileOnly project(':panilla-api') - compileOnly 'io.papermc.paper:paper-server:1.20.6-R0.1-SNAPSHOT' - compileOnly 'org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT' - implementation 'de.tr7zw:item-nbt-api:2.13.2' -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} \ No newline at end of file diff --git a/paper-v1_20_6/build.gradle.kts b/paper-v1_20_6/build.gradle.kts new file mode 100644 index 00000000..08f5fba6 --- /dev/null +++ b/paper-v1_20_6/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +dependencies { + compileOnly(project(":panilla-api")) + paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") + implementation(libs.item.nbt.api) +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/PacketInspector.java b/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/PacketInspector.java index 58faea2d..856760bc 100644 --- a/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/PacketInspector.java +++ b/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/PacketInspector.java @@ -17,7 +17,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.EntityItem; +import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; @@ -38,54 +38,51 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayInWindowClick)) return; - PacketPlayInWindowClick packet = (PacketPlayInWindowClick) packetHandle; - int windowId = packet.b(); + public void checkPacketPlayInClickContainer(Object packetHandle, IPanillaPlayer player) throws NbtNotPermittedException { + if (!(packetHandle instanceof ServerboundContainerClickPacket packet)) return; + int windowId = packet.getContainerId(); if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) return; - int slot = packet.f(); - ItemStack item = packet.g(); + int slot = packet.getSlotNum(); + ItemStack item = packet.getCarriedItem(); if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); String itemClass = item.getDescriptionId(); - String packetClass = "PacketPlayInWindowClick"; + String packetClass = packet.getClass().getSimpleName(); NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); } @Override public void checkPacketPlayInSetCreativeSlot(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayInSetCreativeSlot)) return; - PacketPlayInSetCreativeSlot packet = (PacketPlayInSetCreativeSlot) packetHandle; + if (!(packetHandle instanceof ServerboundSetCreativeModeSlotPacket packet)) return; - int slot = packet.b(); - ItemStack item = packet.e(); + int slot = packet.slotNum(); + ItemStack item = packet.itemStack(); if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); String itemClass = item.getDescriptionId(); - String packetClass = "PacketPlayInSetCreativeSlot"; + String packetClass = packet.getClass().getSimpleName(); NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); } @Override public void checkPacketPlayOutSetSlot(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayOutSetSlot)) return; - PacketPlayOutSetSlot packet = (PacketPlayOutSetSlot) packetHandle; + if (!(packetHandle instanceof ClientboundContainerSetSlotPacket packet)) return; - int windowId = packet.b(); + int windowId = packet.getContainerId(); // check if window is not player inventory and we are ignoring non-player inventories if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) { return; } - int slot = packet.e(); + int slot = packet.getSlot(); - ItemStack item = packet.f(); + ItemStack item = packet.getItem(); if (item == null || item.isEmpty() || item.getComponents().isEmpty()) { return; @@ -100,20 +97,19 @@ public void checkPacketPlayOutSetSlot(Object packetHandle) throws NbtNotPermitte @Override public void checkPacketPlayOutWindowItems(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayOutWindowItems)) return; - PacketPlayOutWindowItems packet = (PacketPlayOutWindowItems) packetHandle; + if (!(packetHandle instanceof ClientboundContainerSetContentPacket packet)) return; - int windowId = packet.b(); + int windowId = packet.getContainerId(); // check if window is not player inventory if (windowId != 0) { return; } - List itemStacks = packet.e(); + List itemStacks = packet.getItems(); for (ItemStack itemStack : itemStacks) { - if (!itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + if (itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { continue; } @@ -127,11 +123,9 @@ public void checkPacketPlayOutWindowItems(Object packetHandle) throws NbtNotPerm @Override public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtNotPermittedException { - if ((!(packetHandle instanceof PacketPlayOutSpawnEntity))) return; + if (!(packetHandle instanceof ClientboundAddEntityPacket packet)) return; - PacketPlayOutSpawnEntity packet = (PacketPlayOutSpawnEntity) packetHandle; - - UUID entityId = packet.e(); + UUID entityId = packet.getUUID(); Entity entity = null; for (ServerLevel worldServer : MinecraftServer.getServer().getAllLevels()) { @@ -139,10 +133,9 @@ public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtN if (entity != null) break; } - if (!(entity instanceof EntityItem)) return; + if (!(entity instanceof ItemEntity item)) return; - EntityItem item = (EntityItem) entity; - ItemStack itemStack = item.p(); + ItemStack itemStack = item.getItem(); if (itemStack == null) { return; @@ -182,7 +175,7 @@ public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtN public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); ServerPlayer entityPlayer = craftPlayer.getHandle(); - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(entityPlayer.containerMenu.containerId, entityPlayer.containerMenu.incrementStateId(), slot, new ItemStack(Blocks.AIR)); + ClientboundContainerSetSlotPacket packet = new ClientboundContainerSetSlotPacket(entityPlayer.containerMenu.containerId, entityPlayer.containerMenu.incrementStateId(), slot, new ItemStack(Blocks.AIR)); entityPlayer.connection.send(packet); } @@ -195,9 +188,8 @@ public void stripNbtFromItemEntity(UUID entityId) { if (entity != null) break; } - if (entity instanceof EntityItem) { - EntityItem item = (EntityItem) entity; - ItemStack itemStack = item.p(); + if (entity instanceof ItemEntity item) { + ItemStack itemStack = item.getItem(); if (itemStack == null || itemStack.isEmpty() || itemStack.getComponents().isEmpty()) return; Iterator> iter = itemStack.getComponents().iterator(); while (iter.hasNext()) iter.remove(); @@ -210,8 +202,7 @@ public void stripNbtFromItemEntityLegacy(int entityId) { } @Override - public void validateBaseComponentParse(String string) throws Exception { + public void validateBaseComponentParse(String string) { CraftChatMessage.fromJSON(string); } - } diff --git a/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/dplx/PacketSerializer.java b/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/dplx/PacketSerializer.java index fff43be4..270eee65 100644 --- a/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/dplx/PacketSerializer.java +++ b/paper-v1_20_6/src/main/java/com/ruinscraft/panilla/paper/v1_20_6/io/dplx/PacketSerializer.java @@ -2,14 +2,14 @@ import com.ruinscraft.panilla.api.io.IPacketSerializer; import io.netty.buffer.ByteBuf; -import net.minecraft.network.PacketDataSerializer; +import net.minecraft.network.FriendlyByteBuf; public class PacketSerializer implements IPacketSerializer { - private final PacketDataSerializer handle; + private final FriendlyByteBuf handle; public PacketSerializer(ByteBuf byteBuf) { - this.handle = new PacketDataSerializer(byteBuf); + this.handle = new FriendlyByteBuf(byteBuf); } @Override @@ -19,7 +19,7 @@ public int readableBytes() { @Override public int readVarInt() { - return handle.l(); + return handle.readVarInt(); } @Override diff --git a/paper-v1_21/build.gradle b/paper-v1_21/build.gradle deleted file mode 100644 index b0a987e0..00000000 --- a/paper-v1_21/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -dependencies { - compileOnly project(':panilla-api') - compileOnly 'io.papermc.paper:paper-server:1.21-R0.1-SNAPSHOT' - compileOnly 'org.spigotmc:spigot:1.21.1-R0.1-SNAPSHOT' - implementation 'de.tr7zw:item-nbt-api:2.13.2' -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} diff --git a/paper-v1_21/build.gradle.kts b/paper-v1_21/build.gradle.kts new file mode 100644 index 00000000..07cea7ae --- /dev/null +++ b/paper-v1_21/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +dependencies { + compileOnly(project(":panilla-api")) + paperweight.paperDevBundle("1.21-R0.1-SNAPSHOT") + implementation(libs.item.nbt.api) + compileOnly("me.lucko:spark-paper:1.10.119-SNAPSHOT") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/PacketInspector.java b/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/PacketInspector.java index 47d66118..f0a7b400 100644 --- a/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/PacketInspector.java +++ b/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/PacketInspector.java @@ -17,7 +17,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.item.EntityItem; +import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; @@ -38,54 +38,51 @@ public PacketInspector(IPanilla panilla) { } @Override - public void checkPacketPlayInClickContainer(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayInWindowClick)) return; - PacketPlayInWindowClick packet = (PacketPlayInWindowClick) packetHandle; - int windowId = packet.b(); + public void checkPacketPlayInClickContainer(Object packetHandle, IPanillaPlayer player) throws NbtNotPermittedException { + if (!(packetHandle instanceof ServerboundContainerClickPacket packet)) return; + int windowId = packet.getContainerId(); if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) return; - int slot = packet.f(); - ItemStack item = packet.g(); + int slot = packet.getSlotNum(); + ItemStack item = packet.getCarriedItem(); if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); String itemClass = item.getDescriptionId(); - String packetClass = "PacketPlayInWindowClick"; + String packetClass = packet.getClass().getSimpleName(); NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); } @Override public void checkPacketPlayInSetCreativeSlot(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayInSetCreativeSlot)) return; - PacketPlayInSetCreativeSlot packet = (PacketPlayInSetCreativeSlot) packetHandle; + if (!(packetHandle instanceof ServerboundSetCreativeModeSlotPacket packet)) return; - int slot = packet.b(); - ItemStack item = packet.e(); + int slot = packet.slotNum(); + ItemStack item = packet.itemStack(); if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); String itemClass = item.getDescriptionId(); - String packetClass = "PacketPlayInSetCreativeSlot"; + String packetClass = packet.getClass().getSimpleName(); NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); } @Override public void checkPacketPlayOutSetSlot(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayOutSetSlot)) return; - PacketPlayOutSetSlot packet = (PacketPlayOutSetSlot) packetHandle; + if (!(packetHandle instanceof ClientboundContainerSetSlotPacket packet)) return; - int windowId = packet.b(); + int windowId = packet.getContainerId(); // check if window is not player inventory and we are ignoring non-player inventories if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) { return; } - int slot = packet.e(); + int slot = packet.getSlot(); - ItemStack item = packet.f(); + ItemStack item = packet.getItem(); if (item == null || item.isEmpty() || item.getComponents().isEmpty()) { return; @@ -100,20 +97,19 @@ public void checkPacketPlayOutSetSlot(Object packetHandle) throws NbtNotPermitte @Override public void checkPacketPlayOutWindowItems(Object packetHandle) throws NbtNotPermittedException { - if (!(packetHandle instanceof PacketPlayOutWindowItems)) return; - PacketPlayOutWindowItems packet = (PacketPlayOutWindowItems) packetHandle; + if (!(packetHandle instanceof ClientboundContainerSetContentPacket packet)) return; - int windowId = packet.b(); + int windowId = packet.getContainerId(); // check if window is not player inventory if (windowId != 0) { return; } - List itemStacks = packet.e(); + List itemStacks = packet.getItems(); for (ItemStack itemStack : itemStacks) { - if (!itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + if (itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { continue; } @@ -127,11 +123,9 @@ public void checkPacketPlayOutWindowItems(Object packetHandle) throws NbtNotPerm @Override public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtNotPermittedException { - if ((!(packetHandle instanceof PacketPlayOutSpawnEntity))) return; + if (!(packetHandle instanceof ClientboundAddEntityPacket packet)) return; - PacketPlayOutSpawnEntity packet = (PacketPlayOutSpawnEntity) packetHandle; - - UUID entityId = packet.e(); + UUID entityId = packet.getUUID(); Entity entity = null; for (ServerLevel worldServer : MinecraftServer.getServer().getAllLevels()) { @@ -139,10 +133,9 @@ public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtN if (entity != null) break; } - if (!(entity instanceof EntityItem)) return; + if (!(entity instanceof ItemEntity item)) return; - EntityItem item = (EntityItem) entity; - ItemStack itemStack = item.p(); + ItemStack itemStack = item.getItem(); if (itemStack == null) { return; @@ -182,7 +175,7 @@ public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtN public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); ServerPlayer entityPlayer = craftPlayer.getHandle(); - PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(entityPlayer.containerMenu.containerId, entityPlayer.containerMenu.incrementStateId(), slot, new ItemStack(Blocks.AIR)); + ClientboundContainerSetSlotPacket packet = new ClientboundContainerSetSlotPacket(entityPlayer.containerMenu.containerId, entityPlayer.containerMenu.incrementStateId(), slot, new ItemStack(Blocks.AIR)); entityPlayer.connection.send(packet); } @@ -195,9 +188,8 @@ public void stripNbtFromItemEntity(UUID entityId) { if (entity != null) break; } - if (entity instanceof EntityItem) { - EntityItem item = (EntityItem) entity; - ItemStack itemStack = item.p(); + if (entity instanceof ItemEntity item) { + ItemStack itemStack = item.getItem(); if (itemStack == null || itemStack.isEmpty() || itemStack.getComponents().isEmpty()) return; Iterator> iter = itemStack.getComponents().iterator(); while (iter.hasNext()) iter.remove(); @@ -210,8 +202,7 @@ public void stripNbtFromItemEntityLegacy(int entityId) { } @Override - public void validateBaseComponentParse(String string) throws Exception { + public void validateBaseComponentParse(String string) { CraftChatMessage.fromJSON(string); } - } diff --git a/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/dplx/PacketSerializer.java b/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/dplx/PacketSerializer.java index 6ac617b8..04070ef1 100644 --- a/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/dplx/PacketSerializer.java +++ b/paper-v1_21/src/main/java/com/ruinscraft/panilla/paper/v1_21/io/dplx/PacketSerializer.java @@ -2,14 +2,14 @@ import com.ruinscraft.panilla.api.io.IPacketSerializer; import io.netty.buffer.ByteBuf; -import net.minecraft.network.PacketDataSerializer; +import net.minecraft.network.FriendlyByteBuf; public class PacketSerializer implements IPacketSerializer { - private final PacketDataSerializer handle; + private final FriendlyByteBuf handle; public PacketSerializer(ByteBuf byteBuf) { - this.handle = new PacketDataSerializer(byteBuf); + this.handle = new FriendlyByteBuf(byteBuf); } @Override @@ -19,7 +19,7 @@ public int readableBytes() { @Override public int readVarInt() { - return handle.l(); + return handle.readVarInt(); } @Override diff --git a/paper-v1_21_3/build.gradle.kts b/paper-v1_21_3/build.gradle.kts new file mode 100644 index 00000000..aabb3f2e --- /dev/null +++ b/paper-v1_21_3/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +dependencies { + compileOnly(project(":panilla-api")) + paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT") + implementation(libs.item.nbt.api) +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/InventoryCleaner.java b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/InventoryCleaner.java new file mode 100644 index 00000000..578afd38 --- /dev/null +++ b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/InventoryCleaner.java @@ -0,0 +1,60 @@ +package com.ruinscraft.panilla.paper.v1_21_3; + +import com.ruinscraft.panilla.api.IInventoryCleaner; +import com.ruinscraft.panilla.api.IPanilla; +import com.ruinscraft.panilla.api.IPanillaPlayer; +import com.ruinscraft.panilla.api.exception.FailedNbt; +import com.ruinscraft.panilla.api.exception.FailedNbtList; +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.checks.NbtChecks; +import com.ruinscraft.panilla.paper.v1_21_3.nbt.NbtTagCompound; +import de.tr7zw.changeme.nbtapi.NBT; +import net.minecraft.core.component.TypedDataComponent; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.entity.CraftPlayer; + +import java.util.Iterator; + +public class InventoryCleaner implements IInventoryCleaner { + + private final IPanilla panilla; + + public InventoryCleaner(IPanilla panilla) { + this.panilla = panilla; + } + + @Override + public void clean(IPanillaPlayer player) { + CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); + Inventory container = craftPlayer.getHandle().getInventory(); + + for (int slot = 0; slot < container.getContents().size(); slot++) { + ItemStack itemStack = container.getContents().get(slot); + + if (itemStack == null || itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + continue; + } + + INbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(itemStack.getBukkitStack()).getCompound("components")); + String itemName = itemStack.getItem().getDescriptionId(); + + FailedNbtList failedNbtList = NbtChecks.checkAll(tag, itemName, panilla); + + for (FailedNbt failedNbt : failedNbtList) { + if (FailedNbt.failsThreshold(failedNbt)) { + Iterator> iter = itemStack.getComponents().iterator(); + while (iter.hasNext()) iter.remove(); + + break; + } else if (FailedNbt.fails(failedNbt)) { + NBT.modifyComponents(itemStack.getBukkitStack(), s -> { + s.removeKey(failedNbt.key); + }); + break; + } + } + } + } + +} diff --git a/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/PacketInspector.java b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/PacketInspector.java new file mode 100644 index 00000000..7a7b85e6 --- /dev/null +++ b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/PacketInspector.java @@ -0,0 +1,208 @@ +package com.ruinscraft.panilla.paper.v1_21_3.io; + +import com.ruinscraft.panilla.api.IPanilla; +import com.ruinscraft.panilla.api.IPanillaPlayer; +import com.ruinscraft.panilla.api.exception.EntityNbtNotPermittedException; +import com.ruinscraft.panilla.api.exception.FailedNbt; +import com.ruinscraft.panilla.api.exception.FailedNbtList; +import com.ruinscraft.panilla.api.exception.NbtNotPermittedException; +import com.ruinscraft.panilla.api.io.IPacketInspector; +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.checks.NbtChecks; +import com.ruinscraft.panilla.paper.v1_21_3.nbt.NbtTagCompound; +import de.tr7zw.changeme.nbtapi.NBT; +import net.minecraft.core.component.TypedDataComponent; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftChatMessage; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +public class PacketInspector implements IPacketInspector { + + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + + @Override + public void checkPacketPlayInClickContainer(Object packetHandle, IPanillaPlayer player) throws NbtNotPermittedException { + if (!(packetHandle instanceof ServerboundContainerClickPacket packet)) return; + int windowId = packet.getContainerId(); + if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) return; + + int slot = packet.getSlotNum(); + ItemStack item = packet.getCarriedItem(); + if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); + String itemClass = item.getItem().getDescriptionId(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); + } + + @Override + public void checkPacketPlayInSetCreativeSlot(Object packetHandle) throws NbtNotPermittedException { + if (!(packetHandle instanceof ServerboundSetCreativeModeSlotPacket packet)) return; + + int slot = packet.slotNum(); + ItemStack item = packet.itemStack(); + if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); + String itemClass = item.getItem().getDescriptionId(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); + } + + @Override + public void checkPacketPlayOutSetSlot(Object packetHandle) throws NbtNotPermittedException { + if (!(packetHandle instanceof ClientboundContainerSetSlotPacket packet)) return; + + int windowId = packet.getContainerId(); + + // check if window is not player inventory and we are ignoring non-player inventories + if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) { + return; + } + + int slot = packet.getSlot(); + + ItemStack item = packet.getItem(); + + if (item == null || item.isEmpty() || item.getComponents().isEmpty()) { + return; + } + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); + String itemClass = item.getClass().getSimpleName(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayOut(slot, tag, itemClass, packetClass, panilla); + } + + @Override + public void checkPacketPlayOutWindowItems(Object packetHandle) throws NbtNotPermittedException { + if (!(packetHandle instanceof ClientboundContainerSetContentPacket packet)) return; + + int windowId = packet.getContainerId(); + + // check if window is not player inventory + if (windowId != 0) { + return; + } + + List itemStacks = packet.getItems(); + + for (ItemStack itemStack : itemStacks) { + if (itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + continue; + } + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(itemStack.asBukkitCopy()).getCompound("components")); + String itemClass = itemStack.getClass().getSimpleName(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayOut(0, tag, itemClass, packetClass, panilla); // TODO: set slot? + } + } + + @Override + public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtNotPermittedException { + if (!(packetHandle instanceof ClientboundAddEntityPacket packet)) return; + + UUID entityId = packet.getUUID(); + Entity entity = null; + + for (ServerLevel worldServer : MinecraftServer.getServer().getAllLevels()) { + entity = worldServer.moonrise$getEntityLookup().get(entityId); + if (entity != null) break; + } + + if (!(entity instanceof ItemEntity item)) return; + + ItemStack itemStack = item.getItem(); + + if (itemStack == null) { + return; + } + + if (itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + return; + } + + INbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(itemStack.getBukkitStack()).getCompound("components")); + String itemName = itemStack.getItem().getDescriptionId(); + String worldName = ""; + + try { + Field worldField = Entity.class.getDeclaredField("level"); + worldField.setAccessible(true); + Level world = (Level) worldField.get(entity); + worldName = world.getWorld().getName(); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + + FailedNbtList failedNbtList = NbtChecks.checkAll(tag, itemName, panilla); + + if (failedNbtList.containsCritical()) { + throw new EntityNbtNotPermittedException(packet.getClass().getSimpleName(), false, failedNbtList.getCritical(), entityId, worldName); + } + + FailedNbt failedNbt = failedNbtList.findFirstNonCritical(); + + if (failedNbt != null) { + throw new EntityNbtNotPermittedException(packet.getClass().getSimpleName(), false, failedNbt, entityId, worldName); + } + } + + @Override + public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { + CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); + ServerPlayer entityPlayer = craftPlayer.getHandle(); + ClientboundContainerSetSlotPacket packet = new ClientboundContainerSetSlotPacket(entityPlayer.containerMenu.containerId, entityPlayer.containerMenu.incrementStateId(), slot, new ItemStack(Blocks.AIR)); + entityPlayer.connection.send(packet); + } + + @Override + public void stripNbtFromItemEntity(UUID entityId) { + Entity entity = null; + + for (ServerLevel worldServer : MinecraftServer.getServer().getAllLevels()) { + entity = worldServer.moonrise$getEntityLookup().get(entityId); + if (entity != null) break; + } + + if (entity instanceof ItemEntity item) { + ItemStack itemStack = item.getItem(); + if (itemStack == null || itemStack.isEmpty() || itemStack.getComponents().isEmpty()) return; + Iterator> iter = itemStack.getComponents().iterator(); + while (iter.hasNext()) iter.remove(); + } + } + + @Override + public void stripNbtFromItemEntityLegacy(int entityId) { + throw new RuntimeException("cannot use #stripNbtFromItemEntityLegacy on 1.20.6"); + } + + @Override + public void validateBaseComponentParse(String string) { + CraftChatMessage.fromJSON(string); + } +} diff --git a/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/PlayerInjector.java b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/PlayerInjector.java new file mode 100644 index 00000000..1e11439c --- /dev/null +++ b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/PlayerInjector.java @@ -0,0 +1,39 @@ +package com.ruinscraft.panilla.paper.v1_21_3.io; + +import com.ruinscraft.panilla.api.IPanillaPlayer; +import com.ruinscraft.panilla.api.io.IPlayerInjector; +import de.tr7zw.changeme.nbtapi.NBT; +import io.netty.channel.Channel; +import io.netty.handler.codec.ByteToMessageDecoder; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.craftbukkit.entity.CraftPlayer; + +public class PlayerInjector implements IPlayerInjector { + + static { + NBT.preloadApi(); + } + + @Override + public Channel getPlayerChannel(IPanillaPlayer player) throws IllegalArgumentException { + CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); + ServerPlayer entityPlayer = craftPlayer.getHandle(); + return entityPlayer.connection.connection.channel; + } + + @Override + public int getCompressionLevel() { + return 256; + } + + @Override + public ByteToMessageDecoder getDecompressor() { + return null; + } + + @Override + public ByteToMessageDecoder getDecoder() { + throw new RuntimeException("Not implemented"); + } + +} diff --git a/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/dplx/PacketSerializer.java b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/dplx/PacketSerializer.java new file mode 100644 index 00000000..e69f4cc4 --- /dev/null +++ b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/io/dplx/PacketSerializer.java @@ -0,0 +1,35 @@ +package com.ruinscraft.panilla.paper.v1_21_3.io.dplx; + +import com.ruinscraft.panilla.api.io.IPacketSerializer; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.FriendlyByteBuf; + +public class PacketSerializer implements IPacketSerializer { + + private final FriendlyByteBuf handle; + + public PacketSerializer(ByteBuf byteBuf) { + this.handle = new FriendlyByteBuf(byteBuf); + } + + @Override + public int readableBytes() { + return handle.readableBytes(); + } + + @Override + public int readVarInt() { + return handle.readVarInt(); + } + + @Override + public ByteBuf readBytes(int i) { + return handle.readBytes(i); + } + + @Override + public ByteBuf readBytes(byte[] buffer) { + return handle.readBytes(buffer); + } + +} diff --git a/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/nbt/NbtTagCompound.java b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/nbt/NbtTagCompound.java new file mode 100644 index 00000000..aac5af93 --- /dev/null +++ b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/nbt/NbtTagCompound.java @@ -0,0 +1,88 @@ +package com.ruinscraft.panilla.paper.v1_21_3.nbt; + +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.INbtTagList; +import com.ruinscraft.panilla.api.nbt.NbtDataType; +import de.tr7zw.changeme.nbtapi.NBTType; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; + +import java.util.Collections; +import java.util.Set; + +public class NbtTagCompound implements INbtTagCompound { + + private final ReadWriteNBT handle; + + public NbtTagCompound(ReadWriteNBT handle) { + this.handle = handle; + } + + @Override + public Object getHandle() { + return handle; + } + + @Override + public boolean hasKey(String key) { + if (handle == null) return false; + return handle.hasTag(key); + } + + @Override + public boolean hasKeyOfType(String key, NbtDataType nbtDataType) { + if (handle == null) return false; + return handle.hasTag(key, NBTType.valueOf(nbtDataType.id)); + } + + @Override + public Set getKeys() { + if (handle == null) return Collections.emptySet(); + return handle.getKeys(); + } + + @Override + public int getInt(String key) { + return handle.getInteger(key); + } + + @Override + public double getDouble(String key) { + return handle.getDouble(key); + } + + @Override + public short getShort(String key) { + return handle.getShort(key); + } + + @Override + public byte getByte(String key) { + return handle.getByte(key); + } + + @Override + public String getString(String key) { + return handle.getString(key); + } + + @Override + public int[] getIntArray(String key) { + return handle.getIntArray(key); + } + + @Override + public INbtTagList getList(String key, NbtDataType nbtDataType) { + return new NbtTagList(nbtDataType == NbtDataType.STRING ? handle.getStringList(key) : handle.getCompoundList(key)); + } + + @Override + public INbtTagList getList(String key) { + return new NbtTagList(handle.getCompoundList(key)); + } + + @Override + public INbtTagCompound getCompound(String key) { + return new NbtTagCompound(handle.getCompound(key)); + } + +} diff --git a/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/nbt/NbtTagList.java b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/nbt/NbtTagList.java new file mode 100644 index 00000000..09a6e7ba --- /dev/null +++ b/paper-v1_21_3/src/main/java/com/ruinscraft/panilla/paper/v1_21_3/nbt/NbtTagList.java @@ -0,0 +1,36 @@ +package com.ruinscraft.panilla.paper.v1_21_3.nbt; + +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.INbtTagList; +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList; + +public class NbtTagList implements INbtTagList { + + private final ReadableNBTList handle; + + public NbtTagList(ReadableNBTList handle) { + this.handle = handle; + } + + @Override + public INbtTagCompound getCompound(int index) { + return new NbtTagCompound((NBTCompound) handle.get(index)); + } + + @Override + public String getString(int index) { + return (String) handle.get(index); + } + + @Override + public boolean isCompound(int index) { + return handle.get(index) instanceof NBTCompound; + } + + @Override + public int size() { + return handle.size(); + } + +} diff --git a/paper-v1_21_5/build.gradle.kts b/paper-v1_21_5/build.gradle.kts new file mode 100644 index 00000000..4f013851 --- /dev/null +++ b/paper-v1_21_5/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +dependencies { + compileOnly(project(":panilla-api")) + paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT") + implementation(libs.item.nbt.api) +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} \ No newline at end of file diff --git a/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/InventoryCleaner.java b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/InventoryCleaner.java new file mode 100644 index 00000000..72953d52 --- /dev/null +++ b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/InventoryCleaner.java @@ -0,0 +1,60 @@ +package com.ruinscraft.panilla.paper.v1_21_5; + +import com.ruinscraft.panilla.api.IInventoryCleaner; +import com.ruinscraft.panilla.api.IPanilla; +import com.ruinscraft.panilla.api.IPanillaPlayer; +import com.ruinscraft.panilla.api.exception.FailedNbt; +import com.ruinscraft.panilla.api.exception.FailedNbtList; +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.checks.NbtChecks; +import com.ruinscraft.panilla.paper.v1_21_5.nbt.NbtTagCompound; +import de.tr7zw.changeme.nbtapi.NBT; +import net.minecraft.core.component.TypedDataComponent; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.entity.CraftPlayer; + +import java.util.Iterator; + +public class InventoryCleaner implements IInventoryCleaner { + + private final IPanilla panilla; + + public InventoryCleaner(IPanilla panilla) { + this.panilla = panilla; + } + + @Override + public void clean(IPanillaPlayer player) { + CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); + Inventory container = craftPlayer.getHandle().getInventory(); + + for (int slot = 0; slot < container.getContents().size(); slot++) { + ItemStack itemStack = container.getContents().get(slot); + + if (itemStack == null || itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + continue; + } + + INbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(itemStack.getBukkitStack()).getCompound("components")); + String itemName = itemStack.getItem().getDescriptionId(); + + FailedNbtList failedNbtList = NbtChecks.checkAll(tag, itemName, panilla); + + for (FailedNbt failedNbt : failedNbtList) { + if (FailedNbt.failsThreshold(failedNbt)) { + Iterator> iter = itemStack.getComponents().iterator(); + while (iter.hasNext()) iter.remove(); + + break; + } else if (FailedNbt.fails(failedNbt)) { + NBT.modifyComponents(itemStack.getBukkitStack(), s -> { + s.removeKey(failedNbt.key); + }); + break; + } + } + } + } + +} diff --git a/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/PacketInspector.java b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/PacketInspector.java new file mode 100644 index 00000000..af7d261c --- /dev/null +++ b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/PacketInspector.java @@ -0,0 +1,228 @@ +package com.ruinscraft.panilla.paper.v1_21_5.io; + +import com.ruinscraft.panilla.api.IPanilla; +import com.ruinscraft.panilla.api.IPanillaPlayer; +import com.ruinscraft.panilla.api.exception.EntityNbtNotPermittedException; +import com.ruinscraft.panilla.api.exception.FailedNbt; +import com.ruinscraft.panilla.api.exception.FailedNbtList; +import com.ruinscraft.panilla.api.exception.NbtNotPermittedException; +import com.ruinscraft.panilla.api.io.IPacketInspector; +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.checks.NbtChecks; +import com.ruinscraft.panilla.paper.v1_21_5.nbt.NbtTagCompound; +import de.tr7zw.changeme.nbtapi.NBT; +import net.minecraft.core.component.TypedDataComponent; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftChatMessage; + +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +public class PacketInspector implements IPacketInspector { + + private final IPanilla panilla; + + public PacketInspector(IPanilla panilla) { + this.panilla = panilla; + } + + @Override + public void checkPacketPlayInClickContainer(Object packetHandle, IPanillaPlayer player) throws NbtNotPermittedException { + if (!(packetHandle instanceof ServerboundContainerClickPacket packet)) return; + int windowId = packet.containerId(); + if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) return; + + var craftPlayer = (CraftPlayer) player.getHandle(); + var nmsPlayer = craftPlayer.getHandle(); + var menu = nmsPlayer.containerMenu; + + int slot = packet.slotNum(); + + if (slot < 0 || slot >= menu.slots.size()) { + ItemStack carried = menu.getCarried(); + if (carried == null || carried.isEmpty() || carried.getComponents().isEmpty()) return; + + NbtTagCompound tag = new NbtTagCompound( + NBT.itemStackToNBT(carried.getBukkitStack()).getCompound("components") + ); + String itemClass = carried.getItem().getDescriptionId(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayIn(-1, tag, itemClass, packetClass, panilla); + return; + } + + ItemStack item = ((CraftPlayer) player.getHandle()).getHandle().containerMenu.getSlot(slot).getItem(); + + if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); + String itemClass = item.getItem().getDescriptionId(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); + } + + @Override + public void checkPacketPlayInSetCreativeSlot(Object packetHandle) throws NbtNotPermittedException { + if (!(packetHandle instanceof ServerboundSetCreativeModeSlotPacket packet)) return; + + int slot = packet.slotNum(); + ItemStack item = packet.itemStack(); + if (item == null || item.isEmpty() || item.getComponents().isEmpty()) return; + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); + String itemClass = item.getItem().getDescriptionId(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla); + } + + @Override + public void checkPacketPlayOutSetSlot(Object packetHandle) throws NbtNotPermittedException { + if (!(packetHandle instanceof ClientboundContainerSetSlotPacket packet)) return; + + int windowId = packet.getContainerId(); + + // check if window is not player inventory and we are ignoring non-player inventories + if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) { + return; + } + + int slot = packet.getSlot(); + + ItemStack item = packet.getItem(); + + if (item == null || item.isEmpty() || item.getComponents().isEmpty()) { + return; + } + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(item.getBukkitStack()).getCompound("components")); + String itemClass = item.getClass().getSimpleName(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayOut(slot, tag, itemClass, packetClass, panilla); + } + + @Override + public void checkPacketPlayOutWindowItems(Object packetHandle) throws NbtNotPermittedException { + if (!(packetHandle instanceof ClientboundContainerSetContentPacket packet)) return; + + int windowId = packet.containerId(); + + // check if window is not player inventory + if (windowId != 0) { + return; + } + + List itemStacks = packet.items(); + + for (ItemStack itemStack : itemStacks) { + if (itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + continue; + } + + NbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(itemStack.asBukkitCopy()).getCompound("components")); + String itemClass = itemStack.getClass().getSimpleName(); + String packetClass = packet.getClass().getSimpleName(); + + NbtChecks.checkPacketPlayOut(0, tag, itemClass, packetClass, panilla); // TODO: set slot? + } + } + + @Override + public void checkPacketPlayOutSpawnEntity(Object packetHandle) throws EntityNbtNotPermittedException { + if (!(packetHandle instanceof ClientboundAddEntityPacket packet)) return; + + UUID entityId = packet.getUUID(); + Entity entity = null; + + for (ServerLevel worldServer : MinecraftServer.getServer().getAllLevels()) { + entity = worldServer.moonrise$getEntityLookup().get(entityId); + if (entity != null) break; + } + + if (!(entity instanceof ItemEntity item)) return; + + ItemStack itemStack = item.getItem(); + + if (itemStack == null) { + return; + } + + if (itemStack.isEmpty() || itemStack.getComponents().isEmpty()) { + return; + } + + INbtTagCompound tag = new NbtTagCompound(NBT.itemStackToNBT(itemStack.getBukkitStack()).getCompound("components")); + String itemName = itemStack.getItem().getDescriptionId(); + String worldName = ""; + + try { + Field worldField = Entity.class.getDeclaredField("level"); + worldField.setAccessible(true); + Level world = (Level) worldField.get(entity); + worldName = world.getWorld().getName(); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + + FailedNbtList failedNbtList = NbtChecks.checkAll(tag, itemName, panilla); + + if (failedNbtList.containsCritical()) { + throw new EntityNbtNotPermittedException(packet.getClass().getSimpleName(), false, failedNbtList.getCritical(), entityId, worldName); + } + + FailedNbt failedNbt = failedNbtList.findFirstNonCritical(); + + if (failedNbt != null) { + throw new EntityNbtNotPermittedException(packet.getClass().getSimpleName(), false, failedNbt, entityId, worldName); + } + } + + @Override + public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) { + CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); + ServerPlayer entityPlayer = craftPlayer.getHandle(); + ClientboundContainerSetSlotPacket packet = new ClientboundContainerSetSlotPacket(entityPlayer.containerMenu.containerId, entityPlayer.containerMenu.incrementStateId(), slot, new ItemStack(Blocks.AIR)); + entityPlayer.connection.send(packet); + } + + @Override + public void stripNbtFromItemEntity(UUID entityId) { + Entity entity = null; + + for (ServerLevel worldServer : MinecraftServer.getServer().getAllLevels()) { + entity = worldServer.moonrise$getEntityLookup().get(entityId); + if (entity != null) break; + } + + if (entity instanceof ItemEntity item) { + ItemStack itemStack = item.getItem(); + if (itemStack == null || itemStack.isEmpty() || itemStack.getComponents().isEmpty()) return; + Iterator> iter = itemStack.getComponents().iterator(); + while (iter.hasNext()) iter.remove(); + } + } + + @Override + public void stripNbtFromItemEntityLegacy(int entityId) { + throw new RuntimeException("cannot use #stripNbtFromItemEntityLegacy on 1.20.6"); + } + + @Override + public void validateBaseComponentParse(String string) { + CraftChatMessage.fromJSON(string); + } +} diff --git a/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/PlayerInjector.java b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/PlayerInjector.java new file mode 100644 index 00000000..8be769d8 --- /dev/null +++ b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/PlayerInjector.java @@ -0,0 +1,39 @@ +package com.ruinscraft.panilla.paper.v1_21_5.io; + +import com.ruinscraft.panilla.api.IPanillaPlayer; +import com.ruinscraft.panilla.api.io.IPlayerInjector; +import de.tr7zw.changeme.nbtapi.NBT; +import io.netty.channel.Channel; +import io.netty.handler.codec.ByteToMessageDecoder; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.craftbukkit.entity.CraftPlayer; + +public class PlayerInjector implements IPlayerInjector { + + static { + NBT.preloadApi(); + } + + @Override + public Channel getPlayerChannel(IPanillaPlayer player) throws IllegalArgumentException { + CraftPlayer craftPlayer = (CraftPlayer) player.getHandle(); + ServerPlayer entityPlayer = craftPlayer.getHandle(); + return entityPlayer.connection.connection.channel; + } + + @Override + public int getCompressionLevel() { + return 256; + } + + @Override + public ByteToMessageDecoder getDecompressor() { + return null; + } + + @Override + public ByteToMessageDecoder getDecoder() { + throw new RuntimeException("Not implemented"); + } + +} diff --git a/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/dplx/PacketSerializer.java b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/dplx/PacketSerializer.java new file mode 100644 index 00000000..78eff3f5 --- /dev/null +++ b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/io/dplx/PacketSerializer.java @@ -0,0 +1,35 @@ +package com.ruinscraft.panilla.paper.v1_21_5.io.dplx; + +import com.ruinscraft.panilla.api.io.IPacketSerializer; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.FriendlyByteBuf; + +public class PacketSerializer implements IPacketSerializer { + + private final FriendlyByteBuf handle; + + public PacketSerializer(ByteBuf byteBuf) { + this.handle = new FriendlyByteBuf(byteBuf); + } + + @Override + public int readableBytes() { + return handle.readableBytes(); + } + + @Override + public int readVarInt() { + return handle.readVarInt(); + } + + @Override + public ByteBuf readBytes(int i) { + return handle.readBytes(i); + } + + @Override + public ByteBuf readBytes(byte[] buffer) { + return handle.readBytes(buffer); + } + +} diff --git a/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/nbt/NbtTagCompound.java b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/nbt/NbtTagCompound.java new file mode 100644 index 00000000..55a408e6 --- /dev/null +++ b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/nbt/NbtTagCompound.java @@ -0,0 +1,88 @@ +package com.ruinscraft.panilla.paper.v1_21_5.nbt; + +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.INbtTagList; +import com.ruinscraft.panilla.api.nbt.NbtDataType; +import de.tr7zw.changeme.nbtapi.NBTType; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; + +import java.util.Collections; +import java.util.Set; + +public class NbtTagCompound implements INbtTagCompound { + + private final ReadWriteNBT handle; + + public NbtTagCompound(ReadWriteNBT handle) { + this.handle = handle; + } + + @Override + public Object getHandle() { + return handle; + } + + @Override + public boolean hasKey(String key) { + if (handle == null) return false; + return handle.hasTag(key); + } + + @Override + public boolean hasKeyOfType(String key, NbtDataType nbtDataType) { + if (handle == null) return false; + return handle.hasTag(key, NBTType.valueOf(nbtDataType.id)); + } + + @Override + public Set getKeys() { + if (handle == null) return Collections.emptySet(); + return handle.getKeys(); + } + + @Override + public int getInt(String key) { + return handle.getInteger(key); + } + + @Override + public double getDouble(String key) { + return handle.getDouble(key); + } + + @Override + public short getShort(String key) { + return handle.getShort(key); + } + + @Override + public byte getByte(String key) { + return handle.getByte(key); + } + + @Override + public String getString(String key) { + return handle.getString(key); + } + + @Override + public int[] getIntArray(String key) { + return handle.getIntArray(key); + } + + @Override + public INbtTagList getList(String key, NbtDataType nbtDataType) { + return new NbtTagList(nbtDataType == NbtDataType.STRING ? handle.getStringList(key) : handle.getCompoundList(key)); + } + + @Override + public INbtTagList getList(String key) { + return new NbtTagList(handle.getCompoundList(key)); + } + + @Override + public INbtTagCompound getCompound(String key) { + return new NbtTagCompound(handle.getCompound(key)); + } + +} diff --git a/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/nbt/NbtTagList.java b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/nbt/NbtTagList.java new file mode 100644 index 00000000..142aca0c --- /dev/null +++ b/paper-v1_21_5/src/main/java/com/ruinscraft/panilla/paper/v1_21_5/nbt/NbtTagList.java @@ -0,0 +1,36 @@ +package com.ruinscraft.panilla.paper.v1_21_5.nbt; + +import com.ruinscraft.panilla.api.nbt.INbtTagCompound; +import com.ruinscraft.panilla.api.nbt.INbtTagList; +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList; + +public class NbtTagList implements INbtTagList { + + private final ReadableNBTList handle; + + public NbtTagList(ReadableNBTList handle) { + this.handle = handle; + } + + @Override + public INbtTagCompound getCompound(int index) { + return new NbtTagCompound((NBTCompound) handle.get(index)); + } + + @Override + public String getString(int index) { + return (String) handle.get(index); + } + + @Override + public boolean isCompound(int index) { + return handle.get(index) instanceof NBTCompound; + } + + @Override + public int size() { + return handle.size(); + } + +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 88a83ea2..00000000 --- a/settings.gradle +++ /dev/null @@ -1,51 +0,0 @@ -rootProject.name = 'panilla' - -// api -include(':panilla-api') - -// bukkit -include(':panilla-craftbukkit-v1_8_R3') -include(':panilla-craftbukkit-v1_12_R1') -include(':panilla-craftbukkit-v1_13_R2') -include(':panilla-craftbukkit-v1_14_R1') -include(':panilla-craftbukkit-v1_15_R1') -include(':panilla-craftbukkit-v1_16_R1') -include(':panilla-craftbukkit-v1_16_R2') -include(':panilla-craftbukkit-v1_16_R3') -include(':panilla-craftbukkit-v1_17_R1') -include(':panilla-craftbukkit-v1_18_R1') -include(':panilla-craftbukkit-v1_18_R2') -include(':panilla-craftbukkit-v1_19_R1') -include(':panilla-craftbukkit-v1_19_R2') -include(':panilla-craftbukkit-v1_19_R3') -include(':panilla-craftbukkit-v1_20_R1') -include(':panilla-craftbukkit-v1_20_R2') -include(':panilla-craftbukkit-v1_20_R3') -include(':panilla-paper-v1_20_6') -include(':panilla-paper-v1_21') -include(':panilla-bukkit') - -// api -project(':panilla-api').projectDir = file('api') - -// bukkit -project(':panilla-craftbukkit-v1_8_R3').projectDir = file('craftbukkit-v1_8_R3') -project(':panilla-craftbukkit-v1_12_R1').projectDir = file('craftbukkit-v1_12_R1') -project(':panilla-craftbukkit-v1_13_R2').projectDir = file('craftbukkit-v1_13_R2') -project(':panilla-craftbukkit-v1_14_R1').projectDir = file('craftbukkit-v1_14_R1') -project(':panilla-craftbukkit-v1_15_R1').projectDir = file('craftbukkit-v1_15_R1') -project(':panilla-craftbukkit-v1_16_R1').projectDir = file('craftbukkit-v1_16_R1') -project(':panilla-craftbukkit-v1_16_R2').projectDir = file('craftbukkit-v1_16_R2') -project(':panilla-craftbukkit-v1_16_R3').projectDir = file('craftbukkit-v1_16_R3') -project(':panilla-craftbukkit-v1_17_R1').projectDir = file('craftbukkit-v1_17_R1') -project(':panilla-craftbukkit-v1_18_R1').projectDir = file('craftbukkit-v1_18_R1') -project(':panilla-craftbukkit-v1_18_R2').projectDir = file('craftbukkit-v1_18_R2') -project(':panilla-craftbukkit-v1_19_R1').projectDir = file('craftbukkit-v1_19_R1') -project(':panilla-craftbukkit-v1_19_R2').projectDir = file('craftbukkit-v1_19_R2') -project(':panilla-craftbukkit-v1_19_R3').projectDir = file('craftbukkit-v1_19_R3') -project(':panilla-craftbukkit-v1_20_R1').projectDir = file('craftbukkit-v1_20_R1') -project(':panilla-craftbukkit-v1_20_R2').projectDir = file('craftbukkit-v1_20_R2') -project(':panilla-craftbukkit-v1_20_R3').projectDir = file('craftbukkit-v1_20_R3') -project(':panilla-paper-v1_20_6').projectDir = file('paper-v1_20_6') -project(':panilla-paper-v1_21').projectDir = file('paper-v1_21') -project(':panilla-bukkit').projectDir = file('bukkit') diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..33dce0be --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,63 @@ +rootProject.name = "panilla" + +// api +include(":panilla-api") + +// bukkit +include( + ":panilla-craftbukkit-v1_8_R3", + ":panilla-craftbukkit-v1_12_R1", + ":panilla-craftbukkit-v1_13_R2", + ":panilla-craftbukkit-v1_14_R1", + ":panilla-craftbukkit-v1_15_R1", + ":panilla-craftbukkit-v1_16_R1", + ":panilla-craftbukkit-v1_16_R2", + ":panilla-craftbukkit-v1_16_R3", + ":panilla-craftbukkit-v1_17_R1", + ":panilla-craftbukkit-v1_18_R1", + ":panilla-craftbukkit-v1_18_R2", + ":panilla-craftbukkit-v1_19_R1", + ":panilla-craftbukkit-v1_19_R2", + ":panilla-craftbukkit-v1_19_R3", + ":panilla-craftbukkit-v1_20_R1", + ":panilla-craftbukkit-v1_20_R2", + ":panilla-craftbukkit-v1_20_R3", + ":panilla-paper-v1_20_6", + ":panilla-paper-v1_21", + ":panilla-paper-v1_21_3", + ":panilla-paper-v1_21_5", + ":panilla-bukkit" +) + +// api +project(":panilla-api").projectDir = file("api") + +// bukkit +project(":panilla-craftbukkit-v1_8_R3").projectDir = file("craftbukkit-v1_8_R3") +project(":panilla-craftbukkit-v1_12_R1").projectDir = file("craftbukkit-v1_12_R1") +project(":panilla-craftbukkit-v1_13_R2").projectDir = file("craftbukkit-v1_13_R2") +project(":panilla-craftbukkit-v1_14_R1").projectDir = file("craftbukkit-v1_14_R1") +project(":panilla-craftbukkit-v1_15_R1").projectDir = file("craftbukkit-v1_15_R1") +project(":panilla-craftbukkit-v1_16_R1").projectDir = file("craftbukkit-v1_16_R1") +project(":panilla-craftbukkit-v1_16_R2").projectDir = file("craftbukkit-v1_16_R2") +project(":panilla-craftbukkit-v1_16_R3").projectDir = file("craftbukkit-v1_16_R3") +project(":panilla-craftbukkit-v1_17_R1").projectDir = file("craftbukkit-v1_17_R1") +project(":panilla-craftbukkit-v1_18_R1").projectDir = file("craftbukkit-v1_18_R1") +project(":panilla-craftbukkit-v1_18_R2").projectDir = file("craftbukkit-v1_18_R2") +project(":panilla-craftbukkit-v1_19_R1").projectDir = file("craftbukkit-v1_19_R1") +project(":panilla-craftbukkit-v1_19_R2").projectDir = file("craftbukkit-v1_19_R2") +project(":panilla-craftbukkit-v1_19_R3").projectDir = file("craftbukkit-v1_19_R3") +project(":panilla-craftbukkit-v1_20_R1").projectDir = file("craftbukkit-v1_20_R1") +project(":panilla-craftbukkit-v1_20_R2").projectDir = file("craftbukkit-v1_20_R2") +project(":panilla-craftbukkit-v1_20_R3").projectDir = file("craftbukkit-v1_20_R3") +project(":panilla-paper-v1_20_6").projectDir = file("paper-v1_20_6") +project(":panilla-paper-v1_21").projectDir = file("paper-v1_21") +project(":panilla-paper-v1_21_3").projectDir = file("paper-v1_21_3") +project(":panilla-paper-v1_21_5").projectDir = file("paper-v1_21_5") +project(":panilla-bukkit").projectDir = file("bukkit") + +pluginManagement { + plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.19" + } +}