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

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

View File

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

View File

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

View File

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

View File

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

View File

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

146
pom.xml
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,7 +19,6 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.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
@ -153,14 +152,13 @@ public class LockedCategory extends Category {
* @return Whether the {@link Player} has fully completed all parent categories, otherwise false
*/
public boolean hasUnlocked(@Nonnull Player p, @Nonnull PlayerProfile profile) {
Validate.notNull(p, "The player cannot be null!");
Validate.notNull(profile, "The Profile cannot be null!");
for (Category category : parents) {
for (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())) {
// Check if the Player has researched every item (if the item is enabled)
if (!item.isDisabledIn(p.getWorld()) && item.hasResearch() && !profile.hasUnlocked(item.getResearch())) {
return false;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,8 +5,10 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import javax.annotation.ParametersAreNonnullByDefault;
@ -15,6 +17,7 @@ import org.bukkit.block.Block;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -63,6 +66,7 @@ class CargoNetworkTask implements Runnable {
public void run() {
long timestamp = System.nanoTime();
try {
// Chest Terminal Code
if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) {
network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs);
@ -89,6 +93,9 @@ class CargoNetworkTask implements Runnable {
// This will deduct any CT timings and attribute them towards the actual terminal
timestamp += network.updateTerminals(chestTerminalInputs);
}
} catch (Exception | LinkageError x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception was caught while ticking a Cargo network @ " + new BlockPosition(network.getRegulator()));
}
// Submit a timings report
SlimefunPlugin.getProfiler().closeEntry(network.getRegulator(), SlimefunItems.CARGO_MANAGER.getItem(), timestamp);
@ -150,7 +157,7 @@ class CargoNetworkTask implements Runnable {
Deque<Location> destinations = new LinkedList<>(outputNodes);
Config cfg = BlockStorage.getLocationInfo(inputNode);
boolean roundrobin = "true".equals(cfg.getString("round-robin"));
boolean roundrobin = Objects.equals(cfg.getString("round-robin"), "true");
if (roundrobin) {
roundRobinSort(inputNode, destinations);

View File

@ -240,11 +240,11 @@ final class CargoUtils {
int maxSlot = range[1];
for (int slot = minSlot; slot < maxSlot; slot++) {
ItemStack is = contents[slot];
ItemStack item = contents[slot];
if (matchesFilter(network, node, is)) {
if (matchesFilter(network, node, item)) {
inv.setItem(slot, null);
return new ItemStackAndInteger(is, slot);
return new ItemStackAndInteger(item, slot);
}
}

View File

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

View File

@ -29,13 +29,25 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
*/
public class BackupService implements Runnable {
/**
* The maximum amount of backups to maintain
*/
private static final int MAX_BACKUPS = 20;
/**
* Our {@link DateTimeFormatter} for formatting file names.
*/
private final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm", Locale.ROOT);
/**
* The directory in which to create the backups
*/
private final File directory = new File("data-storage/Slimefun/block-backups");
@Override
public void run() {
// Make sure that the directory exists.
if (directory.exists()) {
List<File> backups = Arrays.asList(directory.listFiles());
if (backups.size() > MAX_BACKUPS) {
@ -60,7 +72,8 @@ public class BackupService implements Runnable {
SlimefunPlugin.logger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName());
}
} catch (IOException x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Error occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion());
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion());
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -56,7 +56,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
@ -133,6 +132,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
}
};
// TODO: Move this into a BlockBreakHandler
registerBlockHandler(getId(), (p, b, stack, reason) -> {
boolean allow = reason == UnregisterReason.PLAYER_BREAK && (BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(p.getUniqueId().toString()) || p.hasPermission("slimefun.android.bypass"));
@ -151,7 +151,8 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
addItemHandler(onPlace());
}
private ItemHandler onPlace() {
@Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -18,10 +20,16 @@ public class CargoOutputNode extends AbstractCargoNode {
private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
@ParametersAreNonnullByDefault
public CargoOutputNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
}
@Override
public boolean hasItemFilter() {
return false;
}
@Override
protected void onPlace(BlockPlaceEvent e) {
// We only require the default values

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.Iterator;
@ -25,14 +25,14 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
public class XPCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
public class ExpCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
private final int[] border = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
private static final int ENERGY_CONSUMPTION = 10;
private static final String DATA_KEY = "stored-exp";
public XPCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
public ExpCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
createPreset(this, this::constructMenu);
@ -91,7 +91,7 @@ public class XPCollector extends SlimefunItem implements InventoryBlock, EnergyN
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
XPCollector.this.tick(b);
ExpCollector.this.tick(b);
}
@Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
@ -9,15 +11,29 @@ import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
/**
* The {@link ExplosionsListener} is a {@link Listener} which listens to any explosion events.
* Any {@link WitherProof} block is excluded from these explosions and this {@link Listener} also
* calls the explosive part of the {@link BlockBreakHandler}.
*
* @author TheBusyBiscuit
*
* @see BlockBreakHandler
* @see WitherProof
*
*/
public class ExplosionsListener implements Listener {
public ExplosionsListener(@Nonnull SlimefunPlugin plugin) {
@ -26,12 +42,19 @@ public class ExplosionsListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent e) {
Iterator<Block> blocks = e.blockList().iterator();
removeResistantBlocks(e.blockList().iterator());
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockExplode(BlockExplodeEvent e) {
removeResistantBlocks(e.blockList().iterator());
}
private void removeResistantBlocks(@Nonnull Iterator<Block> blocks) {
while (blocks.hasNext()) {
Block block = blocks.next();
SlimefunItem item = BlockStorage.check(block);
if (item != null) {
blocks.remove();
@ -41,6 +64,24 @@ public class ExplosionsListener implements Listener {
if (blockHandler != null) {
success = blockHandler.onBreak(null, block, item, UnregisterReason.EXPLODE);
} else {
item.callItemHandler(BlockBreakHandler.class, handler -> {
if (handler.isExplosionAllowed(block)) {
BlockStorage.clearBlockInfo(block);
block.setType(Material.AIR);
List<ItemStack> drops = new ArrayList<>();
handler.onExplode(block, drops);
for (ItemStack drop : drops) {
if (drop != null && !drop.getType().isAir()) {
block.getWorld().dropItemNaturally(block.getLocation(), drop);
}
}
}
});
return;
}
if (success) {

View File

@ -14,13 +14,12 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.armor.Parachute;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.JetBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.Jetpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedMagnet;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.InfusedMagnetTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.JetBootsTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.JetpackTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.InfusedMagnetTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ParachuteTask;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for listening to the {@link PlayerToggleSneakEvent}
@ -59,7 +58,7 @@ public class GadgetsListener implements Listener {
if (SlimefunUtils.containsSimilarItem(p.getInventory(), SlimefunItems.INFUSED_MAGNET, true)) {
InfusedMagnet magnet = (InfusedMagnet) SlimefunItems.INFUSED_MAGNET.getItem();
if (Slimefun.hasUnlocked(p, magnet, true)) {
if (magnet.canUse(p, true)) {
new InfusedMagnetTask(p, magnet.getRadius()).scheduleRepeating(0, 8);
}
}
@ -67,7 +66,7 @@ public class GadgetsListener implements Listener {
}
private void handleChestplate(@Nonnull Player p, @Nullable SlimefunItem chestplate) {
if (chestplate == null || !Slimefun.hasUnlocked(p, chestplate, true)) {
if (chestplate == null || !chestplate.canUse(p, true)) {
return;
}
@ -83,7 +82,7 @@ public class GadgetsListener implements Listener {
}
private void handleBoots(@Nonnull Player p, @Nullable SlimefunItem boots) {
if (boots instanceof JetBoots && Slimefun.hasUnlocked(p, boots, true)) {
if (boots instanceof JetBoots && boots.canUse(p, true)) {
double speed = ((JetBoots) boots).getSpeed();
if (speed > 0.2) {

View File

@ -0,0 +1,45 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import javax.annotation.Nonnull;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
/**
* This {@link Listener} makes sure that an {@link AndroidMineEvent} gets properly propagated
* to the {@link BlockBreakHandler#onAndroidBreak(AndroidMineEvent)} method of a placed block.
* If that block is a {@link SlimefunItem} of course.
*
* @author TheBusyBiscuit
*
* @see BlockBreakHandler
*
*/
public class MiningAndroidListener implements Listener {
public MiningAndroidListener(@Nonnull SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@EventHandler(ignoreCancelled = true)
public void onAndroidMine(AndroidMineEvent e) {
SlimefunItem slimefunItem = BlockStorage.check(e.getBlock());
// Fixes #2839 - Can't believe we forgot a null check here
if (slimefunItem != null) {
slimefunItem.callItemHandler(BlockBreakHandler.class, handler -> {
if (handler.isAndroidAllowed(e.getBlock())) {
handler.onAndroidBreak(e);
} else {
e.setCancelled(true);
}
});
}
}
}

View File

@ -62,8 +62,13 @@ public class MultiBlockListener implements Listener {
e.setCancelled(true);
MultiBlock mb = multiblocks.getLast();
MultiBlockInteractEvent event = new MultiBlockInteractEvent(p, mb, b, e.getBlockFace());
Bukkit.getPluginManager().callEvent(event);
// Fixes #2809
if (!event.isCancelled()) {
mb.getSlimefunItem().callItemHandler(MultiBlockInteractionHandler.class, handler -> handler.onInteract(p, mb, b));
Bukkit.getPluginManager().callEvent(new MultiBlockInteractEvent(p, mb, b, e.getBlockFace()));
}
}
}

View File

@ -23,7 +23,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.armor.LongFallBoo
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.StomperBoots;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for handling all boots provided by
@ -53,7 +52,7 @@ public class SlimefunBootsListener implements Listener {
Player p = (Player) e.getEntity();
SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots());
if (boots instanceof EnderBoots && Slimefun.hasUnlocked(p, boots, true)) {
if (boots instanceof EnderBoots && boots.canUse(p, true)) {
e.setCancelled(true);
}
}
@ -65,7 +64,7 @@ public class SlimefunBootsListener implements Listener {
if (boots != null) {
// Check if the boots were researched
if (!Slimefun.hasUnlocked(p, boots, true)) {
if (!boots.canUse(p, true)) {
return;
}
@ -91,7 +90,7 @@ public class SlimefunBootsListener implements Listener {
Player p = e.getPlayer();
SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots());
if (boots instanceof FarmerShoes && Slimefun.hasUnlocked(p, boots, true)) {
if (boots instanceof FarmerShoes && boots.canUse(p, true)) {
e.setCancelled(true);
}
}

View File

@ -11,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for handling the {@link ItemConsumptionHandler}
@ -33,7 +32,7 @@ public class SlimefunItemConsumeListener implements Listener {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null) {
if (Slimefun.hasUnlocked(p, sfItem, true)) {
if (sfItem.canUse(p, true)) {
sfItem.callItemHandler(ItemConsumptionHandler.class, handler -> handler.onConsume(e, p, item));
} else {
e.setCancelled(true);

View File

@ -25,7 +25,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
@ -94,8 +93,10 @@ public class SlimefunItemInteractListener implements Listener {
Optional<SlimefunItem> optional = event.getSlimefunItem();
if (optional.isPresent()) {
if (Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) {
return optional.get().callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(event));
SlimefunItem sfItem = optional.get();
if (sfItem.canUse(e.getPlayer(), true)) {
return sfItem.callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(event));
} else {
event.setUseItem(Result.DENY);
}
@ -109,19 +110,20 @@ public class SlimefunItemInteractListener implements Listener {
Optional<SlimefunItem> optional = event.getSlimefunBlock();
if (optional.isPresent()) {
if (!Slimefun.hasUnlocked(event.getPlayer(), optional.get(), true)) {
SlimefunItem sfItem = optional.get();
if (!sfItem.canUse(event.getPlayer(), true)) {
event.getInteractEvent().setCancelled(true);
return false;
}
boolean interactable = optional.get().callItemHandler(BlockUseHandler.class, handler -> handler.onRightClick(event));
boolean interactable = sfItem.callItemHandler(BlockUseHandler.class, handler -> handler.onRightClick(event));
if (!interactable) {
String id = optional.get().getId();
Player p = event.getPlayer();
if (BlockMenuPreset.isInventory(id)) {
openInventory(p, id, event.getInteractEvent().getClickedBlock(), event);
if (BlockMenuPreset.isInventory(sfItem.getId())) {
openInventory(p, sfItem, event.getInteractEvent().getClickedBlock(), event);
return false;
}
}
@ -131,12 +133,13 @@ public class SlimefunItemInteractListener implements Listener {
}
@ParametersAreNonnullByDefault
private void openInventory(Player p, String id, Block clickedBlock, PlayerRightClickEvent event) {
private void openInventory(Player p, SlimefunItem item, Block clickedBlock, PlayerRightClickEvent event) {
try {
if (!p.isSneaking() || event.getItem().getType() == Material.AIR) {
event.getInteractEvent().setCancelled(true);
if (BlockStorage.hasUniversalInventory(id)) {
UniversalBlockMenu menu = BlockStorage.getUniversalInventory(id);
if (BlockStorage.hasUniversalInventory(item.getId())) {
UniversalBlockMenu menu = BlockStorage.getUniversalInventory(item.getId());
if (menu.canOpen(clickedBlock, p)) {
menu.open(p);
@ -153,6 +156,9 @@ public class SlimefunItemInteractListener implements Listener {
}
}
}
} catch (Exception | LinkageError x) {
item.error("An Exception was caught while trying to open the Inventory", x);
}
}
}

View File

@ -61,24 +61,24 @@ public class TalismanListener implements Listener {
public void onDamageGet(EntityDamageEvent e) {
if (e.getEntity() instanceof Player) {
if (e.getCause() == DamageCause.LAVA) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_LAVA);
Talisman.trigger(e, SlimefunItems.TALISMAN_LAVA);
}
if (e.getCause() == DamageCause.DROWNING) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_WATER);
Talisman.trigger(e, SlimefunItems.TALISMAN_WATER);
}
if (e.getCause() == DamageCause.FALL) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_ANGEL);
Talisman.trigger(e, SlimefunItems.TALISMAN_ANGEL);
}
if (e.getCause() == DamageCause.FIRE) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_FIRE);
Talisman.trigger(e, SlimefunItems.TALISMAN_FIRE);
}
if (e.getCause() == DamageCause.ENTITY_ATTACK) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_KNIGHT);
Talisman.checkFor(e, SlimefunItems.TALISMAN_WARRIOR);
Talisman.trigger(e, SlimefunItems.TALISMAN_KNIGHT);
Talisman.trigger(e, SlimefunItems.TALISMAN_WARRIOR);
}
if (e.getCause() == DamageCause.PROJECTILE && e instanceof EntityDamageByEntityEvent) {
@ -91,7 +91,7 @@ public class TalismanListener implements Listener {
if (e.getDamager() instanceof Projectile && !(e.getDamager() instanceof Trident)) {
Projectile projectile = (Projectile) e.getDamager();
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
if (Talisman.trigger(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
Player p = (Player) e.getEntity();
returnProjectile(p, projectile);
}
@ -143,7 +143,7 @@ public class TalismanListener implements Listener {
// We are also excluding entities which can pickup items, this is not perfect
// but it at least prevents dupes by tossing items to zombies
if (!entity.getCanPickupItems() && Talisman.checkFor(e, SlimefunItems.TALISMAN_HUNTER)) {
if (!entity.getCanPickupItems() && Talisman.trigger(e, SlimefunItems.TALISMAN_HUNTER)) {
Collection<ItemStack> extraDrops = getExtraDrops(e.getEntity(), e.getDrops());
for (ItemStack drop : extraDrops) {
@ -192,7 +192,7 @@ public class TalismanListener implements Listener {
@EventHandler
public void onItemBreak(PlayerItemBreakEvent e) {
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_ANVIL)) {
if (Talisman.trigger(e, SlimefunItems.TALISMAN_ANVIL)) {
PlayerInventory inv = e.getPlayer().getInventory();
int slot = inv.getHeldItemSlot();
@ -225,7 +225,7 @@ public class TalismanListener implements Listener {
@EventHandler
public void onSprint(PlayerToggleSprintEvent e) {
if (e.isSprinting()) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_TRAVELLER);
Talisman.trigger(e, SlimefunItems.TALISMAN_TRAVELLER);
}
}
@ -235,17 +235,23 @@ public class TalismanListener implements Listener {
Map<Enchantment, Integer> enchantments = e.getEnchantsToAdd();
// Magician Talisman
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_MAGICIAN)) {
MagicianTalisman talisman = (MagicianTalisman) SlimefunItems.TALISMAN_MAGICIAN.getItem();
TalismanEnchantment enchantment = talisman.getRandomEnchantment(e.getItem(), enchantments.keySet());
if (enchantment != null) {
if (enchantment != null && Talisman.trigger(e, SlimefunItems.TALISMAN_MAGICIAN)) {
/*
* Fix #2679
* By default, the Bukkit API doesn't allow us to give enchantment books extra enchantments.
*/
if (talisman.isEnchantmentBookAllowed() && e.getItem().getType() == Material.BOOK) {
e.getItem().addUnsafeEnchantment(enchantment.getEnchantment(), enchantment.getLevel());
} else {
enchantments.put(enchantment.getEnchantment(), enchantment.getLevel());
}
}
// Wizard Talisman
if (!enchantments.containsKey(Enchantment.SILK_TOUCH) && Enchantment.LOOT_BONUS_BLOCKS.canEnchantItem(e.getItem()) && Talisman.checkFor(e, SlimefunItems.TALISMAN_WIZARD)) {
if (!enchantments.containsKey(Enchantment.SILK_TOUCH) && Enchantment.LOOT_BONUS_BLOCKS.canEnchantItem(e.getItem()) && Talisman.trigger(e, SlimefunItems.TALISMAN_WIZARD)) {
// Randomly lower some enchantments
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
if (entry.getValue() > 1 && random.nextInt(100) < 40) {
@ -260,7 +266,8 @@ public class TalismanListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onExperienceReceive(PlayerExpChangeEvent e) {
if (e.getAmount() > 0 && Talisman.checkFor(e, SlimefunItems.TALISMAN_WISE)) {
// Check if the experience change was positive.
if (e.getAmount() > 0 && Talisman.trigger(e, SlimefunItems.TALISMAN_WISE)) {
// Double-XP
e.setAmount(e.getAmount() * 2);
}
@ -268,21 +275,27 @@ public class TalismanListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlockDropItems(BlockDropItemEvent e) {
// We only want to double ores
Material type = e.getBlockState().getType();
if (type.name().endsWith("_ORE")) {
ItemStack item = e.getPlayer().getInventory().getItemInMainHand();
// We are going to ignore Silk Touch here
if (item.getType() != Material.AIR && item.getAmount() > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) {
Material type = e.getBlockState().getType();
// We only want to double ores
if (SlimefunTag.MINER_TALISMAN_TRIGGERS.isTagged(type)) {
Collection<Item> drops = e.getItems();
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_MINER)) {
if (Talisman.trigger(e, SlimefunItems.TALISMAN_MINER, false)) {
int dropAmount = getAmountWithFortune(type, item.getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS));
// Keep track of whether we actually doubled the drops or not
boolean doubledDrops = false;
// Loop through all dropped items
for (Item drop : drops) {
ItemStack droppedItem = drop.getItemStack();
// We do not want to dupe blocks
if (!droppedItem.getType().isBlock()) {
int amount = Math.max(1, (dropAmount * 2) - droppedItem.getAmount());
e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), new CustomItem(droppedItem, amount));
@ -290,8 +303,14 @@ public class TalismanListener implements Listener {
}
}
// Fixes #2077
if (doubledDrops) {
SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.talisman.miner", true);
Talisman talisman = SlimefunItems.TALISMAN_MINER.getItem(Talisman.class);
// Fixes #2818
if (talisman != null) {
talisman.sendMessage(e.getPlayer());
}
}
}
}
@ -301,7 +320,7 @@ public class TalismanListener implements Listener {
@EventHandler
public void onBlockBreak(BlockBreakEvent e) {
if (SlimefunTag.CAVEMAN_TALISMAN_TRIGGERS.isTagged(e.getBlock().getType())) {
Talisman.checkFor(e, SlimefunItems.TALISMAN_CAVEMAN);
Talisman.trigger(e, SlimefunItems.TALISMAN_CAVEMAN);
}
}

View File

@ -13,7 +13,6 @@ import org.bukkit.potion.PotionEffect;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.VampireBlade;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is exclusively used for the {@link VampireBlade}.
@ -44,7 +43,7 @@ public class VampireBladeListener implements Listener {
Player p = (Player) e.getDamager();
if (blade.isItem(p.getInventory().getItemInMainHand())) {
if (Slimefun.hasUnlocked(p, blade, true)) {
if (blade.canUse(p, true)) {
blade.heal(p);
} else {
e.setCancelled(true);

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