1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00

Merge branch 'tests' into renovate/com.github.thebusybiscuit-cs-corelib2-0.x

This commit is contained in:
TheBusyBiscuit 2020-05-12 22:27:01 +02:00 committed by GitHub
commit e79bf4e29b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
115 changed files with 4833 additions and 1360 deletions

View File

@ -1,5 +1,5 @@
## Description
<!-- Please explain your changes in detail. -->
<!-- Please explain what you changed/added and why you did it in detail. -->
## Changes
<!-- Please list all the changes you have made. -->
@ -9,8 +9,10 @@
<!-- Syntax: "Resolves #000" -->
## Checklist
<!-- After posting your issue, please check the boxes below if they apply -->
<!-- Here is a little checklist you should follow. -->
<!-- You can click those check boxes after you posted your issue. -->
- [ ] I have fully tested the proposed changes and promise that they will not break everything into chaos.
- [ ] I have also tested the proposed changes in combination with various popular addons and can confirm my changes do not break them.
- [ ] I followed the existing code standards and didn't mess up the formatting.
- [ ] I did my best to add documentation to any public classes or methods I added.
- [ ] I did my best to add documentation to any public classes or methods I added.
- [ ] I added sufficient Unit Tests to cover my code.

13
.gitignore vendored
View File

@ -1,10 +1,13 @@
/bin/
/target/
/plugins/
/sonar/
/.settings/
/.idea/
dependency-reduced-pom.xml
.classpath
.project
/.settings/
*.iml
/target
/.idea/
dependency-reduced-pom.xml
javadoc.xml
.DS_Store

View File

@ -21,9 +21,13 @@
#### Additions
* Added Ukrainian translations
* Added /sf backpack to restore lost backpacks
* Added automated Unit Tests
#### Changes
* Little performance improvements
* Bandages, Rags and Splints will no longer be consumed if your health is full and you are not on fire
* Player Profiles (researches and stuff) are now loaded completely asynchronously
#### Fixes
* Fixed #1824
@ -32,6 +36,10 @@
* Fixed #1843
* Fixed #1873
* Fixed Electric Smeltery not prioritisting recipes
* Fixed #1851
* Fixed #1891
* Fixed #1893
* Fixed #1897
## Release Candidate 11 (25 Apr 2020)

View File

@ -10,7 +10,7 @@ It currently adds over **500 new items and recipes** to Minecraft ([Read more ab
But it also comes with a lot of Addons too!<br>
Check out our [Addons](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Addons), you may find exactly what you were looking for.
## Quick navigation
### Quick navigation
* **[Download Slimefun4](#download-slimefun-4)**
* **[Discord Support Server](#discord)**
* **[Bug Tracker](https://github.com/TheBusyBiscuit/Slimefun4/issues)**
@ -21,11 +21,11 @@ Check out our [Addons](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Addons),
(See also: [How to install Slimefun](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Installing-Slimefun))<br>
Slimefun 4 can be downloaded **for free** on our builds page.<br>
We currently provide two versions of Slimefun, development builds and "stable" builds.<br>
Here is a full summary of the differences between these two versions of Slimefun.
Here is a full summary of the differences between different versions of Slimefun.
| | development (latest) | "stable" |
| ------------------ | -------- | -------- |
| **Minecraft version(s)** | 1.13.X - 1.15.X | 1.13.X - 1.15.X |
| **Minecraft version(s)** | :video_game: 1.13.X - 1.15.X | :video_game: 1.13.X - 1.15.X |
| **testing before release** | :x: | :heavy_check_mark: |
| **latest content** | :heavy_check_mark: | :x: |
| **Discord support** | :heavy_check_mark: | :x: |
@ -36,9 +36,9 @@ Here is a full summary of the differences between these two versions of Slimefun
**! We wholeheartedly recommend you to use development builds !**
"Stable" builds do ___not___ receive frequent updates or fast patches. Therefore they will always contain many more bugs than the develoment builds. We will also ___not___ accept or review any bug reports from "stable" builds since they are basically just outdated development builds.<br>
**Why use a "stable" build then?** While "stable" builds contain more bugs than development builds you can be sure that they will not include any game-breaking issues, development builds almost never contain such issues either. But if your server/business heavily depends on a version of Slimefun that you need to rely on, you are forgiven if you choose the "stable" branch.<br>
**What exactly are these "stable" builds then and why do you put them in quotes?** "Stable" builds are literally just outdated development builds that seemed to run fine without any major issues. But they are not exactly bug-free hence why calling them stable would be hipocritical. However these builds can only really stay "stable" if enough people use the development builds to test them and report bugs. Otherwise potential issues may go unnoticed and slip into "stable" builds. Again, we really recommend you to choose the development builds. But since many people really wanted "stable" builds, they are now an option too.
"Stable" builds do not receive frequent updates or fast patches. Therefore they will always contain a lot more bugs than the develoment builds. We will also not accept or review any bug reports from "stable" builds. These are just old development builds that seemed to run without any major issues.<br>
**Why use a "stable" build then?** While "stable" builds contain more bugs than development builds you can be sure that they will not include game-breaking issues, development builds almost never contain such issues either. But if your server/business heavily depends on a version of Slimefun that you need to rely on, you are forgiven if you choose the "stable" branch.<br>
**What exactly are these "stable" builds then and why do you put them in quotes?** "Stable" builds are literally just outdated development builds that seemed to run fine without any major issues. But they are not exactly bug-free hence why actually calling them stable would be hypocritical. However these builds can only really stay "stable" if there are enough people using development builds to report bugs. Otherwise potential issues may go unnoticed and slip into "stable" builds. Again, we really recommend you to choose the development builds. But since many people really wanted "stable" builds, they are now an option too.
Whatever version of Slimefun you choose, we also recommend you to keep `auto-updates` enabled to receive automatic patches and fixes for Slimefun!
@ -69,7 +69,7 @@ Slimefun has a (detailed and well-maintained - *cough*) Wiki for new players, ma
expanding the wiki to help grow our community and help out new users of this plugin.
https://github.com/TheBusyBiscuit/Slimefun4/wiki
### Highlighted Articles
##### Highlighted Articles
* [What is Slimefun?](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Slimefun-in-a-nutshell)
* [How to install Slimefun](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Installing-Slimefun)
* [Addons for Slimefun 4](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Addons)
@ -88,33 +88,47 @@ Slimefun 4 is an Open-Source project and licensed under
Over 100 people have already contributed to this amazing project. You guys are awesome.<br>
Please consider helping us maintain this project too, your engagement keeps the project alive <3.
<p align="center">
<a href="https://github.com/TheBusyBiscuit/Slimefun4/graphs/contributors">
<img alt="GitHub contributors" src="https://img.shields.io/github/contributors/TheBusyBiscuit/Slimefun4?style=for-the-badge">
</a>
</p>
### Pull requests
This is an open-source community project, so **your contributions keep this plugin alive!**<br>
Pull Requests can be fixes, changes or even additions, but please keep in mind that if you add too much content to Slimefun 4, you should maybe consider making an Addon for it instead ([Developer Guide](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Developer-Guide)).
### Translations
Slimefun4 has recently added suport for translations, note that translations are still _work in progress_.<br>
So not everything may be available for translation yet.<br>
[Read more...](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Translating-Slimefun)
### Pull requests
This is an open-source community project, so **your contributions keep this plugin alive!**<br>
Pull Requests can be fixes, changes or even additions, but please keep in mind that if you add too much content to Slimefun 4, you should maybe consider making an Addon for it instead ([Developer Guide](https://github.com/TheBusyBiscuit/Slimefun4/wiki/Developer-Guide)).
### Code Quality
Slimefun uses [Sonarcloud.io](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) to monitor Code Quality.
| [Overall Maintainability](https://sonarcloud.io/documentation/user-guide/metric-definitions/#maintainability) | "Code Smells" | "Technical Debt" | Test Coverage |
| ---- | ---- | ---- | ---- |
| [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) | [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=code_smells)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) | [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=sqale_index)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=TheBusyBiscuit_Slimefun4&metric=coverage)](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) |
##### "Code Smells"
Code Smells are portions of the source code that are confusing, lack documentation or are just done very badly in general. These code smells should be held to a bare minimum.
_Please contact us on [Discord](#discord) before working on any code smells. Some design patterns may not be changed abruptly because an addon might depend on them._
##### "Technical Debt"
Technical Debt is basically an estimate for how long it would take to fix all issues and code smells.
##### Test Coverage
Slimefun now also uses Automated Tests to determine whether an update could break something. The coverage shows how much these tests cover. Higher coverage means less breaking changes and in turn better and more reliable builds.
Due to this being a very huge project though, getting to `100% coverage` is probably impossible. But increasing that number even slightly still helps. So feel free to write Unit Tests for Slimefun and place them in the [/src/test/java/](https://github.com/TheBusyBiscuit/Slimefun4/tree/master/src/test/java) folder.
## Disclaimers
Slimefun4 uses various systems that collect usage information or download automatic updates as well as the latest information about the project.<br>
We do __not__ collect any personal information from you but here is a full list of what services may collect or download other kinds of data.
Slimefun4 uses various systems that collect usage information or download automatic updates as well as the latest information about the project.
We do not collect any personal information from you but there are some services that may gather or download some data.
You can opt-out of the Auto-Updater and stats collection at any time.
### Auto-Updates
#### Auto-Updates
Slimefun4 uses an Auto-Updater which connects to https://thebusybiscuit.github.io/builds/ to check for and download updates.<br>
This behaviour is enabled by default but can be turned off under `/plugins/Slimefun/config.yml`<br>
This behaviour is enabled by default but can be turned off under `/plugins/Slimefun/config.yml`.<br>
We highly recommend you to keep this on at any time though, as you could be missing out on important patches.
### Metrics and Statistics
#### Metrics and Statistics
Slimefun4 uses [bStats](https://bstats.org/plugin/bukkit/Slimefun/4574) to collect anonymous information about the usage of this plugin.<br>
This is solely for statistical purposes, as we are interested in how Servers/Players use this plugin.<br>
All available data is anonymous and aggregated, at no point can we see individual server or player information.<br>
@ -123,12 +137,12 @@ All of the collected data is publicly accessible: https://bstats.org/plugin/bukk
You can also disable this behaviour under `/plugins/bStats/config.yml`.<br>
For more info see [bStats' Privacy Policy](https://bstats.org/privacy-policy)
### GitHub Integration
#### GitHub Integration
Lastly, Slimefun4 connects to https://api.github.com/ to gather information about this open-source project.<br>
No information about your Minecraft Server is sent to GitHub.
This information includes (but is not limited to)
* list of contributors, their username and profile link (from the repositories `TheBusyBiscuit/Slimefun4`, `TheBusyBiscuit/Slimefun4-Wiki` and `TheBusyBiscuit/Slimefun4-Resourcepack`)
* list of contributors, their username and profile link (from the repositories `TheBusyBiscuit/Slimefun4`, `Slimefun/Slimefun-Wiki` and `Slimefun/Resourcepack`)
* amount of open issues in this repository
* amount of pending pull requests in this repository
* amount of stars in this repository

268
pom.xml
View File

@ -1,29 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.mrCookieSlime</groupId>
<groupId>io.github.thebusybiscuit</groupId>
<artifactId>Slimefun</artifactId>
<!-- Our default version will be UNOFFICIAL, this will prevent the auto updater -->
<!-- Our default version will be UNOFFICIAL, this will prevent auto updates -->
<!-- from overriding our local test file -->
<version>4.3-UNOFFICIAL</version>
<inceptionYear>2013</inceptionYear>
<packaging>jar</packaging>
<description>Slimefun is a Bukkit / Spigot plugin that simulates a modpack-like atmosphere by adding over 500 new items and recipes to your Minecraft Server.</description>
<url>https://github.com/TheBusyBiscuit/Slimefun4</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- Bukkit properties -->
<!-- Bukkit properties -->
<bukkit.version>1.15.2</bukkit.version>
<bukkit.javadocs>https://hub.spigotmc.org/javadocs/bukkit/</bukkit.javadocs>
<!-- Default settings for sonarcloud.io -->
<sonar.projectKey>TheBusyBiscuit_Slimefun4</sonar.projectKey>
<sonar.organization>thebusybiscuit-github</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.projectKey>TheBusyBiscuit_Slimefun4</sonar.projectKey>
<sonar.organization>thebusybiscuit-github</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.log.level>DEBUG</sonar.log.level>
<sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
</properties>
<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/TheBusyBiscuit/Slimefun4/issues</url>
</issueManagement>
<licenses>
<license>
<name>GNU General Public License v3.0</name>
<url>https://github.com/TheBusyBiscuit/Slimefun4/blob/master/LICENSE</url>
<distribution>repo</distribution>
</license>
</licenses>
<repositories>
<repository>
<id>paper-repo</id>
@ -50,25 +72,29 @@
<url>http://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<build>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<finalName>${project.name} v${project.version}</finalName>
<plugins>
<!-- Compiler plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<excludes>
<!-- package info files are only important to the Javadocs -->
<!-- We can exclude them from the final jar -->
<!-- package info files are only important for Javadocs -->
<!-- We can safely exclude them from the final jar -->
<exclude>**/package-info.java</exclude>
</excludes>
</configuration>
</plugin>
<!-- Attach sources -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
@ -82,15 +108,54 @@
</execution>
</executions>
</plugin>
<!-- Plugin for Unit Tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
</plugin>
<!-- Sonarcloud Scanner -->
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.7.0.1746</version>
</plugin>
<!-- Code Coverage Reports -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<id>prepare</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Dependency shading -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<!-- Shade bStats and CS-CoreLib2 into the output jar -->
<!-- Shade bStats and CS-CoreLib2 into the output jar -->
<relocations>
<relocation>
<pattern>org.bstats</pattern>
@ -101,18 +166,18 @@
<shadedPattern>me.mrCookieSlime.Slimefun.cscorelib2</shadedPattern>
</relocation>
</relocations>
<!-- Exclude unneeded metadata files from shaded dependencies -->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
@ -122,83 +187,84 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<reportOutputDirectory>${project.basedir}</reportOutputDirectory>
<destDir>docs</destDir>
<doctitle>Slimefun4 - Javadocs</doctitle>
<windowtitle>Slimefun4 - Javadocs</windowtitle>
<detectOfflineLinks>false</detectOfflineLinks>
<additionalJOption>-html5</additionalJOption>
<!-- We can reference Bukkit's API in our Javadocs -->
<links>
<link>${bukkit.javadocs}</link>
</links>
<!-- We can group pakages together in our Javadocs -->
<groups>
<group>
<title>Slimefun4 - API</title>
<packages>io.github.thebusybiscuit.slimefun4.api*</packages>
</group>
<group>
<title>Slimefun4 - Core packages</title>
<packages>io.github.thebusybiscuit.slimefun4.core*</packages>
</group>
<group>
<title>Slimefun4 - Implementations</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation*</packages>
</group>
<group>
<title>Slimefun4 - Common utility packages</title>
<packages>io.github.thebusybiscuit.slimefun4.utils*</packages>
</group>
<group>
<title>Slimefun4 - Item Implementations</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation.items*</packages>
</group>
<group>
<title>Slimefun4 - Old packages</title>
<packages>me.mrCookieSlime.Slimefun*</packages>
</group>
</groups>
</configuration>
</plugin>
<!-- Javadocs Settings -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<reportOutputDirectory>${project.basedir}</reportOutputDirectory>
<destDir>docs</destDir>
<doctitle>Slimefun4 - Javadocs</doctitle>
<windowtitle>Slimefun4 - Javadocs</windowtitle>
<detectOfflineLinks>false</detectOfflineLinks>
<additionalJOption>-html5</additionalJOption>
<!-- We can reference Bukkit's API in our Javadocs -->
<links>
<link>${bukkit.javadocs}</link>
</links>
<!-- We can group pakages together in our Javadocs -->
<groups>
<group>
<title>Slimefun4 - API</title>
<packages>io.github.thebusybiscuit.slimefun4.api*</packages>
</group>
<group>
<title>Slimefun4 - Core packages</title>
<packages>io.github.thebusybiscuit.slimefun4.core*</packages>
</group>
<group>
<title>Slimefun4 - Implementations</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation*</packages>
</group>
<group>
<title>Slimefun4 - Common utility packages</title>
<packages>io.github.thebusybiscuit.slimefun4.utils*</packages>
</group>
<group>
<title>Slimefun4 - Item Implementations</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation.items*</packages>
</group>
<group>
<title>Slimefun4 - Old packages</title>
<packages>me.mrCookieSlime.Slimefun*</packages>
</group>
</groups>
</configuration>
</plugin>
</plugins>
<resources>
<!-- Resources we want to include, such as configs or language files -->
<!-- Resources we want to include, e.g. configs or language files -->
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*</include>
<include>languages/*</include>
</includes>
</resource>
<!-- We also want to include our LICENSE file -->
<!-- We also want to include our LICENSE file -->
<resource>
<directory>${basedir}</directory>
<includes>
<include>LICENSE</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
<!-- Hard dependencies -->
<!-- Hard dependencies -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
@ -211,7 +277,27 @@
<version>8081bb4fe4</version>
<scope>provided</scope>
</dependency>
<!-- Development / Testing dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit</artifactId>
<version>v1.15-d69d9ca9cb-1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
<!-- Shaded packages -->
<dependency>
<groupId>com.github.thebusybiscuit</groupId>
@ -225,7 +311,7 @@
<version>1.7</version>
<scope>compile</scope>
</dependency>
<!-- Third party plugin integrations -->
<dependency>
<groupId>com.sk89q.worldedit</groupId>
@ -245,7 +331,7 @@
<version>3cd370b5d8</version>
<scope>provided</scope>
</dependency>
<!-- System dependency, this project has no maven repository -->
<dependency>
<groupId>me.minebuilders</groupId>

View File

@ -11,7 +11,7 @@ import me.mrCookieSlime.Slimefun.SlimefunPlugin;
*
*/
public enum MinecraftVersion {
/**
* This constant represents Minecraft (Java Edition) Version 1.14
* (The Update Aquatic)
@ -34,7 +34,13 @@ public enum MinecraftVersion {
* This constant represents an exceptional state in which we were unable
* to identify the Minecraft Version we are using
*/
UNKNOWN("Unknown");
UNKNOWN("Unknown"),
/**
* This is a very special state that represents the environment being a Unit
* Test and not an actual running Minecraft Server.
*/
UNIT_TEST("Unit Test Environment");
private final String name;
private final String prefix;

View File

@ -18,9 +18,9 @@ public class MultiBlockInteractEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private Player player;
private MultiBlock multiBlock;
private Block clickedBlock;
private final Player player;
private final MultiBlock multiBlock;
private final Block clickedBlock;
private boolean cancelled;
public HandlerList getHandlers() {

View File

@ -5,7 +5,7 @@ import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import me.mrCookieSlime.Slimefun.Objects.Research;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
/**
* This {@link Event} is called whenever a {@link Player} unlocks a {@link Research}.

View File

@ -5,7 +5,7 @@ import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
/**
* A {@link PrematureCodeException} is thrown when a {@link SlimefunAddon} tried
* to access Slimefun code before Slimefun was enabled.
* Always let your code inside onEnable() or later, never on class initialization.
* Always let your code run inside onEnable() or later, never on class initialization.
*
* @author TheBusyBiscuit
*

View File

@ -40,7 +40,7 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
public class ResourceManager {
private final int[] backgroundSlots = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 17, 18, 26, 27, 35, 36, 44, 45, 46, 48, 49, 50, 52, 53 };
private final ItemStack chunkTexture = SkullItem.fromBase64("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=");
private final ItemStack chunkTexture = SkullItem.fromHash("8449b9318e33158e64a46ab0de121c3d40000e3332c1574932b3c849d8fa0dc2");
private final Config config;
public ResourceManager(SlimefunPlugin plugin) {
@ -48,7 +48,8 @@ public class ResourceManager {
}
void register(GEOResource resource) {
boolean enabled = config.getOrSetDefault(resource.getKey().toString().replace(':', '.') + ".enabled", true);
String key = resource.getKey().getNamespace() + '.' + resource.getKey().getKey();
boolean enabled = config.getOrSetDefault(key + ".enabled", true);
if (enabled) {
SlimefunPlugin.getRegistry().getGEOResources().add(resource);
@ -81,11 +82,11 @@ public class ResourceManager {
if (value > 0) {
int bound = resource.getMaxDeviation();
if (bound <= 0) {
throw new IllegalStateException("GEO Resource \"" + resource.getKey() + "\" was misconfigured! getMaxDeviation() must return a value higher than zero!");
}
value += ThreadLocalRandom.current().nextInt(bound);
}

View File

@ -10,8 +10,8 @@ import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.Particle.DustOptions;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
@ -62,33 +62,53 @@ public abstract class Network {
protected Location regulator;
private Queue<Location> nodeQueue = new ArrayDeque<>();
protected Set<Location> connectedLocations = new HashSet<>();
protected Set<Location> regulatorNodes = new HashSet<>();
protected Set<Location> connectorNodes = new HashSet<>();
protected Set<Location> terminusNodes = new HashSet<>();
private final NetworkManager manager;
protected final Set<Location> connectedLocations = new HashSet<>();
protected final Set<Location> regulatorNodes = new HashSet<>();
protected final Set<Location> connectorNodes = new HashSet<>();
protected final Set<Location> terminusNodes = new HashSet<>();
protected Network(Location regulator) {
protected Network(NetworkManager manager, Location regulator) {
this.manager = manager;
this.regulator = regulator;
connectedLocations.add(regulator);
nodeQueue.add(regulator.clone());
}
/**
* This returns the size of this {@link Network}. It is equivalent to the amount
* of {@link Location Locations} connected to this {@link Network}.
*
* @return The size of this {@link Network}
*/
public int getSize() {
return regulatorNodes.size() + connectorNodes.size() + terminusNodes.size();
}
protected void addLocationToNetwork(Location l) {
if (connectedLocations.contains(l)) {
return;
}
connectedLocations.add(l.clone());
handleLocationUpdate(l);
markDirty(l);
}
public void handleLocationUpdate(Location l) {
/**
* This method marks the given {@link Location} as dirty and adds it to a {@link Queue}
* to handle this update.
*
* @param l
* The {@link Location} to update
*/
public void markDirty(Location l) {
if (regulator.equals(l)) {
SlimefunPlugin.getNetworkManager().unregisterNetwork(this);
return;
manager.unregisterNetwork(this);
}
else {
nodeQueue.add(l.clone());
}
nodeQueue.add(l.clone());
}
/**
@ -117,7 +137,7 @@ public abstract class Network {
}
private void discoverStep() {
int maxSteps = SlimefunPlugin.getNetworkManager().getMaxSize();
int maxSteps = manager.getMaxSize();
int steps = 0;
while (nodeQueue.peek() != null) {
@ -128,7 +148,7 @@ public abstract class Network {
if (classification != currentAssignment) {
if (currentAssignment == NetworkComponent.REGULATOR || currentAssignment == NetworkComponent.CONNECTOR) {
// Requires a complete rebuild of the network, so we just throw the current one away.
SlimefunPlugin.getNetworkManager().unregisterNetwork(this);
manager.unregisterNetwork(this);
return;
}
else if (currentAssignment == NetworkComponent.TERMINUS) {

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.api.network;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
/**
* This enum holds the different types of components a {@link Network} can have.
* It is used for classification of nodes inside the {@link Network}.

View File

@ -8,8 +8,9 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This class represents the instance of a {@link SlimefunBackpack} that is ready to
@ -59,25 +60,53 @@ public class PlayerBackpack {
* The size of this Backpack
*/
public PlayerBackpack(PlayerProfile profile, int id, int size) {
if (size < 9 || size > 54 || size % 9 != 0) {
throw new IllegalArgumentException("Invalid size! Size must be one of: [9, 18, 27, 36, 45, 54]");
}
this.profile = profile;
this.id = id;
this.cfg = profile.getConfig();
this.size = size;
cfg.setValue("backpacks." + id + ".size", size);
profile.markDirty();
markDirty();
inventory = Bukkit.createInventory(null, size, "Backpack [" + size + " Slots]");
}
public int getID() {
/**
* This returns the id of this {@link PlayerBackpack}
*
* @return The id of this {@link PlayerBackpack}
*/
public int getId() {
return id;
}
/**
* This method returns the {@link PlayerProfile} this {@link PlayerBackpack} belongs to
*
* @return The owning {@link PlayerProfile}
*/
public PlayerProfile getOwner() {
return profile;
}
/**
* This returns the size of this {@link PlayerBackpack}.
*
* @return The size of this {@link PlayerBackpack}
*/
public int getSize() {
return size;
}
/**
* This method returns the {@link Inventory} of this {@link PlayerBackpack}
*
* @return The {@link Inventory} of this {@link PlayerBackpack}
*/
public Inventory getInventory() {
return inventory;
}
@ -90,9 +119,11 @@ public class PlayerBackpack {
* The players who this Backpack will be shown to
*/
public void open(Player... players) {
for (Player p : players) {
p.openInventory(inventory);
}
Slimefun.runSync(() -> {
for (Player p : players) {
p.openInventory(inventory);
}
});
}
/**
@ -102,6 +133,10 @@ public class PlayerBackpack {
* The new size for this Backpack
*/
public void setSize(int size) {
if (size < 9 || size > 54 || size % 9 != 0) {
throw new IllegalArgumentException("Invalid size! Size must be one of: [9, 18, 27, 36, 45, 54]");
}
this.size = size;
cfg.setValue("backpacks." + id + ".size", size);

View File

@ -13,6 +13,7 @@ import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
@ -24,10 +25,10 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.items.HashedArmorpiece;
import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Research;
/**
* A class that can store a Player's {@link Research} progress for caching purposes.
@ -67,10 +68,6 @@ public final class PlayerProfile {
}
}
private PlayerProfile(UUID uuid) {
this(Bukkit.getOfflinePlayer(uuid));
}
public HashedArmorpiece[] getArmor() {
return armor;
}
@ -79,6 +76,11 @@ public final class PlayerProfile {
return cfg;
}
/**
* This returns the {@link UUID} this {@link PlayerProfile} is linked to.
*
* @return The {@link UUID} of our {@link PlayerProfile}
*/
public UUID getUUID() {
return uuid;
}
@ -124,6 +126,7 @@ public final class PlayerProfile {
* Whether the {@link Research} should be unlocked or locked
*/
public void setResearched(Research research, boolean unlock) {
Validate.notNull(research, "Research must not be null!");
dirty = true;
if (unlock) {
@ -144,6 +147,11 @@ public final class PlayerProfile {
* @return Whether this {@link Research} has been unlocked
*/
public boolean hasUnlocked(Research research) {
if (research == null) {
// No Research, no restriction
return true;
}
return !research.isEnabled() || researches.contains(research);
}
@ -181,15 +189,23 @@ public final class PlayerProfile {
return backpack;
}
public PlayerBackpack getBackpack(int id) {
public Optional<PlayerBackpack> getBackpack(int id) {
if (id < 0) {
throw new IllegalArgumentException("Backpacks cannot have negative ids!");
}
PlayerBackpack backpack = backpacks.get(id);
if (backpack != null) return backpack;
else {
if (backpack != null) {
return Optional.of(backpack);
}
else if (cfg.contains("backpacks." + id + ".size")) {
backpack = new PlayerBackpack(this, id);
backpacks.put(id, backpack);
return backpack;
return Optional.of(backpack);
}
return Optional.empty();
}
public String getTitle() {
@ -216,6 +232,12 @@ public final class PlayerProfile {
sender.sendMessage(ChatColors.color("&7Total XP Levels spent: " + ChatColor.AQUA + levels));
}
/**
* This returns the {@link Player} who this {@link PlayerProfile} belongs to.
* If the {@link Player} is offline, null will be returned.
*
* @return The {@link Player} of this {@link PlayerProfile} or null
*/
public Player getPlayer() {
return Bukkit.getPlayer(getUUID());
}
@ -230,62 +252,8 @@ public final class PlayerProfile {
return guideHistory;
}
/**
* This is now deprecated, use {@link #fromUUID(UUID, Consumer)} instead
*
* @param uuid
* The UUID of the profile you are trying to retrieve.
* @return The PlayerProfile of this player
*/
public static PlayerProfile fromUUID(UUID uuid) {
PlayerProfile profile = SlimefunPlugin.getRegistry().getPlayerProfiles().get(uuid);
if (profile == null) {
profile = new PlayerProfile(uuid);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(uuid, profile);
}
else {
profile.markedForDeletion = false;
}
return profile;
}
public static boolean fromUUID(UUID uuid, Consumer<PlayerProfile> callback) {
PlayerProfile profile = SlimefunPlugin.getRegistry().getPlayerProfiles().get(uuid);
if (profile != null) {
callback.accept(profile);
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
PlayerProfile pp = new PlayerProfile(uuid);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(uuid, pp);
callback.accept(pp);
});
return false;
}
/**
* This is now deprecated, use {@link #get(OfflinePlayer, Consumer)} instead
*
* @param p
* The player's profile you wish to retrieve
* @return The PlayerProfile of this player
*/
public static PlayerProfile get(OfflinePlayer p) {
PlayerProfile profile = SlimefunPlugin.getRegistry().getPlayerProfiles().get(p.getUniqueId());
if (profile == null) {
profile = new PlayerProfile(p);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(p.getUniqueId(), profile);
}
else {
profile.markedForDeletion = false;
}
return profile;
return get(Bukkit.getOfflinePlayer(uuid), callback);
}
/**
@ -299,22 +267,56 @@ public final class PlayerProfile {
* @return If the player was cached or not.
*/
public static boolean get(OfflinePlayer p, Consumer<PlayerProfile> callback) {
PlayerProfile cached = SlimefunPlugin.getRegistry().getPlayerProfiles().get(p.getUniqueId());
UUID uuid = p.getUniqueId();
PlayerProfile profile = SlimefunPlugin.getRegistry().getPlayerProfiles().get(uuid);
if (cached != null) {
callback.accept(cached);
if (profile != null) {
callback.accept(profile);
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
PlayerProfile profile = new PlayerProfile(p);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(p.getUniqueId(), profile);
callback.accept(profile);
PlayerProfile pp = new PlayerProfile(p);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(uuid, pp);
callback.accept(pp);
});
return false;
}
/**
* This requests an instance of {@link PlayerProfile} to be loaded for the given {@link OfflinePlayer}.
* This method will return true if the {@link PlayerProfile} was already found.
*
* @param p
* The {@link OfflinePlayer} to request the {@link PlayerProfile} for.
*
* @return Whether the {@link PlayerProfile} was already loaded
*/
public static boolean request(OfflinePlayer p) {
if (!SlimefunPlugin.getRegistry().getPlayerProfiles().containsKey(p.getUniqueId())) {
// Should probably prevent multiple requests for the same profile in the future
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
PlayerProfile pp = new PlayerProfile(p);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(p.getUniqueId(), pp);
});
return false;
}
return true;
}
/**
* This method tries to search for a {@link PlayerProfile} of the given {@link OfflinePlayer}.
* The result of this method is an {@link Optional}, if no {@link PlayerProfile} was found, an empty
* {@link Optional} will be returned.
*
* @param p
* The {@link OfflinePlayer} to get the {@link PlayerProfile} for
*
* @return An {@link Optional} describing the result
*/
public static Optional<PlayerProfile> find(OfflinePlayer p) {
return Optional.ofNullable(SlimefunPlugin.getRegistry().getPlayerProfiles().get(p.getUniqueId()));
}
@ -323,8 +325,10 @@ public final class PlayerProfile {
return SlimefunPlugin.getRegistry().getPlayerProfiles().values().iterator();
}
public static PlayerBackpack getBackpack(ItemStack item) {
if (item == null || !item.hasItemMeta() || !item.getItemMeta().hasLore()) return null;
public static void getBackpack(ItemStack item, Consumer<PlayerBackpack> callback) {
if (item == null || !item.hasItemMeta() || !item.getItemMeta().hasLore()) {
return;
}
OptionalInt id = OptionalInt.empty();
String uuid = "";
@ -341,14 +345,27 @@ public final class PlayerProfile {
}
if (id.isPresent()) {
PlayerProfile profile = fromUUID(UUID.fromString(uuid));
return profile.getBackpack(id.getAsInt());
}
else {
return null;
int number = id.getAsInt();
fromUUID(UUID.fromString(uuid), profile -> {
Optional<PlayerBackpack> backpack = profile.getBackpack(number);
if (backpack.isPresent()) {
callback.accept(backpack.get());
}
});
}
}
@Override
public int hashCode() {
return uuid.hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof PlayerProfile && uuid.equals(((PlayerProfile) obj).uuid);
}
@Override
public String toString() {
return "PlayerProfile {" + uuid + "}";

View File

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.World;
@ -35,12 +36,14 @@ public class MultiBlock {
private static final Set<Tag<Material>> SUPPORTED_TAGS = new HashSet<>();
static {
SUPPORTED_TAGS.add(Tag.LOGS);
SUPPORTED_TAGS.add(Tag.WOODEN_TRAPDOORS);
SUPPORTED_TAGS.add(Tag.WOODEN_SLABS);
if (SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) {
SUPPORTED_TAGS.add(Tag.LOGS);
SUPPORTED_TAGS.add(Tag.WOODEN_TRAPDOORS);
SUPPORTED_TAGS.add(Tag.WOODEN_SLABS);
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
SUPPORTED_TAGS.add(Tag.WOODEN_FENCES);
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
SUPPORTED_TAGS.add(Tag.WOODEN_FENCES);
}
}
}
@ -54,12 +57,17 @@ public class MultiBlock {
private final boolean isSymmetric;
public MultiBlock(SlimefunItem item, Material[] build, BlockFace trigger) {
this.item = item;
Validate.notNull(item, "A MultiBlock reuquires a SlimefunItem!");
if (build == null || build.length != 9) {
throw new IllegalArgumentException("MultiBlocks must have a length of 9!");
}
if (trigger != BlockFace.SELF && trigger != BlockFace.UP && trigger != BlockFace.DOWN) {
throw new IllegalArgumentException("Multiblock Blockface must be either UP, DOWN or SELF");
}
this.item = item;
this.blocks = build;
this.trigger = trigger;
this.isSymmetric = isSymmetric(build);
@ -89,7 +97,7 @@ public class MultiBlock {
MultiBlock mb = (MultiBlock) obj;
if (trigger == mb.getTriggerBlock()) {
if (trigger == mb.getTriggerBlock() && isSymmetric == mb.isSymmetric) {
for (int i = 0; i < mb.getStructure().length; i++) {
if (!compareBlocks(blocks[i], mb.getStructure()[i])) {
return false;

View File

@ -24,11 +24,11 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
@ -56,7 +56,6 @@ public class SlimefunRegistry {
private final List<Research> researches = new LinkedList<>();
private final List<String> researchRanks = new ArrayList<>();
private final Set<UUID> researchingPlayers = new HashSet<>();
private final KeyMap<Research> researchIds = new KeyMap<>();
private boolean automaticallyLoadItems;
private boolean enableResearches;
@ -131,18 +130,10 @@ public class SlimefunRegistry {
return enabledItems;
}
public int countVanillaItems() {
return (int) getEnabledSlimefunItems().stream().filter(item -> !item.isAddonItem()).count();
}
public List<Research> getResearches() {
return researches;
}
public KeyMap<Research> getResearchIds() {
return researchIds;
}
public Set<UUID> getCurrentlyResearchingPlayers() {
return researchingPlayers;
}
@ -159,6 +150,10 @@ public class SlimefunRegistry {
return enableResearches;
}
public void setFreeCreativeResearchingEnabled(boolean enabled) {
freeCreativeResearches = enabled;
}
public boolean isFreeCreativeResearchingEnabled() {
return freeCreativeResearches;
}

View File

@ -77,4 +77,14 @@ public abstract class FlexCategory extends Category {
throw new UnsupportedOperationException("A FlexCategory has no items!");
}
@Override
public final boolean contains(SlimefunItem item) {
throw new UnsupportedOperationException("A FlexCategory has no items!");
}
@Override
public final void remove(SlimefunItem item) {
throw new UnsupportedOperationException("A FlexCategory has no items, so there is nothing remove!");
}
}

View File

@ -0,0 +1,161 @@
package io.github.thebusybiscuit.slimefun4.core.categories;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
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.player.PlayerProfile;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
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
* are fully unlocked.
* <p>
* See {@link Category} for the complete documentation.
*
* @author TheBusyBiscuit
*
* @see Category
* @see SeasonalCategory
*
*/
public class LockedCategory extends Category {
private final NamespacedKey[] keys;
private final Set<Category> parents = new HashSet<>();
/**
* The basic constructor for a LockedCategory.
* Like {@link Category}, the default tier is automatically set to 3.
*
* @param key
* A unique identifier for this category
* @param item
* The display item for this category
* @param parents
* The parent categories for this category
*
*/
public LockedCategory(NamespacedKey key, ItemStack item, NamespacedKey... parents) {
this(key, item, 3, parents);
}
/**
* The constructor for a LockedCategory.
*
* @param key
* A unique identifier for this category
* @param item
* The display item for this category
* @param tier
* The tier of this category
* @param parents
* The parent categories for this category
*
*/
public LockedCategory(NamespacedKey key, ItemStack item, int tier, NamespacedKey... parents) {
super(key, item, tier);
Validate.noNullElements(parents, "A LockedCategory must not have any 'null' parents!");
this.keys = parents;
}
@Override
public void register() {
super.register();
List<NamespacedKey> namespacedKeys = new ArrayList<>();
for (NamespacedKey key : keys) {
if (key != null) {
namespacedKeys.add(key);
}
}
for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
if (namespacedKeys.remove(category.getKey())) {
addParent(category);
}
}
for (NamespacedKey key : namespacedKeys) {
Slimefun.getLogger().log(Level.INFO, "Parent \"{0}\" for Category \"{1}\" was not found, probably just disabled.", new Object[] { key, getKey() });
}
}
/**
* Gets the list of parent categories for this {@link LockedCategory}.
*
* @return the list of parent categories
*
* @see #addParent(Category)
* @see #removeParent(Category)
*/
public Set<Category> getParents() {
return parents;
}
/**
* Adds a parent {@link Category} to this {@link LockedCategory}.
*
* @param category
* The {@link Category} to add as a parent
*
* @see #getParents()
* @see #removeParent(Category)
*/
public void addParent(Category category) {
if (category == this || category == null) {
throw new IllegalArgumentException("Category '" + item.getItemMeta().getDisplayName() + "' cannot be a parent of itself or have a 'null' parent.");
}
parents.add(category);
}
/**
* Removes a {@link Category} from the parents of this {@link LockedCategory}.
*
* @param category
* The {@link Category} to remove from the parents of this {@link LockedCategory}
*
* @see #getParents()
* @see #addParent(Category)
*/
public void removeParent(Category category) {
parents.remove(category);
}
/**
* Checks if the {@link Player} has fully unlocked all parent categories.
*
* @param p
* The {@link Player} to check
* @param profile
* The {@link PlayerProfile} that belongs to the given {@link Player}
* @return Whether the {@link Player} has fully completed all parent categories, otherwise false
*/
public boolean hasUnlocked(Player p, PlayerProfile profile) {
for (Category category : parents) {
for (SlimefunItem item : category.getItems()) {
// Should probably be replaced with Slimefun.hasUnlocked(...)
// 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 true;
}
}

View File

@ -8,7 +8,6 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
/**
* Represents a {@link Category} that is only displayed in the Guide during

View File

@ -5,13 +5,12 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.bukkit.NamespacedKey;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -35,14 +34,14 @@ class SlimefunTabCompleter implements TabCompleter {
return createReturnList(getSlimefunItems(), args[2]);
}
else if (args[0].equalsIgnoreCase("research")) {
Set<NamespacedKey> researches = SlimefunPlugin.getRegistry().getResearchIds().keySet();
List<Research> researches = SlimefunPlugin.getRegistry().getResearches();
List<String> suggestions = new LinkedList<>();
suggestions.add("all");
suggestions.add("reset");
for (NamespacedKey key : researches) {
suggestions.add(key.toString().toLowerCase(Locale.ROOT));
for (Research research : researches) {
suggestions.add(research.getKey().toString().toLowerCase(Locale.ROOT));
}
return createReturnList(suggestions, args[2]);

View File

@ -0,0 +1,80 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.api.Slimefun;
class BackpackCommand extends SubCommand {
BackpackCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd);
}
@Override
public String getName() {
return "backpack";
}
@Override
protected String getDescription() {
return "commands.backpack.description";
}
@Override
public boolean isHidden() {
return false;
}
@Override
public void onExecute(CommandSender sender, String[] args) {
if (!(sender instanceof Player) || !sender.hasPermission("slimefun.command.backpack")) {
SlimefunPlugin.getLocal().sendMessage(sender, "messages.no-permission", true);
return;
}
if (args.length != 3) {
SlimefunPlugin.getLocal().sendMessage(sender, "messages.usage", true, msg -> msg.replace("%usage%", "/sf backpack <Player> <ID>"));
return;
}
Player p = (Player) sender;
if (!PatternUtils.NUMERIC.matcher(args[2]).matches()) {
SlimefunPlugin.getLocal().sendMessage(sender, "commands.backpack.invalid-id");
return;
}
int id = Integer.parseInt(args[2]);
@SuppressWarnings("deprecation")
OfflinePlayer owner = Bukkit.getOfflinePlayer(args[1]);
if (!owner.hasPlayedBefore()) {
SlimefunPlugin.getLocal().sendMessage(sender, "commands.backpack.player-never-joined");
return;
}
PlayerProfile.get(owner, profile -> {
if (!profile.getBackpack(id).isPresent()) {
SlimefunPlugin.getLocal().sendMessage(sender, "commands.backpack.backpack-does-not-exist");
return;
}
Slimefun.runSync(() -> {
ItemStack item = SlimefunItems.RESTORED_BACKPACK.clone();
SlimefunPlugin.getBackpackListener().setBackpackId(p, item, 2, id);
p.getInventory().addItem(item);
SlimefunPlugin.getLocal().sendMessage(sender, "commands.backpack.restored-backpack-given");
});
});
}
}

View File

@ -8,7 +8,8 @@ import me.mrCookieSlime.Slimefun.SlimefunPlugin;
public final class Commands {
private Commands() {}
private Commands() {
}
public static void addCommands(SlimefunCommand cmd, Collection<SubCommand> commands) {
SlimefunPlugin plugin = cmd.getPlugin();
@ -25,5 +26,6 @@ public final class Commands {
commands.add(new OpenGuideCommand(plugin, cmd));
commands.add(new SearchCommand(plugin, cmd));
commands.add(new DebugFishCommand(plugin, cmd));
commands.add(new BackpackCommand(plugin, cmd));
}
}

View File

@ -9,8 +9,8 @@ import io.github.thebusybiscuit.cscorelib2.players.PlayerList;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Research;
class ResearchCommand extends SubCommand {

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.core.guide;
import java.util.Deque;
import java.util.LinkedList;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -32,6 +33,7 @@ public class GuideHistory {
* The {@link PlayerProfile} this {@link GuideHistory} was made for
*/
public GuideHistory(PlayerProfile profile) {
Validate.notNull(profile, "Cannot create a GuideHistory without a PlayerProfile!");
this.profile = profile;
}
@ -77,6 +79,7 @@ public class GuideHistory {
* The {@link SlimefunItem} that should be added to this {@link GuideHistory}
*/
public void add(SlimefunItem item) {
Validate.notNull(item, "Cannot add a nonexisting SlimefunItem to the GuideHistory!");
queue.add(new GuideEntry<>(item, 0));
}
@ -87,13 +90,17 @@ public class GuideHistory {
* The term that the {@link Player} searched for
*/
public void add(String searchTerm) {
Validate.notNull(searchTerm, "Cannot add an empty Search Term to the GuideHistory!");
queue.add(new GuideEntry<>(searchTerm, 0));
}
private <T> void refresh(T object, int page) {
Validate.notNull(object, "Cannot add a null Entry to the GuideHistory!");
Validate.isTrue(page >= 0, "page must not be negative!");
GuideEntry<?> lastEntry = getLastEntry(false);
if (lastEntry != null && lastEntry.getIndexedObject() == object) {
if (lastEntry != null && lastEntry.getIndexedObject().equals(object)) {
lastEntry.setPage(page);
}
else {

View File

@ -87,7 +87,7 @@ public final class SlimefunGuide {
if (!SlimefunPlugin.getWorldSettingsService().isWorldEnabled(p.getWorld())) {
return;
}
Optional<PlayerProfile> optional = PlayerProfile.find(p);
if (optional.isPresent()) {

View File

@ -5,11 +5,11 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;

View File

@ -100,7 +100,7 @@ public final class SlimefunGuideSettings {
});
if (SlimefunPlugin.getUpdater().getBranch().isOfficial()) {
menu.addItem(49, new CustomItem(Material.REDSTONE_TORCH, "&4" + SlimefunPlugin.getLocal().getMessage(p, "guide.title.bugs"), "", "&7&oBug reports have to be made in English!", "", "&7Open Issues: &a" + SlimefunPlugin.getGitHubService().getIssues(), "&7Pending Pull Requests: &a" + SlimefunPlugin.getGitHubService().getPullRequests(), "", "&7\u21E8 &eClick to go to the Slimefun4 Bug Tracker"), (pl, slot, item, action) -> {
menu.addItem(49, new CustomItem(Material.REDSTONE_TORCH, "&4" + SlimefunPlugin.getLocal().getMessage(p, "guide.title.bugs"), "", "&7&oBug reports have to be made in English!", "", "&7Open Issues: &a" + SlimefunPlugin.getGitHubService().getOpenissues(), "&7Pending Pull Requests: &a" + SlimefunPlugin.getGitHubService().getPendingPullRequests(), "", "&7\u21E8 &eClick to go to the Slimefun4 Bug Tracker"), (pl, slot, item, action) -> {
pl.closeInventory();
ChatUtils.sendURL(pl, "https://github.com/TheBusyBiscuit/Slimefun4/issues");
return false;

View File

@ -1,13 +1,16 @@
package io.github.thebusybiscuit.slimefun4.api.network;
package io.github.thebusybiscuit.slimefun4.core.networks;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Server;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
/**
@ -20,7 +23,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListen
* @see NetworkListener
*
*/
public final class NetworkManager {
public class NetworkManager {
private final int maxNodes;
private final List<Network> networks = new LinkedList<>();
@ -28,11 +31,12 @@ public final class NetworkManager {
/**
* This creates a new {@link NetworkManager} with the given capacity.
*
* @param capacity
* @param maxStepSize
* The maximum amount of nodes a {@link Network} can have
*/
public NetworkManager(int capacity) {
maxNodes = capacity;
public NetworkManager(int maxStepSize) {
Validate.isTrue(maxStepSize > 0, "The maximal Network size must be above zero!");
maxNodes = maxStepSize;
}
/**
@ -54,14 +58,14 @@ public final class NetworkManager {
return networks;
}
public <T extends Network> T getNetworkFromLocation(Location l, Class<T> type) {
public <T extends Network> Optional<T> getNetworkFromLocation(Location l, Class<T> type) {
for (Network network : networks) {
if (type.isInstance(network) && network.connectsTo(l)) {
return type.cast(network);
return Optional.of(type.cast(network));
}
}
return null;
return Optional.empty();
}
public <T extends Network> List<T> getNetworksFromLocation(Location l, Class<T> type) {
@ -86,7 +90,7 @@ public final class NetworkManager {
public void handleAllNetworkLocationUpdate(Location l) {
for (Network n : getNetworksFromLocation(l, Network.class)) {
n.handleLocationUpdate(l);
n.markDirty(l);
}
}

View File

@ -36,18 +36,20 @@ public class CargoNet extends ChestTerminalNetwork {
private int tickDelayThreshold = 0;
public static CargoNet getNetworkFromLocation(Location l) {
return SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, CargoNet.class);
return SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, CargoNet.class).orElse(null);
}
public static CargoNet getNetworkFromLocationOrCreate(Location l) {
CargoNet cargoNetwork = getNetworkFromLocation(l);
Optional<CargoNet> cargoNetwork = SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, CargoNet.class);
if (cargoNetwork == null) {
cargoNetwork = new CargoNet(l);
SlimefunPlugin.getNetworkManager().registerNetwork(cargoNetwork);
if (cargoNetwork.isPresent()) {
return cargoNetwork.get();
}
else {
CargoNet network = new CargoNet(l);
SlimefunPlugin.getNetworkManager().registerNetwork(network);
return network;
}
return cargoNetwork;
}
protected CargoNet(Location l) {
@ -210,57 +212,10 @@ public class CargoNet extends ChestTerminalNetwork {
// (Apart from ChestTerminal Buses)
for (Map.Entry<Location, Integer> entry : inputs.entrySet()) {
Location input = entry.getKey();
Optional<Block> attachedBlock = getAttachedBlock(input.getBlock());
if (!attachedBlock.isPresent()) {
continue;
}
Block inputTarget = attachedBlock.get();
Config cfg = BlockStorage.getLocationInfo(input);
boolean roundrobin = "true".equals(cfg.getString("round-robin"));
ItemStackAndInteger slot = CargoUtils.withdraw(input.getBlock(), inputTarget, Integer.parseInt(cfg.getString("index")));
if (slot == null) {
continue;
}
ItemStack stack = slot.getItem();
int previousSlot = slot.getInt();
List<Location> outputs = output.get(entry.getValue());
if (outputs != null) {
List<Location> outputList = new LinkedList<>(outputs);
if (roundrobin) {
roundRobinSort(input, outputList);
}
for (Location out : outputList) {
Optional<Block> target = getAttachedBlock(out.getBlock());
if (target.isPresent()) {
stack = CargoUtils.insert(out.getBlock(), target.get(), stack, -1);
if (stack == null) {
break;
}
}
}
}
DirtyChestMenu menu = CargoUtils.getChestMenu(inputTarget);
if (menu != null) {
menu.replaceExistingItem(previousSlot, stack);
}
else if (CargoUtils.hasInventory(inputTarget)) {
BlockState state = inputTarget.getState();
if (state instanceof InventoryHolder) {
Inventory inv = ((InventoryHolder) state).getInventory();
inv.setItem(previousSlot, stack);
}
if (attachedBlock.isPresent()) {
routeItems(input, attachedBlock.get(), entry.getValue(), output);
}
}
@ -270,10 +225,59 @@ public class CargoNet extends ChestTerminalNetwork {
}
}
private void routeItems(Location inputNode, Block inputTarget, int frequency, Map<Integer, List<Location>> outputNodes) {
Config cfg = BlockStorage.getLocationInfo(inputNode);
boolean roundrobin = "true".equals(cfg.getString("round-robin"));
ItemStackAndInteger slot = CargoUtils.withdraw(inputNode.getBlock(), inputTarget, Integer.parseInt(cfg.getString("index")));
if (slot == null) {
return;
}
ItemStack stack = slot.getItem();
int previousSlot = slot.getInt();
List<Location> outputs = outputNodes.get(frequency);
if (outputs != null) {
List<Location> outputList = new LinkedList<>(outputs);
if (roundrobin) {
roundRobinSort(inputNode, outputList);
}
for (Location output : outputList) {
Optional<Block> target = getAttachedBlock(output.getBlock());
if (target.isPresent()) {
stack = CargoUtils.insert(output.getBlock(), target.get(), stack, -1);
if (stack == null) {
break;
}
}
}
}
DirtyChestMenu menu = CargoUtils.getChestMenu(inputTarget);
if (menu != null) {
menu.replaceExistingItem(previousSlot, stack);
}
else if (CargoUtils.hasInventory(inputTarget)) {
BlockState state = inputTarget.getState();
if (state instanceof InventoryHolder) {
Inventory inv = ((InventoryHolder) state).getInventory();
inv.setItem(previousSlot, stack);
}
}
}
private void roundRobinSort(Location input, List<Location> outputs) {
int index = roundRobin.getOrDefault(input, 0);
if (index < outputs.size()) {
// Not ideal but actually not bad performance-wise over more elegant alternatives
for (int i = 0; i < index; i++) {
Location temp = outputs.remove(0);
outputs.add(temp);

View File

@ -27,6 +27,7 @@ import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
@ -54,7 +55,7 @@ abstract class ChestTerminalNetwork extends Network {
private final Set<ItemRequest> itemRequests = new HashSet<>();
protected ChestTerminalNetwork(Location regulator) {
super(regulator);
super(SlimefunPlugin.getNetworkManager(), regulator);
}
protected static Optional<Block> getAttachedBlock(Block block) {

View File

@ -1,6 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.networks.energy;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.bukkit.Location;
@ -59,19 +60,17 @@ public class EnergyNet extends Network {
return EnergyNetComponentType.NONE;
}
public static EnergyNet getNetworkFromLocation(Location l) {
return SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, EnergyNet.class);
}
public static EnergyNet getNetworkFromLocationOrCreate(Location l) {
EnergyNet energyNetwork = getNetworkFromLocation(l);
Optional<EnergyNet> cargoNetwork = SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, EnergyNet.class);
if (energyNetwork == null) {
energyNetwork = new EnergyNet(l);
SlimefunPlugin.getNetworkManager().registerNetwork(energyNetwork);
if (cargoNetwork.isPresent()) {
return cargoNetwork.get();
}
else {
EnergyNet network = new EnergyNet(l);
SlimefunPlugin.getNetworkManager().registerNetwork(network);
return network;
}
return energyNetwork;
}
private final Set<Location> generators = new HashSet<>();
@ -79,7 +78,7 @@ public class EnergyNet extends Network {
private final Set<Location> consumers = new HashSet<>();
protected EnergyNet(Location l) {
super(l);
super(SlimefunPlugin.getNetworkManager(), l);
}
@Override

View File

@ -0,0 +1,6 @@
/**
* This package provides the core functionality for the {@link io.github.thebusybiscuit.slimefun4.api.network.Network}
* class, such as the {@link io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager} and also the subpackages
* for actual implementations of the {@link io.github.thebusybiscuit.slimefun4.api.network.Network} class.
*/
package io.github.thebusybiscuit.slimefun4.core.networks;

View File

@ -0,0 +1,335 @@
package io.github.thebusybiscuit.slimefun4.core.researching;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.ResearchUnlockEvent;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup;
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* Represents a research, which is bound to one
* {@link SlimefunItem} or more and requires XP levels to unlock said item(s).
*
* @author TheBusyBiscuit
*
* @see ResearchSetup
* @see ResearchUnlockEvent
*
*/
public class Research implements Keyed {
private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 };
private static final String PLACEHOLDER_RESEARCH = "%research%";
private final NamespacedKey key;
private final int id;
private String name;
private boolean enabled = true;
private int cost;
private final List<SlimefunItem> items = new LinkedList<>();
/**
* The constructor for a {@link Research}.
*
* Create a new research, then bind this research to the Slimefun items you want by calling
* {@link #addItems(SlimefunItem...)}. Once you're finished, call {@link #register()}
* to register it.
*
* To speed up, directly setup the research by calling
* {@link Slimefun#registerResearch(Research, org.bukkit.inventory.ItemStack...)}.
*
* @param key
* A unique identifier for this {@link Research}
* @param id
* old way of identifying researches
* @param name
* The displayed name of this {@link Research}
* @param defaultCost
* The Cost in XP levels to unlock this {@link Research}
*
*/
public Research(NamespacedKey key, int id, String name, int defaultCost) {
this.key = key;
this.id = id;
this.name = name;
this.cost = defaultCost;
}
@Override
public NamespacedKey getKey() {
return key;
}
/**
* This method returns whether this {@link Research} is enabled.
* {@code false} can mean that this particular {@link Research} was disabled or that
* researches alltogether have been disabled.
*
* @return Whether this {@link Research} is enabled or not
*/
public boolean isEnabled() {
return SlimefunPlugin.getRegistry().isResearchingEnabled() && enabled;
}
/**
* Gets the ID of this {@link Research}.
* This is the old way of identifying Researches, use a {@link NamespacedKey} in the future.
*
* @deprecated Numeric Ids for Researches are deprecated, use {@link #getKey()} for identification instead.
*
* @return The ID of this {@link Research}
*/
@Deprecated
public int getID() {
return id;
}
/**
* This method gives you a localized name for this {@link Research}.
* The name is automatically taken from the currently selected {@link Language} of
* the specified {@link Player}.
*
* @param p
* The {@link Player} to translate this name for.
* @return The localized Name of this {@link Research}.
*/
public String getName(Player p) {
String localized = SlimefunPlugin.getLocal().getResearchName(p, key);
return localized != null ? localized : name;
}
/**
* Gets the cost in XP levels to unlock this {@link Research}.
*
* @return The cost in XP levels for this {@link Research}
*/
public int getCost() {
return cost;
}
/**
* Sets the cost in XP levels to unlock this {@link Research}.
*
* @param cost
* The cost in XP levels
*/
public void setCost(int cost) {
if (cost < 0) {
throw new IllegalArgumentException("Research cost must be zero or greater!");
}
this.cost = cost;
}
/**
* Bind the specified {@link SlimefunItem SlimefunItems} to this {@link Research}.
*
* @param items
* Instances of {@link SlimefunItem} to bind to this {@link Research}
*/
public void addItems(SlimefunItem... items) {
for (SlimefunItem item : items) {
if (item != null) {
item.setResearch(this);
}
}
}
/**
* Bind the specified ItemStacks to this {@link Research}.
*
* @param items
* Instances of {@link ItemStack} to bind to this {@link Research}
*
* @return The current instance of {@link Research}
*/
public Research addItems(ItemStack... items) {
for (ItemStack item : items) {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null) {
sfItem.setResearch(this);
}
}
return this;
}
/**
* Lists every {@link SlimefunItem} that is bound to this {@link Research}.
*
* @return The Slimefun items bound to this {@link Research}.
*/
public List<SlimefunItem> getAffectedItems() {
return items;
}
/**
* Checks if the {@link Player} can unlock this {@link Research}.
*
* @param p
* The {@link Player} to check
* @return Whether that {@link Player} can unlock this {@link Research}
*/
public boolean canUnlock(Player p) {
if (!isEnabled()) {
return true;
}
boolean creativeResearch = p.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled();
return creativeResearch || p.getLevel() >= cost;
}
/**
* Unlocks this {@link Research} for the specified {@link Player}.
*
* @param p
* The {@link Player} for which to unlock this {@link Research}
* @param instant
* Whether to unlock the research instantly
*/
public void unlock(Player p, boolean instant) {
if (!instant) {
Slimefun.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", "0%"));
}, 10L);
}
PlayerProfile.get(p, profile -> {
if (!profile.hasUnlocked(this)) {
Slimefun.runSync(() -> {
ResearchUnlockEvent event = new ResearchUnlockEvent(p, this);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (instant) {
finishResearch(p, profile);
}
else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)));
playResearchAnimation(p);
Slimefun.runSync(() -> {
finishResearch(p, profile);
SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId());
}, (RESEARCH_PROGRESS.length + 1) * 20L);
}
}
});
}
});
}
private void finishResearch(Player p, PlayerProfile profile) {
profile.setResearched(this, true);
SlimefunPlugin.getLocal().sendMessage(p, "messages.unlocked", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)));
if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) {
FireworkUtils.launchRandom(p, 1);
}
}
private void playResearchAnimation(Player p) {
for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) {
int j = i;
Slimefun.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%"));
}, i * 20L);
}
}
/**
* Registers this {@link Research}.
*/
public void register() {
SlimefunPlugin.getResearchCfg().setDefaultValue("enable-researching", true);
String path = key.getNamespace() + '.' + key.getKey();
if (SlimefunPlugin.getResearchCfg().contains(path + ".enabled") && !SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled")) {
for (SlimefunItem item : new ArrayList<>(items)) {
if (item != null) {
item.setResearch(null);
}
}
enabled = false;
return;
}
SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".cost", getCost());
SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".enabled", true);
setCost(SlimefunPlugin.getResearchCfg().getInt(path + ".cost"));
enabled = true;
SlimefunPlugin.getRegistry().getResearches().add(this);
}
/**
* Attempts to get a {@link Research} with the given ID.
*
* @deprecated Numeric Research Ids are fading out, please use {@link #getResearch(NamespacedKey)} instead.
*
* @param id
* ID of the research to get
* @return {@link Research} if found, or null
*/
@Deprecated
public static Research getByID(int id) {
for (Research research : SlimefunPlugin.getRegistry().getResearches()) {
if (research.getID() == id) {
return research;
}
}
return null;
}
/**
* Attempts to get a {@link Research} with the given {@link NamespacedKey}.
*
* @param key
* the {@link NamespacedKey} of the {@link Research} you are looking for
*
* @return An {@link Optional} with or without the found {@link Research}
*/
public static Optional<Research> getResearch(NamespacedKey key) {
if (key == null) {
return Optional.empty();
}
for (Research research : SlimefunPlugin.getRegistry().getResearches()) {
if (research.getKey().equals(key)) {
return Optional.of(research);
}
}
return Optional.empty();
}
@Override
public String toString() {
return "Research (" + getKey() + ')';
}
}

View File

@ -0,0 +1,5 @@
/**
* This package holds everything connected to the {@link io.github.thebusybiscuit.slimefun4.core.researching.Research}
* class.
*/
package io.github.thebusybiscuit.slimefun4.core.researching;

View File

@ -84,7 +84,7 @@ public class BlockDataService implements PersistentDataService, Keyed {
* @return Whether the given {@link Material} is considered a Tile Entity
*/
public boolean isTileEntity(Material type) {
if (!SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
if (type == null || !SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
// We can only store data on Tile Entities in 1.14+
// So we will just return false here in that case.
return false;

View File

@ -1,8 +1,10 @@
package io.github.thebusybiscuit.slimefun4.core.services;
import java.util.Collection;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
@ -21,16 +23,28 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class CustomTextureService {
private final Config config;
private String version = null;
private boolean modified = false;
public CustomTextureService(Plugin plugin) {
config = new Config(plugin, "item-models.yml");
public CustomTextureService(Config config) {
this.config = config;
config.getConfiguration().options().header("This file is used to assign items from Slimefun or any of its addons\n" + "the 'CustomModelData' NBT tag. This can be used in conjunction with a custom resource pack\n" + "to give items custom textures.\n0 means there is no data assigned to that item.\n\n" + "There is no official Slimefun resource pack at the moment.");
config.getConfiguration().options().copyHeader(true);
}
public void register(Iterable<SlimefunItem> items) {
/**
* This method registers the given {@link SlimefunItem SlimefunItems} to this {@link CustomTextureService}.
* If saving is enabled, it will save them to the {@link Config} file.
*
* @param items
* The {@link SlimefunItem SlimefunItems} to register
* @param save
* Whether to save this file
*/
public void register(Collection<SlimefunItem> items, boolean save) {
Validate.notEmpty(items, "items must neither be null or empty.");
config.setDefaultValue("SLIMEFUN_GUIDE", 0);
config.setDefaultValue("_UI_BACKGROUND", 0);
@ -53,11 +67,15 @@ public class CustomTextureService {
}
}
config.save();
version = config.getString("version");
if (save) {
config.save();
}
}
public String getVersion() {
return config.getString("version");
return version;
}
public boolean isActive() {
@ -65,6 +83,7 @@ public class CustomTextureService {
}
public int getModelData(String id) {
Validate.notNull(id, "Cannot get the ModelData for 'null'");
return config.getInt(id);
}

View File

@ -48,28 +48,34 @@ public class LocalizationService extends SlimefunLocalization implements Persist
this.plugin = plugin;
this.prefix = prefix;
translationsEnabled = SlimefunPlugin.getCfg().getBoolean("options.enable-translations");
languageKey = new NamespacedKey(plugin, LANGUAGE_PATH);
defaultLanguage = new Language(serverDefaultLanguage, "11b3188fd44902f72602bd7c2141f5a70673a411adb3d81862c69e536166b");
defaultLanguage.setMessages(getConfig().getConfiguration());
if (serverDefaultLanguage != null) {
translationsEnabled = SlimefunPlugin.getCfg().getBoolean("options.enable-translations");
defaultLanguage = new Language(serverDefaultLanguage, "11b3188fd44902f72602bd7c2141f5a70673a411adb3d81862c69e536166b");
defaultLanguage.setMessages(getConfig().getConfiguration());
loadEmbeddedLanguages();
loadEmbeddedLanguages();
String language = getConfig().getString(LANGUAGE_PATH);
if (language == null) language = serverDefaultLanguage;
String language = getConfig().getString(LANGUAGE_PATH);
if (language == null) language = serverDefaultLanguage;
if (hasLanguage(serverDefaultLanguage)) {
setLanguage(serverDefaultLanguage, !serverDefaultLanguage.equals(language));
if (hasLanguage(serverDefaultLanguage)) {
setLanguage(serverDefaultLanguage, !serverDefaultLanguage.equals(language));
}
else {
setLanguage("en", false);
plugin.getLogger().log(Level.WARNING, "Could not recognize the given language: \"{0}\"", serverDefaultLanguage);
}
Slimefun.getLogger().log(Level.INFO, "Available languages: {0}", String.join(", ", languages.keySet()));
save();
}
else {
setLanguage("en", false);
plugin.getLogger().log(Level.WARNING, "Could not recognize the given language: \"{0}\"", serverDefaultLanguage);
translationsEnabled = false;
defaultLanguage = null;
}
Slimefun.getLogger().log(Level.INFO, "Available languages: {0}", String.join(", ", languages.keySet()));
save();
}
/**

View File

@ -4,6 +4,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
@ -60,6 +61,10 @@ public class MinecraftRecipeService {
* @return An {@link Optional} describing the furnace output of the given {@link ItemStack}
*/
public Optional<ItemStack> getFurnaceOutput(ItemStack input) {
if (input == null) {
return Optional.empty();
}
return snapshot.getRecipeOutput(MinecraftRecipe.FURNACE, input);
}
@ -75,6 +80,8 @@ public class MinecraftRecipeService {
* @return An Array of {@link RecipeChoice} representing the shape of this {@link Recipe}
*/
public RecipeChoice[] getRecipeShape(Recipe recipe) {
Validate.notNull(recipe, "Recipe must not be null!");
if (recipe instanceof ShapedRecipe) {
List<RecipeChoice> choices = new LinkedList<>();

View File

@ -11,6 +11,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import org.bukkit.Server;
@ -18,6 +19,7 @@ import org.bukkit.World;
import io.github.thebusybiscuit.cscorelib2.collections.OptionalMap;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -32,9 +34,9 @@ public class PerWorldSettingsService {
private final SlimefunPlugin plugin;
private final OptionalMap<String, Set<String>> disabledItems = new OptionalMap<>(HashMap::new);
private final OptionalMap<UUID, Set<String>> disabledItems = new OptionalMap<>(HashMap::new);
private final Map<SlimefunAddon, Set<String>> disabledAddons = new HashMap<>();
private final Set<String> disabledWorlds = new HashSet<>();
private final Set<UUID> disabledWorlds = new HashSet<>();
public PerWorldSettingsService(SlimefunPlugin plugin) {
this.plugin = plugin;
@ -66,7 +68,7 @@ public class PerWorldSettingsService {
* The {@link World} to load
*/
public void load(World world) {
disabledItems.putIfAbsent(world.getName(), loadWorldFromConfig(world.getName()));
disabledItems.putIfAbsent(world.getUID(), loadWorldFromConfig(world));
}
/**
@ -111,9 +113,9 @@ public class PerWorldSettingsService {
* @return Whether the given {@link SlimefunItem} is enabled in that {@link World}
*/
public boolean isEnabled(World world, SlimefunItem item) {
Set<String> items = disabledItems.computeIfAbsent(world.getName(), this::loadWorldFromConfig);
Set<String> items = disabledItems.computeIfAbsent(world.getUID(), id -> loadWorldFromConfig(world));
if (disabledWorlds.contains(world.getName())) {
if (disabledWorlds.contains(world.getUID())) {
return false;
}
@ -131,7 +133,7 @@ public class PerWorldSettingsService {
* Whether the given {@link SlimefunItem} should be enabled in that world
*/
public void setEnabled(World world, SlimefunItem item, boolean enabled) {
Set<String> items = disabledItems.computeIfAbsent(world.getName(), this::loadWorldFromConfig);
Set<String> items = disabledItems.computeIfAbsent(world.getUID(), id -> loadWorldFromConfig(world));
if (enabled) {
items.remove(item.getID());
@ -141,6 +143,25 @@ public class PerWorldSettingsService {
}
}
/**
* This method enables or disables the given {@link World}.
*
* @param world
* The {@link World} to enable or disable
* @param enabled
* Whether this {@link World} should be enabled or not
*/
public void setEnabled(World world, boolean enabled) {
load(world);
if (enabled) {
disabledWorlds.remove(world.getUID());
}
else {
disabledWorlds.add(world.getUID());
}
}
/**
* This checks whether the given {@link World} is enabled or not.
*
@ -151,7 +172,8 @@ public class PerWorldSettingsService {
*/
public boolean isWorldEnabled(World world) {
load(world);
return !disabledWorlds.contains(world.getName());
return !disabledWorlds.contains(world.getUID());
}
/**
@ -177,7 +199,7 @@ public class PerWorldSettingsService {
* The {@link World} to save
*/
public void save(World world) {
Set<String> items = disabledItems.computeIfAbsent(world.getName(), this::loadWorldFromConfig);
Set<String> items = disabledItems.computeIfAbsent(world.getUID(), id -> loadWorldFromConfig(world));
Config config = new Config(plugin, "world-settings/" + world + ".yml");
@ -191,8 +213,9 @@ public class PerWorldSettingsService {
config.save();
}
private Set<String> loadWorldFromConfig(String name) {
Optional<Set<String>> optional = disabledItems.get(name);
private Set<String> loadWorldFromConfig(World world) {
String name = world.getName();
Optional<Set<String>> optional = disabledItems.get(world.getUID());
if (optional.isPresent()) {
return optional.get();
@ -225,10 +248,12 @@ public class PerWorldSettingsService {
}
}
config.save();
if (SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) {
config.save();
}
}
else {
disabledWorlds.add(name);
disabledWorlds.add(world.getUID());
}
return items;

View File

@ -33,7 +33,7 @@ public class PermissionsService {
config.getConfiguration().options().copyHeader(true);
}
public void register(Iterable<SlimefunItem> items) {
public void register(Iterable<SlimefunItem> items, boolean save) {
for (SlimefunItem item : items) {
if (item != null && item.getID() != null && !migrate(item)) {
config.setDefaultValue(item.getID() + ".permission", "none");
@ -42,7 +42,9 @@ public class PermissionsService {
}
}
config.save();
if (save) {
config.save();
}
}
// Temporary migration method for the old system

View File

@ -5,6 +5,7 @@ import java.util.logging.Level;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.cscorelib2.updater.GitHubBuildsUpdater;
import io.github.thebusybiscuit.cscorelib2.updater.Updater;
import io.github.thebusybiscuit.slimefun4.api.SlimefunBranch;
@ -30,32 +31,47 @@ public class UpdaterService {
*
* @param plugin
* The instance of Slimefun
* @param version
* The current version of Slimefun
* @param file
* The {@link File} of this {@link Plugin}
*/
public UpdaterService(SlimefunPlugin plugin, File file) {
public UpdaterService(SlimefunPlugin plugin, String version, File file) {
this.plugin = plugin;
String version = plugin.getDescription().getVersion();
Updater autoUpdater = null;
if (version.contains("UNOFFICIAL")) {
// This Server is using a modified build that is not a public release.
updater = null;
branch = SlimefunBranch.UNOFFICIAL;
}
else if (version.startsWith("DEV - ")) {
// If we are using a development build, we want to switch to our custom
updater = new GitHubBuildsUpdater(plugin, file, "TheBusyBiscuit/Slimefun4/master");
try {
autoUpdater = new GitHubBuildsUpdater(plugin, file, "TheBusyBiscuit/Slimefun4/master");
}
catch (Exception x) {
plugin.getLogger().log(Level.SEVERE, "Failed to create AutoUpdater", x);
}
branch = SlimefunBranch.DEVELOPMENT;
}
else if (version.startsWith("RC - ")) {
// If we are using a "stable" build, we want to switch to our custom
updater = new GitHubBuildsUpdater(plugin, file, "TheBusyBiscuit/Slimefun4/stable", "RC - ");
try {
autoUpdater = new GitHubBuildsUpdater(plugin, file, "TheBusyBiscuit/Slimefun4/stable", "RC - ");
}
catch (Exception x) {
plugin.getLogger().log(Level.SEVERE, "Failed to create AutoUpdater", x);
}
branch = SlimefunBranch.STABLE;
}
else {
updater = null;
branch = SlimefunBranch.UNKNOWN;
}
this.updater = autoUpdater;
}
/**
@ -86,6 +102,17 @@ public class UpdaterService {
}
}
/**
* This returns whether the {@link Updater} is enabled or not.
* This includes the {@link Config} setting but also whether or not we are running an
* official or unofficial build.
*
* @return Whether the {@link Updater} is enabled
*/
public boolean isEnabled() {
return SlimefunPlugin.getCfg().getBoolean("options.auto-update") && updater != null;
}
/**
* This method is called when the {@link UpdaterService} was disabled.
*/

View File

@ -35,6 +35,12 @@ public class GitHubService {
private int stars = 0;
private LocalDateTime lastUpdate = LocalDateTime.now();
/**
* This creates a new {@link GitHubService} for the given repository.
*
* @param repository
* The repository to create this {@link GitHubService} for
*/
public GitHubService(String repository) {
this.repository = repository;
@ -70,10 +76,10 @@ public class GitHubService {
connectors.add(new ContributionsConnector(this, "code2", 2, repository, "developer"));
// TheBusyBiscuit/Slimefun4-Wiki
connectors.add(new ContributionsConnector(this, "wiki", 1, "TheBusyBiscuit/Slimefun4-wiki", "wiki"));
connectors.add(new ContributionsConnector(this, "wiki", 1, "Slimefun/Slimefun-wiki", "wiki"));
// TheBusyBiscuit/Slimefun4-Resourcepack
connectors.add(new ContributionsConnector(this, "resourcepack", 1, "TheBusyBiscuit/Slimefun4-Resourcepack", "resourcepack"));
connectors.add(new ContributionsConnector(this, "resourcepack", 1, "Slimefun/Resourcepack", "resourcepack"));
// Issues and Pull Requests
connectors.add(new GitHubIssuesTracker(this, repository, (issues, pullRequests) -> {
@ -103,35 +109,74 @@ public class GitHubService {
});
}
public Set<GitHubConnector> getConnectors() {
protected Set<GitHubConnector> getConnectors() {
return connectors;
}
protected boolean isLoggingEnabled() {
return logging;
}
/**
* This returns the {@link Contributor Contributors} to this project.
*
* @return A {@link ConcurrentMap} containing all {@link Contributor Contributors}
*/
public ConcurrentMap<String, Contributor> getContributors() {
return contributors;
}
/**
* This returns the amount of forks of our repository
*
* @return The amount of forks
*/
public int getForks() {
return forks;
}
/**
* This method returns the amount of stargazers of the repository.
*
* @return The amount of people who starred the repository
*/
public int getStars() {
return stars;
}
public int getIssues() {
/**
* This returns the amount of open Issues on our repository.
*
* @return The amount of open issues
*/
public int getOpenissues() {
return issues;
}
public int getPullRequests() {
/**
* Returns the id of Slimefun's GitHub Repository. (e.g. "TheBusyBiscuit/Slimefun4").
*
* @return The id of our GitHub Repository
*/
public String getRepository() {
return repository;
}
/**
* This method returns the amount of pending pull requests.
*
* @return The amount of pending pull requests
*/
public int getPendingPullRequests() {
return pullRequests;
}
/**
* This returns the date and time of the last commit to this repository.
*
* @return A {@link LocalDateTime} object representing the date and time of the latest commit
*/
public LocalDateTime getLastUpdate() {
return lastUpdate;
}
public boolean isLoggingEnabled() {
return logging;
}
}

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.core.services.localization;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
@ -85,11 +86,13 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
public String getMessage(Player p, String key) {
Language language = getLanguage(p);
if (language == null) return "NO LANGUAGE FOUND";
return language.getMessages().getString(key);
}
public List<String> getMessages(Player p, String key) {
Language language = getLanguage(p);
if (language == null) return Arrays.asList("NO LANGUAGE FOUND");
return language.getMessages().getStringList(key);
}

View File

@ -8,7 +8,7 @@ class AutoUpdaterChart extends SimplePie {
AutoUpdaterChart() {
super("auto_updates", () -> {
boolean enabled = SlimefunPlugin.getCfg().getBoolean("options.auto-update");
boolean enabled = SlimefunPlugin.getUpdater().isEnabled();
return enabled ? "enabled" : "disabled";
});
}

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
@ -7,9 +8,9 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Research;
class PlaceholderAPIHook extends PlaceholderExpansion {
@ -40,27 +41,43 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
@Override
public String onRequest(OfflinePlayer p, String params) {
if (params.equals("researches_total_xp_levels_spent")) {
Stream<Research> stream = PlayerProfile.get(p).getResearches().stream();
return String.valueOf(stream.mapToInt(Research::getCost).sum());
if (params.equals("researches_total_xp_levels_spent") && PlayerProfile.request(p)) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
Stream<Research> stream = profile.get().getResearches().stream();
return String.valueOf(stream.mapToInt(Research::getCost).sum());
}
}
if (params.equals("researches_total_researches_unlocked")) {
Set<Research> set = PlayerProfile.get(p).getResearches();
return String.valueOf(set.size());
if (params.equals("researches_total_researches_unlocked") && PlayerProfile.request(p)) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
Set<Research> set = profile.get().getResearches();
return String.valueOf(set.size());
}
}
if (params.equals("researches_total_researches")) {
return String.valueOf(SlimefunPlugin.getRegistry().getResearches().size());
}
if (params.equals("researches_percentage_researches_unlocked")) {
Set<Research> set = PlayerProfile.get(p).getResearches();
return String.valueOf(Math.round(((set.size() * 100.0F) / SlimefunPlugin.getRegistry().getResearches().size()) * 100.0F) / 100.0F);
if (params.equals("researches_percentage_researches_unlocked") && PlayerProfile.request(p)) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
Set<Research> set = profile.get().getResearches();
return String.valueOf(Math.round(((set.size() * 100.0F) / SlimefunPlugin.getRegistry().getResearches().size()) * 100.0F) / 100.0F);
}
}
if (params.equals("researches_title")) {
return PlayerProfile.get(p).getTitle();
if (params.equals("researches_title") && PlayerProfile.request(p)) {
Optional<PlayerProfile> profile = PlayerProfile.find(p);
if (profile.isPresent()) {
return profile.get().getTitle();
}
}
if (params.equals("gps_complexity")) {

View File

@ -21,15 +21,15 @@ import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@ -47,7 +47,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
return new CustomItem(new ItemStack(Material.ENCHANTED_BOOK), "&aSlimefun Guide &7(Book GUI)", "", "&eRight Click &8\u21E8 &7Browse Items", "&eShift + Right Click &8\u21E8 &7Open Settings / Credits");
}
private void openBook(Player p, List<ChatComponent> lines, boolean backButton) {
private void openBook(Player p, PlayerProfile profile, List<ChatComponent> lines, boolean backButton) {
CustomBookInterface book = new CustomBookInterface(SlimefunPlugin.instance);
book.setTitle(SlimefunPlugin.getLocal().getMessage(p, "guide.title.main"));
@ -56,10 +56,10 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
ChatComponent header = new ChatComponent(ChatColors.color("&b&l- " + SlimefunPlugin.getLocal().getMessage(p, "guide.title.main") + " -\n\n"));
header.setHoverEvent(new HoverEvent(ChestMenuUtils.getSearchButton(p)));
header.setClickEvent(new ClickEvent(guideSearch, player -> PlayerProfile.get(player, profile -> Slimefun.runSync(() -> {
header.setClickEvent(new ClickEvent(guideSearch, player -> Slimefun.runSync(() -> {
SlimefunPlugin.getLocal().sendMessage(player, "guide.search.message");
ChatInput.waitForPlayer(SlimefunPlugin.instance, player, msg -> SlimefunGuide.openSearch(profile, msg, true, true));
}, 1))));
}, 1)));
page.append(header);
@ -72,7 +72,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
if (backButton) {
ChatComponent button = new ChatComponent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocal().getMessage(p, "guide.back.title"));
button.setHoverEvent(new HoverEvent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocal().getMessage(p, "guide.back.title"), "", ChatColor.GRAY + SlimefunPlugin.getLocal().getMessage(p, "guide.back.guide")));
button.setClickEvent(new ClickEvent(new NamespacedKey(SlimefunPlugin.instance, "slimefun_guide"), pl -> openMainMenu(PlayerProfile.get(pl), 1)));
button.setClickEvent(new ClickEvent(new NamespacedKey(SlimefunPlugin.instance, "slimefun_guide"), pl -> openMainMenu(profile, 1)));
page.append(button);
}
@ -132,7 +132,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
}
}
openBook(p, lines, false);
openBook(p, profile, lines, false);
}
@Override
@ -206,7 +206,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
}
}
openBook(p, lines, true);
openBook(p, profile, lines, true);
}
else {
p.sendMessage(ChatColor.RED + "That Category is too big to open :/");

View File

@ -28,11 +28,13 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.MultiBlock;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
@ -40,8 +42,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.MenuClickHan
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks.MultiBlockMachine;
import me.mrCookieSlime.Slimefun.api.Slimefun;

View File

@ -0,0 +1,34 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.backpacks;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.Category;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
/**
* This class represents a {@link SlimefunBackpack} that has been restored via /sf backpack for retrieving items if the
* original has been lost.
* This backpack cannot be crafted nor crafted into other items. Its purpose is exclusively that of restoring
* the lost inventory and shouldn't be used as a backpack replacement.
* Right-Clicking will open the {@link Inventory} of the restored Backpack.
*
* @author Sfiguz7
*
* @see PlayerBackpack
*/
public class RestoredBackpack extends SlimefunBackpack {
/**
* This will create a new {@link SlimefunBackpack} with the given arguments.
*
* @param category
* the category to bind this {@link SlimefunBackpack} to
*/
public RestoredBackpack(Category category) {
super(54, category, SlimefunItems.RESTORED_BACKPACK, RecipeType.NULL, new ItemStack[9]);
this.hidden = true;
}
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.tools;
package io.github.thebusybiscuit.slimefun4.implementation.items.backpacks;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;

View File

@ -1,17 +1,22 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
package io.github.thebusybiscuit.slimefun4.implementation.items.backpacks;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* This implementation of {@link SlimefunBackpack} is also {@link Soulbound}.
*
* @author TheBusyBiscuit
*
*/
public class SoulboundBackpack extends SlimefunBackpack implements Soulbound {
public SoulboundBackpack(int size, Category category, SlimefunItemStack item, ItemStack[] recipe) {
super(size, category, item, RecipeType.MAGIC_WORKBENCH, recipe);
public SoulboundBackpack(int size, Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(size, category, item, recipeType, recipe);
}
}

View File

@ -0,0 +1,5 @@
/**
* This package holds classes related to
* {@link io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack}.
*/
package io.github.thebusybiscuit.slimefun4.implementation.items.backpacks;

View File

@ -72,7 +72,7 @@ public class EnhancedFurnace extends SimpleSlimefunItem<BlockTicker> {
if (furnace.getCookTime() > 0) {
int cookTime = furnace.getCookTime() + getSpeed() * 10;
furnace.setCookTime((short) Math.min(cookTime, furnace.getCookTimeTotal()));
furnace.setCookTime((short) Math.min(cookTime, furnace.getCookTimeTotal() - 1));
furnace.update(true, false);
}
}

View File

@ -0,0 +1,24 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.NotPlaceable;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemUseHandler;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class UnplaceableBlock extends SimpleSlimefunItem<ItemUseHandler> implements NotPlaceable {
public UnplaceableBlock(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@Override
public ItemUseHandler getItemHandler() {
return PlayerRightClickEvent::cancel;
}
}

View File

@ -97,10 +97,12 @@ public class AutoBreeder extends SlimefunItem implements InventoryBlock, EnergyN
protected void tick(Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
for (Entity n : b.getWorld().getNearbyEntities(b.getLocation(), 4.0, 2.0, 4.0, n -> n instanceof Animals && n.isValid() && ((Animals) n).isAdult() && !((Animals) n).isLoveMode())) {
for (Entity n : b.getWorld().getNearbyEntities(b.getLocation(), 4.0, 2.0, 4.0, this::canBreed)) {
for (int slot : getInputSlots()) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), SlimefunItems.ORGANIC_FOOD, false)) {
if (ChargableBlock.getCharge(b) < ENERGY_CONSUMPTION) return;
if (ChargableBlock.getCharge(b) < ENERGY_CONSUMPTION) {
return;
}
ChargableBlock.addCharge(b, -ENERGY_CONSUMPTION);
inv.consumeItem(slot);
@ -113,4 +115,14 @@ public class AutoBreeder extends SlimefunItem implements InventoryBlock, EnergyN
}
}
private boolean canBreed(Entity n) {
if (n.isValid() && n instanceof Animals) {
Animals animal = (Animals) n;
return animal.isAdult() && !animal.isLoveMode();
}
return false;
}
}

View File

@ -3,7 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.food;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.CoolerListener;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;

View File

@ -13,10 +13,10 @@ import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemUseHandler;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -42,8 +42,9 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
@Override
public ItemDropHandler getItemHandler() {
return (e, p, i) -> {
ItemStack item = i.getItemStack();
return (e, p, droppedItem) -> {
ItemStack item = droppedItem.getItemStack();
if (isItem(item)) {
if (!Slimefun.hasUnlocked(p, SlimefunItems.RUNE_SOULBOUND, true)) {
@ -52,42 +53,39 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
Slimefun.runSync(() -> {
// Being sure the entity is still valid and not picked up or whatsoever.
if (!i.isValid()) return;
if (!droppedItem.isValid()) {
return;
}
Location l = i.getLocation();
Location l = droppedItem.getLocation();
Collection<Entity> entites = l.getWorld().getNearbyEntities(l, 1.5, 1.5, 1.5, this::findCompatibleItem);
if (entites.isEmpty()) return;
if (entites.isEmpty()) {
return;
}
Entity entity = entites.stream().findFirst().get();
ItemStack ench = ((Item) entity).getItemStack();
Item ent = (Item) entity;
ItemStack target = ((Item) entity).getItemStack();
Item targetItem = (Item) entity;
if (ench.getAmount() == 1) {
SlimefunUtils.setSoulbound(target, true);
if (target.getAmount() == 1) {
e.setCancelled(true);
ItemMeta enchMeta = ench.getItemMeta();
List<String> lore = enchMeta.hasLore() ? enchMeta.getLore() : new ArrayList<>();
// This lightning is just an effect, it deals no damage.
l.getWorld().strikeLightningEffect(l);
Slimefun.runSync(() -> {
// Being sure entities are still valid and not picked up or whatsoever.
if (i.isValid() && ent.isValid()) {
if (droppedItem.isValid() && targetItem.isValid() && target.getAmount() == 1) {
l.getWorld().createExplosion(l, 0.0F);
l.getWorld().playSound(l, Sound.ENTITY_GENERIC_EXPLODE, 0.3F, 1F);
lore.add(ChatColor.GRAY + "Soulbound");
enchMeta.setLore(lore);
ench.setItemMeta(enchMeta);
ent.remove();
i.remove();
l.getWorld().dropItemNaturally(l, ench);
targetItem.remove();
droppedItem.remove();
l.getWorld().dropItemNaturally(l, target);
SlimefunPlugin.getLocal().sendMessage(p, "messages.soulbound-rune.success", true);
}
@ -104,6 +102,22 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
};
}
/**
* This method applies the {@link Soulbound} effect onto a given {@link ItemStack}.
*
* @param item
* The {@link ItemStack} to apply this effect to
*/
public void apply(ItemStack item) {
// Should rather use PersistentData here
ItemMeta meta = item.getItemMeta();
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
lore.add(ChatColor.GRAY + "Soulbound");
meta.setLore(lore);
item.setItemMeta(meta);
}
private boolean findCompatibleItem(Entity n) {
if (n instanceof Item) {
Item item = (Item) n;

View File

@ -5,9 +5,9 @@ import org.bukkit.block.EnderChest;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@ -21,13 +21,8 @@ class EnderTalisman extends Talisman {
private static final LockedCategory ENDER_TALISMANS_CATEGORY = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance, "ender_talismans"), new CustomItem(SlimefunItems.ENDER_TALISMAN, "&7Talismans - &aTier II"), 3, Talisman.TALISMANS_CATEGORY.getKey());
public EnderTalisman(Talisman parent) {
super(ENDER_TALISMANS_CATEGORY, parent.upgrade(), new ItemStack[] { SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3, null, parent.getItem(), null, SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3 }, parent.isConsumable(), parent.isEventCancelled(), parent.getSuffix(), parent.getChance(), parent.getEffects());
}
@Override
public SlimefunItemStack upgrade() {
throw new UnsupportedOperationException();
public EnderTalisman(Talisman parent, SlimefunItemStack item) {
super(ENDER_TALISMANS_CATEGORY, item, new ItemStack[] { SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3, null, parent.getItem(), null, SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3 }, parent.isConsumable(), parent.isEventCancelled(), parent.getMessageSuffix(), parent.getChance(), parent.getEffects());
}
@Override

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical.talisman
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import org.bukkit.ChatColor;
@ -19,11 +20,11 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
@ -32,6 +33,8 @@ public class Talisman extends SlimefunItem {
protected static final Category TALISMANS_CATEGORY = new Category(new NamespacedKey(SlimefunPlugin.instance, "talismans"), new CustomItem(SlimefunItems.TALISMAN, "&7Talismans - &aTier I"), 2);
private final SlimefunItemStack enderTalisman;
protected final String suffix;
protected final boolean consumable;
protected final boolean cancel;
@ -58,43 +61,51 @@ public class Talisman extends SlimefunItem {
this.suffix = messageSuffix;
this.effects = effects;
this.chance = chance;
}
public String getSuffix() {
return suffix;
if (!(this instanceof EnderTalisman)) {
String name = "&5Ender " + ChatColor.stripColor(getItem().getItemMeta().getDisplayName());
List<String> lore = new ArrayList<>();
lore.add("&7&oEnder Infused");
lore.add("");
for (String line : getItem().getItemMeta().getLore()) {
lore.add(line);
}
enderTalisman = new SlimefunItemStack("ENDER_" + getID(), getItem().getType(), name, lore.toArray(new String[0]));
}
else {
enderTalisman = null;
}
}
public boolean isConsumable() {
return consumable;
}
public boolean isEventCancelled() {
return cancel;
public int getChance() {
return chance;
}
public PotionEffect[] getEffects() {
return effects;
}
public int getChance() {
return chance;
protected String getMessageSuffix() {
return suffix;
}
public SlimefunItemStack upgrade() {
List<String> lore = new ArrayList<>();
lore.add("&7&oEnder Infused");
lore.add("");
protected boolean isEventCancelled() {
return cancel;
}
for (String line : getItem().getItemMeta().getLore()) {
lore.add(line);
}
return new SlimefunItemStack("ENDER_" + getID(), getItem().getType(), "&5Ender " + ChatColor.stripColor(getItem().getItemMeta().getDisplayName()), lore.toArray(new String[lore.size()]));
private SlimefunItemStack getEnderVariant() {
return enderTalisman;
}
@Override
public void postRegister() {
EnderTalisman talisman = new EnderTalisman(this);
EnderTalisman talisman = new EnderTalisman(this, getEnderVariant());
talisman.register(addon);
}
@ -105,16 +116,16 @@ public class Talisman extends SlimefunItem {
}
protected void createEnderTalisman() {
EnderTalisman talisman = (EnderTalisman) SlimefunItem.getByItem(upgrade());
Research research = Research.getByID(112);
EnderTalisman talisman = (EnderTalisman) SlimefunItem.getByItem(getEnderVariant());
Optional<Research> research = Research.getResearch(new NamespacedKey(SlimefunPlugin.instance, "ender_talismans"));
if (talisman != null && research != null) {
talisman.setResearch(research);
if (talisman != null && research.isPresent()) {
talisman.setResearch(research.get());
}
}
private static boolean hasMessage(Talisman talisman) {
return !("").equalsIgnoreCase(talisman.getSuffix());
return !("").equalsIgnoreCase(talisman.getMessageSuffix());
}
public static boolean checkFor(Event e, SlimefunItemStack stack) {
@ -137,25 +148,37 @@ public class Talisman extends SlimefunItem {
return false;
}
if (p.getInventory().containsAtLeast(talisman.getItem(), 1)) {
if (Slimefun.hasUnlocked(p, talisman.getItem(), true)) {
activateTalisman(e, p, p.getInventory(), talisman, talisman.getItem());
ItemStack talismanItem = talisman.getItem();
if (p.getInventory().containsAtLeast(talismanItem, 1)) {
if (Slimefun.hasUnlocked(p, talismanItem, true)) {
activateTalisman(e, p, p.getInventory(), talisman, talismanItem);
return true;
}
else return false;
}
else if (p.getEnderChest().containsAtLeast(talisman.upgrade(), 1)) {
if (Slimefun.hasUnlocked(p, talisman.upgrade(), true)) {
activateTalisman(e, p, p.getEnderChest(), talisman, talisman.upgrade());
return true;
else {
return false;
}
}
else {
ItemStack enderTalisman = talisman.getEnderVariant();
if (p.getEnderChest().containsAtLeast(enderTalisman, 1)) {
if (Slimefun.hasUnlocked(p, enderTalisman, true)) {
activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman);
return true;
}
else {
return false;
}
}
else {
return false;
}
else return false;
}
else return false;
}
private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismantype) {
consumeItem(inv, talisman, talismantype);
private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismanItem) {
consumeItem(inv, talisman, talismanItem);
applyTalismanEffects(p, talisman);
cancelEvent(e, talisman);
sendMessage(p, talisman);
@ -176,22 +199,32 @@ public class Talisman extends SlimefunItem {
private static void sendMessage(Player p, Talisman talisman) {
if (hasMessage(talisman)) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.talisman." + talisman.getSuffix(), true);
SlimefunPlugin.getLocal().sendMessage(p, "messages.talisman." + talisman.getMessageSuffix(), true);
}
}
private static void consumeItem(Inventory inv, Talisman talisman, ItemStack talismantype) {
private static void consumeItem(Inventory inv, Talisman talisman, ItemStack talismanItem) {
if (talisman.isConsumable()) {
inv.removeItem(talismantype);
inv.removeItem(talismanItem);
}
}
private static Player getPlayerByEventType(Event e) {
if (e instanceof EntityDeathEvent) return ((EntityDeathEvent) e).getEntity().getKiller();
else if (e instanceof BlockBreakEvent) return ((BlockBreakEvent) e).getPlayer();
else if (e instanceof PlayerEvent) return ((PlayerEvent) e).getPlayer();
else if (e instanceof EntityEvent) return (Player) ((EntityEvent) e).getEntity();
else if (e instanceof EnchantItemEvent) return ((EnchantItemEvent) e).getEnchanter();
if (e instanceof EntityDeathEvent) {
return ((EntityDeathEvent) e).getEntity().getKiller();
}
else if (e instanceof BlockBreakEvent) {
return ((BlockBreakEvent) e).getPlayer();
}
else if (e instanceof PlayerEvent) {
return ((PlayerEvent) e).getPlayer();
}
else if (e instanceof EntityEvent) {
return (Player) ((EntityEvent) e).getEntity();
}
else if (e instanceof EnchantItemEvent) {
return ((EnchantItemEvent) e).getEnchanter();
}
return null;
}

View File

@ -1,10 +1,10 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
@ -12,11 +12,13 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks.MultiBlockMachine;
@ -50,44 +52,57 @@ abstract class BackpackCrafter extends MultiBlockMachine {
}
int size = backpack.getSize();
String id = retrieveID(backpackItem, size);
Optional<String> id = retrieveID(backpackItem, size);
if (id.equals("")) {
if (id.isPresent()) {
for (int line = 0; line < output.getItemMeta().getLore().size(); line++) {
if (output.getItemMeta().getLore().get(line).equals(ChatColor.translateAlternateColorCodes('&', "&7ID: <ID>"))) {
int backpackID = PlayerProfile.get(p).createBackpack(size).getID();
BackpackListener.setBackpackId(p, output, line, backpackID);
}
}
}
else {
for (int line = 0; line < output.getItemMeta().getLore().size(); line++) {
if (output.getItemMeta().getLore().get(line).equals(ChatColor.translateAlternateColorCodes('&', "&7ID: <ID>"))) {
if (output.getItemMeta().getLore().get(line).equals(ChatColors.color("&7ID: <ID>"))) {
ItemMeta im = output.getItemMeta();
List<String> lore = im.getLore();
lore.set(line, lore.get(line).replace("<ID>", id));
lore.set(line, lore.get(line).replace("<ID>", id.get()));
im.setLore(lore);
output.setItemMeta(im);
break;
}
}
}
}
else {
for (int line = 0; line < output.getItemMeta().getLore().size(); line++) {
if (output.getItemMeta().getLore().get(line).equals(ChatColors.color("&7ID: <ID>"))) {
int target = line;
private String retrieveID(ItemStack backpack, int size) {
if (backpack != null) {
for (String line : backpack.getItemMeta().getLore()) {
if (line.startsWith(ChatColor.translateAlternateColorCodes('&', "&7ID: ")) && line.contains("#")) {
String id = line.replace(ChatColor.translateAlternateColorCodes('&', "&7ID: "), "");
String[] idSplit = PatternUtils.HASH.split(id);
PlayerProfile.fromUUID(UUID.fromString(idSplit[0])).getBackpack(Integer.parseInt(idSplit[1])).setSize(size);
return id;
PlayerProfile.get(p, profile -> {
int backpackId = profile.createBackpack(size).getId();
SlimefunPlugin.getBackpackListener().setBackpackId(p, output, target, backpackId);
});
break;
}
}
}
return "";
}
private Optional<String> retrieveID(ItemStack backpack, int size) {
if (backpack != null) {
for (String line : backpack.getItemMeta().getLore()) {
if (line.startsWith(ChatColors.color("&7ID: ")) && line.contains("#")) {
String id = line.replace(ChatColors.color("&7ID: "), "");
String[] idSplit = PatternUtils.HASH.split(id);
PlayerProfile.fromUUID(UUID.fromString(idSplit[0]), profile -> {
Optional<PlayerBackpack> optional = profile.getBackpack(Integer.parseInt(idSplit[1]));
if (optional.isPresent()) {
optional.get().setSize(size);
}
});
return Optional.of(id);
}
}
}
return Optional.empty();
}
}

View File

@ -12,7 +12,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;

View File

@ -14,7 +14,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;

View File

@ -22,109 +22,98 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks.MultiBlockMachine;
public class OreWasher extends MultiBlockMachine {
private final boolean legacyMode;
public OreWasher(Category category) {
super(category, SlimefunItems.ORE_WASHER,
new ItemStack[] {null, new ItemStack(Material.DISPENSER), null, null, new ItemStack(Material.OAK_FENCE), null, null, new ItemStack(Material.CAULDRON), null},
new ItemStack[] {
SlimefunItems.SIFTED_ORE, SlimefunItems.IRON_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.GOLD_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.COPPER_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.TIN_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.ZINC_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.ALUMINUM_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.MAGNESIUM_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.LEAD_DUST,
SlimefunItems.SIFTED_ORE, SlimefunItems.SILVER_DUST
},
BlockFace.SELF
);
legacyMode = SlimefunPlugin.getCfg().getBoolean("options.legacy-ore-washer");
}
@Override
public List<ItemStack> getDisplayRecipes() {
return recipes.stream().map(items -> items[0]).collect(Collectors.toList());
}
@Override
public void onInteract(Player p, Block b) {
Block dispBlock = b.getRelative(BlockFace.UP);
Dispenser disp = (Dispenser) dispBlock.getState();
Inventory inv = disp.getInventory();
public OreWasher(Category category) {
super(category, SlimefunItems.ORE_WASHER, new ItemStack[] { null, new ItemStack(Material.DISPENSER), null, null, new ItemStack(Material.OAK_FENCE), null, null, new ItemStack(Material.CAULDRON), null }, new ItemStack[] { SlimefunItems.SIFTED_ORE, SlimefunItems.IRON_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.GOLD_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.COPPER_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.TIN_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.ZINC_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.ALUMINUM_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.MAGNESIUM_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.LEAD_DUST, SlimefunItems.SIFTED_ORE, SlimefunItems.SILVER_DUST }, BlockFace.SELF);
for (ItemStack current : inv.getContents()) {
if (current != null) {
if (SlimefunUtils.isItemSimilar(current, SlimefunItems.SIFTED_ORE, true)) {
ItemStack adding = getRandomDust();
Inventory outputInv = null;
legacyMode = SlimefunPlugin.getCfg().getBoolean("options.legacy-ore-washer");
}
if (!legacyMode) {
// This is a fancy way of checking if there is empty space in the inv; by checking if an unobtainable item could fit in it.
// However, due to the way the method findValidOutputInv() functions, the dummyAdding will never actually be added to the real inventory,
// so it really doesn't matter what item the ItemStack is made by. SlimefunItems.DEBUG_FISH however, signals that it's
// not supposed to be given to the player.
ItemStack dummyAdding = SlimefunItems.DEBUG_FISH;
outputInv = findOutputInventory(dummyAdding, dispBlock, inv);
}
else outputInv = findOutputInventory(adding, dispBlock, inv);
@Override
public List<ItemStack> getDisplayRecipes() {
return recipes.stream().map(items -> items[0]).collect(Collectors.toList());
}
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(1);
inv.removeItem(removing);
outputInv.addItem(adding);
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER);
if (InvUtils.fits(outputInv, SlimefunItems.STONE_CHUNK)) outputInv.addItem(SlimefunItems.STONE_CHUNK);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
return;
}
else if (SlimefunUtils.isItemSimilar(current, new ItemStack(Material.SAND, 4), false)) {
ItemStack adding = SlimefunItems.SALT;
Inventory outputInv = findOutputInventory(adding, dispBlock, inv);
@Override
public void onInteract(Player p, Block b) {
Block dispBlock = b.getRelative(BlockFace.UP);
Dispenser disp = (Dispenser) dispBlock.getState();
Inventory inv = disp.getInventory();
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(4);
inv.removeItem(removing);
outputInv.addItem(adding);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER);
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
for (ItemStack current : inv.getContents()) {
if (current != null) {
if (SlimefunUtils.isItemSimilar(current, SlimefunItems.SIFTED_ORE, true)) {
ItemStack output = getRandomDust();
Inventory outputInv = null;
return;
}
else if (SlimefunUtils.isItemSimilar(current, SlimefunItems.PULVERIZED_ORE, true)) {
ItemStack adding = SlimefunItems.PURE_ORE_CLUSTER;
Inventory outputInv = findOutputInventory(adding, dispBlock, inv);
if (!legacyMode) {
// This is a fancy way of checking if there is empty space in the inv; by checking if an
// unobtainable item could fit in it.
// However, due to the way the method findValidOutputInv() functions, the dummyAdding will never
// actually be added to the real inventory,
// so it really doesn't matter what item the ItemStack is made by. SlimefunItems.DEBUG_FISH
// however, signals that it's
// not supposed to be given to the player.
ItemStack dummyAdding = SlimefunItems.DEBUG_FISH;
outputInv = findOutputInventory(dummyAdding, dispBlock, inv);
}
else outputInv = findOutputInventory(output, dispBlock, inv);
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(1);
inv.removeItem(removing);
outputInv.addItem(adding);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER);
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(1);
inv.removeItem(removing);
outputInv.addItem(output);
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER);
if (InvUtils.fits(outputInv, SlimefunItems.STONE_CHUNK)) outputInv.addItem(SlimefunItems.STONE_CHUNK);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
return;
}
}
}
SlimefunPlugin.getLocal().sendMessage(p, "machines.unknown-material", true);
}
return;
}
else if (SlimefunUtils.isItemSimilar(current, new ItemStack(Material.SAND, 4), false)) {
ItemStack output = SlimefunItems.SALT;
Inventory outputInv = findOutputInventory(output, dispBlock, inv);
public ItemStack getRandomDust() {
int index = ThreadLocalRandom.current().nextInt(shownRecipes.size() / 2);
return shownRecipes.get(index * 2 + 1).clone();
}
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(2);
inv.removeItem(removing);
outputInv.addItem(output);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER);
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
return;
}
else if (SlimefunUtils.isItemSimilar(current, SlimefunItems.PULVERIZED_ORE, true)) {
ItemStack output = SlimefunItems.PURE_ORE_CLUSTER;
Inventory outputInv = findOutputInventory(output, dispBlock, inv);
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(1);
inv.removeItem(removing);
outputInv.addItem(output);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER);
p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
return;
}
}
}
SlimefunPlugin.getLocal().sendMessage(p, "machines.unknown-material", true);
}
public ItemStack getRandomDust() {
int index = ThreadLocalRandom.current().nextInt(shownRecipes.size() / 2);
return shownRecipes.get(index * 2 + 1).clone();
}
}

View File

@ -21,9 +21,9 @@ import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.Juice;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@ -53,10 +53,12 @@ public class BackpackListener implements Listener {
@EventHandler
public void onClose(InventoryCloseEvent e) {
if (backpacks.containsKey(e.getPlayer().getUniqueId())) {
((Player) e.getPlayer()).playSound(e.getPlayer().getLocation(), Sound.ENTITY_HORSE_ARMOR, 1F, 1F);
PlayerProfile.getBackpack(backpacks.get(e.getPlayer().getUniqueId())).markDirty();
backpacks.remove(e.getPlayer().getUniqueId());
Player p = ((Player) e.getPlayer());
ItemStack backpack = backpacks.remove(p.getUniqueId());
if (backpack != null) {
p.playSound(p.getLocation(), Sound.ENTITY_HORSE_ARMOR, 1F, 1F);
PlayerProfile.getBackpack(backpack, PlayerBackpack::markDirty);
}
}
@ -131,7 +133,7 @@ public class BackpackListener implements Listener {
List<String> lore = item.getItemMeta().getLore();
for (int line = 0; line < lore.size(); line++) {
if (lore.get(line).equals(ChatColors.color("&7ID: <ID>"))) {
setBackpackId(p, item, line, profile.createBackpack(size).getID());
setBackpackId(p, item, line, profile.createBackpack(size).getId());
break;
}
}
@ -140,9 +142,7 @@ public class BackpackListener implements Listener {
p.playSound(p.getLocation(), Sound.ENTITY_HORSE_ARMOR, 1F, 1F);
backpacks.put(p.getUniqueId(), item);
Slimefun.runSync(() -> {
PlayerBackpack backpack = PlayerProfile.getBackpack(item);
PlayerProfile.getBackpack(item, backpack -> {
if (backpack != null) {
backpack.open(p);
}
@ -153,7 +153,7 @@ public class BackpackListener implements Listener {
}
}
public static void setBackpackId(Player p, ItemStack item, int line, int id) {
public void setBackpackId(Player p, ItemStack item, int line, int id) {
ItemMeta im = item.getItemMeta();
List<String> lore = im.getLore();
lore.set(line, lore.get(line).replace("<ID>", p.getUniqueId() + "#" + id));

View File

@ -20,9 +20,7 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.HandledBlock;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -163,25 +161,6 @@ public class BlockListener implements Listener {
}
}
@EventHandler(ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
ItemStack item = e.getItemInHand();
if (SlimefunUtils.isItemSimilar(item, SlimefunItems.ADVANCED_CIRCUIT_BOARD, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.CARBON, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.COMPRESSED_CARBON, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.CARBON_CHUNK, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.ANDROID_MEMORY_CORE, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.LAVA_CRYSTAL, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.TINY_URANIUM, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.SMALL_URANIUM, true)) e.setCancelled(true);
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.BROKEN_SPAWNER, false)) e.setCancelled(true);
else if (e.getBlock().getY() != e.getBlockAgainst().getY() && (SlimefunUtils.isItemSimilar(item, SlimefunItems.CARGO_INPUT, false) || SlimefunUtils.isItemSimilar(item, SlimefunItems.CARGO_OUTPUT, false) || SlimefunUtils.isItemSimilar(item, SlimefunItems.CARGO_OUTPUT_ADVANCED, false))) {
SlimefunPlugin.getLocal().sendMessage(e.getPlayer(), "machines.CARGO_NODES.must-be-placed", true);
e.setCancelled(true);
}
}
private int getBonusDropsWithFortune(ItemStack item, Block b) {
int fortune = 1;

View File

@ -0,0 +1,38 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
/**
* This {@link Listener} is solely responsible for preventing Cargo Nodes from being placed
* on the top or bottom of a block.
*
* @author TheBusyBiscuit
*
*/
public class CargoNodeListener implements Listener {
public CargoNodeListener(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@EventHandler(ignoreCancelled = true)
public void onCargoNodePlace(BlockPlaceEvent e) {
if (e.getBlock().getY() != e.getBlockAgainst().getY() && isCargoNode(e.getItemInHand())) {
SlimefunPlugin.getLocal().sendMessage(e.getPlayer(), "machines.CARGO_NODES.must-be-placed", true);
e.setCancelled(true);
}
}
private boolean isCargoNode(ItemStack item) {
return SlimefunUtils.isItemSimilar(item, SlimefunItems.CARGO_INPUT, false)
|| SlimefunUtils.isItemSimilar(item, SlimefunItems.CARGO_OUTPUT, false)
|| SlimefunUtils.isItemSimilar(item, SlimefunItems.CARGO_OUTPUT_ADVANCED, false);
}
}

View File

@ -39,22 +39,22 @@ public class CoolerListener implements Listener {
}
@EventHandler
public void onStarve(FoodLevelChangeEvent e) {
public void onHungerLoss(FoodLevelChangeEvent e) {
if (cooler == null || cooler.isDisabled()) {
return;
}
if (e.getFoodLevel() < ((Player) e.getEntity()).getFoodLevel()) {
Player p = (Player) e.getEntity();
Player p = (Player) e.getEntity();
if (e.getFoodLevel() < p.getFoodLevel()) {
for (ItemStack item : p.getInventory().getContents()) {
if (cooler.isItem(item)) {
if (Slimefun.hasUnlocked(p, cooler, true)) {
PlayerBackpack backpack = PlayerProfile.getBackpack(item);
if (backpack != null && consumeJuice(p, backpack)) {
break;
}
PlayerProfile.getBackpack(item, backpack -> {
if (backpack != null) {
Slimefun.runSync(() -> consumeJuice(p, backpack));
}
});
}
else {
return;

View File

@ -1,6 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.bukkit.block.Furnace;
import org.bukkit.event.EventHandler;
@ -27,6 +28,10 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
*/
public class EnhancedFurnaceListener implements Listener {
// This will throttle the spam a bit, enough to irritate Server Owners so they report it
// but low enough to not cause them to rage quit
private long lastWarning = 0;
public EnhancedFurnaceListener(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -36,7 +41,14 @@ public class EnhancedFurnaceListener implements Listener {
SlimefunItem furnace = BlockStorage.check(e.getBlock());
if (furnace instanceof EnhancedFurnace && ((EnhancedFurnace) furnace).getFuelEfficiency() > 0) {
e.setBurnTime(((EnhancedFurnace) furnace).getFuelEfficiency() * e.getBurnTime());
int burnTime = e.getBurnTime();
int newBurnTime = ((EnhancedFurnace) furnace).getFuelEfficiency() * burnTime;
e.setBurnTime(newBurnTime);
if (e.getBurnTime() < burnTime && lastWarning + TimeUnit.MINUTES.toMillis(10) < System.currentTimeMillis()) {
lastWarning = System.currentTimeMillis();
throw new IllegalStateException("Enhanced Furnace tried to increase burn time but actually decreased it: " + burnTime + " > " + e.getBurnTime() + " (supposed to be " + newBurnTime + ")");
}
}
}

View File

@ -10,6 +10,7 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -40,17 +41,21 @@ public class IronGolemListener implements Listener {
item = inv.getItemInOffHand();
}
if (item != null && item.getType() == Material.IRON_INGOT && SlimefunItem.getByItem(item) != null) {
e.setCancelled(true);
SlimefunPlugin.getLocal().sendMessage(e.getPlayer(), "messages.no-iron-golem-heal");
if (item != null && item.getType() == Material.IRON_INGOT) {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
// This is just there to update the Inventory...
// Somehow cancelling it isn't enough.
if (e.getHand() == EquipmentSlot.HAND) {
inv.setItemInMainHand(item);
}
else if (e.getHand() == EquipmentSlot.OFF_HAND) {
inv.setItemInOffHand(item);
if (sfItem != null && !(sfItem instanceof VanillaItem)) {
e.setCancelled(true);
SlimefunPlugin.getLocal().sendMessage(e.getPlayer(), "messages.no-iron-golem-heal");
// This is just there to update the Inventory...
// Somehow cancelling it isn't enough.
if (e.getHand() == EquipmentSlot.HAND) {
inv.setItemInMainHand(item);
}
else if (e.getHand() == EquipmentSlot.OFF_HAND) {
inv.setItemInOffHand(item);
}
}
}
}

View File

@ -7,7 +7,7 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.api.network.NetworkManager;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
/**
@ -23,8 +23,8 @@ public class NetworkListener implements Listener {
private final NetworkManager manager;
public NetworkListener(SlimefunPlugin plugin) {
manager = SlimefunPlugin.getNetworkManager();
public NetworkListener(SlimefunPlugin plugin, NetworkManager manager) {
this.manager = manager;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -34,7 +34,7 @@ public class NetworkListener implements Listener {
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlaceBreak(BlockPlaceEvent e) {
public void onBlockPlace(BlockPlaceEvent e) {
manager.handleAllNetworkLocationUpdate(e.getBlock().getLocation());
}
}

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
@ -13,9 +14,8 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
@ -37,7 +37,8 @@ public class VanillaMachinesListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onGrindstone(InventoryClickEvent e) {
// The Grindstone was only ever added in MC 1.14
if (!SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
MinecraftVersion minecraftVersion = SlimefunPlugin.getMinecraftVersion();
if (!minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
return;
}
@ -46,9 +47,10 @@ public class VanillaMachinesListener implements Listener {
ItemStack item2 = e.getInventory().getContents()[1];
if (checkForUnallowedItems(item1, item2)) {
e.setCancelled(true);
e.setResult(Result.DENY);
}
}
}
@EventHandler
@ -57,7 +59,7 @@ public class VanillaMachinesListener implements Listener {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null && !sfItem.isUseableInWorkbench()) {
e.setCancelled(true);
e.setResult(Result.DENY);
SlimefunPlugin.getLocal().sendMessage((Player) e.getWhoClicked(), "workbench.not-enhanced", true);
break;
}
@ -78,14 +80,14 @@ public class VanillaMachinesListener implements Listener {
}
}
@EventHandler
@EventHandler(ignoreCancelled = true)
public void onAnvil(InventoryClickEvent e) {
if (e.getRawSlot() == 2 && e.getInventory().getType() == InventoryType.ANVIL && e.getWhoClicked() instanceof Player) {
ItemStack item1 = e.getInventory().getContents()[0];
ItemStack item2 = e.getInventory().getContents()[1];
if (!SlimefunUtils.isItemSimilar(item1, SlimefunItems.ELYTRA, true) && checkForUnallowedItems(item1, item2)) {
e.setCancelled(true);
if (checkForUnallowedItems(item1, item2)) {
e.setResult(Result.DENY);
SlimefunPlugin.getLocal().sendMessage((Player) e.getWhoClicked(), "anvil.not-working", true);
}
}
@ -96,7 +98,7 @@ public class VanillaMachinesListener implements Listener {
Inventory inventory = e.getInventory();
if (inventory.getType() == InventoryType.BREWING && e.getRawSlot() < inventory.getSize() && inventory.getHolder() instanceof BrewingStand) {
e.setCancelled(SlimefunItem.getByItem(e.getCursor()) != null);
e.setCancelled(isUnallowed(SlimefunItem.getByItem(e.getCursor())));
}
}
@ -108,11 +110,15 @@ public class VanillaMachinesListener implements Listener {
SlimefunItem sfItem1 = SlimefunItem.getByItem(item1);
SlimefunItem sfItem2 = SlimefunItem.getByItem(item2);
if ((sfItem1 != null && !sfItem1.isDisabled()) || (sfItem2 != null && !sfItem2.isDisabled())) {
if (isUnallowed(sfItem1) || isUnallowed(sfItem2)) {
return true;
}
}
return false;
}
private boolean isUnallowed(SlimefunItem item) {
return item != null && !(item instanceof VanillaItem) && !item.isDisabled();
}
}

View File

@ -7,12 +7,12 @@ import org.bukkit.NamespacedKey;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.skull.SkullItem;
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
/**
* This class holds a reference to every {@link Category}

View File

@ -87,13 +87,13 @@ public final class PostSetup {
CommandSender sender = Bukkit.getConsoleSender();
int total = SlimefunPlugin.getRegistry().getEnabledSlimefunItems().size();
int vanilla = SlimefunPlugin.getRegistry().countVanillaItems();
int slimefunOnly = countNonAddonItems();
sender.sendMessage("");
sender.sendMessage(ChatColor.GREEN + "######################### - Slimefun v" + SlimefunPlugin.getVersion() + " - #########################");
sender.sendMessage("");
sender.sendMessage(ChatColor.GREEN + "Successfully loaded " + total + " Items and " + SlimefunPlugin.getRegistry().getResearches().size() + " Researches");
sender.sendMessage(ChatColor.GREEN + "( " + vanilla + " Items from Slimefun, " + (total - vanilla) + " Items from " + SlimefunPlugin.getInstalledAddons().size() + " Addons )");
sender.sendMessage(ChatColor.GREEN + "( " + slimefunOnly + " Items from Slimefun, " + (total - slimefunOnly) + " Items from " + SlimefunPlugin.getInstalledAddons().size() + " Addons )");
sender.sendMessage("");
sender.sendMessage(ChatColor.GREEN + "Slimefun is an Open-Source project that is kept alive by a large community.");
sender.sendMessage(ChatColor.GREEN + "Consider helping us maintain this project by contributing on GitHub!");
@ -117,6 +117,10 @@ public final class PostSetup {
SlimefunPlugin.getRegistry().setAutoLoadingMode(true);
}
private static int countNonAddonItems() {
return (int) SlimefunPlugin.getRegistry().getEnabledSlimefunItems().stream().filter(item -> item.getAddon() instanceof SlimefunPlugin).count();
}
private static void loadAutomaticCraftingChamber() {
AutomatedCraftingChamber crafter = (AutomatedCraftingChamber) SlimefunItems.AUTOMATED_CRAFTING_CHAMBER.getItem();

View File

@ -4,11 +4,10 @@ import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This static setup class is used to register all default implementations of
@ -110,10 +109,10 @@ public final class ResearchSetup {
register("table_saw", 92, "Table Saw", 4, SlimefunItems.TABLE_SAW);
register("slime_steel_armor", 93, "Slimy Steel Armor", 27, SlimefunItems.SLIME_HELMET_STEEL, SlimefunItems.SLIME_CHESTPLATE_STEEL, SlimefunItems.SLIME_LEGGINGS_STEEL, SlimefunItems.SLIME_BOOTS_STEEL);
register("blade_of_vampires", 94, "Blade of Vampires", 26, SlimefunItems.BLADE_OF_VAMPIRES);
Slimefun.registerResearch(new NamespacedKey(SlimefunPlugin.instance, "digital_miner"), 95, "Lazy Mining", 40, SlimefunItems.DIGITAL_MINER);
register("digital_miner", 95, "Lazy Mining", 40, SlimefunItems.DIGITAL_MINER);
register("water_staff", 96, "Water Staff", 8, SlimefunItems.STAFF_WATER);
register("24k_gold_block", 97, "Golden City", 19, SlimefunItems.GOLD_24K_BLOCK);
Slimefun.registerResearch(new NamespacedKey(SlimefunPlugin.instance, "advanced_digital_miner"), 98, "Advanced Mining 101", 42, SlimefunItems.ADVANCED_DIGITAL_MINER);
register("advanced_digital_miner", 98, "Advanced Mining 101", 42, SlimefunItems.ADVANCED_DIGITAL_MINER);
register("composter", 99, "Composting Dirt", 3, SlimefunItems.COMPOSTER);
register("farmer_shoes", 100, "Farmer Shoes", 4, SlimefunItems.FARMER_SHOES);
register("explosive_tools", 101, "Explosive Tools", 30, SlimefunItems.EXPLOSIVE_PICKAXE, SlimefunItems.EXPLOSIVE_SHOVEL);

View File

@ -41,6 +41,9 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.androids.Programm
import io.github.thebusybiscuit.slimefun4.implementation.items.androids.WoodcutterAndroid;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.Parachute;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.RestoredBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SoulboundBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.BlockPlacer;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.Composter;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.Crucible;
@ -49,6 +52,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramPr
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.InfusedHopper;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RainbowBlock;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RepairedSpawner;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.UnplaceableBlock;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.WitherProofBlock;
import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.AdvancedCargoOutputNode;
import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.CargoConnectorNode;
@ -125,7 +129,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedMa
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.KnowledgeFlask;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.KnowledgeTome;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.MagicEyeOfEnder;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundRune;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.StormStaff;
@ -166,7 +169,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.tools.PickaxeOfTh
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.PickaxeOfVeinMining;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.PortableCrafter;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.PortableDustbin;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SmeltersPickaxe;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.ExplosiveBow;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.IcyBow;
@ -374,7 +376,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {null, null, null, null, new CustomItem(SkullItem.fromBase64("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19"), "&aIron Golem"), null, null, null, null})
.register(plugin);
new SlimefunItem(categories.technicalComponents, (SlimefunItemStack) SlimefunItems.ADVANCED_CIRCUIT_BOARD, RecipeType.ENHANCED_CRAFTING_TABLE,
new UnplaceableBlock(categories.technicalComponents, (SlimefunItemStack) SlimefunItems.ADVANCED_CIRCUIT_BOARD, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {new ItemStack(Material.LAPIS_BLOCK), new ItemStack(Material.LAPIS_BLOCK), new ItemStack(Material.LAPIS_BLOCK), new ItemStack(Material.REDSTONE_BLOCK), SlimefunItems.BASIC_CIRCUIT_BOARD, new ItemStack(Material.REDSTONE_BLOCK), new ItemStack(Material.LAPIS_BLOCK), new ItemStack(Material.LAPIS_BLOCK), new ItemStack(Material.LAPIS_BLOCK)})
.register(plugin);
@ -565,7 +567,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {new ItemStack(Material.NETHERRACK, 16), null, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, (SlimefunItemStack) SlimefunItems.CARBON, RecipeType.COMPRESSOR,
new UnplaceableBlock(categories.resources, (SlimefunItemStack) SlimefunItems.CARBON, RecipeType.COMPRESSOR,
new ItemStack[] {new ItemStack(Material.COAL, 8), null, null, null, null, null, null, null, null})
.register(plugin);
@ -577,11 +579,11 @@ public final class SlimefunItemSetup {
new ItemStack[] {new CustomItem(SlimefunItems.STEEL_INGOT, 8), null, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, (SlimefunItemStack) SlimefunItems.COMPRESSED_CARBON, RecipeType.COMPRESSOR,
new UnplaceableBlock(categories.resources, (SlimefunItemStack) SlimefunItems.COMPRESSED_CARBON, RecipeType.COMPRESSOR,
new ItemStack[] {new CustomItem(SlimefunItems.CARBON, 4), null, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, (SlimefunItemStack) SlimefunItems.CARBON_CHUNK, RecipeType.ENHANCED_CRAFTING_TABLE,
new UnplaceableBlock(categories.resources, (SlimefunItemStack) SlimefunItems.CARBON_CHUNK, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {SlimefunItems.COMPRESSED_CARBON, SlimefunItems.COMPRESSED_CARBON, SlimefunItems.COMPRESSED_CARBON, SlimefunItems.COMPRESSED_CARBON, new ItemStack(Material.FLINT), SlimefunItems.COMPRESSED_CARBON, SlimefunItems.COMPRESSED_CARBON, SlimefunItems.COMPRESSED_CARBON, SlimefunItems.COMPRESSED_CARBON})
.register(plugin);
@ -763,7 +765,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.SOLAR_PANEL, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.REINFORCED_ALLOY_INGOT, null, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.MEDIUM_CAPACITOR, null, SlimefunItems.MEDIUM_CAPACITOR})
.register(plugin);
new SlimefunItem(categories.magicalResources, (SlimefunItemStack) SlimefunItems.LAVA_CRYSTAL, RecipeType.ENHANCED_CRAFTING_TABLE,
new UnplaceableBlock(categories.magicalResources, (SlimefunItemStack) SlimefunItems.LAVA_CRYSTAL, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.RUNE_FIRE, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.MAGIC_LUMP_1, new ItemStack(Material.BLAZE_POWDER), SlimefunItems.MAGIC_LUMP_1})
.register(plugin);
@ -917,7 +919,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.PULVERIZED_ORE, null, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.misc, (SlimefunItemStack) SlimefunItems.TINY_URANIUM, RecipeType.ORE_CRUSHER,
new UnplaceableBlock(categories.misc, (SlimefunItemStack) SlimefunItems.TINY_URANIUM, RecipeType.ORE_CRUSHER,
new ItemStack[] {SlimefunItems.PURE_ORE_CLUSTER, null, null, null, null, null, null, null, null})
.register(plugin);
@ -1201,6 +1203,8 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.GOLD_24K, null, SlimefunItems.GOLD_24K, new ItemStack(Material.LEATHER), SlimefunItems.GILDED_BACKPACK, new ItemStack(Material.LEATHER), SlimefunItems.GOLD_24K, null, SlimefunItems.GOLD_24K})
.register(plugin);
new RestoredBackpack(categories.usefulItems).register(plugin);
new SlimefunItem(categories.technicalComponents, (SlimefunItemStack) SlimefunItems.MAGNET, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.NICKEL_INGOT, SlimefunItems.ALUMINUM_DUST, SlimefunItems.IRON_DUST, SlimefunItems.COBALT_INGOT, null, null, null, null, null})
.register(plugin);
@ -1221,7 +1225,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.ENDER_LUMP_3, SlimefunItems.RUNE_AIR, SlimefunItems.ENDER_LUMP_3, SlimefunItems.RUNE_EARTH, SlimefunItems.NECROTIC_SKULL, SlimefunItems.RUNE_FIRE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.RUNE_WATER, SlimefunItems.ENDER_LUMP_3})
.register(plugin);
new SoulboundBackpack(36, categories.usefulItems, SlimefunItems.BOUND_BACKPACK,
new SoulboundBackpack(36, categories.usefulItems, SlimefunItems.BOUND_BACKPACK, RecipeType.MAGIC_WORKBENCH,
new ItemStack[] {SlimefunItems.ENDER_LUMP_2, null, SlimefunItems.ENDER_LUMP_2, SlimefunItems.ESSENCE_OF_AFTERLIFE, SlimefunItems.WOVEN_BACKPACK, SlimefunItems.ESSENCE_OF_AFTERLIFE, SlimefunItems.ENDER_LUMP_2, null, SlimefunItems.ENDER_LUMP_2})
.register(plugin);
@ -1345,7 +1349,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {new ItemStack(Material.GOLDEN_APPLE), null, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.magicalResources, (SlimefunItemStack) SlimefunItems.BROKEN_SPAWNER, new RecipeType(new NamespacedKey(plugin, "pickaxe_of_containment"), SlimefunItems.PICKAXE_OF_CONTAINMENT),
new UnplaceableBlock(categories.magicalResources, (SlimefunItemStack) SlimefunItems.BROKEN_SPAWNER, new RecipeType(new NamespacedKey(plugin, "pickaxe_of_containment"), SlimefunItems.PICKAXE_OF_CONTAINMENT),
new ItemStack[] {null, null, null, null, new ItemStack(Material.SPAWNER), null, null, null, null})
.register(plugin);
@ -2207,7 +2211,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {null, null, null, null, SlimefunItems.BUCKET_OF_OIL, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.technicalComponents, (SlimefunItemStack) SlimefunItems.ANDROID_MEMORY_CORE, RecipeType.ENHANCED_CRAFTING_TABLE,
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.ANDROID_MEMORY_CORE, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {SlimefunItems.BRASS_INGOT, new ItemStack(Material.ORANGE_STAINED_GLASS), SlimefunItems.BRASS_INGOT, SlimefunItems.POWER_CRYSTAL, SlimefunItems.TIN_DUST, SlimefunItems.POWER_CRYSTAL, SlimefunItems.BRASS_INGOT, new ItemStack(Material.ORANGE_STAINED_GLASS), SlimefunItems.BRASS_INGOT})
.register(plugin);

View File

@ -39,6 +39,8 @@ public class JetpackTask extends PlayerTask {
p.setVelocity(vector);
}
else Bukkit.getScheduler().cancelTask(id);
else {
Bukkit.getScheduler().cancelTask(id);
}
}
}

View File

@ -62,7 +62,7 @@ public class SlimefunStartupTask implements Runnable {
}
if (isEnabled("ENERGY_REGULATOR", "CARGO_MANAGER")) {
new NetworkListener(plugin);
new NetworkListener(plugin, SlimefunPlugin.getNetworkManager());
}
}

View File

@ -1,17 +1,23 @@
package io.github.thebusybiscuit.slimefun4.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Item;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import io.github.thebusybiscuit.cscorelib2.item.ImmutableItemMeta;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound;
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal;
import me.mrCookieSlime.EmeraldEnchants.EmeraldEnchants;
@ -33,9 +39,11 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public final class SlimefunUtils {
private static final String EMERALDENCHANTS_LORE = ChatColor.YELLOW.toString() + ChatColor.YELLOW.toString() + ChatColor.GRAY.toString();
private static final String SOULBOUND_LORE = ChatColor.GRAY + "Soulbound";
private static final String NO_PICKUP_METADATA = "no_pickup";
private static final NamespacedKey SOULBOUND_KEY = new NamespacedKey(SlimefunPlugin.instance, "soulbound");
private static final String SOULBOUND_LORE = ChatColor.GRAY + "Soulbound";
private SlimefunUtils() {}
/**
@ -75,33 +83,96 @@ public final class SlimefunUtils {
return false;
}
else {
SlimefunItem backpack = SlimefunItems.BOUND_BACKPACK.getItem();
ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : null;
if (backpack != null && backpack.isItem(item)) {
return !backpack.isDisabled();
}
else {
ItemStack strippedItem = item.clone();
if (meta != null && SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
PersistentDataContainer container = meta.getPersistentDataContainer();
if (SlimefunPlugin.getThirdPartySupportService().isEmeraldEnchantsInstalled()) {
for (ItemEnchantment enchantment : EmeraldEnchants.getInstance().getRegistry().getEnchantments(item)) {
EmeraldEnchants.getInstance().getRegistry().applyEnchantment(strippedItem, enchantment.getEnchantment(), 0);
}
}
SlimefunItem sfItem = SlimefunItem.getByItem(strippedItem);
if (sfItem instanceof Soulbound && !sfItem.isDisabled()) {
if (container.has(SOULBOUND_KEY, PersistentDataType.BYTE)) {
return true;
}
else if (item.hasItemMeta()) {
ItemMeta im = item.getItemMeta();
return (im.hasLore() && im.getLore().contains(SOULBOUND_LORE));
}
}
return false;
if (SlimefunPlugin.getThirdPartySupportService().isEmeraldEnchantsInstalled()) {
// We wanna operate on a copy now
item = item.clone();
for (ItemEnchantment enchantment : EmeraldEnchants.getInstance().getRegistry().getEnchantments(item)) {
EmeraldEnchants.getInstance().getRegistry().applyEnchantment(item, enchantment.getEnchantment(), 0);
}
}
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem instanceof Soulbound) {
return !sfItem.isDisabled();
}
else if (meta != null) {
return meta.hasLore() && meta.getLore().contains(SOULBOUND_LORE);
}
return false;
}
}
/**
* Toggles an {@link ItemStack} to be Soulbound.<br>
* If true is passed, this will add the {@link #SOULBOUND_LORE} and
* add a {@link NamespacedKey} to the item so it can be quickly identified
* by {@link #isSoulbound(ItemStack)}.<br>
* If false is passed, this property will be removed.
*
* @param item
* The {@link ItemStack} you want to add/remove Soulbound from.
* @param makeSoulbound
* If they item should be soulbound.
*
* @see #isSoulbound(ItemStack)
*/
public static void setSoulbound(ItemStack item, boolean makeSoulbound) {
if (item == null || item.getType() == Material.AIR) {
throw new IllegalArgumentException("A soulbound item cannot be null or air!");
}
boolean isSoulbound = isSoulbound(item);
ItemMeta meta = item.getItemMeta();
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) {
PersistentDataContainer container = meta.getPersistentDataContainer();
if (makeSoulbound && !isSoulbound) {
container.set(SOULBOUND_KEY, PersistentDataType.BYTE, (byte) 1);
}
if (!makeSoulbound && isSoulbound) {
container.remove(SOULBOUND_KEY);
}
}
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
if (makeSoulbound && !isSoulbound) {
lore.add(SOULBOUND_LORE);
}
if (!makeSoulbound && isSoulbound) {
lore.remove(SOULBOUND_LORE);
}
meta.setLore(lore);
item.setItemMeta(meta);
}
/**
* This method checks whether the given {@link ItemStack} is radioactive.
*
* @param item
* The {@link ItemStack} to check
*
* @return Whether this {@link ItemStack} is radioactive or not
*/
public static boolean isRadioactive(ItemStack item) {
return SlimefunItem.getByItem(item) instanceof Radioactive;
}
public static boolean containsSimilarItem(Inventory inventory, ItemStack itemStack, boolean checkLore) {

View File

@ -21,7 +21,8 @@ public final class ItemStackWrapper extends ItemStack {
private ItemMeta meta;
public ItemStackWrapper(ItemStack item) {
super(item);
super(item.getType());
meta = item.getItemMeta();
}
@Override
@ -30,10 +31,6 @@ public final class ItemStackWrapper extends ItemStack {
// Since this class is immutable, we can simply let the super class create one copy
// and then store that instead of creating a clone everytime.
// This will significantly speed up any loop comparisons if used correctly.
if (meta == null) {
meta = super.getItemMeta();
}
return meta;
}
@ -44,7 +41,7 @@ public final class ItemStackWrapper extends ItemStack {
@Override
public boolean equals(Object obj) {
throw new UnsupportedOperationException("ItemStackWrapper do not allow .equals()");
throw new UnsupportedOperationException("ItemStackWrappers do not allow .equals()");
}
@Override

View File

@ -12,7 +12,6 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.skull.SkullItem;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.core.attributes.MachineTier;
import io.github.thebusybiscuit.slimefun4.core.attributes.MachineType;
@ -73,6 +72,8 @@ public final class SlimefunItems {
public static final ItemStack RADIANT_BACKPACK = new SlimefunItemStack("RADIANT_BACKPACK", "40cb1e67b512ab2d4bf3d7ace0eaaf61c32cd4681ddc3987ceb326706a33fa", "&eRadiant Backpack", "", "&7Size: &e54 (Double chest)", "&7ID: <ID>", "", "&7&eRight Click&7 to open");
public static final SlimefunItemStack BOUND_BACKPACK = new SlimefunItemStack("BOUND_BACKPACK", "2a3b34862b9afb63cf8d5779966d3fba70af82b04e83f3eaf6449aeba", "&cSoulbound Backpack", "", "&7Size: &e36", "&7ID: <ID>", "", "&7&eRight Click&7 to open");
public static final SlimefunItemStack COOLER = new SlimefunItemStack("COOLER", "d4c1572584eb5de229de9f5a4f779d0aacbaffd33bcb33eb4536a6a2bc6a1", "&bCooler", "&rAllows you to store Juices/Smoothies", "&rand automatically consumes them when you are hungry", "&rand you have this in your Inventory", "", "&7Size: &e27", "&7ID: <ID>", "", "&7&eRight Click&7 to open");
public static final SlimefunItemStack RESTORED_BACKPACK = new SlimefunItemStack("RESTORED_BACKPACK", "40cb1e67b512ab2d4bf3d7ace0eaaf61c32cd4681ddc3987ceb326706a33fa", "&eRestored Backpack", "", "&7Retrieve your lost items", "&7ID: <ID>", "", "&7&eRight Click&7 to open");
/* Jetpacks */
public static final SlimefunItemStack DURALUMIN_JETPACK = new SlimefunItemStack("DURALUMIN_JETPACK", Material.LEATHER_CHESTPLATE, Color.SILVER, "&9Electric Jetpack &7- &eI", "", "&8\u21E8 &7Material: &bDuralumin", "&c&o&8\u21E8 &e\u26A1 &70 / 20 J", "&8\u21E8 &7Thrust: &c0.35", "", "&7Hold &eShift&7 to use");
@ -660,7 +661,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack REFINERY = new SlimefunItemStack("REFINERY", Material.PISTON, "&cRefinery", "", "&rRefines Oil to create Fuel");
public static final SlimefunItemStack COMBUSTION_REACTOR = new SlimefunItemStack("COMBUSTION_REACTOR", "9343ce58da54c79924a2c9331cfc417fe8ccbbea9be45a7ac85860a6c730", "&cCombustion Reactor", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.GENERATOR), LoreBuilder.powerBuffer(256), LoreBuilder.powerPerSecond(24));
public static final ItemStack ANDROID_MEMORY_CORE = new SlimefunItemStack("ANDROID_MEMORY_CORE", "d78f2b7e5e75639ea7fb796c35d364c4df28b4243e66b76277aadcd6261337", "&bAndroid Memory Core");
public static final SlimefunItemStack ANDROID_MEMORY_CORE = new SlimefunItemStack("ANDROID_MEMORY_CORE", "d78f2b7e5e75639ea7fb796c35d364c4df28b4243e66b76277aadcd6261337", "&bAndroid Memory Core");
public static final SlimefunItemStack GPS_TELEPORTER_PYLON = new SlimefunItemStack("GPS_TELEPORTER_PYLON", Material.PURPLE_STAINED_GLASS, "&5GPS Teleporter Pylon", "", "&7Teleporter Component");
public static final SlimefunItemStack GPS_TELEPORTATION_MATRIX = new SlimefunItemStack("GPS_TELEPORTATION_MATRIX", Material.IRON_BLOCK, "&bGPS Teleporter Matrix", "", "&rThis is your Teleporter's Main Component", "&rThis Matrix allows Players to choose from all", "&rWaypoints made by the Player who has placed", "&rthis Device.");
@ -710,27 +711,27 @@ public final class SlimefunItems {
public static final SlimefunItemStack AUTO_BREEDER = new SlimefunItemStack("AUTO_BREEDER", Material.HAY_BLOCK, "&eAuto-Breeder", "", "&rRuns on &aOrganic Food", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), LoreBuilder.powerBuffer(1024), "&8\u21E8 &e\u26A1 &760 J/Animal");
public static final ItemStack ORGANIC_FOOD = new CustomItem(SkullItem.fromBase64("b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79"), "&aOrganic Food", "&7Content: &9X");
public static final SlimefunItemStack WHEAT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_WHEAT", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Wheat");
public static final SlimefunItemStack CARROT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_CARROT", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Carrots");
public static final SlimefunItemStack POTATO_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_POTATO", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Potatoes");
public static final SlimefunItemStack SEEDS_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_SEEDS", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Seeds");
public static final SlimefunItemStack BEETROOT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_BEETROOT", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Beetroot");
public static final SlimefunItemStack MELON_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_MELON", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Melon");
public static final SlimefunItemStack APPLE_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_APPLE", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Apple");
public static final SlimefunItemStack SWEET_BERRIES_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_SWEET_BERRIES", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Sweet Berries");
public static final SlimefunItemStack KELP_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_KELP", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9Dried Kelp");
public static final SlimefunItemStack ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Food", "&7Content: &9???");
public static final SlimefunItemStack WHEAT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_WHEAT", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Wheat");
public static final SlimefunItemStack CARROT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_CARROT", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Carrots");
public static final SlimefunItemStack POTATO_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_POTATO", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Potatoes");
public static final SlimefunItemStack SEEDS_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_SEEDS", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Seeds");
public static final SlimefunItemStack BEETROOT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_BEETROOT", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Beetroot");
public static final SlimefunItemStack MELON_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_MELON", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Melon");
public static final SlimefunItemStack APPLE_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_APPLE", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Apple");
public static final SlimefunItemStack SWEET_BERRIES_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_SWEET_BERRIES", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Sweet Berries");
public static final SlimefunItemStack KELP_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_KELP", ORGANIC_FOOD, "&aOrganic Food", "&7Content: &9Dried Kelp");
public static final ItemStack FERTILIZER = new CustomItem(SkullItem.fromBase64("b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79"), "&aOrganic Fertilizer", "&7Content: &9X");
public static final SlimefunItemStack WHEAT_FERTILIZER = new SlimefunItemStack("FERTILIZER_WHEAT", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Wheat");
public static final SlimefunItemStack CARROT_FERTILIZER = new SlimefunItemStack("FERTILIZER_CARROT", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Carrots");
public static final SlimefunItemStack POTATO_FERTILIZER = new SlimefunItemStack("FERTILIZER_POTATO", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Potatoes");
public static final SlimefunItemStack SEEDS_FERTILIZER = new SlimefunItemStack("FERTILIZER_SEEDS", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Seeds");
public static final SlimefunItemStack BEETROOT_FERTILIZER = new SlimefunItemStack("FERTILIZER_BEETROOT", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Beetroot");
public static final SlimefunItemStack MELON_FERTILIZER = new SlimefunItemStack("FERTILIZER_MELON", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Melon");
public static final SlimefunItemStack APPLE_FERTILIZER = new SlimefunItemStack("FERTILIZER_APPLE", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Apple");
public static final SlimefunItemStack SWEET_BERRIES_FERTILIZER = new SlimefunItemStack("FERTILIZER_SWEET_BERRIES", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Sweet Berries");
public static final SlimefunItemStack KELP_FERTILIZER = new SlimefunItemStack("FERTILIZER_KELP", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9Dried Kelp");
public static final SlimefunItemStack FERTILIZER = new SlimefunItemStack("FERTILIZER", "b439e3f5acbee9be4c4259289d6d9f35c635ffa661114687b3ea6dda8c79", "&aOrganic Fertilizer", "&7Content: &9???");
public static final SlimefunItemStack WHEAT_FERTILIZER = new SlimefunItemStack("FERTILIZER_WHEAT", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Wheat");
public static final SlimefunItemStack CARROT_FERTILIZER = new SlimefunItemStack("FERTILIZER_CARROT", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Carrots");
public static final SlimefunItemStack POTATO_FERTILIZER = new SlimefunItemStack("FERTILIZER_POTATO", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Potatoes");
public static final SlimefunItemStack SEEDS_FERTILIZER = new SlimefunItemStack("FERTILIZER_SEEDS", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Seeds");
public static final SlimefunItemStack BEETROOT_FERTILIZER = new SlimefunItemStack("FERTILIZER_BEETROOT", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Beetroot");
public static final SlimefunItemStack MELON_FERTILIZER = new SlimefunItemStack("FERTILIZER_MELON", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Melon");
public static final SlimefunItemStack APPLE_FERTILIZER = new SlimefunItemStack("FERTILIZER_APPLE", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Apple");
public static final SlimefunItemStack SWEET_BERRIES_FERTILIZER = new SlimefunItemStack("FERTILIZER_SWEET_BERRIES", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Sweet Berries");
public static final SlimefunItemStack KELP_FERTILIZER = new SlimefunItemStack("FERTILIZER_KELP", FERTILIZER, "&aOrganic Fertilizer", "&7Content: &9Dried Kelp");
public static final SlimefunItemStack ANIMAL_GROWTH_ACCELERATOR = new SlimefunItemStack("ANIMAL_GROWTH_ACCELERATOR", Material.HAY_BLOCK, "&bAnimal Growth Accelerator", "", "&rRuns on &aOrganic Food", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), LoreBuilder.powerBuffer(1024), LoreBuilder.powerPerSecond(28));
public static final SlimefunItemStack CROP_GROWTH_ACCELERATOR = new SlimefunItemStack("CROP_GROWTH_ACCELERATOR", Material.LIME_TERRACOTTA, "&aCrop Growth Accelerator", "", "&rRuns on &aOrganic Fertilizer", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), "&8\u21E8 &7Radius: 7x7", "&8\u21E8 &7Speed: &a3/time", LoreBuilder.powerBuffer(1024), LoreBuilder.powerPerSecond(50));

View File

@ -6,6 +6,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
@ -15,6 +16,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
@ -64,6 +66,9 @@ public class Category implements Keyed {
* the {@link SlimefunGuide}
*/
public Category(NamespacedKey key, ItemStack item, int tier) {
Validate.notNull(key, "A Category's NamespacedKey must not be null!");
Validate.notNull(item, "A Category's ItemStack must not be null!");
this.item = item;
this.key = key;
@ -96,6 +101,13 @@ public class Category implements Keyed {
* the {@link SlimefunItem} that should be added to this {@link Category}
*/
public void add(SlimefunItem item) {
Validate.notNull(item, "Cannot add null Items to a Category!");
if (items.contains(item)) {
// Ignore duplicate entries
return;
}
items.add(item);
}
@ -152,6 +164,18 @@ public class Category implements Keyed {
return items;
}
/**
* This method returns whether a given {@link SlimefunItem} exists in this {@link Category}.
*
* @param item
* The {@link SlimefunItem} to find
*
* @return Whether the given {@link SlimefunItem} was found in this {@link Category}
*/
public boolean contains(SlimefunItem item) {
return item != null && items.contains(item);
}
/**
* Returns the tier of this {@link Category}.
* The tier determines the position of this {@link Category} in the {@link SlimefunGuide}.

View File

@ -1,159 +1,20 @@
package me.mrCookieSlime.Slimefun.Objects;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
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.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
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
* are fully unlocked.
* <p>
* See {@link Category} for the complete documentation.
*
* @author TheBusyBiscuit
*
* @see Category
* @see SeasonalCategory
* @deprecated Moved to io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory
*
*/
public class LockedCategory extends Category {
@Deprecated
public class LockedCategory extends io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory {
private final NamespacedKey[] keys;
private final Set<Category> parents = new HashSet<>();
/**
* The basic constructor for a LockedCategory.
* Like {@link Category}, the default tier is automatically set to 3.
*
* @param key
* A unique identifier for this category
* @param item
* The display item for this category
* @param parents
* The parent categories for this category
*
*/
public LockedCategory(NamespacedKey key, ItemStack item, NamespacedKey... parents) {
this(key, item, 3, parents);
}
/**
* The constructor for a LockedCategory.
*
* @param key
* A unique identifier for this category
* @param item
* The display item for this category
* @param tier
* The tier of this category
* @param parents
* The parent categories for this category
*
*/
public LockedCategory(NamespacedKey key, ItemStack item, int tier, NamespacedKey... parents) {
super(key, item, tier);
Validate.noNullElements(parents, "A LockedCategory must not have any 'null' parents!");
this.keys = parents;
}
@Override
public void register() {
super.register();
List<NamespacedKey> namespacedKeys = new ArrayList<>();
for (NamespacedKey key : keys) {
if (key != null) {
namespacedKeys.add(key);
}
}
for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
if (namespacedKeys.remove(category.getKey())) {
addParent(category);
}
}
for (NamespacedKey key : namespacedKeys) {
Slimefun.getLogger().log(Level.INFO, "Parent \"{0}\" for Category \"{1}\" was not found, probably just disabled.", new Object[] { key, getKey() });
}
}
/**
* Gets the list of parent categories for this {@link LockedCategory}.
*
* @return the list of parent categories
*
* @see #addParent(Category)
* @see #removeParent(Category)
*/
public Set<Category> getParents() {
return parents;
}
/**
* Adds a parent {@link Category} to this {@link LockedCategory}.
*
* @param category
* The {@link Category} to add as a parent
*
* @see #getParents()
* @see #removeParent(Category)
*/
public void addParent(Category category) {
if (category == this || category == null) {
throw new IllegalArgumentException("Category '" + item.getItemMeta().getDisplayName() + "' cannot be a parent of itself or have a 'null' parent.");
}
parents.add(category);
}
/**
* Removes a {@link Category} from the parents of this {@link LockedCategory}.
*
* @param category
* The {@link Category} to remove from the parents of this {@link LockedCategory}
*
* @see #getParents()
* @see #addParent(Category)
*/
public void removeParent(Category category) {
parents.remove(category);
}
/**
* Checks if the {@link Player} has fully unlocked all parent categories.
*
* @param p
* The {@link Player} to check
* @param profile
* The {@link PlayerProfile} that belongs to the given {@link Player}
* @return Whether the {@link Player} has fully completed all parent categories, otherwise false
*/
public boolean hasUnlocked(Player p, PlayerProfile profile) {
for (Category category : parents) {
for (SlimefunItem item : category.getItems()) {
// Should we replace this all with Slimefun.hasUnlocked() ?
if (Slimefun.isEnabled(p, item, false) && Slimefun.hasPermission(p, item, false) && item.getResearch() != null && !profile.hasUnlocked(item.getResearch())) {
return false;
}
}
}
return true;
super(key, item, tier, parents);
}
}

View File

@ -1,296 +1,15 @@
package me.mrCookieSlime.Slimefun.Objects;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.api.events.ResearchUnlockEvent;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup;
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* Represents a research, which is bound to one
* {@link SlimefunItem} or more and requires XP levels to unlock said item(s).
*
* @author TheBusyBiscuit
*
* @see ResearchSetup
* @see ResearchUnlockEvent
* @deprecated Moved to io.github.thebusybiscuit.slimefun4.core.researching.Research
*
*/
public class Research implements Keyed {
@Deprecated
public class Research extends io.github.thebusybiscuit.slimefun4.core.researching.Research {
private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 };
private final NamespacedKey key;
private final int id;
private String name;
private boolean enabled = true;
private int cost;
private final List<SlimefunItem> items = new LinkedList<>();
/**
* The constructor for a {@link Research}.
*
* Create a new research, then bind this research to the Slimefun items you want by calling
* {@link #addItems(SlimefunItem...)}. Once you're finished, call {@link #register()}
* to register it.
*
* To speed up, directly setup the research by calling
* {@link Slimefun#registerResearch(Research, org.bukkit.inventory.ItemStack...)}.
*
* @param key
* A unique identifier for this {@link Research}
* @param id
* old way of identifying researches
* @param name
* The displayed name of this {@link Research}
* @param defaultCost
* The Cost in XP levels to unlock this {@link Research}
*
*/
public Research(NamespacedKey key, int id, String name, int defaultCost) {
this.key = key;
this.id = id;
this.name = name;
this.cost = defaultCost;
}
@Override
public NamespacedKey getKey() {
return key;
}
/**
* This method returns whether this {@link Research} is enabled.
* {@code false} can mean that this particular {@link Research} was disabled or that
* researches alltogether have been disabled.
*
* @return Whether this {@link Research} is enabled or not
*/
public boolean isEnabled() {
return SlimefunPlugin.getRegistry().isResearchingEnabled() && enabled;
}
/**
* Gets the ID of this {@link Research}.
* This is the old way of identifying Researches, use a {@link NamespacedKey} in the future.
*
* @return The ID of this {@link Research}
*/
public int getID() {
return id;
}
/**
* This method gives you a localized name for this {@link Research}.
* The name is automatically taken from the currently selected {@link Language} of
* the specified {@link Player}.
*
* @param p
* The {@link Player} to translate this name for.
* @return The localized Name of this {@link Research}.
*/
public String getName(Player p) {
String localized = SlimefunPlugin.getLocal().getResearchName(p, key);
return localized != null ? localized : name;
}
/**
* Gets the cost in XP levels to unlock this {@link Research}.
*
* @return The cost in XP levels for this {@link Research}
*/
public int getCost() {
return cost;
}
/**
* Sets the cost in XP levels to unlock this {@link Research}.
*
* @param cost
* The cost in XP levels
*/
public void setCost(int cost) {
this.cost = cost;
}
/**
* Bind the specified Slimefun items to this {@link Research}.
*
* @param items
* Instances of {@link SlimefunItem} to bind to this {@link Research}
*/
public void addItems(SlimefunItem... items) {
for (SlimefunItem item : items) {
if (item != null) {
item.setResearch(this);
}
}
}
/**
* Lists every {@link SlimefunItem} that is bound to this {@link Research}.
*
* @return The Slimefun items bound to this {@link Research}.
*/
public List<SlimefunItem> getAffectedItems() {
return items;
}
/**
* Checks if the {@link Player} can unlock this {@link Research}.
*
* @param p
* The {@link Player} to check
* @return Whether that {@link Player} can unlock this {@link Research}
*/
public boolean canUnlock(Player p) {
if (!isEnabled()) {
return true;
}
boolean creativeResearch = p.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled();
return creativeResearch || p.getLevel() >= cost;
}
/**
* Unlocks this {@link Research} for the specified {@link Player}.
*
* @param p
* The {@link Player} for which to unlock this {@link Research}
* @param instant
* Whether to unlock the research instantly
*/
public void unlock(Player p, boolean instant) {
if (!instant) {
Slimefun.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace("%research%", getName(p)).replace("%progress%", "0%"));
}, 10L);
}
PlayerProfile.get(p, profile -> {
if (!profile.hasUnlocked(this)) {
Runnable runnable = () -> {
profile.setResearched(this, true);
SlimefunPlugin.getLocal().sendMessage(p, "messages.unlocked", true, msg -> msg.replace("%research%", getName(p)));
if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) {
FireworkUtils.launchRandom(p, 1);
}
};
Slimefun.runSync(() -> {
ResearchUnlockEvent event = new ResearchUnlockEvent(p, this);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (instant) {
runnable.run();
}
else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.research.start", true, msg -> msg.replace("%research%", getName(p)));
playResearchAnimation(p);
Slimefun.runSync(() -> {
runnable.run();
SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId());
}, (RESEARCH_PROGRESS.length + 1) * 20L);
}
}
});
}
});
}
private void playResearchAnimation(Player p) {
for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) {
int j = i;
Slimefun.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace("%research%", getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%"));
}, i * 20L);
}
}
/**
* Registers this {@link Research}.
*/
public void register() {
SlimefunPlugin.getResearchCfg().setDefaultValue("enable-researching", true);
String path = key.getNamespace() + '.' + key.getKey();
migrate(id, path);
if (SlimefunPlugin.getResearchCfg().contains(path + ".enabled") && !SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled")) {
for (SlimefunItem item : new ArrayList<>(items)) {
if (item != null) {
item.setResearch(null);
}
}
return;
}
SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".cost", this.getCost());
SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".enabled", true);
this.cost = SlimefunPlugin.getResearchCfg().getInt(path + ".cost");
this.enabled = SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled");
SlimefunPlugin.getRegistry().getResearches().add(this);
SlimefunPlugin.getRegistry().getResearchIds().add(this);
}
// Temporary migration method from ids to Namespaced Keys.
private void migrate(int id, String path) {
if (SlimefunPlugin.getResearchCfg().contains(id + ".enabled")) {
SlimefunPlugin.getResearchCfg().setValue(path + ".enabled", SlimefunPlugin.getResearchCfg().getBoolean(id + ".enabled"));
}
if (SlimefunPlugin.getResearchCfg().contains(id + ".cost")) {
SlimefunPlugin.getResearchCfg().setValue(path + ".cost", SlimefunPlugin.getResearchCfg().getInt(id + ".cost"));
}
SlimefunPlugin.getResearchCfg().setValue(String.valueOf(id), null);
}
/**
* Attempts to get a {@link Research} with the given ID.
*
* We will use {@link NamespacedKey} for this in the future.
*
* @param id
* ID of the research to get
* @return {@link Research} if found, or null
*/
public static Research getByID(int id) {
for (Research research : SlimefunPlugin.getRegistry().getResearches()) {
if (research.getID() == id) {
return research;
}
}
return null;
}
@Override
public String toString() {
return "Research (" + getKey() + ')';
public Research(NamespacedKey key, int id, String name, int cost) {
super(key, id, name, cost);
}
}

View File

@ -28,17 +28,16 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoEnchanter;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.Objects.handlers.GeneratorTicker;
@ -129,7 +128,7 @@ public class SlimefunItem implements Placeable {
*
* @return the identifier of this {@link SlimefunItem}
*/
public String getID() {
public final String getID() {
return id;
}
@ -276,15 +275,6 @@ public class SlimefunItem implements Placeable {
}
}
/**
* This method returns whether this {@link SlimefunItem} was added by an addon.
*
* @return Whether this {@link SlimefunItem} was added by an addon.
*/
public final boolean isAddonItem() {
return !(addon instanceof SlimefunPlugin);
}
/**
* This method returns whether this {@link SlimefunItem} is disabled.
*
@ -457,8 +447,8 @@ public class SlimefunItem implements Placeable {
}
public void setRecipe(ItemStack[] recipe) {
if (recipe == null || recipe.length < 9) {
throw new IllegalArgumentException("Cannot set a recipe shorter than 9 elements.");
if (recipe == null || recipe.length != 9) {
throw new IllegalArgumentException("Recipes must be of length 9");
}
this.recipe = recipe;
@ -539,9 +529,13 @@ public class SlimefunItem implements Placeable {
}
// Support for legacy items
if (this instanceof ChargableItem && SlimefunUtils.isItemSimilar(item, this.item, false)) return true;
else if (this instanceof SlimefunBackpack && SlimefunUtils.isItemSimilar(item, this.item, false)) return true;
else return SlimefunUtils.isItemSimilar(item, this.item, true);
if (this instanceof ChargableItem && SlimefunUtils.isItemSimilar(item, this.item, false)) {
return true;
}
else {
boolean loreInsensitive = this instanceof SlimefunBackpack || id.equals("BROKEN_SPAWNER") || id.equals("REINFORCED_SPAWNER");
return SlimefunUtils.isItemSimilar(item, this.item, !loreInsensitive);
}
}
/**
@ -568,6 +562,9 @@ public class SlimefunItem implements Placeable {
* Any {@link ItemHandler} that should be added to this {@link SlimefunItem}
*/
public final void addItemHandler(ItemHandler... handlers) {
Validate.notEmpty(handlers, "You cannot add zero handlers...");
Validate.noNullElements(handlers, "You cannot add any 'null' ItemHandler!");
if (state != ItemState.UNREGISTERED) {
throw new UnsupportedOperationException("You cannot add an ItemHandler after the SlimefunItem was registered.");
}
@ -595,6 +592,9 @@ public class SlimefunItem implements Placeable {
* Any {@link ItemSetting} that should be added to this {@link SlimefunItem}
*/
public final void addItemSetting(ItemSetting<?>... settings) {
Validate.notEmpty(settings, "You cannot add zero settings...");
Validate.noNullElements(settings, "You cannot add any 'null' ItemSettings!");
if (state != ItemState.UNREGISTERED) {
throw new UnsupportedOperationException("You cannot add an ItemSetting after the SlimefunItem was registered.");
}
@ -717,7 +717,12 @@ public class SlimefunItem implements Placeable {
@Override
public String toString() {
return getClass().getSimpleName() + " - '" + id + "' (" + addon.getName() + " v" + addon.getPluginVersion() + ')';
if (addon == null) {
return getClass().getSimpleName() + " - '" + id + "'";
}
else {
return getClass().getSimpleName() + " - '" + id + "' (" + addon.getName() + " v" + addon.getPluginVersion() + ')';
}
}
@Override
@ -794,14 +799,6 @@ public class SlimefunItem implements Placeable {
}
}
if (SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.BROKEN_SPAWNER, false)) {
return getByID("BROKEN_SPAWNER");
}
if (SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.REPAIRED_SPAWNER, false)) {
return getByID("REINFORCED_SPAWNER");
}
return null;
}

View File

@ -15,7 +15,9 @@ import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
@ -24,10 +26,10 @@ import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.gps.GPSNetwork;
import io.github.thebusybiscuit.slimefun4.api.network.NetworkManager;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.SlimefunRegistry;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.core.services.AutoSavingService;
import io.github.thebusybiscuit.slimefun4.core.services.BackupService;
import io.github.thebusybiscuit.slimefun4.core.services.BlockDataService;
@ -50,18 +52,19 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarL
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BlockListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BlockPhysicsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.CargoNodeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.CoolerListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.DeathpointListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.DebugFishListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.DispenserListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.EnhancedFurnaceListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MobDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ExplosionsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.FireworksListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.GadgetsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.GrapplingHookListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.IronGolemListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MobDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PlayerProfileListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SeismicAxeListener;
@ -103,6 +106,8 @@ import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
public static SlimefunPlugin instance;
private final boolean isTestEnvironment;
private MinecraftVersion minecraftVersion = MinecraftVersion.UNKNOWN;
private final SlimefunRegistry registry = new SlimefunRegistry();
@ -112,9 +117,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Services - Systems that fulfill certain tasks, treat them as a black box
private final CustomItemDataService itemDataService = new CustomItemDataService(this, "slimefun_item");
private final BlockDataService blockDataService = new BlockDataService(this, "slimefun_block");
private final CustomTextureService textureService = new CustomTextureService(this);
private final CustomTextureService textureService = new CustomTextureService(new Config(this, "item-models.yml"));
private final GitHubService gitHubService = new GitHubService("TheBusyBiscuit/Slimefun4");
private final UpdaterService updaterService = new UpdaterService(this, getFile());
private final UpdaterService updaterService = new UpdaterService(this, getDescription().getVersion(), getFile());
private final MetricsService metricsService = new MetricsService(this);
private final AutoSavingService autoSavingService = new AutoSavingService();
private final BackupService backupService = new BackupService();
@ -139,9 +144,24 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private final BackpackListener backpackListener = new BackpackListener();
private final SlimefunBowListener bowListener = new SlimefunBowListener();
public SlimefunPlugin() {
super();
isTestEnvironment = false;
}
public SlimefunPlugin(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
super(loader, description, dataFolder, file);
isTestEnvironment = true;
}
@Override
public void onEnable() {
if (getServer().getPluginManager().isPluginEnabled("CS-CoreLib")) {
if (isTestEnvironment) {
instance = this;
minecraftVersion = MinecraftVersion.UNIT_TEST;
local = new LocalizationService(this, "", null);
}
else if (getServer().getPluginManager().isPluginEnabled("CS-CoreLib")) {
long timestamp = System.nanoTime();
// We wanna ensure that the Server uses a compatible version of Minecraft
@ -162,7 +182,15 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Setting up Networks
gpsNetwork = new GPSNetwork();
networkManager = new NetworkManager(config.getInt("networks.max-size"));
int networkSize = config.getInt("networks.max-size");
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);
networkSize = 1;
}
networkManager = new NetworkManager(networkSize);
// Setting up bStats
metricsService.start();
@ -194,6 +222,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
new SlimefunItemListener(this);
new SlimefunItemConsumeListener(this);
new BlockPhysicsListener(this);
new CargoNodeListener(this);
new MultiBlockListener(this);
new GadgetsListener(this);
new DispenserListener(this);
@ -243,8 +272,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Initiating various Stuff and all Items with a slightly delay (0ms after the Server finished loading)
Slimefun.runSync(new SlimefunStartupTask(this, () -> {
protections = new ProtectionManager(getServer());
textureService.register(registry.getAllSlimefunItems());
permissionsService.register(registry.getAllSlimefunItems());
textureService.register(registry.getAllSlimefunItems(), true);
permissionsService.register(registry.getAllSlimefunItems(), true);
recipeService.refresh();
}), 0);
@ -339,7 +368,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
@Override
public void onDisable() {
// Slimefun never loaded successfully, so we don't even bother doing stuff here
if (instance == null) {
if (instance == null || isTestEnvironment) {
return;
}

View File

@ -1,5 +1,6 @@
package me.mrCookieSlime.Slimefun.api;
import java.util.Optional;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
@ -29,25 +30,15 @@ public final class Slimefun {
}
/**
* Registers this Research and automatically binds these ItemStacks to it.
* <p>
* This convenience method spares from doing the code below:
* Registers a research.
*
* <pre>
* {@code
* Research r = new Research(7, "Glowstone Armor", 3);
* r.addItems(SlimefunItem.getByItem(SlimefunItems.GLOWSTONE_HELMET),
* SlimefunItem.getByItem(SlimefunItems.GLOWSTONE_CHESTPLATE),
* SlimefunItem.getByItem(SlimefunItems.GLOWSTONE_LEGGINGS),
* SlimefunItem.getByItem(SlimefunItems.GLOWSTONE_BOOTS));
* r.register();
* }*
* </pre>
* @deprecated The Research class was moved, this method is no longer valid. Please use
* {@link io.github.thebusybiscuit.slimefun4.core.researching.Research#register()} instead.
*
* @param research
* the research to register, not null
* The research
* @param items
* the items to bind, not null
* The items
*/
@Deprecated
public static void registerResearch(Research research, ItemStack... items) {
@ -58,6 +49,23 @@ public final class Slimefun {
research.register();
}
/**
* Registers a research.
*
* @deprecated The Research class was moved, this method is no longer valid. Please use
* {@link io.github.thebusybiscuit.slimefun4.core.researching.Research#register()} instead.
*
* @param key
* The key
* @param id
* The id
* @param name
* The name
* @param cost
* The default cost
* @param items
* The items
*/
@Deprecated
public static void registerResearch(NamespacedKey key, int id, String name, int cost, ItemStack... items) {
registerResearch(new Research(key, id, name, cost), items);
@ -81,28 +89,11 @@ public final class Slimefun {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null) {
if (sfItem.getState() == ItemState.DISABLED) {
if (message) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-item", true);
}
return false;
}
if (isEnabled(p, item, message) && hasPermission(p, sfItem, message)) {
if (sfItem.getResearch() == null) return true;
else if (PlayerProfile.get(p).hasUnlocked(sfItem.getResearch())) return true;
else {
if (message && !(sfItem instanceof VanillaItem)) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.not-researched", true);
}
return false;
}
}
else return false;
return hasUnlocked(p, sfItem, message);
}
else {
return true;
}
else return true;
}
/**
@ -119,19 +110,33 @@ public final class Slimefun {
* <code>false</code> otherwise.
*/
public static boolean hasUnlocked(Player p, SlimefunItem sfItem, boolean message) {
if (sfItem.getState() == ItemState.VANILLA_FALLBACK) {
return true;
}
if (isEnabled(p, sfItem, message) && hasPermission(p, sfItem, message)) {
if (sfItem.getResearch() == null) {
return true;
}
else if (PlayerProfile.get(p).hasUnlocked(sfItem.getResearch())) {
return true;
}
else {
if (message && !(sfItem instanceof VanillaItem)) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.not-researched", true);
}
Optional<PlayerProfile> profile = PlayerProfile.find(p);
return false;
if (!profile.isPresent()) {
// We will return false since we cannot know the answer yet
// But we will schedule the Profile for loading.
PlayerProfile.request(p);
return false;
}
else if (profile.get().hasUnlocked(sfItem.getResearch())) {
return true;
}
else {
if (message && !(sfItem instanceof VanillaItem)) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.not-researched", true);
}
return false;
}
}
}

View File

@ -22,6 +22,7 @@ import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.item.ImmutableItemMeta;
import io.github.thebusybiscuit.cscorelib2.skull.SkullItem;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.exceptions.PrematureCodeException;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
@ -184,6 +185,10 @@ public class SlimefunItemStack extends CustomItem {
}
private static ItemStack getSkull(String id, String texture) {
if (SlimefunPlugin.getMinecraftVersion() == MinecraftVersion.UNIT_TEST) {
return new ItemStack(Material.PLAYER_HEAD);
}
return SkullItem.fromBase64(getTexture(id, texture));
}

View File

@ -14,6 +14,13 @@ commands:
description: Unlock/Reset researches for a player
reset: '&cYou have reset %player%''s Knowledge'
reset-target: '&cYour Knowledge has been reset'
backpack:
description: Retrieve an existing backpack
invalid-id: '&4The backpack id must be a non-negative number!'
player-never-joined: '&4No player with that name has ever joined the server!'
backpack-does-not-exist: '&4That backpack does not exist!'
restored-backpack-given: '&bBackpack restored successfully! Added to your inventory!'
guide:
locked: 'LOCKED'

View File

@ -37,6 +37,9 @@ permissions:
slimefun.command.versions:
description: Allows you to do /sf versions
default: op
slimefun.command.backpack:
description: Allows you to do /sf backpack
default: op
slimefun.command.guide:
description: Allows you to obtain the Slimefun guide book
default: true

View File

@ -1,103 +1,103 @@
{
"GOLD_PAN": "Gold-Pan",
"SIFTED_ORE": "Sifted-Ore",
"SMELTERY": "Smeltery",
"DIET_COOKIE": "Diet-Cookie",
"ENHANCED_CRAFTING_TABLE": "Enhanced-Crafting-Table",
"FORTUNE_COOKIE": "Fortune-Cookie",
"TABLE_SAW": "Table-Saw",
"APPLE_JUICE": "Juices",
"GOLDEN_APPLE_JUICE": "Juices",
"CARROT_JUICE": "Juices",
"MELON_JUICE": "Juices",
"PUMPKIN_JUICE": "Juices",
"SWEET_BERRY_JUICE": "Juices",
"MAGIC_SUGAR": "Magic-Sugar",
"MONSTER_JERKY": "Monster-Jerky",
"OUTPUT_CHEST": "Output-Chest",
"BEEF_JERKY": "Meat-Jerky",
"PORK_JERKY": "Meat-Jerky",
"CHICKEN_JERKY": "Meat-Jerky",
"MUTTON_JERKY": "Meat-Jerky",
"RABBIT_JERKY": "Meat-Jerky",
"FISH_JERKY": "Meat-Jerky",
"KELP_COOKIE": "Kelp-Cookie",
"ANCIENT_ALTAR": "Ancient-Altar",
"ANCIENT_PEDESTAL": "Ancient-Pedestal",
"BLADE_OF_VAMPIRES": "Blade-of-Vampires",
"BROKEN_SPAWNER": "Broken-Spawner",
"REPAIRED_SPAWNER": "Reinforced-Spawner",
"NETHER_GOLD_PAN": "Nether-Gold-Pan",
"PICKAXE_OF_CONTAINMENT": "Pickaxe-of-Containment",
"SEISMIC_AXE": "Seismic-Axe",
"SMELTERS_PICKAXE": "Smelter's-Pickaxe",
"MAGNET": "Magnet",
"BASIC_CIRCUIT_BOARD": "Circuit-Boards",
"ADVANCED_CIRCUIT_BOARD": "Circuit-Boards",
"BATTERY": "Battery",
"STEEL_THRUSTER": "Steel-Thruster",
"POWER_CRYSTAL": "Power-Crystal",
"SOLAR_PANEL": "Solar-Panel",
"ELECTRO_MAGNET": "Electromagnet",
"ELECTRIC_MOTOR": "Electric-Motor",
"HEATING_COIL": "Heating-Coil",
"COPPER_WIRE": "Copper-Wire",
"HARDENED_GLASS": "Hardened-Glass",
"COOLING_UNIT": "Cooling-Unit",
"WITHER_PROOF_OBSIDIAN": "Wither-Proof-Blocks",
"WITHER_PROOF_GLASS": "Wither-Proof-Blocks",
"REACTOR_COOLANT_CELL": "Coolant-Cells",
"NETHER_ICE_COOLANT_CELL": "Coolant-Cells",
"IRON_DUST": "Iron-Dust",
"GOLD_DUST": "Gold-Dust",
"GOLD_4K": "Gold-Ingot",
"GOLD_6K": "Gold-Ingot",
"GOLD_8K": "Gold-Ingot",
"GOLD_10K": "Gold-Ingot",
"GOLD_12K": "Gold-Ingot",
"GOLD_14K": "Gold-Ingot",
"GOLD_16K": "Gold-Ingot",
"GOLD_18K": "Gold-Ingot",
"GOLD_20K": "Gold-Ingot",
"GOLD_22K": "Gold-Ingot",
"GOLD_24K": "Gold-Ingot",
"ENERGY_REGULATOR": "Energy-Regulator",
"SMALL_CAPACITOR": "Energy-Capacitors",
"MEDIUM_CAPACITOR": "Energy-Capacitors",
"BIG_CAPACITOR": "Energy-Capacitors",
"LARGE_CAPACITOR": "Energy-Capacitors",
"CARBONADO_EDGED_CAPACITOR": "Energy-Capacitors",
"SOLAR_GENERATOR": "Solar-Generator",
"SOLAR_GENERATOR_2": "Solar-Generator",
"SOLAR_GENERATOR_3": "Solar-Generator",
"SOLAR_GENERATOR_4": "Solar-Generator",
"COAL_GENERATOR": "Coal-Generator",
"COAL_GENERATOR_2": "Coal-Generator",
"COBALT_PICKAXE": "Cobalt-Pickaxe",
"EXPLOSIVE_PICKAXE": "Explosive-Pickaxe",
"EXPLOSIVE_SHOVEL": "Explosive-Shovel",
"GRAPPLING_HOOK": "Grappling-Hook",
"HERCULES_PICKAXE": "Hercules'-Pickaxe",
"LUMBER_AXE": "Lumber-Axe",
"PICKAXE_OF_VEIN_MINING": "Pickaxe-of-Vein-Mining",
"PICKAXE_OF_THE_SEEKER": "Pickaxe-of-the-Seeker",
"CARGO_OUTPUT_ADVANCED": "Advanced-Output-Node",
"CARGO_MANAGER": "Cargo-Manager",
"CARGO_MOTOR": "Cargo-Motor",
"CARGO_NODE": "Connector-Node",
"CARGO_INPUT": "Input-Node",
"CARGO_OUTPUT": "Output-Node",
"TRASH_CAN": "Trash-Can",
"ORE_WASHER": "Ore-Washer",
"SCUBA_HELMET": "Hazmat-Suit",
"HAZMAT_CHESTPLATE": "Hazmat-Suit",
"HAZMAT_LEGGINGS": "Hazmat-Suit",
"RUBBER_BOOTS": "Hazmat-Suit",
"ARMOR_FORGE": "Armor-Forge",
"AUTOMATED_PANNING_MACHINE": "Automated-Panning-Machine",
"COMPRESSOR": "Compressor",
"ORE_CRUSHER": "Ore-Crusher",
"PRESSURE_CHAMBER": "Pressure-Chamber",
"GRIND_STONE": "Grind-Stone",
"MAGIC_WORKBENCH": "Magic-Workbench"
"GOLD_PAN" : "Gold-Pan",
"SIFTED_ORE" : "Sifted-Ore",
"SMELTERY" : "Smeltery",
"DIET_COOKIE" : "Diet-Cookie",
"ENHANCED_CRAFTING_TABLE" : "Enhanced-Crafting-Table",
"FORTUNE_COOKIE" : "Fortune-Cookie",
"TABLE_SAW" : "Table-Saw",
"APPLE_JUICE" : "Juices",
"GOLDEN_APPLE_JUICE" : "Juices",
"CARROT_JUICE" : "Juices",
"MELON_JUICE" : "Juices",
"PUMPKIN_JUICE" : "Juices",
"SWEET_BERRY_JUICE" : "Juices",
"MAGIC_SUGAR" : "Magic-Sugar",
"MONSTER_JERKY" : "Monster-Jerky",
"OUTPUT_CHEST" : "Output-Chest",
"BEEF_JERKY" : "Meat-Jerky",
"PORK_JERKY" : "Meat-Jerky",
"CHICKEN_JERKY" : "Meat-Jerky",
"MUTTON_JERKY" : "Meat-Jerky",
"RABBIT_JERKY" : "Meat-Jerky",
"FISH_JERKY" : "Meat-Jerky",
"KELP_COOKIE" : "Kelp-Cookie",
"ANCIENT_ALTAR" : "Ancient-Altar",
"ANCIENT_PEDESTAL" : "Ancient-Pedestal",
"BLADE_OF_VAMPIRES" : "Blade-of-Vampires",
"BROKEN_SPAWNER" : "Broken-Spawner",
"REPAIRED_SPAWNER" : "Reinforced-Spawner",
"NETHER_GOLD_PAN" : "Nether-Gold-Pan",
"PICKAXE_OF_CONTAINMENT" : "Pickaxe-of-Containment",
"SEISMIC_AXE" : "Seismic-Axe",
"SMELTERS_PICKAXE" : "Smelter's-Pickaxe",
"MAGNET" : "Magnet",
"BASIC_CIRCUIT_BOARD" : "Circuit-Boards",
"ADVANCED_CIRCUIT_BOARD" : "Circuit-Boards",
"BATTERY" : "Battery",
"STEEL_THRUSTER" : "Steel-Thruster",
"POWER_CRYSTAL" : "Power-Crystal",
"SOLAR_PANEL" : "Solar-Panel",
"ELECTRO_MAGNET" : "Electromagnet",
"ELECTRIC_MOTOR" : "Electric-Motor",
"HEATING_COIL" : "Heating-Coil",
"COPPER_WIRE" : "Copper-Wire",
"HARDENED_GLASS" : "Hardened-Glass",
"COOLING_UNIT" : "Cooling-Unit",
"WITHER_PROOF_OBSIDIAN" : "Wither-Proof-Blocks",
"WITHER_PROOF_GLASS" : "Wither-Proof-Blocks",
"REACTOR_COOLANT_CELL" : "Coolant-Cells",
"NETHER_ICE_COOLANT_CELL" : "Coolant-Cells",
"IRON_DUST" : "Iron-Dust",
"GOLD_DUST" : "Gold-Dust",
"GOLD_4K" : "Gold-Ingot",
"GOLD_6K" : "Gold-Ingot",
"GOLD_8K" : "Gold-Ingot",
"GOLD_10K" : "Gold-Ingot",
"GOLD_12K" : "Gold-Ingot",
"GOLD_14K" : "Gold-Ingot",
"GOLD_16K" : "Gold-Ingot",
"GOLD_18K" : "Gold-Ingot",
"GOLD_20K" : "Gold-Ingot",
"GOLD_22K" : "Gold-Ingot",
"GOLD_24K" : "Gold-Ingot",
"ENERGY_REGULATOR" : "Energy-Regulator",
"SMALL_CAPACITOR" : "Energy-Capacitors",
"MEDIUM_CAPACITOR" : "Energy-Capacitors",
"BIG_CAPACITOR" : "Energy-Capacitors",
"LARGE_CAPACITOR" : "Energy-Capacitors",
"CARBONADO_EDGED_CAPACITOR" : "Energy-Capacitors",
"SOLAR_GENERATOR" : "Solar-Generator",
"SOLAR_GENERATOR_2" : "Solar-Generator",
"SOLAR_GENERATOR_3" : "Solar-Generator",
"SOLAR_GENERATOR_4" : "Solar-Generator",
"COAL_GENERATOR" : "Coal-Generator",
"COAL_GENERATOR_2" : "Coal-Generator",
"COBALT_PICKAXE" : "Cobalt-Pickaxe",
"EXPLOSIVE_PICKAXE" : "Explosive-Pickaxe",
"EXPLOSIVE_SHOVEL" : "Explosive-Shovel",
"GRAPPLING_HOOK" : "Grappling-Hook",
"HERCULES_PICKAXE" : "Hercules'-Pickaxe",
"LUMBER_AXE" : "Lumber-Axe",
"PICKAXE_OF_VEIN_MINING" : "Pickaxe-of-Vein-Mining",
"PICKAXE_OF_THE_SEEKER" : "Pickaxe-of-the-Seeker",
"CARGO_OUTPUT_ADVANCED" : "Advanced-Output-Node",
"CARGO_MANAGER" : "Cargo-Manager",
"CARGO_MOTOR" : "Cargo-Motor",
"CARGO_NODE" : "Connector-Node",
"CARGO_INPUT" : "Input-Node",
"CARGO_OUTPUT" : "Output-Node",
"TRASH_CAN" : "Trash-Can",
"ORE_WASHER" : "Ore-Washer",
"SCUBA_HELMET" : "Hazmat-Suit",
"HAZMAT_CHESTPLATE" : "Hazmat-Suit",
"HAZMAT_LEGGINGS" : "Hazmat-Suit",
"RUBBER_BOOTS" : "Hazmat-Suit",
"ARMOR_FORGE" : "Armor-Forge",
"AUTOMATED_PANNING_MACHINE" : "Automated-Panning-Machine",
"COMPRESSOR" : "Compressor",
"ORE_CRUSHER" : "Ore-Crusher",
"PRESSURE_CHAMBER" : "Pressure-Chamber",
"GRIND_STONE" : "Grind-Stone",
"MAGIC_WORKBENCH" : "Magic-Workbench"
}

View File

@ -0,0 +1,12 @@
package io.github.thebusybiscuit.slimefun4.mocks;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
public class MockItemHandler implements ItemHandler {
@Override
public Class<? extends ItemHandler> getIdentifier() {
return getClass();
}
}

View File

@ -0,0 +1,14 @@
package io.github.thebusybiscuit.slimefun4.mocks;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
class MockSlimefunItem extends SlimefunItem {
public MockSlimefunItem(Category category, ItemStack item, String id) {
super(category, item, id, null, new ItemStack[9]);
}
}

View File

@ -0,0 +1,66 @@
package io.github.thebusybiscuit.slimefun4.mocks;
import static org.mockito.Mockito.when;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.OfflinePlayer;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.junit.jupiter.api.Assertions;
import org.mockito.Mockito;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
public final class TestUtilities {
private TestUtilities() {}
public static Inventory mockInventory(InventoryType type, ItemStack... contents) {
Inventory inv = Mockito.mock(Inventory.class);
when(inv.getType()).thenReturn(type);
when(inv.getContents()).thenReturn(contents);
return inv;
}
public static SlimefunItem mockSlimefunItem(Plugin plugin, String id, ItemStack item) {
Category category = new Category(new NamespacedKey(plugin, "test"), new CustomItem(Material.EMERALD, "&4Test Category"));
return new MockSlimefunItem(category, item, id);
}
public static VanillaItem mockVanillaItem(Plugin plugin, Material type, boolean enabled) {
Category category = new Category(new NamespacedKey(plugin, "test"), new CustomItem(Material.EMERALD, "&4Test Category"));
VanillaItem item = new VanillaItem(category, new ItemStack(type), type.name(), null, new ItemStack[9]);
SlimefunPlugin.getItemCfg().setValue(type.name() + ".enabled", enabled);
return item;
}
public static PlayerProfile awaitProfile(OfflinePlayer player) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<PlayerProfile> ref = new AtomicReference<>();
// This loads the profile asynchronously
Assertions.assertFalse(PlayerProfile.get(player, profile -> {
ref.set(profile);
latch.countDown();
}));
latch.await(2, TimeUnit.SECONDS);
return ref.get();
}
}

View File

@ -0,0 +1,70 @@
package io.github.thebusybiscuit.slimefun4.tests;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import be.seeseemelk.mockbukkit.MockBukkit;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
public class TestPluginClass {
@BeforeAll
public static void load() {
MockBukkit.mock();
MockBukkit.load(SlimefunPlugin.class);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
@Test
public void verifyTestEnvironment() {
MinecraftVersion version = SlimefunPlugin.getMinecraftVersion();
Assertions.assertEquals(MinecraftVersion.UNIT_TEST, version);
Assertions.assertEquals("Unit Test Environment", version.getName());
}
@Test
public void testConfigs() {
Assertions.assertNotNull(SlimefunPlugin.getCfg());
Assertions.assertNotNull(SlimefunPlugin.getResearchCfg());
Assertions.assertNotNull(SlimefunPlugin.getItemCfg());
}
@Test
public void testGetters() {
Assertions.assertNotNull(SlimefunPlugin.getTicker());
Assertions.assertNotNull(SlimefunPlugin.getVersion());
Assertions.assertNotNull(SlimefunPlugin.getRegistry());
Assertions.assertNotNull(SlimefunPlugin.getCommand());
}
@Test
public void testServicesNotNull() {
Assertions.assertNotNull(SlimefunPlugin.getLocal());
Assertions.assertNotNull(SlimefunPlugin.getMinecraftRecipes());
Assertions.assertNotNull(SlimefunPlugin.getItemDataService());
Assertions.assertNotNull(SlimefunPlugin.getItemTextureService());
Assertions.assertNotNull(SlimefunPlugin.getPermissionsService());
Assertions.assertNotNull(SlimefunPlugin.getBlockDataService());
Assertions.assertNotNull(SlimefunPlugin.getThirdPartySupportService());
Assertions.assertNotNull(SlimefunPlugin.getWorldSettingsService());
Assertions.assertNotNull(SlimefunPlugin.getGitHubService());
Assertions.assertNotNull(SlimefunPlugin.getUpdater());
}
@Test
public void testListenersNotNull() {
Assertions.assertNotNull(SlimefunPlugin.getAncientAltarListener());
Assertions.assertNotNull(SlimefunPlugin.getGrapplingHookListener());
Assertions.assertNotNull(SlimefunPlugin.getBackpackListener());
Assertions.assertNotNull(SlimefunPlugin.getBowListener());
}
}

View File

@ -0,0 +1,185 @@
package io.github.thebusybiscuit.slimefun4.tests.items;
import java.time.LocalDate;
import java.time.Month;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.mocks.TestUtilities;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
public class TestCategories {
private static ServerMock server;
private static SlimefunPlugin plugin;
@BeforeAll
public static void load() {
server = MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
@Test
public void testCategoryGetters() {
Category category = new Category(new NamespacedKey(plugin, "getter_test"), new CustomItem(Material.DIAMOND_AXE, "&6Testing"));
Assertions.assertEquals(3, category.getTier());
Assertions.assertEquals(new NamespacedKey(SlimefunPlugin.instance, "getter_test"), category.getKey());
Assertions.assertEquals("Testing", category.getUnlocalizedName());
Assertions.assertEquals(0, category.getItems().size());
}
@Test
public void testAddItem() {
Category category = new Category(new NamespacedKey(plugin, "items_test"), new CustomItem(Material.DIAMOND_AXE, "&6Testing"));
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CATEGORY_ITEMS_TEST_ITEM", new CustomItem(Material.BAMBOO, "&6Test Bamboo"));
item.setCategory(category);
item.register(plugin);
item.load();
Assertions.assertTrue(category.getItems().contains(item));
Assertions.assertEquals(1, category.getItems().size());
// Size must still be 1 since we disallow duplicates
item.setCategory(category);
Assertions.assertEquals(1, category.getItems().size());
Assertions.assertThrows(IllegalArgumentException.class, () -> category.add(null));
}
@Test
public void testHidden() {
Category category = new Category(new NamespacedKey(plugin, "hiddenCategory"), new ItemStack(Material.BEACON));
Player player = server.addPlayer();
// Empty Categories are also hidden
Assertions.assertTrue(category.isHidden(player));
SlimefunItem disabledItem = TestUtilities.mockSlimefunItem(plugin, "DISABLED_CATEGORY_ITEM", new CustomItem(Material.BEETROOT, "&4Disabled"));
SlimefunPlugin.getItemCfg().setValue("DISABLED_CATEGORY_ITEM.enabled", false);
disabledItem.setCategory(category);
disabledItem.register(plugin);
disabledItem.load();
// A disabled Item should also make the Category hide
Assertions.assertTrue(category.isHidden(player));
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CATEGORY_HIDDEN_TEST", new CustomItem(Material.BAMBOO, "&6Test Bamboo"));
item.setCategory(category);
item.setHidden(true);
item.register(plugin);
item.load();
// A hidden Item should also make the Category hide
Assertions.assertTrue(category.isHidden(player));
item.setHidden(false);
Assertions.assertFalse(category.isHidden(player));
}
@Test
public void testContains() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CATEGORY_TEST_ITEM_2", new CustomItem(Material.BOW, "&6Test Bow"));
item.register(plugin);
item.load();
Category category = item.getCategory();
Assertions.assertTrue(category.contains(item));
Assertions.assertFalse(category.contains(null));
// Unregistered Item
Assertions.assertFalse(category.contains(TestUtilities.mockSlimefunItem(plugin, "NULL", new ItemStack(Material.BEDROCK))));
}
@Test
public void testLockedCategories() {
Assertions.assertThrows(IllegalArgumentException.class, () -> new LockedCategory(new NamespacedKey(plugin, "locked"), new CustomItem(Material.GOLD_NUGGET, "&6Locked Test"), (NamespacedKey) null));
Category category = new Category(new NamespacedKey(plugin, "unlocked"), new CustomItem(Material.EMERALD, "&5I am SHERlocked"));
category.register();
Category unregistered = new Category(new NamespacedKey(plugin, "unregistered"), new CustomItem(Material.EMERALD, "&5I am unregistered"));
LockedCategory locked = new LockedCategory(new NamespacedKey(plugin, "locked"), new CustomItem(Material.GOLD_NUGGET, "&6Locked Test"), category.getKey(), unregistered.getKey());
locked.register();
Assertions.assertTrue(locked.getParents().contains(category));
Assertions.assertFalse(locked.getParents().contains(unregistered));
locked.removeParent(category);
Assertions.assertFalse(locked.getParents().contains(category));
Assertions.assertThrows(IllegalArgumentException.class, () -> locked.addParent(locked));
Assertions.assertThrows(IllegalArgumentException.class, () -> locked.addParent(null));
locked.addParent(category);
Assertions.assertTrue(locked.getParents().contains(category));
}
@Test
public void testSeasonalCategories() {
// Category with current Month
Month month = LocalDate.now().getMonth();
SeasonalCategory category = new SeasonalCategory(new NamespacedKey(plugin, "seasonal"), month, 1, new CustomItem(Material.NETHER_STAR, "&cSeasonal Test"));
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "SEASONAL_ITEM", new CustomItem(Material.NETHER_STAR, "&dSeasonal Test Star"));
item.setCategory(category);
item.register(plugin);
item.load();
Player player = server.addPlayer();
Assertions.assertEquals(month, category.getMonth());
Assertions.assertFalse(category.isHidden(player));
// Category with future Month
SeasonalCategory category2 = new SeasonalCategory(category.getKey(), month.plus(6), 1, new CustomItem(Material.MILK_BUCKET, "&dSeasonal Test"));
Assertions.assertTrue(category2.isHidden(player));
}
@Test
public void testFlexCategory() {
FlexCategory category = new FlexCategory(new NamespacedKey(plugin, "flex"), new CustomItem(Material.REDSTONE, "&4Weird flex but ok")) {
@Override
public void open(Player p, PlayerProfile profile, SlimefunGuideLayout layout) {
// Nothing
}
@Override
public boolean isVisible(Player p, PlayerProfile profile, SlimefunGuideLayout layout) {
return true;
}
};
Player player = server.addPlayer();
Assertions.assertFalse(category.isHidden(player));
Assertions.assertThrows(UnsupportedOperationException.class, () -> category.add(null));
Assertions.assertThrows(UnsupportedOperationException.class, () -> category.contains(null));
Assertions.assertThrows(UnsupportedOperationException.class, () -> category.remove(null));
Assertions.assertThrows(UnsupportedOperationException.class, () -> category.getItems());
}
}

View File

@ -0,0 +1,102 @@
package io.github.thebusybiscuit.slimefun4.tests.items;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bukkit.Material;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import be.seeseemelk.mockbukkit.MockBukkit;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.exceptions.IncompatibleItemHandlerException;
import io.github.thebusybiscuit.slimefun4.mocks.MockItemHandler;
import io.github.thebusybiscuit.slimefun4.mocks.TestUtilities;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.BowShootHandler;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemUseHandler;
public class TestItemHandlers {
private static SlimefunPlugin plugin;
@BeforeAll
public static void load() {
MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
@Test
public void testIllegalItemHandlers() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_HANDLER_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.register(plugin);
Assertions.assertThrows(IllegalArgumentException.class, () -> item.addItemHandler());
Assertions.assertThrows(IllegalArgumentException.class, () -> item.addItemHandler((MockItemHandler) null));
Assertions.assertThrows(UnsupportedOperationException.class, () -> item.addItemHandler(new MockItemHandler()));
}
@Test
public void testItemHandler() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_HANDLER_TEST_2", new CustomItem(Material.DIAMOND, "&cTest"));
MockItemHandler handler = new MockItemHandler();
item.addItemHandler(handler);
item.register(plugin);
Assertions.assertTrue(item.getHandlers().contains(handler));
AtomicBoolean bool = new AtomicBoolean(false);
Assertions.assertTrue(item.callItemHandler(MockItemHandler.class, x -> bool.set(true)));
Assertions.assertTrue(bool.get());
AtomicBoolean bool2 = new AtomicBoolean(false);
Assertions.assertFalse(item.callItemHandler(ItemUseHandler.class, x -> bool2.set(true)));
Assertions.assertFalse(bool2.get());
}
@Test
public void testBowShootHandler() {
BowShootHandler handler = (e, n) -> {};
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "NOT_A_BOW", new CustomItem(Material.KELP, "&bNot a bow!"));
Optional<IncompatibleItemHandlerException> exception = handler.validate(item);
Assertions.assertTrue(exception.isPresent());
SlimefunItem bow = TestUtilities.mockSlimefunItem(plugin, "A_BOW", new CustomItem(Material.BOW, "&bA bow!"));
Optional<IncompatibleItemHandlerException> exception2 = handler.validate(bow);
Assertions.assertFalse(exception2.isPresent());
}
@Test
public void testPublicHandler() {
ItemHandler handler = new MockItemHandler() {
@Override
public boolean isPrivate() {
return false;
}
};
Assertions.assertFalse(handler.isPrivate());
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "PUBLIC_HANDLER_TEST", new CustomItem(Material.KELP, "&bHappy kelp"));
item.addItemHandler(handler);
item.register(plugin);
Map<Class<? extends ItemHandler>, Set<ItemHandler>> handlers = SlimefunPlugin.getRegistry().getPublicItemHandlers();
Assertions.assertTrue(handlers.get(handler.getIdentifier()).contains(handler));
}
}

View File

@ -0,0 +1,89 @@
package io.github.thebusybiscuit.slimefun4.tests.items;
import java.util.Optional;
import org.bukkit.Material;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import be.seeseemelk.mockbukkit.MockBukkit;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.mocks.TestUtilities;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
public class TestItemSettings {
private static SlimefunPlugin plugin;
@BeforeAll
public static void load() {
MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
@Test
public void testIllegalItemSettings() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_SETTINGS_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.register(plugin);
Assertions.assertThrows(IllegalArgumentException.class, () -> new ItemSetting<>("prematureInvocation", "Hello world").getValue());
Assertions.assertThrows(IllegalArgumentException.class, () -> item.addItemSetting());
Assertions.assertThrows(IllegalArgumentException.class, () -> item.addItemSetting((ItemSetting<String>) null));
Assertions.assertThrows(UnsupportedOperationException.class, () -> item.addItemSetting(new ItemSetting<>("test", "Hello World")));
}
@Test
public void testAddItemSetting() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_SETTINGS_TEST_2", new CustomItem(Material.DIAMOND, "&cTest"));
ItemSetting<String> setting = new ItemSetting<>("test", "Hello World");
Assertions.assertTrue(setting.isType(String.class));
Assertions.assertFalse(setting.isType(Integer.class));
item.addItemSetting(setting);
item.register(plugin);
Assertions.assertTrue(item.getItemSettings().contains(setting));
Optional<ItemSetting<String>> optional = item.getItemSetting(setting.getKey(), String.class);
Assertions.assertTrue(optional.isPresent());
Assertions.assertEquals(setting, optional.get());
Assertions.assertEquals("Hello World", setting.getValue());
Assertions.assertFalse(item.getItemSetting(setting.getKey(), Boolean.class).isPresent());
Assertions.assertFalse(item.getItemSetting("I do not exist", String.class).isPresent());
}
@Test
public void testUpdateItemSetting() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_SETTINGS_TEST_3", new CustomItem(Material.DIAMOND, "&cTest"));
ItemSetting<String> setting = new ItemSetting<>("test", "Hello World");
item.addItemSetting(setting);
item.register(plugin);
Assertions.assertEquals("Hello World", setting.getValue());
setting.update("I am different");
Assertions.assertEquals("I am different", setting.getValue());
Assertions.assertThrows(IllegalArgumentException.class, () -> setting.update(null));
Assertions.assertEquals("I am different", setting.getValue());
}
@Test
public void testAlreadyExistingItemSetting() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_SETTINGS_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.addItemSetting(new ItemSetting<>("test", "Hello World"));
Assertions.assertThrows(IllegalArgumentException.class, () -> item.addItemSetting(new ItemSetting<>("test", "Hello World")));
}
}

View File

@ -0,0 +1,209 @@
package io.github.thebusybiscuit.slimefun4.tests.items;
import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import be.seeseemelk.mockbukkit.MockBukkit;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import io.github.thebusybiscuit.slimefun4.mocks.TestUtilities;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.ItemState;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
public class TestSlimefunItemRegistration {
private static SlimefunPlugin plugin;
@BeforeAll
public static void load() {
MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
@Test
public void testSuccessfulRegistration() {
String id = "TEST_ITEM";
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, id, new CustomItem(Material.DIAMOND, "&cTest"));
Assertions.assertEquals(ItemState.UNREGISTERED, item.getState());
item.register(plugin);
Assertions.assertEquals(ItemState.ENABLED, item.getState());
Assertions.assertFalse(item.isDisabled());
Assertions.assertEquals(id, item.getID());
Assertions.assertEquals(item, SlimefunItem.getByID(id));
}
@Test
public void testDisabledItem() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "DISABLED_ITEM", new CustomItem(Material.DIAMOND, "&cTest"));
SlimefunPlugin.getItemCfg().setValue("DISABLED_ITEM.enabled", false);
item.register(plugin);
Assertions.assertEquals(ItemState.DISABLED, item.getState());
Assertions.assertTrue(item.isDisabled());
}
@Test
public void testWikiPages() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "WIKI_ITEM", new CustomItem(Material.BOOK, "&cTest"));
item.register(plugin);
Assertions.assertFalse(item.getWikipage().isPresent());
// null should not be a valid argument
Assertions.assertThrows(IllegalArgumentException.class, () -> item.addOficialWikipage(null));
item.addOficialWikipage("Test");
Optional<String> wiki = item.getWikipage();
Assertions.assertTrue(wiki.isPresent());
Assertions.assertEquals("https://github.com/TheBusyBiscuit/Slimefun4/wiki/Test", wiki.get());
}
@Disabled("This Test provokes a ClassNotFoundException")
@Test
public void testGetItemName() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ITEM_NAME_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.register(plugin);
Assertions.assertEquals(ChatColor.RED + "Test", item.getItemName());
}
@Test
public void testVanillaItemFallback() {
VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.ACACIA_SIGN, false);
item.register(plugin);
Assertions.assertTrue(item.isUseableInWorkbench());
Assertions.assertEquals(ItemState.VANILLA_FALLBACK, item.getState());
Assertions.assertTrue(item.isDisabled());
}
@Test
public void testIdConflict() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "DUPLICATE_ID", new CustomItem(Material.DIAMOND, "&cTest"));
item.register(plugin);
SlimefunItem item2 = TestUtilities.mockSlimefunItem(plugin, "DUPLICATE_ID", new CustomItem(Material.DIAMOND, "&cTest"));
item2.register(plugin);
Assertions.assertEquals(ItemState.ENABLED, item.getState());
Assertions.assertEquals(ItemState.UNREGISTERED, item2.getState());
}
@Test
public void testRecipe() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "RECIPE_TEST", new CustomItem(Material.DIAMOND, "&dAnother one bites the test"));
ItemStack[] recipe = { null, new ItemStack(Material.DIAMOND), null, null, new ItemStack(Material.DIAMOND), null, null, new ItemStack(Material.DIAMOND), null };
item.setRecipe(recipe);
item.register(plugin);
Assertions.assertArrayEquals(recipe, item.getRecipe());
Assertions.assertThrows(IllegalArgumentException.class, () -> item.setRecipe(null));
Assertions.assertThrows(IllegalArgumentException.class, () -> item.setRecipe(new ItemStack[3]));
Assertions.assertThrows(IllegalArgumentException.class, () -> item.setRecipe(new ItemStack[20]));
}
@Test
public void testRecipeOutput() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "RECIPE_OUTPUT_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.register(plugin);
Assertions.assertEquals(item.getItem(), item.getRecipeOutput());
ItemStack output = new ItemStack(Material.EMERALD, 64);
item.setRecipeOutput(output);
Assertions.assertEquals(output, item.getRecipeOutput());
item.setRecipeOutput(item.getItem());
Assertions.assertEquals(item.getItem(), item.getRecipeOutput());
}
@Test
public void testIsItem() {
CustomItem item = new CustomItem(Material.BEACON, "&cItem Test");
SlimefunItem sfItem = TestUtilities.mockSlimefunItem(plugin, "IS_ITEM_TEST", item);
sfItem.register(plugin);
Assertions.assertTrue(sfItem.isItem(sfItem.getItem()));
Assertions.assertTrue(sfItem.isItem(item));
Assertions.assertTrue(sfItem.isItem(new CustomItem(Material.BEACON, "&cItem Test")));
Assertions.assertFalse(sfItem.isItem(null));
Assertions.assertFalse(sfItem.isItem(new ItemStack(Material.BEACON)));
Assertions.assertFalse(sfItem.isItem(new CustomItem(Material.REDSTONE, "&cTest")));
Assertions.assertEquals(sfItem, SlimefunItem.getByItem(item));
}
@Test
public void testCategoryRegistration() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CATEGORY_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.register(plugin);
item.load();
// null should not be a valid argument
Assertions.assertThrows(IllegalArgumentException.class, () -> item.setCategory(null));
Category category = item.getCategory();
Category category2 = new Category(new NamespacedKey(plugin, "test2"), new CustomItem(Material.OBSIDIAN, "&6Test 2"));
Assertions.assertTrue(category.contains(item));
Assertions.assertFalse(category2.contains(item));
Assertions.assertEquals(category, item.getCategory());
item.setCategory(category2);
Assertions.assertFalse(category.contains(item));
Assertions.assertTrue(category2.contains(item));
Assertions.assertEquals(category2, item.getCategory());
}
@Test
public void testHiddenItem() {
SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "HIDDEN_TEST", new CustomItem(Material.DIAMOND, "&cTest"));
item.setHidden(true);
item.register(plugin);
item.load();
Category category = item.getCategory();
Assertions.assertTrue(item.isHidden());
Assertions.assertFalse(category.contains(item));
Assertions.assertEquals(category, item.getCategory());
item.setHidden(false);
Assertions.assertFalse(item.isHidden());
Assertions.assertTrue(category.contains(item));
Assertions.assertEquals(category, item.getCategory());
item.setHidden(true);
Assertions.assertTrue(item.isHidden());
Assertions.assertFalse(category.contains(item));
Assertions.assertEquals(category, item.getCategory());
// Do nothing if the value hasn't changed
item.setHidden(true);
Assertions.assertTrue(item.isHidden());
Assertions.assertFalse(category.contains(item));
}
}

View File

@ -0,0 +1,101 @@
package io.github.thebusybiscuit.slimefun4.tests.listeners;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.IronGolemListener;
import io.github.thebusybiscuit.slimefun4.mocks.TestUtilities;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
public class TestIronGolemListener {
private static SlimefunPlugin plugin;
private static IronGolemListener listener;
private static ServerMock server;
@BeforeAll
public static void load() {
server = MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
listener = new IronGolemListener(plugin);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
private PlayerInteractEntityEvent callIronGolemEvent(EquipmentSlot hand, ItemStack itemInHand) {
// Fake Player with an Iron Ingot
Player player = server.addPlayer();
if (hand == EquipmentSlot.HAND) {
player.getInventory().setItemInMainHand(itemInHand);
}
else {
player.getInventory().setItemInOffHand(itemInHand);
}
// Fake Iron Golem
IronGolem golem = Mockito.mock(IronGolem.class);
Mockito.when(golem.getType()).thenReturn(EntityType.IRON_GOLEM);
// Fake Event
PlayerInteractEntityEvent event = new PlayerInteractEntityEvent(player, golem, hand);
listener.onIronGolemHeal(event);
return event;
}
@Test
public void testWithIron() {
// This should heal the Iron Golem
ItemStack item = new ItemStack(Material.IRON_INGOT);
PlayerInteractEntityEvent event = callIronGolemEvent(EquipmentSlot.HAND, item);
Assertions.assertFalse(event.isCancelled());
PlayerInteractEntityEvent event2 = callIronGolemEvent(EquipmentSlot.OFF_HAND, item);
Assertions.assertFalse(event2.isCancelled());
}
@Test
public void testWithSlimefunIron() {
SlimefunItem slimefunItem = TestUtilities.mockSlimefunItem(plugin, "SLIMEFUN_IRON", new CustomItem(Material.IRON_INGOT, "&cSlimefun Iron"));
slimefunItem.register(plugin);
// The Event should be cancelled, we do not wanna use Slimefun Items for this
PlayerInteractEntityEvent event = callIronGolemEvent(EquipmentSlot.HAND, slimefunItem.getItem());
Assertions.assertTrue(event.isCancelled());
PlayerInteractEntityEvent event2 = callIronGolemEvent(EquipmentSlot.OFF_HAND, slimefunItem.getItem());
Assertions.assertTrue(event2.isCancelled());
}
@Test
public void testWithVanillaIron() {
VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.IRON_INGOT, true);
item.register(plugin);
PlayerInteractEntityEvent event = callIronGolemEvent(EquipmentSlot.HAND, item.getItem());
Assertions.assertFalse(event.isCancelled());
PlayerInteractEntityEvent event2 = callIronGolemEvent(EquipmentSlot.OFF_HAND, item.getItem());
Assertions.assertFalse(event2.isCancelled());
}
}

View File

@ -0,0 +1,70 @@
package io.github.thebusybiscuit.slimefun4.tests.listeners;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
public class TestNetworkListener {
private static SlimefunPlugin plugin;
private static NetworkListener listener;
private static NetworkManager manager = new NetworkManager(80);
private static ServerMock server;
@BeforeAll
public static void load() {
server = MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
listener = new NetworkListener(plugin, manager);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
@Test
public void testBlockBreak() {
World world = server.addSimpleWorld("Simple Network Listener World");
Location l = new Location(world, 3000, 120, -500);
Network network = Mockito.mock(Network.class);
Mockito.when(network.connectsTo(l)).thenReturn(true);
manager.registerNetwork(network);
listener.onBlockBreak(new BlockBreakEvent(l.getBlock(), server.addPlayer()));
Mockito.verify(network).markDirty(l);
}
@Test
public void testBlockPlace() {
World world = server.addSimpleWorld("Simple Network Listener World");
Location l = new Location(world, 3000, 120, -500);
Location l2 = new Location(world, 3000, 121, -500);
Network network = Mockito.mock(Network.class);
Mockito.when(network.connectsTo(l)).thenReturn(true);
manager.registerNetwork(network);
BlockState state = Mockito.mock(BlockState.class);
listener.onBlockPlace(new BlockPlaceEvent(l.getBlock(), state, l2.getBlock(), new ItemStack(Material.AIR), server.addPlayer(), true, EquipmentSlot.HAND));
Mockito.verify(network).markDirty(l);
}
}

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