diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml index e1e0d1d518..fcc3435e70 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -20,6 +20,8 @@ body: options: - label: I am using the official english version of Slimefun and did not modify the jar. required: true + - label: I downloaded the official version from the new build site [Blob Builds](https://blob.build/). + required: true - label: I am using an up to date "DEV" (not "RC") version of Slimefun. required: true - label: I am aware that issues related to Slimefun addons need to be reported on their bug trackers and not here. diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index 4d44968a97..8f3836fad9 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Approve via actions - uses: hmarr/auto-approve-action@v3.2.1 + uses: hmarr/auto-approve-action@v4.0.0 if: github.actor == 'TheBusyBot' || github.actor == 'renovate[bot]' with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/auto-squash.yml b/.github/workflows/auto-squash.yml index 050acaec2e..8b8ef1f434 100644 --- a/.github/workflows/auto-squash.yml +++ b/.github/workflows/auto-squash.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Auto squash - uses: pascalgn/automerge-action@v0.15.6 + uses: pascalgn/automerge-action@v0.16.4 env: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} UPDATE_RETRIES: 0 @@ -42,7 +42,7 @@ jobs: steps: - name: Auto squash - uses: pascalgn/automerge-action@v0.15.6 + uses: pascalgn/automerge-action@v0.16.4 env: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} UPDATE_RETRIES: 0 diff --git a/.github/workflows/discord-webhook.yml b/.github/workflows/discord-webhook.yml index b424d1c383..6735d5d642 100644 --- a/.github/workflows/discord-webhook.yml +++ b/.github/workflows/discord-webhook.yml @@ -21,13 +21,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.2 - - name: Set up Java JDK 17 - uses: actions/setup-java@v4.0.0 + - name: Set up Java JDK 21 + uses: actions/setup-java@v4.6.0 with: distribution: 'adopt' - java-version: '17' + java-version: '21' java-package: jdk architecture: x64 diff --git a/.github/workflows/e2e-testing.yml b/.github/workflows/e2e-testing.yml index 0f7cc57413..e6be9ca39a 100644 --- a/.github/workflows/e2e-testing.yml +++ b/.github/workflows/e2e-testing.yml @@ -25,15 +25,19 @@ jobs: javaVersion: '18' - mcVersion: '1.19.4' javaVersion: '19' - - mcVersion: 'latest' + - mcVersion: '1.20.4' javaVersion: '20' + - mcVersion: '1.20.6' + javaVersion: '21' + #- mcVersion: 'latest' + # javaVersion: '21' steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v4.0.0 + uses: actions/setup-java@v4.6.0 with: distribution: temurin java-version: ${{ matrix.javaVersion }} @@ -62,7 +66,7 @@ jobs: "https://api.papermc.io/v2/projects/paper/versions/$VERSION/builds/$BUILD/downloads/$JAR_FILE" - name: Download Slimefun - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: ${{ inputs.artifact-name }} path: plugins/ diff --git a/.github/workflows/javadocs.yml b/.github/workflows/javadocs.yml new file mode 100644 index 0000000000..f628c2a692 --- /dev/null +++ b/.github/workflows/javadocs.yml @@ -0,0 +1,37 @@ +name: Javadocs + +on: + push: + paths: + - 'src/**' + - 'pom.xml' + +permissions: + contents: read + +jobs: + build: + name: Maven build + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4.6.0 + with: + distribution: 'adopt' + java-version: '21' + java-package: jdk + architecture: x64 + + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + + - name: Build Javadocs + run: mvn javadoc:javadoc diff --git a/.github/workflows/maven-compiler.yml b/.github/workflows/maven-compiler.yml index 41f5aff546..fa79dc66ca 100644 --- a/.github/workflows/maven-compiler.yml +++ b/.github/workflows/maven-compiler.yml @@ -27,11 +27,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4.0.0 + - name: Set up JDK 21 + uses: actions/setup-java@v4.6.0 with: distribution: 'adopt' - java-version: '17' + java-version: '21' java-package: jdk architecture: x64 diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml index 0636851f90..b857b2faa6 100644 --- a/.github/workflows/pr-labels.yml +++ b/.github/workflows/pr-labels.yml @@ -31,7 +31,7 @@ jobs: api: '🔧 API' compatibility: '🤝 Compatibility' - - uses: thollander/actions-comment-pull-request@v2.4.3 + - uses: thollander/actions-comment-pull-request@v2.5.0 name: Leave a comment about the applied label if: ${{ steps.labeller.outputs.applied != 0 }} with: @@ -40,7 +40,7 @@ jobs: Your Pull Request was automatically labelled as: "${{ steps.labeller.outputs.applied }}" Thank you for contributing to this project! ❤️ - - uses: thollander/actions-comment-pull-request@v2.4.3 + - uses: thollander/actions-comment-pull-request@v2.5.0 name: Leave a comment about our branch naming convention if: ${{ steps.labeller.outputs.applied == 0 }} with: diff --git a/.github/workflows/publish-build.yml b/.github/workflows/publish-build.yml new file mode 100644 index 0000000000..cf70b04c3a --- /dev/null +++ b/.github/workflows/publish-build.yml @@ -0,0 +1,58 @@ +name: Publish build + +on: + push: + branches: + - master + - stable + - experimental + +jobs: + publish: + name: Upload build + runs-on: ubuntu-latest + if: contains(github.event.head_commit.message, '[ci skip]') == false + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4.6.0 + with: + distribution: 'adopt' + java-version: '21' + java-package: jdk + architecture: x64 + + - name: Build with Maven + run: mvn clean package + + - name: Upload Dev build + uses: WalshyDev/blob-builds/gh-action@ea9ecd9266c902c6627f884e657560d0fa6b61dd + if: github.ref == 'refs/heads/master' + with: + project: Slimefun4 + releaseChannel: Dev + apiToken: ${{ secrets.BLOB_BUILDS_API_TOKEN }} + file: './target/Slimefun v4.9-UNOFFICIAL.jar' + releaseNotes: ${{ github.event.head_commit.message }} + + - name: Upload RC build + uses: WalshyDev/blob-builds/gh-action@ea9ecd9266c902c6627f884e657560d0fa6b61dd + if: github.ref == 'refs/heads/stable' + with: + project: Slimefun4 + releaseChannel: 'RC' + apiToken: ${{ secrets.BLOB_BUILDS_API_TOKEN }} + file: './target/Slimefun v4.9-UNOFFICIAL.jar' + releaseNotes: ${{ github.event.head_commit.message }} + + - name: Upload Experimental build + uses: WalshyDev/blob-builds/gh-action@ea9ecd9266c902c6627f884e657560d0fa6b61dd + if: github.ref == 'refs/heads/experimental' + with: + project: Slimefun4 + releaseChannel: 'Experimental' + apiToken: ${{ secrets.BLOB_BUILDS_API_TOKEN }} + file: './target/Slimefun v4.9-UNOFFICIAL.jar' + releaseNotes: ${{ github.event.head_commit.message }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index ad2a33e080..28e0d47a98 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,11 +21,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4.0.0 + - name: Set up JDK 21 + uses: actions/setup-java@v4.6.0 with: distribution: 'adopt' - java-version: '17' + java-version: '21' java-package: jdk architecture: x64 @@ -50,7 +50,7 @@ jobs: run: mvn package - name: Upload the artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: slimefun-${{ github.event.number }}-${{ env.SHORT_COMMIT_HASH }} path: 'target/Slimefun v${{ env.JAR_VERSION }}.jar' diff --git a/.github/workflows/release-candidates.yml b/.github/workflows/release-candidates.yml index 1f4bda442e..e330af4b09 100644 --- a/.github/workflows/release-candidates.yml +++ b/.github/workflows/release-candidates.yml @@ -48,7 +48,7 @@ jobs: body: | ## 💾 Download link This release candidate of Slimefun4 can be downloaded here: - https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/Slimefun4-${{ github.event.inputs.number }}.jar + https://blob.build/project/Slimefun4/RC ### ❓ How to install Slimefun Simply drag & drop the Slimefun4 jar file into the `/plugins/` directory of your server. diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 4d395db640..2702fbb6c8 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -19,15 +19,15 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - - name: Set up JDK 17 - uses: actions/setup-java@v4.0.0 + - name: Set up JDK 21 + uses: actions/setup-java@v4.6.0 with: distribution: 'adopt' - java-version: '17' + java-version: '21' java-package: jdk architecture: x64 diff --git a/.gitignore b/.gitignore index e6f9d7a43c..a6d46cc670 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /.idea/ /.vscode/ /data-storage/ +/javadocs/ dependency-reduced-pom.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index fd52f7a3dc..453eb54984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of contents -- [Release Candidate 37 (TBD)](#release-candidate-37-tbd) +- [Release Candidate 38 (TBD)](#release-candidate-38-tbd) +- [Release Candidate 37 (25 Feb 2024)](#release-candidate-37-25-feb-2024) - [Release Candidate 36 (20 Dec 2023)](#release-candidate-36-20-dec-2023) - [Release Candidate 35 (07 Jul 2023)](#release-candidate-35-07-jul-2023) - [Release Candidate 34 (20 Jun 2023)](#release-candidate-34-20-jun-2023) @@ -37,7 +38,33 @@ - [Release Candidate 2 (29 Sep 2019)](#release-candidate-2-29-sep-2019) - [Release Candidate 1 (26 Sep 2019)](#release-candidate-1-26-sep-2019) -## Release Candidate 37 (TBD) +## Release Candidate 38 (TBD) + +## Release Candidate 37 (25 Feb 2024) + +#### Additions +* (API) Introduce SlimefunItemRegistryFinalizedEvent (#4099) +* Add update warning to /sf versions (#4096) +* Add new analytics service (#4067) + +#### Changes +* Allow blocks to be dropped while in creative mode (#3934) +* Storage rewrite - Phase 1 (#4065) +* Temporarily disable senstive blocks check (#4077) +* Update MockBukkit to 1.20.4 along with existing tests (#4086) +* Move PlayerProfile saving off the main thread (#4119) + +#### Fixes +* Fix contributor head being pullable (#4072) +* Fix backpack IDs not incrementing (#4081) +* Fix inventory being used when Slimefun block is broken (#4088) +* Fix items not being able to be placed on ancient altar (#4094) +* Update dough to fix item stacking issue (#4100) +* Fix slimefun block turning into a vanilla block if there are viewers (#4101) +* Fixes #4123 - Coal Generator will no longer be locked after researching (#4124) +* Fixes exhaustion when loading large profiles (#4127) +* Fixes guide search when using colored chat (#4125) +* Fix dupe glitch with backpacks (#4134) ## Release Candidate 36 (20 Dec 2023) diff --git a/README.md b/README.md index 46ce4c0096..affc3ed96c 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,14 @@ For more info see [bStats' Privacy Policy](https://bstats.org/privacy-policy) Our [bStats Module](https://github.com/Slimefun/MetricsModule) is downloaded automatically when installing this Plugin, this module will automatically update on server starts independently from the main plugin. This way we can automatically roll out updates to the bStats module, in cases of severe performance issues for example where live data and insight into what is impacting performance can be crucial. These updates can of course be disabled under `/plugins/Slimefun/config.yml`. To disable metrics collection as a whole, see the paragraph above. +--- + +Slimefun also uses its own analytics system to collect anonymous information about the performance of this plugin.
+This is solely for statistical purposes, as we are interested in how it's performing for all servers.
+All available data is anonymous and aggregated, at no point can we see individual server information.
+ +You can also disable this behaviour under `/plugins/Slimefun/config.yml`.
+
diff --git a/jitpack.yml b/jitpack.yml index 3dcd4f7383..d9a09de62d 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,6 +1,7 @@ before_install: - - sdk install java 17.0.1-open - - sdk use java 17.0.1-open + - sdk install java 21.0.2-open + - sdk use java 21.0.2-open + - sdk install maven jdk: - - openjdk17 + - openjdk21 diff --git a/pom.xml b/pom.xml index 48e7d9db95..57d6c680ec 100644 --- a/pom.xml +++ b/pom.xml @@ -24,9 +24,12 @@ 16 16 + + 21 + 21 - 1.20.4 + 1.20.6 https://hub.spigotmc.org/javadocs/spigot/ @@ -115,7 +118,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.0 + 3.13.0 @@ -130,7 +133,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.3.1 @@ -146,7 +149,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.5.2 org.junit.jupiter:junit-jupiter @@ -158,14 +161,14 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.10.0.2594 + 5.0.0.4389 org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 @@ -191,7 +194,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.1 + 3.6.0 @@ -204,10 +207,6 @@ io.papermc.lib io.github.thebusybiscuit.slimefun4.libraries.paperlib - - kong.unirest - io.github.thebusybiscuit.slimefun4.libraries.unirest - org.apache.commons.lang io.github.thebusybiscuit.slimefun4.libraries.commons.lang @@ -239,11 +238,11 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.3 + 3.11.2 ${project.basedir} - docs + javadocs Slimefun4 - Javadocs Slimefun4 - Javadocs @@ -333,9 +332,19 @@ - - + + + + org.junit + junit-bom + 5.11.4 + pom + import + + + + com.google.code.findbugs @@ -345,11 +354,10 @@ - com.github.baked-libs.dough dough-api - fcdbd45aa0 + f8ff25187d compile @@ -358,45 +366,30 @@ 1.0.8 compile - - com.konghq - unirest-java - 3.14.5 - compile - - - - - com.google.code.gson - gson - - - org.junit.jupiter junit-jupiter - 5.10.1 test org.mockito mockito-core - 5.9.0 + 5.15.2 test org.slf4j slf4j-simple - 2.0.9 + 2.0.16 test - com.github.seeseemelk - MockBukkit-v1.20 - 3.65.0 + com.github.mockbukkit + MockBukkit + c7cc678834 test @@ -408,12 +401,19 @@ + + + io.papermc.paper + paper-api + 1.20.6-R0.1-SNAPSHOT + test + com.sk89q.worldedit worldedit-core - 7.2.18 + 7.3.9 provided @@ -427,7 +427,7 @@ com.sk89q.worldedit worldedit-bukkit - 7.2.18 + 7.3.9 provided @@ -441,7 +441,7 @@ com.gmail.nossr50.mcMMO mcMMO - 2.1.226 + 2.2.029 provided @@ -455,7 +455,7 @@ me.clip placeholderapi - 2.11.5 + 2.11.6 provided diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java index 511df32ec3..4fc0160ac6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java @@ -10,10 +10,10 @@ /** * This enum holds all versions of Minecraft that we currently support. - * + * * @author TheBusyBiscuit * @author Walshy - * + * * @see Slimefun * */ @@ -47,7 +47,13 @@ public enum MinecraftVersion { * This constant represents Minecraft (Java Edition) Version 1.20 * ("The Trails & Tales Update") */ - MINECRAFT_1_20(20, "1.20.x"), + MINECRAFT_1_20(20, 0, 4, "1.20.x"), + + /** + * This constant represents Minecraft (Java Edition) Version 1.20.5 + * ("The Armored Paws Update") + */ + MINECRAFT_1_20_5(20, 5, "1.20.5+"), /** * This constant represents an exceptional state in which we were unable @@ -64,12 +70,14 @@ public enum MinecraftVersion { private final String name; private final boolean virtual; private final int majorVersion; + private final int minorVersion; + private final int maxMinorVersion; /** * This constructs a new {@link MinecraftVersion} with the given name. * This constructor forces the {@link MinecraftVersion} to be real. * It must be a real version of Minecraft. - * + * * @param majorVersion * The major version of minecraft as an {@link Integer} * @param name @@ -78,6 +86,50 @@ public enum MinecraftVersion { MinecraftVersion(int majorVersion, @Nonnull String name) { this.name = name; this.majorVersion = majorVersion; + this.minorVersion = -1; + this.maxMinorVersion = -1; + this.virtual = false; + } + + /** + * This constructs a new {@link MinecraftVersion} with the given name. + * This constructor forces the {@link MinecraftVersion} to be real. + * It must be a real version of Minecraft. + * + * @param majorVersion + * The major (minor in semver, major in MC land) version of minecraft as an {@link Integer} + * @param minor + * The minor (patch in semver, minor in MC land) version of minecraft as an {@link Integer} + * @param name + * The display name of this {@link MinecraftVersion} + */ + MinecraftVersion(int majorVersion, int minor, @Nonnull String name) { + this.name = name; + this.majorVersion = majorVersion; + this.minorVersion = minor; + this.maxMinorVersion = -1; + this.virtual = false; + } + + /** + * This constructs a new {@link MinecraftVersion} with the given name. + * This constructor forces the {@link MinecraftVersion} to be real. + * It must be a real version of Minecraft. + * + * @param majorVersion + * The major (minor in semver, major in MC land) version of minecraft as an {@link Integer} + * @param minor + * The minor (patch in semver, minor in MC land) version of minecraft as an {@link Integer} + * @param maxMinorVersion + * The maximum minor (patch) version of minecraft this version represents + * @param name + * The display name of this {@link MinecraftVersion} + */ + MinecraftVersion(int majorVersion, int minor, int maxMinorVersion, @Nonnull String name) { + this.name = name; + this.majorVersion = majorVersion; + this.minorVersion = minor; + this.maxMinorVersion = maxMinorVersion; this.virtual = false; } @@ -85,7 +137,7 @@ public enum MinecraftVersion { * This constructs a new {@link MinecraftVersion} with the given name. * A virtual {@link MinecraftVersion} (unknown or unit test) is not an actual * version of Minecraft but rather a state of the {@link Server} software. - * + * * @param name * The display name of this {@link MinecraftVersion} * @param virtual @@ -94,12 +146,14 @@ public enum MinecraftVersion { MinecraftVersion(@Nonnull String name, boolean virtual) { this.name = name; this.majorVersion = 0; + this.minorVersion = -1; + this.maxMinorVersion = -1; this.virtual = virtual; } /** * This returns the name of this {@link MinecraftVersion} in a readable format. - * + * * @return The name of this {@link MinecraftVersion} */ public @Nonnull String getName() { @@ -112,7 +166,7 @@ public enum MinecraftVersion { * a state of the {@link Server} software used. * Virtual {@link MinecraftVersion MinecraftVersions} include "UNKNOWN" and * "UNIT TEST". - * + * * @return Whether this {@link MinecraftVersion} is virtual or not */ public boolean isVirtual() { @@ -127,25 +181,49 @@ public boolean isVirtual() { * It is equivalent to the "major" version *

* Example: {@literal "1.13"} returns {@literal 13} - * + * * @param minecraftVersion * The {@link Integer} version to match - * + * * @return Whether this {@link MinecraftVersion} matches the specified version id */ public boolean isMinecraftVersion(int minecraftVersion) { - return !isVirtual() && this.majorVersion == minecraftVersion; + return this.isMinecraftVersion(minecraftVersion, -1); + } + + /** + * This tests if the given minecraft version matches with this + * {@link MinecraftVersion}. + *

+ * You can obtain the version number by doing {@link PaperLib#getMinecraftVersion()}. + * It is equivalent to the "major" version
+ * You can obtain the patch version by doing {@link PaperLib#getMinecraftPatchVersion()}. + * It is equivalent to the "minor" version + *

+ * Example: {@literal "1.13"} returns {@literal 13}
+ * Example: {@literal "1.13.2"} returns {@literal 13_2} + * + * @param minecraftVersion + * The {@link Integer} version to match + * + * @return Whether this {@link MinecraftVersion} matches the specified version id + */ + public boolean isMinecraftVersion(int minecraftVersion, int patchVersion) { + return !isVirtual() + && this.majorVersion == minecraftVersion + && (this.minorVersion == -1 || this.minorVersion <= patchVersion) + && (this.maxMinorVersion == -1 || patchVersion <= this.maxMinorVersion); } /** * This method checks whether this {@link MinecraftVersion} is newer or equal to * the given {@link MinecraftVersion}, - * + * * An unknown version will default to {@literal false}. - * + * * @param version * The {@link MinecraftVersion} to compare - * + * * @return Whether this {@link MinecraftVersion} is newer or equal to the given {@link MinecraftVersion} */ public boolean isAtLeast(@Nonnull MinecraftVersion version) { @@ -162,7 +240,7 @@ public boolean isAtLeast(@Nonnull MinecraftVersion version) { * this will essentially always return true and result in a tautology. * This is most definitely an oversight from us and should be fixed, therefore * we will trigger an exception. - * + * * In order to not disrupt server operations, this exception is only thrown during * unit tests since the oversight itself will be harmless. */ @@ -175,12 +253,12 @@ public boolean isAtLeast(@Nonnull MinecraftVersion version) { /** * This checks whether this {@link MinecraftVersion} is older than the specified {@link MinecraftVersion}. - * + * * An unknown version will default to {@literal true}. - * + * * @param version * The {@link MinecraftVersion} to compare - * + * * @return Whether this {@link MinecraftVersion} is older than the given one */ public boolean isBefore(@Nonnull MinecraftVersion version) { @@ -193,4 +271,24 @@ public boolean isBefore(@Nonnull MinecraftVersion version) { return version.ordinal() > this.ordinal(); } + /** + * Checks whether this {@link MinecraftVersion} is older than the specified minecraft and patch versions + * @param minecraftVersion The minecraft version + * @param patchVersion The patch version + * @return True if this version is before, False if this version is virtual or otherwise. + */ + public boolean isBefore(int minecraftVersion, int patchVersion) { + // unit tests or whatever + if (isVirtual()) { + return false; + } + + // major version mismatch + if (this.majorVersion != minecraftVersion) { + return this.majorVersion < minecraftVersion; + } + + return this.minorVersion == -1 ? patchVersion > 0 : this.minorVersion < patchVersion; + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/RadiationDamageEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/RadiationDamageEvent.java new file mode 100644 index 0000000000..b3ef284e75 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/RadiationDamageEvent.java @@ -0,0 +1,69 @@ +package io.github.thebusybiscuit.slimefun4.api.events; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * The {@link RadiationDamageEvent} is called when a player takes radiation damage. + * + * @author HoosierTransfer + */ +public class RadiationDamageEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private final Player player; + private final int exposure; + private boolean cancelled; + + /** + * This constructs a new {@link RadiationDamageEvent}. + * + * @param player The {@link Player} who took radiation damage + * @param exposure The amount of radiation exposure + */ + public RadiationDamageEvent(@Nonnull Player player, int exposure) { + this.player = player; + this.exposure = exposure; + } + + /** + * This returns the {@link Player} who took radiation damage. + * + * @return The {@link Player} who took radiation damage + */ + public @Nonnull Player getPlayer() { + return player; + } + + /** + * This returns the amount of radiation exposure. + * + * @return The amount of radiation exposure + */ + public int getExposure() { + return exposure; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + public static @Nonnull HandlerList getHandlerList() { + return handlers; + } + + @Override + public @Nonnull HandlerList getHandlers() { + return getHandlerList(); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/TalismanActivateEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/TalismanActivateEvent.java index 775691a0a6..b8515bed47 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/TalismanActivateEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/TalismanActivateEvent.java @@ -93,4 +93,4 @@ public void setCancelled(boolean cancel) { public static @Nonnull HandlerList getHandlerList() { return handlers; } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java index 19646ed4c0..6f65962024 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java @@ -16,7 +16,6 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import io.github.bakedlibs.dough.common.ChatColors; import io.github.bakedlibs.dough.items.CustomItemStack; @@ -27,6 +26,7 @@ import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; import io.papermc.lib.PaperLib; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; @@ -220,7 +220,7 @@ private void onTeleport(Player p, Location destination, boolean success, boolean if (success) { // Apply Resistance Effect, if enabled if (resistance) { - p.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 600, 20)); + p.addPotionEffect(new PotionEffect(VersionedPotionEffectType.RESISTANCE, 600, 20)); Slimefun.getLocalization().sendMessage(p, "machines.TELEPORTER.invulnerability"); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemGroup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemGroup.java index 0f70a46e6e..81b8f331f6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemGroup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemGroup.java @@ -25,6 +25,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.groups.SeasonalItemGroup; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedItemFlag; /** * Represents an item group, which structure @@ -85,7 +86,7 @@ public ItemGroup(NamespacedKey key, ItemStack item, int tier) { ItemMeta meta = item.getItemMeta(); meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); + meta.addItemFlags(VersionedItemFlag.HIDE_ADDITIONAL_TOOLTIP); this.item.setItemMeta(meta); this.tier = tier; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java index 6400d8b925..ea3775037c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java @@ -160,6 +160,21 @@ public SlimefunItem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType reci this.recipeOutput = recipeOutput; } + /** + * This creates a new {@link SlimefunItem} from the given arguments. + * + * @param itemGroup + * The {@link ItemGroup} this {@link SlimefunItem} belongs + * to + * @param item + * The {@link SlimefunItemStack} that describes the visual + * features of our {@link SlimefunItem} + */ + @ParametersAreNonnullByDefault + public SlimefunItem(ItemGroup itemGroup, SlimefunItemStack item) { + this(itemGroup, item, RecipeType.NULL, new ItemStack[] {}); + } + // Previously deprecated constructor, now only for internal purposes @ParametersAreNonnullByDefault protected SlimefunItem(ItemGroup itemGroup, ItemStack item, String id, RecipeType recipeType, ItemStack[] recipe) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItemStack.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItemStack.java index 5604cdcfa8..611e85df6d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItemStack.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItemStack.java @@ -15,7 +15,6 @@ import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.Material; -import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; @@ -32,6 +31,7 @@ import io.github.thebusybiscuit.slimefun4.api.exceptions.WrongItemStackException; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedItemFlag; /** * The {@link SlimefunItemStack} functions as the base for any @@ -159,7 +159,7 @@ public SlimefunItemStack(@Nonnull String id, @Nonnull Color color, @Nonnull Poti potionMeta.addCustomEffect(effect, true); if (effect.getType().equals(PotionEffectType.SATURATION)) { - im.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); + im.addItemFlags(VersionedItemFlag.HIDE_ADDITIONAL_TOOLTIP); } } }); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java index 14ab69c85f..256442972a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java @@ -5,9 +5,10 @@ import org.apache.commons.lang.Validate; import org.bukkit.Color; import org.bukkit.Location; -import org.bukkit.Particle; import org.bukkit.Particle.DustOptions; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; + /** * This class represents the visualizer task of a given {@link Network}. * @@ -58,7 +59,7 @@ public void run() { * The {@link Location} of our node */ private void spawnParticles(@Nonnull Location l) { - l.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5, l.getY() + 0.5, l.getZ() + 0.5, 1, 0, 0, 0, 1, particleOptions); + l.getWorld().spawnParticle(VersionedParticle.DUST, l.getX() + 0.5, l.getY() + 0.5, l.getZ() + 0.5, 1, 0, 0, 0, 1, particleOptions); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java index 96290f4849..8dfc7414f8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java @@ -3,12 +3,13 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.OptionalInt; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; -import java.util.stream.IntStream; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -35,6 +36,8 @@ import io.github.thebusybiscuit.slimefun4.api.researches.Research; import io.github.thebusybiscuit.slimefun4.core.attributes.ProtectionType; import io.github.thebusybiscuit.slimefun4.core.attributes.ProtectiveArmor; +import io.github.thebusybiscuit.slimefun4.core.debug.Debug; +import io.github.thebusybiscuit.slimefun4.core.debug.TestCase; import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece; @@ -54,6 +57,8 @@ */ public class PlayerProfile { + private static final Map loading = new ConcurrentHashMap<>(); + private final UUID ownerId; private final String name; @@ -237,6 +242,7 @@ public void removeWaypoint(@Nonnull Waypoint waypoint) { * The profile can then be removed from RAM. */ public final void markForDeletion() { + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Marking {} ({}) profile for deletion", name, ownerId); markedForDeletion = true; } @@ -244,6 +250,7 @@ public final void markForDeletion() { * Call this method if this Profile has unsaved changes. */ public final void markDirty() { + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Marking {} ({}) profile as dirty", name, ownerId); dirty = true; } @@ -358,22 +365,47 @@ public static boolean fromUUID(@Nonnull UUID uuid, @Nonnull Consumer callback) { Validate.notNull(p, "Cannot get a PlayerProfile for: null!"); - UUID uuid = p.getUniqueId(); + + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Getting PlayerProfile for {}", uuid); + PlayerProfile profile = Slimefun.getRegistry().getPlayerProfiles().get(uuid); if (profile != null) { + Debug.log(TestCase.PLAYER_PROFILE_DATA, "PlayerProfile for {} was already loaded", uuid); callback.accept(profile); return true; } - Bukkit.getScheduler().runTaskAsynchronously(Slimefun.instance(), () -> { + // If we're already loading, we don't want to spin up a whole new thread and load the profile again/more + // This can very easily cause CPU, memory and thread exhaustion if the profile is large + // See #4011, #4116 + if (loading.containsKey(uuid)) { + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Attempted to get PlayerProfile ({}) while loading", uuid); + + // We can't easily consume the callback so we will throw it away in this case + // This will mean that if a user has attempted to do an action like open a block while + // their profile is still loading. Instead of it opening after a second or whatever when the + // profile is loaded, they will have to explicitly re-click the block/item/etc. + // This isn't the best but I think it's totally reasonable. + return false; + } + + loading.put(uuid, true); + Slimefun.getThreadService().newThread(Slimefun.instance(), "PlayerProfile#get(" + uuid + ")", () -> { PlayerData data = Slimefun.getPlayerStorage().loadPlayerData(p.getUniqueId()); AsyncProfileLoadEvent event = new AsyncProfileLoadEvent(new PlayerProfile(p, data)); Bukkit.getPluginManager().callEvent(event); Slimefun.getRegistry().getPlayerProfiles().put(uuid, event.getProfile()); + + // Make sure we call this after we put the PlayerProfile into the registry. + // Otherwise, we end up with a race condition where the profile is not in the map just _yet_ + // but the loading flag is gone and we can end up loading it a second time (and thus can dupe items) + // Fixes https://github.com/Slimefun/Slimefun4/issues/4130 + loading.remove(uuid); + callback.accept(event.getProfile()); }); @@ -391,14 +423,32 @@ public static boolean get(@Nonnull OfflinePlayer p, @Nonnull Consumer { - PlayerData data = Slimefun.getPlayerStorage().loadPlayerData(p.getUniqueId()); + Slimefun.getThreadService().newThread(Slimefun.instance(), "PlayerProfile#request(" + uuid + ")", () -> { + PlayerData data = Slimefun.getPlayerStorage().loadPlayerData(uuid); PlayerProfile pp = new PlayerProfile(p, data); - Slimefun.getRegistry().getPlayerProfiles().put(p.getUniqueId(), pp); + Slimefun.getRegistry().getPlayerProfiles().put(uuid, pp); + + // Make sure we call this after we put the PlayerProfile into the registry. + // Otherwise, we end up with a race condition where the profile is not in the map just _yet_ + // but the loading flag is gone and we can end up loading it a second time (and thus can dupe items) + // Fixes https://github.com/Slimefun/Slimefun4/issues/4130 + loading.remove(uuid); }); return false; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java index 05694f3e64..74f4a5ef88 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java @@ -13,6 +13,7 @@ import io.github.bakedlibs.dough.config.Config; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.utils.UnbreakingAlgorithm; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; /** * This interface, when attached to a {@link SlimefunItem}, provides an easy method for damaging @@ -51,7 +52,7 @@ public interface DamageableItem extends ItemAttribute { */ default void damageItem(@Nonnull Player p, @Nullable ItemStack item) { if (isDamageable() && item != null && !item.getType().isAir() && item.getAmount() > 0) { - int unbreakingLevel = item.getEnchantmentLevel(Enchantment.DURABILITY); + int unbreakingLevel = item.getEnchantmentLevel(VersionedEnchantment.UNBREAKING); if (evaluateUnbreakingEnchantment(unbreakingLevel)) { return; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RadiationSymptom.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RadiationSymptom.java index 2c703de40b..154b48efc4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RadiationSymptom.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RadiationSymptom.java @@ -10,6 +10,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.utils.RadiationUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; /** * An enum of potential radiation symptoms. @@ -25,11 +26,11 @@ */ public enum RadiationSymptom { - SLOW(10, PotionEffectType.SLOW, 3), + SLOW(10, VersionedPotionEffectType.SLOWNESS, 3), WITHER_LOW(25, PotionEffectType.WITHER, 0), BLINDNESS(50, PotionEffectType.BLINDNESS, 4), WITHER_HIGH(75, PotionEffectType.WITHER, 3), - IMMINENT_DEATH(100, PotionEffectType.HARM, 49); + IMMINENT_DEATH(100, VersionedPotionEffectType.INSTANT_DAMAGE, 49); private final int minExposure; private final PotionEffect potionEffect; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java index 07ca70bf0c..50a665f308 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java @@ -16,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.researches.Research; +import io.github.thebusybiscuit.slimefun4.core.debug.TestCase; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; class SlimefunTabCompleter implements TabCompleter { @@ -33,6 +34,13 @@ public SlimefunTabCompleter(@Nonnull SlimefunCommand command) { public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { if (args.length == 1) { return createReturnList(command.getSubCommandNames(), args[0]); + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("debug")) { + return createReturnList(TestCase.VALUES_LIST, args[1]); + } else { + // Returning null will make it fallback to the default arguments (all online players) + return null; + } } else if (args.length == 3) { if (args[0].equalsIgnoreCase("give")) { return createReturnList(getSlimefunItems(), args[2]); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java index da4b8d4e06..34ff1f4a20 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java @@ -65,11 +65,25 @@ public void onExecute(@Nonnull CommandSender sender, @Nonnull String[] args) { .append(serverSoftware) .color(ChatColor.GREEN) .append(" " + Bukkit.getVersion() + '\n') - .color(ChatColor.DARK_GREEN) + .color(ChatColor.DARK_GREEN); + + builder .append("Slimefun ") .color(ChatColor.GREEN) - .append(Slimefun.getVersion() + '\n') + .append(Slimefun.getVersion()) .color(ChatColor.DARK_GREEN); + if (!Slimefun.getUpdater().isLatestVersion()) { + builder + .append(" (").color(ChatColor.GRAY) + .append("Update available").color(ChatColor.RED).event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text( + "Your Slimefun version is out of date!\n" + + "Please update to get the latest bug fixes and performance improvements.\n" + + "Please do not report any bugs without updating first." + ))) + .append(")").color(ChatColor.GRAY); + } + + builder.append("\n").event((HoverEvent) null); // @formatter:on if (Slimefun.getMetricsService().getVersion() != null) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/debug/TestCase.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/debug/TestCase.java index 00b3bbf70c..e41ecddc42 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/debug/TestCase.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/debug/TestCase.java @@ -1,9 +1,13 @@ package io.github.thebusybiscuit.slimefun4.core.debug; +import java.util.Arrays; +import java.util.List; import java.util.Locale; import javax.annotation.Nonnull; +import io.github.thebusybiscuit.slimefun4.core.services.AnalyticsService; + /** * Test cases in Slimefun. These are very useful for debugging why behavior is happening. * Server owners can enable these with {@code /sf debug } @@ -17,7 +21,20 @@ public enum TestCase { * being checked and why it is comparing IDs or meta. * This is helpful for us to check into why input nodes are taking a while for servers. */ - CARGO_INPUT_TESTING; + CARGO_INPUT_TESTING, + + /** + * Debug information regarding player profile loading, saving and handling. + * This is an area we're currently changing quite a bit and this will help ensure we're doing it safely + */ + PLAYER_PROFILE_DATA, + + /** + * Debug information regarding our {@link AnalyticsService}. + */ + ANALYTICS; + + public static final List VALUES_LIST = Arrays.stream(values()).map(TestCase::toString).toList(); TestCase() {} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/FireworksOption.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/FireworksOption.java index 07b757018a..64f48a0656 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/FireworksOption.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/FireworksOption.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.core.guide.options; +import java.util.List; import java.util.Optional; import org.bukkit.Material; @@ -31,7 +32,13 @@ public Optional getDisplayItem(Player p, ItemStack guide) { if (registry.isResearchingEnabled() && registry.isResearchFireworkEnabled()) { boolean enabled = getSelectedOption(p, guide).orElse(true); - ItemStack item = new CustomItemStack(Material.FIREWORK_ROCKET, "&bFireworks: &" + (enabled ? "aYes" : "4No"), "", "&7You can now toggle whether you", "&7will be presented with a big firework", "&7upon researching an item.", "", "&7\u21E8 &eClick to " + (enabled ? "disable" : "enable") + " your fireworks"); + + String optionState = enabled ? "enabled" : "disabled"; + List lore = Slimefun.getLocalization().getMessages(p, "guide.options.fireworks." + optionState + ".text"); + lore.add(""); + lore.add("&7\u21E8 " + Slimefun.getLocalization().getMessage(p, "guide.options.fireworks." + optionState + ".click")); + + ItemStack item = new CustomItemStack(Material.FIREWORK_ROCKET, lore); return Optional.of(item); } else { return Optional.empty(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/GuideModeOption.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/GuideModeOption.java index f86694211d..92ede97bc9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/GuideModeOption.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/GuideModeOption.java @@ -56,14 +56,15 @@ public Optional getDisplayItem(Player p, ItemStack guide) { } ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(ChatColor.GRAY + "Slimefun Guide Type: " + ChatColor.YELLOW + ChatUtils.humanize(selectedMode.name())); + meta.setDisplayName(ChatColor.GRAY + Slimefun.getLocalization().getMessage(p, "guide.modes.selected") + + ChatColor.YELLOW + Slimefun.getLocalization().getMessage(p, "guide.modes." + selectedMode.name())); List lore = new ArrayList<>(); lore.add(""); - lore.add((selectedMode == SlimefunGuideMode.SURVIVAL_MODE ? ChatColor.GREEN : ChatColor.GRAY) + "Survival Mode"); - lore.add((selectedMode == SlimefunGuideMode.CHEAT_MODE ? ChatColor.GREEN : ChatColor.GRAY) + "Cheat Sheet"); + lore.add((selectedMode == SlimefunGuideMode.SURVIVAL_MODE ? ChatColor.GREEN : ChatColor.GRAY) + Slimefun.getLocalization().getMessage(p, "guide.modes.SURVIVAL_MODE")); + lore.add((selectedMode == SlimefunGuideMode.CHEAT_MODE ? ChatColor.GREEN : ChatColor.GRAY) + Slimefun.getLocalization().getMessage(p, "guide.modes.CHEAT_MODE")); lore.add(""); - lore.add(ChatColor.GRAY + "\u21E8 " + ChatColor.YELLOW + "Click to change the type"); + lore.add(ChatColor.GRAY + "\u21E8 " + ChatColor.YELLOW + Slimefun.getLocalization().getMessage(p, "guide.modes.change")); meta.setLore(lore); item.setItemMeta(meta); @@ -114,4 +115,4 @@ public void setSelectedOption(Player p, ItemStack guide, SlimefunGuideMode value guide.setItemMeta(SlimefunGuide.getItem(value).getItemMeta()); } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AnalyticsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AnalyticsService.java new file mode 100644 index 0000000000..b0afd40657 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AnalyticsService.java @@ -0,0 +1,158 @@ +package io.github.thebusybiscuit.slimefun4.core.services; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.github.thebusybiscuit.slimefun4.core.debug.Debug; +import io.github.thebusybiscuit.slimefun4.core.debug.TestCase; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +/** + * This class represents an analytics service that sends data. + * This data is used to analyse performance of this {@link Plugin}. + *

+ * You can find more info in the README file of this Project on GitHub. + * + * @author WalshyDev + */ +public class AnalyticsService { + + private static final int VERSION = 1; + private static final String API_URL = "https://analytics.slimefun.dev/ingest"; + + private final JavaPlugin plugin; + private final HttpClient client = HttpClient.newHttpClient(); + + private boolean enabled; + + public AnalyticsService(JavaPlugin plugin) { + this.plugin = plugin; + } + + public void start() { + this.enabled = Slimefun.getCfg().getBoolean("metrics.analytics"); + + if (enabled) { + plugin.getLogger().info("Enabled Analytics Service"); + + // Send the timings data every minute + Slimefun.getThreadService().newScheduledThread( + plugin, + "AnalyticsService - Timings", + sendTimingsAnalytics(), + 1, + 1, + TimeUnit.MINUTES + ); + } + } + + // We'll send some timing data every minute. + // To date, we collect the tick interval, the avg timing per tick and avg timing per machine + @Nonnull + private Runnable sendTimingsAnalytics() { + return () -> { + double tickInterval = Slimefun.getTickerTask().getTickRate(); + // This is currently used by bStats in a ranged way, we'll move this + double totalTimings = Slimefun.getProfiler().getAndResetAverageNanosecondTimings(); + double avgPerMachine = Slimefun.getProfiler().getAverageTimingsPerMachine(); + + if (totalTimings == 0 || avgPerMachine == 0) { + Debug.log(TestCase.ANALYTICS, "Ignoring analytics data for server_timings as no data was found" + + " - total: " + totalTimings + ", avg: " + avgPerMachine); + // Ignore if no data + return; + } + + send("server_timings", new double[]{ + // double1 is schema version + tickInterval, // double2 + totalTimings, // double3 + avgPerMachine // double4 + }, null); + }; + } + + public void recordPlayerProfileDataTime(@Nonnull String backend, boolean load, long nanoseconds) { + send( + "player_profile_data_load_time", + new double[]{ + // double1 is schema version + nanoseconds, // double2 + load ? 1 : 0 // double3 - 1 if load, 0 if save + }, + new String[]{ + // blob1 is version + backend // blob2 + } + ); + } + + // Important: Keep the order of these doubles and blobs the same unless you increment the version number + // If a value is no longer used, just send null or replace it with a new value - don't shift the order + @ParametersAreNonnullByDefault + private void send(String id, double[] doubles, String[] blobs) { + // If not enabled or not official build (e.g. local build) or a unit test, just ignore. + if ( + !enabled + || !Slimefun.getUpdater().getBranch().isOfficial() + || Slimefun.instance().isUnitTest() + ) return; + + JsonObject object = new JsonObject(); + // Up to 1 index + JsonArray indexes = new JsonArray(); + indexes.add(id); + object.add("indexes", indexes); + + // Up to 20 doubles (including the version) + JsonArray doublesArray = new JsonArray(); + doublesArray.add(VERSION); + if (doubles != null) { + for (double d : doubles) { + doublesArray.add(d); + } + } + object.add("doubles", doublesArray); + + // Up to 20 blobs (including the version) + JsonArray blobsArray = new JsonArray(); + blobsArray.add(Slimefun.getVersion()); + if (blobs != null) { + for (String s : blobs) { + blobsArray.add(s); + } + } + object.add("blobs", blobsArray); + + Debug.log(TestCase.ANALYTICS, "Sending analytics data for " + id); + Debug.log(TestCase.ANALYTICS, object.toString()); + + // Send async, we do not care about the result. If it fails, that's fine. + client.sendAsync(HttpRequest.newBuilder() + .uri(URI.create(API_URL)) + .header("User-Agent", "Mozilla/5.0 Slimefun4 AnalyticsService") + .POST(HttpRequest.BodyPublishers.ofString(object.toString())) + .build(), + HttpResponse.BodyHandlers.discarding() + ).thenAcceptAsync((res) -> { + if (res.statusCode() == 200) { + Debug.log(TestCase.ANALYTICS, "Analytics data for " + id + " sent successfully"); + } else { + Debug.log(TestCase.ANALYTICS, "Analytics data for " + id + " failed to send - " + res.statusCode()); + } + }); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java index a0455323f6..060ce0d772 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java @@ -13,6 +13,8 @@ import org.bukkit.entity.Player; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.debug.Debug; +import io.github.thebusybiscuit.slimefun4.core.debug.TestCase; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -39,9 +41,8 @@ public class AutoSavingService { public void start(@Nonnull Slimefun plugin, int interval) { this.interval = interval; - plugin.getServer().getScheduler().runTaskTimer(plugin, this::saveAllPlayers, 2000L, interval * 60L * 20L); + plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this::saveAllPlayers, 2000L, interval * 60L * 20L); plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this::saveAllBlocks, 2000L, interval * 60L * 20L); - } /** @@ -52,16 +53,30 @@ private void saveAllPlayers() { Iterator iterator = PlayerProfile.iterator(); int players = 0; + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Saving all players data"); + while (iterator.hasNext()) { PlayerProfile profile = iterator.next(); if (profile.isDirty()) { players++; profile.save(); + + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Saved data for {} ({})", + profile.getPlayer() != null ? profile.getPlayer().getName() : "Unknown", profile.getUUID() + ); } - if (profile.isMarkedForDeletion()) { + // Remove the PlayerProfile from memory if the player has left the server (marked from removal) + // and they're still not on the server + // At this point, we've already saved their profile so we can safely remove it + // without worry for having a data sync issue (e.g. data is changed but then we try to re-load older data) + if (profile.isMarkedForDeletion() && profile.getPlayer() == null) { iterator.remove(); + + Debug.log(TestCase.PLAYER_PROFILE_DATA, "Removed data from memory for {}", + profile.getUUID() + ); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java index e186004c4e..d5fc57c879 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java @@ -4,11 +4,23 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.URI; import java.net.URL; import java.net.URLClassLoader; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Redirect; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; +import java.net.http.HttpResponse.BodySubscriber; +import java.nio.ByteBuffer; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.concurrent.atomic.AtomicInteger; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Flow.Subscription; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -16,14 +28,12 @@ import org.bukkit.plugin.Plugin; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + import io.github.bakedlibs.dough.common.CommonPatterns; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; - -import kong.unirest.GetRequest; -import kong.unirest.HttpResponse; -import kong.unirest.JsonNode; -import kong.unirest.Unirest; -import kong.unirest.UnirestException; +import io.github.thebusybiscuit.slimefun4.utils.JsonUtils; /** * This Class represents a Metrics Service that sends data to https://bstats.org/ @@ -66,22 +76,12 @@ public class MetricsService { private final Slimefun plugin; private final File parentFolder; private final File metricsModuleFile; + private final HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.NORMAL).build(); private URLClassLoader moduleClassLoader; private String metricVersion = null; private boolean hasDownloadedUpdate = false; - static { - // @formatter:off (We want this to stay this nicely aligned :D ) - Unirest.config() - .concurrency(2, 1) - .setDefaultHeader("User-Agent", "MetricsModule Auto-Updater") - .setDefaultHeader("Accept", "application/vnd.github.v3+json") - .enableCookieManagement(false) - .cookieSpec("ignoreCookies"); - // @formatter:on - } - /** * This constructs a new instance of our {@link MetricsService}. * @@ -199,20 +199,16 @@ public boolean checkForUpdate(@Nullable String currentVersion) { */ private int getLatestVersion() { try { - HttpResponse response = Unirest.get(RELEASES_URL).asJson(); + HttpResponse response = client.send(buildBaseRequest(URI.create(RELEASES_URL)), HttpResponse.BodyHandlers.ofString()); - if (!response.isSuccess()) { + if (response.statusCode() < 200 || response.statusCode() >= 300) { return -1; } - JsonNode node = response.getBody(); + JsonElement element = JsonUtils.parseString(response.body()); - if (node == null) { - return -1; - } - - return node.getObject().getInt("tag_name"); - } catch (UnirestException e) { + return element.getAsJsonObject().get("tag_name").getAsInt(); + } catch (IOException | InterruptedException | JsonParseException e) { plugin.getLogger().log(Level.WARNING, "Failed to fetch latest builds for Metrics: {0}", e.getMessage()); return -1; } @@ -235,19 +231,12 @@ private boolean download(int version) { Files.delete(file.toPath()); } - AtomicInteger lastPercentPosted = new AtomicInteger(); - GetRequest request = Unirest.get(DOWNLOAD_URL + "/" + version + "/" + JAR_NAME + ".jar"); - - HttpResponse response = request.downloadMonitor((b, fileName, bytesWritten, totalBytes) -> { - int percent = (int) (20 * (Math.round((((double) bytesWritten / totalBytes) * 100) / 20))); + HttpResponse response = client.send( + buildBaseRequest(URI.create(DOWNLOAD_URL + "/" + version + "/" + JAR_NAME + ".jar")), + downloadMonitor(HttpResponse.BodyHandlers.ofFile(file.toPath())) + ); - if (percent != 0 && percent != lastPercentPosted.get()) { - plugin.getLogger().info("# Downloading... " + percent + "% " + "(" + bytesWritten + "/" + totalBytes + " bytes)"); - lastPercentPosted.set(percent); - } - }).asFile(file.getPath()); - - if (response.isSuccess()) { + if (response.statusCode() >= 200 && response.statusCode() < 300) { plugin.getLogger().log(Level.INFO, "Successfully downloaded {0} build: #{1}", new Object[] { JAR_NAME, version }); // Replace the metric file with the new one @@ -257,8 +246,10 @@ private boolean download(int version) { metricVersion = String.valueOf(version); hasDownloadedUpdate = true; return true; + } else { + plugin.getLogger().log(Level.WARNING, "Failed to download the latest jar file from GitHub. Response code: {0}", response.statusCode()); } - } catch (UnirestException e) { + } catch (InterruptedException | JsonParseException e) { plugin.getLogger().log(Level.WARNING, "Failed to fetch the latest jar file from the builds page. Perhaps GitHub is down? Response: {0}", e.getMessage()); } catch (IOException e) { plugin.getLogger().log(Level.WARNING, "Failed to replace the old metric file with the new one. Please do this manually! Error: {0}", e.getMessage()); @@ -287,4 +278,58 @@ public String getVersion() { public boolean hasAutoUpdates() { return Slimefun.instance().getConfig().getBoolean("metrics.auto-update"); } + + private HttpRequest buildBaseRequest(@Nonnull URI uri) { + return HttpRequest.newBuilder() + .uri(uri) + .timeout(Duration.ofSeconds(5)) + .header("User-Agent", "MetricsModule Auto-Updater") + .header("Accept", "application/vnd.github.v3+json") + .build(); + } + + private BodyHandler downloadMonitor(BodyHandler h) { + return info -> new BodySubscriber() { + + private BodySubscriber delegateSubscriber = h.apply(info); + private int lastPercentPosted = 0; + private long bytesWritten = 0; + + @Override + public void onSubscribe(Subscription subscription) { + delegateSubscriber.onSubscribe(subscription); + } + + @Override + public void onNext(List item) { + bytesWritten += item.stream().mapToLong(ByteBuffer::capacity).sum(); + long totalBytes = info.headers().firstValue("Content-Length").map(Long::parseLong).orElse(-1L); + + int percent = (int) (20 * (Math.round((((double) bytesWritten / totalBytes) * 100) / 20))); + + if (percent != 0 && percent != lastPercentPosted) { + plugin.getLogger().info("# Downloading... " + percent + "% " + "(" + bytesWritten + "/" + totalBytes + " bytes)"); + lastPercentPosted = percent; + } + + delegateSubscriber.onNext(item); + } + + @Override + public void onError(Throwable throwable) { + delegateSubscriber.onError(throwable); + + } + + @Override + public void onComplete() { + delegateSubscriber.onComplete(); + } + + @Override + public CompletionStage getBody() { + return delegateSubscriber.getBody(); + } + }; + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/ThreadService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/ThreadService.java new file mode 100644 index 0000000000..a5aa0c58e0 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/ThreadService.java @@ -0,0 +1,99 @@ +package io.github.thebusybiscuit.slimefun4.core.services; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import javax.annotation.ParametersAreNonnullByDefault; + +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitScheduler; + +public final class ThreadService { + + private final ThreadGroup group; + private final ExecutorService cachedPool; + private final ScheduledExecutorService scheduledPool; + + public ThreadService(JavaPlugin plugin) { + this.group = new ThreadGroup(plugin.getName()); + this.cachedPool = Executors.newCachedThreadPool(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(group, r, plugin.getName() + " - ThreadService"); + } + }); + + this.scheduledPool = Executors.newScheduledThreadPool(1, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(group, r, plugin.getName() + " - ScheduledThreadService"); + } + }); + } + + /** + * Invoke a new thread from the cached thread pool with the given name. + * This is a much better alternative to using + * {@link BukkitScheduler#runTaskAsynchronously(org.bukkit.plugin.Plugin, Runnable)} + * as this will show not only the plugin but a useful name. + * By default, Bukkit will use "Craft Scheduler Thread - {@literal } - {@literal }" which is nice to show the plugin but + * it's impossible to track exactly what thread that is. + * + * @param plugin The {@link JavaPlugin} that is creating this thread + * @param name The name of this thread, this will be prefixed with the plugin's name + * @param runnable The {@link Runnable} to execute + */ + @ParametersAreNonnullByDefault + public void newThread(JavaPlugin plugin, String name, Runnable runnable) { + cachedPool.submit(() -> { + // This is a bit of a hack, but it's the only way to have the thread name be as desired + Thread.currentThread().setName(plugin.getName() + " - " + name); + runnable.run(); + }); + } + + /** + * Invoke a new scheduled thread from the cached thread pool with the given name. + * This is a much better alternative to using + * {@link BukkitScheduler#runTaskTimerAsynchronously(org.bukkit.plugin.Plugin, Runnable, long, long)} + * as this will show not only the plugin but a useful name. + * By default, Bukkit will use "Craft Scheduler Thread - {@literal } - {@literal }" which is nice to show the plugin but + * it's impossible to track exactly what thread that is. + * + * @param plugin The {@link JavaPlugin} that is creating this thread + * @param name The name of this thread, this will be prefixed with the plugin's name + * @param runnable The {@link Runnable} to execute + */ + @ParametersAreNonnullByDefault + public void newScheduledThread( + JavaPlugin plugin, + String name, + Runnable runnable, + long delay, + long period, + TimeUnit unit + ) { + this.scheduledPool.scheduleWithFixedDelay(() -> { + // This is a bit of a hack, but it's the only way to have the thread name be as desired + Thread.currentThread().setName(plugin.getName() + " - " + name); + runnable.run(); + }, delay, delay, unit); + } + + /** + * Get the caller of a given method, this should only be used for debugging purposes and is not performant. + * + * @return The caller of the method that called this method. + */ + public static String getCaller() { + // First item will be getting the call stack + // Second item will be this call + // Third item will be the func we care about being called + // And finally will be the caller + StackTraceElement element = Thread.currentThread().getStackTrace()[3]; + return element.getClassName() + "." + element.getMethodName() + ":" + element.getLineNumber(); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java index b556789a91..ac21007fce 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java @@ -1,6 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.services; import java.io.File; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -110,6 +111,29 @@ public int getBuildNumber() { return -1; } + public int getLatestVersion() { + if (updater != null && updater.getLatestVersion().isDone()) { + PrefixedVersion version; + try { + version = updater.getLatestVersion().get(); + return version.getVersionNumber(); + } catch (InterruptedException | ExecutionException e) { + return -1; + } + } + + return -1; + } + + public boolean isLatestVersion() { + if (getBuildNumber() == -1 || getLatestVersion() == -1) { + // We don't know if we're latest so just report we are + return true; + } + + return getBuildNumber() == getLatestVersion(); + } + /** * This will start the {@link UpdaterService} and check for updates. * If it can find an update it will automatically be installed. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java index 7dd4970552..4eb9d92637 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java @@ -9,11 +9,11 @@ import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; -import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; -import kong.unirest.JsonNode; -import kong.unirest.json.JSONArray; -import kong.unirest.json.JSONObject; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; class ContributionsConnector extends GitHubConnector { @@ -90,11 +90,11 @@ public boolean hasFinished() { } @Override - public void onSuccess(@Nonnull JsonNode response) { + public void onSuccess(@Nonnull JsonElement response) { finished = true; - if (response.isArray()) { - computeContributors(response.getArray()); + if (response.isJsonArray()) { + computeContributors(response.getAsJsonArray()); } else { Slimefun.logger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response); } @@ -123,13 +123,13 @@ public Map getParameters() { return parameters; } - private void computeContributors(@Nonnull JSONArray array) { - for (int i = 0; i < array.length(); i++) { - JSONObject object = array.getJSONObject(i); + private void computeContributors(@Nonnull JsonArray array) { + for (JsonElement element : array) { + JsonObject object = element.getAsJsonObject(); - String name = object.getString("login"); - int commits = object.getInt("contributions"); - String profile = object.getString("html_url"); + String name = object.get("login").getAsString(); + int commits = object.get("contributions").getAsInt(); + String profile = object.get("html_url").getAsString(); if (!ignoredAccounts.contains(name)) { String username = aliases.getOrDefault(name, name); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java index b298195e7b..60697f1345 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java @@ -7,10 +7,10 @@ import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; -import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; -import kong.unirest.JsonNode; -import kong.unirest.json.JSONObject; +import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; class GitHubActivityConnector extends GitHubConnector { @@ -23,11 +23,11 @@ class GitHubActivityConnector extends GitHubConnector { } @Override - public void onSuccess(@Nonnull JsonNode response) { - JSONObject object = response.getObject(); - int forks = object.getInt("forks"); - int stars = object.getInt("stargazers_count"); - LocalDateTime lastPush = NumberUtils.parseGitHubDate(object.getString("pushed_at")); + public void onSuccess(@Nonnull JsonElement response) { + JsonObject object = response.getAsJsonObject(); + int forks = object.get("forks").getAsInt(); + int stars = object.get("stargazers_count").getAsInt(); + LocalDateTime lastPush = NumberUtils.parseGitHubDate(object.get("pushed_at").getAsString()); callback.accept(forks, stars, lastPush); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java index 422ed31787..6b7d89e1ea 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java @@ -6,7 +6,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.logging.Level; @@ -14,13 +19,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; -import kong.unirest.HttpResponse; -import kong.unirest.JsonNode; -import kong.unirest.Unirest; -import kong.unirest.UnirestException; -import kong.unirest.json.JSONException; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.JsonUtils; /** * The {@link GitHubConnector} is used to connect to the GitHub API service. @@ -34,6 +37,7 @@ abstract class GitHubConnector { private static final String API_URL = "https://api.github.com/"; private static final String USER_AGENT = "Slimefun4 (https://github.com/Slimefun)"; + private static final HttpClient client = HttpClient.newHttpClient(); protected final GitHubService github; private final String url; @@ -83,7 +87,7 @@ abstract class GitHubConnector { * @param response * The response */ - public abstract void onSuccess(@Nonnull JsonNode response); + public abstract void onSuccess(@Nonnull JsonElement response); /** * This method is called when the connection has failed. @@ -105,38 +109,44 @@ void download() { } try { - // @formatter:off - HttpResponse response = Unirest.get(url) - .queryString(getParameters()) - .header("User-Agent", USER_AGENT) - .asJson(); - // @formatter:on - - if (response.isSuccess()) { - onSuccess(response.getBody()); - writeCacheFile(response.getBody()); + String params = getParameters().entrySet().stream() + .map(p -> p.getKey() + "=" + p.getValue()) + .reduce((p1, p2) -> p1 + "&" + p2) + .map(s -> "?" + s) + .orElse(""); + URI uri = new URI(url + params); + + HttpResponse response = client.send( + HttpRequest.newBuilder(uri).header("User-Agent", USER_AGENT).build(), + HttpResponse.BodyHandlers.ofString() + ); + JsonElement element = JsonUtils.parseString(response.body()); + + if (response.statusCode() >= 200 && response.statusCode() < 300) { + onSuccess(element); + writeCacheFile(element); } else { if (github.isLoggingEnabled()) { - Slimefun.logger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.getStatus(), response.getBody() }); + Slimefun.logger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.statusCode(), element }); } // It has the cached file, let's just read that then if (file.exists()) { - JsonNode cache = readCacheFile(); + JsonElement cache = readCacheFile(); if (cache != null) { onSuccess(cache); } } } - } catch (UnirestException e) { + } catch (IOException | InterruptedException | JsonParseException | URISyntaxException e) { if (github.isLoggingEnabled()) { Slimefun.logger().log(Level.WARNING, "Could not connect to GitHub in time.", e); } // It has the cached file, let's just read that then if (file.exists()) { - JsonNode cache = readCacheFile(); + JsonElement cache = readCacheFile(); if (cache != null) { onSuccess(cache); @@ -150,16 +160,16 @@ void download() { } @Nullable - private JsonNode readCacheFile() { + private JsonElement readCacheFile() { try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) { - return new JsonNode(reader.readLine()); - } catch (IOException | JSONException e) { + return JsonUtils.parseString(reader.readLine()); + } catch (IOException | JsonParseException e) { Slimefun.logger().log(Level.WARNING, "Failed to read Github cache file: {0} - {1}: {2}", new Object[] { file.getName(), e.getClass().getSimpleName(), e.getMessage() }); return null; } } - private void writeCacheFile(@Nonnull JsonNode node) { + private void writeCacheFile(@Nonnull JsonElement node) { try (FileOutputStream output = new FileOutputStream(file)) { output.write(node.toString().getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java index 81cd1ac5d3..96a4237e1e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java @@ -7,11 +7,11 @@ import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; -import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; -import kong.unirest.JsonNode; -import kong.unirest.json.JSONArray; -import kong.unirest.json.JSONObject; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; class GitHubIssuesConnector extends GitHubConnector { @@ -24,15 +24,15 @@ class GitHubIssuesConnector extends GitHubConnector { } @Override - public void onSuccess(@Nonnull JsonNode response) { - if (response.isArray()) { - JSONArray array = response.getArray(); + public void onSuccess(@Nonnull JsonElement response) { + if (response.isJsonArray()) { + JsonArray array = response.getAsJsonArray(); int issues = 0; int pullRequests = 0; - for (int i = 0; i < array.length(); i++) { - JSONObject obj = array.getJSONObject(i); + for (JsonElement element : array) { + JsonObject obj = element.getAsJsonObject(); if (obj.has("pull_request")) { pullRequests++; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java index 2a1292225a..408fdc439e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java @@ -22,6 +22,8 @@ import org.bukkit.block.Block; import org.bukkit.scheduler.BukkitScheduler; +import com.google.common.util.concurrent.AtomicDouble; + import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; @@ -87,6 +89,8 @@ public class SlimefunProfiler { private final AtomicLong totalMsTicked = new AtomicLong(); private final AtomicInteger ticksPassed = new AtomicInteger(); + private final AtomicLong totalNsTicked = new AtomicLong(); + private final AtomicDouble averageTimingsPerMachine = new AtomicDouble(); /** * This method terminates the {@link SlimefunProfiler}. @@ -222,11 +226,14 @@ private void finishReport() { totalElapsedTime = timings.values().stream().mapToLong(Long::longValue).sum(); + averageTimingsPerMachine.getAndSet(timings.values().stream().mapToLong(Long::longValue).average().orElse(0)); + /* * We log how many milliseconds have been ticked, and how many ticks have passed * This is so when bStats requests the average timings, they're super quick to figure out */ totalMsTicked.addAndGet(TimeUnit.NANOSECONDS.toMillis(totalElapsedTime)); + totalNsTicked.addAndGet(totalElapsedTime); ticksPassed.incrementAndGet(); if (!requests.isEmpty()) { @@ -416,4 +423,26 @@ public long getAndResetAverageTimings() { return l; } + + /** + * Get and reset the average nanosecond timing for this {@link SlimefunProfiler}. + * + * @return The average nanosecond timing for this {@link SlimefunProfiler}. + */ + public double getAndResetAverageNanosecondTimings() { + long l = totalNsTicked.get() / ticksPassed.get(); + totalNsTicked.set(0); + ticksPassed.set(0); + + return l; + } + + /** + * Get and reset the average millisecond timing for each machine. + * + * @return The average millisecond timing for each machine. + */ + public double getAverageTimingsPerMachine() { + return averageTimingsPerMachine.getAndSet(0); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java index 28233ea741..1be851ba17 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java @@ -42,6 +42,7 @@ import io.github.thebusybiscuit.slimefun4.core.SlimefunRegistry; import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager; +import io.github.thebusybiscuit.slimefun4.core.services.AnalyticsService; import io.github.thebusybiscuit.slimefun4.core.services.AutoSavingService; import io.github.thebusybiscuit.slimefun4.core.services.BackupService; import io.github.thebusybiscuit.slimefun4.core.services.BlockDataService; @@ -52,6 +53,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.MinecraftRecipeService; import io.github.thebusybiscuit.slimefun4.core.services.PerWorldSettingsService; import io.github.thebusybiscuit.slimefun4.core.services.PermissionsService; +import io.github.thebusybiscuit.slimefun4.core.services.ThreadService; import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService; import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService; import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService; @@ -182,6 +184,8 @@ public class Slimefun extends JavaPlugin implements SlimefunAddon { private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this); private final HologramsService hologramsService = new HologramsService(this); private final SoundService soundService = new SoundService(this); + private final ThreadService threadService = new ThreadService(this); + private final AnalyticsService analyticsService = new AnalyticsService(this); // Some other things we need private final IntegrationsManager integrations = new IntegrationsManager(this); @@ -309,8 +313,9 @@ private void onPluginStart() { playerStorage = new LegacyStorage(); logger.log(Level.INFO, "Using legacy storage for player data"); - // Setting up bStats + // Setting up bStats and analytics new Thread(metricsService::start, "Slimefun Metrics").start(); + analyticsService.start(); // Starting the Auto-Updater if (config.getBoolean("options.auto-update")) { @@ -520,11 +525,12 @@ private boolean isVersionUnsupported() { // Now check the actual Version of Minecraft int version = PaperLib.getMinecraftVersion(); + int patchVersion = PaperLib.getMinecraftPatchVersion(); if (version > 0) { // Check all supported versions of Minecraft for (MinecraftVersion supportedVersion : MinecraftVersion.values()) { - if (supportedVersion.isMinecraftVersion(version)) { + if (supportedVersion.isMinecraftVersion(version, patchVersion)) { minecraftVersion = supportedVersion; return false; } @@ -901,6 +907,17 @@ public static SoundService getSoundService() { return instance.metricsService; } + /** + * This method returns the {@link AnalyticsService} of Slimefun. + * It is used to handle sending analytic information. + * + * @return The {@link AnalyticsService} for Slimefun + */ + public static @Nonnull AnalyticsService getAnalyticsService() { + validateInstance(); + return instance.analyticsService; + } + /** * This method returns the {@link GitHubService} of Slimefun. * It is used to retrieve data from GitHub repositories. @@ -1068,4 +1085,14 @@ public static boolean isNewlyInstalled() { public static @Nonnull Storage getPlayerStorage() { return instance().playerStorage; } + + /** + * This method returns the {@link ThreadService} of Slimefun. + * Do not use this if you're an addon. Please make your own {@link ThreadService}. + * + * @return The {@link ThreadService} for Slimefun + */ + public static @Nonnull ThreadService getThreadService() { + return instance().threadService; + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java index 8695759316..d3adb16e0b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -22,6 +22,7 @@ import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; import io.github.thebusybiscuit.slimefun4.utils.LoreBuilder; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ColoredFireworkStar; /** @@ -192,8 +193,8 @@ private SlimefunItems() {} GRANDPAS_WALKING_STICK.addUnsafeEnchantment(Enchantment.KNOCKBACK, 5); BLADE_OF_VAMPIRES.addUnsafeEnchantment(Enchantment.FIRE_ASPECT, 2); - BLADE_OF_VAMPIRES.addUnsafeEnchantment(Enchantment.DURABILITY, 4); - BLADE_OF_VAMPIRES.addUnsafeEnchantment(Enchantment.DAMAGE_ALL, 2); + BLADE_OF_VAMPIRES.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 4); + BLADE_OF_VAMPIRES.addUnsafeEnchantment(VersionedEnchantment.SHARPNESS, 2); } /* Bows */ @@ -212,8 +213,8 @@ private SlimefunItems() {} public static final SlimefunItemStack CLIMBING_PICK = new SlimefunItemStack("CLIMBING_PICK", Material.IRON_PICKAXE, "&bClimbing Pick", "", "&fAllows you to climb certain surfaces", "&fby right-clicking.", "&fEnchant this pick with Efficiency to", "&fclimb even faster!"); static { - COBALT_PICKAXE.addUnsafeEnchantment(Enchantment.DURABILITY, 10); - COBALT_PICKAXE.addUnsafeEnchantment(Enchantment.DIG_SPEED, 6); + COBALT_PICKAXE.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 10); + COBALT_PICKAXE.addUnsafeEnchantment(VersionedEnchantment.EFFICIENCY, 6); } /* Armor */ @@ -304,7 +305,7 @@ private SlimefunItems() {} static { Map cactusEnchs = new HashMap<>(); cactusEnchs.put(Enchantment.THORNS, 3); - cactusEnchs.put(Enchantment.DURABILITY, 6); + cactusEnchs.put(VersionedEnchantment.UNBREAKING, 6); CACTUS_HELMET.addUnsafeEnchantments(cactusEnchs); CACTUS_CHESTPLATE.addUnsafeEnchantments(cactusEnchs); @@ -312,8 +313,8 @@ private SlimefunItems() {} CACTUS_BOOTS.addUnsafeEnchantments(cactusEnchs); Map damascusEnchs = new HashMap<>(); - damascusEnchs.put(Enchantment.DURABILITY, 5); - damascusEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 5); + damascusEnchs.put(VersionedEnchantment.UNBREAKING, 5); + damascusEnchs.put(VersionedEnchantment.PROTECTION, 5); DAMASCUS_STEEL_HELMET.addUnsafeEnchantments(damascusEnchs); DAMASCUS_STEEL_CHESTPLATE.addUnsafeEnchantments(damascusEnchs); @@ -321,8 +322,8 @@ private SlimefunItems() {} DAMASCUS_STEEL_BOOTS.addUnsafeEnchantments(damascusEnchs); Map reinforcedEnchs = new HashMap<>(); - reinforcedEnchs.put(Enchantment.DURABILITY, 9); - reinforcedEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 9); + reinforcedEnchs.put(VersionedEnchantment.UNBREAKING, 9); + reinforcedEnchs.put(VersionedEnchantment.PROTECTION, 9); REINFORCED_ALLOY_HELMET.addUnsafeEnchantments(reinforcedEnchs); REINFORCED_ALLOY_CHESTPLATE.addUnsafeEnchantments(reinforcedEnchs); @@ -330,22 +331,22 @@ private SlimefunItems() {} REINFORCED_ALLOY_BOOTS.addUnsafeEnchantments(reinforcedEnchs); Map gildedEnchs = new HashMap<>(); - gildedEnchs.put(Enchantment.DURABILITY, 6); - gildedEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 8); + gildedEnchs.put(VersionedEnchantment.UNBREAKING, 6); + gildedEnchs.put(VersionedEnchantment.PROTECTION, 8); GILDED_IRON_HELMET.addUnsafeEnchantments(gildedEnchs); GILDED_IRON_CHESTPLATE.addUnsafeEnchantments(gildedEnchs); GILDED_IRON_LEGGINGS.addUnsafeEnchantments(gildedEnchs); GILDED_IRON_BOOTS.addUnsafeEnchantments(gildedEnchs); - GOLDEN_HELMET_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10); - GOLDEN_CHESTPLATE_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10); - GOLDEN_LEGGINGS_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10); - GOLDEN_BOOTS_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10); + GOLDEN_HELMET_12K.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 10); + GOLDEN_CHESTPLATE_12K.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 10); + GOLDEN_LEGGINGS_12K.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 10); + GOLDEN_BOOTS_12K.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 10); Map slimeEnchs = new HashMap<>(); - slimeEnchs.put(Enchantment.DURABILITY, 4); - slimeEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 2); + slimeEnchs.put(VersionedEnchantment.UNBREAKING, 4); + slimeEnchs.put(VersionedEnchantment.PROTECTION, 2); SLIME_HELMET_STEEL.addUnsafeEnchantments(slimeEnchs); SLIME_CHESTPLATE_STEEL.addUnsafeEnchantments(slimeEnchs); @@ -353,8 +354,8 @@ private SlimefunItems() {} SLIME_BOOTS_STEEL.addUnsafeEnchantments(slimeEnchs); Map beeEnchs = new HashMap<>(); - beeEnchs.put(Enchantment.DURABILITY, 4); - beeEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 2); + beeEnchs.put(VersionedEnchantment.UNBREAKING, 4); + beeEnchs.put(VersionedEnchantment.PROTECTION, 2); BEE_HELMET.addUnsafeEnchantments(beeEnchs); BEE_WINGS.addUnsafeEnchantments(beeEnchs); @@ -567,10 +568,10 @@ private SlimefunItems() {} public static final SlimefunItemStack STAFF_STORM = new SlimefunItemStack("STAFF_ELEMENTAL_STORM", Material.STICK, "&6Elemental Staff &7- &8&oStorm", "", "&7Element: &8&oStorm", "", "&eRight Click&7 to summon a lightning", LoreBuilder.usesLeft(StormStaff.MAX_USES)); static { - STAFF_WIND.addUnsafeEnchantment(Enchantment.LUCK, 1); + STAFF_WIND.addUnsafeEnchantment(VersionedEnchantment.LUCK_OF_THE_SEA, 1); STAFF_FIRE.addUnsafeEnchantment(Enchantment.FIRE_ASPECT, 5); - STAFF_WATER.addUnsafeEnchantment(Enchantment.WATER_WORKER, 1); - STAFF_STORM.addUnsafeEnchantment(Enchantment.DURABILITY, 1); + STAFF_WATER.addUnsafeEnchantment(VersionedEnchantment.AQUA_AFFINITY, 1); + STAFF_STORM.addUnsafeEnchantment(VersionedEnchantment.UNBREAKING, 1); } /* Multiblocks */ diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java index 154150d979..83e43be65f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java @@ -48,6 +48,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedItemFlag; import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; @@ -360,7 +361,7 @@ public void openSearch(PlayerProfile profile, String input, boolean addToHistory ItemStack itemstack = new CustomItemStack(slimefunItem.getItem(), meta -> { ItemGroup itemGroup = slimefunItem.getItemGroup(); meta.setLore(Arrays.asList("", ChatColor.DARK_GRAY + "\u21E8 " + ChatColor.WHITE + itemGroup.getDisplayName(p))); - meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_POTION_EFFECTS); + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS, VersionedItemFlag.HIDE_ADDITIONAL_TOOLTIP); }); menu.addItem(index, itemstack); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java index be397c5055..8d041bafb5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java @@ -10,7 +10,6 @@ import org.bukkit.Effect; import org.bukkit.Material; import org.bukkit.OfflinePlayer; -import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; @@ -24,6 +23,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -149,7 +149,7 @@ private void breakBlock(BlockMenu menu, Collection drops, Block block // "poof" a "new" block was generated SoundEffect.MINER_ANDROID_BLOCK_GENERATION_SOUND.playAt(block); - block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getX() + 0.5, block.getY() + 1.25, block.getZ() + 0.5, 8, 0.5, 0.5, 0.5, 0.015); + block.getWorld().spawnParticle(VersionedParticle.SMOKE, block.getX() + 0.5, block.getY() + 1.25, block.getZ() + 0.5, 8, 0.5, 0.5, 0.5, 0.015); } else { block.setType(Material.AIR); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java index 471551575b..8db9826bc7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java @@ -25,7 +25,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -55,8 +54,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; @@ -847,18 +844,7 @@ private void constructMenu(@Nonnull BlockMenuPreset preset) { preset.drawBackground(ChestMenuUtils.getOutputSlotTexture(), OUTPUT_BORDER); for (int i : getOutputSlots()) { - preset.addMenuClickHandler(i, new AdvancedMenuClickHandler() { - - @Override - public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { - return false; - } - - @Override - public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { - return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; - } - }); + preset.addMenuClickHandler(i, ChestMenuUtils.getDefaultOutputHandler()); } preset.addItem(34, getFuelSource().getItem(), ChestMenuUtils.getEmptyClickHandler()); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/AbstractAutoCrafter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/AbstractAutoCrafter.java index 380c7a1273..b75d3c6643 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/AbstractAutoCrafter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/AbstractAutoCrafter.java @@ -14,7 +14,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -41,6 +40,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import io.papermc.lib.PaperLib; import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult; @@ -180,7 +180,7 @@ protected void tick(@Nonnull Block b, @Nonnull Config data) { if (craft(inv, recipe)) { // We are done crafting! Location loc = b.getLocation().add(0.5, 0.8, 0.5); - b.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, loc, 6); + b.getWorld().spawnParticle(VersionedParticle.HAPPY_VILLAGER, loc, 6); removeCharge(b.getLocation(), getEnergyConsumption()); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java index 2e0d31b489..f11e7a35ad 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java @@ -8,7 +8,6 @@ import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.Material; -import org.bukkit.Particle; import org.bukkit.Tag; import org.bukkit.World.Environment; import org.bukkit.block.Block; @@ -30,6 +29,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -165,7 +165,7 @@ private void generateLiquid(@Nonnull Block block, boolean isWater) { // Fixes #2877 - If water in the nether is disabled, abort and play an effect. if (isWater && block.getWorld().getEnvironment() == Environment.NETHER && !allowWaterInNether.getValue()) { // We will still consume the items but won't generate water in the Nether. - block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getLocation().add(0.5, 0.5, 0.5), 4); + block.getWorld().spawnParticle(VersionedParticle.SMOKE, block.getLocation().add(0.5, 0.5, 0.5), 4); SoundEffect.CRUCIBLE_GENERATE_LIQUID_SOUND.playAt(block); return; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java index 56707206d4..d608742da4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java @@ -1,17 +1,20 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import io.github.bakedlibs.dough.common.ChatColors; +import io.github.bakedlibs.dough.data.persistent.PersistentDataAPI; import org.bukkit.ChatColor; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; @@ -22,22 +25,25 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEntityType; /** * The {@link MultiTool} is an electric device which can mimic * the behaviour of any other {@link SlimefunItem}. - * - * @author TheBusyBiscuit * + * @author TheBusyBiscuit */ public class MultiTool extends SlimefunItem implements Rechargeable { private static final float COST = 0.3F; - private final Map selectedMode = new HashMap<>(); private final List modes = new ArrayList<>(); private final float capacity; + private static final NamespacedKey key = new NamespacedKey(Slimefun.instance(), "multitool_mode"); + private static final String LORE_PREFIX = ChatColors.color("&8\u21E8 &7Mode: "); + private static final Pattern REGEX = Pattern.compile(ChatColors.color("(&c&o)?" + LORE_PREFIX) + "(.+)"); + @ParametersAreNonnullByDefault public MultiTool(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, float capacity, String... items) { super(itemGroup, item, recipeType, recipe); @@ -73,17 +79,15 @@ protected ItemUseHandler getItemUseHandler() { return e -> { Player p = e.getPlayer(); ItemStack item = e.getItem(); + ItemMeta meta = item.getItemMeta(); e.cancel(); - int index = selectedMode.getOrDefault(p.getUniqueId(), 0); + int index = PersistentDataAPI.getInt(meta, key, 0); + SlimefunItem sfItem = modes.get(index).getItem(); if (!p.isSneaking()) { - if (removeItemCharge(item, COST)) { - SlimefunItem sfItem = modes.get(index).getItem(); - - if (sfItem != null) { - sfItem.callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(e)); - } + if (sfItem != null && removeItemCharge(item, COST)) { + sfItem.callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(e)); } } else { index = nextIndex(index); @@ -91,7 +95,28 @@ protected ItemUseHandler getItemUseHandler() { SlimefunItem selectedItem = modes.get(index).getItem(); String itemName = selectedItem != null ? selectedItem.getItemName() : "Unknown"; Slimefun.getLocalization().sendMessage(p, "messages.multi-tool.mode-change", true, msg -> msg.replace("%device%", "Multi Tool").replace("%mode%", ChatColor.stripColor(itemName))); - selectedMode.put(p.getUniqueId(), index); + + PersistentDataAPI.setInt(meta, key, index); + + List lore = meta.hasLore() ? meta.getLore() : new ArrayList<>(); + + boolean regexMatchFound = false; + for (int i = 0; i < lore.size(); i++) { + String line = lore.get(i); + + if (REGEX.matcher(line).matches()) { + lore.set(i, LORE_PREFIX + ChatColor.stripColor(itemName)); + regexMatchFound = true; + break; + } + } + + if (!regexMatchFound) { + lore.add(2, LORE_PREFIX + ChatColor.stripColor(itemName)); + } + + meta.setLore(lore); + item.setItemMeta(meta); } }; } @@ -109,15 +134,13 @@ private ToolUseHandler getToolUseHandler() { private EntityInteractHandler getEntityInteractionHandler() { return (e, item, offhand) -> { // Fixes #2217 - Prevent them from being used to shear entities - switch (e.getRightClicked().getType()) { - case MUSHROOM_COW: - case SHEEP: - case SNOWMAN: - Slimefun.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears"); - e.setCancelled(true); - break; - default: - break; + EntityType type = e.getRightClicked().getType(); + if (type == VersionedEntityType.MOOSHROOM + || type == VersionedEntityType.SNOW_GOLEM + || type == EntityType.SHEEP + ) { + Slimefun.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears"); + e.setCancelled(true); } }; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiToolMode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiToolMode.java index 7bf079771b..d3963496d4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiToolMode.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiToolMode.java @@ -8,22 +8,43 @@ class MultiToolMode { + private final int id; + private final String itemId; private final ItemSetting item; private final ItemSetting enabled; + // TODO: Move "id" into some NamespacedKey MultiToolMode(@Nonnull MultiTool multiTool, int id, @Nonnull String itemId) { + this.id = id; + this.itemId = itemId; this.item = new ItemSetting<>(multiTool, "mode." + id + ".item", itemId); this.enabled = new ItemSetting<>(multiTool, "mode." + id + ".enabled", true); multiTool.addItemSetting(item, enabled); } + /** + * This method is deprecated and should not be used. + * + * + * @return The ID of this mode + */ + @Deprecated(since = "RC-37", forRemoval = true) + public int getId() { + return id; + } + @Nullable SlimefunItem getItem() { return SlimefunItem.getById(item.getValue()); } + @Nonnull + String getItemId() { + return itemId; + } + boolean isEnabled() { return enabled.getValue(); } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoBrewer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoBrewer.java index f00676edd6..962bc2d32f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoBrewer.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoBrewer.java @@ -7,6 +7,7 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; @@ -18,7 +19,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.core.attributes.NotHopperable; - +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionType; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; @@ -36,22 +37,22 @@ public class AutoBrewer extends AContainer implements NotHopperable { private static final Map fermentations = new EnumMap<>(PotionType.class); static { - potionRecipes.put(Material.SUGAR, PotionType.SPEED); - potionRecipes.put(Material.RABBIT_FOOT, PotionType.JUMP); + potionRecipes.put(Material.SUGAR, VersionedPotionType.SWIFTNESS); + potionRecipes.put(Material.RABBIT_FOOT, VersionedPotionType.LEAPING); potionRecipes.put(Material.BLAZE_POWDER, PotionType.STRENGTH); - potionRecipes.put(Material.GLISTERING_MELON_SLICE, PotionType.INSTANT_HEAL); + potionRecipes.put(Material.GLISTERING_MELON_SLICE, VersionedPotionType.HEALING); potionRecipes.put(Material.SPIDER_EYE, PotionType.POISON); - potionRecipes.put(Material.GHAST_TEAR, PotionType.REGEN); + potionRecipes.put(Material.GHAST_TEAR, VersionedPotionType.REGENERATION); potionRecipes.put(Material.MAGMA_CREAM, PotionType.FIRE_RESISTANCE); potionRecipes.put(Material.PUFFERFISH, PotionType.WATER_BREATHING); potionRecipes.put(Material.GOLDEN_CARROT, PotionType.NIGHT_VISION); potionRecipes.put(Material.TURTLE_HELMET, PotionType.TURTLE_MASTER); potionRecipes.put(Material.PHANTOM_MEMBRANE, PotionType.SLOW_FALLING); - fermentations.put(PotionType.SPEED, PotionType.SLOWNESS); - fermentations.put(PotionType.JUMP, PotionType.SLOWNESS); - fermentations.put(PotionType.INSTANT_HEAL, PotionType.INSTANT_DAMAGE); - fermentations.put(PotionType.POISON, PotionType.INSTANT_DAMAGE); + fermentations.put(VersionedPotionType.SWIFTNESS, PotionType.SLOWNESS); + fermentations.put(VersionedPotionType.LEAPING, PotionType.SLOWNESS); + fermentations.put(VersionedPotionType.HEALING, VersionedPotionType.HARMING); + fermentations.put(PotionType.POISON, VersionedPotionType.HARMING); fermentations.put(PotionType.NIGHT_VISION, PotionType.INVISIBILITY); } @@ -104,8 +105,53 @@ public AutoBrewer(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipe @ParametersAreNonnullByDefault private @Nullable ItemStack brew(Material input, Material potionType, PotionMeta potion) { - PotionData data = potion.getBasePotionData(); + if (Slimefun.getMinecraftVersion().isBefore(20,2)) { + return brewPreBasePotionType(input, potionType, potion); + } + PotionType type = potion.getBasePotionType(); + if (type == PotionType.WATER) { + if (input == Material.FERMENTED_SPIDER_EYE) { + potion.setBasePotionType(PotionType.WEAKNESS); + return new ItemStack(potionType); + } else if (input == Material.NETHER_WART) { + potion.setBasePotionType(PotionType.AWKWARD); + return new ItemStack(potionType); + } else if (potionType == Material.POTION && input == Material.GUNPOWDER) { + return new ItemStack(Material.SPLASH_POTION); + } else if (potionType == Material.SPLASH_POTION && input == Material.DRAGON_BREATH) { + return new ItemStack(Material.LINGERING_POTION); + } + } else if (input == Material.FERMENTED_SPIDER_EYE) { + PotionType fermented = fermentations.get(type); + + if (fermented != null) { + potion.setBasePotionType(fermented); + return new ItemStack(potionType); + } + } else if (input == Material.REDSTONE && type.isExtendable() && !type.isUpgradeable()) { + // Fixes #3390 - Potions can only be either extended or upgraded. Not both. + potion.setBasePotionType(type); + return new ItemStack(potionType); + } else if (input == Material.GLOWSTONE_DUST && type.isUpgradeable() && !type.isExtendable()) { + // Fixes #3390 - Potions can only be either extended or upgraded. Not both. + potion.setBasePotionType(type); + return new ItemStack(potionType); + } else if (type == PotionType.AWKWARD) { + PotionType potionRecipe = potionRecipes.get(input); + + if (potionRecipe != null) { + potion.setBasePotionType(potionRecipe); + return new ItemStack(potionType); + } + } + return null; + } + + @ParametersAreNonnullByDefault + @SuppressWarnings("deprecration") + private ItemStack brewPreBasePotionType(Material input, Material potionType, PotionMeta potion) { + PotionData data = potion.getBasePotionData(); PotionType type = data.getType(); if (type == PotionType.WATER) { if (input == Material.FERMENTED_SPIDER_EYE) { @@ -142,16 +188,15 @@ public AutoBrewer(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipe return new ItemStack(potionType); } } - return null; } /** * Checks whether a given {@link Material} is a valid Potion material. - * + * * @param mat * The {@link Material} to check - * + * * @return Whether this {@link Material} is a valid potion */ private boolean isPotion(@Nonnull Material mat) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ChargingBench.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ChargingBench.java index e3395e9f64..b535e44b40 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ChargingBench.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ChargingBench.java @@ -44,6 +44,10 @@ protected void tick(Block b) { for (int slot : getInputSlots()) { ItemStack item = inv.getItemInSlot(slot); + if (item == null || item.getAmount() != 1) { + continue; + } + if (charge(b, inv, slot, item)) { return; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java index 24e0e0c33e..2218339998 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java @@ -11,7 +11,6 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import io.github.bakedlibs.dough.items.CustomItemStack; @@ -25,8 +24,6 @@ import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu; @@ -126,18 +123,7 @@ protected void constructMenu(BlockMenuPreset preset) { preset.addItem(22, new CustomItemStack(Material.BLACK_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); for (int i : getOutputSlots()) { - preset.addMenuClickHandler(i, new AdvancedMenuClickHandler() { - - @Override - public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { - return false; - } - - @Override - public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { - return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; - } - }); + preset.addMenuClickHandler(i, ChestMenuUtils.getDefaultOutputHandler()); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java index b0bfacd9de..729fd2ff51 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java @@ -7,14 +7,13 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Levelled; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import io.github.bakedlibs.dough.blocks.Vein; @@ -32,8 +31,6 @@ import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -100,18 +97,7 @@ private void constructMenu(@Nonnull BlockMenuPreset preset) { } for (int i : getOutputSlots()) { - preset.addMenuClickHandler(i, new AdvancedMenuClickHandler() { - - @Override - public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { - return false; - } - - @Override - public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { - return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; - } - }); + preset.addMenuClickHandler(i, ChestMenuUtils.getDefaultOutputHandler()); } } @@ -218,7 +204,11 @@ private Block findNextFluid(@Nonnull Block fluid) { case BUBBLE_COLUMN: ItemStack waterBottle = new ItemStack(Material.POTION); PotionMeta meta = (PotionMeta) waterBottle.getItemMeta(); - meta.setBasePotionData(new PotionData(PotionType.WATER)); + if (Slimefun.getMinecraftVersion().isBefore(20, 2)) { + meta.setBasePotionData(new PotionData(PotionType.WATER)); + } else { + meta.setBasePotionType(PotionType.WATER); + } waterBottle.setItemMeta(meta); return waterBottle; default: @@ -239,10 +229,10 @@ private Block findNextFluid(@Nonnull Block fluid) { /** * This method checks if the given {@link Block} is a liquid source {@link Block}. - * + * * @param block * The {@link Block} in question - * + * * @return Whether that {@link Block} is a liquid and a source {@link Block}. */ private boolean isSource(@Nonnull Block block) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java index 68a570f8a5..1da903c425 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java @@ -1,6 +1,5 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators; -import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.entity.Ageable; import org.bukkit.entity.Entity; @@ -12,6 +11,7 @@ import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -54,7 +54,7 @@ protected void tick(Block b) { ageable.setAge(0); } - n.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, ((LivingEntity) n).getEyeLocation(), 8, 0.2F, 0.2F, 0.2F); + n.getWorld().spawnParticle(VersionedParticle.HAPPY_VILLAGER, ((LivingEntity) n).getEyeLocation(), 8, 0.2F, 0.2F, 0.2F); return; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java index 5649c70c73..5cf09b31f9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java @@ -1,6 +1,5 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators; -import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.block.data.Ageable; import org.bukkit.inventory.ItemStack; @@ -10,6 +9,7 @@ import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; @@ -65,7 +65,7 @@ private boolean grow(Block machine, BlockMenu inv, Block crop) { ageable.setAge(ageable.getAge() + 1); crop.setBlockData(ageable); - crop.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, crop.getLocation().add(0.5D, 0.5D, 0.5D), 4, 0.1F, 0.1F, 0.1F); + crop.getWorld().spawnParticle(VersionedParticle.HAPPY_VILLAGER, crop.getLocation().add(0.5D, 0.5D, 0.5D), 4, 0.1F, 0.1F, 0.1F); return true; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java index e6e79311db..a9332d777e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java @@ -4,7 +4,6 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; -import org.bukkit.Particle; import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -18,6 +17,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -93,7 +93,7 @@ private boolean applyBoneMeal(Block machine, Block sapling, BlockMenu inv) { sapling.applyBoneMeal(BlockFace.UP); inv.consumeItem(slot); - sapling.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, sapling.getLocation().add(0.5D, 0.5D, 0.5D), 4, 0.1F, 0.1F, 0.1F); + sapling.getWorld().spawnParticle(VersionedParticle.HAPPY_VILLAGER, sapling.getLocation().add(0.5D, 0.5D, 0.5D), 4, 0.1F, 0.1F, 0.1F); return true; } } @@ -111,7 +111,7 @@ private boolean updateSaplingData(Block machine, Block block, BlockMenu inv, Sap block.setBlockData(sapling, false); inv.consumeItem(slot); - block.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, block.getLocation().add(0.5D, 0.5D, 0.5D), 4, 0.1F, 0.1F, 0.1F); + block.getWorld().spawnParticle(VersionedParticle.HAPPY_VILLAGER, block.getLocation().add(0.5D, 0.5D, 0.5D), 4, 0.1F, 0.1F, 0.1F); return true; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java index 3a6cb6d857..4697ec75fd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java @@ -44,35 +44,43 @@ public class ExpCollector extends SlimefunItem implements InventoryBlock, Energy private final int[] border = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; - private static final int ENERGY_CONSUMPTION = 10; private static final String DATA_KEY = "stored-exp"; + private final double range; + private int energyConsumedPerTick = -1; + private int energyCapacity = -1; + + @Deprecated(since = "RC-38", forRemoval = true) @ParametersAreNonnullByDefault public ExpCollector(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + this(itemGroup, item, recipeType, recipe, 4.0); + } + + @ParametersAreNonnullByDefault + public ExpCollector(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, double range) { super(itemGroup, item, recipeType, recipe); + this.range = range; createPreset(this, this::constructMenu); - addItemHandler(onPlace(), onBreak()); } - @Nonnull - private BlockPlaceHandler onPlace() { + + private @Nonnull BlockPlaceHandler onPlace() { return new BlockPlaceHandler(false) { @Override - public void onPlayerPlace(BlockPlaceEvent e) { + public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { BlockStorage.addBlockInfo(e.getBlock(), "owner", e.getPlayer().getUniqueId().toString()); } }; } - @Nonnull - private ItemHandler onBreak() { + private @Nonnull ItemHandler onBreak() { return new SimpleBlockBreakHandler() { @Override - public void onBlockBreak(Block b) { + public void onBlockBreak(@Nonnull Block b) { BlockMenu inv = BlockStorage.getInventory(b); if (inv != null) { @@ -97,11 +105,6 @@ public EnergyNetComponentType getEnergyComponentType() { return EnergyNetComponentType.CONSUMER; } - @Override - public int getCapacity() { - return 1024; - } - protected void constructMenu(BlockMenuPreset preset) { for (int slot : border) { preset.addItem(slot, new CustomItemStack(Material.PURPLE_STAINED_GLASS_PANE, " "), (p, s, item, action) -> false); @@ -126,19 +129,19 @@ public boolean isSynchronized() { protected void tick(Block block) { Location location = block.getLocation(); - Iterator iterator = block.getWorld().getNearbyEntities(location, 4.0, 4.0, 4.0, n -> n instanceof ExperienceOrb && n.isValid()).iterator(); + Iterator iterator = block.getWorld().getNearbyEntities(location, range, range, range, n -> n instanceof ExperienceOrb && n.isValid()).iterator(); int experiencePoints = 0; while (iterator.hasNext() && experiencePoints == 0) { ExperienceOrb orb = (ExperienceOrb) iterator.next(); - if (getCharge(location) < ENERGY_CONSUMPTION) { + if (getCharge(location) < getEnergyConsumption()) { return; } experiencePoints = getStoredExperience(location) + orb.getExperience(); - removeCharge(location, ENERGY_CONSUMPTION); + removeCharge(location, getEnergyConsumption()); orb.remove(); produceFlasks(location, experiencePoints); } @@ -179,4 +182,23 @@ private int getStoredExperience(Location location) { return 0; } } + + public int getEnergyConsumption() { + return energyConsumedPerTick; + } + + public ExpCollector setEnergyConsumption(int energyConsumedPerTick) { + this.energyConsumedPerTick = energyConsumedPerTick; + return this; + } + + @Override + public int getCapacity() { + return energyCapacity; + } + + public ExpCollector setCapacity(int energyCapacity) { + this.energyCapacity = energyCapacity; + return this; + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java index cc09eb0ac6..d21815533b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java @@ -11,9 +11,7 @@ import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.entity.Player; import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import io.github.bakedlibs.dough.items.CustomItemStack; @@ -38,8 +36,6 @@ import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -265,18 +261,7 @@ protected void constructMenu(@Nonnull BlockMenuPreset preset) { preset.addItem(4, new CustomItemStack(Material.BLACK_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); for (int i : OUTPUT_SLOTS) { - preset.addMenuClickHandler(i, new AdvancedMenuClickHandler() { - - @Override - public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { - return false; - } - - @Override - public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { - return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; - } - }); + preset.addMenuClickHandler(i, ChestMenuUtils.getDefaultOutputHandler()); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java index ce8e53f8d9..33e54e7544 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java @@ -14,7 +14,6 @@ import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Particle; import org.bukkit.SoundCategory; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; @@ -30,6 +29,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; /** * This {@link SlimefunItem} allows you to enchant any enchantable {@link ItemStack} with a random @@ -50,6 +50,8 @@ public EnchantmentRune(ItemGroup itemGroup, SlimefunItemStack item, RecipeType r super(itemGroup, item, recipeType, recipe); for (Material mat : Material.values()) { + if (Slimefun.instance().isUnitTest() && mat.isLegacy()) continue; + List enchantments = new ArrayList<>(); for (Enchantment enchantment : Enchantment.values()) { @@ -140,7 +142,7 @@ private void addRandomEnchantment(@Nonnull Player p, @Nonnull Item rune) { // Being sure entities are still valid and not picked up or whatsoever. if (rune.isValid() && item.isValid() && itemStack.getAmount() == 1) { - l.getWorld().spawnParticle(Particle.CRIT_MAGIC, l, 1); + l.getWorld().spawnParticle(VersionedParticle.ENCHANTED_HIT, l, 1); SoundEffect.ENCHANTMENT_RUNE_ADD_ENCHANT_SOUND.playAt(l, SoundCategory.PLAYERS); item.remove(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java index d5a3b325aa..fe5195e22c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java @@ -22,6 +22,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; /** * This {@link SlimefunItem} allows you to reset a {@link Villager} profession. @@ -64,7 +65,7 @@ public VillagerRune(ItemGroup itemGroup, SlimefunItemStack item, RecipeType reci SoundEffect.VILLAGER_RUNE_TRANSFORM_SOUND.playAt(villager.getLocation(), SoundCategory.NEUTRAL); villager.getWorld().spawnParticle(Particle.CRIMSON_SPORE, villager.getLocation(), 10, 0, offset / 2, 0, 0); - villager.getWorld().spawnParticle(Particle.ENCHANTMENT_TABLE, villager.getLocation(), 5, 0.04, 1, 0.04); + villager.getWorld().spawnParticle(VersionedParticle.ENCHANT, villager.getLocation(), 5, 0.04, 1, 0.04); } }; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Bandage.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Bandage.java index d69ceeaa91..b87882cf6d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Bandage.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Bandage.java @@ -9,7 +9,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import io.github.bakedlibs.dough.items.ItemUtils; import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; @@ -17,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; /** * A {@link Bandage} or Rag is a medical supply which heals the {@link Player} and extinguishes @@ -51,7 +51,7 @@ public ItemUseHandler getItemHandler() { } p.getWorld().playEffect(p.getLocation(), Effect.STEP_SOUND, Material.WHITE_WOOL); - p.addPotionEffect(new PotionEffect(PotionEffectType.HEAL, 1, healingLevel)); + p.addPotionEffect(new PotionEffect(VersionedPotionEffectType.INSTANT_HEALTH, 1, healingLevel)); p.setFireTicks(0); e.cancel(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/MedicalSupply.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/MedicalSupply.java index 2a0383001b..350376eab8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/MedicalSupply.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/MedicalSupply.java @@ -18,6 +18,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; public abstract class MedicalSupply extends SimpleSlimefunItem { @@ -32,10 +33,10 @@ protected MedicalSupply(ItemGroup itemGroup, int healAmount, SlimefunItemStack i curedEffects.add(PotionEffectType.POISON); curedEffects.add(PotionEffectType.WITHER); - curedEffects.add(PotionEffectType.SLOW); - curedEffects.add(PotionEffectType.SLOW_DIGGING); + curedEffects.add(VersionedPotionEffectType.SLOWNESS); + curedEffects.add(VersionedPotionEffectType.MINING_FATIGUE); curedEffects.add(PotionEffectType.WEAKNESS); - curedEffects.add(PotionEffectType.CONFUSION); + curedEffects.add(VersionedPotionEffectType.NAUSEA); curedEffects.add(PotionEffectType.BLINDNESS); curedEffects.add(PotionEffectType.BAD_OMEN); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Splint.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Splint.java index a6495d061a..0a510ff28a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Splint.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/medical/Splint.java @@ -8,7 +8,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import io.github.bakedlibs.dough.items.ItemUtils; import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; @@ -17,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; public class Splint extends SimpleSlimefunItem { @@ -40,7 +40,7 @@ public Splint(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType } SoundEffect.SPLINT_CONSUME_SOUND.playFor(p); - p.addPotionEffect(new PotionEffect(PotionEffectType.HEAL, 1, 0)); + p.addPotionEffect(new PotionEffect(VersionedPotionEffectType.INSTANT_HEALTH, 1, 0)); e.cancel(); }; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/MiningTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/MiningTask.java index 5da4697970..0169f0f846 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/MiningTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/MiningTask.java @@ -10,7 +10,6 @@ import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Particle; import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.block.Block; @@ -30,6 +29,7 @@ import io.github.bakedlibs.dough.scheduling.TaskQueue; import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; import io.papermc.lib.PaperLib; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel; @@ -341,7 +341,7 @@ private void setPistonState(@Nonnull Block block, boolean extended) { try { // Smoke Particles around the Chest for dramatic effect Location particleLoc = chest.getLocation().clone().add(0, -1, 0); - block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, particleLoc, 20, 0.7, 0.7, 0.7, 0); + block.getWorld().spawnParticle(VersionedParticle.SMOKE, particleLoc, 20, 0.7, 0.7, 0.7, 0); if (block.getType() == Material.MOVING_PISTON) { // Yeah it isn't really cool when this happens diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ClimbingPick.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ClimbingPick.java index 43f0225237..265db240ed 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ClimbingPick.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ClimbingPick.java @@ -39,6 +39,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; import io.github.thebusybiscuit.slimefun4.implementation.settings.ClimbableSurface; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; /** @@ -147,7 +148,7 @@ public double getClimbingSpeed(@Nonnull ItemStack item, @Nonnull Material type) double speed = getClimbingSpeed(type); if (speed > 0) { - int efficiencyLevel = item.getEnchantmentLevel(Enchantment.DIG_SPEED); + int efficiencyLevel = item.getEnchantmentLevel(VersionedEnchantment.EFFICIENCY); if (efficiencyLevel > 0) { speed += efficiencyLevel * EFFICIENCY_MODIFIER; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java index d4cea025f5..1477549c9f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java @@ -6,7 +6,6 @@ import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.Bukkit; -import org.bukkit.Particle; import org.bukkit.SoundCategory; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; @@ -22,6 +21,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; import io.github.thebusybiscuit.slimefun4.core.handlers.BowShootHandler; import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; /** * The {@link ExplosiveBow} is a {@link SlimefunBow} which creates a fake explosion when it hits @@ -49,7 +49,7 @@ public ExplosiveBow(ItemGroup itemGroup, SlimefunItemStack item, ItemStack[] rec @Override public BowShootHandler onShoot() { return (e, target) -> { - target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation(), 1); + target.getWorld().spawnParticle(VersionedParticle.EXPLOSION, target.getLocation(), 1); SoundEffect.EXPLOSIVE_BOW_HIT_SOUND.playAt(target.getLocation(), SoundCategory.PLAYERS); int radius = range.getValue(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java index 474a7277d6..b3e54f15ed 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java @@ -9,13 +9,13 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.core.handlers.BowShootHandler; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; /** * The {@link IcyBow} is a special kind of bow which slows down any @@ -48,8 +48,8 @@ public BowShootHandler onShoot() { } n.getWorld().playEffect(n.getLocation(), Effect.STEP_SOUND, Material.ICE); n.getWorld().playEffect(n.getEyeLocation(), Effect.STEP_SOUND, Material.ICE); - n.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 10)); - n.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 20 * 2, -10)); + n.addPotionEffect(new PotionEffect(VersionedPotionEffectType.SLOWNESS, 20 * 2, 10)); + n.addPotionEffect(new PotionEffect(VersionedPotionEffectType.JUMP_BOOST, 20 * 2, -10)); }; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java index 12937e45a4..40b976e345 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java @@ -39,6 +39,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -70,18 +71,18 @@ public void onBlockPlaceExisting(BlockPlaceEvent e) { Block block = e.getBlock(); // Fixes #2636 - This will solve the "ghost blocks" issue - if (e.getBlockReplacedState().getType().isAir()) { + if (e.getBlockReplacedState().getType().isAir() && BlockStorage.hasBlockInfo(block) && !Slimefun.getTickerTask().isDeletedSoon(block.getLocation())) { SlimefunItem sfItem = BlockStorage.check(block); - if (sfItem != null && !Slimefun.getTickerTask().isDeletedSoon(block.getLocation())) { + if (sfItem != null) { for (ItemStack item : sfItem.getDrops()) { if (item != null && !item.getType().isAir()) { block.getWorld().dropItemNaturally(block.getLocation(), item); } } - - BlockStorage.clearBlockInfo(block); } + + BlockStorage.clearBlockInfo(block); } else if (BlockStorage.hasBlockInfo(e.getBlock())) { // If there is no air (e.g. grass) then don't let the block be placed e.setCancelled(true); @@ -374,7 +375,7 @@ private int getBonusDropsWithFortune(@Nullable ItemStack item, @Nonnull Block b) * directly and re use it. */ ItemMeta meta = item.getItemMeta(); - int fortuneLevel = meta.getEnchantLevel(Enchantment.LOOT_BONUS_BLOCKS); + int fortuneLevel = meta.getEnchantLevel(VersionedEnchantment.FORTUNE); if (fortuneLevel > 0 && !meta.hasEnchant(Enchantment.SILK_TOUCH)) { Random random = ThreadLocalRandom.current(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java index a01625c836..7a8b29c0df 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java @@ -49,6 +49,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.MagicianTalisman; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman; import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; /** @@ -301,7 +302,7 @@ public void onEnchant(EnchantItemEvent e) { } // Wizard Talisman - if (!enchantments.containsKey(Enchantment.SILK_TOUCH) && Enchantment.LOOT_BONUS_BLOCKS.canEnchantItem(e.getItem()) && Talisman.trigger(e, SlimefunItems.TALISMAN_WIZARD)) { + if (!enchantments.containsKey(Enchantment.SILK_TOUCH) && VersionedEnchantment.FORTUNE.canEnchantItem(e.getItem()) && Talisman.trigger(e, SlimefunItems.TALISMAN_WIZARD)) { // Randomly lower some enchantments for (Map.Entry entry : enchantments.entrySet()) { if (entry.getValue() > 1 && random.nextInt(100) < 40) { @@ -310,7 +311,7 @@ public void onEnchant(EnchantItemEvent e) { } // Give an extra Fortune boost (Lvl 3 - 5) - enchantments.put(Enchantment.LOOT_BONUS_BLOCKS, random.nextInt(3) + 3); + enchantments.put(VersionedEnchantment.FORTUNE, random.nextInt(3) + 3); } } @@ -351,7 +352,7 @@ private void doubleTalismanDrops(BlockDropItemEvent e, SlimefunItemStack talisma Collection drops = e.getItems(); if (Talisman.trigger(e, talismanItemStack, false)) { - int dropAmount = getAmountWithFortune(type, meta.getEnchantLevel(Enchantment.LOOT_BONUS_BLOCKS)); + int dropAmount = getAmountWithFortune(type, meta.getEnchantLevel(VersionedEnchantment.FORTUNE)); // Keep track of whether we actually doubled the drops or not boolean doubledDrops = false; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java index 9ade30e843..14575310af 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java @@ -217,6 +217,7 @@ import io.github.thebusybiscuit.slimefun4.utils.ColoredMaterial; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; /** * This class holds the recipes of all items. @@ -241,7 +242,7 @@ public static void setup(@Nonnull Slimefun plugin) { new SlimefunItem(itemGroups.weapons, SlimefunItems.GRANDMAS_WALKING_STICK, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null}) .register(plugin); - + new SlimefunItem(itemGroups.weapons, SlimefunItems.GRANDPAS_WALKING_STICK, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {new ItemStack(Material.LEATHER), new ItemStack(Material.OAK_LOG), new ItemStack(Material.LEATHER), null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null}) .register(plugin); @@ -261,7 +262,7 @@ public static void setup(@Nonnull Slimefun plugin) { new OutputChest(itemGroups.basicMachines, SlimefunItems.OUTPUT_CHEST, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.LEAD_INGOT, new ItemStack(Material.HOPPER), SlimefunItems.LEAD_INGOT, SlimefunItems.LEAD_INGOT, new ItemStack(Material.CHEST), SlimefunItems.LEAD_INGOT, null, SlimefunItems.LEAD_INGOT, null}) .register(plugin); - + new EnhancedCraftingTable(itemGroups.basicMachines, SlimefunItems.ENHANCED_CRAFTING_TABLE).register(plugin); new PortableDustbin(itemGroups.usefulItems, SlimefunItems.PORTABLE_DUSTBIN, RecipeType.ENHANCED_CRAFTING_TABLE, @@ -299,14 +300,14 @@ public static void setup(@Nonnull Slimefun plugin) { new GrindStone(itemGroups.basicMachines, SlimefunItems.GRIND_STONE).register(plugin); new ArmorForge(itemGroups.basicMachines, SlimefunItems.ARMOR_FORGE).register(plugin); - + OreCrusher oreCrusher = new OreCrusher(itemGroups.basicMachines, SlimefunItems.ORE_CRUSHER); oreCrusher.register(plugin); - + new Compressor(itemGroups.basicMachines, SlimefunItems.COMPRESSOR).register(plugin); new SlimefunItem(itemGroups.magicalResources, SlimefunItems.MAGIC_LUMP_1, RecipeType.GRIND_STONE, - new ItemStack[] {new ItemStack(Material.NETHER_WART), null, null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.NETHER_WART), null, null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.MAGIC_LUMP_1, 2)) .register(plugin); @@ -378,7 +379,7 @@ public static void setup(@Nonnull Slimefun plugin) { new LongFallBoots(itemGroups.magicalArmor, SlimefunItems.SLIME_BOOTS, RecipeType.ARMOR_FORGE, new ItemStack[] {null, null, null, new ItemStack(Material.SLIME_BALL), null, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.IRON_INGOT)}, - new PotionEffect[] {new PotionEffect(PotionEffectType.JUMP, 300, 5)}, + new PotionEffect[] {new PotionEffect(VersionedPotionEffectType.JUMP_BOOST, 300, 5)}, SoundEffect.SLIME_BOOTS_FALL_SOUND) .register(plugin); @@ -416,11 +417,11 @@ public static void setup(@Nonnull Slimefun plugin) { new MakeshiftSmeltery(itemGroups.basicMachines, SlimefunItems.MAKESHIFT_SMELTERY).register(plugin); new Smeltery(itemGroups.basicMachines, SlimefunItems.SMELTERY).register(plugin); - + new IgnitionChamber(itemGroups.basicMachines, SlimefunItems.IGNITION_CHAMBER, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {new ItemStack(Material.IRON_INGOT), new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.IRON_INGOT), new ItemStack(Material.IRON_INGOT), SlimefunItems.BASIC_CIRCUIT_BOARD, new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.OBSERVER), null}) .register(plugin); - + new PressureChamber(itemGroups.basicMachines, SlimefunItems.PRESSURE_CHAMBER).register(plugin); new UnplaceableBlock(itemGroups.technicalComponents, SlimefunItems.BATTERY, RecipeType.ENHANCED_CRAFTING_TABLE, @@ -429,9 +430,9 @@ public static void setup(@Nonnull Slimefun plugin) { registerArmorSet(itemGroups.magicalArmor, new ItemStack(Material.GLOWSTONE), new ItemStack[] {SlimefunItems.GLOWSTONE_HELMET, SlimefunItems.GLOWSTONE_CHESTPLATE, SlimefunItems.GLOWSTONE_LEGGINGS, SlimefunItems.GLOWSTONE_BOOTS}, "GLOWSTONE", false, new PotionEffect[][] { - new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)}, - new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)}, - new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)}, + new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)}, + new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)}, + new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)}, new PotionEffect[] {new PotionEffect(PotionEffectType.NIGHT_VISION, 600, 0)} }, plugin); @@ -551,12 +552,12 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new SlimefunItem(itemGroups.resources, SlimefunItems.IRON_DUST, RecipeType.ORE_CRUSHER, - new ItemStack[] {new ItemStack(Material.IRON_ORE), null, null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.IRON_ORE), null, null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.IRON_DUST, oreCrusher.isOreDoublingEnabled() ? 2 : 1)) .register(plugin); new SlimefunItem(itemGroups.resources, SlimefunItems.GOLD_DUST, RecipeType.ORE_CRUSHER, - new ItemStack[] {new ItemStack(Material.GOLD_ORE), null, null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.GOLD_ORE), null, null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.GOLD_DUST, oreCrusher.isOreDoublingEnabled() ? 2 : 1)) .register(plugin); @@ -571,7 +572,7 @@ public static void setup(@Nonnull Slimefun plugin) { new SlimefunItem(itemGroups.resources, SlimefunItems.SILVER_DUST, RecipeType.ORE_WASHER, new ItemStack[] {SlimefunItems.SIFTED_ORE, null, null, null, null, null, null, null, null}) .register(plugin); - + new SlimefunItem(itemGroups.resources, SlimefunItems.LEAD_DUST, RecipeType.ORE_WASHER, new ItemStack[] {SlimefunItems.SIFTED_ORE, null, null, null, null, null, null, null, null}) .register(plugin); @@ -693,12 +694,12 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new HologramProjector(itemGroups.technicalGadgets, SlimefunItems.HOLOGRAM_PROJECTOR, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, SlimefunItems.POWER_CRYSTAL, null, SlimefunItems.ALUMINUM_BRASS_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_BRASS_INGOT, null, SlimefunItems.ALUMINUM_BRASS_INGOT, null}, + new ItemStack[] {null, SlimefunItems.POWER_CRYSTAL, null, SlimefunItems.ALUMINUM_BRASS_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_BRASS_INGOT, null, SlimefunItems.ALUMINUM_BRASS_INGOT, null}, new SlimefunItemStack(SlimefunItems.HOLOGRAM_PROJECTOR, 3)) .register(plugin); new UnplaceableBlock(itemGroups.misc, SlimefunItems.CHAIN, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, null, SlimefunItems.STEEL_INGOT, null, SlimefunItems.STEEL_INGOT, null, SlimefunItems.STEEL_INGOT, null, null}, + new ItemStack[] {null, null, SlimefunItems.STEEL_INGOT, null, SlimefunItems.STEEL_INGOT, null, SlimefunItems.STEEL_INGOT, null, null}, new SlimefunItemStack(SlimefunItems.CHAIN, 8)) .register(plugin); @@ -723,11 +724,11 @@ public static void setup(@Nonnull Slimefun plugin) { new WaterStaff(itemGroups.magicalGadgets, SlimefunItems.STAFF_WATER, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {null, new ItemStack(Material.LILY_PAD), SlimefunItems.MAGIC_LUMP_2, null, SlimefunItems.STAFF_ELEMENTAL, new ItemStack(Material.LILY_PAD), SlimefunItems.STAFF_ELEMENTAL, null, null}) .register(plugin); - + new EnchantedItem(itemGroups.magicalGadgets, SlimefunItems.STAFF_FIRE, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {null, null, SlimefunItems.LAVA_CRYSTAL, null, SlimefunItems.STAFF_ELEMENTAL, null, SlimefunItems.STAFF_ELEMENTAL, null, null}) - .register(plugin); - + .register(plugin); + String[] multiToolItems = new String[] {"PORTABLE_CRAFTER", "MAGIC_EYE_OF_ENDER", "STAFF_ELEMENTAL_WIND", "GRAPPLING_HOOK"}; new MultiTool(itemGroups.technicalGadgets, SlimefunItems.DURALUMIN_MULTI_TOOL, RecipeType.ENHANCED_CRAFTING_TABLE, @@ -832,14 +833,18 @@ public static void setup(@Nonnull Slimefun plugin) { new UnplaceableBlock(itemGroups.magicalResources, SlimefunItems.LAVA_CRYSTAL, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.FIRE_RUNE, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.MAGIC_LUMP_1}) .register(plugin); - + new StormStaff(itemGroups.magicalGadgets, SlimefunItems.STAFF_STORM, RecipeType.ANCIENT_ALTAR, new ItemStack[] {SlimefunItems.LIGHTNING_RUNE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.LIGHTNING_RUNE, SlimefunItems.STAFF_WATER, SlimefunItems.MAGIC_SUGAR, SlimefunItems.STAFF_WIND, SlimefunItems.LIGHTNING_RUNE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.LIGHTNING_RUNE}) .register(plugin); ItemStack weaknessPotion = new ItemStack(Material.POTION); PotionMeta meta = (PotionMeta) weaknessPotion.getItemMeta(); - meta.setBasePotionData(new PotionData(PotionType.WEAKNESS, false, false)); + if (Slimefun.getMinecraftVersion().isBefore(20, 2)) { + meta.setBasePotionData(new PotionData(PotionType.WEAKNESS, false, false)); + } else { + meta.setBasePotionType(PotionType.WEAKNESS); + } weaknessPotion.setItemMeta(meta); new MagicalZombiePills(itemGroups.magicalGadgets, SlimefunItems.MAGICAL_ZOMBIE_PILLS, RecipeType.MAGIC_WORKBENCH, @@ -907,7 +912,7 @@ public static void setup(@Nonnull Slimefun plugin) { new Talisman(SlimefunItems.TALISMAN_WARRIOR, new ItemStack[] {SlimefunItems.MAGIC_LUMP_3, null, SlimefunItems.MAGIC_LUMP_3, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.COMMON_TALISMAN, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.MAGIC_LUMP_3, null, SlimefunItems.MAGIC_LUMP_3}, - true, true, "warrior", new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 3600, 2)) + true, true, "warrior", new PotionEffect(VersionedPotionEffectType.STRENGTH, 3600, 2)) .register(plugin); new Talisman(SlimefunItems.TALISMAN_KNIGHT, @@ -917,7 +922,7 @@ public static void setup(@Nonnull Slimefun plugin) { new Talisman(SlimefunItems.TALISMAN_CAVEMAN, new ItemStack[] { SlimefunItems.MAGIC_LUMP_3, null, SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.GOLDEN_PICKAXE), SlimefunItems.TALISMAN_MINER, SlimefunItems.EARTH_RUNE, SlimefunItems.MAGIC_LUMP_3, null, SlimefunItems.MAGIC_LUMP_3}, - false, false, "caveman", 50, new PotionEffect(PotionEffectType.FAST_DIGGING, 800, 2)) + false, false, "caveman", 50, new PotionEffect(VersionedPotionEffectType.HASTE, 800, 2)) .register(plugin); new Talisman(SlimefunItems.TALISMAN_WISE, @@ -946,7 +951,7 @@ public static void setup(@Nonnull Slimefun plugin) { new ItemStack[] {SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3, SlimefunItems.MAGIC_EYE_OF_ENDER, SlimefunItems.TALISMAN_MAGICIAN, SlimefunItems.MAGIC_EYE_OF_ENDER, SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3}, false, false, "wizard", 60) .register(plugin); - + new LumberAxe(itemGroups.tools, SlimefunItems.LUMBER_AXE, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {SlimefunItems.SYNTHETIC_DIAMOND, SlimefunItems.SYNTHETIC_DIAMOND, null, SlimefunItems.SYNTHETIC_EMERALD, SlimefunItems.GILDED_IRON, null, null, SlimefunItems.GILDED_IRON, null}) .register(plugin); @@ -956,7 +961,7 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new HeavyCream(itemGroups.misc, SlimefunItems.HEAVY_CREAM, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.MILK_BUCKET), null, null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.MILK_BUCKET), null, null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.HEAVY_CREAM, 2)) .register(plugin); @@ -971,7 +976,7 @@ public static void setup(@Nonnull Slimefun plugin) { registerArmorSet(itemGroups.armor, SlimefunItems.GILDED_IRON, new ItemStack[] { SlimefunItems.GILDED_IRON_HELMET, SlimefunItems.GILDED_IRON_CHESTPLATE, SlimefunItems.GILDED_IRON_LEGGINGS, SlimefunItems.GILDED_IRON_BOOTS }, "GILDED_IRON", false, new PotionEffect[0][0], plugin); - + new SlimefunItem(itemGroups.technicalComponents, SlimefunItems.REINFORCED_CLOTH, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.CLOTH, null, SlimefunItems.CLOTH, SlimefunItems.LEAD_INGOT, SlimefunItems.CLOTH, null, SlimefunItems.CLOTH, null}, new SlimefunItemStack(SlimefunItems.REINFORCED_CLOTH, 2)) .register(plugin); @@ -1027,7 +1032,7 @@ public static void setup(@Nonnull Slimefun plugin) { }, "GOLD_12K", false, new PotionEffect[0][0], plugin); new SlimefunItem(itemGroups.misc, SlimefunItems.CLOTH, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.WHITE_WOOL), null, null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.WHITE_WOOL), null, null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CLOTH, 8)) .register(plugin); @@ -1037,17 +1042,17 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new Bandage(itemGroups.usefulItems, SlimefunItems.BANDAGE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.RAG, new ItemStack(Material.STRING), SlimefunItems.RAG, null, null, null, null, null, null}, + new ItemStack[] {SlimefunItems.RAG, new ItemStack(Material.STRING), SlimefunItems.RAG, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.BANDAGE, 4), 1) .register(plugin); new Splint(itemGroups.usefulItems, SlimefunItems.SPLINT, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.STICK), new ItemStack(Material.STICK), new ItemStack(Material.STICK), null, new ItemStack(Material.IRON_INGOT), null}, + new ItemStack[] {null, new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.STICK), new ItemStack(Material.STICK), new ItemStack(Material.STICK), null, new ItemStack(Material.IRON_INGOT), null}, new SlimefunItemStack(SlimefunItems.SPLINT, 4)) .register(plugin); new UnplaceableBlock(itemGroups.misc, SlimefunItems.TIN_CAN, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, null, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT}, + new ItemStack[] {SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, null, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT, SlimefunItems.TIN_INGOT}, new SlimefunItemStack(SlimefunItems.TIN_CAN, 8)) .register(plugin); @@ -1067,7 +1072,7 @@ public static void setup(@Nonnull Slimefun plugin) { new PickaxeOfContainment(itemGroups.tools, SlimefunItems.PICKAXE_OF_CONTAINMENT, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {SlimefunItems.FERROSILICON, SlimefunItems.FERROSILICON, SlimefunItems.FERROSILICON, null, SlimefunItems.GILDED_IRON, null, null, SlimefunItems.GILDED_IRON, null}) .register(plugin); - + new TableSaw(itemGroups.basicMachines, SlimefunItems.TABLE_SAW).register(plugin); new SlimefunArmorPiece(itemGroups.magicalArmor, SlimefunItems.SLIME_HELMET_STEEL, RecipeType.ARMOR_FORGE, @@ -1085,7 +1090,7 @@ public static void setup(@Nonnull Slimefun plugin) { new LongFallBoots(itemGroups.magicalArmor, SlimefunItems.SLIME_BOOTS_STEEL, RecipeType.ARMOR_FORGE, new ItemStack[] {null, null, null, new ItemStack(Material.SLIME_BALL), null, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), SlimefunItems.STEEL_PLATE, new ItemStack(Material.SLIME_BALL)}, - new PotionEffect[] {new PotionEffect(PotionEffectType.JUMP, 300, 5)}, + new PotionEffect[] {new PotionEffect(VersionedPotionEffectType.JUMP_BOOST, 300, 5)}, SoundEffect.SLIME_BOOTS_FALL_SOUND) .register(plugin); @@ -1104,7 +1109,7 @@ public static void setup(@Nonnull Slimefun plugin) { new FarmerShoes(itemGroups.magicalArmor, SlimefunItems.FARMER_SHOES, RecipeType.ARMOR_FORGE, new ItemStack[] {null, null, null, new ItemStack(Material.HAY_BLOCK), null, new ItemStack(Material.HAY_BLOCK), new ItemStack(Material.HAY_BLOCK), null, new ItemStack(Material.HAY_BLOCK)}) .register(plugin); - + new ExplosivePickaxe(itemGroups.tools, SlimefunItems.EXPLOSIVE_PICKAXE, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {new ItemStack(Material.TNT), SlimefunItems.SYNTHETIC_DIAMOND, new ItemStack(Material.TNT), null, SlimefunItems.FERROSILICON, null, null, SlimefunItems.FERROSILICON, null}) .register(plugin); @@ -1114,7 +1119,7 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new AutomatedPanningMachine(itemGroups.basicMachines, SlimefunItems.AUTOMATED_PANNING_MACHINE).register(plugin); - + new IndustrialMiner(itemGroups.basicMachines, SlimefunItems.INDUSTRIAL_MINER, Material.IRON_BLOCK, false, 3).register(plugin); new AdvancedIndustrialMiner(itemGroups.basicMachines, SlimefunItems.ADVANCED_INDUSTRIAL_MINER).register(plugin); @@ -1232,7 +1237,7 @@ public static void setup(@Nonnull Slimefun plugin) { new PickaxeOfVeinMining(itemGroups.tools, SlimefunItems.PICKAXE_OF_VEIN_MINING, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {new ItemStack(Material.EMERALD_ORE), SlimefunItems.SYNTHETIC_DIAMOND, new ItemStack(Material.EMERALD_ORE), null, SlimefunItems.GILDED_IRON, null, null, SlimefunItems.GILDED_IRON, null}) .register(plugin); - + new ClimbingPick(itemGroups.tools, SlimefunItems.CLIMBING_PICK, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.STEEL_INGOT, SlimefunItems.HARDENED_METAL_INGOT, SlimefunItems.STEEL_INGOT, null, new ItemStack(Material.STICK), null, null, new ItemStack(Material.STICK), null}) .register(plugin); @@ -1240,7 +1245,7 @@ public static void setup(@Nonnull Slimefun plugin) { new SoulboundItem(itemGroups.weapons, SlimefunItems.SOULBOUND_SWORD, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {null, SlimefunItems.ESSENCE_OF_AFTERLIFE, null, null, new ItemStack(Material.DIAMOND_SWORD), null, null, SlimefunItems.ESSENCE_OF_AFTERLIFE, null}) .register(plugin); - + new SoulboundItem(itemGroups.weapons, SlimefunItems.SOULBOUND_TRIDENT, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {null, SlimefunItems.ESSENCE_OF_AFTERLIFE, null, null, new ItemStack(Material.TRIDENT), null, null, SlimefunItems.ESSENCE_OF_AFTERLIFE, null}) .register(plugin); @@ -1384,10 +1389,10 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new UnplaceableBlock(itemGroups.technicalComponents, SlimefunItems.COPPER_WIRE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, null, null, SlimefunItems.COPPER_INGOT, SlimefunItems.COPPER_INGOT, SlimefunItems.COPPER_INGOT, null, null, null}, + new ItemStack[] {null, null, null, SlimefunItems.COPPER_INGOT, SlimefunItems.COPPER_INGOT, SlimefunItems.COPPER_INGOT, null, null, null}, new SlimefunItemStack(SlimefunItems.COPPER_WIRE, 8)) .register(plugin); - + new BlockPlacer(itemGroups.basicMachines, SlimefunItems.BLOCK_PLACER, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.GOLD_4K, new ItemStack(Material.PISTON), SlimefunItems.GOLD_4K, new ItemStack(Material.IRON_INGOT), SlimefunItems.ELECTRIC_MOTOR, new ItemStack(Material.IRON_INGOT), SlimefunItems.GOLD_4K, new ItemStack(Material.PISTON), SlimefunItems.GOLD_4K}) .register(plugin); @@ -1409,7 +1414,7 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new KnowledgeFlask(itemGroups.magicalGadgets, SlimefunItems.FLASK_OF_KNOWLEDGE, RecipeType.MAGIC_WORKBENCH, - new ItemStack[] {null, null, null, SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.GLASS_PANE), SlimefunItems.MAGIC_LUMP_2, null, SlimefunItems.MAGIC_LUMP_2, null}, + new ItemStack[] {null, null, null, SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.GLASS_PANE), SlimefunItems.MAGIC_LUMP_2, null, SlimefunItems.MAGIC_LUMP_2, null}, new SlimefunItemStack(SlimefunItems.FLASK_OF_KNOWLEDGE, 8)) .register(plugin); @@ -1422,37 +1427,37 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new Juice(itemGroups.christmas, SlimefunItems.CHRISTMAS_MILK, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.MILK_BUCKET), new ItemStack(Material.GLASS_BOTTLE), null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.MILK_BUCKET), new ItemStack(Material.GLASS_BOTTLE), null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_MILK, 4)) .register(plugin); new Juice(itemGroups.christmas, SlimefunItems.CHRISTMAS_CHOCOLATE_MILK, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.CHRISTMAS_MILK, new ItemStack(Material.COCOA_BEANS), null, null, null, null, null, null, null}, + new ItemStack[] {SlimefunItems.CHRISTMAS_MILK, new ItemStack(Material.COCOA_BEANS), null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_CHOCOLATE_MILK, 2)) .register(plugin); new Juice(itemGroups.christmas, SlimefunItems.CHRISTMAS_EGG_NOG, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.CHRISTMAS_MILK, new ItemStack(Material.EGG), null, null, null, null, null, null, null}, + new ItemStack[] {SlimefunItems.CHRISTMAS_MILK, new ItemStack(Material.EGG), null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_EGG_NOG, 2)) .register(plugin); new Juice(itemGroups.christmas, SlimefunItems.CHRISTMAS_APPLE_CIDER, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.APPLE_JUICE, new ItemStack(Material.SUGAR), null, null, null, null, null, null, null}, + new ItemStack[] {SlimefunItems.APPLE_JUICE, new ItemStack(Material.SUGAR), null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_APPLE_CIDER, 2)) .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_COOKIE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.COOKIE), new ItemStack(Material.SUGAR), new ItemStack(Material.LIME_DYE), null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.COOKIE), new ItemStack(Material.SUGAR), new ItemStack(Material.LIME_DYE), null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_COOKIE, 16)) .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_FRUIT_CAKE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.EGG), new ItemStack(Material.APPLE), new ItemStack(Material.MELON), new ItemStack(Material.SUGAR), null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.EGG), new ItemStack(Material.APPLE), new ItemStack(Material.MELON), new ItemStack(Material.SUGAR), null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_FRUIT_CAKE, 4)) .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_APPLE_PIE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.APPLE), new ItemStack(Material.EGG), null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.APPLE), new ItemStack(Material.EGG), null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_APPLE_PIE, 2)) .register(plugin); @@ -1461,22 +1466,22 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_CAKE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.EGG), new ItemStack(Material.SUGAR), SlimefunItems.WHEAT_FLOUR, new ItemStack(Material.MILK_BUCKET), null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.EGG), new ItemStack(Material.SUGAR), SlimefunItems.WHEAT_FLOUR, new ItemStack(Material.MILK_BUCKET), null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_CAKE, 4)) .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_CARAMEL, RecipeType.SMELTERY, - new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.SUGAR), null, null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.SUGAR), null, null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_CARAMEL, 4)) .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_CARAMEL_APPLE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, SlimefunItems.CHRISTMAS_CARAMEL, null, null, new ItemStack(Material.APPLE), null, null, new ItemStack(Material.STICK), null}, + new ItemStack[] {null, SlimefunItems.CHRISTMAS_CARAMEL, null, null, new ItemStack(Material.APPLE), null, null, new ItemStack(Material.STICK), null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_CARAMEL_APPLE, 2)) .register(plugin); new SlimefunItem(itemGroups.christmas, SlimefunItems.CHRISTMAS_CHOCOLATE_APPLE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, new ItemStack(Material.COCOA_BEANS), null, null, new ItemStack(Material.APPLE), null, null, new ItemStack(Material.STICK), null}, + new ItemStack[] {null, new ItemStack(Material.COCOA_BEANS), null, null, new ItemStack(Material.APPLE), null, null, new ItemStack(Material.STICK), null}, new SlimefunItemStack(SlimefunItems.CHRISTMAS_CHOCOLATE_APPLE, 2)) .register(plugin); @@ -1497,17 +1502,17 @@ public static void setup(@Nonnull Slimefun plugin) { ).register(plugin); new SlimefunItem(itemGroups.easter, SlimefunItems.EASTER_CARROT_PIE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.CARROT), new ItemStack(Material.EGG), null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.CARROT), new ItemStack(Material.EGG), null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.EASTER_CARROT_PIE, 2)) .register(plugin); new SlimefunItem(itemGroups.easter, SlimefunItems.EASTER_APPLE_PIE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.APPLE), new ItemStack(Material.EGG), null, null, null, null, null, null}, + new ItemStack[] {new ItemStack(Material.SUGAR), new ItemStack(Material.APPLE), new ItemStack(Material.EGG), null, null, null, null, null, null}, new SlimefunItemStack(SlimefunItems.EASTER_APPLE_PIE, 2)) .register(plugin); new EasterEgg(itemGroups.easter, SlimefunItems.EASTER_EGG, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, null, null, new ItemStack(Material.LIME_DYE), new ItemStack(Material.EGG), new ItemStack(Material.PURPLE_DYE), null, null, null}, + new ItemStack[] {null, null, null, new ItemStack(Material.LIME_DYE), new ItemStack(Material.EGG), new ItemStack(Material.PURPLE_DYE), null, null, null}, new SlimefunItemStack(SlimefunItems.EASTER_EGG, 2), // Gifts: new SlimefunItemStack(SlimefunItems.EASTER_CARROT_PIE, 4), @@ -1543,7 +1548,7 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new AncientPedestal(itemGroups.magicalGadgets, SlimefunItems.ANCIENT_PEDESTAL, RecipeType.MAGIC_WORKBENCH, - new ItemStack[] {new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN), null, new ItemStack(Material.STONE), null, new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN)}, + new ItemStack[] {new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN), null, new ItemStack(Material.STONE), null, new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN)}, new SlimefunItemStack(SlimefunItems.ANCIENT_PEDESTAL, 4)) .register(plugin); @@ -1561,7 +1566,7 @@ public static void setup(@Nonnull Slimefun plugin) { .register(plugin); new SlimefunItem(itemGroups.misc, SlimefunItems.DUCT_TAPE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.ALUMINUM_DUST, SlimefunItems.ALUMINUM_DUST, SlimefunItems.ALUMINUM_DUST, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.SLIME_BALL), new ItemStack(Material.PAPER), new ItemStack(Material.PAPER), new ItemStack(Material.PAPER)}, + new ItemStack[] {SlimefunItems.ALUMINUM_DUST, SlimefunItems.ALUMINUM_DUST, SlimefunItems.ALUMINUM_DUST, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.SLIME_BALL), new ItemStack(Material.PAPER), new ItemStack(Material.PAPER), new ItemStack(Material.PAPER)}, new SlimefunItemStack(SlimefunItems.DUCT_TAPE, 2)) .register(plugin); @@ -1604,7 +1609,7 @@ public static void setup(@Nonnull Slimefun plugin) { new SolarGenerator(itemGroups.electricity, 128, 64, SlimefunItems.SOLAR_GENERATOR_4, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.SOLAR_GENERATOR_3, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.SOLAR_GENERATOR_3, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.SOLAR_GENERATOR_3, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.SOLAR_GENERATOR_3}) .register(plugin); - + new ChargingBench(itemGroups.electricity, SlimefunItems.CHARGING_BENCH, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.ELECTRO_MAGNET, null, SlimefunItems.BATTERY, new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.BATTERY, null, SlimefunItems.SMALL_CAPACITOR, null}) .setCapacity(128) @@ -1804,11 +1809,11 @@ public static void setup(@Nonnull Slimefun plugin) { .setEnergyConsumption(20) .setProcessingSpeed(3) .register(plugin); - + new SlimefunItem(itemGroups.resources, SlimefunItems.MAGNESIUM_SALT, RecipeType.HEATED_PRESSURE_CHAMBER, new ItemStack[] {SlimefunItems.MAGNESIUM_DUST, SlimefunItems.SALT, null, null, null, null, null, null, null}) .register(plugin); - + new MagnesiumGenerator(itemGroups.electricity, SlimefunItems.MAGNESIUM_GENERATOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.ELECTRIC_MOTOR, null, SlimefunItems.COMPRESSED_CARBON, new ItemStack(Material.WATER_BUCKET), SlimefunItems.COMPRESSED_CARBON, SlimefunItems.DURALUMIN_INGOT, SlimefunItems.DURALUMIN_INGOT, SlimefunItems.DURALUMIN_INGOT}) .setCapacity(128) @@ -1879,7 +1884,7 @@ public static void setup(@Nonnull Slimefun plugin) { new GPSTransmitter(itemGroups.gps, 1, SlimefunItems.GPS_TRANSMITTER, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, null, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.STEEL_INGOT, SlimefunItems.ADVANCED_CIRCUIT_BOARD, SlimefunItems.STEEL_INGOT, SlimefunItems.STEEL_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.STEEL_INGOT}) { - + @Override public int getMultiplier(int y) { return y; @@ -1894,7 +1899,7 @@ public int getEnergyConsumption() { new GPSTransmitter(itemGroups.gps, 2, SlimefunItems.GPS_TRANSMITTER_2, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.GPS_TRANSMITTER, SlimefunItems.BRONZE_INGOT, SlimefunItems.GPS_TRANSMITTER, SlimefunItems.BRONZE_INGOT, SlimefunItems.CARBON, SlimefunItems.BRONZE_INGOT, SlimefunItems.GPS_TRANSMITTER, SlimefunItems.BRONZE_INGOT, SlimefunItems.GPS_TRANSMITTER}) { - + @Override public int getMultiplier(int y) { return y * 4 + 100; @@ -1909,7 +1914,7 @@ public int getEnergyConsumption() { new GPSTransmitter(itemGroups.gps, 3, SlimefunItems.GPS_TRANSMITTER_3, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.GPS_TRANSMITTER_2, SlimefunItems.CORINTHIAN_BRONZE_INGOT, SlimefunItems.GPS_TRANSMITTER_2, SlimefunItems.CORINTHIAN_BRONZE_INGOT, SlimefunItems.CARBONADO, SlimefunItems.CORINTHIAN_BRONZE_INGOT, SlimefunItems.GPS_TRANSMITTER_2, SlimefunItems.CORINTHIAN_BRONZE_INGOT, SlimefunItems.GPS_TRANSMITTER_2}) { - + @Override public int getMultiplier(int y) { return y * 16 + 500; @@ -1924,7 +1929,7 @@ public int getEnergyConsumption() { new GPSTransmitter(itemGroups.gps, 4, SlimefunItems.GPS_TRANSMITTER_4, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.GPS_TRANSMITTER_3, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.GPS_TRANSMITTER_3, SlimefunItems.NICKEL_INGOT, SlimefunItems.CARBONADO, SlimefunItems.NICKEL_INGOT, SlimefunItems.GPS_TRANSMITTER_3, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.GPS_TRANSMITTER_3}) { - + @Override public int getMultiplier(int y) { return y * 64 + 2100; @@ -1934,7 +1939,7 @@ public int getMultiplier(int y) { public int getEnergyConsumption() { return 43; } - + }.register(plugin); new GPSControlPanel(itemGroups.gps, SlimefunItems.GPS_CONTROL_PANEL, RecipeType.ENHANCED_CRAFTING_TABLE, @@ -2014,32 +2019,32 @@ public int getEnergyConsumption() { .register(plugin); new ElementalRune(itemGroups.magicalResources, SlimefunItems.AIR_RUNE, - new ItemStack[] {new ItemStack(Material.FEATHER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.FEATHER), new ItemStack(Material.GHAST_TEAR), SlimefunItems.BLANK_RUNE, new ItemStack(Material.GHAST_TEAR), new ItemStack(Material.FEATHER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.FEATHER)}, + new ItemStack[] {new ItemStack(Material.FEATHER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.FEATHER), new ItemStack(Material.GHAST_TEAR), SlimefunItems.BLANK_RUNE, new ItemStack(Material.GHAST_TEAR), new ItemStack(Material.FEATHER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.FEATHER)}, new SlimefunItemStack(SlimefunItems.AIR_RUNE, 4)) .register(plugin); new ElementalRune(itemGroups.magicalResources, SlimefunItems.EARTH_RUNE, - new ItemStack[] {new ItemStack(Material.DIRT), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.STONE), new ItemStack(Material.OBSIDIAN), SlimefunItems.BLANK_RUNE, new ItemStack(Material.OBSIDIAN), new ItemStack(Material.STONE), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.DIRT)}, + new ItemStack[] {new ItemStack(Material.DIRT), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.STONE), new ItemStack(Material.OBSIDIAN), SlimefunItems.BLANK_RUNE, new ItemStack(Material.OBSIDIAN), new ItemStack(Material.STONE), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.DIRT)}, new SlimefunItemStack(SlimefunItems.EARTH_RUNE, 4)) .register(plugin); new ElementalRune(itemGroups.magicalResources, SlimefunItems.FIRE_RUNE, - new ItemStack[] {new ItemStack(Material.FIRE_CHARGE), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.FIRE_CHARGE), new ItemStack(Material.BLAZE_POWDER), SlimefunItems.EARTH_RUNE, new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.FIRE_CHARGE), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.FIRE_CHARGE)}, + new ItemStack[] {new ItemStack(Material.FIRE_CHARGE), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.FIRE_CHARGE), new ItemStack(Material.BLAZE_POWDER), SlimefunItems.EARTH_RUNE, new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.FIRE_CHARGE), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.FIRE_CHARGE)}, new SlimefunItemStack(SlimefunItems.FIRE_RUNE, 4)) .register(plugin); new ElementalRune(itemGroups.magicalResources, SlimefunItems.WATER_RUNE, - new ItemStack[] {new ItemStack(Material.SALMON), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.WATER_BUCKET), new ItemStack(Material.SAND), SlimefunItems.BLANK_RUNE, new ItemStack(Material.SAND), new ItemStack(Material.WATER_BUCKET), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.COD)}, + new ItemStack[] {new ItemStack(Material.SALMON), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.WATER_BUCKET), new ItemStack(Material.SAND), SlimefunItems.BLANK_RUNE, new ItemStack(Material.SAND), new ItemStack(Material.WATER_BUCKET), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.COD)}, new SlimefunItemStack(SlimefunItems.WATER_RUNE, 4)) .register(plugin); new ElementalRune(itemGroups.magicalResources, SlimefunItems.ENDER_RUNE, - new ItemStack[] {new ItemStack(Material.ENDER_PEARL), SlimefunItems.ENDER_LUMP_3, new ItemStack(Material.ENDER_PEARL), new ItemStack(Material.ENDER_EYE), SlimefunItems.BLANK_RUNE, new ItemStack(Material.ENDER_EYE), new ItemStack(Material.ENDER_PEARL), SlimefunItems.ENDER_LUMP_3, new ItemStack(Material.ENDER_PEARL)}, + new ItemStack[] {new ItemStack(Material.ENDER_PEARL), SlimefunItems.ENDER_LUMP_3, new ItemStack(Material.ENDER_PEARL), new ItemStack(Material.ENDER_EYE), SlimefunItems.BLANK_RUNE, new ItemStack(Material.ENDER_EYE), new ItemStack(Material.ENDER_PEARL), SlimefunItems.ENDER_LUMP_3, new ItemStack(Material.ENDER_PEARL)}, new SlimefunItemStack(SlimefunItems.ENDER_RUNE, 6)) .register(plugin); new ElementalRune(itemGroups.magicalResources, SlimefunItems.LIGHTNING_RUNE, - new ItemStack[] {new ItemStack(Material.IRON_INGOT), SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.IRON_INGOT), SlimefunItems.AIR_RUNE, new ItemStack(Material.PHANTOM_MEMBRANE), SlimefunItems.WATER_RUNE, new ItemStack(Material.IRON_INGOT), SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.IRON_INGOT)}, + new ItemStack[] {new ItemStack(Material.IRON_INGOT), SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.IRON_INGOT), SlimefunItems.AIR_RUNE, new ItemStack(Material.PHANTOM_MEMBRANE), SlimefunItems.WATER_RUNE, new ItemStack(Material.IRON_INGOT), SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.IRON_INGOT)}, new SlimefunItemStack(SlimefunItems.LIGHTNING_RUNE, 4)) .register(plugin); @@ -2056,7 +2061,7 @@ public int getEnergyConsumption() { .register(plugin); new InfernalBonemeal(itemGroups.magicalGadgets, SlimefunItems.INFERNAL_BONEMEAL, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.NETHER_WART), SlimefunItems.EARTH_RUNE, new ItemStack(Material.NETHER_WART), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.BONE_MEAL), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.NETHER_WART), new ItemStack(Material.BLAZE_POWDER), new ItemStack(Material.NETHER_WART)}, + new ItemStack[] {new ItemStack(Material.NETHER_WART), SlimefunItems.EARTH_RUNE, new ItemStack(Material.NETHER_WART), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.BONE_MEAL), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.NETHER_WART), new ItemStack(Material.BLAZE_POWDER), new ItemStack(Material.NETHER_WART)}, new SlimefunItemStack(SlimefunItems.INFERNAL_BONEMEAL, 8)) .register(plugin); @@ -2085,133 +2090,133 @@ public int getEnergyConsumption() { .register(plugin); new RainbowBlock(itemGroups.magicalGadgets, SlimefunItems.RAINBOW_WOOL, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL)}, + new ItemStack[] {new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.WHITE_WOOL)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL, 8), new RainbowTickHandler(ColoredMaterial.WOOL)) .register(plugin); new RainbowBlock(itemGroups.magicalGadgets, SlimefunItems.RAINBOW_GLASS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS)}, + new ItemStack[] {new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.WHITE_STAINED_GLASS)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS, 8), new RainbowTickHandler(ColoredMaterial.STAINED_GLASS)) .register(plugin); new RainbowBlock(itemGroups.magicalGadgets, SlimefunItems.RAINBOW_GLASS_PANE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE)}, + new ItemStack[] {new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE, 8), new RainbowTickHandler(ColoredMaterial.STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(itemGroups.magicalGadgets, SlimefunItems.RAINBOW_CLAY, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA)}, + new ItemStack[] {new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.WHITE_TERRACOTTA)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY, 8), new RainbowTickHandler(ColoredMaterial.TERRACOTTA)) .register(plugin); new RainbowBlock(itemGroups.magicalGadgets, SlimefunItems.RAINBOW_CONCRETE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE)}, + new ItemStack[] {new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.WHITE_CONCRETE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE, 8), new RainbowTickHandler(ColoredMaterial.CONCRETE)) .register(plugin); - + new RainbowBlock(itemGroups.magicalGadgets, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA)}, + new ItemStack[] {new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA, 8), new RainbowTickHandler(ColoredMaterial.GLAZED_TERRACOTTA)) .register(plugin); // Christmas new RainbowBlock(itemGroups.christmas, SlimefunItems.RAINBOW_WOOL_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL_XMAS, 2), new RainbowTickHandler(Material.RED_WOOL, Material.GREEN_WOOL)) .register(plugin); new RainbowBlock(itemGroups.christmas, SlimefunItems.RAINBOW_GLASS_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_XMAS, 2), new RainbowTickHandler(Material.RED_STAINED_GLASS, Material.GREEN_STAINED_GLASS)) .register(plugin); new RainbowBlock(itemGroups.christmas, SlimefunItems.RAINBOW_GLASS_PANE_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE_XMAS, 2), new RainbowTickHandler(Material.RED_STAINED_GLASS_PANE, Material.GREEN_STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(itemGroups.christmas, SlimefunItems.RAINBOW_CLAY_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY_XMAS, 2), new RainbowTickHandler(Material.RED_TERRACOTTA, Material.GREEN_TERRACOTTA)) .register(plugin); new RainbowBlock(itemGroups.christmas, SlimefunItems.RAINBOW_CONCRETE_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE_XMAS, 2), new RainbowTickHandler(Material.RED_CONCRETE, Material.GREEN_CONCRETE)) .register(plugin); - + new RainbowBlock(itemGroups.christmas, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_XMAS, 2), new RainbowTickHandler(Material.RED_GLAZED_TERRACOTTA, Material.GREEN_GLAZED_TERRACOTTA)) .register(plugin); - + // Valentines Day new RainbowBlock(itemGroups.valentinesDay, SlimefunItems.RAINBOW_WOOL_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_WOOL, Material.PINK_WOOL)) .register(plugin); new RainbowBlock(itemGroups.valentinesDay, SlimefunItems.RAINBOW_GLASS_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_STAINED_GLASS, Material.PINK_STAINED_GLASS)) .register(plugin); new RainbowBlock(itemGroups.valentinesDay, SlimefunItems.RAINBOW_GLASS_PANE_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_STAINED_GLASS_PANE, Material.PINK_STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(itemGroups.valentinesDay, SlimefunItems.RAINBOW_CLAY_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_TERRACOTTA, Material.PINK_TERRACOTTA)) .register(plugin); - + new RainbowBlock(itemGroups.valentinesDay, SlimefunItems.RAINBOW_CONCRETE_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_CONCRETE, Material.PINK_CONCRETE)) .register(plugin); - + new RainbowBlock(itemGroups.valentinesDay, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_GLAZED_TERRACOTTA, Material.PINK_GLAZED_TERRACOTTA)) .register(plugin); // Halloween - + new RainbowBlock(itemGroups.halloween, SlimefunItems.RAINBOW_WOOL_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_WOOL, Material.BLACK_WOOL)) .register(plugin); new RainbowBlock(itemGroups.halloween, SlimefunItems.RAINBOW_GLASS_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_STAINED_GLASS, Material.BLACK_STAINED_GLASS)) .register(plugin); new RainbowBlock(itemGroups.halloween, SlimefunItems.RAINBOW_GLASS_PANE_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_STAINED_GLASS_PANE, Material.BLACK_STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(itemGroups.halloween, SlimefunItems.RAINBOW_CLAY_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_TERRACOTTA, Material.BLACK_TERRACOTTA)) .register(plugin); - + new RainbowBlock(itemGroups.halloween, SlimefunItems.RAINBOW_CONCRETE_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_CONCRETE, Material.BLACK_CONCRETE)) .register(plugin); - + new RainbowBlock(itemGroups.halloween, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_GLAZED_TERRACOTTA, Material.BLACK_GLAZED_TERRACOTTA)) .register(plugin); new WitherProofBlock(itemGroups.technicalComponents, SlimefunItems.WITHER_PROOF_GLASS, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.LEAD_INGOT, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.LEAD_INGOT, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.HARDENED_GLASS, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.LEAD_INGOT, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.LEAD_INGOT}, + new ItemStack[] {SlimefunItems.LEAD_INGOT, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.LEAD_INGOT, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.HARDENED_GLASS, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.LEAD_INGOT, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.LEAD_INGOT}, new SlimefunItemStack(SlimefunItems.WITHER_PROOF_GLASS, 4)) .register(plugin); @@ -2275,7 +2280,7 @@ public int getEnergyConsumption() { .register(plugin); new TeleporterPylon(itemGroups.gps, SlimefunItems.GPS_TELEPORTER_PYLON, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.ZINC_INGOT, new ItemStack(Material.GLASS), SlimefunItems.ZINC_INGOT, new ItemStack(Material.GLASS), SlimefunItems.HEATING_COIL, new ItemStack(Material.GLASS), SlimefunItems.ZINC_INGOT, new ItemStack(Material.GLASS), SlimefunItems.ZINC_INGOT}, + new ItemStack[] {SlimefunItems.ZINC_INGOT, new ItemStack(Material.GLASS), SlimefunItems.ZINC_INGOT, new ItemStack(Material.GLASS), SlimefunItems.HEATING_COIL, new ItemStack(Material.GLASS), SlimefunItems.ZINC_INGOT, new ItemStack(Material.GLASS), SlimefunItems.ZINC_INGOT}, new SlimefunItemStack(SlimefunItems.GPS_TELEPORTER_PYLON, 8)) .register(plugin); @@ -2379,9 +2384,11 @@ public int getEnergyConsumption() { new TreeGrowthAccelerator(itemGroups.electricity, SlimefunItems.TREE_GROWTH_ACCELERATOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.CARBONADO, null, SlimefunItems.ELECTRIC_MOTOR, new ItemStack(Material.DIAMOND_AXE), SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.MAGNESIUM_SALT, SlimefunItems.BIG_CAPACITOR, SlimefunItems.MAGNESIUM_SALT}) .register(plugin); - + new ExpCollector(itemGroups.electricity, SlimefunItems.EXP_COLLECTOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.BLISTERING_INGOT_3, null, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.AUTO_ENCHANTER, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ALUMINUM_BRONZE_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_BRONZE_INGOT}) + .setEnergyConsumption(10) + .setCapacity(1024) .register(plugin); new FoodComposter(itemGroups.electricity, SlimefunItems.FOOD_COMPOSTER, RecipeType.ENHANCED_CRAFTING_TABLE, @@ -2515,7 +2522,7 @@ public int getSpeed() { new NuclearReactor(itemGroups.electricity, SlimefunItems.NUCLEAR_REACTOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.CARBONADO_EDGED_CAPACITOR, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.REINFORCED_PLATE, SlimefunItems.COOLING_UNIT, SlimefunItems.REINFORCED_PLATE, SlimefunItems.LEAD_INGOT, SlimefunItems.REINFORCED_PLATE, SlimefunItems.LEAD_INGOT}){ - + @Override public int getEnergyProduction() { return 250; @@ -2525,7 +2532,7 @@ public int getEnergyProduction() { public int getCapacity() { return 16384; } - + }.register(plugin); new NetherStarReactor(itemGroups.electricity, SlimefunItems.NETHER_STAR_REACTOR, RecipeType.ENHANCED_CRAFTING_TABLE, @@ -2544,7 +2551,7 @@ public int getCapacity() { }.register(plugin); new UnplaceableBlock(itemGroups.cargo, SlimefunItems.CARGO_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS, SlimefunItems.SILVER_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.SILVER_INGOT, SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS}, + new ItemStack[] {SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS, SlimefunItems.SILVER_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.SILVER_INGOT, SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS}, new SlimefunItemStack(SlimefunItems.CARGO_MOTOR, 4)) .register(plugin); @@ -2553,17 +2560,17 @@ public int getCapacity() { .register(plugin); new CargoConnectorNode(itemGroups.cargo, SlimefunItems.CARGO_CONNECTOR_NODE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.BRONZE_INGOT, SlimefunItems.SILVER_INGOT, SlimefunItems.BRONZE_INGOT, SlimefunItems.SILVER_INGOT, SlimefunItems.CARGO_MOTOR, SlimefunItems.SILVER_INGOT, SlimefunItems.BRONZE_INGOT, SlimefunItems.SILVER_INGOT, SlimefunItems.BRONZE_INGOT}, + new ItemStack[] {SlimefunItems.BRONZE_INGOT, SlimefunItems.SILVER_INGOT, SlimefunItems.BRONZE_INGOT, SlimefunItems.SILVER_INGOT, SlimefunItems.CARGO_MOTOR, SlimefunItems.SILVER_INGOT, SlimefunItems.BRONZE_INGOT, SlimefunItems.SILVER_INGOT, SlimefunItems.BRONZE_INGOT}, new SlimefunItemStack(SlimefunItems.CARGO_CONNECTOR_NODE, 4)) .register(plugin); new CargoInputNode(itemGroups.cargo, SlimefunItems.CARGO_INPUT_NODE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, new ItemStack(Material.HOPPER), null, SlimefunItems.BILLON_INGOT, SlimefunItems.CARGO_CONNECTOR_NODE, SlimefunItems.BILLON_INGOT, null, new ItemStack(Material.HOPPER), null}, + new ItemStack[] {null, new ItemStack(Material.HOPPER), null, SlimefunItems.BILLON_INGOT, SlimefunItems.CARGO_CONNECTOR_NODE, SlimefunItems.BILLON_INGOT, null, new ItemStack(Material.HOPPER), null}, new SlimefunItemStack(SlimefunItems.CARGO_INPUT_NODE, 2)) .register(plugin); new CargoOutputNode(itemGroups.cargo, SlimefunItems.CARGO_OUTPUT_NODE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {null, new ItemStack(Material.HOPPER), null, SlimefunItems.BRASS_INGOT, SlimefunItems.CARGO_CONNECTOR_NODE, SlimefunItems.BRASS_INGOT, null, new ItemStack(Material.HOPPER), null}, + new ItemStack[] {null, new ItemStack(Material.HOPPER), null, SlimefunItems.BRASS_INGOT, SlimefunItems.CARGO_CONNECTOR_NODE, SlimefunItems.BRASS_INGOT, null, new ItemStack(Material.HOPPER), null}, new SlimefunItemStack(SlimefunItems.CARGO_OUTPUT_NODE, 2)) .register(plugin); @@ -2625,11 +2632,11 @@ public int getCapacity() { new WitherAssembler(itemGroups.electricity, SlimefunItems.WITHER_ASSEMBLER, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.BLISTERING_INGOT_3, new ItemStack(Material.NETHER_STAR), SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ANDROID_MEMORY_CORE, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.CARBONADO_EDGED_CAPACITOR}) .register(plugin); - + new TapeMeasure(itemGroups.usefulItems, SlimefunItems.TAPE_MEASURE, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), new ItemStack(Material.STRING), new ItemStack(Material.YELLOW_DYE), SlimefunItems.GILDED_IRON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON}) .register(plugin); - + MinecraftVersion minecraftVersion = Slimefun.getMinecraftVersion(); new SlimefunItem(itemGroups.magicalArmor, SlimefunItems.BEE_HELMET, RecipeType.ARMOR_FORGE, @@ -2646,7 +2653,7 @@ public int getCapacity() { new LongFallBoots(itemGroups.magicalArmor, SlimefunItems.BEE_BOOTS, RecipeType.ARMOR_FORGE, new ItemStack[] {null, null, null, SlimefunItems.GOLD_8K, null, SlimefunItems.GOLD_8K, new ItemStack(Material.HONEY_BLOCK), null, new ItemStack(Material.HONEY_BLOCK)}, - new PotionEffect[] {new PotionEffect(PotionEffectType.JUMP, 300, 2)}, + new PotionEffect[] {new PotionEffect(VersionedPotionEffectType.JUMP_BOOST, 300, 2)}, SoundEffect.BEE_BOOTS_FALL_SOUND) .register(plugin); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java index b32e719efc..be256b0031 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java @@ -14,7 +14,6 @@ import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Particle; import org.bukkit.SoundCategory; import org.bukkit.block.Block; import org.bukkit.entity.Item; @@ -28,6 +27,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal; import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle; /** * The {@link AncientAltarTask} is responsible for the animation that happens when a ritual @@ -117,12 +117,12 @@ private boolean checkLockedItems() { } private void idle() { - dropLocation.getWorld().spawnParticle(Particle.SPELL_WITCH, dropLocation, 16, 1.2F, 0F, 1.2F); - dropLocation.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, dropLocation, 8, 0.2F, 0F, 0.2F); + dropLocation.getWorld().spawnParticle(VersionedParticle.WITCH, dropLocation, 16, 1.2F, 0F, 1.2F); + dropLocation.getWorld().spawnParticle(VersionedParticle.FIREWORK, dropLocation, 8, 0.2F, 0F, 0.2F); for (Location loc : particleLocations) { - dropLocation.getWorld().spawnParticle(Particle.ENCHANTMENT_TABLE, loc, 16, 0.3F, 0.2F, 0.3F); - dropLocation.getWorld().spawnParticle(Particle.CRIT_MAGIC, loc, 8, 0.3F, 0.2F, 0.3F); + dropLocation.getWorld().spawnParticle(VersionedParticle.ENCHANT, loc, 16, 0.3F, 0.2F, 0.3F); + dropLocation.getWorld().spawnParticle(VersionedParticle.ENCHANTED_HIT, loc, 8, 0.3F, 0.2F, 0.3F); } } @@ -137,8 +137,8 @@ private void checkPedestal(@Nonnull Block pedestal) { items.add(pedestalItem.getOriginalItemStack(entity)); SoundEffect.ANCIENT_ALTAR_ITEM_CHECK_SOUND.playAt(pedestal); - dropLocation.getWorld().spawnParticle(Particle.ENCHANTMENT_TABLE, pedestal.getLocation().add(0.5, 1.5, 0.5), 16, 0.3F, 0.2F, 0.3F); - dropLocation.getWorld().spawnParticle(Particle.CRIT_MAGIC, pedestal.getLocation().add(0.5, 1.5, 0.5), 8, 0.3F, 0.2F, 0.3F); + dropLocation.getWorld().spawnParticle(VersionedParticle.ENCHANT, pedestal.getLocation().add(0.5, 1.5, 0.5), 16, 0.3F, 0.2F, 0.3F); + dropLocation.getWorld().spawnParticle(VersionedParticle.ENCHANTED_HIT, pedestal.getLocation().add(0.5, 1.5, 0.5), 8, 0.3F, 0.2F, 0.3F); positionLock.remove(entity); entity.remove(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java index 32141cb010..051f931460 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java @@ -24,10 +24,9 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.ProtectionType; import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.SolarHelmet; -import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedPotionEffectType; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; /** @@ -55,10 +54,10 @@ public ArmorTask(boolean radioactiveFire) { Set effects = new HashSet<>(); effects.add(new PotionEffect(PotionEffectType.WITHER, 400, 2)); effects.add(new PotionEffect(PotionEffectType.BLINDNESS, 400, 3)); - effects.add(new PotionEffect(PotionEffectType.CONFUSION, 400, 3)); + effects.add(new PotionEffect(VersionedPotionEffectType.NAUSEA, 400, 3)); effects.add(new PotionEffect(PotionEffectType.WEAKNESS, 400, 2)); - effects.add(new PotionEffect(PotionEffectType.SLOW, 400, 1)); - effects.add(new PotionEffect(PotionEffectType.SLOW_DIGGING, 400, 1)); + effects.add(new PotionEffect(VersionedPotionEffectType.SLOWNESS, 400, 1)); + effects.add(new PotionEffect(VersionedPotionEffectType.MINING_FATIGUE, 400, 1)); radiationEffects = Collections.unmodifiableSet(effects); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java index cbf6e42eb1..91525994fb 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java @@ -44,6 +44,7 @@ public class TickerTask implements Runnable { /** * This Map holds all currently actively ticking locations. + * The value of this map (Set entries) MUST be thread-safe and mutable. */ private final Map> tickingLocations = new ConcurrentHashMap<>(); @@ -329,7 +330,7 @@ public Map> getLocations() { public Set getLocations(@Nonnull Chunk chunk) { Validate.notNull(chunk, "The Chunk cannot be null!"); - Set locations = tickingLocations.getOrDefault(new ChunkPosition(chunk), new HashSet<>()); + Set locations = tickingLocations.getOrDefault(new ChunkPosition(chunk), Collections.emptySet()); return Collections.unmodifiableSet(locations); } @@ -343,7 +344,14 @@ public void enableTicker(@Nonnull Location l) { Validate.notNull(l, "Location cannot be null!"); ChunkPosition chunk = new ChunkPosition(l.getWorld(), l.getBlockX() >> 4, l.getBlockZ() >> 4); - Set newValue = new HashSet<>(); + + /* + Note that all the values in #tickingLocations must be thread-safe. + Thus, the choice is between the CHM KeySet or a synchronized set. + The CHM KeySet was chosen since it at least permits multiple concurrent + reads without blocking. + */ + Set newValue = ConcurrentHashMap.newKeySet(); Set oldValue = tickingLocations.putIfAbsent(chunk, newValue); /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java index 29ac850805..85e4c4bfe8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java @@ -1,31 +1,30 @@ package io.github.thebusybiscuit.slimefun4.implementation.tasks.armor; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import javax.annotation.Nonnull; -import javax.annotation.ParametersAreNonnullByDefault; - -import org.bukkit.GameMode; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - import io.github.bakedlibs.dough.common.ChatColors; +import io.github.thebusybiscuit.slimefun4.api.events.RadiationDamageEvent; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.attributes.ProtectionType; import io.github.thebusybiscuit.slimefun4.core.attributes.RadiationSymptom; import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive; -import io.github.thebusybiscuit.slimefun4.implementation.listeners.RadioactivityListener; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; -import io.github.thebusybiscuit.slimefun4.implementation.items.RadioactiveItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.RadioactivityListener; import io.github.thebusybiscuit.slimefun4.utils.RadiationUtils; - import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ComponentBuilder; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * The {@link RadiationTask} handles radioactivity for * {@link Radioactive} items. @@ -48,13 +47,15 @@ protected void onPlayerTick(Player p, PlayerProfile profile) { } int exposureTotal = 0; - if (!profile.hasFullProtectionAgainst(ProtectionType.RADIATION) && p.getGameMode() != GameMode.CREATIVE && p.getGameMode() != GameMode.SPECTATOR) { + if (!profile.hasFullProtectionAgainst(ProtectionType.RADIATION) + && p.getGameMode() != GameMode.CREATIVE + && p.getGameMode() != GameMode.SPECTATOR) { for (ItemStack item : p.getInventory()) { if (item == null || item.getType().isAir()) { continue; } SlimefunItem sfItem = SlimefunItem.getByItem(item); - if (sfItem instanceof RadioactiveItem radioactiveItem) { + if (sfItem instanceof Radioactive radioactiveItem) { exposureTotal += item.getAmount() * radioactiveItem.getRadioactivity().getExposureModifier(); } } @@ -72,7 +73,14 @@ protected void onPlayerTick(Player p, PlayerProfile profile) { int exposureLevelAfter = RadiationUtils.getExposure(p); - Slimefun.runSync(() -> { + Slimefun.runSync(() -> { + RadiationDamageEvent event = new RadiationDamageEvent(p, exposureLevelAfter); + Bukkit.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + for (RadiationSymptom symptom : symptoms) { if (symptom.shouldApply(exposureLevelAfter)) { symptom.apply(p); @@ -81,8 +89,11 @@ protected void onPlayerTick(Player p, PlayerProfile profile) { }); if (exposureLevelAfter > 0 || exposureLevelBefore > 0) { - String msg = Slimefun.getLocalization().getMessage(p, "actionbar.radiation").replace("%level%", "" + exposureLevelAfter); - BaseComponent[] components = new ComponentBuilder().append(ChatColors.color(msg)).create(); + String msg = Slimefun.getLocalization() + .getMessage(p, "actionbar.radiation") + .replace("%level%", "" + exposureLevelAfter); + BaseComponent[] components = + new ComponentBuilder().append(ChatColors.color(msg)).create(); p.spigot().sendMessage(ChatMessageType.ACTION_BAR, components); } } else { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java b/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java index d7981a5466..f051a3b846 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/storage/backend/legacy/LegacyStorage.java @@ -27,6 +27,8 @@ public class LegacyStorage implements Storage { @Override public PlayerData loadPlayerData(@Nonnull UUID uuid) { + long start = System.nanoTime(); + Config playerFile = new Config("data-storage/Slimefun/Players/" + uuid + ".yml"); // Not too sure why this is its own file Config waypointsFile = new Config("data-storage/Slimefun/waypoints/" + uuid + ".yml"); @@ -73,12 +75,17 @@ public PlayerData loadPlayerData(@Nonnull UUID uuid) { } } + long end = System.nanoTime(); + Slimefun.getAnalyticsService().recordPlayerProfileDataTime("legacy", true, end - start); + return new PlayerData(researches, backpacks, waypoints); } // The current design of saving all at once isn't great, this will be refined. @Override public void savePlayerData(@Nonnull UUID uuid, @Nonnull PlayerData data) { + long start = System.nanoTime(); + Config playerFile = new Config("data-storage/Slimefun/Players/" + uuid + ".yml"); // Not too sure why this is its own file Config waypointsFile = new Config("data-storage/Slimefun/waypoints/" + uuid + ".yml"); @@ -91,7 +98,17 @@ public void savePlayerData(@Nonnull UUID uuid, @Nonnull PlayerData data) { playerFile.setValue("researches." + research.getID(), true); // Remove the research if it's no longer researched - } else if (playerFile.contains("researches." + research.getID())) { + // ---- + // We have a duplicate ID (173) used for both Coal Gen and Bio Reactor + // If you researched the Goal Gen we would remove it on save if you didn't also have the Bio Reactor + // Due to the fact we would set it as researched (true in the branch above) on Coal Gen + // but then go into this branch and remove it if you didn't have Bio Reactor + // Sooooo we're gonna hack this for now while we move away from the Legacy Storage + // Let's make sure the user doesn't have _any_ research with this ID and _then_ remove it + } else if ( + playerFile.contains("researches." + research.getID()) + && !data.getResearches().stream().anyMatch((r) -> r.getID() == research.getID()) + ) { playerFile.setValue("researches." + research.getID(), null); } } @@ -123,5 +140,8 @@ public void savePlayerData(@Nonnull UUID uuid, @Nonnull PlayerData data) { // Save files playerFile.save(); waypointsFile.save(); + + long end = System.nanoTime(); + Slimefun.getAnalyticsService().recordPlayerProfileDataTime("legacy", false, end - start); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java index 3df992835b..928233eb5d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java @@ -5,9 +5,11 @@ import javax.annotation.Nonnull; +import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; @@ -43,6 +45,19 @@ private ChestMenuUtils() {} private static final ItemStack PREV_BUTTON_INACTIVE = new SlimefunItemStack("_UI_PREVIOUS_INACTIVE", Material.BLACK_STAINED_GLASS_PANE, "&8\u21E6 Previous Page"); private static final ItemStack NEXT_BUTTON_INACTIVE = new SlimefunItemStack("_UI_NEXT_INACTIVE", Material.BLACK_STAINED_GLASS_PANE, "&8Next Page \u21E8"); + private static final ChestMenu.AdvancedMenuClickHandler OUTPUT_HANDLER = new ChestMenu.AdvancedMenuClickHandler() { + + @Override + public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { + return false; + } + + @Override + public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { + return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; + } + }; + private static final MenuClickHandler CLICK_HANDLER = (p, s, i, a) -> false; public static @Nonnull ItemStack getBackground() { @@ -69,6 +84,10 @@ private ChestMenuUtils() {} return CLICK_HANDLER; } + public static @Nonnull ChestMenu.AdvancedMenuClickHandler getDefaultOutputHandler() { + return OUTPUT_HANDLER; + } + public static @Nonnull ItemStack getBackButton(@Nonnull Player p, String... lore) { return new CustomItemStack(BACK_BUTTON, "&7\u21E6 " + Slimefun.getLocalization().getMessage(p, "guide.back.title"), lore); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/FireworkUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/FireworkUtils.java index 808c5364ce..e09851349d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/FireworkUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/FireworkUtils.java @@ -15,6 +15,8 @@ import org.bukkit.entity.Firework; import org.bukkit.inventory.meta.FireworkMeta; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEntityType; + /** * This is a simple utility class for spawning random and colorful {@link Firework} rockets. * @@ -31,6 +33,8 @@ public final class FireworkUtils { Color.RED, Color.SILVER, Color.TEAL, Color.WHITE, Color.YELLOW }; // @formatter:on + + private static final EntityType firework = VersionedEntityType.FIREWORK; private FireworkUtils() {} @@ -39,7 +43,7 @@ public static void launchFirework(@Nonnull Location l, @Nonnull Color color) { } public static @Nonnull Firework createFirework(@Nonnull Location l, @Nonnull Color color) { - Firework fw = (Firework) l.getWorld().spawnEntity(l, EntityType.FIREWORK); + Firework fw = (Firework) l.getWorld().spawnEntity(l, firework); FireworkMeta meta = fw.getFireworkMeta(); meta.setDisplayName(ChatColor.GREEN + "Slimefun Research"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java index 5fc3bda47f..a509b207f3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java @@ -485,11 +485,24 @@ private static boolean equalsItemMeta(@Nonnull ItemMeta itemMeta, @Nonnull ItemM return false; } - if (itemMeta instanceof PotionMeta && sfitemMeta instanceof PotionMeta) { - return ((PotionMeta) itemMeta).getBasePotionData().equals(((PotionMeta) sfitemMeta).getBasePotionData()); + if (!(itemMeta instanceof PotionMeta potionMeta) || !(sfitemMeta instanceof PotionMeta sfPotionMeta)) { + return true; } - - return true; + MinecraftVersion current = Slimefun.getMinecraftVersion(); + + if (current.isBefore(20, 2)) { + // getBasePotionData pre 1.20.2 + return potionMeta.getBasePotionData().equals(sfPotionMeta.getBasePotionData()); + } else if (current.isBefore(20, 5)) { + // getBasePotionType without null check for 1.20.3 and 1.20.4 + return potionMeta.getBasePotionType() == sfPotionMeta.getBasePotionType(); + } + // check if potionMetha has a basePotionType (acting a null check for getBasePotionType + // on 1.20.5+ + if (potionMeta.hasBasePotionType() != sfPotionMeta.hasBasePotionType()) { + return false; + } + return potionMeta.getBasePotionType() == sfPotionMeta.getBasePotionType(); } /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedEnchantment.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedEnchantment.java new file mode 100644 index 0000000000..d5063ce413 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedEnchantment.java @@ -0,0 +1,48 @@ +package io.github.thebusybiscuit.slimefun4.utils.compatibility; + +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.enchantments.Enchantment; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java?until=2a6207fe150b6165722fce94c83cc1f206620ab5&untilPath=src%2Fmain%2Fjava%2Forg%2Fbukkit%2Fcraftbukkit%2Flegacy%2FFieldRename.java#86-110 +public class VersionedEnchantment { + + public static final Enchantment EFFICIENCY; + public static final Enchantment UNBREAKING; + public static final Enchantment PROTECTION; + public static final Enchantment SHARPNESS; + public static final Enchantment LUCK_OF_THE_SEA; + public static final Enchantment AQUA_AFFINITY; + public static final Enchantment FORTUNE; + + static { + // DIG_SPEED is renamed to EFFICIENCY in 1.20.5 + EFFICIENCY = getKey("efficiency"); + + // DURABILITY is renamed to UNBREAKING in 1.20.5 + UNBREAKING = getKey("unbreaking"); + + // PROTECTION_ENVIRONMENTAL is renamed to PROTECTION in 1.20.5 + PROTECTION = getKey("protection"); + + // DAMAGE_ALL is renamed to SHARPNESS in 1.20.5 + SHARPNESS = getKey("sharpness"); + + // LUCK is renamed to LUCK_OF_THE_SEA in 1.20.5 + LUCK_OF_THE_SEA = getKey("luck_of_the_sea"); + + // WATER_WORKER is renamed to AQUA_AFFINITY in 1.20.5 + AQUA_AFFINITY = getKey("aqua_affinity"); + + // LOOT_BONUS_BLOCKS is renamed to FORTUNE in 1.20.5 + FORTUNE = getKey("fortune"); + } + + @Nullable + private static Enchantment getKey(@Nonnull String key) { + return Registry.ENCHANTMENT.get(NamespacedKey.minecraft(key)); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedEntityType.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedEntityType.java new file mode 100644 index 0000000000..10ae11e803 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedEntityType.java @@ -0,0 +1,31 @@ +package io.github.thebusybiscuit.slimefun4.utils.compatibility; + +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.entity.EntityType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java?until=2a6207fe150b6165722fce94c83cc1f206620ab5&untilPath=src%2Fmain%2Fjava%2Forg%2Fbukkit%2Fcraftbukkit%2Flegacy%2FFieldRename.java#158-193 +public class VersionedEntityType { + + public static final EntityType MOOSHROOM; + public static final EntityType SNOW_GOLEM; + public static final EntityType FIREWORK; + + static { + // MUSHROOM_COW is renamed to MOOSHROOM in 1.20.5 + MOOSHROOM = getKey("mooshroom"); + + // SNOWMAN is renamed to SNOW_GOLEM in 1.20.5 + SNOW_GOLEM = getKey("snow_golem"); + + FIREWORK = getKey("firework_rocket"); + } + + @Nullable + private static EntityType getKey(@Nonnull String key) { + return Registry.ENTITY_TYPE.get(NamespacedKey.minecraft(key)); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedItemFlag.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedItemFlag.java new file mode 100644 index 0000000000..507a903a23 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedItemFlag.java @@ -0,0 +1,34 @@ +package io.github.thebusybiscuit.slimefun4.utils.compatibility; + +import java.lang.reflect.Field; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bukkit.inventory.ItemFlag; + +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +public class VersionedItemFlag { + + public static final ItemFlag HIDE_ADDITIONAL_TOOLTIP; + + static { + MinecraftVersion version = Slimefun.getMinecraftVersion(); + + HIDE_ADDITIONAL_TOOLTIP = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? ItemFlag.HIDE_ADDITIONAL_TOOLTIP + : getKey("HIDE_POTION_EFFECTS"); + } + + @Nullable + private static ItemFlag getKey(@Nonnull String key) { + try { + Field field = ItemFlag.class.getDeclaredField(key); + return (ItemFlag) field.get(null); + } catch(Exception e) { + return null; + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedParticle.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedParticle.java new file mode 100644 index 0000000000..fafd340cc0 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedParticle.java @@ -0,0 +1,78 @@ +package io.github.thebusybiscuit.slimefun4.utils.compatibility; + +import java.lang.reflect.Field; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bukkit.Particle; + +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java?until=2a6207fe150b6165722fce94c83cc1f206620ab5&untilPath=src%2Fmain%2Fjava%2Forg%2Fbukkit%2Fcraftbukkit%2Flegacy%2FFieldRename.java#281-318 +public class VersionedParticle { + + public static final Particle DUST; + public static final Particle SMOKE; + public static final Particle HAPPY_VILLAGER; + public static final Particle ENCHANTED_HIT; + public static final Particle EXPLOSION; + public static final Particle WITCH; + public static final Particle FIREWORK; + public static final Particle ENCHANT; + + static { + MinecraftVersion version = Slimefun.getMinecraftVersion(); + + // REDSTONE is renamed to DUST in 1.20.5 + DUST = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.DUST + : getKey("REDSTONE"); + + // SMOKE_NORMAL is renamed to SMOKE in 1.20.5 + SMOKE = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.SMOKE + : getKey("SMOKE_NORMAL"); + + // VILLAGER_HAPPY is renamed to HAPPY_VILLAGER in 1.20.5 + HAPPY_VILLAGER = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.HAPPY_VILLAGER + : getKey("VILLAGER_HAPPY"); + + // CRIT_MAGIC is renamed to ENCHANTED_HIT in 1.20.5 + ENCHANTED_HIT = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.ENCHANTED_HIT + : getKey("CRIT_MAGIC"); + + // EXPLOSION_LARGE is renamed to EXPLOSION in 1.20.5 + EXPLOSION = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.EXPLOSION + : getKey("EXPLOSION_LARGE"); + + // SPELL_WITCH is renamed to WITCH in 1.20.5 + WITCH = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.WITCH + : getKey("SPELL_WITCH"); + + // FIREWORKS_SPARK is renamed to FIREWORK in 1.20.5 + FIREWORK = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.FIREWORK + : getKey("FIREWORKS_SPARK"); + + // ENCHANTMENT_TABLE is renamed to ENCHANT in 1.20.5 + ENCHANT = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? Particle.ENCHANT + : getKey("ENCHANTMENT_TABLE"); + } + + @Nullable + private static Particle getKey(@Nonnull String key) { + try { + Field field = Particle.class.getDeclaredField(key); + return (Particle) field.get(null); + } catch(Exception e) { + return null; + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedPotionEffectType.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedPotionEffectType.java new file mode 100644 index 0000000000..f3dbe6b6d1 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedPotionEffectType.java @@ -0,0 +1,75 @@ +package io.github.thebusybiscuit.slimefun4.utils.compatibility; + +import java.lang.reflect.Field; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bukkit.potion.PotionEffectType; + +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java?until=2a6207fe150b6165722fce94c83cc1f206620ab5&untilPath=src%2Fmain%2Fjava%2Forg%2Fbukkit%2Fcraftbukkit%2Flegacy%2FFieldRename.java#216-228 +public class VersionedPotionEffectType { + + public static final PotionEffectType SLOWNESS; + public static final PotionEffectType HASTE; + public static final PotionEffectType MINING_FATIGUE; + public static final PotionEffectType STRENGTH; + public static final PotionEffectType INSTANT_HEALTH; + public static final PotionEffectType INSTANT_DAMAGE; + public static final PotionEffectType JUMP_BOOST; + public static final PotionEffectType NAUSEA; + public static final PotionEffectType RESISTANCE; + + static { + MinecraftVersion version = Slimefun.getMinecraftVersion(); + + SLOWNESS = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.SLOWNESS + : getKey("SLOW"); + + HASTE = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.HASTE + : getKey("FAST_DIGGING"); + + MINING_FATIGUE = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.MINING_FATIGUE + : getKey("SLOW_DIGGING"); + + STRENGTH = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.STRENGTH + : getKey("INCREASE_DAMAGE"); + + INSTANT_HEALTH = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.INSTANT_HEALTH + : getKey("HEAL"); + + INSTANT_DAMAGE = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.INSTANT_DAMAGE + : getKey("HARM"); + + JUMP_BOOST = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.JUMP_BOOST + : getKey("JUMP"); + + NAUSEA = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.NAUSEA + : getKey("CONFUSION"); + + RESISTANCE = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionEffectType.RESISTANCE + : getKey("DAMAGE_RESISTANCE"); + } + + @Nullable + private static PotionEffectType getKey(@Nonnull String key) { + try { + Field field = PotionEffectType.class.getDeclaredField(key); + return (PotionEffectType) field.get(null); + } catch(Exception e) { + return null; + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedPotionType.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedPotionType.java new file mode 100644 index 0000000000..1713d77baf --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/compatibility/VersionedPotionType.java @@ -0,0 +1,55 @@ +package io.github.thebusybiscuit.slimefun4.utils.compatibility; + +import java.lang.reflect.Field; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bukkit.potion.PotionType; + +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +// https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java?until=2a6207fe150b6165722fce94c83cc1f206620ab5&untilPath=src%2Fmain%2Fjava%2Forg%2Fbukkit%2Fcraftbukkit%2Flegacy%2FFieldRename.java#242-250 +public class VersionedPotionType { + + public static final PotionType LEAPING; + public static final PotionType SWIFTNESS; + public static final PotionType HEALING; + public static final PotionType HARMING; + public static final PotionType REGENERATION; + + static { + MinecraftVersion version = Slimefun.getMinecraftVersion(); + + LEAPING = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionType.LEAPING + : getKey("JUMP"); + + SWIFTNESS = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionType.SWIFTNESS + : getKey("SPEED"); + + HEALING = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionType.HEALING + : getKey("INSTANT_HEAL"); + + HARMING = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionType.HARMING + : getKey("INSTANT_DAMAGE"); + + REGENERATION = version.isAtLeast(MinecraftVersion.MINECRAFT_1_20_5) + ? PotionType.REGENERATION + : getKey("REGEN"); + } + + @Nullable + private static PotionType getKey(@Nonnull String key) { + try { + Field field = PotionType.class.getDeclaredField(key); + return (PotionType) field.get(null); + } catch(Exception e) { + return null; + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ColoredFireworkStar.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ColoredFireworkStar.java index 17a62c352f..063d91f8d1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ColoredFireworkStar.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ColoredFireworkStar.java @@ -9,12 +9,12 @@ import org.bukkit.FireworkEffect; import org.bukkit.FireworkEffect.Type; import org.bukkit.Material; -import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.FireworkEffectMeta; import io.github.bakedlibs.dough.common.ChatColors; import io.github.bakedlibs.dough.items.CustomItemStack; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedItemFlag; /** * This simple {@link ItemStack} implementation allows us to obtain @@ -44,7 +44,7 @@ public ColoredFireworkStar(Color color, String name, String... lore) { im.setLore(lines); } - im.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); + im.addItemFlags(VersionedItemFlag.HIDE_ADDITIONAL_TOOLTIP); }); } diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/Configuration/Config.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/Configuration/Config.java index 7784370617..7cceeb6a08 100644 --- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/Configuration/Config.java +++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/Configuration/Config.java @@ -13,10 +13,8 @@ * An old remnant of CS-CoreLib. * This will be removed once we updated everything. * Don't look at the code, it will be gone soon, don't worry. - * - * @deprecated Only used by the legacy {@link BlockStorage} system. + * Only used by the legacy {@link BlockStorage} system. */ -@Deprecated public class Config { private final File file; diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java index 1d047d0615..d13234063c 100644 --- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java +++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java @@ -16,9 +16,7 @@ * An old remnant of CS-CoreLib. * This will be removed once we updated everything. * Don't look at the code, it will be gone soon, don't worry. - * */ -@Deprecated public class ChestMenu { private boolean clickable; @@ -207,7 +205,6 @@ public ChestMenu addMenuCloseHandler(MenuCloseHandler handler) { * * @return The ChestMenu Instance */ - @Deprecated public ChestMenu build() { return this; } diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ClickAction.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ClickAction.java index 2592862ff2..4ad692a6e1 100644 --- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ClickAction.java +++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ClickAction.java @@ -4,9 +4,7 @@ * An old remnant of CS-CoreLib. * This will be removed once we updated everything. * Don't look at the code, it will be gone soon, don't worry. - * */ -@Deprecated public class ClickAction { private boolean right; diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/MenuListener.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/MenuListener.java index 3483e5a6e8..1647e5aeee 100644 --- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/MenuListener.java +++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/MenuListener.java @@ -17,12 +17,9 @@ /** * An old {@link Listener} for CS-CoreLib - * - * @deprecated This is an old remnant of CS-CoreLib, the last bits of the past. They will be removed once everything is + * This is an old remnant of CS-CoreLib, the last bits of the past. They will be removed once everything is * updated. - * */ -@Deprecated public class MenuListener implements Listener { static final Map menus = new HashMap<>(); diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/package-info.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/package-info.java index ca990142b2..4a7b23e254 100644 --- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/package-info.java +++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/package-info.java @@ -1,5 +1,4 @@ /** * Old CS-CoreLib 1.X code. */ -@java.lang.Deprecated package me.mrCookieSlime.CSCoreLibPlugin; \ No newline at end of file diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java index be71fbe598..04747b4f84 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java @@ -12,8 +12,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -37,8 +35,6 @@ import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -115,18 +111,7 @@ protected void constructMenu(BlockMenuPreset preset) { preset.addItem(22, new CustomItemStack(Material.BLACK_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); for (int i : getOutputSlots()) { - preset.addMenuClickHandler(i, new AdvancedMenuClickHandler() { - - @Override - public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { - return false; - } - - @Override - public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { - return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; - } - }); + preset.addMenuClickHandler(i, ChestMenuUtils.getDefaultOutputHandler()); } } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java index 0bc27e5d17..db5555f6c9 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java @@ -12,7 +12,6 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import io.github.bakedlibs.dough.items.CustomItemStack; @@ -35,8 +34,6 @@ import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; @@ -122,18 +119,7 @@ private void constructMenu(BlockMenuPreset preset) { } for (int i : getOutputSlots()) { - preset.addMenuClickHandler(i, new AdvancedMenuClickHandler() { - - @Override - public boolean onClick(Player p, int slot, ItemStack cursor, ClickAction action) { - return false; - } - - @Override - public boolean onClick(InventoryClickEvent e, Player p, int slot, ItemStack cursor, ClickAction action) { - return cursor == null || cursor.getType() == null || cursor.getType() == Material.AIR; - } - }); + preset.addMenuClickHandler(i, ChestMenuUtils.getDefaultOutputHandler()); } preset.addItem(22, new CustomItemStack(Material.BLACK_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); @@ -282,7 +268,7 @@ public void register(@Nonnull SlimefunAddon addon) { if (getCapacity() < 0) { warn("The capacity has not been configured correctly. The Item was disabled."); - warn("Make sure to call '" + getClass().getSimpleName() + "#setEnergyCapacity(...)' before registering!"); + warn("Make sure to call '" + getClass().getSimpleName() + "#setCapacity(...)' before registering!"); } if (getEnergyProduction() <= 0) { diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockInfoConfig.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockInfoConfig.java index c2f5a821eb..448f0fbcfe 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockInfoConfig.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockInfoConfig.java @@ -118,4 +118,4 @@ public String toJSON() { return new GsonBuilder().create().toJson(data); } -} \ No newline at end of file +} diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java index c2df4fd2c9..78c9cc90a7 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java @@ -35,6 +35,7 @@ import com.google.gson.JsonParser; import com.google.gson.stream.JsonWriter; +import io.github.bakedlibs.dough.blocks.BlockPosition; import io.github.bakedlibs.dough.common.CommonPatterns; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; @@ -201,7 +202,7 @@ private void loadBlock(File file, FileConfiguration cfg, String key) { * error to the console (if enabled). */ if (Slimefun.getRegistry().logDuplicateBlockEntries()) { - Slimefun.logger().log(Level.INFO, "Ignoring duplicate block @ {0}, {1}, {2} ({3} -> {4})", new Object[] { l.getBlockX(), l.getBlockY(), l.getBlockZ(), blockInfo.getString("id"), storage.get(l).getString("id") }); + Slimefun.logger().log(Level.INFO, "Ignoring duplicate block @ %d, %d, %d (%s -> %s)".formatted(l.getBlockX(), l.getBlockY(), l.getBlockZ(), blockInfo.getString("id"), storage.get(l).getString("id"))); } return; @@ -513,10 +514,18 @@ public static String getLocationInfo(Location l, String key) { return getLocationInfo(l).getString(key); } + public static String getLocationInfo(BlockPosition l, String key) { + return getLocationInfo(l.toLocation()).getString(key); + } + public static void addBlockInfo(Location l, String key, String value) { addBlockInfo(l, key, value, false); } + public static void addBlockInfo(BlockPosition l, String key, String value) { + addBlockInfo(l.toLocation(), key, value, false); + } + public static void addBlockInfo(Block block, String key, String value) { addBlockInfo(block.getLocation(), key, value); } @@ -525,6 +534,10 @@ public static void addBlockInfo(Block block, String key, String value, boolean u addBlockInfo(block.getLocation(), key, value, updateTicker); } + public static void addBlockInfo(BlockPosition l, String key, String value, boolean updateTicker) { + addBlockInfo(l.toLocation(), key, value, updateTicker); + } + public static void addBlockInfo(Location l, String key, String value, boolean updateTicker) { Config cfg = getLocationInfo(l); diff --git a/src/main/java/me/mrCookieSlime/package-info.java b/src/main/java/me/mrCookieSlime/package-info.java index 2fc365aed1..d346250b2c 100644 --- a/src/main/java/me/mrCookieSlime/package-info.java +++ b/src/main/java/me/mrCookieSlime/package-info.java @@ -3,5 +3,4 @@ * Don't look too close at the code that lays here. It's horrible, believe me. * Once we updated everything, all of these classes will be removed. */ -@java.lang.Deprecated package me.mrCookieSlime; \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index cb133170e4..5e36b700b7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -50,6 +50,7 @@ talismans: metrics: auto-update: true + analytics: true research-ranks: - Chicken diff --git a/src/main/resources/languages/de/messages.yml b/src/main/resources/languages/de/messages.yml index 55f8ead5ae..5debea0c8e 100644 --- a/src/main/resources/languages/de/messages.yml +++ b/src/main/resources/languages/de/messages.yml @@ -148,6 +148,7 @@ messages: bee-suit-slow-fall: '&eDeine Bienenflügel haben dir eine sichere Landung ermöglicht' deprecated-item: '&4Dieses Item ist veraltet und wird bald aus Slimefun entfernt.' researching-is-disabled: '&cDas Freischalten von Items wurde auf diesem Server deaktiviert. Alles ist bereits automatisch freigeschaltet!' + await-deletion: '&cDu kannst keinen Slimefun Block so kurz nach dem Abbauen eines anderen platzieren. Versuche es in Kürze erneut.' multi-tool: mode-change: '&bDer Modus von deinem Multi-Tool wurde geändert zu: &9%mode%' not-shears: '&cEinMulti Tool kann nicht als Schere verwendet werden!' diff --git a/src/main/resources/languages/en/messages.yml b/src/main/resources/languages/en/messages.yml index 81d5115c30..77bd80895a 100644 --- a/src/main/resources/languages/en/messages.yml +++ b/src/main/resources/languages/en/messages.yml @@ -98,7 +98,28 @@ guide: name: '&aIs something missing?' lore: 'Click to add your own translation' + modes: + selected: 'Slimefun Guide Type: ' + change: 'Click to change the type' + SURVIVAL_MODE: 'Survival Mode' + CHEAT_MODE: 'Cheat Sheet' + options: + fireworks: + enabled: + text: + - '&bFireworks: &aYes' + - '' + - '&7You can now toggle whether you' + - '&7will see fireworks upon researching an item.' + click: '&eClick to disable your fireworks' + disabled: + text: + - '&bFireworks: &4No' + - '' + - '&7You can now toggle whether you' + - '&7will see fireworks upon researching an item.' + click: '&eClick to enable your fireworks' learning-animation: enabled: text: diff --git a/src/main/resources/languages/fa/messages.yml b/src/main/resources/languages/fa/messages.yml index 1daccfc6ff..eadfe05e13 100644 --- a/src/main/resources/languages/fa/messages.yml +++ b/src/main/resources/languages/fa/messages.yml @@ -109,7 +109,7 @@ android: editor: 'ویرایش برنامه' uploaded: - '&bدرحال آپلود...' - - '&aSuccessfully uploaded your script!' + - '&aآپلود اسکریپت کامل شد!' languages: default: 'پیشفرض سرور' en: 'انگلیسی' @@ -118,9 +118,11 @@ languages: it: 'ایتالیایی' es: 'اسپانیایی' pl: 'لهستانی' + sv: 'سوئدی' nl: 'هلندی' cs: 'کشور چک' hu: 'مجارستانی' + lv: 'لاتویایی' ru: 'روسی' zh-TW: 'چینی (تایوان)' vi: 'ویتنامی' diff --git a/src/main/resources/languages/he/messages.yml b/src/main/resources/languages/he/messages.yml index a6294cdf1e..00041a9ad0 100644 --- a/src/main/resources/languages/he/messages.yml +++ b/src/main/resources/languages/he/messages.yml @@ -124,6 +124,8 @@ guide: wiki: '&3ויקי עורך ' resourcepack: '&c אמן חבילת משאבים' translator: '&9מתרגם' +actionbar: + radiation: '&6רמת חשיפה לקרינה: &c%level%&7/&e100' messages: not-researched: '&4אין לך מספיק ידע להבין זאת. &c אתה צריך לשחרר את &f"%item%&f"' not-enough-xp: "&4אין לך מספיק נקודות ניסיון\nכדי לפתוח את זה " diff --git a/src/main/resources/languages/hu/messages.yml b/src/main/resources/languages/hu/messages.yml index 4f99929461..9f135acb48 100644 --- a/src/main/resources/languages/hu/messages.yml +++ b/src/main/resources/languages/hu/messages.yml @@ -124,6 +124,8 @@ guide: wiki: '&3Wiki szerkesztő' resourcepack: '&cForráscsomag művész' translator: '&9Fordító' +actionbar: + radiation: '&6Sugárterhelési szint: &c%level%&7/&e100' messages: not-researched: '&4Nincs elég tudásod, hogy megértsd ezt.&cFel kel még oldanod ezt a tárgyat: &f"%item%&f"' not-enough-xp: '&4Nincs elég XP-d ennek a feloldásához' @@ -147,6 +149,8 @@ messages: piglin-barter: '&4Slimefun tárgyakat nem cserélhetsz el a piglinekkel.' bee-suit-slow-fall: '&eA Bee Wings segít neked visszatérni a földre lassan és biztonságosan' deprecated-item: '&4Ez a tárgy elavult, és hamarosan eltávolítjuk a Slimefunból.' + researching-is-disabled: '&cA kutatás le van tiltva ezen a szerveren. Alapértelmezés szerint minden fel van oldva!' + await-deletion: '&cNem tehetsz le egy Slimefun blockot ilyen gyorsan egy másik kiütése után. Próbáld újra később.' multi-tool: mode-change: '&b%device% mód átállítva: &9%mode%' not-shears: '&cA Multi Tool nem használható óllóként!' @@ -257,6 +261,9 @@ machines: pick-a-floor: '&3- Válassz emeletet -' current-floor: '&eEzen az emeleten tartózkodsz:' click-to-teleport: '&eKattints&7, hogy erre az emeletre teleportálj:' + enter-name: '&7Kérlek írd be a kívánt emelet nevét a Chatre. &f(Színkódok is használhatóak!)' + named: '&2Sikeresen elnevezted ezt az emeletet: &f%floor%' + editor-title: 'Lift konfigurálása' TELEPORTER: teleporting: '&3Teleportálás...' teleported: '&3Teleportálva!' @@ -272,6 +279,8 @@ machines: waypoints: 'Útpont áttekintése' CARGO_NODES: must-be-placed: '&4Ládára vagy gépre kell helyezni!' + connected: '&2Csatlakoztatva!' + not-connected: '&4Nincs csatlakoztatva!' INDUSTRIAL_MINER: no-fuel: '&cAz Industrial Miner-ednek elfogyott az üzemanyaga! Tedd az üzemanyagot a felette lévő ládába.' piston-facing: '&cAz Industrial Miner-edhez szükségesek dugattyúk, amik felfelé néznek!' @@ -301,6 +310,8 @@ cauldron: no-discoloring: '&4Nem színteleníthetsz Slimefun páncélt!' gps: deathpoint: '&4Halálpont: &7%date%' + status-online: 'ELÉRHETŐ' + status-offline: 'NEM ELÉRHETÔ' waypoint: new: '&eKérlek írd be az új útpont nevét chatre. &7(Színkódok használhatóak!)' added: '&aSikeresen létrehoztál egy útpontot' @@ -400,3 +411,5 @@ languages: mk: 'Macedón' sr: 'Szerb' be: 'Belarusz' + si-LK: 'Szingaléz' + lt: 'Litván' diff --git a/src/main/resources/languages/hu/researches.yml b/src/main/resources/languages/hu/researches.yml index d911b94f33..9cd0534ced 100644 --- a/src/main/resources/languages/hu/researches.yml +++ b/src/main/resources/languages/hu/researches.yml @@ -259,3 +259,4 @@ slimefun: medium_tier_auto_enchanting: Gyors Automata Varázslás és Varázslat törlése portable_teleporter: Teleportálás bárhonnan farmer_talisman: A Farmer talizmánja + rainbow_armor: Látni akarom a szivárványt magasan az égben diff --git a/src/main/resources/languages/id/messages.yml b/src/main/resources/languages/id/messages.yml index cc5c9157f0..d19eb84def 100644 --- a/src/main/resources/languages/id/messages.yml +++ b/src/main/resources/languages/id/messages.yml @@ -68,21 +68,24 @@ guide: text: - '&bAnimasi Pembelajaran: &aYa' - '' - - '&7You can now toggle whether you' - - '&7will see information about your pondering in chat' - - '&7upon researching an item.' + - '&7Sekarang Anda dapat beralih apakah Anda ingin' + - '&7akan melihat informasi tentang perenungan Anda dalam obrolan' + - '&7setelah meneliti suatu item.' + click: '&eKlik untuk menonaktifkan animasi pembelajaran Anda' disabled: text: - '&bAnimasi Pembelajaran: &4Tidak' - '' - - '&7You can now toggle whether you' - - '&7will see information about your pondering in chat' - - '&7upon researching an item.' + - '&7Sekarang Anda dapat beralih apakah Anda ingin' + - '&7akan melihat informasi tentang perenungan Anda dalam obrolan' + - '&7setelah meneliti suatu item.' + click: '&eKlik untuk mengaktifkan animasi pembelajaran Anda' title: main: 'Panduan Slimefun' settings: 'Pengaturan & Informasi' languages: 'Pilih Bahasa Yang Anda Inginkan' credits: 'Para Kontributor Slimefun4' + wiki: 'Slimefun4 Wiki' addons: 'Addons untuk Slimefun4' bugs: 'Laporkan masalah' source: 'Kode sumber' @@ -97,6 +100,7 @@ guide: resourcepack: '&cArtis Resourcepack' translator: '&9Penerjemah' messages: + not-researched: '&4Anda tidak memiliki cukup pengetahuan untuk memahami ini. &cAnda butuh membuka &f"%item%&f" terlebih dahulu' not-enough-xp: '&4Anda Tidak Memiliki Cukup XP untuk Membuka Ini' unlocked: '&bAnda Telah Membuka &7"%research%"' only-players: '&4Perintah Ini Hanya Untuk Para Pemain' @@ -115,6 +119,9 @@ messages: disabled-item: '&4&lBenda Ini Telah Dinonakrifkan! Bagaimana Anda Mendapatkannya?' no-tome-yourself: '&cKamu Tidak Bisa Menggunakan &4Tome Of Knowledge &cUntuk Diri Anda Sendiri...' multimeter: '&bEnergi Yang Telah Tersimpan: &3%stored% &b/ &3%capacity%' + deprecated-item: '&4Item ini telah lama tidak digunakan dan akan dihapus dari slimefun sebentar lagi.' + researching-is-disabled: "&cPembelajaran telah dimatikan di server ini.\nSemua ilmu terbuka gratis!" + await-deletion: '&cAnda tidak bisa menempatkan blok slimefun segera setelah menghancurkannya. Coba lagi sesaat kemudian.' auto-crafting: select: 'Pilih resep ini' talisman: diff --git a/src/main/resources/languages/pl/messages.yml b/src/main/resources/languages/pl/messages.yml index 60d1775a3c..bae152e144 100644 --- a/src/main/resources/languages/pl/messages.yml +++ b/src/main/resources/languages/pl/messages.yml @@ -22,6 +22,8 @@ commands: description: 'Uruchom debugowanie dla programistów' none-running: '&7Nie ma obecnie żadnego przypadku testowego!' disabled: '&7Wyłączono tryb debugowania.' +placeholderapi: + profile-loading: 'Ładowanie...' guide: locked: 'Zablokowany' work-in-progress: 'Ta funkcja nie została jeszcze ukończona!' @@ -80,7 +82,7 @@ guide: description: - '&7Slimefun jest projektem open-source' - '&7i utrzymywany przez dużą społeczność ludzi.' - - '&7Over &e%contributors% &7people have worked on' + - '&7Ponad &e%contributors% &7osoby pracowały nad' - '&7Slimefun przez te wszystkie lata.' roles: developer: '&6Deweloper' diff --git a/src/main/resources/languages/pt/messages.yml b/src/main/resources/languages/pt/messages.yml index 773cfd3682..23ddfacb86 100644 --- a/src/main/resources/languages/pt/messages.yml +++ b/src/main/resources/languages/pt/messages.yml @@ -52,6 +52,7 @@ guide: miner: 'Recursos que podes obter com este Miner' generator: 'Tipos de combustível disponíveis' gold-pan: 'Recursos que podes obter' + climbing-pick: 'Superfícies que podes escalar' pages: previous: 'Página anterior' next: 'Página seguinte' @@ -79,16 +80,18 @@ guide: text: - '&bAnimação de descoberta: &aSim' - '' - - '&7You can now toggle whether you' - - '&7will see information about your pondering in chat' - - '&7upon researching an item.' + - '&7Agora podes escolher se tu' + - '&7vais ver informações sobre a tua ponderação no chat' + - '&7ao pesquisar um item.' + click: '&eClica para desativar a tua animação de descoberta' disabled: text: - '&bAnimação de descoberta: &aNão' - '' - - '&7You can now toggle whether you' - - '&7will see information about your pondering in chat' - - '&7upon researching an item.' + - '&7Agora podes escolher se tu' + - '&7vais ver informações sobre a tua ponderação no chat' + - '&7ao pesquisar um item.' + click: '&eClica para desativar a tua animação de descoberta' title: main: 'Guia Slimefun' settings: 'Configurações e informação' @@ -110,6 +113,9 @@ guide: resourcepack: '&cArtista de Resourcepack' translator: '&9Tradutor' messages: + not-researched: '&4Não tens conhecimento suficiente para entender isto. &cVais precisar de desbloquear &f"%item%&f"' + not-enough-xp: '&4Não tens XP suficiente para desbloquear isto' + unlocked: '&bDesbloqueaste &7"%research%"' only-players: '&4Este comando é apenas para Jogadores' unknown-player: '&4Jogador Desconhecido: &c%player%' no-permission: '&4Não tens as permissões necessárias para fazer isto' @@ -121,19 +127,45 @@ messages: disabled-in-world: '&4&lEsse item foi desativado neste mundo' disabled-item: '&4&lEsse item foi desativado! Como é que o conseguiste?' piglin-barter: '&4Não podes trocar com piglins utilizando itens de Slimefun' + deprecated-item: '&4Este item foi descontinuado e será removido de Slimefun em breve.' + researching-is-disabled: '&cA pesquisa foi desativada neste servidor. Tudo está desbloqueado por padrão!' + await-deletion: '&cNão podes colocar um bloco do Slimefun logo após teres quebrado um. Tenta novamente.' auto-crafting: + select-a-recipe: '&eBaixa-te e faz Clique Direito &7neste bloco com o item que queres craftar.' + recipe-set: '&aDefiniste o item para esta máquina.' + recipe-removed: '&eRemoveste o item desta máquina. Podes mandá-la fazer um item novo.' + no-recipes: '&cNão conseguimos encontrar nenhuma maneira válida de fazer o item que tu seguras.' + missing-chest: '&cOs Auto-Crafters teem que ser colocados sobre um baú!' + select: 'Selecionar esta receita' + temporarily-disabled: '&eEste Auto-Crafter foi temporariamente desativado. Podes reativá-lo a qualquer momento!' + re-enabled: '&eEste Auto-Crafter foi reativado!' + recipe-unavailable: | + &cOu este item foi desativado pelo servidor, ou ainda não desbloqueaste. + &7Tenta fazer o item se nunca o fizeste antes para descbloqueares a receita. tooltips: + enabled: + - '&aEsta receita está ativada' + - '' + - '&eClique esquerdo &7para desativar a receita temporariamente' + - '&eClique direito &7para remover esta receita' disabled: - '&cEsta receita está desativada no momento' - '' - - '&eLeft Click &7to re-enable this recipe' - - '&eRight Click &7to remove this recipe' + - '&eClique direito &7para reativar esta receita' + - '&eClique direito &7para remover esta receita' + research: + progress: '&7Começas a ponderar &b%research% &e(%progress%)' no-pvp: '&cNão podes fazer pvp aqui!' opening-guide: '&bA abrir o guia, isto pode demorar alguns segundos...' opening-backpack: '&bA abrir a mochila, isto pode demorar alguns segundos...' link-prompt: '&eClique aqui:' machines: + pattern-not-found: '&eEu não reconheço esta receita. Coloca os itens no padrão correto no Dispenser.' full-inventory: '&eDesculpa, o meu inventário está cheio!' + in-use: '&cO inventário deste bloco foi aberto por um jogador diferente.' + ignition-chamber-no-flint: '&cA câmara de ignição não tem isqueiros.' + ANCIENT_ALTAR: + unknown-recipe: '&4Receita desconhecida! &cUsa a receita correta!' HOLOGRAM_PROJECTOR: inventory-title: 'Editor de Holograma' ELEVATOR: @@ -150,6 +182,9 @@ machines: GPS_CONTROL_PANEL: transmitters: 'Transmissores' waypoints: 'Waypoints' + CARGO_NODES: + connected: '&2Conectado!' + not-connected: '&4Não conectado!' anvil: not-working: '&4Não podes usar itens de Slimefun em uma bigorna!' mcmmo-salvaging: '&4Não podes destruir itens do Slimefun!' @@ -163,6 +198,9 @@ villagers: no-trading: '&4Não podes trocar itens de Slimefun com Villagers!' backpack: already-open: '&cEsta mochila está aberta em outro lugar!' +gps: + status-online: 'LIGADO' + status-offline: 'DESLIGADO' inventory: no-access: '&4Não tens permissão para aceder este bloco' android: @@ -221,6 +259,7 @@ languages: ru: 'Russo' sk: 'Eslovaco' zh-CN: 'Chines (China)' + zh-TW: 'Chinês (Taiwan)' vi: 'Vietnamita' id: 'Indonésio' el: 'Grego' @@ -246,3 +285,5 @@ languages: mk: 'Macedónio' sr: 'Sérvio' be: 'Bielorrusso' + si-LK: 'Cingalês' + lt: 'Lituano' diff --git a/src/main/resources/languages/ru/messages.yml b/src/main/resources/languages/ru/messages.yml index af6b255bf7..61b0dbfb5b 100644 --- a/src/main/resources/languages/ru/messages.yml +++ b/src/main/resources/languages/ru/messages.yml @@ -129,13 +129,28 @@ messages: mode-change: '&bРежим «%device%» изменён на: &9%mode%' not-shears: '&cМультиинструмент не может быть использован в качестве ножниц!' auto-crafting: + select-a-recipe: '&eПрисядьте и нажмите ПКМ &7по этому блоку предметом, который хотите создать.' + recipe-set: '&aВы успешно установили рецепт для этой машины.' + recipe-removed: '&eВы успешно удалили рецепт из этой машины. Вы можете установить новый рецепт в любое время!' + no-recipes: '&cНе удалось найти подходящие рецепты для предмета в руке.' + missing-chest: '&cОтсутствует сундук! Авто-крафтеры нужно размещать над сундуком.' select: 'Выбрать этот рецепт' + temporarily-disabled: '&eЭтот автоматический верстак был временно отключен. Вы можете снова включить его в любой момент!' + re-enabled: '&eЭтот Авто-крафтер был снова включен!' + recipe-unavailable: | + &cЭтот предмет либо отключен на сервере, либо вы еще не разблокировали его. + &7Попробуйте создать предмет, если вы еще не сделали этого, чтобы разблокировать рецепт. tooltips: enabled: - '&cЭтот рецепт сейчас включён' - '' - - '&eLeft Click &7to temporarily disable the recipe' - - '&eRight Click &7to remove this recipe' + - '&eЛевый клик &7для временного отключения рецепта' + - '&eПравый клик &7для удаления этого рецепта' + disabled: + - '&cЭтот рецепт сейчас отключён' + - '' + - '&eЛевый клик &7для включения рецепта' + - '&eПравый клик &7для удаления этого рецепта' talisman: anvil: '&a&oВаш талисман сохранил инструмент от поломки' miner: '&a&oВаш талисман удвоил Ваш дроп' @@ -214,6 +229,7 @@ machines: pick-a-floor: '&3- Выберите пункт назначения -' current-floor: '&eВаш текущий этаж:' click-to-teleport: '&eНажмите &7для перемещения на этот этаж:' + editor-title: 'Настроить этот лифт' TELEPORTER: teleporting: '&3Телепортация…' teleported: '&3Телепортировано!' diff --git a/src/main/resources/languages/sv/categories.yml b/src/main/resources/languages/sv/categories.yml index 3b31f79f7e..d82006ff2d 100644 --- a/src/main/resources/languages/sv/categories.yml +++ b/src/main/resources/languages/sv/categories.yml @@ -6,6 +6,7 @@ slimefun: food: 'Mat' basic_machines: 'Grundläggande Maskiner' electricity: 'Energi och El' + androids: 'Programerbara Androider' gps: 'GPS-baserade Maskiner' armor: 'Rustning' magical_items: 'Magiska Föremål' diff --git a/src/main/resources/languages/sv/messages.yml b/src/main/resources/languages/sv/messages.yml index 52713bca69..aa141bee30 100644 --- a/src/main/resources/languages/sv/messages.yml +++ b/src/main/resources/languages/sv/messages.yml @@ -13,6 +13,9 @@ commands: description: Låser upp/återställer en spelares forskningar reset: '&cDu har återställt %player%s kunskap' reset-target: '&cDin kunskap har blivit återställd' + backpack: + invalid-id: '&4ID måste vara ett icke-negativt tal!' + backpack-does-not-exist: '&4Den angivna ryggsäcken finns inte!' placeholderapi: profile-loading: 'Laddar...' guide: @@ -36,6 +39,7 @@ guide: miner: 'Resurser du kan få med denna Gruvarbetare' generator: 'Tillgängliga typer av bränsle' gold-pan: 'Resurser du kan få' + climbing-pick: 'Ytor som du kan klättra' cheat: no-multiblocks: '&4Du kan inte fuska fram Multiblocks, du måste bygga dem!' pages: @@ -59,6 +63,7 @@ guide: settings: 'Inställningar & Info' languages: 'Välj ditt föredragna språk' credits: 'Slimefun4-medhjälpare' + wiki: 'Slimefun4 Wiki' addons: 'Tilläg till Slimefun4' bugs: 'Bugg Rapporter' source: 'Källkoden' @@ -91,6 +96,8 @@ messages: disabled-item: '&4&lDetta föremål är inaktiverat! Hur fick du ens det?' no-tome-yourself: '&cDu kan inte använda &4Tome of Knowledge &cpå dig själv' multimeter: '&bLagrad energi: &3%stored% &b/ &3%capacity%' + auto-crafting: + select: 'Välj recept' talisman: anvil: '&a&oDin talisman förhindrade ditt verktyg från att gå sönder' miner: '&a&oDin talisman dubblade precis dina gruvfynd' diff --git a/src/main/resources/languages/sv/recipes.yml b/src/main/resources/languages/sv/recipes.yml index ed97d539c0..83042679a5 100644 --- a/src/main/resources/languages/sv/recipes.yml +++ b/src/main/resources/languages/sv/recipes.yml @@ -1 +1,6 @@ --- +slimefun: + multiblock: + name: 'Multiblock' + oil_pump: + name: 'Oljepump' diff --git a/src/main/resources/languages/tl/messages.yml b/src/main/resources/languages/tl/messages.yml index 051a7d8bbd..08d1463bbb 100644 --- a/src/main/resources/languages/tl/messages.yml +++ b/src/main/resources/languages/tl/messages.yml @@ -30,6 +30,7 @@ commands: debug: none-running: '&7Walang kaso ng pagsubok ang kasalukuyang pinapatakbo!' running: '&7Pinapatakbo ang debug mode kasama ang test: &6%test%' + disabled: '&7Hindi na tumatakbo ang debug mode.' placeholderapi: profile-loading: 'Naglo-load...' guide: @@ -80,19 +81,8 @@ guide: options: learning-animation: enabled: - text: - - '&bKarunungang Animasyon: &aYes' - - '' - - '&7You can now toggle whether you' - - '&7will see information about your pondering in chat' - - '&7upon researching an item.' + click: '&eI-click para huwag paganahin ang iyong learning animation' disabled: - text: - - '&bLearning Animation: &4No' - - '' - - '&7You can now toggle whether you' - - '&7makikita ang impormasyon na pinagtatakahan mo sa chat' - - '&7upon researching an item.' click: '&eI-click para paganahin ang iyong karunungang animasyon' title: main: 'Gabay para sa Slimefun' @@ -116,6 +106,7 @@ guide: roles: translator: '&9Tagapagsaling-wika' messages: + not-researched: '&4Kulang ang iyong Kaalaman upang ito ay maintindihan. &cKailangan mo I-unlock &f"%item%&f"' not-enough-xp: '&4Kulang ang iyong XP upang ito''y ma-unlock.' unlocked: '&bNa-unlock mo ang &7"%research%"' only-players: '&4Ang command na ito ay para lamang sa Players.' diff --git a/src/main/resources/languages/tr/messages.yml b/src/main/resources/languages/tr/messages.yml index 4cf08c8129..eb3a9f2276 100644 --- a/src/main/resources/languages/tr/messages.yml +++ b/src/main/resources/languages/tr/messages.yml @@ -78,6 +78,24 @@ guide: translations: name: '&aBir şeyler mi eksik?' lore: 'Kendi çevirinizi eklemek için tıklayın' + options: + learning-animation: + enabled: + text: + - '&bÖğrenme Animasyonu: &aAçık' + - '' + - '&7İstediğiniz zaman Eşyanın bilgilerini' + - '&7yazdığınız zaman' + - '&7kanalda görmenizi sağlar.' + click: '&eÖğrenme animasyonunu kapatmak için tıkla' + disabled: + text: + - '&bÖğrenme Animasyonu: &4Kapalı' + - '' + - '&7İstediğiniz zaman Eşyanın bilgilerini' + - '&7yazdığınız zaman' + - '&7kanalda görmenizi sağlar.' + click: '&eÖğrenme animasyonunu açmak için tıkla' title: main: 'Slimefun Rehberi' settings: 'Ayarlar & Bilgi' @@ -127,18 +145,24 @@ messages: mode-change: '&b%device% modül değiştirildi: &9%mode%' not-shears: '&cBir Multi Tool makas olarak kullanılamaz!' auto-crafting: + recipe-set: '&aBu makinenin tarifini başarıyla ayarladınız.' + recipe-removed: '&eTarifi bu makineden başarıyla kaldırdınız. İstediğiniz zaman yeni bir tarif ayarlayabilirsiniz!' + no-recipes: '&cTuttuğunuz öğe için geçerli herhangi bir tarif bulamadık.' + missing-chest: '&cKayıp göğüs! Otomatik zanaatkarlar bir sandığın üzerine yerleştirilmelidir.' select: 'Bu tarifi seçin' + temporarily-disabled: '&eBu otomatik Crafter geçici olarak devre dışı bırakıldı. İstediğiniz zaman yeniden etkinleştirebilirsiniz!' + re-enabled: '&eBu otomatik Crafter yeniden etkinleştirildi!' tooltips: enabled: - '&aBu tarif şu anda etkin' - '' - - '&eLeft Click &7to temporarily disable the recipe' - - '&eRight Click &7to remove this recipe' + - '&eSol Tıklama &7tarifi geçici olarak devre dışı bırakmak için' + - '&eSağ Tıklama &7bu tarifi kaldırmak için' disabled: - '&cBu tarif şu anda devre dışı' - '' - - '&eLeft Click &7to re-enable this recipe' - - '&eRight Click &7to remove this recipe' + - '&eSol Tıklama &7bu tarifi yeniden etkinleştirmek için' + - '&eSağ Tıklama &7bu tarifi kaldırmak için' talisman: anvil: '&a&oTılsım aletinizi kırılmadan kurtardı' miner: '&a&oTılsımın madenini ikiye katladı' @@ -235,6 +259,7 @@ machines: waypoints: 'Yer Noktası Genel Bakışı' CARGO_NODES: must-be-placed: '&4Mutlaka bir sandık veya makineye bağlanmalı!' + connected: '&2Bağlandı!' INDUSTRIAL_MINER: no-fuel: '&cIndustrial Miner''ınızın yakıtı bitti! Yukarıdaki sandığa yakıt koyun.' piston-facing: '&cIndustrial Miner''ınızın pistonu yukarıya bakmalı!' diff --git a/src/main/resources/languages/zh-CN/messages.yml b/src/main/resources/languages/zh-CN/messages.yml index ea7d7da109..e79b887552 100644 --- a/src/main/resources/languages/zh-CN/messages.yml +++ b/src/main/resources/languages/zh-CN/messages.yml @@ -81,7 +81,27 @@ guide: translations: name: '&a少了些什么?' lore: '单击添加你自己的翻译' + modes: + selected: 'Slimefun 指南类型: ' + change: '点击更改类型' + SURVIVAL_MODE: '生存模式' + CHEAT_MODE: '作弊模式' options: + fireworks: + enabled: + text: + - '&b烟花: &a是' + - '' + - '&7你现在可以选择是否' + - '&7启用研究物品时的烟花。' + click: '&e点击关闭烟花' + disabled: + text: + - '&b烟花: &4否' + - '' + - '&7你现在可以选择是否' + - '&7启用研究物品时的烟花。' + click: '&e点击开启烟花' learning-animation: enabled: text: @@ -124,6 +144,8 @@ guide: wiki: '&3Wiki 编辑者' resourcepack: '&c材质制作者' translator: '&9翻译者' +actionbar: + radiation: '&6辐射暴露等级:&c%level%&7/&e100' messages: not-researched: '&4你的知识还不足以理解这个物品. &c你需要先解锁 &f"%item%"&f' not-enough-xp: '&4你没有足够的经验来解锁这个研究' @@ -148,6 +170,7 @@ messages: bee-suit-slow-fall: '&e你的蜂翅将会让你安全缓降' deprecated-item: '&4该物品已被弃用,将在不久后从 Slimefun 中移除。' researching-is-disabled: '&c该服务器已禁用研究,所有物品都已解锁!' + await-deletion: '&c你不能在破坏一个 Slimefun 方块后立即放置一个 Slimefun 方块。请稍后再试。' multi-tool: mode-change: '&b%device% 的模式已切换为: &9%mode%' not-shears: '&c多功能工具 (Multi Tool) 不能作为剪刀使用!' diff --git a/src/main/resources/languages/zh-CN/researches.yml b/src/main/resources/languages/zh-CN/researches.yml index 8a9f87f32a..07398f94e8 100644 --- a/src/main/resources/languages/zh-CN/researches.yml +++ b/src/main/resources/languages/zh-CN/researches.yml @@ -226,7 +226,7 @@ slimefun: radiant_backpack: 金光闪闪的背包 auto_drier: 自动烘干机 diet_cookie: 减肥曲奇 - storm_staff: 风之法杖 + storm_staff: 雷之法杖 soulbound_rune: 灵魂绑定符文 geo_miner: 自然资源开采机 lightning_rune: 雷电符文 @@ -259,3 +259,4 @@ slimefun: medium_tier_auto_enchanting: 高速自动附魔/祛魔 portable_teleporter: 从任何地方传送 farmer_talisman: 农夫护身符 + rainbow_armor: 我想看到高空中的彩虹 diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/api/events/TestTalismanActivateEvent.java b/src/test/java/io/github/thebusybiscuit/slimefun4/api/events/TestTalismanActivateEvent.java index 94b1947cf1..40cfc61fe5 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/api/events/TestTalismanActivateEvent.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/api/events/TestTalismanActivateEvent.java @@ -78,23 +78,20 @@ void testEventIsFired() { activateAnvilTalisman(true, true); server.getPluginManager().assertEventFired(TalismanActivateEvent.class, ignored -> true); server.getPluginManager().clearEvents(); + // Assert the normal talisman does not activate in the ender chest activateAnvilTalisman(false, true); - try { - server.getPluginManager().assertEventFired(TalismanActivateEvent.class, ignored -> true); - } catch (AssertionError ignored) { - return; // This is expected; the event should not have fired - } - server.getPluginManager().clearEvents(); + Assertions.assertThrows( + AssertionError.class, + () -> server.getPluginManager().assertEventFired(TalismanActivateEvent.class, ignored -> true) + ); // Assert the ender talisman does not activate in the inventory - try { - activateAnvilTalisman(true, false); - server.getPluginManager().assertEventFired(TalismanActivateEvent.class, ignored -> true); - } catch (AssertionError ignored) { - return; // This is expected; the event should not have fired - } - server.getPluginManager().clearEvents(); + activateAnvilTalisman(true, false); + Assertions.assertThrows( + AssertionError.class, + () -> server.getPluginManager().assertEventFired(TalismanActivateEvent.class, ignored -> true) + ); } @Test diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/core/commands/TestGuideCommand.java b/src/test/java/io/github/thebusybiscuit/slimefun4/core/commands/TestGuideCommand.java index 0612ade074..57560503a7 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/core/commands/TestGuideCommand.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/core/commands/TestGuideCommand.java @@ -38,9 +38,9 @@ public static void unload() { void testCommand(boolean op) { Player player = server.addPlayer(); player.setOp(op); + boolean hasPermission = player.hasPermission("slimefun.command.guide"); server.execute("slimefun", player, "guide").assertSucceeded(); - ItemStack guide = SlimefunGuide.getItem(SlimefunGuideMode.SURVIVAL_MODE); - Assertions.assertEquals(op, SlimefunUtils.containsSimilarItem(player.getInventory(), guide, true)); + Assertions.assertEquals(hasPermission, SlimefunUtils.containsSimilarItem(player.getInventory(), guide, true)); } } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/AbstractLocaleRegexChecker.java b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/AbstractLocaleRegexChecker.java index 63eef282b4..df8668f285 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/AbstractLocaleRegexChecker.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/AbstractLocaleRegexChecker.java @@ -1,8 +1,8 @@ package io.github.thebusybiscuit.slimefun4.core.services.localization; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; @@ -16,7 +16,9 @@ import javax.annotation.ParametersAreNonnullByDefault; import org.apache.commons.lang.Validate; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -50,16 +52,23 @@ public static void unload() { @ParametersAreNonnullByDefault @Nullable - BufferedReader readLanguageFile(LanguagePreset lang, LanguageFile file) { + FileConfiguration readLanguageFile(LanguagePreset lang, LanguageFile file) throws IOException, InvalidConfigurationException { String path = file.getFilePath(lang.getLanguageCode()); - InputStream inputStream = getClass().getResourceAsStream(path); - - if (inputStream == null) { - // This file does not exist, we consider it "passed". + byte[] bytes; + try (InputStream inputStream = getClass().getResourceAsStream(path)) { + if (inputStream == null) { + // This file does not exist, we consider it "passed". + return null; + } + bytes = inputStream.readAllBytes(); + } + String contents = new String(bytes, StandardCharsets.UTF_8); + if (contents.trim().equals("---")) { return null; } - - return new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + YamlConfiguration configuration = new YamlConfiguration(); + configuration.loadFromString(contents); + return configuration; } @ParametersAreNonnullByDefault diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestColorCodes.java b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestColorCodes.java index 9be3d2710b..88371ac0ee 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestColorCodes.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestColorCodes.java @@ -1,17 +1,15 @@ package io.github.thebusybiscuit.slimefun4.core.services.localization; -import java.io.BufferedReader; -import java.io.IOException; -import java.util.regex.Pattern; - -import javax.annotation.ParametersAreNonnullByDefault; - +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import javax.annotation.ParametersAreNonnullByDefault; +import java.io.IOException; +import java.util.regex.Pattern; + /** * We need to make sure that color codes are still working properly. *

@@ -24,7 +22,7 @@ *

* The test will catch occurences like "a& ", "b&Hello" or "7&", "5& a". * The test will however ignore valid color codes such as "a&a". - * + * * @author TheBusyBiscuit * */ @@ -38,15 +36,12 @@ class TestColorCodes extends AbstractLocaleRegexChecker { @ParametersAreNonnullByDefault @MethodSource("getAllLanguageFiles") @DisplayName("Test for mistakes in color codes for Slimefun locale files") - void testSpelling(LanguagePreset lang, LanguageFile file) throws IOException { - try (BufferedReader reader = readLanguageFile(lang, file)) { - if (reader == null) { - return; - } - - FileConfiguration config = YamlConfiguration.loadConfiguration(reader); - assertNoRegexMatchesForAllEntries(lang, file, config); + void testSpelling(LanguagePreset lang, LanguageFile file) throws IOException, InvalidConfigurationException { + FileConfiguration config = readLanguageFile(lang, file); + if (config == null) { + return; } + assertNoRegexMatchesForAllEntries(lang, file, config); } } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestSlimefunSpelling.java b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestSlimefunSpelling.java index c33bb4c11d..dd8b62be3a 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestSlimefunSpelling.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/core/services/localization/TestSlimefunSpelling.java @@ -1,13 +1,12 @@ package io.github.thebusybiscuit.slimefun4.core.services.localization; -import java.io.BufferedReader; import java.io.IOException; import java.util.regex.Pattern; import javax.annotation.ParametersAreNonnullByDefault; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -16,7 +15,7 @@ * Your friendly neighbourhood spellcheck. * Brought to you by our Discord bot "@WalshBot". * No more incorrect spelling of "Slimefun". - * + * * @author TheBusyBiscuit * */ @@ -30,15 +29,12 @@ class TestSlimefunSpelling extends AbstractLocaleRegexChecker { @ParametersAreNonnullByDefault @MethodSource("getAllLanguageFiles") @DisplayName("Test correct spelling of Slimefun in language files") - void testSpelling(LanguagePreset lang, LanguageFile file) throws IOException { - try (BufferedReader reader = readLanguageFile(lang, file)) { - if (reader == null) { - return; - } - - FileConfiguration config = YamlConfiguration.loadConfiguration(reader); - assertNoRegexMatchesForAllEntries(lang, file, config); + void testSpelling(LanguagePreset lang, LanguageFile file) throws IOException, InvalidConfigurationException { + FileConfiguration config = readLanguageFile(lang, file); + if (config == null) { + return; } + assertNoRegexMatchesForAllEntries(lang, file, config); } } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestDamageableItem.java b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestDamageableItem.java index d7aec62eec..7a97e33cf3 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestDamageableItem.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestDamageableItem.java @@ -20,7 +20,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.test.TestUtilities; import io.github.thebusybiscuit.slimefun4.test.mocks.MockDamageable; - +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; import be.seeseemelk.mockbukkit.MockBukkit; import be.seeseemelk.mockbukkit.ServerMock; @@ -82,8 +82,8 @@ void testDamageableItemDamagesItem() { @DisplayName("Test if DamageableItem cares about unbreaking levels") void testDamageableItemCaresUnbreaking() { MockDamageable noUnbreakingItem = getDummyItem("NU", true, null, null); - MockDamageable iiiUnbreakingItem = getDummyItem("IIIU", true, Enchantment.DURABILITY, 3); - MockDamageable xUnbreakingItem = getDummyItem("XU", true, Enchantment.DURABILITY, 10); + MockDamageable iiiUnbreakingItem = getDummyItem("IIIU", true, VersionedEnchantment.UNBREAKING, 3); + MockDamageable xUnbreakingItem = getDummyItem("XU", true, VersionedEnchantment.UNBREAKING, 10); ItemStack noUnbreakingItemIS = noUnbreakingItem.getItem().clone(); ItemStack iiiUnbreakingItemIS = iiiUnbreakingItem.getItem().clone(); ItemStack xUnbreakingItemIS = xUnbreakingItem.getItem().clone(); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/TestClimbingPick.java b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/TestClimbingPick.java index 53181b2c1b..9a43bc12f5 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/TestClimbingPick.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/TestClimbingPick.java @@ -7,7 +7,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockFace; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; @@ -26,6 +25,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.test.TestUtilities; import io.github.thebusybiscuit.slimefun4.test.presets.SlimefunItemTest; +import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedEnchantment; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import be.seeseemelk.mockbukkit.MockBukkit; @@ -164,7 +164,7 @@ void testEfficiency() { private ItemStack getPickWithEfficiency(@Nonnull ClimbingPick pick, int level) { ItemStack item = pick.getItem().clone(); - item.addUnsafeEnchantment(Enchantment.DIG_SPEED, level); + item.addUnsafeEnchantment(VersionedEnchantment.EFFICIENCY, level); return item; } } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TestCoolerListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TestCoolerListener.java index 5bd37ce19d..e606840cbc 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TestCoolerListener.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TestCoolerListener.java @@ -25,7 +25,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler; import io.github.thebusybiscuit.slimefun4.implementation.items.food.Juice; import io.github.thebusybiscuit.slimefun4.test.TestUtilities; - import be.seeseemelk.mockbukkit.MockBukkit; import be.seeseemelk.mockbukkit.ServerMock; diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java b/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java index c8e1916f54..98653ee5b7 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/storage/backend/TestLegacyBackend.java @@ -17,6 +17,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -52,8 +53,6 @@ public static void load() { // within the class isn't being fired (where ItemStack and other classes are registered) ConfigurationSerialization.registerClass(ItemStack.class); ConfigurationSerialization.registerClass(ItemMeta.class); - - setupResearches(); } @AfterAll @@ -62,9 +61,16 @@ public static void unload() throws IOException { FileUtils.deleteDirectory(new File("data-storage")); } + @AfterEach + public void cleanup() { + Slimefun.getRegistry().getResearches().clear(); + } + // Test simple loading and saving of player data @Test void testLoadingResearches() throws IOException { + setupResearches(); + // Create a player file which we can load UUID uuid = UUID.randomUUID(); File playerFile = new File("data-storage/Slimefun/Players/" + uuid + ".yml"); @@ -184,6 +190,8 @@ void testLoadingWaypoints() throws IOException { @Test void testSavingResearches() throws InterruptedException { + setupResearches(); + // Create a player file which we can load UUID uuid = UUID.randomUUID(); File playerFile = new File("data-storage/Slimefun/Players/" + uuid + ".yml"); @@ -279,6 +287,8 @@ void testSavingWaypoints() throws InterruptedException { // Test realistic situations @Test void testResearchChanges() throws InterruptedException { + setupResearches(); + UUID uuid = UUID.randomUUID(); File playerFile = new File("data-storage/Slimefun/Players/" + uuid + ".yml"); @@ -372,6 +382,41 @@ void testWaypointChanges() throws InterruptedException { Assertions.assertEquals(1, assertion.getWaypoints().size()); } + @Test + void testDuplicateResearchesDontGetUnResearched() throws InterruptedException { + // Create a player file which we can load + UUID uuid = UUID.randomUUID(); + File playerFile = new File("data-storage/Slimefun/Players/" + uuid + ".yml"); + + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + PlayerProfile profile = TestUtilities.awaitProfile(player); + + // Setup initial research + NamespacedKey initialKey = new NamespacedKey(plugin, "test_1"); + Research initialResearch = new Research(initialKey, 1, "Test 1", 100); + initialResearch.register(); + + // Setup duplicate research + // Keep the ID as 1 but change name and key + NamespacedKey duplicateKey = new NamespacedKey(plugin, "test_2"); + Research duplicateResearch = new Research(duplicateKey, 1, "Test 2", 100); + duplicateResearch.register(); + + profile.setResearched(initialResearch, true); + + // Save the player data + LegacyStorage storage = new LegacyStorage(); + storage.savePlayerData(uuid, profile.getPlayerData()); + + // Assert the file exists and data is correct + Assertions.assertTrue(playerFile.exists()); + PlayerData assertion = storage.loadPlayerData(uuid); + // Will have both the initial and duplicate research + Assertions.assertEquals(2, assertion.getResearches().size()); + Assertions.assertTrue(assertion.getResearches().contains(initialResearch)); + Assertions.assertTrue(assertion.getResearches().contains(duplicateResearch)); + } + // Utils private static void setupResearches() { for (int i = 0; i < 10; i++) { diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/utils/TestMinecraftVersion.java b/src/test/java/io/github/thebusybiscuit/slimefun4/utils/TestMinecraftVersion.java index 72beee0091..74a2622cce 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/utils/TestMinecraftVersion.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/utils/TestMinecraftVersion.java @@ -11,11 +11,27 @@ class TestMinecraftVersion { @Test @DisplayName("Test if Minecraft versions match themselves") void testMatches() { - Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(16)); - Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_17.isMinecraftVersion(17)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(16, -1)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_17.isMinecraftVersion(17, -1)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20_5.isMinecraftVersion(20, 5)); - Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_17.isMinecraftVersion(16)); - Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(0)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_17.isMinecraftVersion(16, -1)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(0, -1)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_20_5.isMinecraftVersion(20, 4)); + } + + @Test + @DisplayName("Test if Minecraft versions match minor versions") + void testMatchesMinor() { + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(16, 1)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(16, 2)); + + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20.isMinecraftVersion(20, 4)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20_5.isMinecraftVersion(20, 6)); + + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_20.isMinecraftVersion(20, 5)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_16.isMinecraftVersion(17, 1)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_20_5.isMinecraftVersion(20, 4)); } @Test @@ -24,6 +40,8 @@ void testAtLeast() { Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_18.isAtLeast(MinecraftVersion.MINECRAFT_1_16)); Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_17.isAtLeast(MinecraftVersion.MINECRAFT_1_16)); Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_17.isAtLeast(MinecraftVersion.MINECRAFT_1_17)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20.isAtLeast(MinecraftVersion.MINECRAFT_1_20)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20_5.isAtLeast(MinecraftVersion.MINECRAFT_1_20)); Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_17.isAtLeast(MinecraftVersion.MINECRAFT_1_18)); } @@ -48,6 +66,24 @@ void testIsBefore() { Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_17.isBefore(MinecraftVersion.MINECRAFT_1_16)); } + @Test + @DisplayName("Test if Minecraft versions #isBefore behaves correctly for minor versions") + void testIsBeforeMinor() { + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_18.isBefore(16, 5)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_18.isBefore(17, 1)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_18.isBefore(18, 0)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_18.isBefore(18, 1)); + + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_20.isBefore(20, 0)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20.isBefore(20, 2)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20.isBefore(20, 4)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20.isBefore(20, 5)); + + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_20_5.isBefore(20, 4)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_20_5.isBefore(20, 5)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_20_5.isBefore(20, 6)); + } + @Test @DisplayName("Test correct behaviour for MinecraftVersion.UNKNOWN.isBefore(...)") void testIsBeforeUnknown() { diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/utils/biomes/TestBiomeMapCompatibility.java b/src/test/java/io/github/thebusybiscuit/slimefun4/utils/biomes/TestBiomeMapCompatibility.java index cdb132d91c..99f7c6100f 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/utils/biomes/TestBiomeMapCompatibility.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/utils/biomes/TestBiomeMapCompatibility.java @@ -34,7 +34,7 @@ /** * This test checks if biome maps work across multiple versions of Minecraft. * A similar test can be written for Material Tags :? - * + * * @author TheBusyBiscuit * */ @@ -45,6 +45,9 @@ class TestBiomeMapCompatibility { @BeforeAll public static void load() { MockBukkit.mock(); + // Needed for JsonUtils.parseString which relies on a valid Slimefun plugin instance to determine the current + // MinecraftVersion + MockBukkit.load(Slimefun.class); for (MinecraftVersion version : MinecraftVersion.values()) { if (!version.isVirtual()) { @@ -91,7 +94,7 @@ void testCompatibilities(String name, MinecraftVersion version) { /** * We manually specify here which biome map works on which minecraft versions. - * + * * @return A {@link Stream} of {@link Arguments} for our unit test. */ private static @Nonnull Stream biomeMaps() { @@ -105,37 +108,37 @@ void testCompatibilities(String name, MinecraftVersion version) { MinecraftVersion.MINECRAFT_1_19, MinecraftVersion.MINECRAFT_1_20 }); - + testCases.put("oil_v1.16", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_16, MinecraftVersion.MINECRAFT_1_17 }); - + testCases.put("oil_v1.18", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_18, MinecraftVersion.MINECRAFT_1_19, MinecraftVersion.MINECRAFT_1_20 }); - + testCases.put("salt_v1.16", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_16, MinecraftVersion.MINECRAFT_1_17 }); - + testCases.put("salt_v1.18", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_18, MinecraftVersion.MINECRAFT_1_19, MinecraftVersion.MINECRAFT_1_20 }); - + testCases.put("uranium_v1.16", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_16 }); - + testCases.put("uranium_v1.17", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_17 }); - + testCases.put("uranium_v1.18", new MinecraftVersion[] { MinecraftVersion.MINECRAFT_1_18, MinecraftVersion.MINECRAFT_1_19, diff --git a/src/test/resources/biomes/1.20.5+.json b/src/test/resources/biomes/1.20.5+.json new file mode 100644 index 0000000000..dfe92f1834 --- /dev/null +++ b/src/test/resources/biomes/1.20.5+.json @@ -0,0 +1,67 @@ +[ + "minecraft:ocean", + "minecraft:plains", + "minecraft:desert", + "minecraft:windswept_hills", + "minecraft:forest", + "minecraft:taiga", + "minecraft:swamp", + "minecraft:mangrove_swamp", + "minecraft:river", + "minecraft:nether_wastes", + "minecraft:the_end", + "minecraft:frozen_ocean", + "minecraft:frozen_river", + "minecraft:snowy_plains", + "minecraft:mushroom_fields", + "minecraft:beach", + "minecraft:jungle", + "minecraft:sparse_jungle", + "minecraft:deep_ocean", + "minecraft:stony_shore", + "minecraft:snowy_beach", + "minecraft:birch_forest", + "minecraft:dark_forest", + "minecraft:snowy_taiga", + "minecraft:old_growth_pine_taiga", + "minecraft:windswept_forest", + "minecraft:savanna", + "minecraft:savanna_plateau", + "minecraft:badlands", + "minecraft:wooded_badlands", + "minecraft:small_end_islands", + "minecraft:end_midlands", + "minecraft:end_highlands", + "minecraft:end_barrens", + "minecraft:warm_ocean", + "minecraft:lukewarm_ocean", + "minecraft:cold_ocean", + "minecraft:deep_lukewarm_ocean", + "minecraft:deep_cold_ocean", + "minecraft:deep_frozen_ocean", + "minecraft:the_void", + "minecraft:sunflower_plains", + "minecraft:windswept_gravelly_hills", + "minecraft:flower_forest", + "minecraft:ice_spikes", + "minecraft:old_growth_birch_forest", + "minecraft:old_growth_spruce_taiga", + "minecraft:windswept_savanna", + "minecraft:eroded_badlands", + "minecraft:bamboo_jungle", + "minecraft:soul_sand_valley", + "minecraft:crimson_forest", + "minecraft:warped_forest", + "minecraft:basalt_deltas", + "minecraft:dripstone_caves", + "minecraft:lush_caves", + "minecraft:deep_dark", + "minecraft:meadow", + "minecraft:grove", + "minecraft:snowy_slopes", + "minecraft:frozen_peaks", + "minecraft:jagged_peaks", + "minecraft:stony_peaks", + "minecraft:cherry_grove", + "minecraft:custom", +] \ No newline at end of file