1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-20 11:45:51 +00:00
api/machine-operations

Conflicts:
	src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java
	src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
This commit is contained in:
TheBusyBiscuit 2021-03-13 17:36:55 +01:00
commit 44a6d15d18
158 changed files with 4591 additions and 1999 deletions

View File

@ -1,8 +1,5 @@
{ {
"extends": [ "extends": [
"config:base" "config:base"
],
"labels": [
"🚨 Dependency Update"
] ]
} }

View File

@ -6,8 +6,11 @@ on:
jobs: jobs:
comment: comment:
name: Comment on Issue
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: contains(github.event.issue.labels.*.name, '🐞 Bug Report') if: contains(github.event.issue.labels.*.name, '🐞 Bug Report')
steps: steps:
- name: Query recent commits - name: Query recent commits
uses: TheBusyBiscuit/recently-closed-issues@1.1.0 uses: TheBusyBiscuit/recently-closed-issues@1.1.0
@ -44,8 +47,8 @@ jobs:
* [ ] Your issue has already been reported before, it is a duplicate. Check the other issues first before posting! * [ ] Your issue has already been reported before, it is a duplicate. Check the other issues first before posting!
* [ ] You posted an error without using pastebin. Please always post errors via pastebin otherwise they become nearly unreadable. * [ ] You posted an error without using pastebin. Please always post errors via pastebin otherwise they become nearly unreadable.
* [ ] You seem to be reporting multiple bugs at once. Please make a separate issue for each bug you encountered, so we can properly handle them individually. * [ ] You seem to be reporting multiple bugs at once. Please make a separate issue for each bug you encountered, so we can properly handle them individually.
* [ ] Your issue has already been fixed in a later version of Slimefun or CS-CoreLib, you should update. * [ ] Your issue has already been fixed in a later version of Slimefun, you should update.
* [ ] You are using an outdated and unsupported version of Slimefun / CS-CoreLib, again, you should update. * [ ] You are using an outdated and unsupported version of Slimefun, again, you should update.
* [ ] You are using an unofficially modified build of Slimefun. We only support official versions of Slimefun - for obvious reasons. * [ ] You are using an unofficially modified build of Slimefun. We only support official versions of Slimefun - for obvious reasons.
* [ ] You are using an unsupported version of Minecraft. We only provide support for the Minecraft versions Slimefun was developed for, older versions are not supported anymore. * [ ] You are using an unsupported version of Minecraft. We only provide support for the Minecraft versions Slimefun was developed for, older versions are not supported anymore.
* [ ] You are using a \"stable\" version of Slimefun (prefixed with \"RC - \"), your issue may have been fixed in a development build, so we only accept bug reports from those. * [ ] You are using a \"stable\" version of Slimefun (prefixed with \"RC - \"), your issue may have been fixed in a development build, so we only accept bug reports from those.

View File

@ -10,34 +10,36 @@ jobs:
name: Pull Request Labels name: Pull Request Labels
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'Slimefun/Slimefun4' && github.actor != 'gitlocalize-app[bot]' && github.actor != 'renovate[bot]' if: github.repository == 'Slimefun/Slimefun4' && github.actor != 'gitlocalize-app[bot]'
steps: steps:
- uses: WalshyDev/pr-labels@v1.1 - uses: WalshyDev/pr-labels@v1.1
id: labeller id: labeller
name: Apply labels based on branch name: Apply labels based on branch
with: with:
token: "${{ secrets.ACCESS_TOKEN }}" token: "${{ secrets.GITHUB_TOKEN }}"
renovate: '🚨 Dependency Update'
feature: '🎈 Feature' feature: '🎈 Feature'
fix: '✨ Fix' fix: '✨ Fix'
chore: '🧹 Chores' chore: '🧹 Chores'
performance: '💡 Performance Optimization' performance: '💡 Performance Optimization'
api: '🔧 API' api: '🔧 API'
compatibility: '🤝 Compatibility'
- uses: thollander/actions-comment-pull-request@1.0.1 - uses: thollander/actions-comment-pull-request@1.0.1
name: Comment the applied label name: Leave a comment about the applied label
if: ${{ steps.labeller.outputs.applied != 0 }} if: ${{ steps.labeller.outputs.applied != 0 }}
with: with:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
message: | message: |
Your Pull Request was automatically labelled as: ${{ steps.labeller.outputs.applied }} Your Pull Request was automatically labelled as: "${{ steps.labeller.outputs.applied }}"
Thank you for contributing to this project! ❤️ Thank you for contributing to this project! ❤️
- uses: thollander/actions-comment-pull-request@1.0.1 - uses: thollander/actions-comment-pull-request@1.0.1
name: Comment the applied label name: Leave a comment about our branch naming convention
if: ${{ steps.labeller.outputs.applied == 0 }} if: ${{ steps.labeller.outputs.applied == 0 }}
with: with:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
message: | message: |
**Pro Tip!** **Pro Tip!**
You can help us label your Pull Requests by using the following branch naming convention next time you create a pull request. ❤️ You can help us label your Pull Requests by using the following branch naming convention next time you create a pull request. ❤️
@ -48,6 +50,7 @@ jobs:
`chore/**` | 🧹 Chores `chore/**` | 🧹 Chores
`api/**` | 🔧 API `api/**` | 🔧 API
`performance/**` | 💡 Performance Optimization `performance/**` | 💡 Performance Optimization
`compatibility/**` | 🤝 Compatibility
<hr> <hr>
If your changes do not fall into any of these categories, don't worry. If your changes do not fall into any of these categories, don't worry.
You can just ignore this message in that case! 👀 You can just ignore this message in that case! 👀

View File

@ -1,4 +1,5 @@
# Table of contents # Table of contents
- [Release Candidate 21 (TBD)](#release-candidate-21-tbd)
- [Release Candidate 20 (30 Jan 2021)](#release-candidate-20-30-jan-2021) - [Release Candidate 20 (30 Jan 2021)](#release-candidate-20-30-jan-2021)
- [Release Candidate 19 (11 Jan 2021)](#release-candidate-19-11-jan-2021) - [Release Candidate 19 (11 Jan 2021)](#release-candidate-19-11-jan-2021)
- [Release Candidate 18 (03 Dec 2020)](#release-candidate-18-03-dec-2020) - [Release Candidate 18 (03 Dec 2020)](#release-candidate-18-03-dec-2020)
@ -20,6 +21,46 @@
- [Release Candidate 2 (29 Sep 2019)](#release-candidate-2-29-sep-2019) - [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 1 (26 Sep 2019)](#release-candidate-1-26-sep-2019)
## Release Candidate 21 (TBD)
#### Additions
* Nether Wart Blocks can now be turned into Nether Warts using a Grind Stone
* Added an option to allow Talismans to send their notifications via the Actionbar
* (API) Added support for nested Categories
* (API) Added ExplosiveToolBreakBlocksEvent
* Added an option to enable/disable water in the nether via a crucible
* /sf versions now shows the Java version and some useful tooltips
#### Changes
* Deprecated Automatic Crafting Chamber
* Performance Improvements and Optimizations for Cobblestone/Stone/Basalt generators and mining androids
* Androids operating on a Cobblestone/Stone/Basalt generator now work faster
* (API) Improvements to the BlockBreakHandler
* (API) Deprecated SlimefunBlockHandler
#### Fixes
* Fixed #2794
* Fixed #2793
* Fixed #2809
* Fixed a small exception which gets thrown when Slimefun is disabled due to an invalid environment
* Fixed #2810
* Fixed #2804
* Fixed #2817
* Fixed exceptions with inventories not being printed using the logger of the addon that caused it
* Fixed #2818
* Fixed a duplication glitch with the Woodcutter Android
* Fixed #2839
* Fixed #2849
* Fixed #2851
* Fixed #2852
* Fixed some issues with the Book Binder
* Fixed #2805
* Fixed #2861
* Fixed #2856
* Fixed #2876
* Fixed #2877
* Fixed #2878
## Release Candidate 20 (30 Jan 2021) ## Release Candidate 20 (30 Jan 2021)
#### Additions #### Additions
@ -36,6 +77,8 @@
#### Fixes #### Fixes
* Fixed elevator floor order * Fixed elevator floor order
* Fixed "block-explosions" (e.g. beds in Nether) not properly respecting explosion-resistant blocks
* Fixed #2560
* Fixed #2449 * Fixed #2449
* Fixed #2511 * Fixed #2511
* Fixed #2636 * Fixed #2636
@ -54,6 +97,7 @@
* Fixed #2760 * Fixed #2760
* Fixed #2771 * Fixed #2771
* Fixed placeholders that did not get loaded yet not having a label * Fixed placeholders that did not get loaded yet not having a label
* Fixed #2679
## Release Candidate 19 (11 Jan 2021) ## Release Candidate 19 (11 Jan 2021)
@ -64,6 +108,7 @@
#### Changes #### Changes
* Performance optimizations for Cargo networks * Performance optimizations for Cargo networks
* Removed an old version of bStats * Removed an old version of bStats
* General performance improvements
* CraftBukkit is officially no longer supported, Slimefun will now be disabled on old builds of CraftBukkit * CraftBukkit is officially no longer supported, Slimefun will now be disabled on old builds of CraftBukkit
* Removed the deprecated ItemManipulationAPI for BlockMenus * Removed the deprecated ItemManipulationAPI for BlockMenus
* Removed the "Written Book" variant of the Slimefun Guide * Removed the "Written Book" variant of the Slimefun Guide

View File

@ -67,7 +67,7 @@ Well, we asked some users on our [Discord server](#discord) to send us some scre
| *Screenshot provided by GalaxyKat11#3816* | *Screenshot provided by TamThan#7987* | *Screenshot provided by Kilaruna#4981* | | *Screenshot provided by GalaxyKat11#3816* | *Screenshot provided by TamThan#7987* | *Screenshot provided by Kilaruna#4981* |
## Discord ## Discord
You can find Slimefun's community on Discord and connect with **over 3000** users of this plugin from all over the world.<br> You can find Slimefun's community on Discord and connect with **over 4000** users of this plugin from all over the world.<br>
Click the badge down below to join the server for suggestions/questions or other discussions about this plugin.<br> Click the badge down below to join the server for suggestions/questions or other discussions about this plugin.<br>
We are also hosting a community event every so often, join us to find out more.<br> We are also hosting a community event every so often, join us to find out more.<br>
**Important**: We do **not** accept bug reports on discord, please use our [Issue Tracker](https://github.com/Slimefun/Slimefun4/issues) to submit bug reports! **Important**: We do **not** accept bug reports on discord, please use our [Issue Tracker](https://github.com/Slimefun/Slimefun4/issues) to submit bug reports!

146
pom.xml
View File

@ -18,7 +18,10 @@
<url>https://github.com/Slimefun/Slimefun4</url> <url>https://github.com/Slimefun/Slimefun4</url>
<properties> <properties>
<!-- UTF-8 is our standard encoding for source files -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Target Java 8 -->
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
@ -34,68 +37,81 @@
<sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths> <sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
</properties> </properties>
<!-- Bug Tracker -->
<issueManagement> <issueManagement>
<!-- Bug Tracker -->
<system>GitHub Issues</system> <system>GitHub Issues</system>
<url>https://github.com/Slimefun/Slimefun4/issues</url> <url>https://github.com/Slimefun/Slimefun4/issues</url>
</issueManagement> </issueManagement>
<!-- License -->
<licenses> <licenses>
<license> <license>
<!-- License -->
<name>GNU General Public License v3.0</name> <name>GNU General Public License v3.0</name>
<url>https://github.com/Slimefun/Slimefun4/blob/master/LICENSE</url> <url>https://github.com/Slimefun/Slimefun4/blob/master/LICENSE</url>
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>
</licenses> </licenses>
<!-- The repositories which host our dependencies --> <!-- Repositories that host our dependencies -->
<!-- Well, any that aren't found on maven-central. -->
<repositories> <repositories>
<repository> <repository>
<!-- Spigot-API -->
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository> </repository>
<repository> <repository>
<!-- PaperLib -->
<id>paper-repo</id> <id>paper-repo</id>
<url>https://papermc.io/repo/repository/maven-public</url> <url>https://papermc.io/repo/repository/maven-public</url>
</repository> </repository>
<repository> <repository>
<!-- CS-CoreLib2, ItemsAdder -->
<id>jitpack.io</id> <id>jitpack.io</id>
<url>https://jitpack.io</url> <url>https://jitpack.io</url>
</repository> </repository>
<repository> <repository>
<!-- WorldEdit -->
<id>worldedit-repo</id> <id>worldedit-repo</id>
<url>https://maven.sk89q.com/repo</url> <url>https://maven.sk89q.com/repo</url>
</repository> </repository>
<repository> <repository>
<id>codemc-repo</id> <!-- PlaceholderAPI -->
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
<repository>
<id>placeholderapi-repo</id> <id>placeholderapi-repo</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi</url> <url>https://repo.extendedclip.com/content/repositories/placeholderapi</url>
</repository> </repository>
<repository> <repository>
<!-- mcMMO -->
<id>mcmmo-repo</id>
<url>https://nexus.neetgames.com/repository/maven-public</url>
</repository>
<repository>
<!-- ClearLag -->
<id>walshy-public</id> <id>walshy-public</id>
<url>https://repo.walshy.dev/public</url> <url>https://repo.walshy.dev/public</url>
</repository> </repository>
</repositories> </repositories>
<!-- Build settings -->
<build> <build>
<!-- /src/main/java/ contains all sources (production code) -->
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory> <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<!-- /src/test/java/ contains all unit tests (testing code) -->
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory> <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<!-- The default goal for compiling is "clean package" -->
<defaultGoal>clean package</defaultGoal> <defaultGoal>clean package</defaultGoal>
<!-- The name of the final jar --> <!-- The name of the final jar -->
<finalName>${project.name} v${project.version}</finalName> <finalName>${project.name} v${project.version}</finalName>
<plugins> <plugins>
<!-- Compiler plugin -->
<plugin> <plugin>
<!-- Compiler plugin -->
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<excludes> <excludes>
<!-- package info files are only important for Javadocs --> <!-- package info files are only important for Javadocs -->
@ -105,8 +121,8 @@
</configuration> </configuration>
</plugin> </plugin>
<!-- Attach sources -->
<plugin> <plugin>
<!-- Attach sources -->
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version> <version>3.2.1</version>
@ -121,8 +137,8 @@
</executions> </executions>
</plugin> </plugin>
<!-- Plugin for Unit Tests -->
<plugin> <plugin>
<!-- Plugin for Unit Tests -->
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <version>3.0.0-M5</version>
@ -133,15 +149,15 @@
</configuration> </configuration>
</plugin> </plugin>
<!-- Sonarcloud Scanner -->
<plugin> <plugin>
<!-- Sonarcloud Scanner -->
<groupId>org.sonarsource.scanner.maven</groupId> <groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId> <artifactId>sonar-maven-plugin</artifactId>
<version>3.8.0.2131</version> <version>3.8.0.2131</version>
</plugin> </plugin>
<!-- Code Coverage Reports -->
<plugin> <plugin>
<!-- Code Coverage Reports -->
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version> <version>0.8.6</version>
@ -166,8 +182,8 @@
</executions> </executions>
</plugin> </plugin>
<!-- Dependency shading -->
<plugin> <plugin>
<!-- Dependency shading -->
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version> <version>3.2.4</version>
@ -210,8 +226,8 @@
</executions> </executions>
</plugin> </plugin>
<!-- Javadocs Settings -->
<plugin> <plugin>
<!-- Javadocs -->
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version> <version>3.2.0</version>
@ -225,8 +241,8 @@
<detectOfflineLinks>false</detectOfflineLinks> <detectOfflineLinks>false</detectOfflineLinks>
<additionalJOption>-html5</additionalJOption> <additionalJOption>-html5</additionalJOption>
<!-- We can reference the Spigot API in our Javadocs -->
<links> <links>
<!-- We can reference the Spigot API in our Javadocs -->
<link>${spigot.javadocs}</link> <link>${spigot.javadocs}</link>
</links> </links>
@ -315,14 +331,21 @@
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<version>5.7.0</version> <version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.8.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.seeseemelk</groupId> <groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.16</artifactId> <artifactId>MockBukkit-v1.16</artifactId>
<version>0.21.0</version> <version>0.31.0</version>
<scope>test</scope> <scope>test</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<!-- We use javax.annotation instead. Excluding this --> <!-- We use javax.annotation instead. Excluding this -->
@ -332,18 +355,12 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.7.7</version>
<scope>test</scope>
</dependency>
<!-- Shaded packages --> <!-- Shaded packages -->
<dependency> <dependency>
<groupId>com.github.TheBusyBiscuit</groupId> <groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>CS-CoreLib2</artifactId> <artifactId>CS-CoreLib2</artifactId>
<version>0.29.6</version> <version>0.30.2</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -355,10 +372,12 @@
<dependency> <dependency>
<groupId>com.konghq</groupId> <groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId> <artifactId>unirest-java</artifactId>
<version>3.11.10</version> <version>3.11.11</version>
<scope>compile</scope> <scope>compile</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<!-- No need to shade Gson, Spigot does that already -->
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
</exclusion> </exclusion>
@ -368,47 +387,42 @@
<!-- Third party plugin integrations / soft dependencies --> <!-- Third party plugin integrations / soft dependencies -->
<dependency> <dependency>
<groupId>com.sk89q.worldedit</groupId> <groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId> <artifactId>worldedit-core</artifactId>
<version>7.2.2</version> <version>7.2.3</version>
<scope>provided</scope> <scope>provided</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<!-- This one is ignored because it pops up everytime --> <!-- We don't need any of the dependencies -->
<!-- I try to import File... yes, I want java.io.File --> <groupId>*</groupId>
<groupId>de.schlichtherle</groupId> <artifactId>*</artifactId>
<artifactId>truezip</artifactId>
</exclusion> </exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.2.4</version>
<scope>provided</scope>
<exclusions>
<exclusion> <exclusion>
<groupId>net.java.truevfs</groupId> <!-- We don't need any of the dependencies -->
<artifactId>truevfs-profile-default_2.13</artifactId> <groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.gmail.nossr50.mcMMO</groupId> <groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId> <artifactId>mcMMO</artifactId>
<version>2.1.173</version> <version>2.1.181</version>
<scope>provided</scope> <scope>provided</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<!-- We use javax.annotation instead. Excluding this --> <!-- We don't need any of the dependencies -->
<!-- prevents us from using inconsistent annotations --> <groupId>*</groupId>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.sk89q.worldguard</groupId>
<artifactId>worldguard-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sk89q.worldguard</groupId>
<artifactId>worldguard-legacy</artifactId>
</exclusion>
<exclusion>
<!-- We do not want to use the wrong TextComponents by -->
<!-- accident. If we use adventure, then we will add -->
<!-- it ourselves. -->
<groupId>net.kyori</groupId>
<artifactId>*</artifactId> <artifactId>*</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
@ -418,12 +432,12 @@
<artifactId>placeholderapi</artifactId> <artifactId>placeholderapi</artifactId>
<version>2.10.9</version> <version>2.10.9</version>
<scope>provided</scope> <scope>provided</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<!-- We use javax.annotation instead. Excluding this --> <!-- We don't need any of the dependencies -->
<!-- prevents us from using inconsistent annotations --> <groupId>*</groupId>
<groupId>org.jetbrains</groupId> <artifactId>*</artifactId>
<artifactId>annotations</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
@ -432,18 +446,26 @@
<artifactId>clearlag-core</artifactId> <artifactId>clearlag-core</artifactId>
<version>3.1.6</version> <version>3.1.6</version>
<scope>provided</scope> <scope>provided</scope>
<exclusions>
<exclusion>
<!-- We don't need any of the dependencies -->
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.LoneDev6</groupId> <groupId>com.github.LoneDev6</groupId>
<artifactId>itemsadder-api</artifactId> <artifactId>itemsadder-api</artifactId>
<version>2.1.25</version> <version>2.2.1</version>
<scope>provided</scope> <scope>provided</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<!-- We use javax.annotation instead. Excluding this --> <!-- We don't need any of the dependencies -->
<!-- prevents us from using inconsistent annotations --> <groupId>*</groupId>
<groupId>org.jetbrains</groupId> <artifactId>*</artifactId>
<artifactId>annotations</artifactId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>

View File

@ -7,7 +7,7 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter;
/** /**
* An {@link Event} that is called whenever an {@link AutoDisenchanter} has * An {@link Event} that is called whenever an {@link AutoDisenchanter} has

View File

@ -0,0 +1,95 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosiveTool;
import org.apache.commons.lang.Validate;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
/**
* This {@link Event} is called when an {@link ExplosiveTool} is used to break blocks.
*
* @author GallowsDove
*
*/
public class ExplosiveToolBreakBlocksEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final ItemStack itemInHand;
private final ExplosiveTool explosiveTool;
private final List<Block> blocks;
private boolean cancelled;
@ParametersAreNonnullByDefault
public ExplosiveToolBreakBlocksEvent(Player player, List<Block> blocks, ItemStack item, ExplosiveTool explosiveTool) {
super(player);
Validate.notEmpty(blocks, "Blocks cannot be null or empty");
Validate.notNull(item, "Item cannot be null");
Validate.notNull(explosiveTool, "ExplosiveTool cannot be null");
this.blocks = blocks;
this.itemInHand = item;
this.explosiveTool = explosiveTool;
}
/**
* Gets the {@link Block} {@link List} of blocks destroyed in this event.
*
* @return The broken blocks
*/
@Nonnull
public List<Block> getBlocks() {
return this.blocks;
}
/**
* Gets the {@link ExplosiveTool} which triggered this event
*
* @return the {@link ExplosiveTool} that was involved
*/
@Nonnull
public ExplosiveTool getExplosiveTool() {
return this.explosiveTool;
}
/**
* Gets the {@link ItemStack} of the tool used to destroy this block
*
* @return The {@link ItemStack} in the hand of the {@link Player}
*/
@Nonnull
public ItemStack getItemInHand() {
return this.itemInHand;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Nonnull
public static HandlerList getHandlerList() {
return handlers;
}
@Nonnull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -79,6 +79,7 @@ public abstract class Network {
* *
* @param l * @param l
* The {@link Location} to classify * The {@link Location} to classify
*
* @return The assigned type of {@link NetworkComponent} for this {@link Location} * @return The assigned type of {@link NetworkComponent} for this {@link Location}
*/ */
@Nullable @Nullable

View File

@ -64,12 +64,14 @@ public final class SlimefunRegistry {
private final List<String> researchRanks = new ArrayList<>(); private final List<String> researchRanks = new ArrayList<>();
private final Set<UUID> researchingPlayers = Collections.synchronizedSet(new HashSet<>()); private final Set<UUID> researchingPlayers = Collections.synchronizedSet(new HashSet<>());
// TODO: Move this all into a proper "config cache" class
private boolean backwardsCompatibility; private boolean backwardsCompatibility;
private boolean automaticallyLoadItems; private boolean automaticallyLoadItems;
private boolean enableResearches; private boolean enableResearches;
private boolean freeCreativeResearches; private boolean freeCreativeResearches;
private boolean researchFireworks; private boolean researchFireworks;
private boolean logDuplicateBlockEntries; private boolean logDuplicateBlockEntries;
private boolean talismanActionBarMessages;
private final Set<String> tickers = new HashSet<>(); private final Set<String> tickers = new HashSet<>();
private final Set<SlimefunItem> radioactive = new HashSet<>(); private final Set<SlimefunItem> radioactive = new HashSet<>();
@ -110,6 +112,7 @@ public final class SlimefunRegistry {
freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode"); freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode");
researchFireworks = cfg.getBoolean("researches.enable-fireworks"); researchFireworks = cfg.getBoolean("researches.enable-fireworks");
logDuplicateBlockEntries = cfg.getBoolean("options.log-duplicate-block-entries"); logDuplicateBlockEntries = cfg.getBoolean("options.log-duplicate-block-entries");
talismanActionBarMessages = cfg.getBoolean("talismans.use-actionbar");
} }
/** /**
@ -330,6 +333,7 @@ public final class SlimefunRegistry {
return globalItemHandlers; return globalItemHandlers;
} }
@Deprecated
@Nonnull @Nonnull
public Map<String, SlimefunBlockHandler> getBlockHandlers() { public Map<String, SlimefunBlockHandler> getBlockHandlers() {
return blockHandlers; return blockHandlers;
@ -354,6 +358,10 @@ public final class SlimefunRegistry {
return logDuplicateBlockEntries; return logDuplicateBlockEntries;
} }
public boolean useActionbarForTalismans() {
return talismanActionBarMessages;
}
@Nonnull @Nonnull
public NamespacedKey getSoulboundDataKey() { public NamespacedKey getSoulboundDataKey() {
return soulboundKey; return soulboundKey;

View File

@ -19,7 +19,6 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* Represents a {@link Category} that cannot be opened until the parent category/categories * Represents a {@link Category} that cannot be opened until the parent category/categories
@ -153,14 +152,13 @@ public class LockedCategory extends Category {
* @return Whether the {@link Player} has fully completed all parent categories, otherwise false * @return Whether the {@link Player} has fully completed all parent categories, otherwise false
*/ */
public boolean hasUnlocked(@Nonnull Player p, @Nonnull PlayerProfile profile) { public boolean hasUnlocked(@Nonnull Player p, @Nonnull PlayerProfile profile) {
Validate.notNull(p, "The player cannot be null!");
Validate.notNull(profile, "The Profile cannot be null!");
for (Category category : parents) { for (Category category : parents) {
for (SlimefunItem item : category.getItems()) { for (SlimefunItem item : category.getItems()) {
/* // Check if the Player has researched every item (if the item is enabled)
* Should probably be replaced with Slimefun.hasUnlocked(...) if (!item.isDisabledIn(p.getWorld()) && item.hasResearch() && !profile.hasUnlocked(item.getResearch())) {
* However this will result in better performance because we don't
* request the PlayerProfile everytime
*/
if (Slimefun.isEnabled(p, item, false) && Slimefun.hasPermission(p, item, false) && !profile.hasUnlocked(item.getResearch())) {
return false; return false;
} }
} }

View File

@ -0,0 +1,138 @@
package io.github.thebusybiscuit.slimefun4.core.categories;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
public class MultiCategory extends FlexCategory {
private static final int CATEGORY_SIZE = 36;
private final List<SubCategory> subCategories = new ArrayList<>();
@ParametersAreNonnullByDefault
public MultiCategory(NamespacedKey key, ItemStack item) {
this(key, item, 3);
}
@ParametersAreNonnullByDefault
public MultiCategory(NamespacedKey key, ItemStack item, int tier) {
super(key, item, tier);
}
/**
* This will add the given {@link SubCategory} to this {@link MultiCategory}.
*
* @param category
* The {@link SubCategory} to add.
*/
public void addSubCategory(@Nonnull SubCategory category) {
Validate.notNull(category, "The Category cannot be null!");
subCategories.add(category);
}
/**
* This will remove the given {@link SubCategory} from this {@link MultiCategory} (if present).
*
* @param category
* The {@link SubCategory} to remove.
*/
public void removeSubCategory(@Nonnull SubCategory category) {
Validate.notNull(category, "The Category cannot be null!");
subCategories.remove(category);
}
@Override
@ParametersAreNonnullByDefault
public boolean isVisible(Player p, PlayerProfile profile, SlimefunGuideMode mode) {
return true;
}
@Override
@ParametersAreNonnullByDefault
public void open(Player p, PlayerProfile profile, SlimefunGuideMode mode) {
openGuide(p, profile, mode, 1);
}
@ParametersAreNonnullByDefault
private void openGuide(Player p, PlayerProfile profile, SlimefunGuideMode mode, int page) {
if (mode == SlimefunGuideMode.SURVIVAL_MODE) {
profile.getGuideHistory().add(this, page);
}
ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocalization().getMessage(p, "guide.title.main"));
SurvivalSlimefunGuide guide = (SurvivalSlimefunGuide) SlimefunPlugin.getRegistry().getSlimefunGuide(mode);
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), guide.getSound(), 1, 1));
guide.createHeader(p, profile, menu);
menu.addItem(1, new CustomItem(ChestMenuUtils.getBackButton(p, "", ChatColor.GRAY + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide"))));
menu.addMenuClickHandler(1, (pl, s, is, action) -> {
SlimefunGuide.openMainMenu(profile, mode, 1);
return false;
});
int index = 9;
int target = (CATEGORY_SIZE * (page - 1)) - 1;
while (target < (subCategories.size() - 1) && index < CATEGORY_SIZE + 9) {
target++;
SubCategory category = subCategories.get(target);
menu.addItem(index, category.getItem(p));
menu.addMenuClickHandler(index, (pl, slot, item, action) -> {
SlimefunGuide.openCategory(profile, category, mode, 1);
return false;
});
index++;
}
int pages = target == subCategories.size() - 1 ? page : (subCategories.size() - 1) / CATEGORY_SIZE + 1;
menu.addItem(46, ChestMenuUtils.getPreviousButton(p, page, pages));
menu.addMenuClickHandler(46, (pl, slot, item, action) -> {
int next = page - 1;
if (next != page && next > 0) {
openGuide(p, profile, mode, next);
}
return false;
});
menu.addItem(52, ChestMenuUtils.getNextButton(p, page, pages));
menu.addMenuClickHandler(52, (pl, slot, item, action) -> {
int next = page + 1;
if (next != page && next <= pages) {
openGuide(p, profile, mode, next);
}
return false;
});
menu.open(p);
}
}

View File

@ -0,0 +1,65 @@
package io.github.thebusybiscuit.slimefun4.core.categories;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import me.mrCookieSlime.Slimefun.Objects.Category;
/**
* The {@link SubCategory} is a child {@link Category} of the
* {@link MultiCategory}.
*
* @author TheBusyBiscuit
*
* @see MultiCategory
*
*/
public class SubCategory extends Category {
private final MultiCategory multiCategory;
@ParametersAreNonnullByDefault
public SubCategory(NamespacedKey key, MultiCategory parent, ItemStack item) {
this(key, parent, item, 3);
}
@ParametersAreNonnullByDefault
public SubCategory(NamespacedKey key, MultiCategory parent, ItemStack item, int tier) {
super(key, item, tier);
Validate.notNull(parent, "The parent category cannot be null");
multiCategory = parent;
parent.addSubCategory(this);
}
@Override
public final boolean isHidden(@Nonnull Player p) {
/*
* Sub Categories are always hidden,
* they won't show up in the normal guide view.
*/
return true;
}
@Nonnull
public final MultiCategory getParent() {
return multiCategory;
}
@Override
public final void register(@Nonnull SlimefunAddon addon) {
super.register(addon);
if (!multiCategory.isRegistered()) {
multiCategory.register(addon);
}
}
}

View File

@ -3,18 +3,30 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Collection; import java.util.Collection;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Text;
/**
* This is our class for the /sf versions subcommand.
*
* @author TheBusyBiscuit
* @author Walshy
*
*/
class VersionsCommand extends SubCommand { class VersionsCommand extends SubCommand {
VersionsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { VersionsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
@ -24,39 +36,171 @@ class VersionsCommand extends SubCommand {
@Override @Override
public void onExecute(@Nonnull CommandSender sender, @Nonnull String[] args) { public void onExecute(@Nonnull CommandSender sender, @Nonnull String[] args) {
if (sender.hasPermission("slimefun.command.versions") || sender instanceof ConsoleCommandSender) { if (sender.hasPermission("slimefun.command.versions") || sender instanceof ConsoleCommandSender) {
// After all these years... Spigot still displays as "CraftBukkit" /*
// so we will just fix this inconsistency for them :) * After all these years... Spigot still displays as "CraftBukkit".
* so we will just fix this inconsistency for them :)
*/
String serverSoftware = PaperLib.isSpigot() && !PaperLib.isPaper() ? "Spigot" : Bukkit.getName(); String serverSoftware = PaperLib.isSpigot() && !PaperLib.isPaper() ? "Spigot" : Bukkit.getName();
ComponentBuilder builder = new ComponentBuilder();
sender.sendMessage(ChatColor.GRAY + "This Server uses the following setup of Slimefun:"); // @formatter:off
sender.sendMessage(ChatColors.color("&a" + serverSoftware + " &2" + Bukkit.getVersion())); builder.append("This Server uses the following setup of Slimefun:\n")
sender.sendMessage(ChatColors.color("&aSlimefun &2v" + SlimefunPlugin.getVersion())); .color(ChatColor.GRAY)
.append(serverSoftware)
.color(ChatColor.GREEN)
.append(" " + Bukkit.getVersion() + '\n')
.color(ChatColor.DARK_GREEN)
.append("Slimefun ")
.color(ChatColor.GREEN)
.append(SlimefunPlugin.getVersion() + '\n')
.color(ChatColor.DARK_GREEN);
// @formatter:on
if (SlimefunPlugin.getMetricsService().getVersion() != null) { if (SlimefunPlugin.getMetricsService().getVersion() != null) {
sender.sendMessage(ChatColors.color("&aMetrics build: &2#" + SlimefunPlugin.getMetricsService().getVersion())); // @formatter:off
builder.append("Metrics-Module ")
.color(ChatColor.GREEN)
.append("#" + SlimefunPlugin.getMetricsService().getVersion() + '\n')
.color(ChatColor.DARK_GREEN);
// @formatter:on
} }
addJavaVersion(builder);
if (SlimefunPlugin.getRegistry().isBackwardsCompatible()) { if (SlimefunPlugin.getRegistry().isBackwardsCompatible()) {
sender.sendMessage(ChatColor.RED + "Backwards compatibility enabled!"); // @formatter:off
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(
"Backwards compatibility has a negative impact on performance!\n" +
"We recommend you to disable this setting unless your server still " +
"has legacy Slimefun items (from before summer 2019) in circulation."
));
// @formatter:on
builder.append("\nBackwards compatibility enabled!\n").color(ChatColor.RED).event(hoverEvent);
} }
sender.sendMessage(""); builder.append("\n").event((HoverEvent) null);
addPluginVersions(builder);
Collection<Plugin> addons = SlimefunPlugin.getInstalledAddons(); sender.spigot().sendMessage(builder.create());
sender.sendMessage(ChatColors.color("&7Installed Addons: &8(" + addons.size() + ")"));
for (Plugin plugin : addons) {
String version = plugin.getDescription().getVersion();
if (Bukkit.getPluginManager().isPluginEnabled(plugin)) {
sender.sendMessage(ChatColor.GREEN + " " + plugin.getName() + ChatColor.DARK_GREEN + " v" + version);
} else {
sender.sendMessage(ChatColor.RED + " " + plugin.getName() + ChatColor.DARK_RED + " v" + version);
}
}
} else { } else {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true); SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
} }
} }
private void addJavaVersion(@Nonnull ComponentBuilder builder) {
String javaVer = System.getProperty("java.version");
if (javaVer.startsWith("1.")) {
javaVer = javaVer.substring(2);
}
// If it's like 11.0.1.3 or 8.0_275
if (javaVer.indexOf('.') != -1) {
javaVer = javaVer.substring(0, javaVer.indexOf('.'));
}
int version = Integer.parseInt(javaVer);
if (version < 11) {
// @formatter:off
builder.append("Java " + version).color(ChatColor.RED)
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(
"Your Java version is out of date!\n!" +
"You should use Java 11 or higher.\n" +
"Paper will be dropping support for older versions with the release of Minecraft 1.17."
)))
.append("\n")
.event((HoverEvent) null);
// @formatter:on
} else {
builder.append("Java ").color(ChatColor.GREEN).append(version + "\n").color(ChatColor.DARK_GREEN);
}
}
private void addPluginVersions(@Nonnull ComponentBuilder builder) {
Collection<Plugin> addons = SlimefunPlugin.getInstalledAddons();
if (addons.isEmpty()) {
builder.append("No Addons installed").color(ChatColor.GRAY).italic(true);
return;
}
builder.append("Installed Addons: ").color(ChatColor.GRAY).append("(" + addons.size() + ")").color(ChatColor.DARK_GRAY);
for (Plugin plugin : addons) {
String version = plugin.getDescription().getVersion();
HoverEvent hoverEvent = null;
ClickEvent clickEvent = null;
ChatColor primaryColor;
ChatColor secondaryColor;
if (Bukkit.getPluginManager().isPluginEnabled(plugin)) {
primaryColor = ChatColor.GREEN;
secondaryColor = ChatColor.DARK_GREEN;
String authors = String.join(", ", plugin.getDescription().getAuthors());
if (plugin instanceof SlimefunAddon && ((SlimefunAddon) plugin).getBugTrackerURL() != null) {
// @formatter:off
hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder()
.append("Author(s): ")
.append(authors)
.color(ChatColor.YELLOW)
.append("\n> Click here to go to their issues tracker")
.color(ChatColor.GOLD)
.create()
));
// @formatter:on
clickEvent = new ClickEvent(ClickEvent.Action.OPEN_URL, ((SlimefunAddon) plugin).getBugTrackerURL());
} else {
// @formatter:off
hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder()
.append("Author(s): ")
.append(authors)
.color(ChatColor.YELLOW)
.create()
));
// @formatter:on
}
} else {
primaryColor = ChatColor.RED;
secondaryColor = ChatColor.DARK_RED;
if (plugin instanceof SlimefunAddon && ((SlimefunAddon) plugin).getBugTrackerURL() != null) {
// @formatter:off
hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder()
.append("This plugin is disabled.\nCheck the console for an error message.")
.color(ChatColor.RED)
.append("\n> Click here to report on their issues tracker")
.color(ChatColor.DARK_RED)
.create()
));
// @formatter:on
SlimefunAddon addon = (SlimefunAddon) plugin;
if (addon.getBugTrackerURL() != null) {
clickEvent = new ClickEvent(ClickEvent.Action.OPEN_URL, addon.getBugTrackerURL());
}
} else {
hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Plugin is disabled. Check the console for an error and report on their issues tracker."));
}
}
// @formatter:off
// We need to reset the hover event or it's added to all components
builder.append("\n " + plugin.getName())
.color(primaryColor)
.event(hoverEvent)
.event(clickEvent)
.append(" v" + version)
.color(secondaryColor)
.append("")
.event((ClickEvent) null)
.event((HoverEvent) null);
// @formatter:on
}
}
} }

View File

@ -2,18 +2,103 @@ package io.github.thebusybiscuit.slimefun4.core.handlers;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
import io.github.thebusybiscuit.slimefun4.implementation.items.androids.MinerAndroid;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler; import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
@FunctionalInterface /**
public interface BlockBreakHandler extends ItemHandler { * The {@link BlockBreakHandler} is called when a {@link Block} is broken
* which holds a {@link SlimefunItem}.
* The {@link BlockBreakHandler} provides three methods for this, one for block breaking
* caused by a {@link Player}, one for a {@link MinerAndroid} and one method for a {@link Block}
* being destroyed by an explosion.
*
* @author TheBusyBiscuit
*
* @see BlockPlaceHandler
*
*/
public abstract class BlockBreakHandler implements ItemHandler {
boolean onBlockBreak(BlockBreakEvent e, ItemStack item, int fortune, List<ItemStack> drops); /**
* Whether a {@link MinerAndroid} is allowed to break this block.
*/
private final boolean allowAndroids;
/**
* Whether an explosion is allowed to destroy this block.
*/
private final boolean allowExplosions;
/**
* This constructs a new {@link BlockBreakHandler}.
*
* @param allowAndroids
* Whether a {@link MinerAndroid} is allowed to break blocks of this type
* @param allowExplosions
* Whether blocks of this type are allowed to be broken by explosions
*/
public BlockBreakHandler(boolean allowAndroids, boolean allowExplosions) {
this.allowAndroids = allowAndroids;
this.allowExplosions = allowExplosions;
}
@ParametersAreNonnullByDefault
public abstract void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops);
@ParametersAreNonnullByDefault
public void onExplode(Block b, List<ItemStack> drops) {
// This can be overridden, if necessary
}
@ParametersAreNonnullByDefault
public void onAndroidBreak(AndroidMineEvent e) {
// This can be overridden, if necessary
}
/**
* This returns whether an explosion is able to break the given {@link Block}.
*
* @param b
* The {@link Block}
* @return Whether explosions can destroy this {@link Block}
*/
public boolean isExplosionAllowed(@Nonnull Block b) {
/*
* By default our flag is returned, but you can override it
* to be handled on a per-Block basis.
*/
return allowExplosions;
}
/**
* This returns whether a {@link MinerAndroid} is allowed to break
* the given {@link Block}.
*
* @param b
* The {@link Block}
*
* @return Whether androids can break the given {@link Block}
*/
public boolean isAndroidAllowed(@Nonnull Block b) {
/*
* By default our flag is returned, but you can override it
* to be handled on a per-Block basis.
*/
return allowAndroids;
}
@Override @Override
default Class<? extends ItemHandler> getIdentifier() { public final Class<? extends ItemHandler> getIdentifier() {
return BlockBreakHandler.class; return BlockBreakHandler.class;
} }
} }

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.handlers; package io.github.thebusybiscuit.slimefun4.core.handlers;
import javax.annotation.Nonnull;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
@ -31,7 +33,7 @@ public abstract class BlockPlaceHandler implements ItemHandler {
* @param e * @param e
* The corresponding {@link BlockPlaceEvent} * The corresponding {@link BlockPlaceEvent}
*/ */
public abstract void onPlayerPlace(BlockPlaceEvent e); public abstract void onPlayerPlace(@Nonnull BlockPlaceEvent e);
/** /**
* This method is called whenever a {@link BlockPlacer} places this {@link Block}. * This method is called whenever a {@link BlockPlacer} places this {@link Block}.
@ -42,7 +44,7 @@ public abstract class BlockPlaceHandler implements ItemHandler {
* @param e * @param e
* The corresponding {@link BlockPlacerPlaceEvent} * The corresponding {@link BlockPlacerPlaceEvent}
*/ */
public void onBlockPlacerPlace(BlockPlacerPlaceEvent e) { public void onBlockPlacerPlace(@Nonnull BlockPlacerPlaceEvent e) {
// This can be overridden, if necessary // This can be overridden, if necessary
} }
@ -56,7 +58,7 @@ public abstract class BlockPlaceHandler implements ItemHandler {
} }
@Override @Override
public Class<? extends ItemHandler> getIdentifier() { public final Class<? extends ItemHandler> getIdentifier() {
return BlockPlaceHandler.class; return BlockPlaceHandler.class;
} }
} }

View File

@ -6,6 +6,7 @@ import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Material; import org.bukkit.Material;
@ -26,12 +27,12 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.MultiBlockInteractionHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.MultiBlockInteractionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.OutputChest;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
@ -51,6 +52,7 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
protected final List<ItemStack> displayRecipes; protected final List<ItemStack> displayRecipes;
protected final MultiBlock multiblock; protected final MultiBlock multiblock;
@ParametersAreNonnullByDefault
public MultiBlockMachine(Category category, SlimefunItemStack item, ItemStack[] recipe, ItemStack[] machineRecipes, BlockFace trigger) { public MultiBlockMachine(Category category, SlimefunItemStack item, ItemStack[] recipe, ItemStack[] machineRecipes, BlockFace trigger) {
super(category, item, RecipeType.MULTIBLOCK, recipe); super(category, item, RecipeType.MULTIBLOCK, recipe);
this.recipes = new ArrayList<>(); this.recipes = new ArrayList<>();
@ -61,6 +63,7 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
registerDefaultRecipes(displayRecipes); registerDefaultRecipes(displayRecipes);
} }
@ParametersAreNonnullByDefault
public MultiBlockMachine(Category category, SlimefunItemStack item, ItemStack[] recipe, BlockFace trigger) { public MultiBlockMachine(Category category, SlimefunItemStack item, ItemStack[] recipe, BlockFace trigger) {
this(category, item, recipe, new ItemStack[0], trigger); this(category, item, recipe, new ItemStack[0], trigger);
} }
@ -114,10 +117,11 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
} }
} }
@Nonnull
protected MultiBlockInteractionHandler getInteractionHandler() { protected MultiBlockInteractionHandler getInteractionHandler() {
return (p, mb, b) -> { return (p, mb, b) -> {
if (mb.equals(getMultiBlock())) { if (mb.equals(getMultiBlock())) {
if (!isDisabled() && SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK) && Slimefun.hasUnlocked(p, this, true)) { if (canUse(p, true) && SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK)) {
onInteract(p, b); onInteract(p, b);
} }
@ -142,17 +146,25 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
* The {@link Block} of our {@link Dispenser} * The {@link Block} of our {@link Dispenser}
* @param dispInv * @param dispInv
* The {@link Inventory} of our {@link Dispenser} * The {@link Inventory} of our {@link Dispenser}
*
* @return The target {@link Inventory} * @return The target {@link Inventory}
*/ */
@Nullable
@ParametersAreNonnullByDefault
protected Inventory findOutputInventory(ItemStack adding, Block dispBlock, Inventory dispInv) { protected Inventory findOutputInventory(ItemStack adding, Block dispBlock, Inventory dispInv) {
return findOutputInventory(adding, dispBlock, dispInv, dispInv); return findOutputInventory(adding, dispBlock, dispInv, dispInv);
} }
@Nullable
@ParametersAreNonnullByDefault
protected Inventory findOutputInventory(ItemStack product, Block dispBlock, Inventory dispInv, Inventory placeCheckerInv) { protected Inventory findOutputInventory(ItemStack product, Block dispBlock, Inventory dispInv, Inventory placeCheckerInv) {
Inventory outputInv = findOutputChest(dispBlock, product); Inventory outputInv = findOutputChest(dispBlock, product);
// This if-clause will trigger if no suitable output chest was found. It's functionally the same as the old fit /*
// check for the dispenser, only refactored. * This if-clause will trigger if no suitable output chest was found.
* It's functionally the same as the old fit check for the dispenser,
* only refactored.
*/
if (outputInv == null && InvUtils.fits(placeCheckerInv, product)) { if (outputInv == null && InvUtils.fits(placeCheckerInv, product)) {
return dispInv; return dispInv;
} else { } else {
@ -166,9 +178,9 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
Block potentialOutput = b.getRelative(face); Block potentialOutput = b.getRelative(face);
if (potentialOutput.getType() == Material.CHEST) { if (potentialOutput.getType() == Material.CHEST) {
String id = BlockStorage.checkID(potentialOutput); SlimefunItem slimefunItem = BlockStorage.check(potentialOutput);
if (id != null && id.equals("OUTPUT_CHEST")) { if (slimefunItem instanceof OutputChest) {
// Found the output chest! Now, let's check if we can fit the product in it. // Found the output chest! Now, let's check if we can fit the product in it.
BlockState state = PaperLib.getBlockState(potentialOutput, false).getState(); BlockState state = PaperLib.getBlockState(potentialOutput, false).getState();
@ -187,7 +199,7 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
} }
@Nonnull @Nonnull
private static Material[] convertItemStacksToMaterial(ItemStack[] items) { private static Material[] convertItemStacksToMaterial(@Nonnull ItemStack[] items) {
List<Material> materials = new ArrayList<>(); List<Material> materials = new ArrayList<>();
for (ItemStack item : items) { for (ItemStack item : items) {

View File

@ -115,14 +115,14 @@ abstract class AbstractItemNetwork extends Network {
if (menu != null) { if (menu != null) {
switch (request.getDirection()) { switch (request.getDirection()) {
case INSERT: case INSERT:
distributeInsertionRequest(inventories, request, menu, iterator, destinations); distributeInsertionRequest(inventories, request, menu, iterator, destinations);
break; break;
case WITHDRAW: case WITHDRAW:
collectExtractionRequest(inventories, request, menu, iterator, providers); collectExtractionRequest(inventories, request, menu, iterator, providers);
break; break;
default: default:
break; break;
} }
} }
} }

View File

@ -92,19 +92,19 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
} }
switch (id) { switch (id) {
case "CARGO_MANAGER": case "CARGO_MANAGER":
return NetworkComponent.REGULATOR; return NetworkComponent.REGULATOR;
case "CARGO_NODE": case "CARGO_NODE":
return NetworkComponent.CONNECTOR; return NetworkComponent.CONNECTOR;
case "CARGO_NODE_INPUT": case "CARGO_NODE_INPUT":
case "CARGO_NODE_OUTPUT": case "CARGO_NODE_OUTPUT":
case "CARGO_NODE_OUTPUT_ADVANCED": case "CARGO_NODE_OUTPUT_ADVANCED":
case "CT_IMPORT_BUS": case "CT_IMPORT_BUS":
case "CT_EXPORT_BUS": case "CT_EXPORT_BUS":
case "CHEST_TERMINAL": case "CHEST_TERMINAL":
return NetworkComponent.TERMINUS; return NetworkComponent.TERMINUS;
default: default:
return null; return null;
} }
} }
@ -123,24 +123,24 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
if (to == NetworkComponent.TERMINUS) { if (to == NetworkComponent.TERMINUS) {
String id = BlockStorage.checkID(l); String id = BlockStorage.checkID(l);
switch (id) { switch (id) {
case "CARGO_NODE_INPUT": case "CARGO_NODE_INPUT":
inputNodes.add(l); inputNodes.add(l);
break; break;
case "CARGO_NODE_OUTPUT": case "CARGO_NODE_OUTPUT":
case "CARGO_NODE_OUTPUT_ADVANCED": case "CARGO_NODE_OUTPUT_ADVANCED":
outputNodes.add(l); outputNodes.add(l);
break; break;
case "CHEST_TERMINAL": case "CHEST_TERMINAL":
terminals.add(l); terminals.add(l);
break; break;
case "CT_IMPORT_BUS": case "CT_IMPORT_BUS":
imports.add(l); imports.add(l);
break; break;
case "CT_EXPORT_BUS": case "CT_EXPORT_BUS":
exports.add(l); exports.add(l);
break; break;
default: default:
break; break;
} }
} }
} }

View File

@ -5,8 +5,10 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.logging.Level;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
@ -15,6 +17,7 @@ import org.bukkit.block.Block;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager; import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -63,31 +66,35 @@ class CargoNetworkTask implements Runnable {
public void run() { public void run() {
long timestamp = System.nanoTime(); long timestamp = System.nanoTime();
// Chest Terminal Code try {
if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) { // Chest Terminal Code
network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs); if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) {
} network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs);
}
/** /**
* All operations happen here: Everything gets iterated from the Input Nodes. * All operations happen here: Everything gets iterated from the Input Nodes.
* (Apart from ChestTerminal Buses) * (Apart from ChestTerminal Buses)
*/ */
SlimefunItem inputNode = SlimefunItems.CARGO_INPUT_NODE.getItem(); SlimefunItem inputNode = SlimefunItems.CARGO_INPUT_NODE.getItem();
for (Map.Entry<Location, Integer> entry : inputs.entrySet()) { for (Map.Entry<Location, Integer> entry : inputs.entrySet()) {
long nodeTimestamp = System.nanoTime(); long nodeTimestamp = System.nanoTime();
Location input = entry.getKey(); Location input = entry.getKey();
Optional<Block> attachedBlock = network.getAttachedBlock(input); Optional<Block> attachedBlock = network.getAttachedBlock(input);
attachedBlock.ifPresent(block -> routeItems(input, block, entry.getValue(), outputs)); attachedBlock.ifPresent(block -> routeItems(input, block, entry.getValue(), outputs));
// This will prevent this timings from showing up for the Cargo Manager // This will prevent this timings from showing up for the Cargo Manager
timestamp += SlimefunPlugin.getProfiler().closeEntry(entry.getKey(), inputNode, nodeTimestamp); timestamp += SlimefunPlugin.getProfiler().closeEntry(entry.getKey(), inputNode, nodeTimestamp);
} }
// Chest Terminal Code // Chest Terminal Code
if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) { if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) {
// This will deduct any CT timings and attribute them towards the actual terminal // This will deduct any CT timings and attribute them towards the actual terminal
timestamp += network.updateTerminals(chestTerminalInputs); timestamp += network.updateTerminals(chestTerminalInputs);
}
} catch (Exception | LinkageError x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception was caught while ticking a Cargo network @ " + new BlockPosition(network.getRegulator()));
} }
// Submit a timings report // Submit a timings report
@ -150,7 +157,7 @@ class CargoNetworkTask implements Runnable {
Deque<Location> destinations = new LinkedList<>(outputNodes); Deque<Location> destinations = new LinkedList<>(outputNodes);
Config cfg = BlockStorage.getLocationInfo(inputNode); Config cfg = BlockStorage.getLocationInfo(inputNode);
boolean roundrobin = "true".equals(cfg.getString("round-robin")); boolean roundrobin = Objects.equals(cfg.getString("round-robin"), "true");
if (roundrobin) { if (roundrobin) {
roundRobinSort(inputNode, destinations); roundRobinSort(inputNode, destinations);

View File

@ -68,19 +68,19 @@ final class CargoUtils {
Material type = block.getType(); Material type = block.getType();
switch (type) { switch (type) {
case CHEST: case CHEST:
case TRAPPED_CHEST: case TRAPPED_CHEST:
case FURNACE: case FURNACE:
case DISPENSER: case DISPENSER:
case DROPPER: case DROPPER:
case HOPPER: case HOPPER:
case BREWING_STAND: case BREWING_STAND:
case BARREL: case BARREL:
case BLAST_FURNACE: case BLAST_FURNACE:
case SMOKER: case SMOKER:
return true; return true;
default: default:
return SlimefunTag.SHULKER_BOXES.isTagged(type); return SlimefunTag.SHULKER_BOXES.isTagged(type);
} }
} }
@ -240,11 +240,11 @@ final class CargoUtils {
int maxSlot = range[1]; int maxSlot = range[1];
for (int slot = minSlot; slot < maxSlot; slot++) { for (int slot = minSlot; slot < maxSlot; slot++) {
ItemStack is = contents[slot]; ItemStack item = contents[slot];
if (matchesFilter(network, node, is)) { if (matchesFilter(network, node, item)) {
inv.setItem(slot, null); inv.setItem(slot, null);
return new ItemStackAndInteger(is, slot); return new ItemStackAndInteger(item, slot);
} }
} }

View File

@ -11,6 +11,7 @@ import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.CargoNode;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
@ -81,23 +82,45 @@ class ItemFilter implements Predicate<ItemStack> {
SlimefunItem item = SlimefunItem.getByID(id); SlimefunItem item = SlimefunItem.getByID(id);
BlockMenu menu = BlockStorage.getInventory(b.getLocation()); BlockMenu menu = BlockStorage.getInventory(b.getLocation());
if (item == null || menu == null) { if (!(item instanceof CargoNode) || menu == null) {
// Don't filter for a non-existing item (safety check) // Don't filter for a non-existing item (safety check)
clear(false); clear(false);
} else if (id.equals("CARGO_NODE_OUTPUT")) {
// Output Nodes have no filter, allow everything
clear(true);
} else { } else {
this.items.clear(); try {
this.checkLore = Objects.equals(blockData.getString("filter-lore"), "true"); CargoNode node = (CargoNode) item;
this.rejectOnMatch = !Objects.equals(blockData.getString("filter-type"), "whitelist");
for (int slot : CargoUtils.getFilteringSlots()) { if (!node.hasItemFilter()) {
ItemStack stack = menu.getItemInSlot(slot); // Node does not have a filter, allow everything
clear(true);
} else {
int[] slots = CargoUtils.getFilteringSlots();
int inventorySize = menu.toInventory().getSize();
if (stack != null && stack.getType() != Material.AIR) { if (inventorySize < slots[slots.length - 1]) {
this.items.add(new ItemStackWrapper(stack)); /*
* Related to #2876
* The reason was a missing negation int he filtering statement above.
* However if that ever happens again, we will know the reason and be able
* to send a warning in response to it.
*/
item.warn("Cargo Node was marked as a 'filtering' node but has an insufficient inventory size (" + inventorySize + ")");
return;
}
this.items.clear();
this.checkLore = Objects.equals(blockData.getString("filter-lore"), "true");
this.rejectOnMatch = !Objects.equals(blockData.getString("filter-type"), "whitelist");
for (int slot : slots) {
ItemStack stack = menu.getItemInSlot(slot);
if (stack != null && stack.getType() != Material.AIR) {
this.items.add(new ItemStackWrapper(stack));
}
}
} }
} catch (Exception | LinkageError x) {
item.error("Something went wrong while updating the ItemFilter for this cargo node.", x);
} }
} }

View File

@ -75,14 +75,14 @@ public class EnergyNet extends Network implements HologramOwner {
return null; return null;
} else { } else {
switch (component.getEnergyComponentType()) { switch (component.getEnergyComponentType()) {
case CONNECTOR: case CONNECTOR:
case CAPACITOR: case CAPACITOR:
return NetworkComponent.CONNECTOR; return NetworkComponent.CONNECTOR;
case CONSUMER: case CONSUMER:
case GENERATOR: case GENERATOR:
return NetworkComponent.TERMINUS; return NetworkComponent.TERMINUS;
default: default:
return null; return null;
} }
} }
} }
@ -98,21 +98,21 @@ public class EnergyNet extends Network implements HologramOwner {
if (component != null) { if (component != null) {
switch (component.getEnergyComponentType()) { switch (component.getEnergyComponentType()) {
case CAPACITOR: case CAPACITOR:
capacitors.put(l, component); capacitors.put(l, component);
break; break;
case CONSUMER: case CONSUMER:
consumers.put(l, component); consumers.put(l, component);
break; break;
case GENERATOR: case GENERATOR:
if (component instanceof EnergyNetProvider) { if (component instanceof EnergyNetProvider) {
generators.put(l, (EnergyNetProvider) component); generators.put(l, (EnergyNetProvider) component);
} else if (component instanceof SlimefunItem) { } else if (component instanceof SlimefunItem) {
((SlimefunItem) component).warn("This Item is marked as a GENERATOR but does not implement the interface EnergyNetProvider!"); ((SlimefunItem) component).warn("This Item is marked as a GENERATOR but does not implement the interface EnergyNetProvider!");
} }
break; break;
default: default:
break; break;
} }
} }
} }

View File

@ -29,38 +29,51 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
*/ */
public class BackupService implements Runnable { public class BackupService implements Runnable {
/**
* The maximum amount of backups to maintain
*/
private static final int MAX_BACKUPS = 20; private static final int MAX_BACKUPS = 20;
/**
* Our {@link DateTimeFormatter} for formatting file names.
*/
private final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm", Locale.ROOT); private final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm", Locale.ROOT);
/**
* The directory in which to create the backups
*/
private final File directory = new File("data-storage/Slimefun/block-backups"); private final File directory = new File("data-storage/Slimefun/block-backups");
@Override @Override
public void run() { public void run() {
List<File> backups = Arrays.asList(directory.listFiles()); // Make sure that the directory exists.
if (directory.exists()) {
List<File> backups = Arrays.asList(directory.listFiles());
if (backups.size() > MAX_BACKUPS) { if (backups.size() > MAX_BACKUPS) {
try { try {
purgeBackups(backups); purgeBackups(backups);
} catch (IOException e) { } catch (IOException e) {
SlimefunPlugin.logger().log(Level.WARNING, "Could not delete an old backup", e); SlimefunPlugin.logger().log(Level.WARNING, "Could not delete an old backup", e);
} }
} }
File file = new File(directory, format.format(LocalDateTime.now()) + ".zip"); File file = new File(directory, format.format(LocalDateTime.now()) + ".zip");
if (!file.exists()) { if (!file.exists()) {
try { try {
if (file.createNewFile()) { if (file.createNewFile()) {
try (ZipOutputStream output = new ZipOutputStream(new FileOutputStream(file))) { try (ZipOutputStream output = new ZipOutputStream(new FileOutputStream(file))) {
createBackup(output); createBackup(output);
} }
SlimefunPlugin.logger().log(Level.INFO, "Backed up Slimefun data to: {0}", file.getName()); SlimefunPlugin.logger().log(Level.INFO, "Backed up Slimefun data to: {0}", file.getName());
} else { } else {
SlimefunPlugin.logger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName()); SlimefunPlugin.logger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName());
}
} catch (IOException x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion());
} }
} catch (IOException x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Error occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion());
} }
} }
} }

View File

@ -138,29 +138,29 @@ public class BlockDataService implements Keyed {
} }
switch (type) { switch (type) {
case PLAYER_HEAD: case PLAYER_HEAD:
case PLAYER_WALL_HEAD: case PLAYER_WALL_HEAD:
case CHEST: case CHEST:
case DISPENSER: case DISPENSER:
case BREWING_STAND: case BREWING_STAND:
case DROPPER: case DROPPER:
case FURNACE: case FURNACE:
case BLAST_FURNACE: case BLAST_FURNACE:
case HOPPER: case HOPPER:
case LECTERN: case LECTERN:
case JUKEBOX: case JUKEBOX:
case ENDER_CHEST: case ENDER_CHEST:
case ENCHANTING_TABLE: case ENCHANTING_TABLE:
case DAYLIGHT_DETECTOR: case DAYLIGHT_DETECTOR:
case SMOKER: case SMOKER:
case BARREL: case BARREL:
case SPAWNER: case SPAWNER:
case BEACON: case BEACON:
// All of the above Materials are Tile Entities // All of the above Materials are Tile Entities
return true; return true;
default: default:
// Otherwise we assume they're not Tile Entities // Otherwise we assume they're not Tile Entities
return false; return false;
} }
} }

View File

@ -106,15 +106,19 @@ public class MetricsService {
} }
try { try {
// Load the jar file into a child class loader using the SF PluginClassLoader /*
// as a parent. * Load the jar file into a child class loader using the Slimefun
* PluginClassLoader as a parent.
*/
moduleClassLoader = URLClassLoader.newInstance(new URL[] { metricsModuleFile.toURI().toURL() }, plugin.getClass().getClassLoader()); moduleClassLoader = URLClassLoader.newInstance(new URL[] { metricsModuleFile.toURI().toURL() }, plugin.getClass().getClassLoader());
Class<?> metricsClass = moduleClassLoader.loadClass("dev.walshy.sfmetrics.MetricsModule"); Class<?> metricsClass = moduleClassLoader.loadClass("dev.walshy.sfmetrics.MetricsModule");
metricVersion = metricsClass.getPackage().getImplementationVersion(); metricVersion = metricsClass.getPackage().getImplementationVersion();
// If it has not been newly downloaded, auto-updates are on AND there's a new version /*
// then cleanup, download and start * If it has not been newly downloaded, auto-updates are enabled
* AND there's a new version then cleanup, download and start
*/
if (!hasDownloadedUpdate && hasAutoUpdates() && checkForUpdate(metricVersion)) { if (!hasDownloadedUpdate && hasAutoUpdates() && checkForUpdate(metricVersion)) {
plugin.getLogger().info("Cleaned up, now re-loading Metrics-Module!"); plugin.getLogger().info("Cleaned up, now re-loading Metrics-Module!");
start(); start();

View File

@ -1,6 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.services; package io.github.thebusybiscuit.slimefun4.core.services;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -10,6 +11,9 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.inventory.FurnaceRecipe; import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -34,9 +38,19 @@ import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunG
*/ */
public class MinecraftRecipeService { public class MinecraftRecipeService {
/**
* Our {@link Plugin} instance
*/
private final Plugin plugin; private final Plugin plugin;
/**
* The subscriber list for the {@link RecipeSnapshot}.
*/
private final List<Consumer<RecipeSnapshot>> subscriptions = new LinkedList<>(); private final List<Consumer<RecipeSnapshot>> subscriptions = new LinkedList<>();
/**
* Our {@link RecipeSnapshot} - The centerpiece of this class.
*/
private RecipeSnapshot snapshot; private RecipeSnapshot snapshot;
/** /**
@ -115,6 +129,7 @@ public class MinecraftRecipeService {
* *
* @param recipe * @param recipe
* The {@link Recipe} to get the shape from * The {@link Recipe} to get the shape from
*
* @return An Array of {@link RecipeChoice} representing the shape of this {@link Recipe} * @return An Array of {@link RecipeChoice} representing the shape of this {@link Recipe}
*/ */
@Nonnull @Nonnull
@ -149,6 +164,7 @@ public class MinecraftRecipeService {
* *
* @param item * @param item
* The {@link ItemStack} for which to get the recipes * The {@link ItemStack} for which to get the recipes
*
* @return An array of {@link Recipe Recipes} to craft the given {@link ItemStack} * @return An array of {@link Recipe Recipes} to craft the given {@link ItemStack}
*/ */
@Nonnull @Nonnull
@ -160,4 +176,27 @@ public class MinecraftRecipeService {
} }
} }
/**
* This returns the corresponding {@link Keyed} {@link Recipe} for the given {@link NamespacedKey}.
* If no {@link Recipe} was found, null will be returned.
* This is a significantly faster method over {@link Bukkit#getRecipe(NamespacedKey)} since we
* operate on a cached {@link HashMap}
*
* @param key
* The {@link NamespacedKey}
*
* @return The corresponding {@link Recipe} or null
*/
@Nullable
public Recipe getRecipe(@Nonnull NamespacedKey key) {
Validate.notNull(key, "The NamespacedKey should not be null");
if (snapshot != null) {
// We operate on a cached HashMap which is much faster than Bukkit's method.
return snapshot.getRecipe(key);
} else {
return Bukkit.getRecipe(key);
}
}
} }

View File

@ -1,7 +1,6 @@
package io.github.thebusybiscuit.slimefun4.core.services; package io.github.thebusybiscuit.slimefun4.core.services;
import java.io.File; import java.io.File;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -124,8 +123,7 @@ public class PermissionsService {
@Nonnull @Nonnull
public List<String> getLore(@Nonnull SlimefunItem item) { public List<String> getLore(@Nonnull SlimefunItem item) {
List<String> lore = config.getStringList(item.getId() + ".lore"); return config.getStringList(item.getId() + ".lore");
return lore == null ? Arrays.asList("LORE NOT FOUND") : lore;
} }
} }

View File

@ -26,6 +26,9 @@ import io.github.thebusybiscuit.slimefun4.api.SlimefunBranch;
import io.github.thebusybiscuit.slimefun4.core.services.LocalizationService; import io.github.thebusybiscuit.slimefun4.core.services.LocalizationService;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
/** /**
* This is an abstract parent class of {@link LocalizationService}. * This is an abstract parent class of {@link LocalizationService}.
@ -215,76 +218,84 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
} }
@Override @Override
public void sendMessage(CommandSender sender, String key, boolean addPrefix) { public void sendMessage(CommandSender recipient, String key, boolean addPrefix) {
String prefix = addPrefix ? getPrefix() : ""; String prefix = addPrefix ? getPrefix() : "";
if (sender instanceof Player) { if (recipient instanceof Player) {
sender.sendMessage(ChatColors.color(prefix + getMessage((Player) sender, key))); recipient.sendMessage(ChatColors.color(prefix + getMessage((Player) recipient, key)));
} else { } else {
sender.sendMessage(ChatColor.stripColor(ChatColors.color(prefix + getMessage(key)))); recipient.sendMessage(ChatColor.stripColor(ChatColors.color(prefix + getMessage(key))));
} }
} }
@Override public void sendActionbarMessage(@Nonnull Player player, @Nonnull String key, boolean addPrefix) {
public void sendMessage(CommandSender sender, String key) { String prefix = addPrefix ? getPrefix() : "";
sendMessage(sender, key, true); String message = ChatColors.color(prefix + getMessage(player, key));
}
public void sendMessage(CommandSender sender, String key, UnaryOperator<String> function) { BaseComponent[] components = TextComponent.fromLegacyText(message);
sendMessage(sender, key, true, function); player.spigot().sendMessage(ChatMessageType.ACTION_BAR, components);
} }
@Override @Override
public void sendMessage(CommandSender sender, String key, boolean addPrefix, UnaryOperator<String> function) { public void sendMessage(CommandSender recipient, String key) {
sendMessage(recipient, key, true);
}
public void sendMessage(CommandSender recipient, String key, UnaryOperator<String> function) {
sendMessage(recipient, key, true, function);
}
@Override
public void sendMessage(CommandSender recipient, String key, boolean addPrefix, UnaryOperator<String> function) {
if (SlimefunPlugin.getMinecraftVersion() == MinecraftVersion.UNIT_TEST) { if (SlimefunPlugin.getMinecraftVersion() == MinecraftVersion.UNIT_TEST) {
return; return;
} }
String prefix = addPrefix ? getPrefix() : ""; String prefix = addPrefix ? getPrefix() : "";
if (sender instanceof Player) { if (recipient instanceof Player) {
sender.sendMessage(ChatColors.color(prefix + function.apply(getMessage((Player) sender, key)))); recipient.sendMessage(ChatColors.color(prefix + function.apply(getMessage((Player) recipient, key))));
} else { } else {
sender.sendMessage(ChatColor.stripColor(ChatColors.color(prefix + function.apply(getMessage(key))))); recipient.sendMessage(ChatColor.stripColor(ChatColors.color(prefix + function.apply(getMessage(key)))));
} }
} }
@Override @Override
public void sendMessages(CommandSender sender, String key) { public void sendMessages(CommandSender recipient, String key) {
String prefix = getPrefix(); String prefix = getPrefix();
if (sender instanceof Player) { if (recipient instanceof Player) {
for (String translation : getMessages((Player) sender, key)) { for (String translation : getMessages((Player) recipient, key)) {
String message = ChatColors.color(prefix + translation); String message = ChatColors.color(prefix + translation);
sender.sendMessage(message); recipient.sendMessage(message);
} }
} else { } else {
for (String translation : getMessages(key)) { for (String translation : getMessages(key)) {
String message = ChatColors.color(prefix + translation); String message = ChatColors.color(prefix + translation);
sender.sendMessage(ChatColor.stripColor(message)); recipient.sendMessage(ChatColor.stripColor(message));
} }
} }
} }
@Override @Override
public void sendMessages(CommandSender sender, String key, boolean addPrefix, UnaryOperator<String> function) { public void sendMessages(CommandSender recipient, String key, boolean addPrefix, UnaryOperator<String> function) {
String prefix = addPrefix ? getPrefix() : ""; String prefix = addPrefix ? getPrefix() : "";
if (sender instanceof Player) { if (recipient instanceof Player) {
for (String translation : getMessages((Player) sender, key)) { for (String translation : getMessages((Player) recipient, key)) {
String message = ChatColors.color(prefix + function.apply(translation)); String message = ChatColors.color(prefix + function.apply(translation));
sender.sendMessage(message); recipient.sendMessage(message);
} }
} else { } else {
for (String translation : getMessages(key)) { for (String translation : getMessages(key)) {
String message = ChatColors.color(prefix + function.apply(translation)); String message = ChatColors.color(prefix + function.apply(translation));
sender.sendMessage(ChatColor.stripColor(message)); recipient.sendMessage(ChatColor.stripColor(message));
} }
} }
} }
public void sendMessages(CommandSender sender, String key, UnaryOperator<String> function) { public void sendMessages(CommandSender recipient, String key, UnaryOperator<String> function) {
sendMessages(sender, key, true, function); sendMessages(recipient, key, true, function);
} }
} }

View File

@ -38,6 +38,7 @@ public class Translators {
addTranslator("NinoFutur", SupportedLanguage.FRENCH, true); addTranslator("NinoFutur", SupportedLanguage.FRENCH, true);
addTranslator("TheRetix", SupportedLanguage.FRENCH, true); addTranslator("TheRetix", SupportedLanguage.FRENCH, true);
addTranslator("Aeris1One", SupportedLanguage.FRENCH, true); addTranslator("Aeris1One", SupportedLanguage.FRENCH, true);
addTranslator("Aomitsu", SupportedLanguage.FRENCH, true);
// Translators - Italian // Translators - Italian
addTranslator("xXDOTTORXx", SupportedLanguage.ITALIAN, true); addTranslator("xXDOTTORXx", SupportedLanguage.ITALIAN, true);
@ -89,6 +90,9 @@ public class Translators {
addTranslator("MrFriggo", SupportedLanguage.CZECH, true); addTranslator("MrFriggo", SupportedLanguage.CZECH, true);
addTranslator("100petr", SupportedLanguage.CZECH, true); addTranslator("100petr", SupportedLanguage.CZECH, true);
addTranslator("frfole", SupportedLanguage.CZECH, true); addTranslator("frfole", SupportedLanguage.CZECH, true);
addTranslator("bobhenl", SupportedLanguage.CZECH, true);
addTranslator("janvrska", SupportedLanguage.CZECH, true);
addTranslator("LirCZE", SupportedLanguage.CZECH, true);
// Translators - Russian // Translators - Russian
addTranslator("SoSeDiK", SupportedLanguage.RUSSIAN, false); addTranslator("SoSeDiK", SupportedLanguage.RUSSIAN, false);
@ -103,6 +107,9 @@ public class Translators {
addTranslator("NihilistBrew", "ma1yang2", SupportedLanguage.SWEDISH, false); addTranslator("NihilistBrew", "ma1yang2", SupportedLanguage.SWEDISH, false);
addTranslator("Tra-sh", "TurretTrash", SupportedLanguage.SWEDISH, true); addTranslator("Tra-sh", "TurretTrash", SupportedLanguage.SWEDISH, true);
// Translators - Finnish
addTranslator("developer-pseudo", SupportedLanguage.FINNISH, true);
// Translators - Dutch // Translators - Dutch
addTranslator("Dr4gonD", "DragonD", SupportedLanguage.DUTCH, true); addTranslator("Dr4gonD", "DragonD", SupportedLanguage.DUTCH, true);
addTranslator("svr333", SupportedLanguage.DUTCH, false); addTranslator("svr333", SupportedLanguage.DUTCH, false);
@ -110,6 +117,7 @@ public class Translators {
addTranslator("milvantiou", SupportedLanguage.DUTCH, true); addTranslator("milvantiou", SupportedLanguage.DUTCH, true);
addTranslator("Sven313D", SupportedLanguage.DUTCH, true); addTranslator("Sven313D", SupportedLanguage.DUTCH, true);
addTranslator("TypischTeun", SupportedLanguage.DUTCH, true); addTranslator("TypischTeun", SupportedLanguage.DUTCH, true);
addTranslator("peppower", SupportedLanguage.DUTCH, true);
// Translators - Danish // Translators - Danish
addTranslator("Mini-kun", SupportedLanguage.DANISH, true); addTranslator("Mini-kun", SupportedLanguage.DANISH, true);
@ -124,6 +132,7 @@ public class Translators {
addTranslator("StarWishsama", "StarWish_Sama", SupportedLanguage.CHINESE_CHINA, false); addTranslator("StarWishsama", "StarWish_Sama", SupportedLanguage.CHINESE_CHINA, false);
addTranslator("Rothes", SupportedLanguage.CHINESE_CHINA, true); addTranslator("Rothes", SupportedLanguage.CHINESE_CHINA, true);
addTranslator("Chihsiao", SupportedLanguage.CHINESE_CHINA, true); addTranslator("Chihsiao", SupportedLanguage.CHINESE_CHINA, true);
addTranslator("Jiejue233", SupportedLanguage.CHINESE_CHINA, true);
// Translators - Chinese (Taiwan) // Translators - Chinese (Taiwan)
addTranslator("BrineYT", "HeroBrineKing", SupportedLanguage.CHINESE_TAIWAN, true); addTranslator("BrineYT", "HeroBrineKing", SupportedLanguage.CHINESE_TAIWAN, true);

View File

@ -841,7 +841,9 @@ public final class SlimefunItems {
public static final SlimefunItemStack ELECTRIC_INGOT_FACTORY_2 = new SlimefunItemStack("ELECTRIC_INGOT_FACTORY_2", Material.RED_TERRACOTTA, "&cElectric Ingot Factory &7(&eII&7)", "", LoreBuilder.machine(MachineTier.BASIC, MachineType.MACHINE), LoreBuilder.speed(2), LoreBuilder.powerPerSecond(14)); public static final SlimefunItemStack ELECTRIC_INGOT_FACTORY_2 = new SlimefunItemStack("ELECTRIC_INGOT_FACTORY_2", Material.RED_TERRACOTTA, "&cElectric Ingot Factory &7(&eII&7)", "", LoreBuilder.machine(MachineTier.BASIC, MachineType.MACHINE), LoreBuilder.speed(2), LoreBuilder.powerPerSecond(14));
public static final SlimefunItemStack ELECTRIC_INGOT_FACTORY_3 = new SlimefunItemStack("ELECTRIC_INGOT_FACTORY_3", Material.RED_TERRACOTTA, "&cElectric Ingot Factory &7(&eIII&7)", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), LoreBuilder.speed(8), LoreBuilder.powerPerSecond(40)); public static final SlimefunItemStack ELECTRIC_INGOT_FACTORY_3 = new SlimefunItemStack("ELECTRIC_INGOT_FACTORY_3", Material.RED_TERRACOTTA, "&cElectric Ingot Factory &7(&eIII&7)", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), LoreBuilder.speed(8), LoreBuilder.powerPerSecond(40));
@Deprecated
public static final SlimefunItemStack AUTOMATED_CRAFTING_CHAMBER = new SlimefunItemStack("AUTOMATED_CRAFTING_CHAMBER", Material.CRAFTING_TABLE, "&6Automated Crafting Chamber", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &710 J/Item"); public static final SlimefunItemStack AUTOMATED_CRAFTING_CHAMBER = new SlimefunItemStack("AUTOMATED_CRAFTING_CHAMBER", Material.CRAFTING_TABLE, "&6Automated Crafting Chamber", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &710 J/Item");
public static final SlimefunItemStack FLUID_PUMP = new SlimefunItemStack("FLUID_PUMP", Material.BLUE_TERRACOTTA, "&9Fluid Pump", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &732 J/Block"); public static final SlimefunItemStack FLUID_PUMP = new SlimefunItemStack("FLUID_PUMP", Material.BLUE_TERRACOTTA, "&9Fluid Pump", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &732 J/Block");
public static final SlimefunItemStack CHARGING_BENCH = new SlimefunItemStack("CHARGING_BENCH", Material.CRAFTING_TABLE, "&6Charging Bench", "", "&fCharges Items such as Jetpacks", "", LoreBuilder.machine(MachineTier.BASIC, MachineType.MACHINE), LoreBuilder.powerBuffer(128), "&8\u21E8 &e\u26A1 &7Energy Loss: &c50%"); public static final SlimefunItemStack CHARGING_BENCH = new SlimefunItemStack("CHARGING_BENCH", Material.CRAFTING_TABLE, "&6Charging Bench", "", "&fCharges Items such as Jetpacks", "", LoreBuilder.machine(MachineTier.BASIC, MachineType.MACHINE), LoreBuilder.powerBuffer(128), "&8\u21E8 &e\u26A1 &7Energy Loss: &c50%");

View File

@ -78,6 +78,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.GrapplingHook
import io.github.thebusybiscuit.slimefun4.implementation.listeners.HopperListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.HopperListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemDropListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MiningAndroidListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PlayerProfileListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.PlayerProfileListener;
@ -128,14 +129,26 @@ import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
*/ */
public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
/**
* Our static instance of {@link SlimefunPlugin}.
* Make sure to clean this up in {@link #onDisable()} !
*/
private static SlimefunPlugin instance; private static SlimefunPlugin instance;
/**
* Keep track of which {@link MinecraftVersion} we are on.
*/
private MinecraftVersion minecraftVersion = MinecraftVersion.UNKNOWN; private MinecraftVersion minecraftVersion = MinecraftVersion.UNKNOWN;
/**
* Keep track of whether this is a fresh install or a regular boot up.
*/
private boolean isNewlyInstalled = false; private boolean isNewlyInstalled = false;
// Various things we need
private final SlimefunRegistry registry = new SlimefunRegistry(); private final SlimefunRegistry registry = new SlimefunRegistry();
private final TickerTask ticker = new TickerTask();
private final SlimefunCommand command = new SlimefunCommand(this); private final SlimefunCommand command = new SlimefunCommand(this);
private final TickerTask ticker = new TickerTask();
// Services - Systems that fulfill certain tasks, treat them as a black box // Services - Systems that fulfill certain tasks, treat them as a black box
private final CustomItemDataService itemDataService = new CustomItemDataService(this, "slimefun_item"); private final CustomItemDataService itemDataService = new CustomItemDataService(this, "slimefun_item");
@ -151,10 +164,12 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this); private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this);
private final HologramsService hologramsService = new HologramsService(this); private final HologramsService hologramsService = new HologramsService(this);
// Some other things we need
private final IntegrationsManager integrations = new IntegrationsManager(this); private final IntegrationsManager integrations = new IntegrationsManager(this);
private final SlimefunProfiler profiler = new SlimefunProfiler(); private final SlimefunProfiler profiler = new SlimefunProfiler();
private final GPSNetwork gpsNetwork = new GPSNetwork(this); private final GPSNetwork gpsNetwork = new GPSNetwork(this);
// Even more things we need
private NetworkManager networkManager; private NetworkManager networkManager;
private LocalizationService local; private LocalizationService local;
@ -231,6 +246,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private void onPluginStart() { private void onPluginStart() {
long timestamp = System.nanoTime(); long timestamp = System.nanoTime();
// Check if Paper (<3) is installed
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied."); getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied.");
} else { } else {
@ -256,6 +272,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
int networkSize = config.getInt("networks.max-size"); int networkSize = config.getInt("networks.max-size");
// Make sure that the network size is a valid input
if (networkSize < 1) { if (networkSize < 1) {
getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize); getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize);
networkSize = 1; networkSize = 1;
@ -359,8 +376,12 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
Bukkit.getScheduler().cancelTasks(this); Bukkit.getScheduler().cancelTasks(this);
// Finishes all started movements/removals of block data // Finishes all started movements/removals of block data
ticker.halt(); try {
ticker.run(); ticker.halt();
ticker.run();
} catch (Exception x) {
getLogger().log(Level.SEVERE, x, () -> "Something went wrong while disabling the ticker task for Slimefun v" + getDescription().getVersion());
}
// Kill our Profiler Threads // Kill our Profiler Threads
profiler.kill(); profiler.kill();
@ -594,8 +615,11 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
new GrindstoneListener(this); new GrindstoneListener(this);
new CartographyTableListener(this); new CartographyTableListener(this);
new ButcherAndroidListener(this); new ButcherAndroidListener(this);
new MiningAndroidListener(this);
new NetworkListener(this, networkManager); new NetworkListener(this, networkManager);
new HopperListener(this); new HopperListener(this);
new TalismanListener(this);
new SoulboundListener(this);
// Bees were added in 1.15 // Bees were added in 1.15
if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) { if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) {
@ -617,15 +641,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
bowListener.register(this); bowListener.register(this);
backpackListener.register(this); backpackListener.register(this);
// Toggleable Listeners for performance reasons
if (config.getBoolean("items.talismans")) {
new TalismanListener(this);
}
if (config.getBoolean("items.soulbound")) {
new SoulboundListener(this);
}
// Handle Slimefun Guide being given on Join // Handle Slimefun Guide being given on Join
new SlimefunGuideListener(this, config.getBoolean("guide.receive-on-first-join")); new SlimefunGuideListener(this, config.getBoolean("guide.receive-on-first-join"));
@ -640,7 +655,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
* This (re)loads every {@link SlimefunTag}. * This (re)loads every {@link SlimefunTag}.
*/ */
private void loadTags() { private void loadTags() {
for (SlimefunTag tag : SlimefunTag.valuesCache) { for (SlimefunTag tag : SlimefunTag.values()) {
try { try {
// Only reload "empty" (or unloaded) Tags // Only reload "empty" (or unloaded) Tags
if (tag.isEmpty()) { if (tag.isEmpty()) {

View File

@ -1,6 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.guide; package io.github.thebusybiscuit.slimefun4.implementation.guide;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -73,7 +74,8 @@ public class CheatSheetSlimefunGuide extends SurvivalSlimefunGuide {
} }
@Override @Override
protected void createHeader(Player p, PlayerProfile profile, ChestMenu menu) { @ParametersAreNonnullByDefault
public void createHeader(Player p, PlayerProfile profile, ChestMenu menu) {
super.createHeader(p, profile, menu); super.createHeader(p, profile, menu);
// Remove Settings Panel // Remove Settings Panel

View File

@ -11,6 +11,7 @@ import java.util.logging.Level;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Sound; import org.bukkit.Sound;
@ -76,6 +77,17 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
item = new SlimefunGuideItem(this, "&aSlimefun Guide &7(Chest GUI)"); item = new SlimefunGuideItem(this, "&aSlimefun Guide &7(Chest GUI)");
} }
/**
* This returns the {@link Sound} which is played when someone navigates through
* the {@link SlimefunGuide}
*
* @return The {@link Sound}
*/
@Nonnull
public Sound getSound() {
return sound;
}
@Override @Override
public SlimefunGuideMode getMode() { public SlimefunGuideMode getMode() {
return SlimefunGuideMode.SURVIVAL_MODE; return SlimefunGuideMode.SURVIVAL_MODE;
@ -224,11 +236,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
ChestMenu menu = create(p); ChestMenu menu = create(p);
createHeader(p, profile, menu); createHeader(p, profile, menu);
menu.addItem(1, new CustomItem(ChestMenuUtils.getBackButton(p, "", ChatColor.GRAY + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide")))); addBackButton(menu, 1, p, profile);
menu.addMenuClickHandler(1, (pl, s, is, action) -> {
openMainMenu(profile, 1);
return false;
});
int pages = (category.getItems().size() - 1) / CATEGORY_SIZE + 1; int pages = (category.getItems().size() - 1) / CATEGORY_SIZE + 1;
@ -266,7 +274,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
SlimefunItem sfitem = category.getItems().get(target); SlimefunItem sfitem = category.getItems().get(target);
if (Slimefun.isEnabled(p, sfitem, false)) { if (!sfitem.isDisabledIn(p.getWorld())) {
displaySlimefunItem(menu, category, p, profile, sfitem, page, index); displaySlimefunItem(menu, category, p, profile, sfitem, page, index);
index++; index++;
} }
@ -552,7 +560,12 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
menu.addItem(16, output, ChestMenuUtils.getEmptyClickHandler()); menu.addItem(16, output, ChestMenuUtils.getEmptyClickHandler());
} }
protected void createHeader(Player p, PlayerProfile profile, ChestMenu menu) { @ParametersAreNonnullByDefault
public void createHeader(Player p, PlayerProfile profile, ChestMenu menu) {
Validate.notNull(p, "The Player cannot be null!");
Validate.notNull(profile, "The Profile cannot be null!");
Validate.notNull(menu, "The Inventory cannot be null!");
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
menu.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler()); menu.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
} }
@ -613,7 +626,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
} }
String lore = Slimefun.hasPermission(p, slimefunItem, false) ? "&fNeeds to be unlocked elsewhere" : "&fNo Permission"; String lore = Slimefun.hasPermission(p, slimefunItem, false) ? "&fNeeds to be unlocked elsewhere" : "&fNo Permission";
return Slimefun.hasUnlocked(p, slimefunItem, false) ? item : new CustomItem(Material.BARRIER, ItemUtils.getItemName(item), "&4&l" + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", lore); return slimefunItem.canUse(p, false) ? item : new CustomItem(Material.BARRIER, ItemUtils.getItemName(item), "&4&l" + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", lore);
} else { } else {
return item; return item;
} }

View File

@ -0,0 +1,59 @@
package io.github.thebusybiscuit.slimefun4.implementation.handlers;
import java.util.List;
import javax.annotation.Nonnull;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.androids.MinerAndroid;
/**
* This simple implementation of {@link BlockBreakHandler} will execute the same code
* for when the {@link Block} is broken by a {@link Player}, by a {@link MinerAndroid} or an explosion.
* By default, both androids and explosions are allowed.
*
* @author TheBusyBiscuit
*
* @see BlockBreakHandler
*
*/
public abstract class SimpleBlockBreakHandler extends BlockBreakHandler {
/**
* This constructs a new {@link SimpleBlockBreakHandler}.
*/
public SimpleBlockBreakHandler() {
super(true, true);
}
/**
* This method is called when a {@link Block} of this type is broken by a {@link Player},
* by a {@link MinerAndroid} or through an explosion.
*
* @param b
* The broken {@link Block}
*/
public abstract void onBlockBreak(@Nonnull Block b);
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
onBlockBreak(e.getBlock());
}
@Override
public void onAndroidBreak(AndroidMineEvent e) {
onBlockBreak(e.getBlock());
}
@Override
public void onExplode(Block b, List<ItemStack> drops) {
onBlockBreak(b);
}
}

View File

@ -0,0 +1,5 @@
/**
* This package holds simple implementations of {@link me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler}.
* These are just handlers that can be re-used frequently.
*/
package io.github.thebusybiscuit.slimefun4.implementation.handlers;

View File

@ -21,15 +21,16 @@ import org.bukkit.util.Vector;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AncientAltarTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AncientAltarTask;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
@ -53,21 +54,28 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
public AncientPedestal(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) { public AncientPedestal(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput); super(category, item, recipeType, recipe, recipeOutput);
SlimefunItem.registerBlockHandler(getId(), (p, b, tool, reason) -> { addItemHandler(onBreak());
Optional<Item> entity = getPlacedItem(b); }
if (entity.isPresent()) { @Nonnull
Item stack = entity.get(); private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
if (stack.isValid()) { @Override
stack.removeMetadata("no_pickup", SlimefunPlugin.instance()); public void onBlockBreak(@Nonnull Block b) {
b.getWorld().dropItem(b.getLocation(), getOriginalItemStack(stack)); Optional<Item> entity = getPlacedItem(b);
stack.remove();
if (entity.isPresent()) {
Item stack = entity.get();
if (stack.isValid()) {
stack.removeMetadata("no_pickup", SlimefunPlugin.instance());
b.getWorld().dropItem(b.getLocation(), getOriginalItemStack(stack));
stack.remove();
}
} }
} }
};
return true;
});
} }
@Override @Override

View File

@ -38,20 +38,20 @@ public class ButcherAndroid extends ProgrammableAndroid {
boolean attack = false; boolean attack = false;
switch (face) { switch (face) {
case NORTH: case NORTH:
attack = n.getLocation().getZ() < b.getZ(); attack = n.getLocation().getZ() < b.getZ();
break; break;
case EAST: case EAST:
attack = n.getLocation().getX() > b.getX(); attack = n.getLocation().getX() > b.getX();
break; break;
case SOUTH: case SOUTH:
attack = n.getLocation().getZ() > b.getZ(); attack = n.getLocation().getZ() > b.getZ();
break; break;
case WEST: case WEST:
attack = n.getLocation().getX() < b.getX(); attack = n.getLocation().getX() < b.getX();
break; break;
default: default:
break; break;
} }
if (attack) { if (attack) {

View File

@ -64,22 +64,22 @@ public class FarmerAndroid extends ProgrammableAndroid {
Random random = ThreadLocalRandom.current(); Random random = ThreadLocalRandom.current();
switch (crop) { switch (crop) {
case WHEAT: case WHEAT:
return new ItemStack(Material.WHEAT, random.nextInt(2) + 1); return new ItemStack(Material.WHEAT, random.nextInt(2) + 1);
case POTATOES: case POTATOES:
return new ItemStack(Material.POTATO, random.nextInt(3) + 1); return new ItemStack(Material.POTATO, random.nextInt(3) + 1);
case CARROTS: case CARROTS:
return new ItemStack(Material.CARROT, random.nextInt(3) + 1); return new ItemStack(Material.CARROT, random.nextInt(3) + 1);
case BEETROOTS: case BEETROOTS:
return new ItemStack(Material.BEETROOT, random.nextInt(3) + 1); return new ItemStack(Material.BEETROOT, random.nextInt(3) + 1);
case COCOA: case COCOA:
return new ItemStack(Material.COCOA_BEANS, random.nextInt(3) + 1); return new ItemStack(Material.COCOA_BEANS, random.nextInt(3) + 1);
case NETHER_WART: case NETHER_WART:
return new ItemStack(Material.NETHER_WART, random.nextInt(3) + 1); return new ItemStack(Material.NETHER_WART, random.nextInt(3) + 1);
case SWEET_BERRY_BUSH: case SWEET_BERRY_BUSH:
return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1); return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1);
default: default:
return null; return null;
} }
} }

View File

@ -3,40 +3,73 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import java.util.Collection; import java.util.Collection;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent; import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
/**
* The {@link MinerAndroid} is a variant of the {@link ProgrammableAndroid} which
* is able to break blocks.
* The core functionalities boil down to {@link #dig(Block, BlockMenu, Block)} and
* {@link #moveAndDig(Block, BlockMenu, BlockFace, Block)}.
* Otherwise the functionality is similar to a regular android.
* <p>
* The {@link MinerAndroid} will also fire an {@link AndroidMineEvent} when breaking a {@link Block}.
*
* @author TheBusyBiscuit
* @author creator3
* @author poma123
* @author Sfiguz7
* @author CyberPatriot
* @author Redemption198
* @author Poslovitch
*
* @see AndroidMineEvent
*
*/
public class MinerAndroid extends ProgrammableAndroid { public class MinerAndroid extends ProgrammableAndroid {
// Determines the drops a miner android will get // Determines the drops a miner android will get
private final ItemStack effectivePickaxe = new ItemStack(Material.DIAMOND_PICKAXE); private final ItemStack effectivePickaxe = new ItemStack(Material.DIAMOND_PICKAXE);
private final ItemSetting<Boolean> firesEvent = new ItemSetting<>("trigger-event-for-generators", false);
private final ItemSetting<Boolean> applyOptimizations = new ItemSetting<>("reduced-block-updates", true);
@ParametersAreNonnullByDefault
public MinerAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public MinerAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, tier, item, recipeType, recipe); super(category, tier, item, recipeType, recipe);
addItemSetting(firesEvent);
} }
@Override @Override
@Nonnull
public AndroidType getAndroidType() { public AndroidType getAndroidType() {
return AndroidType.MINER; return AndroidType.MINER;
} }
@Override @Override
@ParametersAreNonnullByDefault
protected void dig(Block b, BlockMenu menu, Block block) { protected void dig(Block b, BlockMenu menu, Block block) {
Collection<ItemStack> drops = block.getDrops(effectivePickaxe); Collection<ItemStack> drops = block.getDrops(effectivePickaxe);
@ -52,22 +85,16 @@ public class MinerAndroid extends ProgrammableAndroid {
} }
// We only want to break non-Slimefun blocks // We only want to break non-Slimefun blocks
String blockId = BlockStorage.checkID(block); if (!BlockStorage.hasBlockInfo(block)) {
if (blockId == null) {
for (ItemStack drop : drops) {
if (menu.fits(drop, getOutputSlots())) {
menu.pushItem(drop, getOutputSlots());
}
}
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType()); block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
block.setType(Material.AIR); breakBlock(menu, drops, block);
} }
} }
} }
} }
@Override @Override
@ParametersAreNonnullByDefault
protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block) { protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block) {
Collection<ItemStack> drops = block.getDrops(effectivePickaxe); Collection<ItemStack> drops = block.getDrops(effectivePickaxe);
@ -83,17 +110,9 @@ public class MinerAndroid extends ProgrammableAndroid {
} }
// We only want to break non-Slimefun blocks // We only want to break non-Slimefun blocks
SlimefunItem blockId = BlockStorage.check(block); if (!BlockStorage.hasBlockInfo(block)) {
if (blockId == null) {
for (ItemStack drop : drops) {
if (menu.fits(drop, getOutputSlots())) {
menu.pushItem(drop, getOutputSlots());
}
}
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType()); block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
breakBlock(menu, drops, block);
block.setType(Material.AIR);
move(b, face, block); move(b, face, block);
} }
} else { } else {
@ -104,4 +123,32 @@ public class MinerAndroid extends ProgrammableAndroid {
} }
} }
@ParametersAreNonnullByDefault
private void breakBlock(BlockMenu menu, Collection<ItemStack> drops, Block block) {
// Push our drops to the inventory
for (ItemStack drop : drops) {
menu.pushItem(drop, getOutputSlots());
}
// Check if Block Generator optimizations should be applied.
if (applyOptimizations.getValue()) {
InfiniteBlockGenerator generator = InfiniteBlockGenerator.findAt(block);
// If we found a generator, continue.
if (generator != null) {
if (firesEvent.getValue()) {
generator.callEvent(block);
}
// "poof" a "new" block was generated
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.075F, 0.8F);
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);
} else {
block.setType(Material.AIR);
}
} else {
block.setType(Material.AIR);
}
}
} }

View File

@ -56,7 +56,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
@ -133,6 +132,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
} }
}; };
// TODO: Move this into a BlockBreakHandler
registerBlockHandler(getId(), (p, b, stack, reason) -> { registerBlockHandler(getId(), (p, b, stack, reason) -> {
boolean allow = reason == UnregisterReason.PLAYER_BREAK && (BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(p.getUniqueId().toString()) || p.hasPermission("slimefun.android.bypass")); boolean allow = reason == UnregisterReason.PLAYER_BREAK && (BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(p.getUniqueId().toString()) || p.hasPermission("slimefun.android.bypass"));
@ -151,7 +151,8 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
addItemHandler(onPlace()); addItemHandler(onPlace());
} }
private ItemHandler onPlace() { @Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) { return new BlockPlaceHandler(false) {
@Override @Override
@ -194,14 +195,14 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
*/ */
public AndroidFuelSource getFuelSource() { public AndroidFuelSource getFuelSource() {
switch (getTier()) { switch (getTier()) {
case 1: case 1:
return AndroidFuelSource.SOLID; return AndroidFuelSource.SOLID;
case 2: case 2:
return AndroidFuelSource.LIQUID; return AndroidFuelSource.LIQUID;
case 3: case 3:
return AndroidFuelSource.NUCLEAR; return AndroidFuelSource.NUCLEAR;
default: default:
throw new IllegalStateException("Cannot convert the following Android tier to a fuel type: " + getTier()); throw new IllegalStateException("Cannot convert the following Android tier to a fuel type: " + getTier());
} }
} }
@ -564,38 +565,38 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
private void registerDefaultFuelTypes() { private void registerDefaultFuelTypes() {
switch (getFuelSource()) { switch (getFuelSource()) {
case SOLID: case SOLID:
registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK))); registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK)));
registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD))); registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD)));
registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK))); registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK)));
// Coal & Charcoal // Coal & Charcoal
registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL))); registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL)));
registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL))); registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL)));
// Logs // Logs
for (Material mat : Tag.LOGS.getValues()) { for (Material mat : Tag.LOGS.getValues()) {
registerFuelType(new MachineFuel(2, new ItemStack(mat))); registerFuelType(new MachineFuel(2, new ItemStack(mat)));
} }
// Wooden Planks // Wooden Planks
for (Material mat : Tag.PLANKS.getValues()) { for (Material mat : Tag.PLANKS.getValues()) {
registerFuelType(new MachineFuel(1, new ItemStack(mat))); registerFuelType(new MachineFuel(1, new ItemStack(mat)));
} }
break; break;
case LIQUID: case LIQUID:
registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET))); registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET)));
registerFuelType(new MachineFuel(200, SlimefunItems.OIL_BUCKET)); registerFuelType(new MachineFuel(200, SlimefunItems.OIL_BUCKET));
registerFuelType(new MachineFuel(500, SlimefunItems.FUEL_BUCKET)); registerFuelType(new MachineFuel(500, SlimefunItems.FUEL_BUCKET));
break; break;
case NUCLEAR: case NUCLEAR:
registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM)); registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM));
registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM)); registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM));
registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM)); registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM));
break; break;
default: default:
throw new IllegalStateException("Unhandled Fuel Source: " + getFuelSource()); throw new IllegalStateException("Unhandled Fuel Source: " + getFuelSource());
} }
} }
@ -685,26 +686,26 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
BlockFace face = rotationData == null ? BlockFace.NORTH : BlockFace.valueOf(rotationData); BlockFace face = rotationData == null ? BlockFace.NORTH : BlockFace.valueOf(rotationData);
switch (instruction) { switch (instruction) {
case START: case START:
case WAIT: case WAIT:
// We are "waiting" here, so we only move a step forward // We are "waiting" here, so we only move a step forward
BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
break;
case REPEAT:
// "repeat" just means, we reset our index
BlockStorage.addBlockInfo(b, "index", String.valueOf(0));
break;
case CHOP_TREE:
// We only move to the next step if we finished chopping wood
if (chopTree(b, inv, face)) {
BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
} break;
break; case REPEAT:
default: // "repeat" just means, we reset our index
// We set the index here in advance to fix moving android issues BlockStorage.addBlockInfo(b, "index", String.valueOf(0));
BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); break;
instruction.execute(this, b, inv, face); case CHOP_TREE:
break; // We only move to the next step if we finished chopping wood
if (chopTree(b, inv, face)) {
BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
}
break;
default:
// We set the index here in advance to fix moving android issues
BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
instruction.execute(this, b, inv, face);
break;
} }
} }
} }

View File

@ -1,8 +1,11 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids; package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Effect; import org.bukkit.Effect;
@ -14,9 +17,10 @@ import org.bukkit.block.BlockFace;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.blocks.Vein; import io.github.thebusybiscuit.cscorelib2.blocks.Vein;
import io.github.thebusybiscuit.cscorelib2.materials.MaterialConverter;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
@ -59,6 +63,7 @@ public class WoodcutterAndroid extends ProgrammableAndroid {
return true; return true;
} }
@ParametersAreNonnullByDefault
private void breakLog(Block log, Block android, BlockMenu menu, BlockFace face) { private void breakLog(Block log, Block android, BlockMenu menu, BlockFace face) {
ItemStack drop = new ItemStack(log.getType()); ItemStack drop = new ItemStack(log.getType());
@ -67,13 +72,96 @@ public class WoodcutterAndroid extends ProgrammableAndroid {
log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType()); log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType());
if (log.getY() == android.getRelative(face).getY()) { if (log.getY() == android.getRelative(face).getY()) {
Optional<Material> sapling = MaterialConverter.getSaplingFromLog(log.getType()); replant(log);
sapling.ifPresent(log::setType);
} else { } else {
log.setType(Material.AIR); log.setType(Material.AIR);
} }
} }
} }
private void replant(@Nonnull Block block) {
Material logType = block.getType();
Material saplingType = null;
Predicate<Material> soilRequirement = null;
switch (logType) {
case OAK_LOG:
case OAK_WOOD:
case STRIPPED_OAK_LOG:
case STRIPPED_OAK_WOOD:
saplingType = Material.OAK_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
break;
case BIRCH_LOG:
case BIRCH_WOOD:
case STRIPPED_BIRCH_LOG:
case STRIPPED_BIRCH_WOOD:
saplingType = Material.BIRCH_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
break;
case JUNGLE_LOG:
case JUNGLE_WOOD:
case STRIPPED_JUNGLE_LOG:
case STRIPPED_JUNGLE_WOOD:
saplingType = Material.JUNGLE_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
break;
case SPRUCE_LOG:
case SPRUCE_WOOD:
case STRIPPED_SPRUCE_LOG:
case STRIPPED_SPRUCE_WOOD:
saplingType = Material.SPRUCE_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
break;
case ACACIA_LOG:
case ACACIA_WOOD:
case STRIPPED_ACACIA_LOG:
case STRIPPED_ACACIA_WOOD:
saplingType = Material.ACACIA_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
break;
case DARK_OAK_LOG:
case DARK_OAK_WOOD:
case STRIPPED_DARK_OAK_LOG:
case STRIPPED_DARK_OAK_WOOD:
saplingType = Material.DARK_OAK_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
break;
default:
break;
}
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
switch (logType) {
case CRIMSON_STEM:
case CRIMSON_HYPHAE:
case STRIPPED_CRIMSON_STEM:
case STRIPPED_CRIMSON_HYPHAE:
saplingType = Material.CRIMSON_FUNGUS;
soilRequirement = SlimefunTag.FUNGUS_SOIL::isTagged;
break;
case WARPED_STEM:
case WARPED_HYPHAE:
case STRIPPED_WARPED_STEM:
case STRIPPED_WARPED_HYPHAE:
saplingType = Material.WARPED_FUNGUS;
soilRequirement = SlimefunTag.FUNGUS_SOIL::isTagged;
break;
default:
break;
}
}
if (saplingType != null && soilRequirement != null) {
if (soilRequirement.test(block.getRelative(BlockFace.DOWN).getType())) {
// Replant the block
block.setType(saplingType);
} else {
// Simply drop the sapling if the soil does not fit
block.getWorld().dropItemNaturally(block.getLocation(), new ItemStack(saplingType));
block.setType(Material.AIR);
}
}
}
} }

View File

@ -3,6 +3,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Location; import org.bukkit.Location;
@ -10,18 +13,21 @@ import org.bukkit.Material;
import org.bukkit.Nameable; import org.bukkit.Nameable;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Dispenser; import org.bukkit.block.Dispenser;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent; import io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.MaterialTagSetting; import io.github.thebusybiscuit.slimefun4.api.items.settings.MaterialTagSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -47,15 +53,17 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/ */
public class BlockPlacer extends SlimefunItem { public class BlockPlacer extends SlimefunItem {
private final ItemSetting<List<String>> blacklist = new MaterialTagSetting("unplaceable-blocks", SlimefunTag.UNBREAKABLE_MATERIALS); private final ItemSetting<List<String>> unplaceableBlocks = new MaterialTagSetting("unplaceable-blocks", SlimefunTag.UNBREAKABLE_MATERIALS);
@ParametersAreNonnullByDefault
public BlockPlacer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public BlockPlacer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
addItemSetting(blacklist); addItemSetting(unplaceableBlocks);
addItemHandler(onPlace(), onBlockDispense()); addItemHandler(onPlace(), onBlockBreak(), onBlockDispense());
} }
@Nonnull
private BlockPlaceHandler onPlace() { private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) { return new BlockPlaceHandler(false) {
@ -69,6 +77,33 @@ public class BlockPlacer extends SlimefunItem {
}; };
} }
@Nonnull
private BlockBreakHandler onBlockBreak() {
/*
* Explosions don't need explicit handling here.
* The default of "destroy the dispenser and drop the contents" is
* fine for our purposes already.
*/
return new BlockBreakHandler(false, true) {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
// Fixes #2852 - Manually drop inventory contents
Block b = e.getBlock();
BlockState state = PaperLib.getBlockState(b, false).getState();
if (state instanceof Dispenser) {
for (ItemStack stack : ((Dispenser) state).getInventory()) {
if (stack != null && !stack.getType().isAir()) {
drops.add(stack);
}
}
}
}
};
}
@Nonnull
private BlockDispenseHandler onBlockDispense() { private BlockDispenseHandler onBlockDispense() {
return (e, dispenser, facedBlock, machine) -> { return (e, dispenser, facedBlock, machine) -> {
if (!hasPermission(dispenser, facedBlock)) { if (!hasPermission(dispenser, facedBlock)) {
@ -79,7 +114,7 @@ public class BlockPlacer extends SlimefunItem {
Material material = e.getItem().getType(); Material material = e.getItem().getType();
if (SlimefunTag.SHULKER_BOXES.isTagged(material)) { if (SlimefunTag.SHULKER_BOXES.isTagged(material)) {
/** /*
* Since vanilla Dispensers can already place Shulker boxes, * Since vanilla Dispensers can already place Shulker boxes,
* we simply fallback to the vanilla behaviour. * we simply fallback to the vanilla behaviour.
*/ */
@ -89,7 +124,7 @@ public class BlockPlacer extends SlimefunItem {
e.setCancelled(true); e.setCancelled(true);
if (!material.isBlock() || SlimefunTag.BLOCK_PLACER_IGNORED_MATERIALS.isTagged(material)) { if (!material.isBlock() || SlimefunTag.BLOCK_PLACER_IGNORED_MATERIALS.isTagged(material)) {
/** /*
* Some materials cannot be reliably placed, like beds, * Some materials cannot be reliably placed, like beds,
* it would look kinda wonky, so we just ignore these altogether. * it would look kinda wonky, so we just ignore these altogether.
* The event has already been cancelled too, so they won't drop. * The event has already been cancelled too, so they won't drop.
@ -97,7 +132,7 @@ public class BlockPlacer extends SlimefunItem {
return; return;
} }
if (facedBlock.isEmpty() && !isBlacklisted(material) && dispenser.getInventory().getViewers().isEmpty()) { if (facedBlock.isEmpty() && isAllowed(material) && dispenser.getInventory().getViewers().isEmpty()) {
SlimefunItem item = SlimefunItem.getByItem(e.getItem()); SlimefunItem item = SlimefunItem.getByItem(e.getItem());
if (item != null) { if (item != null) {
@ -123,11 +158,12 @@ public class BlockPlacer extends SlimefunItem {
* *
* @return Whether this action is permitted or not * @return Whether this action is permitted or not
*/ */
@ParametersAreNonnullByDefault
private boolean hasPermission(Dispenser dispenser, Block target) { private boolean hasPermission(Dispenser dispenser, Block target) {
String owner = BlockStorage.getLocationInfo(dispenser.getLocation(), "owner"); String owner = BlockStorage.getLocationInfo(dispenser.getLocation(), "owner");
if (owner == null) { if (owner == null) {
/** /*
* If no owner was set, then we will fallback to the previous behaviour: * If no owner was set, then we will fallback to the previous behaviour:
* Allowing block placers to bypass protection, newly placed Block placers * Allowing block placers to bypass protection, newly placed Block placers
* will respect protection plugins. * will respect protection plugins.
@ -135,20 +171,30 @@ public class BlockPlacer extends SlimefunItem {
return true; return true;
} }
// Get the corresponding OfflinePlayer
OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(owner)); OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(owner));
return SlimefunPlugin.getProtectionManager().hasPermission(player, target, ProtectableAction.PLACE_BLOCK); return SlimefunPlugin.getProtectionManager().hasPermission(player, target, ProtectableAction.PLACE_BLOCK);
} }
private boolean isBlacklisted(Material type) { /**
for (String blockType : blacklist.getValue()) { * This checks if the given {@link Material} is allowed to be placed.
*
* @param type
* The {@link Material} to check
*
* @return Whether placing this {@link Material} is allowed
*/
private boolean isAllowed(@Nonnull Material type) {
for (String blockType : unplaceableBlocks.getValue()) {
if (type.toString().equals(blockType)) { if (type.toString().equals(blockType)) {
return true; return false;
} }
} }
return false; return true;
} }
@ParametersAreNonnullByDefault
private void placeSlimefunBlock(SlimefunItem sfItem, ItemStack item, Block block, Dispenser dispenser) { private void placeSlimefunBlock(SlimefunItem sfItem, ItemStack item, Block block, Dispenser dispenser) {
BlockPlacerPlaceEvent e = new BlockPlacerPlaceEvent(dispenser.getBlock(), item, block); BlockPlacerPlaceEvent e = new BlockPlacerPlaceEvent(dispenser.getBlock(), item, block);
Bukkit.getPluginManager().callEvent(e); Bukkit.getPluginManager().callEvent(e);
@ -156,68 +202,78 @@ public class BlockPlacer extends SlimefunItem {
if (!e.isCancelled()) { if (!e.isCancelled()) {
boolean hasItemHandler = sfItem.callItemHandler(BlockPlaceHandler.class, handler -> { boolean hasItemHandler = sfItem.callItemHandler(BlockPlaceHandler.class, handler -> {
if (handler.isBlockPlacerAllowed()) { if (handler.isBlockPlacerAllowed()) {
block.setType(item.getType()); schedulePlacement(block, dispenser.getInventory(), item, () -> {
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, item.getType()); block.setType(item.getType());
BlockStorage.store(block, sfItem.getId());
BlockStorage.store(block, sfItem.getId()); handler.onBlockPlacerPlace(e);
handler.onBlockPlacerPlace(e); });
if (dispenser.getInventory().containsAtLeast(item, 2)) {
dispenser.getInventory().removeItem(new CustomItem(item, 1));
} else {
SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
}
} }
}); });
if (!hasItemHandler) { if (!hasItemHandler) {
block.setType(item.getType()); schedulePlacement(block, dispenser.getInventory(), item, () -> {
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, item.getType()); block.setType(item.getType());
BlockStorage.store(block, sfItem.getId());
BlockStorage.store(block, sfItem.getId()); });
if (dispenser.getInventory().containsAtLeast(item, 2)) {
dispenser.getInventory().removeItem(new CustomItem(item, 1));
} else {
SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
}
} }
} }
} }
@ParametersAreNonnullByDefault
private void placeBlock(ItemStack item, Block facedBlock, Dispenser dispenser) { private void placeBlock(ItemStack item, Block facedBlock, Dispenser dispenser) {
BlockPlacerPlaceEvent e = new BlockPlacerPlaceEvent(dispenser.getBlock(), item, facedBlock); BlockPlacerPlaceEvent e = new BlockPlacerPlaceEvent(dispenser.getBlock(), item, facedBlock);
Bukkit.getPluginManager().callEvent(e); Bukkit.getPluginManager().callEvent(e);
if (!e.isCancelled()) { if (!e.isCancelled()) {
facedBlock.setType(item.getType()); schedulePlacement(facedBlock, dispenser.getInventory(), item, () -> {
facedBlock.setType(item.getType());
if (item.hasItemMeta()) { if (item.hasItemMeta()) {
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if (meta.hasDisplayName()) { if (meta.hasDisplayName()) {
BlockStateSnapshotResult blockState = PaperLib.getBlockState(facedBlock, false); BlockStateSnapshotResult blockState = PaperLib.getBlockState(facedBlock, false);
if ((blockState.getState() instanceof Nameable)) { if ((blockState.getState() instanceof Nameable)) {
Nameable nameable = ((Nameable) blockState.getState()); Nameable nameable = ((Nameable) blockState.getState());
nameable.setCustomName(meta.getDisplayName()); nameable.setCustomName(meta.getDisplayName());
if (blockState.isSnapshot()) { if (blockState.isSnapshot()) {
// Update block state after changing name // Update block state after changing name
blockState.getState().update(true, false); blockState.getState().update(true, false);
}
} }
} }
} }
});
}
facedBlock.getWorld().playEffect(facedBlock.getLocation(), Effect.STEP_SOUND, item.getType());
if (dispenser.getInventory().containsAtLeast(item, 2)) {
dispenser.getInventory().removeItem(new CustomItem(item, 1));
} else {
SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
}
} }
} }
@ParametersAreNonnullByDefault
private void schedulePlacement(Block b, Inventory inv, ItemStack item, Runnable runnable) {
// We need to delay this due to Dispenser-Inventory synchronization issues in Spigot.
SlimefunPlugin.runSync(() -> {
// Make sure the Block has not been occupied yet
if (b.isEmpty()) {
// Only remove 1 item.
ItemStack removedItem = item.clone();
removedItem.setAmount(1);
// Play particles
b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, item.getType());
// Make sure the item was actually removed (fixes #2817)
try {
if (inv.removeItem(removedItem).isEmpty()) {
runnable.run();
}
} catch (Exception x) {
error("An Exception was thrown while a BlockPlacer was performing its action", x);
}
}
}, 2L);
}
} }

View File

@ -8,8 +8,10 @@ import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.Tag; import org.bukkit.Tag;
import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Levelled;
@ -19,6 +21,7 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -30,14 +33,26 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link Crucible} is a machine which turns blocks into liquids.
* It is a very reliable source of lava and water.
* The liquids will accumulate over time above the machine.
*
* @author TheBusyBiscuit
* @author Sfiguz7
*
*/
public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements RecipeDisplayItem { public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements RecipeDisplayItem {
private final ItemSetting<Boolean> allowWaterInNether = new ItemSetting<>("allow-water-in-nether", false);
private final List<ItemStack> recipes; private final List<ItemStack> recipes;
@ParametersAreNonnullByDefault
public Crucible(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public Crucible(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
recipes = getMachineRecipes(); recipes = getMachineRecipes();
addItemSetting(allowWaterInNether);
} }
@Override @Override
@ -45,6 +60,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
return recipes; return recipes;
} }
@Nonnull
private List<ItemStack> getMachineRecipes() { private List<ItemStack> getMachineRecipes() {
List<ItemStack> items = new LinkedList<>(); List<ItemStack> items = new LinkedList<>();
@ -113,11 +129,11 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
private boolean craft(Player p, ItemStack input) { private boolean craft(Player p, ItemStack input) {
for (int i = 0; i < recipes.size(); i += 2) { for (int i = 0; i < recipes.size(); i += 2) {
ItemStack convert = recipes.get(i); ItemStack catalyst = recipes.get(i);
if (SlimefunUtils.isItemSimilar(input, convert, true)) { if (SlimefunUtils.isItemSimilar(input, catalyst, true)) {
ItemStack removing = input.clone(); ItemStack removing = input.clone();
removing.setAmount(convert.getAmount()); removing.setAmount(catalyst.getAmount());
p.getInventory().removeItem(removing); p.getInventory().removeItem(removing);
return true; return true;
@ -127,15 +143,31 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
return false; return false;
} }
private void generateLiquid(@Nonnull Block block, boolean water) { /**
if (block.getType() == (water ? Material.WATER : Material.LAVA)) { * This method starts the process of generating liquids.
addLiquidLevel(block, water); *
} else if (block.getType() == (water ? Material.LAVA : Material.WATER)) { * @param block
* The {@link Block} where to generate the liquid
* @param isWater
* Whether we generate water or lava.
*/
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().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
return;
}
if (block.getType() == (isWater ? Material.WATER : Material.LAVA)) {
addLiquidLevel(block, isWater);
} else if (block.getType() == (isWater ? Material.LAVA : Material.WATER)) {
int level = ((Levelled) block.getBlockData()).getLevel(); int level = ((Levelled) block.getBlockData()).getLevel();
block.setType(level == 0 || level == 8 ? Material.OBSIDIAN : Material.STONE); block.setType(level == 0 || level == 8 ? Material.OBSIDIAN : Material.STONE);
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F); block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
} else { } else {
SlimefunPlugin.runSync(() -> placeLiquid(block, water), 50L); SlimefunPlugin.runSync(() -> placeLiquid(block, isWater), 50L);
} }
} }

View File

@ -1,5 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks; package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -16,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram; import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
@ -30,12 +34,14 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
private static final String OFFSET_PARAMETER = "offset"; private static final String OFFSET_PARAMETER = "offset";
@ParametersAreNonnullByDefault
public HologramProjector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) { public HologramProjector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput); super(category, item, recipeType, recipe, recipeOutput);
addItemHandler(onPlace(), onRightClick(), onBreak()); addItemHandler(onPlace(), onRightClick(), onBreak());
} }
@Nonnull
private BlockPlaceHandler onPlace() { private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) { return new BlockPlaceHandler(false) {
@ -52,13 +58,18 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
}; };
} }
@Nonnull
private BlockBreakHandler onBreak() { private BlockBreakHandler onBreak() {
return (e, item, fortune, drops) -> { return new SimpleBlockBreakHandler() {
remove(e.getBlock());
return true; @Override
public void onBlockBreak(@Nonnull Block b) {
remove(b);
}
}; };
} }
@Nonnull
public BlockUseHandler onRightClick() { public BlockUseHandler onRightClick() {
return e -> { return e -> {
e.cancel(); e.cancel();
@ -72,7 +83,7 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
}; };
} }
private static void openEditor(Player p, Block projector) { private static void openEditor(@Nonnull Player p, @Nonnull Block projector) {
ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocalization().getMessage(p, "machines.HOLOGRAM_PROJECTOR.inventory-title")); ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocalization().getMessage(p, "machines.HOLOGRAM_PROJECTOR.inventory-title"));
menu.addItem(0, new CustomItem(Material.NAME_TAG, "&7Text &e(Click to edit)", "", "&r" + ChatColors.color(BlockStorage.getLocationInfo(projector.getLocation(), "text")))); menu.addItem(0, new CustomItem(Material.NAME_TAG, "&7Text &e(Click to edit)", "", "&r" + ChatColors.color(BlockStorage.getLocationInfo(projector.getLocation(), "text"))));
@ -105,7 +116,7 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
menu.open(p); menu.open(p);
} }
private static ArmorStand getArmorStand(Block projector, boolean createIfNoneExists) { private static ArmorStand getArmorStand(@Nonnull Block projector, boolean createIfNoneExists) {
String nametag = BlockStorage.getLocationInfo(projector.getLocation(), "text"); String nametag = BlockStorage.getLocationInfo(projector.getLocation(), "text");
double offset = Double.parseDouble(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER)); double offset = Double.parseDouble(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER));
Location l = new Location(projector.getWorld(), projector.getX() + 0.5, projector.getY() + offset, projector.getZ() + 0.5); Location l = new Location(projector.getWorld(), projector.getX() + 0.5, projector.getY() + offset, projector.getZ() + 0.5);
@ -129,7 +140,7 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
return hologram; return hologram;
} }
private static void remove(Block b) { private static void remove(@Nonnull Block b) {
ArmorStand hologram = getArmorStand(b, false); ArmorStand hologram = getArmorStand(b, false);
if (hologram != null) { if (hologram != null) {

View File

@ -0,0 +1,62 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import java.util.List;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Dropper;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.Smeltery;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link IgnitionChamber} is used to re-ignite a {@link Smeltery}.
*
* @author TheBusyBiscuit
*
* @see Smeltery
*
*/
public class IgnitionChamber extends SimpleSlimefunItem<BlockBreakHandler> {
@ParametersAreNonnullByDefault
public IgnitionChamber(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@Override
public BlockBreakHandler getItemHandler() {
/*
* Explosions don't need explicit handling here.
* The default of "destroy the dispenser and drop the contents" is
* fine for our purposes already.
*/
return new BlockBreakHandler(false, true) {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
// Fixes #2856 - Manually drop inventory contents
Block b = e.getBlock();
BlockState state = PaperLib.getBlockState(b, false).getState();
if (state instanceof Dropper) {
for (ItemStack stack : ((Dropper) state).getInventory()) {
if (stack != null && !stack.getType().isAir()) {
drops.add(stack);
}
}
}
}
};
}
}

View File

@ -0,0 +1,63 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import java.util.List;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link OutputChest} can be used to capture the output items from a {@link MultiBlockMachine}.
*
* @author TheBusyBiscuit
*
* @see MultiBlockMachine
*
*/
public class OutputChest extends SimpleSlimefunItem<BlockBreakHandler> {
@ParametersAreNonnullByDefault
public OutputChest(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@Override
public BlockBreakHandler getItemHandler() {
/*
* Explosions don't need explicit handling here.
* The default of "destroy the chest and drop the contents" is
* fine for our purposes already.
*/
return new BlockBreakHandler(false, true) {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
// Fixes #2849 - Manually drop inventory contents
Block b = e.getBlock();
BlockState state = PaperLib.getBlockState(b, false).getState();
if (state instanceof Chest) {
// Fixes #2851 - Only drop the actual BlockInventory
for (ItemStack stack : ((Chest) state).getBlockInventory()) {
if (stack != null && !stack.getType().isAir()) {
drops.add(stack);
}
}
}
}
};
}
}

View File

@ -11,7 +11,9 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
@ -39,15 +41,27 @@ abstract class AbstractFilterNode extends AbstractCargoNode {
public AbstractFilterNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) { public AbstractFilterNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput); super(category, item, recipeType, recipe, recipeOutput);
registerBlockHandler(getId(), (p, b, stack, reason) -> { addItemHandler(onBreak());
BlockMenu inv = BlockStorage.getInventory(b); }
if (inv != null) { @Override
inv.dropItems(b.getLocation(), SLOTS); public boolean hasItemFilter() {
return true;
}
@Nonnull
private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(@Nonnull Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), SLOTS);
}
} }
};
return true;
});
} }
@Nonnull @Nonnull

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -11,8 +12,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
@ -27,10 +30,18 @@ public class CargoManager extends SlimefunItem implements HologramOwner {
public CargoManager(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public CargoManager(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
registerBlockHandler(getId(), (p, b, tool, reason) -> { addItemHandler(onBreak());
removeHologram(b); }
return true;
}); @Nonnull
private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(@Nonnull Block b) {
removeHologram(b);
}
};
} }
@Override @Override

View File

@ -14,7 +14,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
* @author TheBusyBiscuit * @author TheBusyBiscuit
* *
*/ */
@FunctionalInterface
public interface CargoNode { public interface CargoNode {
/** /**
@ -27,4 +26,11 @@ public interface CargoNode {
*/ */
int getSelectedChannel(@Nonnull Block b); int getSelectedChannel(@Nonnull Block b);
/**
* This returns whether this {@link CargoNode} has item filtering capabilities.
*
* @return Whether this {@link CargoNode} can filter items
*/
boolean hasItemFilter();
} }

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo; package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -18,10 +20,16 @@ public class CargoOutputNode extends AbstractCargoNode {
private static 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[] 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 };
@ParametersAreNonnullByDefault
public CargoOutputNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) { public CargoOutputNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput); super(category, item, recipeType, recipe, recipeOutput);
} }
@Override
public boolean hasItemFilter() {
return false;
}
@Override @Override
protected void onPlace(BlockPlaceEvent e) { protected void onPlace(BlockPlaceEvent e) {
// We only require the default values // We only require the default values

View File

@ -12,9 +12,11 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.CoolantCell; import io.github.thebusybiscuit.slimefun4.implementation.items.misc.CoolantCell;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -50,6 +52,8 @@ public class ReactorAccessPort extends SlimefunItem {
public ReactorAccessPort(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public ReactorAccessPort(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
addItemHandler(onBreak());
new BlockMenuPreset(getId(), "&2Reactor Access Port") { new BlockMenuPreset(getId(), "&2Reactor Access Port") {
@Override @Override
@ -108,18 +112,23 @@ public class ReactorAccessPort extends SlimefunItem {
} }
} }
}; };
}
registerBlockHandler(getId(), (p, b, tool, reason) -> { @Nonnull
BlockMenu inv = BlockStorage.getInventory(b); private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
if (inv != null) { @Override
inv.dropItems(b.getLocation(), getFuelSlots()); public void onBlockBreak(@Nonnull Block b) {
inv.dropItems(b.getLocation(), getCoolantSlots()); BlockMenu inv = BlockStorage.getInventory(b);
inv.dropItems(b.getLocation(), getOutputSlots());
if (inv != null) {
inv.dropItems(b.getLocation(), getFuelSlots());
inv.dropItems(b.getLocation(), getCoolantSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
} }
};
return true;
});
} }
private void constructMenu(@Nonnull BlockMenuPreset preset) { private void constructMenu(@Nonnull BlockMenuPreset preset) {

View File

@ -9,8 +9,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet; import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
@ -34,10 +36,18 @@ public class EnergyRegulator extends SlimefunItem implements HologramOwner {
public EnergyRegulator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public EnergyRegulator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
SlimefunItem.registerBlockHandler(getId(), (p, b, stack, reason) -> { addItemHandler(onBreak());
removeHologram(b); }
return true;
}); @Nonnull
private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(@Nonnull Block b) {
removeHologram(b);
}
};
} }
@Nonnull @Nonnull

View File

@ -110,14 +110,14 @@ public class MultiTool extends SlimefunItem implements Rechargeable {
return (e, item, offhand) -> { return (e, item, offhand) -> {
// Fixes #2217 - Prevent them from being used to shear entities // Fixes #2217 - Prevent them from being used to shear entities
switch (e.getRightClicked().getType()) { switch (e.getRightClicked().getType()) {
case MUSHROOM_COW: case MUSHROOM_COW:
case SHEEP: case SHEEP:
case SNOWMAN: case SNOWMAN:
SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears"); SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears");
e.setCancelled(true); e.setCancelled(true);
break; break;
default: default:
break; break;
} }
}; };
} }

View File

@ -2,84 +2,25 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
public abstract class AbstractGrowthAccelerator extends SlimefunItem implements InventoryBlock, EnergyNetComponent { /**
* This has been moved.
private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; *
* @deprecated Moved to
* {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AbstractGrowthAccelerator}
*
*/
@Deprecated
public abstract class AbstractGrowthAccelerator extends io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AbstractGrowthAccelerator {
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public AbstractGrowthAccelerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public AbstractGrowthAccelerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
createPreset(this, this::constructMenu);
registerBlockHandler(getId(), (p, b, tool, reason) -> {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
}
return true;
});
} }
private void constructMenu(BlockMenuPreset preset) {
for (int i : BORDER) {
preset.addItem(i, new CustomItem(Material.CYAN_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler());
}
}
@Override
public EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.CONSUMER;
}
@Override
public int[] getInputSlots() {
return new int[] { 10, 11, 12, 13, 14, 15, 16 };
}
@Override
public int[] getOutputSlots() {
return new int[0];
}
@Override
public void preRegister() {
super.preRegister();
addItemHandler(new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
AbstractGrowthAccelerator.this.tick(b);
}
@Override
public boolean isSynchronized() {
return true;
}
});
}
protected abstract void tick(Block b);
} }

View File

@ -1,140 +1,26 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.Repairable;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import io.github.thebusybiscuit.slimefun4.api.events.AutoDisenchantEvent;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
/** /**
* The {@link AutoDisenchanter}, in contrast to the {@link AutoEnchanter}, removes * This has been moved.
* {@link Enchantment Enchantments} from a given {@link ItemStack} and transfers them
* to a book.
* *
* @author TheBusyBiscuit * @deprecated Moved to
* @author Walshy * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter}
* @author poma123
*
* @see AutoEnchanter
* *
*/ */
public class AutoDisenchanter extends AContainer { @Deprecated
public class AutoDisenchanter extends io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter {
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public AutoDisenchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public AutoDisenchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
} }
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.DIAMOND_CHESTPLATE);
}
@Override
protected MachineRecipe findNextRecipe(BlockMenu menu) {
Map<Enchantment, Integer> enchantments = new HashMap<>();
for (int slot : getInputSlots()) {
ItemStack item = menu.getItemInSlot(slot);
if (!isDisenchantable(item)) {
return null;
}
AutoDisenchantEvent event = new AutoDisenchantEvent(item);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return null;
}
ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
// Disenchanting
if (target != null && target.getType() == Material.BOOK) {
int amount = 0;
for (Map.Entry<Enchantment, Integer> entry : item.getEnchantments().entrySet()) {
enchantments.put(entry.getKey(), entry.getValue());
amount++;
}
if (amount > 0) {
ItemStack disenchantedItem = item.clone();
disenchantedItem.setAmount(1);
ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
transferEnchantments(disenchantedItem, book, enchantments);
MachineRecipe recipe = new MachineRecipe(90 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { disenchantedItem, book });
if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
return null;
}
for (int inputSlot : getInputSlots()) {
menu.consumeItem(inputSlot);
}
return recipe;
}
}
}
return null;
}
private void transferEnchantments(ItemStack item, ItemStack book, Map<Enchantment, Integer> enchantments) {
ItemMeta itemMeta = item.getItemMeta();
ItemMeta bookMeta = book.getItemMeta();
((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost());
((Repairable) itemMeta).setRepairCost(0);
item.setItemMeta(itemMeta);
book.setItemMeta(bookMeta);
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta();
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
item.removeEnchantment(entry.getKey());
meta.addStoredEnchant(entry.getKey(), entry.getValue(), true);
}
book.setItemMeta(meta);
}
private boolean isDisenchantable(@Nullable ItemStack item) {
if (item == null) {
return false;
} else if (item.getType() != Material.BOOK) {
// ^ This stops endless checks of getByItem for books
SlimefunItem sfItem = SlimefunItem.getByItem(item);
return sfItem == null || sfItem.isDisenchantable();
} else {
return true;
}
}
@Override
public String getMachineIdentifier() {
return "AUTO_DISENCHANTER";
}
} }

View File

@ -1,102 +1,26 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
public class AutoEnchanter extends AContainer { /**
* This has been moved.
*
* @deprecated Moved to
* {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter}
*
*/
@Deprecated
public class AutoEnchanter extends io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter {
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public AutoEnchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public AutoEnchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
} }
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.GOLDEN_CHESTPLATE);
}
@Override
protected MachineRecipe findNextRecipe(BlockMenu menu) {
for (int slot : getInputSlots()) {
ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
// Check if the item is enchantable
if (!isEnchantable(target)) {
return null;
}
ItemStack item = menu.getItemInSlot(slot);
if (item != null && item.getType() == Material.ENCHANTED_BOOK && target != null) {
Map<Enchantment, Integer> enchantments = new HashMap<>();
int amount = 0;
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta();
for (Map.Entry<Enchantment, Integer> e : meta.getStoredEnchants().entrySet()) {
if (e.getKey().canEnchantItem(target)) {
amount++;
enchantments.put(e.getKey(), e.getValue());
}
}
if (amount > 0) {
ItemStack enchantedItem = target.clone();
enchantedItem.setAmount(1);
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
enchantedItem.addUnsafeEnchantment(entry.getKey(), entry.getValue());
}
MachineRecipe recipe = new MachineRecipe(75 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { enchantedItem, new ItemStack(Material.BOOK) });
if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
return null;
}
for (int inputSlot : getInputSlots()) {
menu.consumeItem(inputSlot);
}
return recipe;
}
return null;
}
}
return null;
}
private boolean isEnchantable(ItemStack item) {
SlimefunItem sfItem = null;
// stops endless checks of getByItem for enchanted book stacks.
if (item != null && item.getType() != Material.ENCHANTED_BOOK) {
sfItem = SlimefunItem.getByItem(item);
}
return sfItem == null || sfItem.isEnchantable();
}
@Override
public String getMachineIdentifier() {
return "AUTO_ENCHANTER";
}
} }

View File

@ -7,6 +7,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -57,10 +60,11 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
private final Map<String, ItemStack> craftingRecipes = new HashMap<>(); private final Map<String, ItemStack> craftingRecipes = new HashMap<>();
@ParametersAreNonnullByDefault
public AutomatedCraftingChamber(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public AutomatedCraftingChamber(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
new BlockMenuPreset(getId(), "&6Automated Crafting Chamber") { new BlockMenuPreset(getId(), "&4Deprecated item. Do not use.") {
@Override @Override
public void init() { public void init() {
@ -94,6 +98,7 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
@Override @Override
public boolean canOpen(Block b, Player p) { public boolean canOpen(Block b, Player p) {
p.sendMessage(ChatColor.DARK_RED + "This item has been deprecated. It will be removed soon!");
return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK);
} }
@ -145,6 +150,7 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
@Override @Override
public void onPlayerPlace(BlockPlaceEvent e) { public void onPlayerPlace(BlockPlaceEvent e) {
e.getPlayer().sendMessage(ChatColor.DARK_RED + "This item has been deprecated. It will be removed soon!");
BlockStorage.addBlockInfo(e.getBlock(), "enabled", String.valueOf(false)); BlockStorage.addBlockInfo(e.getBlock(), "enabled", String.valueOf(false));
} }

View File

@ -0,0 +1,85 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
public abstract class AbstractGrowthAccelerator extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
@ParametersAreNonnullByDefault
public AbstractGrowthAccelerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
createPreset(this, this::constructMenu);
registerBlockHandler(getId(), (p, b, tool, reason) -> {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
}
return true;
});
}
private void constructMenu(BlockMenuPreset preset) {
for (int i : BORDER) {
preset.addItem(i, new CustomItem(Material.CYAN_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler());
}
}
@Override
public EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.CONSUMER;
}
@Override
public int[] getInputSlots() {
return new int[] { 10, 11, 12, 13, 14, 15, 16 };
}
@Override
public int[] getOutputSlots() {
return new int[0];
}
@Override
public void preRegister() {
super.preRegister();
addItemHandler(new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
AbstractGrowthAccelerator.this.tick(b);
}
@Override
public boolean isSynchronized() {
return true;
}
});
}
protected abstract void tick(Block b);
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.block.Block; import org.bukkit.block.Block;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.block.Block; import org.bukkit.block.Block;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.Tag; import org.bukkit.Tag;

View File

@ -0,0 +1,5 @@
/**
* This package contains any electric machines related to growth accelerations.
* These growth accelerators speed up the growth of animals or plants.
*/
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;

View File

@ -0,0 +1,140 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.Repairable;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import io.github.thebusybiscuit.slimefun4.api.events.AutoDisenchantEvent;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
/**
* The {@link AutoDisenchanter}, in contrast to the {@link AutoEnchanter}, removes
* {@link Enchantment Enchantments} from a given {@link ItemStack} and transfers them
* to a book.
*
* @author TheBusyBiscuit
* @author Walshy
* @author poma123
*
* @see AutoEnchanter
*
*/
public class AutoDisenchanter extends AContainer {
@ParametersAreNonnullByDefault
public AutoDisenchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.DIAMOND_CHESTPLATE);
}
@Override
protected MachineRecipe findNextRecipe(BlockMenu menu) {
Map<Enchantment, Integer> enchantments = new HashMap<>();
for (int slot : getInputSlots()) {
ItemStack item = menu.getItemInSlot(slot);
if (!isDisenchantable(item)) {
return null;
}
AutoDisenchantEvent event = new AutoDisenchantEvent(item);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return null;
}
ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
// Disenchanting
if (target != null && target.getType() == Material.BOOK) {
int amount = 0;
for (Map.Entry<Enchantment, Integer> entry : item.getEnchantments().entrySet()) {
enchantments.put(entry.getKey(), entry.getValue());
amount++;
}
if (amount > 0) {
ItemStack disenchantedItem = item.clone();
disenchantedItem.setAmount(1);
ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
transferEnchantments(disenchantedItem, book, enchantments);
MachineRecipe recipe = new MachineRecipe(90 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { disenchantedItem, book });
if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
return null;
}
for (int inputSlot : getInputSlots()) {
menu.consumeItem(inputSlot);
}
return recipe;
}
}
}
return null;
}
private void transferEnchantments(ItemStack item, ItemStack book, Map<Enchantment, Integer> enchantments) {
ItemMeta itemMeta = item.getItemMeta();
ItemMeta bookMeta = book.getItemMeta();
((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost());
((Repairable) itemMeta).setRepairCost(0);
item.setItemMeta(itemMeta);
book.setItemMeta(bookMeta);
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta();
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
item.removeEnchantment(entry.getKey());
meta.addStoredEnchant(entry.getKey(), entry.getValue(), true);
}
book.setItemMeta(meta);
}
private boolean isDisenchantable(@Nullable ItemStack item) {
if (item == null) {
return false;
} else if (item.getType() != Material.BOOK) {
// ^ This stops endless checks of getByItem for books
SlimefunItem sfItem = SlimefunItem.getByItem(item);
return sfItem == null || sfItem.isDisenchantable();
} else {
return true;
}
}
@Override
public String getMachineIdentifier() {
return "AUTO_DISENCHANTER";
}
}

View File

@ -0,0 +1,102 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
public class AutoEnchanter extends AContainer {
@ParametersAreNonnullByDefault
public AutoEnchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.GOLDEN_CHESTPLATE);
}
@Override
protected MachineRecipe findNextRecipe(BlockMenu menu) {
for (int slot : getInputSlots()) {
ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
// Check if the item is enchantable
if (!isEnchantable(target)) {
return null;
}
ItemStack item = menu.getItemInSlot(slot);
if (item != null && item.getType() == Material.ENCHANTED_BOOK && target != null) {
Map<Enchantment, Integer> enchantments = new HashMap<>();
int amount = 0;
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta();
for (Map.Entry<Enchantment, Integer> e : meta.getStoredEnchants().entrySet()) {
if (e.getKey().canEnchantItem(target)) {
amount++;
enchantments.put(e.getKey(), e.getValue());
}
}
if (amount > 0) {
ItemStack enchantedItem = target.clone();
enchantedItem.setAmount(1);
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
enchantedItem.addUnsafeEnchantment(entry.getKey(), entry.getValue());
}
MachineRecipe recipe = new MachineRecipe(75 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { enchantedItem, new ItemStack(Material.BOOK) });
if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
return null;
}
for (int inputSlot : getInputSlots()) {
menu.consumeItem(inputSlot);
}
return recipe;
}
return null;
}
}
return null;
}
private boolean isEnchantable(ItemStack item) {
SlimefunItem sfItem = null;
// stops endless checks of getByItem for enchanted book stacks.
if (item != null && item.getType() != Material.ENCHANTED_BOOK) {
sfItem = SlimefunItem.getByItem(item);
}
return sfItem == null || sfItem.isEnchantable();
}
@Override
public String getMachineIdentifier() {
return "AUTO_ENCHANTER";
}
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -54,6 +54,7 @@ public class BookBinder extends AContainer {
Map<Enchantment, Integer> storedTargetEnchantments = targetMeta.getStoredEnchants(); Map<Enchantment, Integer> storedTargetEnchantments = targetMeta.getStoredEnchants();
Map<Enchantment, Integer> enchantments = combineEnchantments(storedItemEnchantments, storedTargetEnchantments); Map<Enchantment, Integer> enchantments = combineEnchantments(storedItemEnchantments, storedTargetEnchantments);
// Just return if no enchantments exist. This shouldn't ever happen. :NotLikeThis:
if (enchantments.size() > 0) { if (enchantments.size() > 0) {
ItemStack book = new ItemStack(Material.ENCHANTED_BOOK); ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
@ -63,6 +64,11 @@ public class BookBinder extends AContainer {
enchantMeta.addStoredEnchant(entry.getKey(), entry.getValue(), bypassVanillaMaxLevel.getValue()); enchantMeta.addStoredEnchant(entry.getKey(), entry.getValue(), bypassVanillaMaxLevel.getValue());
} }
// Make sure we never return an enchanted book with no enchantments.
if (enchantMeta.getStoredEnchants().isEmpty()) {
return null;
}
book.setItemMeta(enchantMeta); book.setItemMeta(enchantMeta);
MachineRecipe recipe = new MachineRecipe(25 * (enchantments.size() / this.getSpeed()), new ItemStack[] { target, item }, new ItemStack[] { book }); MachineRecipe recipe = new MachineRecipe(25 * (enchantments.size() / this.getSpeed()), new ItemStack[] { target, item }, new ItemStack[] { book });
@ -109,15 +115,25 @@ public class BookBinder extends AContainer {
for (Map.Entry<Enchantment, Integer> entry : ech2.entrySet()) { for (Map.Entry<Enchantment, Integer> entry : ech2.entrySet()) {
for (Map.Entry<Enchantment, Integer> conflictsWith : enchantments.entrySet()) { for (Map.Entry<Enchantment, Integer> conflictsWith : enchantments.entrySet()) {
if (entry.getKey().conflictsWith(conflictsWith.getKey())) {
// Check if entry enchantment and conflictsWith enchantment conflict, and confirm that the enchantsments
// aren't the exact same.
if (entry.getKey().conflictsWith(conflictsWith.getKey()) && !entry.getKey().equals(conflictsWith.getKey())) {
conflicts = true; conflicts = true;
} }
} }
if (!conflicts) { if (!conflicts) {
enchantments.merge(entry.getKey(), entry.getValue(), (a, b) -> { enchantments.merge(entry.getKey(), entry.getValue(), (a, b) -> {
int enchantMaxLevel = entry.getKey().getMaxLevel();
if (a.intValue() == b.intValue()) { if (a.intValue() == b.intValue()) {
if (hasCustomMaxLevel.getValue()) {
// Confirm the entry's enchant level doesn't go over the maximum unless it uses
// bypass-vanilla-max-level
if (enchantMaxLevel <= a && !bypassVanillaMaxLevel.getValue()) {
return enchantMaxLevel;
} else if (hasCustomMaxLevel.getValue()) {
return a + 1 > customMaxLevel.getValue() ? customMaxLevel.getValue() : a + 1; return a + 1 > customMaxLevel.getValue() ? customMaxLevel.getValue() : a + 1;
} else { } else {
return a + 1; return a + 1;
@ -125,7 +141,11 @@ public class BookBinder extends AContainer {
} else { } else {
int highestLevel = Math.max(a, b); int highestLevel = Math.max(a, b);
if (hasCustomMaxLevel.getValue()) { // Confirm the entry's enchant level doesn't go over the maximum unless it uses
// bypass-vanilla-max-level
if (enchantMaxLevel <= highestLevel && !bypassVanillaMaxLevel.getValue()) {
return enchantMaxLevel;
} else if (hasCustomMaxLevel.getValue()) {
return highestLevel > customMaxLevel.getValue() ? customMaxLevel.getValue() : highestLevel; return highestLevel > customMaxLevel.getValue() ? customMaxLevel.getValue() : highestLevel;
} else { } else {
return highestLevel; return highestLevel;

View File

@ -0,0 +1,7 @@
/**
* This package contains any electric machines related to enchanting.
* Prominent examples are the
* {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter} and
* {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter}
*/
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Location; import org.bukkit.Location;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.Iterator; import java.util.Iterator;
@ -25,14 +25,14 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
public class XPCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent { public class ExpCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
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 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 int ENERGY_CONSUMPTION = 10;
private static final String DATA_KEY = "stored-exp"; private static final String DATA_KEY = "stored-exp";
public XPCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public ExpCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
createPreset(this, this::constructMenu); createPreset(this, this::constructMenu);
@ -91,7 +91,7 @@ public class XPCollector extends SlimefunItem implements InventoryBlock, EnergyN
@Override @Override
public void tick(Block b, SlimefunItem sf, Config data) { public void tick(Block b, SlimefunItem sf, Config data) {
XPCollector.this.tick(b); ExpCollector.this.tick(b);
} }
@Override @Override

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines; package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;

View File

@ -0,0 +1,6 @@
/**
* This package contains any electric machines related to {@link org.bukkit.entity.Entity} interactions, most notably
* the
* {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.AbstractEntityAssembler}.
*/
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;

View File

@ -24,10 +24,12 @@ import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.ReactorExplodeEvent; import io.github.thebusybiscuit.slimefun4.api.events.ReactorExplodeEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.core.attributes.Processor; import io.github.thebusybiscuit.slimefun4.core.attributes.Processor;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.machines.FuelOperation; import io.github.thebusybiscuit.slimefun4.core.machines.FuelOperation;
import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor; import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.ReactorAccessPort; import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.ReactorAccessPort;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.AbstractEnergyProvider; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.AbstractEnergyProvider;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -73,7 +75,6 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram
private static final int[] border_4 = { 25, 34, 43 }; private static final int[] border_4 = { 25, 34, 43 };
private final Set<Location> explosionsQueue = new HashSet<>(); private final Set<Location> explosionsQueue = new HashSet<>();
private final MachineProcessor<FuelOperation> processor = new MachineProcessor<>(); private final MachineProcessor<FuelOperation> processor = new MachineProcessor<>();
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
@ -109,20 +110,7 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram
} }
}; };
registerBlockHandler(getId(), (p, b, tool, reason) -> { addItemHandler(onBreak());
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getFuelSlots());
inv.dropItems(b.getLocation(), getCoolantSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
processor.removeOperation(b);
removeHologram(b);
return true;
});
registerDefaultFuelTypes(); registerDefaultFuelTypes();
} }
@ -131,6 +119,26 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram
return processor; return processor;
} }
@Nonnull
private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(@Nonnull Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getFuelSlots());
inv.dropItems(b.getLocation(), getCoolantSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
processor.removeOperation(b);
removeHologram(b);
}
};
}
protected void updateInventory(@Nonnull BlockMenu menu, @Nonnull Block b) { protected void updateInventory(@Nonnull BlockMenu menu, @Nonnull Block b) {
ReactorMode mode = getReactorMode(b.getLocation()); ReactorMode mode = getReactorMode(b.getLocation());

View File

@ -21,12 +21,15 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.core.attributes.Processor; import io.github.thebusybiscuit.slimefun4.core.attributes.Processor;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor; import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor;
import io.github.thebusybiscuit.slimefun4.core.machines.MiningOperation; import io.github.thebusybiscuit.slimefun4.core.machines.MiningOperation;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
// github.com/Slimefun/Slimefun4.git
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
@ -56,20 +59,10 @@ public class GEOMiner extends SlimefunItem implements RecipeDisplayItem, EnergyN
processor.setProgressBar(new ItemStack(Material.DIAMOND_PICKAXE)); processor.setProgressBar(new ItemStack(Material.DIAMOND_PICKAXE));
createPreset(this, getItemName(), this::constructMenu); createPreset(this, getItemName(), this::constructMenu);
addItemHandler(onPlace()); addItemHandler(onPlace(), onBreak());
registerBlockHandler(getId(), (p, b, stack, reason) -> { // Unregister the Block handler from AContainer (Fixes #2861)
removeHologram(b); registerBlockHandler(getId(), null);
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), OUTPUT_SLOTS);
}
getMachineProcessor().removeOperation(b);
return true;
});
} }
@Override @Override
@ -88,6 +81,24 @@ public class GEOMiner extends SlimefunItem implements RecipeDisplayItem, EnergyN
}; };
} }
@Nonnull
private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(@Nonnull Block b) {
removeHologram(b);
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), OUTPUT_SLOTS);
}
processor.removeOperation(b);
}
};
}
@Override @Override
public List<ItemStack> getDisplayRecipes() { public List<ItemStack> getDisplayRecipes() {
List<ItemStack> displayRecipes = new LinkedList<>(); List<ItemStack> displayRecipes = new LinkedList<>();

View File

@ -1,12 +1,19 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.gps; package io.github.thebusybiscuit.slimefun4.implementation.items.gps;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -23,16 +30,12 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem<BlockTicker> imp
private final int capacity; private final int capacity;
@ParametersAreNonnullByDefault
public GPSTransmitter(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public GPSTransmitter(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
this.capacity = 4 << (2 * tier); this.capacity = 4 << (2 * tier);
addItemHandler(onPlace()); addItemHandler(onPlace(), onBreak());
registerBlockHandler(getId(), (p, b, stack, reason) -> {
UUID owner = UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner"));
SlimefunPlugin.getGPSNetwork().updateTransmitter(b.getLocation(), owner, false);
return true;
});
} }
@Override @Override
@ -40,6 +43,7 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem<BlockTicker> imp
return capacity; return capacity;
} }
@Nonnull
private BlockPlaceHandler onPlace() { private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) { return new BlockPlaceHandler(false) {
@ -50,6 +54,19 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem<BlockTicker> imp
}; };
} }
@Nonnull
private BlockBreakHandler onBreak() {
return new BlockBreakHandler(false, false) {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
Location l = e.getBlock().getLocation();
UUID owner = UUID.fromString(BlockStorage.getLocationInfo(l, "owner"));
SlimefunPlugin.getGPSNetwork().updateTransmitter(l, owner, false);
}
};
}
public abstract int getMultiplier(int y); public abstract int getMultiplier(int y);
public abstract int getEnergyConsumption(); public abstract int getEnergyConsumption();

View File

@ -9,6 +9,9 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle; import org.bukkit.Particle;
@ -25,7 +28,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunIte
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
@ -42,6 +44,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
private static final double RANGE = 1.5; private static final double RANGE = 1.5;
private final Map<Material, List<Enchantment>> applicableEnchantments = new EnumMap<>(Material.class); private final Map<Material, List<Enchantment>> applicableEnchantments = new EnumMap<>(Material.class);
@ParametersAreNonnullByDefault
public EnchantmentRune(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { public EnchantmentRune(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe); super(category, item, recipeType, recipe);
@ -49,7 +52,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
List<Enchantment> enchantments = new ArrayList<>(); List<Enchantment> enchantments = new ArrayList<>();
for (Enchantment enchantment : Enchantment.values()) { for (Enchantment enchantment : Enchantment.values()) {
if (enchantment == Enchantment.BINDING_CURSE || enchantment == Enchantment.VANISHING_CURSE) { if (enchantment.equals(Enchantment.BINDING_CURSE) || enchantment.equals(Enchantment.VANISHING_CURSE)) {
continue; continue;
} }
@ -66,7 +69,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
public ItemDropHandler getItemHandler() { public ItemDropHandler getItemHandler() {
return (e, p, item) -> { return (e, p, item) -> {
if (isItem(item.getItemStack())) { if (isItem(item.getItemStack())) {
if (Slimefun.hasUnlocked(p, this, true)) { if (canUse(p, true)) {
SlimefunPlugin.runSync(() -> { SlimefunPlugin.runSync(() -> {
try { try {
addRandomEnchantment(p, item); addRandomEnchantment(p, item);
@ -83,7 +86,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
}; };
} }
private void addRandomEnchantment(Player p, Item rune) { private void addRandomEnchantment(@Nonnull Player p, @Nonnull Item rune) {
// Being sure the entity is still valid and not picked up or whatsoever. // Being sure the entity is still valid and not picked up or whatsoever.
if (!rune.isValid()) { if (!rune.isValid()) {
return; return;
@ -106,8 +109,18 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
potentialEnchantments = new ArrayList<>(potentialEnchantments); potentialEnchantments = new ArrayList<>(potentialEnchantments);
} }
// Removing the enchantments that the item already has from enchantmentSet SlimefunItem slimefunItem = SlimefunItem.getByItem(itemStack);
// This also removes any conflicting enchantments
// Fixes #2878 - Respect enchatability config setting.
if (slimefunItem != null && !slimefunItem.isEnchantable()) {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.enchantment-rune.fail", true);
return;
}
/*
* Removing the enchantments that the item already has from enchantmentSet.
* This also removes any conflicting enchantments
*/
removeIllegalEnchantments(itemStack, potentialEnchantments); removeIllegalEnchantments(itemStack, potentialEnchantments);
if (potentialEnchantments.isEmpty()) { if (potentialEnchantments.isEmpty()) {
@ -144,7 +157,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
} }
} }
private int getRandomlevel(Enchantment enchantment) { private int getRandomlevel(@Nonnull Enchantment enchantment) {
int level = 1; int level = 1;
if (enchantment.getMaxLevel() != 1) { if (enchantment.getMaxLevel() != 1) {
@ -154,7 +167,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
return level; return level;
} }
private void removeIllegalEnchantments(ItemStack target, List<Enchantment> potentialEnchantments) { private void removeIllegalEnchantments(@Nonnull ItemStack target, @Nonnull List<Enchantment> potentialEnchantments) {
for (Enchantment enchantment : target.getEnchantments().keySet()) { for (Enchantment enchantment : target.getEnchantments().keySet()) {
Iterator<Enchantment> iterator = potentialEnchantments.iterator(); Iterator<Enchantment> iterator = potentialEnchantments.iterator();
@ -169,7 +182,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
} }
} }
private boolean findCompatibleItem(Entity n) { private boolean findCompatibleItem(@Nonnull Entity n) {
if (n instanceof Item) { if (n instanceof Item) {
Item item = (Item) n; Item item = (Item) n;

View File

@ -3,6 +3,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes;
import java.util.Collection; import java.util.Collection;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nonnull;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -19,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
@ -47,7 +48,7 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
return (e, p, item) -> { return (e, p, item) -> {
if (isItem(item.getItemStack())) { if (isItem(item.getItemStack())) {
if (!Slimefun.hasUnlocked(p, this, true)) { if (!canUse(p, true)) {
return true; return true;
} }
@ -59,7 +60,7 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
}; };
} }
private void activate(Player p, Item rune) { private void activate(@Nonnull Player p, @Nonnull Item rune) {
// Being sure the entity is still valid and not picked up or whatsoever. // Being sure the entity is still valid and not picked up or whatsoever.
if (!rune.isValid()) { if (!rune.isValid()) {
return; return;

View File

@ -1,5 +1,18 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans; package io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -7,20 +20,6 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
* The {@link MagicianTalisman} is a special kind of {@link Talisman} which awards a {@link Player} * The {@link MagicianTalisman} is a special kind of {@link Talisman} which awards a {@link Player}
* with an extra {@link Enchantment} when they enchant their {@link ItemStack}. * with an extra {@link Enchantment} when they enchant their {@link ItemStack}.
@ -30,12 +29,16 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/ */
public class MagicianTalisman extends Talisman { public class MagicianTalisman extends Talisman {
private final ItemSetting<Boolean> allowEnchantmentBooks = new ItemSetting<>("allow-enchantment-books", false);
private final Set<TalismanEnchantment> enchantments = new HashSet<>(); private final Set<TalismanEnchantment> enchantments = new HashSet<>();
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public MagicianTalisman(SlimefunItemStack item, ItemStack[] recipe) { public MagicianTalisman(SlimefunItemStack item, ItemStack[] recipe) {
super(item, recipe, false, false, "magician", 80); super(item, recipe, false, false, "magician", 80);
addItemSetting(allowEnchantmentBooks);
for (Enchantment enchantment : Enchantment.values()) { for (Enchantment enchantment : Enchantment.values()) {
try { try {
for (int i = 1; i <= enchantment.getMaxLevel(); i++) { for (int i = 1; i <= enchantment.getMaxLevel(); i++) {
@ -70,7 +73,7 @@ public class MagicianTalisman extends Talisman {
// @formatter:off // @formatter:off
List<TalismanEnchantment> enabled = enchantments.stream() List<TalismanEnchantment> enabled = enchantments.stream()
.filter(e -> e.getEnchantment().canEnchantItem(item)) .filter(e -> (isEnchantmentBookAllowed() && item.getType() == Material.BOOK) || e.getEnchantment().canEnchantItem(item))
.filter(e -> hasConflicts(existingEnchantments, e)) .filter(e -> hasConflicts(existingEnchantments, e))
.filter(TalismanEnchantment::getValue) .filter(TalismanEnchantment::getValue)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -90,4 +93,13 @@ public class MagicianTalisman extends Talisman {
return true; return true;
} }
/**
* This method checks whether enchantment books
* can be given an extra {@link Enchantment} or not.
*
* @return Whether enchantment books can receive an extra {@link Enchantment}
*/
public boolean isEnchantmentBookAllowed() {
return allowEnchantmentBooks.getValue();
}
} }

View File

@ -9,6 +9,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -33,7 +34,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class Talisman extends SlimefunItem { public class Talisman extends SlimefunItem {
@ -113,10 +113,6 @@ public class Talisman extends SlimefunItem {
return effects; return effects;
} }
protected String getMessageSuffix() {
return suffix;
}
protected boolean isEventCancelled() { protected boolean isEventCancelled() {
return cancel; return cancel;
} }
@ -147,36 +143,44 @@ public class Talisman extends SlimefunItem {
} }
} }
private static boolean hasMessage(@Nonnull Talisman talisman) { @ParametersAreNonnullByDefault
return talisman.getMessageSuffix() != null; public static boolean trigger(Event e, SlimefunItemStack stack) {
return trigger(e, stack.getItem(), true);
} }
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public static boolean checkFor(Event e, SlimefunItemStack stack) { public static boolean trigger(Event e, SlimefunItemStack stack, boolean sendMessage) {
return checkFor(e, stack.getItem()); return trigger(e, stack.getItem(), sendMessage);
} }
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public static boolean checkFor(Event e, SlimefunItem item) { public static boolean trigger(Event e, SlimefunItem item) {
return trigger(e, item, true);
}
@ParametersAreNonnullByDefault
public static boolean trigger(Event e, SlimefunItem item, boolean sendMessage) {
if (!(item instanceof Talisman)) { if (!(item instanceof Talisman)) {
return false; return false;
} }
Talisman talisman = (Talisman) item; Talisman talisman = (Talisman) item;
if (ThreadLocalRandom.current().nextInt(100) > talisman.getChance()) { if (ThreadLocalRandom.current().nextInt(100) > talisman.getChance()) {
return false; return false;
} }
Player p = getPlayerByEventType(e); Player p = getPlayerByEventType(e);
if (p == null || !pass(p, talisman)) {
if (p == null || !talisman.canEffectsBeApplied(p)) {
return false; return false;
} }
ItemStack talismanItem = talisman.getItem(); ItemStack talismanItem = talisman.getItem();
if (SlimefunUtils.containsSimilarItem(p.getInventory(), talismanItem, true)) { if (SlimefunUtils.containsSimilarItem(p.getInventory(), talismanItem, true)) {
if (Slimefun.hasUnlocked(p, talisman, true)) { if (talisman.canUse(p, true)) {
activateTalisman(e, p, p.getInventory(), talisman, talismanItem); activateTalisman(e, p, p.getInventory(), talisman, talismanItem, sendMessage);
return true; return true;
} else { } else {
return false; return false;
@ -185,8 +189,8 @@ public class Talisman extends SlimefunItem {
ItemStack enderTalisman = talisman.getEnderVariant(); ItemStack enderTalisman = talisman.getEnderVariant();
if (SlimefunUtils.containsSimilarItem(p.getEnderChest(), enderTalisman, true)) { if (SlimefunUtils.containsSimilarItem(p.getEnderChest(), enderTalisman, true)) {
if (Slimefun.hasUnlocked(p, talisman, true)) { if (talisman.canUse(p, true)) {
activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman); activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman, sendMessage);
return true; return true;
} else { } else {
return false; return false;
@ -198,11 +202,30 @@ public class Talisman extends SlimefunItem {
} }
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismanItem) { private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismanItem, boolean sendMessage) {
consumeItem(inv, talisman, talismanItem); consumeItem(inv, talisman, talismanItem);
applyTalismanEffects(p, talisman); applyTalismanEffects(p, talisman);
cancelEvent(e, talisman); cancelEvent(e, talisman);
sendMessage(p, talisman);
if (sendMessage) {
talisman.sendMessage(p);
}
}
@ParametersAreNonnullByDefault
private static void consumeItem(Inventory inv, Talisman talisman, ItemStack talismanItem) {
if (talisman.isConsumable()) {
ItemStack[] contents = inv.getContents();
for (int i = 0; i < contents.length; i++) {
ItemStack item = contents[i];
if (SlimefunUtils.isItemSimilar(item, talismanItem, true, false)) {
ItemUtils.consumeItem(item, false);
return;
}
}
}
} }
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
@ -219,29 +242,63 @@ public class Talisman extends SlimefunItem {
} }
} }
@ParametersAreNonnullByDefault /**
private static void sendMessage(Player p, Talisman talisman) { * This returns whether the {@link Talisman} is silent.
if (hasMessage(talisman)) { * A silent {@link Talisman} will not send a message to a {@link Player}
SlimefunPlugin.getLocalization().sendMessage(p, "messages.talisman." + talisman.getMessageSuffix(), true); * when activated.
} *
* @return Whether this {@link Talisman} is silent
*/
public boolean isSilent() {
return getMessageSuffix() == null;
} }
@ParametersAreNonnullByDefault @Nullable
private static void consumeItem(Inventory inv, Talisman talisman, ItemStack talismanItem) { protected final String getMessageSuffix() {
if (talisman.isConsumable()) { return suffix;
ItemStack[] contents = inv.getContents(); }
for (int i = 0; i < contents.length; i++) {
ItemStack item = contents[i];
if (SlimefunUtils.isItemSimilar(item, talismanItem, true, false)) { /**
ItemUtils.consumeItem(item, false); * This method sends the given {@link Player} the message of this {@link Talisman}.
return; * Dependent on the selected config setting, the message will be sent via the actionbar
* or in the chat window.
*
* @param p
* The {@link Player} who shall receive the message
*/
public void sendMessage(@Nonnull Player p) {
Validate.notNull(p, "The Player must not be null.");
// Check if this Talisman has a message
if (!isSilent()) {
try {
String messageKey = "messages.talisman." + getMessageSuffix();
if (SlimefunPlugin.getRegistry().useActionbarForTalismans()) {
// Use the actionbar
SlimefunPlugin.getLocalization().sendActionbarMessage(p, messageKey, false);
} else {
// Send the message via chat
SlimefunPlugin.getLocalization().sendMessage(p, messageKey, true);
} }
} catch (Exception x) {
error("An Exception was thrown while trying to send a Talisman message", x);
} }
} }
} }
private static Player getPlayerByEventType(Event e) { private boolean canEffectsBeApplied(@Nonnull Player p) {
for (PotionEffect effect : getEffects()) {
if (effect != null && p.hasPotionEffect(effect.getType())) {
return false;
}
}
return true;
}
@Nullable
private static Player getPlayerByEventType(@Nonnull Event e) {
if (e instanceof EntityDeathEvent) { if (e instanceof EntityDeathEvent) {
return ((EntityDeathEvent) e).getEntity().getKiller(); return ((EntityDeathEvent) e).getEntity().getKiller();
} else if (e instanceof BlockBreakEvent) { } else if (e instanceof BlockBreakEvent) {
@ -259,14 +316,4 @@ public class Talisman extends SlimefunItem {
return null; return null;
} }
private static boolean pass(Player p, SlimefunItem talisman) {
for (PotionEffect effect : ((Talisman) talisman).getEffects()) {
if (effect != null && p.hasPotionEffect(effect.getType())) {
return false;
}
}
return true;
}
} }

View File

@ -4,9 +4,9 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CropGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodComposter; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodComposter;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.TreeGrowthAccelerator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.TreeGrowthAccelerator;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;

View File

@ -6,8 +6,8 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AnimalGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodFabricator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodFabricator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AnimalGrowthAccelerator;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;

View File

@ -19,7 +19,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
@ -48,7 +47,7 @@ abstract class AbstractSmeltery extends MultiBlockMachine {
if (canCraft(inv, inputs, i)) { if (canCraft(inv, inputs, i)) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone(); ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
if (Slimefun.hasUnlocked(p, output, true)) { if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
Inventory outputInv = findOutputInventory(output, dispBlock, inv); Inventory outputInv = findOutputInventory(output, dispBlock, inv);
if (outputInv != null) { if (outputInv != null) {

View File

@ -21,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class ArmorForge extends AbstractCraftingTable { public class ArmorForge extends AbstractCraftingTable {
@ -44,7 +43,7 @@ public class ArmorForge extends AbstractCraftingTable {
if (isCraftable(inv, inputs.get(i))) { if (isCraftable(inv, inputs.get(i))) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone(); ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
if (Slimefun.hasUnlocked(p, output, true)) { if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
craft(p, output, inv, dispenser); craft(p, output, inv, dispenser);
} }

View File

@ -20,7 +20,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class EnhancedCraftingTable extends AbstractCraftingTable { public class EnhancedCraftingTable extends AbstractCraftingTable {
@ -43,7 +42,7 @@ public class EnhancedCraftingTable extends AbstractCraftingTable {
if (isCraftable(inv, inputs.get(i))) { if (isCraftable(inv, inputs.get(i))) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone(); ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
if (Slimefun.hasUnlocked(p, output, true)) { if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
craft(inv, dispenser, p, b, output); craft(inv, dispenser, p, b, output);
} }

View File

@ -4,6 +4,7 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Sound; import org.bukkit.Sound;
@ -27,6 +28,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class GrindStone extends MultiBlockMachine { public class GrindStone extends MultiBlockMachine {
@ParametersAreNonnullByDefault
public GrindStone(Category category, SlimefunItemStack item) { public GrindStone(Category category, SlimefunItemStack item) {
super(category, item, new ItemStack[] { null, null, null, null, new ItemStack(Material.OAK_FENCE), null, null, new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), null }, BlockFace.SELF); super(category, item, new ItemStack[] { null, null, null, null, new ItemStack(Material.OAK_FENCE), null, null, new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), null }, BlockFace.SELF);
} }
@ -71,6 +73,9 @@ public class GrindStone extends MultiBlockMachine {
recipes.add(new ItemStack(Material.PRISMARINE)); recipes.add(new ItemStack(Material.PRISMARINE));
recipes.add(new ItemStack(Material.PRISMARINE_SHARD, 4)); recipes.add(new ItemStack(Material.PRISMARINE_SHARD, 4));
recipes.add(new ItemStack(Material.NETHER_WART_BLOCK));
recipes.add(new ItemStack(Material.NETHER_WART, 9));
} }
@Override @Override

View File

@ -21,7 +21,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class MagicWorkbench extends AbstractCraftingTable { public class MagicWorkbench extends AbstractCraftingTable {
@ -50,7 +49,7 @@ public class MagicWorkbench extends AbstractCraftingTable {
if (isCraftable(inv, inputs.get(i))) { if (isCraftable(inv, inputs.get(i))) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone(); ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
if (Slimefun.hasUnlocked(p, output, true)) { if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
craft(inv, dispenser, p, b, output); craft(inv, dispenser, p, b, output);
} }

View File

@ -3,6 +3,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -17,6 +19,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class MakeshiftSmeltery extends AbstractSmeltery { public class MakeshiftSmeltery extends AbstractSmeltery {
@ParametersAreNonnullByDefault
public MakeshiftSmeltery(Category category, SlimefunItemStack item) { public MakeshiftSmeltery(Category category, SlimefunItemStack item) {
super(category, item, new ItemStack[] { null, new ItemStack(Material.OAK_FENCE), null, new ItemStack(Material.BRICKS), new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), new ItemStack(Material.BRICKS), null, new ItemStack(Material.FLINT_AND_STEEL), null }, BlockFace.DOWN); super(category, item, new ItemStack[] { null, new ItemStack(Material.OAK_FENCE), null, new ItemStack(Material.BRICKS), new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), new ItemStack(Material.BRICKS), null, new ItemStack(Material.FLINT_AND_STEEL), null }, BlockFace.DOWN);
} }

View File

@ -25,7 +25,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
@ -135,7 +134,7 @@ public class OreCrusher extends MultiBlockMachine {
ItemStack adding = RecipeType.getRecipeOutput(this, convert); ItemStack adding = RecipeType.getRecipeOutput(this, convert);
Inventory outputInv = findOutputInventory(adding, dispBlock, inv); Inventory outputInv = findOutputInventory(adding, dispBlock, inv);
if (Slimefun.hasUnlocked(p, adding, true)) { if (SlimefunUtils.canPlayerUseItem(p, adding, true)) {
if (outputInv != null) { if (outputInv != null) {
ItemStack removing = current.clone(); ItemStack removing = current.clone();
removing.setAmount(convert.getAmount()); removing.setAmount(convert.getAmount());

View File

@ -7,6 +7,8 @@ import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Material; import org.bukkit.Material;
@ -26,6 +28,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.IgnitionChamber;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
@ -36,6 +39,7 @@ public class Smeltery extends AbstractSmeltery {
private final BlockFace[] faces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST }; private final BlockFace[] faces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };
private final ItemSetting<Integer> fireBreakingChance = new IntRangeSetting("fire-breaking-chance", 0, 34, 100); private final ItemSetting<Integer> fireBreakingChance = new IntRangeSetting("fire-breaking-chance", 0, 34, 100);
@ParametersAreNonnullByDefault
public Smeltery(Category category, SlimefunItemStack item) { public Smeltery(Category category, SlimefunItemStack item) {
super(category, item, new ItemStack[] { null, new ItemStack(Material.NETHER_BRICK_FENCE), null, new ItemStack(Material.NETHER_BRICKS), new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), new ItemStack(Material.NETHER_BRICKS), null, new ItemStack(Material.FLINT_AND_STEEL), null }, BlockFace.DOWN); super(category, item, new ItemStack[] { null, new ItemStack(Material.NETHER_BRICK_FENCE), null, new ItemStack(Material.NETHER_BRICKS), new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), new ItemStack(Material.NETHER_BRICKS), null, new ItemStack(Material.FLINT_AND_STEEL), null }, BlockFace.DOWN);
@ -73,6 +77,7 @@ public class Smeltery extends AbstractSmeltery {
} }
} }
@ParametersAreNonnullByDefault
private void consumeFire(Player p, Block dispenser, Block b) { private void consumeFire(Player p, Block dispenser, Block b) {
Inventory chamber = findIgnitionChamber(dispenser); Inventory chamber = findIgnitionChamber(dispenser);
@ -103,9 +108,12 @@ public class Smeltery extends AbstractSmeltery {
} }
} }
@Nullable
private Inventory findIgnitionChamber(@Nonnull Block b) { private Inventory findIgnitionChamber(@Nonnull Block b) {
for (BlockFace face : faces) { for (BlockFace face : faces) {
if (b.getRelative(face).getType() == Material.DROPPER && BlockStorage.check(b.getRelative(face), "IGNITION_CHAMBER")) { Block block = b.getRelative(face);
if (block.getType() == Material.DROPPER && BlockStorage.check(block) instanceof IgnitionChamber) {
BlockState state = PaperLib.getBlockState(b.getRelative(face), false).getState(); BlockState state = PaperLib.getBlockState(b.getRelative(face), false).getState();
if (state instanceof Dropper) { if (state instanceof Dropper) {

View File

@ -120,21 +120,21 @@ public class IndustrialMiner extends MultiBlockMachine {
Random random = ThreadLocalRandom.current(); Random random = ThreadLocalRandom.current();
switch (ore) { switch (ore) {
case COAL_ORE: case COAL_ORE:
return new ItemStack(Material.COAL); return new ItemStack(Material.COAL);
case DIAMOND_ORE: case DIAMOND_ORE:
return new ItemStack(Material.DIAMOND); return new ItemStack(Material.DIAMOND);
case EMERALD_ORE: case EMERALD_ORE:
return new ItemStack(Material.EMERALD); return new ItemStack(Material.EMERALD);
case NETHER_QUARTZ_ORE: case NETHER_QUARTZ_ORE:
return new ItemStack(Material.QUARTZ); return new ItemStack(Material.QUARTZ);
case REDSTONE_ORE: case REDSTONE_ORE:
return new ItemStack(Material.REDSTONE, 4 + random.nextInt(2)); return new ItemStack(Material.REDSTONE, 4 + random.nextInt(2));
case LAPIS_ORE: case LAPIS_ORE:
return new ItemStack(Material.LAPIS_LAZULI, 4 + random.nextInt(4)); return new ItemStack(Material.LAPIS_LAZULI, 4 + random.nextInt(4));
default: default:
// This includes Iron and Gold ore (and Ancient Debris) // This includes Iron and Gold ore (and Ancient Debris)
return new ItemStack(ore); return new ItemStack(ore);
} }
} }

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.tools;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -15,6 +16,7 @@ import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem; import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
@ -39,7 +41,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* @see ExplosiveShovel * @see ExplosiveShovel
* *
*/ */
class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements NotPlaceable, DamageableItem { public class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements NotPlaceable, DamageableItem {
private final ItemSetting<Boolean> damageOnUse = new ItemSetting<>("damage-on-use", true); private final ItemSetting<Boolean> damageOnUse = new ItemSetting<>("damage-on-use", true);
private final ItemSetting<Boolean> callExplosionEvent = new ItemSetting<>("call-explosion-event", false); private final ItemSetting<Boolean> callExplosionEvent = new ItemSetting<>("call-explosion-event", false);
@ -51,6 +53,7 @@ class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements NotPla
addItemSetting(damageOnUse, callExplosionEvent); addItemSetting(damageOnUse, callExplosionEvent);
} }
@Nonnull
@Override @Override
public ToolUseHandler getItemHandler() { public ToolUseHandler getItemHandler() {
return (e, tool, fortune, drops) -> { return (e, tool, fortune, drops) -> {
@ -67,6 +70,8 @@ class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements NotPla
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
private void breakBlocks(Player p, ItemStack item, Block b, List<Block> blocks, List<ItemStack> drops) { private void breakBlocks(Player p, ItemStack item, Block b, List<Block> blocks, List<ItemStack> drops) {
List<Block> blocksToDestroy = new ArrayList<>();
if (callExplosionEvent.getValue().booleanValue()) { if (callExplosionEvent.getValue().booleanValue()) {
BlockExplodeEvent blockExplodeEvent = new BlockExplodeEvent(b, blocks, 0); BlockExplodeEvent blockExplodeEvent = new BlockExplodeEvent(b, blocks, 0);
Bukkit.getServer().getPluginManager().callEvent(blockExplodeEvent); Bukkit.getServer().getPluginManager().callEvent(blockExplodeEvent);
@ -74,17 +79,26 @@ class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements NotPla
if (!blockExplodeEvent.isCancelled()) { if (!blockExplodeEvent.isCancelled()) {
for (Block block : blockExplodeEvent.blockList()) { for (Block block : blockExplodeEvent.blockList()) {
if (canBreak(p, block)) { if (canBreak(p, block)) {
breakBlock(p, item, block, drops); blocksToDestroy.add(block);
} }
} }
} }
} else { } else {
for (Block block : blocks) { for (Block block : blocks) {
if (canBreak(p, block)) { if (canBreak(p, block)) {
breakBlock(p, item, block, drops); blocksToDestroy.add(block);
} }
} }
} }
ExplosiveToolBreakBlocksEvent event = new ExplosiveToolBreakBlocksEvent(p, blocksToDestroy, item, this);
Bukkit.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
for (Block block : blocksToDestroy) {
breakBlock(p, item, block, drops);
}
}
} }
private List<Block> findBlocks(Block b) { private List<Block> findBlocks(Block b) {

View File

@ -96,10 +96,6 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
for (GoldPanDrop setting : drops) { for (GoldPanDrop setting : drops) {
randomizer.add(setting.getOutput(), setting.getValue()); randomizer.add(setting.getOutput(), setting.getValue());
} }
if (randomizer.sumWeights() < 100) {
randomizer.add(new ItemStack(Material.AIR), 100 - randomizer.sumWeights());
}
} }
/** /**
@ -110,7 +106,10 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
*/ */
@Nonnull @Nonnull
public ItemStack getRandomOutput() { public ItemStack getRandomOutput() {
return randomizer.getRandom(); ItemStack item = randomizer.getRandom();
// Fixes #2804
return item != null ? item : new ItemStack(Material.AIR);
} }
@Override @Override
@ -126,12 +125,14 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
if (block.isPresent()) { if (block.isPresent()) {
Block b = block.get(); Block b = block.get();
// Check the clicked block type and for protections
if (b.getType() == getTargetMaterial() && SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), b.getLocation(), ProtectableAction.BREAK_BLOCK)) { if (b.getType() == getTargetMaterial() && SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), b.getLocation(), ProtectableAction.BREAK_BLOCK)) {
ItemStack output = getRandomOutput(); ItemStack output = getRandomOutput();
b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType()); b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType());
b.setType(Material.AIR); b.setType(Material.AIR);
// Make sure that the randomly selected item is not air
if (output.getType() != Material.AIR) { if (output.getType() != Material.AIR) {
b.getWorld().dropItemNaturally(b.getLocation(), output.clone()); b.getWorld().dropItemNaturally(b.getLocation(), output.clone());
} }
@ -148,6 +149,7 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
* *
* @return the {@link EntityInteractHandler} of this {@link SlimefunItem} * @return the {@link EntityInteractHandler} of this {@link SlimefunItem}
*/ */
@Nonnull
public EntityInteractHandler onEntityInteract() { public EntityInteractHandler onEntityInteract() {
return (e, item, offHand) -> { return (e, item, offHand) -> {
if (!(e.getRightClicked() instanceof ItemFrame)) { if (!(e.getRightClicked() instanceof ItemFrame)) {

View File

@ -56,39 +56,39 @@ public class SwordOfBeheading extends SimpleSlimefunItem<EntityKillHandler> {
Random random = ThreadLocalRandom.current(); Random random = ThreadLocalRandom.current();
switch (e.getEntityType()) { switch (e.getEntityType()) {
case ZOMBIE: case ZOMBIE:
if (random.nextInt(100) < chanceZombie.getValue()) { if (random.nextInt(100) < chanceZombie.getValue()) {
e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD)); e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD));
} }
break; break;
case SKELETON: case SKELETON:
if (random.nextInt(100) < chanceSkeleton.getValue()) { if (random.nextInt(100) < chanceSkeleton.getValue()) {
e.getDrops().add(new ItemStack(Material.SKELETON_SKULL)); e.getDrops().add(new ItemStack(Material.SKELETON_SKULL));
} }
break; break;
case CREEPER: case CREEPER:
if (random.nextInt(100) < chanceCreeper.getValue()) { if (random.nextInt(100) < chanceCreeper.getValue()) {
e.getDrops().add(new ItemStack(Material.CREEPER_HEAD)); e.getDrops().add(new ItemStack(Material.CREEPER_HEAD));
} }
break; break;
case WITHER_SKELETON: case WITHER_SKELETON:
if (random.nextInt(100) < chanceWitherSkeleton.getValue()) { if (random.nextInt(100) < chanceWitherSkeleton.getValue()) {
e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL)); e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL));
} }
break; break;
case PLAYER: case PLAYER:
if (random.nextInt(100) < chancePlayer.getValue()) { if (random.nextInt(100) < chancePlayer.getValue()) {
ItemStack skull = new ItemStack(Material.PLAYER_HEAD); ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
ItemMeta meta = skull.getItemMeta(); ItemMeta meta = skull.getItemMeta();
((SkullMeta) meta).setOwningPlayer((Player) e.getEntity()); ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity());
skull.setItemMeta(meta); skull.setItemMeta(meta);
e.getDrops().add(skull); e.getDrops().add(skull);
} }
break; break;
default: default:
break; break;
} }
}; };
} }

View File

@ -41,7 +41,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* This {@link Listener} is responsible for providing the core mechanics of the {@link AncientAltar} * This {@link Listener} is responsible for providing the core mechanics of the {@link AncientAltar}
@ -105,12 +104,13 @@ public class AncientAltarListener implements Listener {
} }
String id = slimefunBlock.get().getId(); String id = slimefunBlock.get().getId();
Player p = e.getPlayer();
if (id.equals(pedestalItem.getId())) { if (id.equals(pedestalItem.getId())) {
e.cancel(); e.cancel();
usePedestal(b, e.getPlayer()); usePedestal(b, p);
} else if (id.equals(altarItem.getId())) { } else if (id.equals(altarItem.getId())) {
if (!Slimefun.hasUnlocked(e.getPlayer(), altarItem, true) || altarsInUse.contains(b.getLocation())) { if (!altarItem.canUse(p, true) || altarsInUse.contains(b.getLocation())) {
e.cancel(); e.cancel();
return; return;
} }
@ -119,7 +119,7 @@ public class AncientAltarListener implements Listener {
altarsInUse.add(b.getLocation()); altarsInUse.add(b.getLocation());
e.cancel(); e.cancel();
useAltar(b, e.getPlayer()); useAltar(b, p);
} }
} }
@ -212,8 +212,9 @@ public class AncientAltarListener implements Listener {
} }
Optional<ItemStack> result = getRecipeOutput(catalyst, input); Optional<ItemStack> result = getRecipeOutput(catalyst, input);
if (result.isPresent()) { if (result.isPresent()) {
if (Slimefun.hasUnlocked(p, result.get(), true)) { if (SlimefunUtils.canPlayerUseItem(p, result.get(), true)) {
List<ItemStack> consumed = new ArrayList<>(); List<ItemStack> consumed = new ArrayList<>();
consumed.add(catalyst); consumed.add(catalyst);
@ -248,7 +249,7 @@ public class AncientAltarListener implements Listener {
} }
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) { public void onBlockPlace(BlockPlaceEvent e) {
if (altarItem == null || altarItem.isDisabled()) { if (altarItem == null || altarItem.isDisabled()) {
return; return;

View File

@ -31,7 +31,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler; import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack; import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* This {@link Listener} is responsible for all events centered around a {@link SlimefunBackpack}. * This {@link Listener} is responsible for all events centered around a {@link SlimefunBackpack}.
@ -122,7 +121,7 @@ public class BackpackListener implements Listener {
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public void openBackpack(Player p, ItemStack item, SlimefunBackpack backpack) { public void openBackpack(Player p, ItemStack item, SlimefunBackpack backpack) {
if (item.getAmount() == 1) { if (item.getAmount() == 1) {
if (Slimefun.hasUnlocked(p, backpack, true) && !PlayerProfile.get(p, profile -> openBackpack(p, item, profile, backpack.getSize()))) { if (backpack.canUse(p, true) && !PlayerProfile.get(p, profile -> openBackpack(p, item, profile, backpack.getSize()))) {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.opening-backpack"); SlimefunPlugin.getLocalization().sendMessage(p, "messages.opening-backpack");
} }
} else { } else {

View File

@ -11,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.BeeWingsTask; import io.github.thebusybiscuit.slimefun4.implementation.tasks.BeeWingsTask;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* This {@link Listener} is responsible for the slow falling effect given to the {@link Player} * This {@link Listener} is responsible for the slow falling effect given to the {@link Player}
@ -44,7 +43,7 @@ public class BeeWingsListener implements Listener {
Player player = (Player) e.getEntity(); Player player = (Player) e.getEntity();
ItemStack chestplate = player.getInventory().getChestplate(); ItemStack chestplate = player.getInventory().getChestplate();
if (wings.isItem(chestplate) && Slimefun.hasUnlocked(player, chestplate, true)) { if (wings.isItem(chestplate) && wings.canUse(player, true)) {
new BeeWingsTask(player).scheduleRepeating(3, 1); new BeeWingsTask(player).scheduleRepeating(3, 1);
} }
} }

View File

@ -56,14 +56,9 @@ public class BlockListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockPlaceExisting(BlockPlaceEvent e) { public void onBlockPlaceExisting(BlockPlaceEvent e) {
/*
* This prevents Players from placing a block where another block already exists.
* While this can cause ghost blocks it also prevents them from replacing grass
* or saplings etc...
*/
Block block = e.getBlock(); Block block = e.getBlock();
// Fixes #2636 // Fixes #2636 - This will solve the "ghost blocks" issue
if (e.getBlockReplacedState().getType().isAir()) { if (e.getBlockReplacedState().getType().isAir()) {
SlimefunItem sfItem = BlockStorage.check(block); SlimefunItem sfItem = BlockStorage.check(block);
@ -77,6 +72,7 @@ public class BlockListener implements Listener {
BlockStorage.clearBlockInfo(block); BlockStorage.clearBlockInfo(block);
} }
} else if (BlockStorage.hasBlockInfo(e.getBlock())) { } 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); e.setCancelled(true);
} }
} }
@ -87,7 +83,7 @@ public class BlockListener implements Listener {
SlimefunItem sfItem = SlimefunItem.getByItem(item); SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null && !(sfItem instanceof NotPlaceable) && Slimefun.isEnabled(e.getPlayer(), sfItem, true)) { if (sfItem != null && !(sfItem instanceof NotPlaceable) && Slimefun.isEnabled(e.getPlayer(), sfItem, true)) {
if (!Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) { if (!sfItem.canUse(e.getPlayer(), true)) {
e.setCancelled(true); e.setCancelled(true);
} else { } else {
if (SlimefunPlugin.getBlockDataService().isTileEntity(e.getBlock().getType())) { if (SlimefunPlugin.getBlockDataService().isTileEntity(e.getBlock().getType())) {
@ -117,18 +113,18 @@ public class BlockListener implements Listener {
return; return;
} }
checkForSensitiveBlockAbove(e.getPlayer(), e.getBlock());
ItemStack item = e.getPlayer().getInventory().getItemInMainHand(); ItemStack item = e.getPlayer().getInventory().getItemInMainHand();
checkForSensitiveBlockAbove(e, item);
int fortune = getBonusDropsWithFortune(item, e.getBlock()); int fortune = getBonusDropsWithFortune(item, e.getBlock());
List<ItemStack> drops = new ArrayList<>(); List<ItemStack> drops = new ArrayList<>();
if (!item.getType().isAir()) { if (!e.isCancelled() && !item.getType().isAir()) {
callToolHandler(e, item, fortune, drops); callToolHandler(e, item, fortune, drops);
} }
if (!e.isCancelled()) { if (!e.isCancelled()) {
callBlockHandler(e, item, fortune, drops); callBlockHandler(e, item, drops);
} }
dropItems(e, drops); dropItems(e, drops);
@ -139,7 +135,7 @@ public class BlockListener implements Listener {
SlimefunItem tool = SlimefunItem.getByItem(item); SlimefunItem tool = SlimefunItem.getByItem(item);
if (tool != null) { if (tool != null) {
if (Slimefun.hasUnlocked(e.getPlayer(), tool, true)) { if (tool.canUse(e.getPlayer(), true)) {
tool.callItemHandler(ToolUseHandler.class, handler -> handler.onToolUse(e, item, fortune, drops)); tool.callItemHandler(ToolUseHandler.class, handler -> handler.onToolUse(e, item, fortune, drops));
} else { } else {
e.setCancelled(true); e.setCancelled(true);
@ -148,7 +144,7 @@ public class BlockListener implements Listener {
} }
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
private void callBlockHandler(BlockBreakEvent e, ItemStack item, int fortune, List<ItemStack> drops) { private void callBlockHandler(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
SlimefunItem sfItem = BlockStorage.check(e.getBlock()); SlimefunItem sfItem = BlockStorage.check(e.getBlock());
if (sfItem == null && SlimefunPlugin.getBlockDataService().isTileEntity(e.getBlock().getType())) { if (sfItem == null && SlimefunPlugin.getBlockDataService().isTileEntity(e.getBlock().getType())) {
@ -172,7 +168,7 @@ public class BlockListener implements Listener {
sfItem.error("Something went wrong while triggering a BlockHandler", x); sfItem.error("Something went wrong while triggering a BlockHandler", x);
} }
} else { } else {
sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onBlockBreak(e, item, fortune, drops)); sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(e, item, drops));
} }
drops.addAll(sfItem.getDrops()); drops.addAll(sfItem.getDrops());
@ -182,13 +178,15 @@ public class BlockListener implements Listener {
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
private void dropItems(BlockBreakEvent e, List<ItemStack> drops) { private void dropItems(BlockBreakEvent e, List<ItemStack> drops) {
if (!drops.isEmpty()) { if (!drops.isEmpty() && !e.isCancelled()) {
e.getBlock().setType(Material.AIR);
// Notify plugins like CoreProtect // Notify plugins like CoreProtect
SlimefunPlugin.getProtectionManager().logAction(e.getPlayer(), e.getBlock(), ProtectableAction.BREAK_BLOCK); SlimefunPlugin.getProtectionManager().logAction(e.getPlayer(), e.getBlock(), ProtectableAction.BREAK_BLOCK);
// Fixes #2560
if (e.isDropItems()) { if (e.isDropItems()) {
// Disable normal block drops
e.setDropItems(false);
for (ItemStack drop : drops) { for (ItemStack drop : drops) {
if (drop != null && drop.getType() != Material.AIR) { if (drop != null && drop.getType() != Material.AIR) {
e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), drop); e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), drop);
@ -209,8 +207,8 @@ public class BlockListener implements Listener {
* The {@link Block} that was broken * The {@link Block} that was broken
*/ */
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
private void checkForSensitiveBlockAbove(Player p, Block b) { private void checkForSensitiveBlockAbove(BlockBreakEvent e, ItemStack item) {
Block blockAbove = b.getRelative(BlockFace.UP); Block blockAbove = e.getBlock().getRelative(BlockFace.UP);
if (SlimefunTag.SENSITIVE_MATERIALS.isTagged(blockAbove.getType())) { if (SlimefunTag.SENSITIVE_MATERIALS.isTagged(blockAbove.getType())) {
SlimefunItem sfItem = BlockStorage.check(blockAbove); SlimefunItem sfItem = BlockStorage.check(blockAbove);
@ -219,13 +217,29 @@ public class BlockListener implements Listener {
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getId()); SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getId());
if (blockHandler != null) { if (blockHandler != null) {
if (blockHandler.onBreak(p, blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) { if (blockHandler.onBreak(e.getPlayer(), blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) {
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove)); blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove));
blockAbove.setType(Material.AIR); blockAbove.setType(Material.AIR);
} }
} else { } else {
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove)); /*
* We create a dummy here to pass onto the BlockBreakHandler.
* This will set the correct block context.
*/
BlockBreakEvent dummyEvent = new BlockBreakEvent(blockAbove, e.getPlayer());
List<ItemStack> drops = new ArrayList<>();
drops.addAll(sfItem.getDrops(e.getPlayer()));
sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));
blockAbove.setType(Material.AIR); blockAbove.setType(Material.AIR);
if (!dummyEvent.isCancelled() && dummyEvent.isDropItems()) {
for (ItemStack drop : drops) {
if (drop != null && drop.getType() != Material.AIR) {
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), drop);
}
}
}
} }
} }
} }

View File

@ -84,9 +84,10 @@ public class BlockPhysicsListener implements Listener {
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onLiquidFlow(BlockFromToEvent e) { public void onLiquidFlow(BlockFromToEvent e) {
Block block = e.getToBlock(); Block block = e.getToBlock();
Material type = block.getType();
// Check if this Material can be destroyed by fluids // Check if this Material can be destroyed by fluids
if (SlimefunTag.FLUID_SENSITIVE_MATERIALS.isTagged(block.getType())) { if (SlimefunTag.FLUID_SENSITIVE_MATERIALS.isTagged(type)) {
// Check if this Block holds any data // Check if this Block holds any data
if (BlockStorage.hasBlockInfo(block)) { if (BlockStorage.hasBlockInfo(block)) {
e.setCancelled(true); e.setCancelled(true);

View File

@ -21,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler; import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.Juice; import io.github.thebusybiscuit.slimefun4.implementation.items.food.Juice;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* This {@link Listener} listens for a {@link FoodLevelChangeEvent} or an {@link EntityDamageEvent} for starvation * This {@link Listener} listens for a {@link FoodLevelChangeEvent} or an {@link EntityDamageEvent} for starvation
@ -74,7 +73,7 @@ public class CoolerListener implements Listener {
for (ItemStack item : p.getInventory().getContents()) { for (ItemStack item : p.getInventory().getContents()) {
if (cooler.isItem(item)) { if (cooler.isItem(item)) {
if (Slimefun.hasUnlocked(p, cooler, true)) { if (cooler.canUse(p, true)) {
takeJuiceFromCooler(p, item); takeJuiceFromCooler(p, item);
} else { } else {
return; return;

View File

@ -18,7 +18,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.ElytraCap; import io.github.thebusybiscuit.slimefun4.implementation.items.armor.ElytraCap;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece; import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* The {@link Listener} for the {@link ElytraCap}. * The {@link Listener} for the {@link ElytraCap}.
@ -57,7 +56,7 @@ public class ElytraImpactListener implements Listener {
if (helmet.isPresent()) { if (helmet.isPresent()) {
SlimefunItem item = helmet.get(); SlimefunItem item = helmet.get();
if (Slimefun.hasUnlocked(p, item, true) && profile.hasFullProtectionAgainst(ProtectionType.FLYING_INTO_WALL)) { if (item.canUse(p, true) && profile.hasFullProtectionAgainst(ProtectionType.FLYING_INTO_WALL)) {
e.setDamage(0); e.setDamage(0);
p.playSound(p.getLocation(), Sound.BLOCK_STONE_HIT, 20, 1); p.playSound(p.getLocation(), Sound.BLOCK_STONE_HIT, 20, 1);

Some files were not shown because too many files have changed in this diff Show More