diff --git a/.github/renovate.json b/.github/renovate.json index c74f8617a..f45d8f110 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,8 +1,5 @@ { "extends": [ "config:base" - ], - "labels": [ - "🚨 Dependency Update" ] } diff --git a/.github/workflows/closed-issues-reason.yml b/.github/workflows/closed-issues-reason.yml index 262b9c54b..f20726e9e 100644 --- a/.github/workflows/closed-issues-reason.yml +++ b/.github/workflows/closed-issues-reason.yml @@ -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. diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml index 343808518..82d2ce043 100644 --- a/.github/workflows/pr-labels.yml +++ b/.github/workflows/pr-labels.yml @@ -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
If your changes do not fall into any of these categories, don't worry. You can just ignore this message in that case! 👀 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da11eed9..ccfb3c386 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 182532689..e56960e74 100644 --- a/README.md +++ b/README.md @@ -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.
+You can find Slimefun's community on Discord and connect with **over 4000** users of this plugin from all over the world.
Click the badge down below to join the server for suggestions/questions or other discussions about this plugin.
We are also hosting a community event every so often, join us to find out more.
**Important**: We do **not** accept bug reports on discord, please use our [Issue Tracker](https://github.com/Slimefun/Slimefun4/issues) to submit bug reports! diff --git a/pom.xml b/pom.xml index bb8068aea..ea33f3f23 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,10 @@ https://github.com/Slimefun/Slimefun4 + UTF-8 + + 1.8 1.8 @@ -34,68 +37,81 @@ target/site/jacoco/jacoco.xml - + GitHub Issues https://github.com/Slimefun/Slimefun4/issues - + GNU General Public License v3.0 https://github.com/Slimefun/Slimefun4/blob/master/LICENSE repo - + + + spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots + paper-repo https://papermc.io/repo/repository/maven-public + jitpack.io https://jitpack.io + worldedit-repo https://maven.sk89q.com/repo - codemc-repo - https://repo.codemc.org/repository/maven-public - - + placeholderapi-repo https://repo.extendedclip.com/content/repositories/placeholderapi + + mcmmo-repo + https://nexus.neetgames.com/repository/maven-public + + + walshy-public https://repo.walshy.dev/public - + ${project.basedir}/src/main/java + + ${project.basedir}/src/test/java + + clean package ${project.name} v${project.version} - + org.apache.maven.plugins maven-compiler-plugin 3.8.1 + @@ -105,8 +121,8 @@ - + org.apache.maven.plugins maven-source-plugin 3.2.1 @@ -121,8 +137,8 @@ - + org.apache.maven.plugins maven-surefire-plugin 3.0.0-M5 @@ -133,15 +149,15 @@ - + org.sonarsource.scanner.maven sonar-maven-plugin 3.8.0.2131 - + org.jacoco jacoco-maven-plugin 0.8.6 @@ -166,8 +182,8 @@ - + org.apache.maven.plugins maven-shade-plugin 3.2.4 @@ -210,8 +226,8 @@ - + org.apache.maven.plugins maven-javadoc-plugin 3.2.0 @@ -225,8 +241,8 @@ false -html5 - + ${spigot.javadocs} @@ -315,14 +331,21 @@ org.junit.jupiter junit-jupiter - 5.7.0 + 5.7.1 + test + + + org.mockito + mockito-core + 3.8.0 test com.github.seeseemelk MockBukkit-v1.16 - 0.21.0 + 0.31.0 test + @@ -332,18 +355,12 @@ - - org.mockito - mockito-core - 3.7.7 - test - com.github.TheBusyBiscuit CS-CoreLib2 - 0.29.6 + 0.30.2 compile @@ -355,10 +372,12 @@ com.konghq unirest-java - 3.11.10 + 3.11.11 compile + + com.google.code.gson gson @@ -368,47 +387,42 @@ com.sk89q.worldedit - worldedit-bukkit - 7.2.2 + worldedit-core + 7.2.3 provided + - - - de.schlichtherle - truezip + + * + * + + + + com.sk89q.worldedit + worldedit-bukkit + 7.2.4 + provided + + - net.java.truevfs - truevfs-profile-default_2.13 + + * + * com.gmail.nossr50.mcMMO mcMMO - 2.1.173 + 2.1.181 provided + - - - org.jetbrains - annotations - - - com.sk89q.worldguard - worldguard-core - - - com.sk89q.worldguard - worldguard-legacy - - - - - - net.kyori + + * * @@ -418,12 +432,12 @@ placeholderapi 2.10.9 provided + - - - org.jetbrains - annotations + + * + * @@ -432,18 +446,26 @@ clearlag-core 3.1.6 provided + + + + + * + * + + com.github.LoneDev6 itemsadder-api - 2.1.25 + 2.2.1 provided + - - - org.jetbrains - annotations + + * + * diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AutoDisenchantEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AutoDisenchantEvent.java index 6bba59cae..ad33db977 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AutoDisenchantEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AutoDisenchantEvent.java @@ -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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ExplosiveToolBreakBlocksEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ExplosiveToolBreakBlocksEvent.java new file mode 100644 index 000000000..5ebf4fd49 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ExplosiveToolBreakBlocksEvent.java @@ -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 blocks; + private boolean cancelled; + + @ParametersAreNonnullByDefault + public ExplosiveToolBreakBlocksEvent(Player player, List 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 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(); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java index eef94aec3..015279689 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java @@ -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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java index e282c31af..9763f6a9a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java @@ -64,12 +64,14 @@ public final class SlimefunRegistry { private final List researchRanks = new ArrayList<>(); private final Set 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 tickers = new HashSet<>(); private final Set 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 getBlockHandlers() { return blockHandlers; @@ -354,6 +358,10 @@ public final class SlimefunRegistry { return logDuplicateBlockEntries; } + public boolean useActionbarForTalismans() { + return talismanActionBarMessages; + } + @Nonnull public NamespacedKey getSoulboundDataKey() { return soulboundKey; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java index 7056eadcf..d5334e011 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java @@ -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; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/MultiCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/MultiCategory.java new file mode 100644 index 000000000..3d9dca521 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/MultiCategory.java @@ -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 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); + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SubCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SubCategory.java new file mode 100644 index 000000000..8da6cbafe --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SubCategory.java @@ -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); + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java index 6a21e4ef9..63d9f13e9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java @@ -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 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 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 + } + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java index d9a045fe3..58f776e3f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java @@ -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 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 drops); + + @ParametersAreNonnullByDefault + public void onExplode(Block b, List 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 getIdentifier() { + public final Class getIdentifier() { return BlockBreakHandler.class; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockPlaceHandler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockPlaceHandler.java index c17dbd6a2..c2aabfe11 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockPlaceHandler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockPlaceHandler.java @@ -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 getIdentifier() { + public final Class getIdentifier() { return BlockPlaceHandler.class; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java index a0f7f33e7..b5bad8660 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java @@ -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 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 materials = new ArrayList<>(); for (ItemStack item : items) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/AbstractItemNetwork.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/AbstractItemNetwork.java index 210125e80..3216b0bd5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/AbstractItemNetwork.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/AbstractItemNetwork.java @@ -115,14 +115,14 @@ abstract class AbstractItemNetwork extends Network { if (menu != null) { switch (request.getDirection()) { - case INSERT: - distributeInsertionRequest(inventories, request, menu, iterator, destinations); - break; - case WITHDRAW: - collectExtractionRequest(inventories, request, menu, iterator, providers); - break; - default: - break; + case INSERT: + distributeInsertionRequest(inventories, request, menu, iterator, destinations); + break; + case WITHDRAW: + collectExtractionRequest(inventories, request, menu, iterator, providers); + break; + default: + break; } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java index 9efb04778..debf7618f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNet.java @@ -92,19 +92,19 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner { } switch (id) { - case "CARGO_MANAGER": - return NetworkComponent.REGULATOR; - case "CARGO_NODE": - return NetworkComponent.CONNECTOR; - case "CARGO_NODE_INPUT": - case "CARGO_NODE_OUTPUT": - case "CARGO_NODE_OUTPUT_ADVANCED": - case "CT_IMPORT_BUS": - case "CT_EXPORT_BUS": - case "CHEST_TERMINAL": - return NetworkComponent.TERMINUS; - default: - return null; + case "CARGO_MANAGER": + return NetworkComponent.REGULATOR; + case "CARGO_NODE": + return NetworkComponent.CONNECTOR; + case "CARGO_NODE_INPUT": + case "CARGO_NODE_OUTPUT": + case "CARGO_NODE_OUTPUT_ADVANCED": + case "CT_IMPORT_BUS": + case "CT_EXPORT_BUS": + case "CHEST_TERMINAL": + return NetworkComponent.TERMINUS; + default: + return null; } } @@ -123,24 +123,24 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner { if (to == NetworkComponent.TERMINUS) { String id = BlockStorage.checkID(l); switch (id) { - case "CARGO_NODE_INPUT": - inputNodes.add(l); - break; - case "CARGO_NODE_OUTPUT": - case "CARGO_NODE_OUTPUT_ADVANCED": - outputNodes.add(l); - break; - case "CHEST_TERMINAL": - terminals.add(l); - break; - case "CT_IMPORT_BUS": - imports.add(l); - break; - case "CT_EXPORT_BUS": - exports.add(l); - break; - default: - break; + case "CARGO_NODE_INPUT": + inputNodes.add(l); + break; + case "CARGO_NODE_OUTPUT": + case "CARGO_NODE_OUTPUT_ADVANCED": + outputNodes.add(l); + break; + case "CHEST_TERMINAL": + terminals.add(l); + break; + case "CT_IMPORT_BUS": + imports.add(l); + break; + case "CT_EXPORT_BUS": + exports.add(l); + break; + default: + break; } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java index 790096791..f90981cc3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java @@ -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,31 +66,35 @@ class CargoNetworkTask implements Runnable { public void run() { long timestamp = System.nanoTime(); - // Chest Terminal Code - if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) { - network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs); - } + try { + // Chest Terminal Code + if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) { + network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs); + } - /** - * All operations happen here: Everything gets iterated from the Input Nodes. - * (Apart from ChestTerminal Buses) - */ - SlimefunItem inputNode = SlimefunItems.CARGO_INPUT_NODE.getItem(); - for (Map.Entry entry : inputs.entrySet()) { - long nodeTimestamp = System.nanoTime(); - Location input = entry.getKey(); - Optional attachedBlock = network.getAttachedBlock(input); + /** + * All operations happen here: Everything gets iterated from the Input Nodes. + * (Apart from ChestTerminal Buses) + */ + SlimefunItem inputNode = SlimefunItems.CARGO_INPUT_NODE.getItem(); + for (Map.Entry entry : inputs.entrySet()) { + long nodeTimestamp = System.nanoTime(); + Location input = entry.getKey(); + Optional attachedBlock = network.getAttachedBlock(input); - attachedBlock.ifPresent(block -> routeItems(input, block, entry.getValue(), outputs)); + attachedBlock.ifPresent(block -> routeItems(input, block, entry.getValue(), outputs)); - // This will prevent this timings from showing up for the Cargo Manager - timestamp += SlimefunPlugin.getProfiler().closeEntry(entry.getKey(), inputNode, nodeTimestamp); - } + // This will prevent this timings from showing up for the Cargo Manager + timestamp += SlimefunPlugin.getProfiler().closeEntry(entry.getKey(), inputNode, nodeTimestamp); + } - // Chest Terminal Code - if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) { - // This will deduct any CT timings and attribute them towards the actual terminal - timestamp += network.updateTerminals(chestTerminalInputs); + // Chest Terminal Code + if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) { + // 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 @@ -150,7 +157,7 @@ class CargoNetworkTask implements Runnable { Deque 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); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoUtils.java index 69f993a0c..b20a03e31 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoUtils.java @@ -68,19 +68,19 @@ final class CargoUtils { Material type = block.getType(); switch (type) { - case CHEST: - case TRAPPED_CHEST: - case FURNACE: - case DISPENSER: - case DROPPER: - case HOPPER: - case BREWING_STAND: - case BARREL: - case BLAST_FURNACE: - case SMOKER: - return true; - default: - return SlimefunTag.SHULKER_BOXES.isTagged(type); + case CHEST: + case TRAPPED_CHEST: + case FURNACE: + case DISPENSER: + case DROPPER: + case HOPPER: + case BREWING_STAND: + case BARREL: + case BLAST_FURNACE: + case SMOKER: + return true; + default: + return SlimefunTag.SHULKER_BOXES.isTagged(type); } } @@ -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); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/ItemFilter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/ItemFilter.java index fb791f8d7..713b3395e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/ItemFilter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/ItemFilter.java @@ -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,23 +82,45 @@ class ItemFilter implements Predicate { 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 - clear(true); } else { - this.items.clear(); - this.checkLore = Objects.equals(blockData.getString("filter-lore"), "true"); - this.rejectOnMatch = !Objects.equals(blockData.getString("filter-type"), "whitelist"); + try { + CargoNode node = (CargoNode) item; - for (int slot : CargoUtils.getFilteringSlots()) { - ItemStack stack = menu.getItemInSlot(slot); + if (!node.hasItemFilter()) { + // Node does not have a filter, allow everything + clear(true); + } else { + int[] slots = CargoUtils.getFilteringSlots(); + int inventorySize = menu.toInventory().getSize(); - if (stack != null && stack.getType() != Material.AIR) { - this.items.add(new ItemStackWrapper(stack)); + 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 : slots) { + ItemStack stack = menu.getItemInSlot(slot); + + if (stack != null && stack.getType() != Material.AIR) { + this.items.add(new ItemStackWrapper(stack)); + } + } } + } catch (Exception | LinkageError x) { + item.error("Something went wrong while updating the ItemFilter for this cargo node.", x); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java index 0be2f59db..d91e4c2b6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java @@ -75,14 +75,14 @@ public class EnergyNet extends Network implements HologramOwner { return null; } else { switch (component.getEnergyComponentType()) { - case CONNECTOR: - case CAPACITOR: - return NetworkComponent.CONNECTOR; - case CONSUMER: - case GENERATOR: - return NetworkComponent.TERMINUS; - default: - return null; + case CONNECTOR: + case CAPACITOR: + return NetworkComponent.CONNECTOR; + case CONSUMER: + case GENERATOR: + return NetworkComponent.TERMINUS; + default: + return null; } } } @@ -98,21 +98,21 @@ public class EnergyNet extends Network implements HologramOwner { if (component != null) { switch (component.getEnergyComponentType()) { - case CAPACITOR: - capacitors.put(l, component); - break; - case CONSUMER: - consumers.put(l, component); - break; - case GENERATOR: - if (component instanceof EnergyNetProvider) { - generators.put(l, (EnergyNetProvider) component); - } else if (component instanceof SlimefunItem) { - ((SlimefunItem) component).warn("This Item is marked as a GENERATOR but does not implement the interface EnergyNetProvider!"); - } - break; - default: - break; + case CAPACITOR: + capacitors.put(l, component); + break; + case CONSUMER: + consumers.put(l, component); + break; + case GENERATOR: + if (component instanceof EnergyNetProvider) { + generators.put(l, (EnergyNetProvider) component); + } else if (component instanceof SlimefunItem) { + ((SlimefunItem) component).warn("This Item is marked as a GENERATOR but does not implement the interface EnergyNetProvider!"); + } + break; + default: + break; } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BackupService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BackupService.java index cacc4f411..a4827a419 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BackupService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BackupService.java @@ -29,38 +29,51 @@ 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() { - List backups = Arrays.asList(directory.listFiles()); + // Make sure that the directory exists. + if (directory.exists()) { + List backups = Arrays.asList(directory.listFiles()); - if (backups.size() > MAX_BACKUPS) { - try { - purgeBackups(backups); - } catch (IOException e) { - SlimefunPlugin.logger().log(Level.WARNING, "Could not delete an old backup", e); - } - } - - File file = new File(directory, format.format(LocalDateTime.now()) + ".zip"); - - if (!file.exists()) { - try { - if (file.createNewFile()) { - try (ZipOutputStream output = new ZipOutputStream(new FileOutputStream(file))) { - createBackup(output); - } - - SlimefunPlugin.logger().log(Level.INFO, "Backed up Slimefun data to: {0}", file.getName()); - } else { - SlimefunPlugin.logger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName()); + if (backups.size() > MAX_BACKUPS) { + try { + purgeBackups(backups); + } catch (IOException e) { + SlimefunPlugin.logger().log(Level.WARNING, "Could not delete an old backup", e); + } + } + + File file = new File(directory, format.format(LocalDateTime.now()) + ".zip"); + + if (!file.exists()) { + try { + if (file.createNewFile()) { + try (ZipOutputStream output = new ZipOutputStream(new FileOutputStream(file))) { + createBackup(output); + } + + SlimefunPlugin.logger().log(Level.INFO, "Backed up Slimefun data to: {0}", file.getName()); + } else { + SlimefunPlugin.logger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName()); + } + } catch (IOException x) { + SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion()); } - } catch (IOException x) { - SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Error occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion()); } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java index c525d312e..462ec8f04 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java @@ -138,29 +138,29 @@ public class BlockDataService implements Keyed { } switch (type) { - case PLAYER_HEAD: - case PLAYER_WALL_HEAD: - case CHEST: - case DISPENSER: - case BREWING_STAND: - case DROPPER: - case FURNACE: - case BLAST_FURNACE: - case HOPPER: - case LECTERN: - case JUKEBOX: - case ENDER_CHEST: - case ENCHANTING_TABLE: - case DAYLIGHT_DETECTOR: - case SMOKER: - case BARREL: - case SPAWNER: - case BEACON: - // All of the above Materials are Tile Entities - return true; - default: - // Otherwise we assume they're not Tile Entities - return false; + case PLAYER_HEAD: + case PLAYER_WALL_HEAD: + case CHEST: + case DISPENSER: + case BREWING_STAND: + case DROPPER: + case FURNACE: + case BLAST_FURNACE: + case HOPPER: + case LECTERN: + case JUKEBOX: + case ENDER_CHEST: + case ENCHANTING_TABLE: + case DAYLIGHT_DETECTOR: + case SMOKER: + case BARREL: + case SPAWNER: + case BEACON: + // All of the above Materials are Tile Entities + return true; + default: + // Otherwise we assume they're not Tile Entities + return false; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java index ad4bee64f..d70276444 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MetricsService.java @@ -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(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java index 694f1b352..ccc8785ab 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java @@ -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> 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); + } + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java index 920896ab2..e32ce2428 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java @@ -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 getLore(@Nonnull SlimefunItem item) { - List lore = config.getStringList(item.getId() + ".lore"); - return lore == null ? Arrays.asList("LORE NOT FOUND") : lore; + return config.getStringList(item.getId() + ".lore"); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/SlimefunLocalization.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/SlimefunLocalization.java index 79523c45a..02f00f8f8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/SlimefunLocalization.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/SlimefunLocalization.java @@ -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)))); } } - @Override - public void sendMessage(CommandSender sender, String key) { - sendMessage(sender, key, true); - } + public void sendActionbarMessage(@Nonnull Player player, @Nonnull String key, boolean addPrefix) { + String prefix = addPrefix ? getPrefix() : ""; + String message = ChatColors.color(prefix + getMessage(player, key)); - public void sendMessage(CommandSender sender, String key, UnaryOperator function) { - sendMessage(sender, key, true, function); + BaseComponent[] components = TextComponent.fromLegacyText(message); + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, components); } @Override - public void sendMessage(CommandSender sender, String key, boolean addPrefix, UnaryOperator function) { + public void sendMessage(CommandSender recipient, String key) { + sendMessage(recipient, key, true); + } + + public void sendMessage(CommandSender recipient, String key, UnaryOperator function) { + sendMessage(recipient, key, true, function); + } + + @Override + public void sendMessage(CommandSender recipient, String key, boolean addPrefix, UnaryOperator 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 function) { + public void sendMessages(CommandSender recipient, String key, boolean addPrefix, UnaryOperator 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 function) { - sendMessages(sender, key, true, function); + public void sendMessages(CommandSender recipient, String key, UnaryOperator function) { + sendMessages(recipient, key, true, function); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java index 1861c7ed8..7179dc1c7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java @@ -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); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java index 84d183605..a9ee7b170 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -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%"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java index 77f8c3ecf..545e4f33a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java @@ -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 - ticker.halt(); - ticker.run(); + 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()) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java index f45f47272..f3594dcd8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java @@ -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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java index 2f8964939..e5fc16d50 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java @@ -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; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java new file mode 100644 index 000000000..4ea8cefd0 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java @@ -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 drops) { + onBlockBreak(e.getBlock()); + } + + @Override + public void onAndroidBreak(AndroidMineEvent e) { + onBlockBreak(e.getBlock()); + } + + @Override + public void onExplode(Block b, List drops) { + onBlockBreak(b); + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/package-info.java new file mode 100644 index 000000000..a0770977f --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/package-info.java @@ -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; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientPedestal.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientPedestal.java index 80cc207cd..a302e2dae 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientPedestal.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientPedestal.java @@ -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,21 +54,28 @@ public class AncientPedestal extends SimpleSlimefunItem { 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) -> { - Optional entity = getPlacedItem(b); + addItemHandler(onBreak()); + } - if (entity.isPresent()) { - Item stack = entity.get(); + @Nonnull + private BlockBreakHandler onBreak() { + return new SimpleBlockBreakHandler() { - if (stack.isValid()) { - stack.removeMetadata("no_pickup", SlimefunPlugin.instance()); - b.getWorld().dropItem(b.getLocation(), getOriginalItemStack(stack)); - stack.remove(); + @Override + public void onBlockBreak(@Nonnull Block b) { + Optional entity = getPlacedItem(b); + + if (entity.isPresent()) { + Item stack = entity.get(); + + if (stack.isValid()) { + stack.removeMetadata("no_pickup", SlimefunPlugin.instance()); + b.getWorld().dropItem(b.getLocation(), getOriginalItemStack(stack)); + stack.remove(); + } } } - - return true; - }); + }; } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java index 51c458d5a..77bb55601 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java @@ -38,20 +38,20 @@ public class ButcherAndroid extends ProgrammableAndroid { boolean attack = false; switch (face) { - case NORTH: - attack = n.getLocation().getZ() < b.getZ(); - break; - case EAST: - attack = n.getLocation().getX() > b.getX(); - break; - case SOUTH: - attack = n.getLocation().getZ() > b.getZ(); - break; - case WEST: - attack = n.getLocation().getX() < b.getX(); - break; - default: - break; + case NORTH: + attack = n.getLocation().getZ() < b.getZ(); + break; + case EAST: + attack = n.getLocation().getX() > b.getX(); + break; + case SOUTH: + attack = n.getLocation().getZ() > b.getZ(); + break; + case WEST: + attack = n.getLocation().getX() < b.getX(); + break; + default: + break; } if (attack) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java index 44948ab4b..1bafdcd3f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java @@ -64,22 +64,22 @@ public class FarmerAndroid extends ProgrammableAndroid { Random random = ThreadLocalRandom.current(); switch (crop) { - case WHEAT: - return new ItemStack(Material.WHEAT, random.nextInt(2) + 1); - case POTATOES: - return new ItemStack(Material.POTATO, random.nextInt(3) + 1); - case CARROTS: - return new ItemStack(Material.CARROT, random.nextInt(3) + 1); - case BEETROOTS: - return new ItemStack(Material.BEETROOT, random.nextInt(3) + 1); - case COCOA: - return new ItemStack(Material.COCOA_BEANS, random.nextInt(3) + 1); - case NETHER_WART: - return new ItemStack(Material.NETHER_WART, random.nextInt(3) + 1); - case SWEET_BERRY_BUSH: - return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1); - default: - return null; + case WHEAT: + return new ItemStack(Material.WHEAT, random.nextInt(2) + 1); + case POTATOES: + return new ItemStack(Material.POTATO, random.nextInt(3) + 1); + case CARROTS: + return new ItemStack(Material.CARROT, random.nextInt(3) + 1); + case BEETROOTS: + return new ItemStack(Material.BEETROOT, random.nextInt(3) + 1); + case COCOA: + return new ItemStack(Material.COCOA_BEANS, random.nextInt(3) + 1); + case NETHER_WART: + return new ItemStack(Material.NETHER_WART, random.nextInt(3) + 1); + case SWEET_BERRY_BUSH: + return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1); + default: + return null; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java index 4328e6c0e..8e87a3e72 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java @@ -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. + *

+ * 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 firesEvent = new ItemSetting<>("trigger-event-for-generators", false); + private final ItemSetting 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 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 drops = block.getDrops(effectivePickaxe); @@ -83,17 +110,9 @@ public class MinerAndroid extends ProgrammableAndroid { } // We only want to break non-Slimefun blocks - SlimefunItem blockId = BlockStorage.check(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); move(b, face, block); } } else { @@ -104,4 +123,32 @@ public class MinerAndroid extends ProgrammableAndroid { } } + @ParametersAreNonnullByDefault + private void breakBlock(BlockMenu menu, Collection drops, Block block) { + // Push our drops to the inventory + for (ItemStack drop : drops) { + menu.pushItem(drop, getOutputSlots()); + } + + // Check if Block Generator optimizations should be applied. + if (applyOptimizations.getValue()) { + InfiniteBlockGenerator generator = InfiniteBlockGenerator.findAt(block); + + // If we found a generator, continue. + if (generator != null) { + if (firesEvent.getValue()) { + generator.callEvent(block); + } + + // "poof" a "new" block was generated + block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.075F, 0.8F); + block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getX() + 0.5, block.getY() + 1.25, block.getZ() + 0.5, 8, 0.5, 0.5, 0.5, 0.015); + } else { + block.setType(Material.AIR); + } + } else { + block.setType(Material.AIR); + } + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java index 525739b61..806384d2d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java @@ -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 @@ -194,14 +195,14 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, */ public AndroidFuelSource getFuelSource() { switch (getTier()) { - case 1: - return AndroidFuelSource.SOLID; - case 2: - return AndroidFuelSource.LIQUID; - case 3: - return AndroidFuelSource.NUCLEAR; - default: - throw new IllegalStateException("Cannot convert the following Android tier to a fuel type: " + getTier()); + case 1: + return AndroidFuelSource.SOLID; + case 2: + return AndroidFuelSource.LIQUID; + case 3: + return AndroidFuelSource.NUCLEAR; + default: + throw new IllegalStateException("Cannot convert the following Android tier to a fuel type: " + getTier()); } } @@ -564,38 +565,38 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, private void registerDefaultFuelTypes() { switch (getFuelSource()) { - case SOLID: - registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK))); - registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD))); - registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK))); + case SOLID: + registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK))); + registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD))); + registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK))); - // Coal & Charcoal - registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL))); - registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL))); + // Coal & Charcoal + registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL))); + registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL))); - // Logs - for (Material mat : Tag.LOGS.getValues()) { - registerFuelType(new MachineFuel(2, new ItemStack(mat))); - } + // Logs + for (Material mat : Tag.LOGS.getValues()) { + registerFuelType(new MachineFuel(2, new ItemStack(mat))); + } - // Wooden Planks - for (Material mat : Tag.PLANKS.getValues()) { - registerFuelType(new MachineFuel(1, new ItemStack(mat))); - } + // Wooden Planks + for (Material mat : Tag.PLANKS.getValues()) { + registerFuelType(new MachineFuel(1, new ItemStack(mat))); + } - break; - case LIQUID: - registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET))); - registerFuelType(new MachineFuel(200, SlimefunItems.OIL_BUCKET)); - registerFuelType(new MachineFuel(500, SlimefunItems.FUEL_BUCKET)); - break; - case NUCLEAR: - registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM)); - registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM)); - registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM)); - break; - default: - throw new IllegalStateException("Unhandled Fuel Source: " + getFuelSource()); + break; + case LIQUID: + registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET))); + registerFuelType(new MachineFuel(200, SlimefunItems.OIL_BUCKET)); + registerFuelType(new MachineFuel(500, SlimefunItems.FUEL_BUCKET)); + break; + case NUCLEAR: + registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM)); + registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM)); + registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM)); + break; + default: + throw new IllegalStateException("Unhandled Fuel Source: " + getFuelSource()); } } @@ -685,26 +686,26 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, BlockFace face = rotationData == null ? BlockFace.NORTH : BlockFace.valueOf(rotationData); switch (instruction) { - case START: - case WAIT: - // We are "waiting" here, so we only move a step forward - BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); - break; - case REPEAT: - // "repeat" just means, we reset our index - BlockStorage.addBlockInfo(b, "index", String.valueOf(0)); - break; - case CHOP_TREE: - // We only move to the next step if we finished chopping wood - if (chopTree(b, inv, face)) { + case START: + case WAIT: + // We are "waiting" here, so we only move a step forward BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); - } - break; - default: - // We set the index here in advance to fix moving android issues - BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); - instruction.execute(this, b, inv, face); - break; + break; + case REPEAT: + // "repeat" just means, we reset our index + BlockStorage.addBlockInfo(b, "index", String.valueOf(0)); + break; + case CHOP_TREE: + // We only move to the next step if we finished chopping wood + if (chopTree(b, inv, face)) { + BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); + } + break; + default: + // We set the index here in advance to fix moving android issues + BlockStorage.addBlockInfo(b, "index", String.valueOf(index)); + instruction.execute(this, b, inv, face); + break; } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java index 2d79132b2..eb5775bf1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java @@ -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 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 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); + } + } + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java index f5800321d..445a96bc1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java @@ -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> blacklist = new MaterialTagSetting("unplaceable-blocks", SlimefunTag.UNBREAKABLE_MATERIALS); + private final ItemSetting> 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 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 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,68 +202,78 @@ public class BlockPlacer extends SlimefunItem { if (!e.isCancelled()) { boolean hasItemHandler = sfItem.callItemHandler(BlockPlaceHandler.class, handler -> { if (handler.isBlockPlacerAllowed()) { - block.setType(item.getType()); - block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, item.getType()); + schedulePlacement(block, dispenser.getInventory(), item, () -> { + block.setType(item.getType()); + BlockStorage.store(block, sfItem.getId()); - 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) { - 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); - } + schedulePlacement(block, dispenser.getInventory(), item, () -> { + block.setType(item.getType()); + BlockStorage.store(block, sfItem.getId()); + }); } } } + @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()) { - facedBlock.setType(item.getType()); + schedulePlacement(facedBlock, dispenser.getInventory(), item, () -> { + facedBlock.setType(item.getType()); - if (item.hasItemMeta()) { - ItemMeta meta = item.getItemMeta(); + if (item.hasItemMeta()) { + ItemMeta meta = item.getItemMeta(); - if (meta.hasDisplayName()) { - BlockStateSnapshotResult blockState = PaperLib.getBlockState(facedBlock, false); + if (meta.hasDisplayName()) { + BlockStateSnapshotResult blockState = PaperLib.getBlockState(facedBlock, false); - if ((blockState.getState() instanceof Nameable)) { - Nameable nameable = ((Nameable) blockState.getState()); - nameable.setCustomName(meta.getDisplayName()); + if ((blockState.getState() instanceof Nameable)) { + Nameable nameable = ((Nameable) blockState.getState()); + nameable.setCustomName(meta.getDisplayName()); - if (blockState.isSnapshot()) { - // Update block state after changing name - blockState.getState().update(true, false); + if (blockState.isSnapshot()) { + // Update block state after changing name + blockState.getState().update(true, false); + } } } + } - - } - - facedBlock.getWorld().playEffect(facedBlock.getLocation(), Effect.STEP_SOUND, item.getType()); - - if (dispenser.getInventory().containsAtLeast(item, 2)) { - dispenser.getInventory().removeItem(new CustomItem(item, 1)); - } else { - SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L); - } + }); } } + + @ParametersAreNonnullByDefault + private void schedulePlacement(Block b, Inventory inv, ItemStack item, Runnable runnable) { + // We need to delay this due to Dispenser-Inventory synchronization issues in Spigot. + SlimefunPlugin.runSync(() -> { + // Make sure the Block has not been occupied yet + if (b.isEmpty()) { + // Only remove 1 item. + ItemStack removedItem = item.clone(); + removedItem.setAmount(1); + + // Play particles + b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, item.getType()); + + // Make sure the item was actually removed (fixes #2817) + + try { + if (inv.removeItem(removedItem).isEmpty()) { + runnable.run(); + } + } catch (Exception x) { + error("An Exception was thrown while a BlockPlacer was performing its action", x); + } + } + }, 2L); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java index 9f84d8bf9..4c9a6563c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java @@ -8,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 implements RecipeDisplayItem { + private final ItemSetting allowWaterInNether = new ItemSetting<>("allow-water-in-nether", false); private final List 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 implements Rec return recipes; } + @Nonnull private List getMachineRecipes() { List items = new LinkedList<>(); @@ -113,11 +129,11 @@ public class Crucible extends SimpleSlimefunItem 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 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); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java index 67d40365b..0e853ad6e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java @@ -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) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/IgnitionChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/IgnitionChamber.java new file mode 100644 index 000000000..d2a558362 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/IgnitionChamber.java @@ -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 { + + @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 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); + } + } + } + } + }; + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/OutputChest.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/OutputChest.java new file mode 100644 index 000000000..931ad4180 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/OutputChest.java @@ -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 { + + @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 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); + } + } + } + } + }; + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java index b06e8668f..7145619be 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java @@ -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) -> { - BlockMenu inv = BlockStorage.getInventory(b); + addItemHandler(onBreak()); + } - if (inv != null) { - inv.dropItems(b.getLocation(), SLOTS); + @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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java index 508d70ddd..979c6c0d5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java @@ -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) -> { - removeHologram(b); - return true; - }); + addItemHandler(onBreak()); + } + + @Nonnull + private BlockBreakHandler onBreak() { + return new SimpleBlockBreakHandler() { + + @Override + public void onBlockBreak(@Nonnull Block b) { + removeHologram(b); + } + }; } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java index c5828d573..0c2fc06bb 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java @@ -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(); + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java index 6d33b69e2..bfaefdcfc 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java @@ -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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java index e1bada9b5..599828883 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java @@ -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,18 +112,23 @@ public class ReactorAccessPort extends SlimefunItem { } } }; + } - registerBlockHandler(getId(), (p, b, tool, reason) -> { - BlockMenu inv = BlockStorage.getInventory(b); + @Nonnull + private BlockBreakHandler onBreak() { + return new SimpleBlockBreakHandler() { - if (inv != null) { - inv.dropItems(b.getLocation(), getFuelSlots()); - inv.dropItems(b.getLocation(), getCoolantSlots()); - inv.dropItems(b.getLocation(), getOutputSlots()); + @Override + public void onBlockBreak(@Nonnull Block b) { + BlockMenu inv = BlockStorage.getInventory(b); + + if (inv != null) { + inv.dropItems(b.getLocation(), getFuelSlots()); + inv.dropItems(b.getLocation(), getCoolantSlots()); + inv.dropItems(b.getLocation(), getOutputSlots()); + } } - - return true; - }); + }; } private void constructMenu(@Nonnull BlockMenuPreset preset) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java index f8735c063..3ab81a185 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java @@ -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) -> { - removeHologram(b); - return true; - }); + addItemHandler(onBreak()); + } + + @Nonnull + private BlockBreakHandler onBreak() { + return new SimpleBlockBreakHandler() { + + @Override + public void onBlockBreak(@Nonnull Block b) { + removeHologram(b); + } + }; } @Nonnull diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java index 4e0e59903..4494fb95c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java @@ -110,14 +110,14 @@ public class MultiTool extends SlimefunItem implements Rechargeable { return (e, item, offhand) -> { // Fixes #2217 - Prevent them from being used to shear entities switch (e.getRightClicked().getType()) { - case MUSHROOM_COW: - case SHEEP: - case SNOWMAN: - SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears"); - e.setCancelled(true); - break; - default: - break; + case MUSHROOM_COW: + case SHEEP: + case SNOWMAN: + SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears"); + e.setCancelled(true); + break; + default: + break; } }; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java index 065f57e1c..dbc7c49ee 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java @@ -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); - -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java index 45ca141b7..ec01e2299 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java @@ -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 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 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 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 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"; - } - -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java index e1550792e..d55af6b1b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java @@ -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 enchantments = new HashMap<>(); - int amount = 0; - EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); - - for (Map.Entry 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 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"; - } - -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java index 93031d45c..69295f738 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java @@ -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 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)); } @@ -308,4 +314,4 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I craftingRecipes.put(builder.toString(), RecipeType.getRecipeOutputList(machine, inputs)); } } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AbstractGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AbstractGrowthAccelerator.java new file mode 100644 index 000000000..e7e57a2ea --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AbstractGrowthAccelerator.java @@ -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); + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java similarity index 98% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java index c8e774573..1629bc8bf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/CropGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java similarity index 98% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/CropGrowthAccelerator.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java index f132a751b..893f3d070 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/CropGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/TreeGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java similarity index 98% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/TreeGrowthAccelerator.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java index 5e3b21ba2..b3ef10fb6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/TreeGrowthAccelerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/package-info.java new file mode 100644 index 000000000..96accec69 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/package-info.java @@ -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; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoDisenchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoDisenchanter.java new file mode 100644 index 000000000..7af3f137f --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoDisenchanter.java @@ -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 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 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 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 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"; + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java new file mode 100644 index 000000000..637f6ddf7 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java @@ -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 enchantments = new HashMap<>(); + int amount = 0; + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + + for (Map.Entry 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 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"; + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/BookBinder.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java similarity index 80% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/BookBinder.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java index 5f8355715..009c75ea4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/BookBinder.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java @@ -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 storedTargetEnchantments = targetMeta.getStoredEnchants(); Map 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 entry : ech2.entrySet()) { for (Map.Entry 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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/package-info.java new file mode 100644 index 000000000..b4e98ffd6 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/package-info.java @@ -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; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/AbstractEntityAssembler.java similarity index 99% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/AbstractEntityAssembler.java index 8c9959b58..1f887237f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/AbstractEntityAssembler.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/XPCollector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java similarity index 94% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/XPCollector.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java index ea96f836a..d9aeb5f5d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/XPCollector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java @@ -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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/IronGolemAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/IronGolemAssembler.java similarity index 98% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/IronGolemAssembler.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/IronGolemAssembler.java index 71426fc7d..398b23f8b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/IronGolemAssembler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/IronGolemAssembler.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/WitherAssembler.java similarity index 98% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/WitherAssembler.java index 07b4c34e2..51801cd37 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/WitherAssembler.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/package-info.java new file mode 100644 index 000000000..d7723caf7 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/package-info.java @@ -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; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java index 58c594f2e..2bf988182 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java @@ -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 explosionsQueue = new HashSet<>(); - private final MachineProcessor processor = new MachineProcessor<>(); @ParametersAreNonnullByDefault @@ -109,20 +110,7 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram } }; - registerBlockHandler(getId(), (p, b, tool, reason) -> { - BlockMenu inv = BlockStorage.getInventory(b); - - if (inv != null) { - inv.dropItems(b.getLocation(), getFuelSlots()); - inv.dropItems(b.getLocation(), getCoolantSlots()); - inv.dropItems(b.getLocation(), getOutputSlots()); - } - - processor.removeOperation(b); - removeHologram(b); - return true; - }); - + addItemHandler(onBreak()); registerDefaultFuelTypes(); } @@ -131,6 +119,26 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram return processor; } + @Nonnull + private BlockBreakHandler onBreak() { + return new SimpleBlockBreakHandler() { + + @Override + public void onBlockBreak(@Nonnull Block b) { + BlockMenu inv = BlockStorage.getInventory(b); + + if (inv != null) { + inv.dropItems(b.getLocation(), getFuelSlots()); + inv.dropItems(b.getLocation(), getCoolantSlots()); + inv.dropItems(b.getLocation(), getOutputSlots()); + } + + processor.removeOperation(b); + removeHologram(b); + } + }; + } + protected void updateInventory(@Nonnull BlockMenu menu, @Nonnull Block b) { ReactorMode mode = getReactorMode(b.getLocation()); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java index a0dc9eb4c..05b151298 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java @@ -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 getDisplayRecipes() { List displayRecipes = new LinkedList<>(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java index ecdf45d34..b47aeb4dd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java @@ -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 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 imp return capacity; } + @Nonnull private BlockPlaceHandler onPlace() { return new BlockPlaceHandler(false) { @@ -50,6 +54,19 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem imp }; } + @Nonnull + private BlockBreakHandler onBreak() { + return new BlockBreakHandler(false, false) { + + @Override + public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List 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(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java index 4ca91cec6..1ba0242f7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java @@ -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 { private static final double RANGE = 1.5; private final Map> 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 { List 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 { 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 { }; } - 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 { 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 { } } - 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 { return level; } - private void removeIllegalEnchantments(ItemStack target, List potentialEnchantments) { + private void removeIllegalEnchantments(@Nonnull ItemStack target, @Nonnull List potentialEnchantments) { for (Enchantment enchantment : target.getEnchantments().keySet()) { Iterator iterator = potentialEnchantments.iterator(); @@ -169,7 +182,7 @@ public class EnchantmentRune extends SimpleSlimefunItem { } } - private boolean findCompatibleItem(Entity n) { + private boolean findCompatibleItem(@Nonnull Entity n) { if (n instanceof Item) { Item item = (Item) n; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java index dfde7821e..997a08acc 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java @@ -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 { 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 { }; } - 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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java index 2d9959a11..0b6758bbe 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java @@ -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 allowEnchantmentBooks = new ItemSetting<>("allow-enchantment-books", false); + private final Set 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 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(); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java index 203ee5b74..8c9f34f6f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java @@ -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]; + @Nullable + protected final String getMessageSuffix() { + return suffix; + } - if (SlimefunUtils.isItemSimilar(item, talismanItem, true, false)) { - ItemUtils.consumeItem(item, false); - return; + /** + * 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; - } - } \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java index ff29a0426..539583f19 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java index 9b4edbbb1..0b86ee8c3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java index 632e95f0a..2dd1632a2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java @@ -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) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java index ff68a91e1..7d66099fc 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java @@ -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); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java index a55a804c2..5aeab8fb5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java @@ -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); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java index 3c1533a98..54d28c391 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java @@ -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 diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java index fd0056e6a..d98935eb1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java @@ -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); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java index 83b044271..1efbe73f3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java @@ -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); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java index bb857f3d5..87df574ae 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java @@ -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()); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java index 0d447e193..f119ce20b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java @@ -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 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) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java index 157b26954..06ec908ed 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java @@ -120,21 +120,21 @@ public class IndustrialMiner extends MultiBlockMachine { Random random = ThreadLocalRandom.current(); switch (ore) { - case COAL_ORE: - return new ItemStack(Material.COAL); - case DIAMOND_ORE: - return new ItemStack(Material.DIAMOND); - case EMERALD_ORE: - return new ItemStack(Material.EMERALD); - case NETHER_QUARTZ_ORE: - return new ItemStack(Material.QUARTZ); - case REDSTONE_ORE: - return new ItemStack(Material.REDSTONE, 4 + random.nextInt(2)); - case LAPIS_ORE: - return new ItemStack(Material.LAPIS_LAZULI, 4 + random.nextInt(4)); - default: - // This includes Iron and Gold ore (and Ancient Debris) - return new ItemStack(ore); + case COAL_ORE: + return new ItemStack(Material.COAL); + case DIAMOND_ORE: + return new ItemStack(Material.DIAMOND); + case EMERALD_ORE: + return new ItemStack(Material.EMERALD); + case NETHER_QUARTZ_ORE: + return new ItemStack(Material.QUARTZ); + case REDSTONE_ORE: + return new ItemStack(Material.REDSTONE, 4 + random.nextInt(2)); + case LAPIS_ORE: + return new ItemStack(Material.LAPIS_LAZULI, 4 + random.nextInt(4)); + default: + // This includes Iron and Gold ore (and Ancient Debris) + return new ItemStack(ore); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java index da52e9750..2aedace52 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java @@ -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 implements NotPlaceable, DamageableItem { +public class ExplosiveTool extends SimpleSlimefunItem implements NotPlaceable, DamageableItem { private final ItemSetting damageOnUse = new ItemSetting<>("damage-on-use", true); private final ItemSetting callExplosionEvent = new ItemSetting<>("call-explosion-event", false); @@ -51,6 +53,7 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla addItemSetting(damageOnUse, callExplosionEvent); } + @Nonnull @Override public ToolUseHandler getItemHandler() { return (e, tool, fortune, drops) -> { @@ -67,6 +70,8 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla @ParametersAreNonnullByDefault private void breakBlocks(Player p, ItemStack item, Block b, List blocks, List drops) { + List 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 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 findBlocks(Block b) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java index 16848bbd7..c2cada5b9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java @@ -96,10 +96,6 @@ public class GoldPan extends SimpleSlimefunItem 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 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 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 implements Recip * * @return the {@link EntityInteractHandler} of this {@link SlimefunItem} */ + @Nonnull public EntityInteractHandler onEntityInteract() { return (e, item, offHand) -> { if (!(e.getRightClicked() instanceof ItemFrame)) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java index aee48bdf8..b93704cb9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java @@ -56,39 +56,39 @@ public class SwordOfBeheading extends SimpleSlimefunItem { Random random = ThreadLocalRandom.current(); switch (e.getEntityType()) { - case ZOMBIE: - if (random.nextInt(100) < chanceZombie.getValue()) { - e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD)); - } - break; - case SKELETON: - if (random.nextInt(100) < chanceSkeleton.getValue()) { - e.getDrops().add(new ItemStack(Material.SKELETON_SKULL)); - } - break; - case CREEPER: - if (random.nextInt(100) < chanceCreeper.getValue()) { - e.getDrops().add(new ItemStack(Material.CREEPER_HEAD)); - } - break; - case WITHER_SKELETON: - if (random.nextInt(100) < chanceWitherSkeleton.getValue()) { - e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL)); - } - break; - case PLAYER: - if (random.nextInt(100) < chancePlayer.getValue()) { - ItemStack skull = new ItemStack(Material.PLAYER_HEAD); + case ZOMBIE: + if (random.nextInt(100) < chanceZombie.getValue()) { + e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD)); + } + break; + case SKELETON: + if (random.nextInt(100) < chanceSkeleton.getValue()) { + e.getDrops().add(new ItemStack(Material.SKELETON_SKULL)); + } + break; + case CREEPER: + if (random.nextInt(100) < chanceCreeper.getValue()) { + e.getDrops().add(new ItemStack(Material.CREEPER_HEAD)); + } + break; + case WITHER_SKELETON: + if (random.nextInt(100) < chanceWitherSkeleton.getValue()) { + e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL)); + } + break; + case PLAYER: + if (random.nextInt(100) < chancePlayer.getValue()) { + ItemStack skull = new ItemStack(Material.PLAYER_HEAD); - ItemMeta meta = skull.getItemMeta(); - ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity()); - skull.setItemMeta(meta); + ItemMeta meta = skull.getItemMeta(); + ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity()); + skull.setItemMeta(meta); - e.getDrops().add(skull); - } - break; - default: - break; + e.getDrops().add(skull); + } + break; + default: + break; } }; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java index 646ed0476..58c7d1a3c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java @@ -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 result = getRecipeOutput(catalyst, input); + if (result.isPresent()) { - if (Slimefun.hasUnlocked(p, result.get(), true)) { + if (SlimefunUtils.canPlayerUseItem(p, result.get(), true)) { List 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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java index 99da8142f..8d800cb10 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java @@ -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 { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java index 3ac4ec600..6fc179556 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java @@ -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); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java index a97cf123e..e13610986 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java @@ -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 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 drops) { + private void callBlockHandler(BlockBreakEvent e, ItemStack item, List 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 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 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); + } + } + } } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java index bd3b8f760..42bec19e6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java @@ -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); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java index 87a5a88a6..c2f836bdd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java @@ -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; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java index 8b065acc6..9b40e0fc1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java @@ -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); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java index c527cc7c5..7026f4f4c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java @@ -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 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 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 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) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java index 2e2b0fecf..f3002e775 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java @@ -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) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MiningAndroidListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MiningAndroidListener.java new file mode 100644 index 000000000..34a43fcdf --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MiningAndroidListener.java @@ -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); + } + }); + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java index d684a274b..0d40e4e3e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java @@ -62,8 +62,13 @@ public class MultiBlockListener implements Listener { e.setCancelled(true); MultiBlock mb = multiblocks.getLast(); - mb.getSlimefunItem().callItemHandler(MultiBlockInteractionHandler.class, handler -> handler.onInteract(p, mb, b)); - Bukkit.getPluginManager().callEvent(new MultiBlockInteractEvent(p, mb, b, e.getBlockFace())); + 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)); + } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java index 0db770f40..5c04c7e49 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java @@ -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); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java index bfd4d657a..fdbd271e2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java @@ -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); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java index ee276c3d3..d17fa55d4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java @@ -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 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 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,27 +133,31 @@ public class SlimefunItemInteractListener implements Listener { } @ParametersAreNonnullByDefault - private void openInventory(Player p, String id, Block clickedBlock, PlayerRightClickEvent event) { - if (!p.isSneaking() || event.getItem().getType() == Material.AIR) { - event.getInteractEvent().setCancelled(true); + 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); - } else { - SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); - } - } else if (BlockStorage.getStorage(clickedBlock.getWorld()).hasInventory(clickedBlock.getLocation())) { - BlockMenu menu = BlockStorage.getInventory(clickedBlock.getLocation()); + if (menu.canOpen(clickedBlock, p)) { + menu.open(p); + } else { + SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); + } + } else if (BlockStorage.getStorage(clickedBlock.getWorld()).hasInventory(clickedBlock.getLocation())) { + BlockMenu menu = BlockStorage.getInventory(clickedBlock.getLocation()); - if (menu.canOpen(clickedBlock, p)) { - menu.open(p); - } else { - SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); + if (menu.canOpen(clickedBlock, p)) { + menu.open(p); + } else { + SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); + } } } + } catch (Exception | LinkageError x) { + item.error("An Exception was caught while trying to open the Inventory", x); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java index 445935569..ce21c0f35 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java @@ -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 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 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()); + 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 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(); + ItemStack item = e.getPlayer().getInventory().getItemInMainHand(); - if (item.getType() != Material.AIR && item.getAmount() > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) { + // 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 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); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java index 31e7444ac..e91d2660f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java @@ -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); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java index 47bf84f4f..f9aaa6abe 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java @@ -14,7 +14,6 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemState; import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; -import me.mrCookieSlime.Slimefun.api.Slimefun; /** * The {@link Listener} responsible for a {@link Player} interacting with an {@link Entity}. @@ -48,7 +47,7 @@ public class EntityInteractionListener implements Listener { SlimefunItem sfItem = SlimefunItem.getByItem(itemStack); if (sfItem != null) { - if (Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) { + if (sfItem.canUse(e.getPlayer(), true)) { sfItem.callItemHandler(EntityInteractHandler.class, handler -> handler.onInteract(e, itemStack, e.getHand() == EquipmentSlot.OFF_HAND)); } else if (sfItem.getState() != ItemState.VANILLA_FALLBACK) { /* diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java index 47579d295..b0f8b85b1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java @@ -18,7 +18,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.misc.BasicCircuitBoard; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; -import me.mrCookieSlime.Slimefun.api.Slimefun; /** * This {@link Listener} is responsible for handling any custom mob drops. @@ -55,7 +54,7 @@ public class MobDropListener implements Listener { if (item.getType() != Material.AIR) { SlimefunItem sfItem = SlimefunItem.getByItem(item); - if (sfItem != null && Slimefun.hasUnlocked(p, sfItem, true)) { + if (sfItem != null && sfItem.canUse(p, true)) { sfItem.callItemHandler(EntityKillHandler.class, handler -> handler.onKill(e, e.getEntity(), p, item)); } } @@ -63,21 +62,21 @@ public class MobDropListener implements Listener { } private boolean canDrop(@Nonnull Player p, @Nonnull ItemStack item) { - SlimefunItem sfi = SlimefunItem.getByItem(item); + SlimefunItem sfItem = SlimefunItem.getByItem(item); - if (sfi == null) { + if (sfItem == null) { return true; - } else if (Slimefun.hasUnlocked(p, sfi, true)) { - if (sfi instanceof RandomMobDrop) { + } else if (sfItem.canUse(p, true)) { + if (sfItem instanceof RandomMobDrop) { int random = ThreadLocalRandom.current().nextInt(100); - if (((RandomMobDrop) sfi).getMobDropChance() <= random) { + if (((RandomMobDrop) sfItem).getMobDropChance() <= random) { return false; } } - if (sfi instanceof BasicCircuitBoard) { - return ((BasicCircuitBoard) sfi).isDroppedFromGolems(); + if (sfItem instanceof BasicCircuitBoard) { + return ((BasicCircuitBoard) sfItem).isDroppedFromGolems(); } return true; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java index c45cc768d..e73b3cfe6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java @@ -32,56 +32,56 @@ class OilResource extends SlimefunResource { } switch (biome) { - case SNOWY_BEACH: - case STONE_SHORE: - case BEACH: - return 6; + case SNOWY_BEACH: + case STONE_SHORE: + case BEACH: + return 6; - case DESERT: - case DESERT_HILLS: - case DESERT_LAKES: - return 45; + case DESERT: + case DESERT_HILLS: + case DESERT_LAKES: + return 45; - case MOUNTAINS: - case GRAVELLY_MOUNTAINS: - case MOUNTAIN_EDGE: - case RIVER: - return 17; + case MOUNTAINS: + case GRAVELLY_MOUNTAINS: + case MOUNTAIN_EDGE: + case RIVER: + return 17; - case SNOWY_MOUNTAINS: - case SNOWY_TUNDRA: - case ICE_SPIKES: - case FROZEN_OCEAN: - case FROZEN_RIVER: - return 14; + case SNOWY_MOUNTAINS: + case SNOWY_TUNDRA: + case ICE_SPIKES: + case FROZEN_OCEAN: + case FROZEN_RIVER: + return 14; - case BADLANDS: - case BADLANDS_PLATEAU: - case WOODED_BADLANDS_PLATEAU: - case ERODED_BADLANDS: - case MODIFIED_BADLANDS_PLATEAU: - case MODIFIED_WOODED_BADLANDS_PLATEAU: - case MUSHROOM_FIELDS: - case MUSHROOM_FIELD_SHORE: - return 24; + case BADLANDS: + case BADLANDS_PLATEAU: + case WOODED_BADLANDS_PLATEAU: + case ERODED_BADLANDS: + case MODIFIED_BADLANDS_PLATEAU: + case MODIFIED_WOODED_BADLANDS_PLATEAU: + case MUSHROOM_FIELDS: + case MUSHROOM_FIELD_SHORE: + return 24; - case DEEP_OCEAN: - case OCEAN: - case COLD_OCEAN: - case DEEP_COLD_OCEAN: - case DEEP_FROZEN_OCEAN: - case DEEP_LUKEWARM_OCEAN: - case DEEP_WARM_OCEAN: - case LUKEWARM_OCEAN: - case WARM_OCEAN: - return 62; + case DEEP_OCEAN: + case OCEAN: + case COLD_OCEAN: + case DEEP_COLD_OCEAN: + case DEEP_FROZEN_OCEAN: + case DEEP_LUKEWARM_OCEAN: + case DEEP_WARM_OCEAN: + case LUKEWARM_OCEAN: + case WARM_OCEAN: + return 62; - case SWAMP: - case SWAMP_HILLS: - return 20; + case SWAMP: + case SWAMP_HILLS: + return 20; - default: - return 10; + default: + return 10; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java index 532bfa339..f6c14c79d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java @@ -26,33 +26,33 @@ class SaltResource extends SlimefunResource { } switch (biome) { - case SNOWY_BEACH: - case STONE_SHORE: - case BEACH: - case DESERT_LAKES: - case RIVER: - case ICE_SPIKES: - case FROZEN_RIVER: - return 40; + case SNOWY_BEACH: + case STONE_SHORE: + case BEACH: + case DESERT_LAKES: + case RIVER: + case ICE_SPIKES: + case FROZEN_RIVER: + return 40; - case DEEP_OCEAN: - case OCEAN: - case COLD_OCEAN: - case DEEP_COLD_OCEAN: - case DEEP_FROZEN_OCEAN: - case DEEP_LUKEWARM_OCEAN: - case DEEP_WARM_OCEAN: - case FROZEN_OCEAN: - case LUKEWARM_OCEAN: - case WARM_OCEAN: - return 60; + case DEEP_OCEAN: + case OCEAN: + case COLD_OCEAN: + case DEEP_COLD_OCEAN: + case DEEP_FROZEN_OCEAN: + case DEEP_LUKEWARM_OCEAN: + case DEEP_WARM_OCEAN: + case FROZEN_OCEAN: + case LUKEWARM_OCEAN: + case WARM_OCEAN: + return 60; - case SWAMP: - case SWAMP_HILLS: - return 20; + case SWAMP: + case SWAMP_HILLS: + return 20; - default: - return 6; + default: + return 6; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java index 3fd2d11c3..3cc10b874 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java @@ -52,6 +52,8 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.Crucible; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.EnhancedFurnace; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HardenedGlass; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramProjector; +import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.IgnitionChamber; +import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.OutputChest; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RainbowBlock; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RepairedSpawner; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.UnplaceableBlock; @@ -77,18 +79,13 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generato import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators.LavaGenerator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators.MagnesiumGenerator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators.SolarGenerator; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AnimalGrowthAccelerator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoAnvil; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoBreeder; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoBrewer; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDrier; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoEnchanter; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutomatedCraftingChamber; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.BookBinder; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CarbonPress; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ChargingBench; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CropGrowthAccelerator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricDustWasher; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricFurnace; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricGoldPan; @@ -103,11 +100,16 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodFabricator; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.Freezer; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.HeatedPressureChamber; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.IronGolemAssembler; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.Refinery; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.TreeGrowthAccelerator; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.WitherAssembler; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.XPCollector; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AnimalGrowthAccelerator; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.TreeGrowthAccelerator; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.BookBinder; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.IronGolemAssembler; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.WitherAssembler; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.ExpCollector; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.NetherStarReactor; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.NuclearReactor; import io.github.thebusybiscuit.slimefun4.implementation.items.elevator.ElevatorPlate; @@ -243,7 +245,7 @@ public final class SlimefunItemSetup { new ItemStack[] {new ItemStack(Material.COOKIE), SlimefunItems.ELYTRA_SCALE, null, null, null, null, null, null, null}) .register(plugin); - new SlimefunItem(categories.basicMachines, SlimefunItems.OUTPUT_CHEST, RecipeType.ENHANCED_CRAFTING_TABLE, + new OutputChest(categories.basicMachines, SlimefunItems.OUTPUT_CHEST, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.LEAD_INGOT, new ItemStack(Material.HOPPER), SlimefunItems.LEAD_INGOT, SlimefunItems.LEAD_INGOT, new ItemStack(Material.CHEST), SlimefunItems.LEAD_INGOT, null, SlimefunItems.LEAD_INGOT, null}) .register(plugin); @@ -401,7 +403,7 @@ public final class SlimefunItemSetup { new MakeshiftSmeltery(categories.basicMachines, SlimefunItems.MAKESHIFT_SMELTERY).register(plugin); new Smeltery(categories.basicMachines, SlimefunItems.SMELTERY).register(plugin); - new SlimefunItem(categories.basicMachines, SlimefunItems.IGNITION_CHAMBER, RecipeType.ENHANCED_CRAFTING_TABLE, + new IgnitionChamber(categories.basicMachines, SlimefunItems.IGNITION_CHAMBER, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {new ItemStack(Material.IRON_INGOT), new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.IRON_INGOT), new ItemStack(Material.IRON_INGOT), SlimefunItems.BASIC_CIRCUIT_BOARD, new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.OBSERVER), null}) .register(plugin); @@ -2287,7 +2289,7 @@ public final class SlimefunItemSetup { new ItemStack[] {null, SlimefunItems.CARBONADO, null, SlimefunItems.ELECTRIC_MOTOR, new ItemStack(Material.DIAMOND_AXE), SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.MAGNESIUM_SALT, SlimefunItems.BIG_CAPACITOR, SlimefunItems.MAGNESIUM_SALT}) .register(plugin); - new XPCollector(categories.electricity, SlimefunItems.EXP_COLLECTOR, RecipeType.ENHANCED_CRAFTING_TABLE, + new ExpCollector(categories.electricity, SlimefunItems.EXP_COLLECTOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.BLISTERING_INGOT_3, null, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.AUTO_ENCHANTER, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ALUMINUM_BRONZE_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_BRONZE_INGOT}) .register(plugin); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java index ed1c04fa3..510dfc07d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java @@ -117,7 +117,7 @@ public class ArmorTask implements Runnable { SlimefunPlugin.runSync(() -> { SlimefunArmorPiece slimefunArmor = armorpiece.getItem().get(); - if (Slimefun.hasUnlocked(p, slimefunArmor, true)) { + if (slimefunArmor.canUse(p, true)) { for (PotionEffect effect : slimefunArmor.getPotionEffects()) { p.removePotionEffect(effect.getType()); p.addPotionEffect(effect); @@ -138,7 +138,7 @@ public class ArmorTask implements Runnable { SlimefunItem item = SlimefunItem.getByItem(helmet); - if (item instanceof SolarHelmet && Slimefun.hasUnlocked(p, item, true)) { + if (item instanceof SolarHelmet && item.canUse(p, true)) { ((SolarHelmet) item).rechargeItems(p); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java index 92ef1ec56..794751805 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java @@ -4,7 +4,9 @@ import java.util.function.Consumer; import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.block.Block; @@ -158,6 +160,30 @@ public class IntegrationsManager { } } + /** + * This method logs a {@link Throwable} that was caused by a {@link Plugin} + * we integrate into. + * Calling this method will probably log the error and provide the version of this {@link Plugin} + * for error analysis. + * + * @param name + * The name of the {@link Plugin} + * @param throwable + * The {@link Throwable} to throw + */ + @ParametersAreNonnullByDefault + protected void logError(String name, Throwable throwable) { + Plugin externalPlugin = Bukkit.getPluginManager().getPlugin(name); + + if (externalPlugin != null) { + String version = externalPlugin.getDescription().getVersion(); + SlimefunPlugin.logger().log(Level.WARNING, "Is {0} v{1} up to date?", new Object[] { name, version }); + SlimefunPlugin.logger().log(Level.SEVERE, throwable, () -> "An unknown error was detected while interacting with \"" + name + " v" + version + "\""); + } else { + SlimefunPlugin.logger().log(Level.SEVERE, throwable, () -> "An unknown error was detected while interacting with the plugin \"" + name + "\""); + } + } + /** * This method loads an integration with a {@link Plugin} of the specified name. * If that {@link Plugin} is installed and enabled, the provided callback will be run. @@ -220,7 +246,15 @@ public class IntegrationsManager { */ @SuppressWarnings("deprecation") public boolean isCustomBlock(@Nonnull Block block) { - return isItemsAdderInstalled && ItemsAdder.isCustomBlock(block); + if (isItemsAdderInstalled) { + try { + return ItemsAdder.isCustomBlock(block); + } catch (Exception | LinkageError x) { + logError("ItemsAdder", x); + } + } + + return false; } public boolean isPlaceholderAPIInstalled() { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java index 722864a0f..2f82b935f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java @@ -36,7 +36,11 @@ class McMMOIntegration implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPlacerPlace(BlockPlacerPlaceEvent e) { // This registers blocks placed by the BlockPlacer as "player-placed" - mcMMO.getPlaceStore().setTrue(e.getBlock()); + try { + mcMMO.getPlaceStore().setTrue(e.getBlock()); + } catch (Exception | LinkageError x) { + SlimefunPlugin.getIntegrations().logError("mcMMO", x); + } } @EventHandler(ignoreCancelled = true) diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java index e5a4d9b04..d71b68e92 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java @@ -62,7 +62,12 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion { private boolean isPlaceholder(@Nullable OfflinePlayer p, boolean requiresProfile, @Nonnull String params, @Nonnull String placeholder) { if (requiresProfile) { - return p != null && placeholder.equals(params) && PlayerProfile.request(p); + if (p != null && placeholder.equals(params)) { + PlayerProfile.request(p); + return true; + } else { + return false; + } } else { return placeholder.equals(params); } @@ -77,7 +82,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion { Stream stream = profile.get().getResearches().stream(); return String.valueOf(stream.mapToInt(Research::getCost).sum()); } else if (p instanceof Player) { - return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading"); + return getProfilePlaceholder((Player) p); } } @@ -88,7 +93,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion { Set set = profile.get().getResearches(); return String.valueOf(set.size()); } else if (p instanceof Player) { - return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading"); + return getProfilePlaceholder((Player) p); } } @@ -103,7 +108,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion { Set set = profile.get().getResearches(); return String.valueOf(Math.round(((set.size() * 100.0F) / SlimefunPlugin.getRegistry().getResearches().size()) * 100.0F) / 100.0F); } else if (p instanceof Player) { - return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading"); + return getProfilePlaceholder((Player) p); } } @@ -113,7 +118,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion { if (profile.isPresent()) { return profile.get().getTitle(); } else if (p instanceof Player) { - return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading"); + return getProfilePlaceholder((Player) p); } } @@ -133,4 +138,9 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion { return null; } + @Nonnull + private String getProfilePlaceholder(@Nonnull Player p) { + return SlimefunPlugin.getLocalization().getMessage(p, "placeholderapi.profile-loading"); + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java index fb791fda3..4f6826508 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java @@ -47,6 +47,28 @@ public enum ColoredMaterial { Material.BLACK_WOOL }), + /** + * This {@link List} contains all carpet colors ordered by their appearance ingame. + */ + CARPET(new Material[] { + Material.WHITE_CARPET, + Material.ORANGE_CARPET, + Material.MAGENTA_CARPET, + Material.LIGHT_BLUE_CARPET, + Material.YELLOW_CARPET, + Material.LIME_CARPET, + Material.PINK_CARPET, + Material.GRAY_CARPET, + Material.LIGHT_GRAY_CARPET, + Material.CYAN_CARPET, + Material.PURPLE_CARPET, + Material.BLUE_CARPET, + Material.BROWN_CARPET, + Material.GREEN_CARPET, + Material.RED_CARPET, + Material.BLACK_CARPET + }), + /** * This {@link List} contains all stained glass colors ordered by their appearance ingame. */ diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/InfiniteBlockGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/InfiniteBlockGenerator.java new file mode 100644 index 000000000..de44929e9 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/InfiniteBlockGenerator.java @@ -0,0 +1,175 @@ +package io.github.thebusybiscuit.slimefun4.utils; + +import java.util.function.Predicate; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.event.block.BlockFormEvent; + +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; +import io.github.thebusybiscuit.slimefun4.implementation.items.androids.MinerAndroid; +import io.papermc.lib.PaperLib; + +/** + * This enum holds various ways of infinite block generators. + * The most prominent member of these is the standard Cobblestone Generator. + * We use this enum for performance optimizations for the {@link MinerAndroid}. + * + * @author TheBusyBiscuit + * + */ +public enum InfiniteBlockGenerator implements Predicate { + + /** + * Your standard Cobblestone Generator with flowing lava and water. + */ + COBBLESTONE_GENERATOR("COBBLESTONE"), + + /** + * When lava flows onto a stationary water block it generates normal stone. + */ + STONE_GENERATOR("STONE"), + + /** + * The Basalt Generator (1.16+ only) allows you to generate infinite Basalt! + */ + BASALT_GENERATOR("BASALT"); + + public static final InfiniteBlockGenerator[] values = values(); + private static final BlockFace[] sameLevelFaces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST }; + + private final Material material; + + InfiniteBlockGenerator(@Nonnull String type) { + this.material = Material.matchMaterial(type); + } + + /** + * This returns the generated {@link Material} of this {@link InfiniteBlockGenerator}. + * This method can return null if the associated {@link Material} is not available in the current + * {@link MinecraftVersion}. + * + * @return The generated {@link Material} or null + */ + @Nullable + public Material getGeneratedMaterial() { + return material; + } + + /** + * Similar to {@link #test(Block)} this tests whether this {@link InfiniteBlockGenerator} + * exists at the given {@link Block}. + * + * @param b + * The {@link Block} + * + * @return Whether this {@link InfiniteBlockGenerator} exists at the given {@link Block} + */ + @Override + public boolean test(@Nonnull Block b) { + Validate.notNull(b, "Block cannot be null!"); + + /* + * This will eliminate non-matching base materials If we + * are on a version without Basalt, it will be null here and not match. + */ + if (b.getType() == getGeneratedMaterial()) { + switch (this) { + case COBBLESTONE_GENERATOR: + return hasSurroundingMaterials(b, Material.WATER, Material.LAVA); + case STONE_GENERATOR: + if (b.getRelative(BlockFace.UP).getType() == Material.LAVA) { + return hasSurroundingMaterials(b, Material.WATER); + } else { + return false; + } + case BASALT_GENERATOR: + if (b.getRelative(BlockFace.DOWN).getType() == Material.SOUL_SOIL) { + return hasSurroundingMaterials(b, Material.LAVA, Material.BLUE_ICE); + } else { + return false; + } + default: + return false; + } + } else { + return false; + } + } + + @ParametersAreNonnullByDefault + private boolean hasSurroundingMaterials(Block b, Material... materials) { + Validate.notNull(b, "The Block cannot be null!"); + Validate.notEmpty(materials, "Materials need to have a size of at least one!"); + + boolean[] matches = new boolean[materials.length]; + int count = 0; + + for (BlockFace face : sameLevelFaces) { + Block neighbour = b.getRelative(face); + Material neighbourType = neighbour.getType(); + + for (int i = 0; i < materials.length; i++) { + if (neighbourType == materials[i] && !matches[i]) { + matches[i] = true; + count++; + break; + } + } + + if (count == materials.length) { + return true; + } + } + + return count == materials.length; + } + + /** + * This method calls a {@link BlockFormEvent} for this {@link InfiniteBlockGenerator}. + * There are a few plugins who catch these events to inject custom {@link Material Materials} into + * Cobblestone Generators, so we wanna give them the oppurtunity to catch this as well. + * + * @param block + * The {@link Block} where the liquid has solidified + * + * @return Our called {@link BlockFormEvent} + */ + @Nonnull + public BlockFormEvent callEvent(@Nonnull Block block) { + Validate.notNull(block, "The Block cannot be null!"); + BlockState state = PaperLib.getBlockState(block, false).getState(); + BlockFormEvent event = new BlockFormEvent(block, state); + Bukkit.getPluginManager().callEvent(event); + return event; + } + + /** + * This will attempt to find an {@link InfiniteBlockGenerator} at the given {@link Block}. + * + * @param b + * The {@link Block} + * + * @return An {@link InfiniteBlockGenerator} or null if none was found. + */ + @Nullable + public static InfiniteBlockGenerator findAt(@Nonnull Block b) { + Validate.notNull(b, "Cannot find a generator without a Location!"); + + for (InfiniteBlockGenerator generator : values) { + if (generator.test(b)) { + return generator; + } + } + + return null; + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java index 8b6eff1ac..c7446de7f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java @@ -15,6 +15,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.entity.Item; +import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -358,4 +359,31 @@ public final class SlimefunUtils { SlimefunPlugin.runSync(new CapacitorTextureUpdateTask(l, charge, capacity)); } + /** + * This checks whether the {@link Player} is able to use the given {@link ItemStack}. + * It will always return true for non-Slimefun items. + *

+ * If you already have an instance of {@link SlimefunItem}, please use {@link SlimefunItem#canUse(Player, boolean)}. + * + * @param p + * The {@link Player} + * @param item + * The {@link ItemStack} to check + * @param sendMessage + * Whether to send a message response to the {@link Player} + * + * @return Whether the {@link Player} is able to use that item. + */ + public static boolean canPlayerUseItem(@Nonnull Player p, @Nullable ItemStack item, boolean sendMessage) { + Validate.notNull(p, "The player cannot be null"); + + SlimefunItem sfItem = SlimefunItem.getByItem(item); + + if (sfItem != null) { + return sfItem.canUse(p, sendMessage); + } else { + return true; + } + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java index 855485681..c8bbd4b86 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java @@ -21,7 +21,8 @@ import org.bukkit.block.data.Waterlogged; import io.github.thebusybiscuit.slimefun4.api.exceptions.TagMisconfigurationException; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.BlockPlacer; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CropGrowthAccelerator; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman; import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.miner.IndustrialMiner; import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ClimbingPick; import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosiveShovel; @@ -120,6 +121,12 @@ public enum SlimefunTag implements Tag { */ DIRT_VARIANTS, + /** + * All soil blocks for a fungus to grow on. + * This includes all dirt variants, nylium and soul soil. + */ + FUNGUS_SOIL, + /** * All variants of concrete powder. * Can you believe there is no tag for this already? @@ -184,6 +191,11 @@ public enum SlimefunTag implements Tag { */ INDUSTRIAL_MINER_ORES, + /** + * All materials (ores) which can be doubled using a Miner {@link Talisman}. + */ + MINER_TALISMAN_TRIGGERS, + /** * All materials (crops) which the {@link CropGrowthAccelerator} will recognize. */ @@ -210,8 +222,16 @@ public enum SlimefunTag implements Tag { */ CAVEMAN_TALISMAN_TRIGGERS; + /** + * Lookup table for tag names. + */ private static final Map nameLookup = new HashMap<>(); - public static final SlimefunTag[] valuesCache = values(); + + /** + * Speed up lookups by caching the values instead of creating a new array + * on every method call. + */ + private static final SlimefunTag[] valuesCache = values(); static { for (SlimefunTag tag : valuesCache) { diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java index d28037ba3..6c6b7860f 100644 --- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java +++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java @@ -59,49 +59,49 @@ public class CustomItemSerializer { builder.append(flag.toString() + "="); switch (flag) { - case AMOUNT: { - builder.append(item.getAmount()); - break; - } - case DATA: { - builder.append((int) item.getData().getData()); - break; - } - case DURABILITY: { - builder.append((int) item.getDurability()); - break; - } - case ENCHANTMENTS: - for (Enchantment enchantment : Enchantment.values()) { - if (item.getEnchantments().containsKey(enchantment)) { - builder.append(enchantment.getName() + ":" + item.getEnchantmentLevel(enchantment)); - } else { - builder.append(enchantment.getName() + ":0"); + case AMOUNT: { + builder.append(item.getAmount()); + break; + } + case DATA: { + builder.append((int) item.getData().getData()); + break; + } + case DURABILITY: { + builder.append((int) item.getDurability()); + break; + } + case ENCHANTMENTS: + for (Enchantment enchantment : Enchantment.values()) { + if (item.getEnchantments().containsKey(enchantment)) { + builder.append(enchantment.getName() + ":" + item.getEnchantmentLevel(enchantment)); + } else { + builder.append(enchantment.getName() + ":0"); + } } + break; + case ITEMMETA_DISPLAY_NAME: { + if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) { + builder.append(item.getItemMeta().getDisplayName().replaceAll("\\u00a7", "&")); + } else { + builder.append("NONE"); + } + break; } - break; - case ITEMMETA_DISPLAY_NAME: { - if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) { - builder.append(item.getItemMeta().getDisplayName().replaceAll("\\u00a7", "&")); - } else { - builder.append("NONE"); + case ITEMMETA_LORE: { + if (item.hasItemMeta() && item.getItemMeta().hasLore()) { + builder.append(item.getItemMeta().getLore().toString().replaceAll("\\u00a7", "&")); + } else { + builder.append("NONE"); + } + break; } - break; - } - case ITEMMETA_LORE: { - if (item.hasItemMeta() && item.getItemMeta().hasLore()) { - builder.append(item.getItemMeta().getLore().toString().replaceAll("\\u00a7", "&")); - } else { - builder.append("NONE"); + case MATERIAL: { + builder.append(item.getType().toString()); + break; } - break; - } - case MATERIAL: { - builder.append(item.getType().toString()); - break; - } - default: - break; + default: + break; } i++; diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java b/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java index 084a6bbe8..635643bb3 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java @@ -9,6 +9,8 @@ import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.ChatColor; import org.bukkit.Keyed; import org.bukkit.Material; @@ -138,16 +140,32 @@ public class RecipeType implements Keyed { } @Override - public NamespacedKey getKey() { + public final NamespacedKey getKey() { return key; } + @Override + public final boolean equals(Object obj) { + if (obj instanceof RecipeType) { + return ((RecipeType) obj).getKey().equals(this.getKey()); + } else { + return false; + } + } + + @Override + public final int hashCode() { + return getKey().hashCode(); + } + + @ParametersAreNonnullByDefault private static void registerBarterDrop(ItemStack[] recipe, ItemStack output) { if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) { SlimefunPlugin.getRegistry().getBarteringDrops().add(output); } } + @ParametersAreNonnullByDefault private static void registerMobDrop(ItemStack[] recipe, ItemStack output) { String mob = ChatColor.stripColor(recipe[4].getItemMeta().getDisplayName()).toUpperCase(Locale.ROOT).replace(' ', '_'); EntityType entity = EntityType.valueOf(mob); @@ -211,4 +229,4 @@ public class RecipeType implements Keyed { List recipes = machine.getRecipes(); return recipes.get((recipes.indexOf(input) + 1))[0]; } -} +} \ No newline at end of file diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java index cf95721f3..2a2ac688e 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java @@ -26,7 +26,6 @@ import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; -import me.mrCookieSlime.Slimefun.api.Slimefun; /** * Represents a category, which structure multiple {@link SlimefunItem} in the {@link SlimefunGuide}. @@ -90,7 +89,8 @@ public class Category implements Keyed { } @Override - public NamespacedKey getKey() { + @Nonnull + public final NamespacedKey getKey() { return key; } @@ -226,7 +226,7 @@ public class Category implements Keyed { * * @return Whether the given {@link SlimefunItem} was found in this {@link Category} */ - public boolean contains(SlimefunItem item) { + public boolean contains(@Nullable SlimefunItem item) { return item != null && items.contains(item); } @@ -240,6 +240,20 @@ public class Category implements Keyed { return tier; } + @Override + public final boolean equals(Object obj) { + if (obj instanceof Category) { + return ((Category) obj).getKey().equals(getKey()); + } else { + return false; + } + } + + @Override + public final int hashCode() { + return key.hashCode(); + } + @Override public String toString() { return getClass().getSimpleName() + " {" + key + ",tier=" + tier + "}"; @@ -258,7 +272,7 @@ public class Category implements Keyed { */ public boolean isHidden(@Nonnull Player p) { for (SlimefunItem slimefunItem : getItems()) { - if (!slimefunItem.isHidden() && Slimefun.isEnabled(p, slimefunItem, false)) { + if (!slimefunItem.isHidden() && !slimefunItem.isDisabledIn(p.getWorld())) { return false; } } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java index 2fcce02eb..6009883e6 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java @@ -4,6 +4,7 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.Event; +import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason; @@ -16,8 +17,10 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason; * * @author TheBusyBiscuit * + * @deprecated Please use the {@link BlockBreakHandler} instead. * */ +@Deprecated @FunctionalInterface public interface SlimefunBlockHandler { diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java index 5cca61a0d..4473093fb 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java @@ -16,9 +16,11 @@ import javax.annotation.ParametersAreNonnullByDefault; import org.apache.commons.lang.Validate; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.permissions.Permission; import io.github.thebusybiscuit.cscorelib2.collections.OptionalMap; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; @@ -32,22 +34,23 @@ import io.github.thebusybiscuit.slimefun4.api.exceptions.UnregisteredItemExcepti import io.github.thebusybiscuit.slimefun4.api.exceptions.WrongItemStackException; import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; import io.github.thebusybiscuit.slimefun4.api.items.ItemState; +import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.attributes.NotConfigurable; import io.github.thebusybiscuit.slimefun4.core.attributes.Placeable; import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive; import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; +import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter; -import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoEnchanter; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; @@ -242,6 +245,13 @@ public class SlimefunItem implements Placeable { return recipe; } + /** + * This method returns the {@link RecipeType}. + * The {@link RecipeType} determines how this {@link SlimefunItem} is crafted. + * + * @return The {@link RecipeType} of this {@link SlimefunItem} + */ + @Nonnull public RecipeType getRecipeType() { return recipeType; } @@ -377,6 +387,26 @@ public class SlimefunItem implements Placeable { return state != ItemState.ENABLED; } + /** + * This method returns whether this {@link SlimefunItem} is disabled + * for that specific {@link World}. + * Note that if the item is disabled globally, this method will still return false. + * + * @param world + * The {@link World} to check + * + * @return Whether this {@link SlimefunItem} is disabled in that world (or in general). + */ + public boolean isDisabledIn(@Nonnull World world) { + if (state == ItemState.UNREGISTERED) { + error("isDisabled(World) cannot be called before registering the item", new UnregisteredItemException(this)); + return false; + } + + // Check if the Item is disabled globally or in this specific world + return isDisabled() || !SlimefunPlugin.getWorldSettingsService().isEnabled(world, this); + } + /** * This method returns the {@link SlimefunAddon} that registered this * {@link SlimefunItem}. If this Item is from Slimefun itself, the current @@ -906,6 +936,7 @@ public class SlimefunItem implements Placeable { * * @return Whether or not an {@link ItemHandler} was found. */ + @ParametersAreNonnullByDefault public boolean callItemHandler(Class c, Consumer callable) { Optional handler = itemhandlers.get(c); @@ -996,7 +1027,6 @@ public class SlimefunItem implements Placeable { */ public void error(@Nonnull String message, @Nonnull Throwable throwable) { Validate.notNull(addon, "Cannot send an error for an unregistered item!"); - addon.getLogger().log(Level.SEVERE, "Item \"{0}\" from {1} v{2} has caused an Error!", new Object[] { id, addon.getName(), addon.getPluginVersion() }); if (addon.getBugTrackerURL() != null) { @@ -1012,6 +1042,88 @@ public class SlimefunItem implements Placeable { } } + /** + * This method checks if the given {@link Player} is able to use this {@link SlimefunItem}. + * A {@link Player} can use it if the following conditions apply: + * + *

    + *
  • The {@link SlimefunItem} is not disabled + *
  • The {@link SlimefunItem} was not disabled for that {@link Player}'s {@link World}. + *
  • The {@link Player} has the required {@link Permission} (if present) + *
  • The {@link Player} has unlocked the required {@link Research} (if present) + *
+ * + * If any of these conditions evaluate to false, then an optional message will be + * sent to the {@link Player}. + * + * @param p + * The {@link Player} to check + * @param sendMessage + * Whether to send that {@link Player} a message response. + * + * @return Whether this {@link Player} is able to use this {@link SlimefunItem}. + */ + public boolean canUse(@Nonnull Player p, boolean sendMessage) { + Validate.notNull(p, "The Player cannot be null!"); + + if (getState() == ItemState.VANILLA_FALLBACK) { + // Vanilla items (which fell back) can always be used. + return true; + } else if (isDisabled()) { + // The Item has been disabled in the config + if (sendMessage) { + SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-item", true); + } + + return false; + } else if (!SlimefunPlugin.getWorldSettingsService().isEnabled(p.getWorld(), this)) { + // The Item was disabled in the current World + if (sendMessage) { + SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-in-world", true); + } + + return false; + } else if (!SlimefunPlugin.getPermissionsService().hasPermission(p, this)) { + // The Player does not have the required permission node + if (sendMessage) { + SlimefunPlugin.getLocalization().sendMessage(p, "messages.no-permission", true); + } + + return false; + } else if (hasResearch()) { + Optional profile = PlayerProfile.find(p); + + if (!profile.isPresent()) { + /* + * We will return false since we cannot know the answer yet. + * But we will schedule the Profile for loading and not send + * any message. + */ + PlayerProfile.request(p); + return false; + } else if (!profile.get().hasUnlocked(getResearch())) { + /* + * The Profile is loaded but Player has not unlocked the + * required Research to use this SlimefunItem. + */ + if (sendMessage && !(this instanceof VanillaItem)) { + SlimefunPlugin.getLocalization().sendMessage(p, "messages.not-researched", true); + } + + return false; + } else { + /* + * The PlayerProfile is loaded and the Player has unlocked + * the required Research. + */ + return true; + } + } else { + // All checks have passed, the Player can use this item. + return true; + } + } + @Override public final boolean equals(Object obj) { if (obj instanceof SlimefunItem) { @@ -1052,12 +1164,16 @@ public class SlimefunItem implements Placeable { // This wrapper improves the heavy ItemStack#getItemMeta() call by caching it. ItemStackWrapper wrapper = new ItemStackWrapper(item); - // Quite expensive performance-wise - // But necessary for supporting legacy items + /* + * Quite expensive performance-wise. + * But necessary for supporting legacy items + */ for (SlimefunItem sfi : SlimefunPlugin.getRegistry().getAllSlimefunItems()) { if (sfi.isItem(wrapper)) { - // If we have to loop all items for the given item, then at least - // set the id via PersistentDataAPI for future performance boosts + /* + * If we have to loop all items for the given item, then at least + * set the id via PersistentDataAPI for future performance boosts + */ SlimefunPlugin.getItemDataService().setItemData(item, sfi.getId()); return sfi; @@ -1068,12 +1184,24 @@ public class SlimefunItem implements Placeable { return null; } - public static Set getPublicItemHandlers(Class identifier) { + @Nonnull + public static Set getPublicItemHandlers(@Nonnull Class identifier) { return SlimefunPlugin.getRegistry().getPublicItemHandlers().computeIfAbsent(identifier, c -> new HashSet<>()); } - public static void registerBlockHandler(String id, SlimefunBlockHandler handler) { + /** + * This has been deprecated. + * + * @deprecated Please use {@link #addItemHandler(ItemHandler...)} and {@link BlockBreakHandler} instead + * + * @param id + * The id + * @param handler + * The handler + */ + @Deprecated + public static void registerBlockHandler(@Nonnull String id, @Nullable me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler handler) { SlimefunPlugin.getRegistry().getBlockHandlers().put(id, handler); } -} +} \ No newline at end of file diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java index fd76a81c9..3361d2787 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java @@ -10,9 +10,12 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler; * * @author TheBusyBiscuit * + * @deprecated This enum is no longer needed + * * @see SlimefunBlockHandler * */ +@Deprecated public enum UnregisterReason { /** diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java index b09f898e8..59c1bb77c 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java @@ -16,7 +16,8 @@ import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; /** * - * @deprecated This interface is not designed to be used by addons. + * @deprecated This interface is not designed to be used by addons. The entire inventory system will be replaced + * eventually. * */ public interface InventoryBlock { @@ -60,7 +61,7 @@ public interface InventoryBlock { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES) && Slimefun.hasUnlocked(p, item, false)); + return p.hasPermission("slimefun.inventory.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK) && Slimefun.hasUnlocked(p, item, false)); } }; } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java index 7333724c2..e2a33f7fe 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java @@ -2,6 +2,8 @@ package me.mrCookieSlime.Slimefun.Objects.handlers; import java.util.Optional; +import javax.annotation.Nonnull; + import io.github.thebusybiscuit.slimefun4.api.exceptions.IncompatibleItemHandlerException; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BowShootHandler; @@ -51,7 +53,8 @@ public interface ItemHandler { * @return An {@link Optional} describing the result, it will contain an {@link IncompatibleItemHandlerException} * should there be an issue */ - default Optional validate(SlimefunItem item) { + @Nonnull + default Optional validate(@Nonnull SlimefunItem item) { return Optional.empty(); } @@ -61,5 +64,6 @@ public interface ItemHandler { * * @return The {@link Class} identifier for this {@link ItemHandler} */ + @Nonnull Class getIdentifier(); } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java index c04900fa7..5c75ac863 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java @@ -378,7 +378,8 @@ public class BlockStorage { * This will return an {@link ImmutableMap} of the underline {@code Map} of * this worlds {@link BlockStorage}. If there is no registered world then this will return null. * - * @param world The world of which to fetch the data from. + * @param world + * The world of which to fetch the data from. * @return An {@link ImmutableMap} of the raw data or null if the world isn't registered. */ @Nullable @@ -416,19 +417,14 @@ public class BlockStorage { * @return the SlimefunItem's ItemStack corresponding to the block if it has one, otherwise null */ @Nullable - public static ItemStack retrieve(Block block) { - if (!hasBlockInfo(block)) { + public static ItemStack retrieve(@Nonnull Block block) { + SlimefunItem item = check(block); + + if (item == null) { return null; } else { - String id = getLocationInfo(block.getLocation(), "id"); - SlimefunItem item = SlimefunItem.getByID(id); clearBlockInfo(block); - - if (item == null) { - return null; - } else { - return item.getItem(); - } + return item.getItem(); } } @@ -704,6 +700,11 @@ public class BlockStorage { return id == null ? null : SlimefunItem.getByID(id); } + public static boolean check(Block block, String slimefunItem) { + String id = checkID(block); + return id != null && id.equals(slimefunItem); + } + @Nullable public static String checkID(@Nonnull Block b) { // Only access the BlockState when on the main thread @@ -718,16 +719,8 @@ public class BlockStorage { return checkID(b.getLocation()); } - public static boolean check(Block block, String slimefunItem) { - String id = checkID(block); - return id != null && id.equals(slimefunItem); - } - - public static String checkID(Location l) { - if (!hasBlockInfo(l)) { - return null; - } - + @Nullable + public static String checkID(@Nonnull Location l) { return getLocationInfo(l, "id"); } @@ -740,7 +733,7 @@ public class BlockStorage { return id != null && id.equals(slimefunItem); } - public static boolean isWorldLoaded(World world) { + public static boolean isWorldLoaded(@Nonnull World world) { return SlimefunPlugin.getRegistry().getWorlds().containsKey(world.getName()); } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java index 6b843802c..de397d152 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java @@ -1,18 +1,15 @@ package me.mrCookieSlime.Slimefun.api; -import java.util.Optional; - import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import io.github.thebusybiscuit.slimefun4.api.items.ItemState; -import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; /** * Provides a few static convenience methods. + * This class is slowly getting stripped away in favour of a more object-oriented approach. * * @author TheBusyBiscuit * @author Walshy @@ -31,19 +28,17 @@ public final class Slimefun { * the item to check, not null * @param message * whether a message should be sent to the player or not + * + * @deprecated Moved to + * {@link SlimefunUtils#canPlayerUseItem(Player, ItemStack, boolean)} * * @return true if the item is a SlimefunItem, enabled, researched and if the player has the permission * to use it, * false otherwise. */ + @Deprecated public static boolean hasUnlocked(Player p, ItemStack item, boolean message) { - SlimefunItem sfItem = SlimefunItem.getByItem(item); - - if (sfItem != null) { - return hasUnlocked(p, sfItem, message); - } else { - return true; - } + return SlimefunUtils.canPlayerUseItem(p, item, message); } /** @@ -55,39 +50,15 @@ public final class Slimefun { * the item to check, not null * @param message * whether a message should be sent to the player or not + * + * @deprecated Please use {@link SlimefunItem#canUse(Player, boolean)} instead. * * @return true if the item is enabled, researched and the player has the permission to use it, * false otherwise. */ + @Deprecated public static boolean hasUnlocked(Player p, SlimefunItem sfItem, boolean message) { - if (sfItem.getState() == ItemState.VANILLA_FALLBACK) { - return true; - } - - if (isEnabled(p, sfItem, message) && hasPermission(p, sfItem, message)) { - if (sfItem.getResearch() == null) { - return true; - } else { - Optional profile = PlayerProfile.find(p); - - if (!profile.isPresent()) { - // We will return false since we cannot know the answer yet - // But we will schedule the Profile for loading. - PlayerProfile.request(p); - return false; - } else if (profile.get().hasUnlocked(sfItem.getResearch())) { - return true; - } else { - if (message && !(sfItem instanceof VanillaItem)) { - SlimefunPlugin.getLocalization().sendMessage(p, "messages.not-researched", true); - } - - return false; - } - } - } - - return false; + return sfItem.canUse(p, message); } /** @@ -126,10 +97,13 @@ public final class Slimefun { * the item to check, not null * @param message * whether a message should be sent to the player or not + * + * @deprecated This method will be removed. * * @return true if the item is a SlimefunItem and is enabled in the world the player is in, * false otherwise. */ + @Deprecated public static boolean isEnabled(Player p, ItemStack item, boolean message) { SlimefunItem sfItem = SlimefunItem.getByItem(item); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 84aff21b3..a0f9cd53a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -38,9 +38,8 @@ networks: enable-visualizer: true delete-excess-items: false -items: - talismans: true - soulbound: true +talismans: + use-actionbar: true metrics: auto-update: true diff --git a/src/main/resources/languages/categories_cs.yml b/src/main/resources/languages/categories_cs.yml index 1facb887f..6a4ea3f5b 100644 --- a/src/main/resources/languages/categories_cs.yml +++ b/src/main/resources/languages/categories_cs.yml @@ -1,25 +1,26 @@ --- slimefun: - armor: Brnění - basic_machines: Základní stroje - birthday: TheBusyBiscuitovy narozeniny (26. Říjen) - cargo: Cargo systém - christmas: Vánoce (Prosinec) - easter: Velikonoce (Duben) - electricity: Energie a elektrika - ender_talismans: Ender Talismany (Tier II) - food: Jídlo - gps: GPS stroje - halloween: Halloween (31. Října) - items: Užitečné itemy - magical_armor: Magická zbroj - magical_gadgets: Magické pomůcky - magical_items: Magické itemy - resources: Materiály - talismans: Talismany (Tier I) - tech_misc: Technické komponenty - technical_gadgets: Technické pomůcky - tools: Nástroje weapons: Zbraně - misc: Smíšené položky - valentines_day: Svatého Valentýna (14. Února) + tools: Nástroje + items: Užitečné předměty + food: Jídlo + basic_machines: Základní stroje + electricity: Energie a elektrika + gps: GPS stroje + armor: Brnění + magical_items: Magické předměty + magical_gadgets: Magické pomůcky + misc: Smíšené předměty + technical_gadgets: Technické pomůcky + resources: Materiály + cargo: Cargo systém + tech_misc: Technické komponenty + magical_armor: Magická zbroj + talismans: Talismany (Tier I) + ender_talismans: Enderitové talismany (Tier II) + christmas: Vánoce (prosinec) + valentines_day: Svatého Valentýna (14. února) + easter: Velikonoce (duben) + birthday: TheBusyBiscuitovy narozeniny (26. říjen) + halloween: Halloween (31. října) + androids: Programovatelné androidy diff --git a/src/main/resources/languages/categories_fi.yml b/src/main/resources/languages/categories_fi.yml new file mode 100644 index 000000000..df0ad816b --- /dev/null +++ b/src/main/resources/languages/categories_fi.yml @@ -0,0 +1,26 @@ +--- +slimefun: + weapons: Aseet + tools: Työkalut + items: Hyödyllisiä Tuotteita + food: Ruoka + basic_machines: Peruskoneet + electricity: Energia ja sähkö + gps: GPS-pohjaiset koneet + armor: Panssari + magical_items: Maagiset esineet + magical_gadgets: Maagiset gadgetit + misc: Sekalaiset tuotteet + technical_gadgets: Tekniset gadgetit + resources: Resurssit + cargo: Cargo Management + tech_misc: Tekniset komponentit + magical_armor: Maaginen panssari + talismans: Talismanit (Taso I) + ender_talismans: Ender Talismanit (Taso II) + christmas: Joulu (joulukuu) + valentines_day: Ystävänpäivä (14. helmikuuta) + easter: Pääsiäinen (huhtikuu) + birthday: TheBusyBiscuit syntymäpäivä (26. lokakuuta) + halloween: Halloween (31. lokakuuta) + androids: Ohjelmoitavat androidit diff --git a/src/main/resources/languages/categories_nl.yml b/src/main/resources/languages/categories_nl.yml index eef15e6b7..54f830d80 100644 --- a/src/main/resources/languages/categories_nl.yml +++ b/src/main/resources/languages/categories_nl.yml @@ -2,7 +2,7 @@ slimefun: weapons: Wapens tools: Gereedschappen - items: Voorwerpen + items: Handige Voorwerpen food: Eten basic_machines: Standaard machines electricity: Energie en Elektriciteit @@ -13,7 +13,7 @@ slimefun: misc: Diverse Voorwerpen technical_gadgets: Technische Gadgets resources: Grondstoffen - cargo: Cargobehering + cargo: Opslagbehering tech_misc: Technische Componenten magical_armor: Magische Bescherming talismans: Amuletten (Niveau I) diff --git a/src/main/resources/languages/categories_vi.yml b/src/main/resources/languages/categories_vi.yml index 0fa2393dc..f8a0798b4 100644 --- a/src/main/resources/languages/categories_vi.yml +++ b/src/main/resources/languages/categories_vi.yml @@ -14,7 +14,7 @@ slimefun: technical_gadgets: Những Đồ Dùng Kỹ Thuật resources: Những Tài Nguyên cargo: Quản Lý Hàng Hoá - tech_misc: Những Thành Phần Kỷ Thuật + tech_misc: Những Thành Phần Kỹ Thuật magical_armor: Giáp Ma Thuật talismans: Bùa Hộ Mệnh ( Loại I ) ender_talismans: Bùa Hộ Mệnh ( Loại II ) @@ -23,4 +23,4 @@ slimefun: easter: Lệ Phục Sinh (Tháng Tư) birthday: Sinh Nhật TheBusyBiscuit (26 Tháng 10) halloween: Halloween (31 tháng 10) - androids: Programmable Androids + androids: Android lập trình diff --git a/src/main/resources/languages/messages_bg.yml b/src/main/resources/languages/messages_bg.yml index 699fa7f3c..bfa337459 100644 --- a/src/main/resources/languages/messages_bg.yml +++ b/src/main/resources/languages/messages_bg.yml @@ -4,7 +4,7 @@ commands: cheat: Позволява Ви да чийтвате Предмети give: Позволява Ви да давате на някого Slimefun Предмети guide: Дава ви Slimefun Ръководство - teleporter: Вижте пътни точки от други играчи + teleporter: Вижте пътни точки на други играчи versions: Лист с всички инсталирани Добавки search: Претърсва вашето Ръководство за даден термин / предмет open_guide: Отваря Ви Slimefun Ръководството без да използвате книгата @@ -48,10 +48,10 @@ guide: selected-language: 'Избран в момента:' change: Натисни, за да избереш нов език description: - - "&7Сега имаш опцията да промениш" - - "&7езика, на който е Slimefun" - - "&7той ще се промени само за теб. Предметите" - - "&7не могат да бъдат преведени за момента." + '0': "&7Сега имаш опцията да промениш" + '1': "&7езика, на който е Slimefun" + '2': "&7той ще се промени само за теб. Предметите" + '3': "&7не могат да бъдат преведени за момента." title: main: Slimefun Ръководство settings: Настройки & Информация @@ -73,10 +73,10 @@ guide: profile-link: Натиснете, за да видите техния профил в GitHub open: Натисни, за да видиш нашите контрибутори description: - - "&7Slimefun е проект с отворен код" - - "&7и е поддържан от голямо общество от хора." - - "&7Над &e%contributors% &7хора са работили върху" - - "&7Slimefun през всички тези години." + '0': "&7Slimefun е проект с отворен код" + '1': "&7и е поддържан от голямо общество от хора." + '2': "&7Над &e%contributors% &7хора са работили върху" + '3': "&7Slimefun през всички тези години." pages: previous: Предишна страница next: Следваща страница @@ -96,9 +96,9 @@ guide: settings: Върнете се обратно в Панела с Настройки(Settings Panel) locked: ЗАКЛЮЧЕНО locked-category: - - За да отключите тази категория - - ще трябва да отключите всички предмети от - - следните категории + '0': За да отключите тази категория + '1': ще трябва да отключите всички предмети от + '2': следните категории work-in-progress: Тази функция не е завършена все още! messages: not-researched: "&4Нямате достатъчно познания, за да разберете това" @@ -154,22 +154,22 @@ messages: link-prompt: "&eНатиснете тук:" diet-cookie: "&eЗапочнахте да се чувствате доста лекичък..." fortune-cookie: - - "&7Помогнете ми, аз съм затворен в Фабрика за Късметлийски Бисквитки!" - - "&7Утре Вие ще умрете... от Creeper" - - "&7В някакъв момент от живота Ви нещо лошо ще се случи!!!" - - "&7Следващата седмица ще забележите, че това не е реалния свят, а всъщност Вие - сте в компютърна игра" - - "&7Тази бисквитка ще стане вкусна в следващите няколко секунди" - - '&7Последната дума, която ще чуете ще бъде "УНИЩОЖЕТЕ!!!"' - - "&7Каквото и да правите никога, ама никога не прегръщайте Creeper... Аз опитах. - Доста добре е, но не си заслужава." - - "&742. Отговорът е 42." - - "&7Walshy веднъж на ден ще пази неприятностите далече." - - "&7Никога не копайте право надолу!" - - "&7Туй е само плътна рана!" - - "&7Винаги гледайте от към хубавата страна на живота!" - - "&7Това беше Бисквитка, а не Курабийка" - - "&7Неоновите табели светят!" + '0': "&7Помогнете ми, аз съм затворен в Фабрика за Късметлийски Бисквитки!" + '1': "&7Утре Вие ще умрете... от Creeper" + '2': "&7В някакъв момент от живота Ви нещо лошо ще се случи!!!" + '3': "&7Следващата седмица ще забележите, че това не е реалния свят, а всъщност + Вие сте в компютърна игра" + '4': "&7Тази бисквитка ще стане вкусна в следващите няколко секунди" + '5': '&7Последната дума, която ще чуете ще бъде "УНИЩОЖЕТЕ!!!"' + '6': "&7Каквото и да правите никога, ама никога не прегръщайте Creeper... Аз опитах. + Доста добре е, но не си заслужава." + '7': "&742. Отговорът е 42." + '8': "&7Walshy веднъж на ден ще пази неприятностите далече." + '9': "&7Никога не копайте право надолу!" + '10': "&7Туй е само плътна рана!" + '11': "&7Винаги гледайте от към хубавата страна на живота!" + '12': "&7Това беше Бисквитка, а не Курабийка" + '13': "&7Неоновите табели светят!" piglin-barter: "&4Не може да разменяте предмети с Пиглините използвайки предмети от Slimefun" enchantment-rune: @@ -269,9 +269,9 @@ gps: max: "&4Достигнахте максималната бройка локации" duplicate: "&4Вие вече сте създал локация на име: &f%waypoint%" insufficient-complexity: - - "&4Недостатъчна Сложност на GPS Мрежата: &c%complexity%" - - "&4a) Все още нямате направена GPS Мрежа" - - "&4b) Вашата GPS Мрежа не е достатъчно сложна" + '0': "&4Недостатъчна Сложност на GPS Мрежата: &c%complexity%" + '1': "&4a) Все още нямате направена GPS Мрежа" + '2': "&4b) Вашата GPS Мрежа не е достатъчно сложна" geo: scan-required: "&4GEO-Scan изискан! &cПърво сканирайте този чънк използвайки GEO-Scanner!" inventory: @@ -310,11 +310,10 @@ android: INTERFACE_ITEMS: "&9Изпратни съдаржанието на Инвентара към лицевия Интерфейс" INTERFACE_FUEL: "&cИзвадете Гориво от лицевия Интерфейс" enter-name: - - - - "&eМоля въведете име за скрипта си" + '1': "&eМоля въведете име за скрипта си" uploaded: - - "&bКачване..." - - "&aУспешно качихме твоя скрипт!" + '0': "&bКачване..." + '1': "&aУспешно качихме твоя скрипт!" rating: own: "&4Не може да оцените собствения си скрипт!" already: "&4Вие вече сте оставили рейтинг за този скрипт!" @@ -370,3 +369,5 @@ cartography_table: not-working: "&4Не може да използвате Slimefun предмети в картографска маса!" cauldron: no-discoloring: "&4Не можете да обезцветявате Slimefun брони" +placeholderapi: + profile-loading: Зареждане... diff --git a/src/main/resources/languages/messages_cs.yml b/src/main/resources/languages/messages_cs.yml index 89f93a40f..127b0d438 100644 --- a/src/main/resources/languages/messages_cs.yml +++ b/src/main/resources/languages/messages_cs.yml @@ -1,34 +1,38 @@ --- commands: help: Zobrazí tuto nápovědu - cheat: Umožňuje nacheatovat věci - give: Dejte někomu nějaké Slimefun věci - guide: Dá vám Slimefun příručku - timings: Lag-Info vašeho serveru - teleporter: "Zobrazí \nznačky \nostatních hráčů" - versions: Seznam všech nainstalovaných doplňků - search: Vyhledá ve vaší příručce daný příkaz + cheat: Umožní našvindlovat si věci + give: Dá hráči vybrané Slimefun předměty + guide: Dá Slimefun příručku + teleporter: Zobrazí záchytné body ostatních hráčů + versions: Zobrazí všechny nainstalované doplňky + search: Vyhledá v příručce daný předmět open_guide: Otevře Slimefun příručku bez použití knihy stats: Ukáže statistiky hráče research: - description: Odemkne/Resetuje výzkum daného hráče + description: Odemkne či resetuje výzkum daného hráče reset: "&cResetoval jsi výzkum hráče %player%" reset-target: "&cTvoje znalost byla resetována " backpack: description: Načíst kopii existujícího batohu invalid-id: "&4Id nesmí být záporné!" player-never-joined: "&4Hráče s tímto jménem nelze nalézt!" - backpack-does-not-exist: "&4Určený batoh neexistuje!" + backpack-does-not-exist: "&4Zadaný batoh neexistuje!" restored-backpack-given: "&aTvůj batoh byl obnoven a navrácen do tvého inventáře!" + charge: + description: Nabije předmět, který držíš + charge-success: Předmět byl nabit! + not-rechargeable: Tento předmět nelze nabít! + timings: Lag-Info vašeho serveru guide: search: message: "&bCo bys chtěl vyhledat?" name: "&7Hledat..." - tooltip: "&bKliknutím vyhledejte položku" + tooltip: "&bKlikni pro vyhledání předmětu" inventory: 'Hledání: %item%' lore: - - "&bCo bys chtěl vyhledat?" - - "&7Napiš do chatu co chceš vyhledat" + '1': "&7Napiš do chatu co chceš vyhledat" + '0': "&bCo bys chtěl vyhledat?" cheat: no-multiblocks: "&4Nemůžeš podvádět v multiblocích, musíš je postavit!" languages: @@ -41,157 +45,169 @@ guide: selected-language: 'Aktuálně vybráno:' change: Klikni pro výběr nového jazyka description: - - "&7Nyní máš možnost to změnit" - - "&7jazyk, ve kterém bude Slimefun" - - "&7bude ti představeno. Předměty" - - "&7nelze prozatím přeložit." + '0': "&7Nyní máš možnost změnit" + '1': "&7jazyk, ve kterém ti bude" + '2': "&7Slimefun prezentován. Předměty" + '3': "&7nelze prozatím přeložit." title: main: Slimefun příručka settings: Nastavení a informace - languages: Zvol tvůj preferovaný jazyk + languages: Zvol svůj preferovaný jazyk credits: Slimefun4 pomocníci wiki: Slimefun4 Wiki - addons: Addony pro Slimefun4 + addons: Doplňky pro Slimefun4 bugs: Nahlášení chyb source: Zdrojový kód versions: Nainstalovaná verze credits: + commit: Commit commits: Commits roles: developer: "&6Vývojář" wiki: "&3Wiki správce" - resourcepack: "&cTvůrce Resourcepacku" - translator: "&9Překladač" - profile-link: Klikni pro navštívení jejich profilu na GitHubu - open: Klikni pro zobrazení našich spoluúčastníků + resourcepack: "&cTvůrce modifikačního balíčku" + translator: "&9Překladatel" + profile-link: Klikni pro navštívení jeho profilu na GitHubu + open: Klikni pro zobrazení našich pomocníků description: - - "&7Slimefun je open-source projekt" - - "&7a udržován velkou komunitou lidí." - - "&Přes&e%contributors% &7lidí na tom pracovalo" - - "&7Slimefun za všechny ty roky." + '0': "&7Slimefun je open-source projekt" + '1': "&7udržován velkou komunitou lidí." + '2': "&7Na Slimefunu za všechny ty roky pracovalo" + '3': "&7přes &e%contributors% &7lidí." pages: previous: Předchozí strana next: Následující strana tooltips: open-category: Klikni pro otevření versions-notice: To jsou velmi důležité při hlášení chyb! - wiki: Zobrazit tento předmět na oficiální SlimeFun Wiki + wiki: Zobrazit tento předmět na oficiální Slimefun Wiki recipes: machine: Recepty vytvářené tímto strojem miner: Materiály, které můžeš získat tímto těžebním robotem generator: Dostupné typy paliv gold-pan: Materiály, které můžeš získat + climbing-pick: Povrchy, na které můžeš lézt back: title: Zpět - guide: Zpět do Slimefun Guide - settings: Zpět do Settings Panel + guide: Zpět do Slimefun příručky + settings: Zpět do panelu nastavení locked: ZAMČENO locked-category: - - Chcete-li odemknout tuto kategorii, budete - - 'je třeba odemknout všechny položky z ' - - následující kategorie + '0': Chceš-li odemknout tuto kategorii, + '1': je potřeba odemknout všechny předměty + '2': z předchozích kategorií work-in-progress: Tato funkce ještě není zcela dokončena! messages: not-researched: "&4Ještě jsi nepostoupil tak daleko, abys pochopil tuhle věc" - not-enough-xp: "&4Nemáš dostatek XP levelů na to, abys vyzkoumal tuhle věc" - unlocked: '&bMáš vyzkoumáno &7"%research%"' + not-enough-xp: "&4Nemáš dostatek XP úrovní na to, abys vyzkoumal tuhle věc" + unlocked: "&bMáš vyzkoumáno &7„%research%”" only-players: "&4Tenhle příkaz je jenom pro hráče" unknown-player: "&4Neznámý hráč: &c%player%" - no-permission: "&4Na tohle nemáš dostatečné povolení" + no-permission: "&4Na tohle nemáš dostatečné oprávnění" usage: "&4Použití: &c%usage%" not-online: "&4%player% &czrovna není připojen!" - invalid-item: "&4%item% &cnení platný item!" - invalid-amount: "&4%amount% &cnení platné číslo : musí být větší než 0!" - given-item: '&bDostal jsi &a%amount% &7"%item%&7"' - give-item: '&bDal jsi %player% &a%amount% &7"%item%&7"' - invalid-research: "&4%research% &cnení platný výzkum!" + given-item: "&bDostal jsi &a%amount% &7„%item%&7”" + give-item: "&bDal jsi %player% &a%amount% &7„%item%&7”" give-research: '&bUdělil jsi %player% výzkum &7"%research%&7"' hungry: "&cJsi moc hladový na to, abys to zvládl!" disabled-in-world: "&4&lTahle věc není v tomhle světě povolená" disabled-item: |- &4&lTahle věc není povolená! Jak jsi ji vůbec dostal? - no-tome-yourself: "&cNemůžeš použít svůj &4Tome of Knowledge &c..." + no-tome-yourself: "&cNemůžeš použít svůj &4Tome of Knowledge&c..." multimeter: "&bEnergie: &3%stored% &b/ &3%capacity%" talisman: anvil: "&a&oTvůj talisman zachránil tvůj nástroj od rozbití" - miner: "&a&oTvůj talisman zdvojnásobil tvoje dropy" - hunter: "&a&oTvůj talisman zdvojnásobil tvoje dropy" + miner: "&a&oTvůj talisman zdvojnásobil tvou kořist" + hunter: "&a&oTvůj talisman zdvojnásobil tvou kořist" lava: "&a&oTvůj talisman tě zachránil před uhořením" water: "&a&oTvůj talisman tě zachránil před utopením" angel: "&a&oTvůj talisman tě zachránil před poškození pádem" fire: "&a&oTvůj talisman tě zachránil před uhořením" - magician: "&a&oTvůj talisman ti dal přídavné enchanty" + magician: "&a&oTvůj talisman ti dal dodatečná očarování" traveller: "&a&oTvůj talisman ti dal rychlost" - warrior: "&a&oTvůj talisman ti dal efekt síly na nějakou tu chvíli" - knight: "&a&oTvůj talisman ti dal 5 vteřin regenerace" + warrior: "&a&oTvůj talisman ti dal na určitou chvilku efekt síly" + knight: "&a&oTvůj talisman ti dal 5 sekund regenerace" whirlwind: "&a&oTvůj talisman odrazil projektil" - wizard: "&a&oTvůj talisman ti dal větší level Štěstí, ale možná snížil level jiných - enchantů" + wizard: "&a&oTvůj talisman ti dal větší úroveň štěstí, ale možná snížil úroveň + jiných očarování" + caveman: "&a&oTvůj talisman ti dal spěch" + wise: "& a&aTvůj talisman zdvojnásobil zisk tvých zkušeností" soulbound-rune: - fail: "&cKe své duši můžeš přidat jen jeden předmět." - success: "&aÚspěšně jsi přidal tento item ke své duši. Pokud zemřeš, item ti zůstane." + fail: "&cSvou duši můžeš spoutat jen s jedním předmětem." + success: "&aÚspěšně jsi spoutal tento předmět se svou duši. Pokud zemřeš, předmět + ti zůstane." research: - start: "&7Antičtí duchové šeptají magické slova do tvého ucha..." + start: "&7Antičtí duchové šeptají magická slova do tvého ucha..." progress: "&7Začal jsi přemýšlet nad &b%research% &e(%progress%)" fire-extinguish: "&7Uhasil ses" cannot-place: "&cZde nemůžeš položit blok!" no-pvp: "&cZde nemůžeš bojovat s hráči!" radiation: "&4Byl jsi vystaven smrtelné radiaci! &cVyhoď radioaktivní předmět nebo - si obleč Hazmat oblek." - opening-guide: "&bOtevírání příručky, může to pár sekund trvat..." - opening-backpack: "&bOtevírání batohu, může to pár sekund trvat..." - no-iron-golem-heal: "&cTo není Iron Ingot! S tímto nemůžeš léčit Iron Golemy!" + si obleč hazmat oblek." + opening-guide: "&bOtevírá se příručka, může to pár sekund trvat..." + opening-backpack: "&bOtevírá se batoh, může to pár sekund trvat..." + no-iron-golem-heal: "&cTohle není železný ingot, a proto s ním nemůžeš léčit železné + golemy!" link-prompt: "&eKlikni zde:" - diet-cookie: "&eZačínáš se cítit velice lehký..." + diet-cookie: "&eZačínáš se cítit velice lehce..." fortune-cookie: - - "&7POMOOC!! Jsem uvězněn v továrně na sušenky štěstí!" - - "&7Zítra zemřeš... s láskou od pana Creepera" - - "&7V nějaké části tvého života se stane něco špatného!!!" - - "&7Příští týden si uvědomíš, že toto není reálný život, ale jsi v počítačové hře." - - "&7Sušenka ti bude za pár vteřin velice chutnat" - - '&7Poslední slovo, které uslyšíš bude "VYHUBIT!!!"' - - "&7Ať se stane cokoliv, nepokoušej se mazlit Creepera... Zkusil jsem to. Je to - dobrý pocit, ale nestojí to za to." - - "&742. Odpověď je 42." - - "&7Walshy udrží den problémy pryč." - - "&7Nikdy nekopej pod sebe!" - - "&7To je jen rána masa!" - - "&7Vždy se podívejte na světlou stránku života!" - - "&7Tohle byl vlastně Biscuit a ne Cookie" - - "&7Neonové cedule jsou LIT!" - piglin-barter: "&4Nemůžete měnit s pigliny Slimefun předměty" + '0': "&7POMOOC!! Jsem uvězněn v továrně na sušenky štěstí!" + '1': "&7Zítra zemřeš... s láskou od pana creepera" + '2': "&7V nějaké části tvého života se stane něco špatného!!!" + '3': "&7Příští týden si uvědomíš, že toto není reálný život, ale že jsi v počítačové + hře" + '4': "&7Sušenka ti bude za pár sekund velice chutnat" + '5': "&7Poslední slovo, které uslyšíš bude „VYHUBIT!!!”" + '6': "&7Ať se stane cokoliv, nepokoušej se mazlit creepera... Zkusil jsem to. + Je to dobrý pocit, ale nestojí to za to." + '7': "&742. Odpověď je 42." + '8': "&7Walshy udrží den problémy pryč." + '9': "&7Nikdy nekopej pod sebe!" + '10': "&7To je jen rána masa!" + '11': "&7Vždy se podívej na světlou stránku života!" + '12': "&7Tohle byl vlastně Biscuit, a ne Cookie" + '13': "&7Neonové cedule jsou LIT!" + piglin-barter: "&4S pigliny nemůžeš vyměňovat Slimefun předměty" enchantment-rune: - fail: "&cNemůžeš enchantovat tento předmět" - no-enchantment: "&cPro tento předmět nelze najít žádný vhodný enchant." - success: "&aÚspěšně jsi na tento předmět daů náhodný enchant." + fail: "&cNemůžeš očarovat tento předmět." + no-enchantment: "&cPro tento předmět nelze najít žádné vhodné očarování." + success: "&aÚspěšně jsi na tento předmět dal náhodné vhodné očarování." tape-measure: - no-anchor: "&cMusíš nastavit kotvu než začneš měřit! " + no-anchor: "&cPřed začátkem měření musíš nastavit kotvu! " wrong-world: "&cTvoje kotva je pravděpodobně v jiném světa!" distance: "&7Měření zahájeno. &eVzdálenost: %distance%" anchor-set: "&aÚspěšně nastavena kotva:&e %anchor%" multi-tool: mode-change: "&b%device% mód změněn na: &9%mode%" not-shears: "&cMulti Tool nemůže být použit jako nůžky!" + climbing-pick: + dual-wielding: "&4Musíš držet Climbing Picks v obou rukou pro jeho použití!" + wrong-material: "&cNa tento povrch nemůžeš vylézt. Zkontroluj Slimefun Guide, + kde najdeš další informace!" + invalid-item: "&4%item% &cnení platný předmět!" + invalid-amount: "&4%amount% &cnení platné číslo. Musí být větší než 0!" + invalid-research: "&4%research% &cnení platný výzkum!" + bee-suit-slow-fall: "&eTvé Bee Wings ti pomohou bezpečně a pomalu se vrátit na zem" mode-change: "&b%device% mód změněn na: &9%mode%" machines: - pattern-not-found: "&eOmlouvám se, ale nerozpoznal jsem tento recept. Dej do dispenseru + pattern-not-found: "&eBohužel se nepodařilo rozpoznat tento recept. Dej do dávkovače předměty tak, aby odpovídaly receptu." - unknown-material: "&eOmlouvám se, ale nepoznal jsem předmět v dispenseru. Dej tam - něco, co znám." - wrong-item: "&eOmlouvám se, ale nerozpoznal jsem předmět, se kterým jsi na mě kliknul. + unknown-material: "&eBohužel se nepodařilo rozpoznat tento předmět v dávkovači. + Dej tam něco správného." + wrong-item: "&eBohužel se nepodařilo rozpoznat předmět, se kterým jsi na mě kliknul. Zkontroluj recept a koukni se, jaké předměty můžeš použít." - full-inventory: "&eOmlouvám se, můj inventář je plný." - in-use: "&cInventář tohoto bloku je právě otevřen jiným hráčem" + full-inventory: "&eBohužel, můj inventář je plný." + in-use: "&cInventář tohoto bloku je právě otevřen jiným hráčem." ignition-chamber-no-flint: "&cIgnition Chamberu chybí křesadlo." ANCIENT_ALTAR: - not-enough-pedestals: "&4Altáři chybí podstavce &c(%pedestals% / 8)" + not-enough-pedestals: "&4Altar nemá dostatek Pedestal &c(%pedestals% / 8)" unknown-catalyst: "&4Neznámý katalyst. &cPoužij správný recept!" unknown-recipe: "&4Neznámý recept! &cPoužij správný recept!" ANCIENT_PEDESTAL: - obstructed: "&4Podstavce jsou zablokované! &cOdstraň cokoliv nad podstavcema!" + obstructed: "&4Pedestal je zablokován! &cOdstraň cokoliv nad ním!" HOLOGRAM_PROJECTOR: - enter-text: "&7Napiš do chatu zprávu, kterou chceš, aby Hologram ukazoval. &r(Barvy + enter-text: "&7Napiš do chatu zprávu, kterou chceš, aby hologram ukazoval. &r(Barvy jsou podporovány!)" inventory-title: Editor hologramu ELEVATOR: @@ -199,62 +215,63 @@ machines: pick-a-floor: "&3- Vyber si patro -" current-floor: "&eAktuální patro:" click-to-teleport: "&eKliknutím &7se teleportuješ na toto patro:" - enter-name: "&7Prosím, zadejte název podlaží do chatu. &r(Barvy jsou podporovány!)" - named: "&2Podlaží úspěšně pojmenováno na: &r%floor%" + enter-name: "&7Zadej název podlaží do chatu. &r(Barvy jsou podporovány!)" + named: "&2Podlaží úspěšně pojmenováno: &r%floor%" TELEPORTER: teleporting: "&3Teleportuji..." teleported: "&3Teleportace dokončena!" cancelled: "&4Teleportace zrušena!" invulnerability: "&b&lZískal jsi 30 sekund nezranitelnosti!" gui: - title: Vaše waypointy - tooltip: Klikněte pro teleportaci + title: Tvé záchytné body + tooltip: Klikni pro teleportaci time: Předpokládaný čas CARGO_NODES: must-be-placed: "&4Musí být umístěn na truhlu nebo stroj!" GPS_CONTROL_PANEL: title: GPS - Kontrolní panel transmitters: Přehled vysílačů - waypoints: Přehled waypointů + waypoints: Přehled záchytných bodů INDUSTRIAL_MINER: - no-fuel: "&cTvému průmyslovému horníku došlo palivo! Vložte palivo do bedny nad." + no-fuel: "&cTvému průmyslovému horníku došlo palivo! Vlož palivo do bedny nad." piston-facing: "&cTvůj průmyslový horník potřebuje píst směřující nahoru!" piston-space: "&cDva písty potřebují prázdný blok nad nimi!" - destroyed: "&cZdá se, váš průmysloví horník byl rozbit." + destroyed: "&cZdá se, že tvůj průmyslový horník byl zničen." already-running: "&cTento průmyslový horník již běží!" full-chest: "&cBedna vašeho průmyslového horníka je plná!" - no-permission: "&4Zdá se, nemáte oprávnění používat průmyslového horníka zde!" - finished: "&eVáš průmysloví horník dokončil práci! Získal %ores% hornin!" + no-permission: "&4Zdá se, že zde nemáš oprávnění používat průmyslového horníka!" + finished: "&eTvůj průmysloví horník dokončil práci! Získal %ores% rud!" anvil: not-working: "&4Předměty ze Slimefunu nelze použít v kovadlině!" + mcmmo-salvaging: "&4Nemůžeš zachránit Slimefun předměty!" backpack: - already-open: "&cOmlouváme se, tento batoh je otevřený již někde jinde!" - no-stack: "&cNemůžeš stackovat batohy" + already-open: "&cBohužel, tento batoh je již otevřený někde jinde!" + no-stack: "&cNemůžeš shromažďovat batohy" workbench: - not-enhanced: "&4Nemůžeš použít itemy ze Slimefunu v normální výrobě" + not-enhanced: "&4Nemůžeš použít předměty ze Slimefunu v normální pracovním stole" gps: deathpoint: "&4Bod úmrtí &7%date%" waypoint: - new: "&eProsím, zadejte název waypointu do chatu. &7(Barvy jsou podporovány!)" - added: "&aÚspěšně přidán nový waypoint" - max: "&4Dosáhl jsi maxima waypointů" - duplicate: "&4Již jsi vytvořil waypoint pojmenovaný: &f%waypoint%" + new: "&eZadej název záchytného bodu do chatu. &7(Barvy jsou podporovány!)" + added: "&aÚspěšně přidán nový záchytný bod" + max: "&4Dosáhl jsi maxima záchytných bodů" + duplicate: "&4Již jsi vytvořil záchytný bod pojmenovaný: &f%waypoint%" insufficient-complexity: - - "&4Nedostatečná komplexita GPS Networku: &c%complexity%" - - "&4a) Nemáš nastavený GPS Network" - - "&4b) TvůjGPS Network není dostatečně komplexní" + '0': "&4Nedostatečná komplexita GPS Networku: &c%complexity%" + '1': "&4a) Nemáš nastavený GPS Network" + '2': "&4b) Tvůj GPS Network není dostatečně komplexní" geo: - scan-required: "&4GEO-Scan je požadován! &cProzkoumejte tento chunk pomocí GEO-Scanneru!" + scan-required: "&4GEO-Scan je požadován! &cProzkoumej tento chunk pomocí GEO-Scanneru!" inventory: no-access: "&4Nemáš přístup k tomuto bloku" android: - started: "&7Tvůj Android právě začal používat jemu přidělený script" - stopped: "&7Tvůj Android pozastavil jemu přidělený script" + started: "&7Tvůj Android právě začal používat jemu přidělený skript" + stopped: "&7Tvůj Android pozastavil jemu přidělený skript" scripts: - already-uploaded: "&4Tento script byl již nahrán." + already-uploaded: "&4Tento skript již byl nahrán." instructions: - START: "&2Začít Script" - REPEAT: "&9Opakovat Script" + START: "&2Začít skript" + REPEAT: "&9Opakovat skript" WAIT: "&ePočkej 0.5s" GO_FORWARD: "&7Posuň se vpřed" GO_UP: "&7Posuň se nahoru" @@ -267,10 +284,10 @@ android: MOVE_AND_DIG_UP: "&bPosuň se a zároveň kopej nahoru" MOVE_AND_DIG_FORWARD: "&bPosuň se a zároveň kopej dopředu" MOVE_AND_DIG_DOWN: "&bPosuň se a zároveň kopej dolů" - ATTACK_MOBS_ANIMALS: "&4Útoč na &cnepřátelské moby a zvířata" - ATTACK_MOBS: "&4Útoč na &cnepřátelské moby" + ATTACK_MOBS_ANIMALS: "&4Útoč na &cnepřátelská stvoření a zvířata" + ATTACK_MOBS: "&4Útoč na &cnepřátelská stvoření" ATTACK_ANIMALS: "&4Útoč na &czvířata" - ATTACK_ANIMALS_ADULT: "&4Útoč na &czvířata&7[Dospělá]" + ATTACK_ANIMALS_ADULT: "&4Útoč na &czvířata &7[Dospělá]" CHOP_TREE: "&cPokácej a zasaď" CATCH_FISH: "&bRybař" FARM_FORWARD: "&bSkliď a zasaď" @@ -280,15 +297,15 @@ android: INTERFACE_ITEMS: "&9Přesuň obsah inventáře do rozhraní na přední straně" INTERFACE_FUEL: "&cVyndej palivo z rozhraní přední strany" enter-name: - - - - "&eProsíme, zadejte název vašeho scriptu" + '1': "&eZadej název tvého skriptu" uploaded: - - "&bNahrávání..." - - "&aTvůj script byl úspěšně nahrán!" + '0': "&bNahrávání..." + '1': "&aTvůj skript byl úspěšně nahrán!" rating: - own: "&4Nemůžeš hodnotit vlastní script!" - already: "&4K tomuto scriptu jsi již zanechal hlasování!" + own: "&4Nemůžeš hodnotit vlastní skript!" + already: "&4K tomuto skriptu jsi již zanechal hlasování!" editor: Editor skriptu + too-long: "&cSkript je příliš dlouhý na úpravu!" languages: default: Výchozí-serverový en: Angličtina @@ -298,7 +315,7 @@ languages: es: Španělština pl: Polština sv: Švédština - nl: Holandština + nl: Nizozemština cs: Čeština hu: Maďarština lv: Lotyština @@ -310,8 +327,6 @@ languages: zh-CN: Čínština (Čína) el: Řečtina he: Hebrejština - pt: Portugalština (Portugalsko) - pt-BR: Portugalština (Brazílie) ar: Arabština af: Afrikánština da: Dánština @@ -323,6 +338,8 @@ languages: fa: Perština th: Thajština ro: Rumunština + pt: Portugalština (Portugalsko) + pt-BR: Portugalština (Brazílie) bg: Bulharština ko: Korejština tr: Turečtina @@ -330,9 +347,16 @@ languages: mk: Makedonština sr: Srbština be: Běloruština + tl: 'Tagalština ' brewing_stand: not-working: "&4Nemůžeš používat Slimefun předměty ve varném stojanu!" villagers: - no-trading: "&4Nemůžeš měnit Slimefun předměty s vesničany!" + no-trading: "&4Nemůžeš vyměňovat Slimefun předměty s vesničany!" +cartography_table: + not-working: "&4Nemůžeš použít Slimefun předměty v kartografickém stole!" +cauldron: + no-discoloring: "&4Nemůžeš odebrat barvu ze Slimefun brnění" +placeholderapi: + profile-loading: Načítání... miner: no-ores: "&eOmlouvám se, nemohu najít rudy v okolí!" diff --git a/src/main/resources/languages/messages_de.yml b/src/main/resources/languages/messages_de.yml index 6853972c2..86aaf9a9c 100644 --- a/src/main/resources/languages/messages_de.yml +++ b/src/main/resources/languages/messages_de.yml @@ -342,7 +342,6 @@ languages: zh-CN: Chinesisch (China) el: Griechisch he: Hebräisch - pt: Portugiesisch (Portugal) pt-BR: Portugiesisch (Brasilien) ar: Arabisch af: Afrikaans @@ -355,6 +354,7 @@ languages: fa: Persisch th: Thailändisch ro: Rumänisch + pt: Portugiesisch (Portugal) bg: Bulgarisch ko: Koreanisch tr: Türkisch @@ -373,3 +373,5 @@ cauldron: no-discoloring: "&4Du kannst Slimefun-Rüstung nicht entfärben" miner: no-ores: "&eIch konnte leider keine Erze in der Nähe finden!" +placeholderapi: + profile-loading: Lade... diff --git a/src/main/resources/languages/messages_fr.yml b/src/main/resources/languages/messages_fr.yml index a3d15040a..f7c71ae96 100644 --- a/src/main/resources/languages/messages_fr.yml +++ b/src/main/resources/languages/messages_fr.yml @@ -4,7 +4,6 @@ commands: cheat: Vous permet de vous donnez des objets give: Donne à quelqu'un des objets Slimefun guide: Vous donne un guide Slimefun - timings: Informations sur la latence de votre serveur teleporter: Affiche les waypoints d'un autre joueur versions: Affiche toutes les extensions installées search: Recherche dans votre guide le terme donné @@ -25,6 +24,11 @@ commands: description: Charge l'objet que vous avez en main charge-success: L'objet a été chargé ! not-rechargeable: Cet objet ne peut pas être chargé ! + timings: + description: Timings pour Slimefun et ses addons + please-wait: "&eAttendez s'il vous plaît, les résultats arrivent !" + verbose-player: "&4Ce flag ne peux pas être utiliser par un joueur!" + unknown-flag: "&4Flag inconnu: &c%flag%" guide: search: message: "&bQue souhaitez-vous rechercher?" @@ -134,6 +138,7 @@ messages: wizard: "&a&oVotre talisman vous a donné un meilleur niveau de Fortune mais a peut-être diminué plusieurs autres enchantements" caveman: "&a&oVotre Talisman vous a donné Célérité" + wise: "&a&oVotre talisman a doublé votre XP" soulbound-rune: fail: "&cVous pouvez lier un seul objet à la fois à votre âme" success: "&aVous avez réussi à lier cet objet à votre âme! Vous le garderez quand @@ -193,9 +198,9 @@ messages: invalid-amount: "&4%amount% &cn'est pas un montant valide: il doit être supérieur à 0!" invalid-research: "&4%research% &cn'est pas une recherche valide!" - mode-change: 'Vous avez changé votre &b%device% en mode : &9%mode%' bee-suit-slow-fall: "&eVos ailes d'abeille vous aideront à revenir au sol lentement et en toute sécurité" + mode-change: 'Vous avez changé votre &b%device% en mode : &9%mode%' machines: pattern-not-found: "&eDésolé, je ne reconnais pas cette recette. Veuillez disposer les objets correctement dans le distributeur." diff --git a/src/main/resources/languages/messages_he.yml b/src/main/resources/languages/messages_he.yml index 3e26c0d63..170137953 100644 --- a/src/main/resources/languages/messages_he.yml +++ b/src/main/resources/languages/messages_he.yml @@ -1,11 +1,18 @@ --- commands: help: הצגת מסך עזרה - teleporter: ראה נקודות ציון של שחקנים אחרים - search: חפש במדריך את המונח הנתון cheat: מאפשר לזמן פריטים ברמאות give: נותן למישהו פירטי סליים פאן guide: תן לעצמך מדריך סליים פאן + teleporter: ראה נקודות ציון של שחקנים אחרים + versions: הצגת תוספים מותקנים + search: חפש במדריך את המונח הנתון + open_guide: פתח את המדריך בלי להשתמש בספר + stats: מציג כמה נתונים סטטיסטיים על שחקן + research: + description: 'בטל נעילה /מחקרים עבור שחקן זה ' + reset: "&c איפס את הידע של %שחקן% זה" + reset-target: "&cהידע שלך אופס " backpack: description: אחזר עותק של גיבוי קיים invalid-id: " המספר המזהה חייב להיות מספר לא שלילי!&4" @@ -21,46 +28,15 @@ commands: please-wait: "&e !אנא המתן שנייה ... התוצאות מגיעות" verbose-player: "&4 האיתות המילולי אינו יכול להיות בשימוש על ידי שחקן!" unknown-flag: "&4איתות לא ידוע: &c%flag%" - versions: הצגת תוספים מותקנים - open_guide: פתח את המדריך בלי להשתמש בספר - stats: מציג כמה נתונים סטטיסטיים על שחקן - research: - description: 'בטל נעילה /מחקרים עבור שחקן זה ' - reset: "&c איפס את הידע של %שחקן% זה" - reset-target: "&cהידע שלך אופס " guide: - title: - main: סליים פאן מדריך - credits: סליים פאן4 תורמים - wiki: סליים פאן4 ויקי - addons: 'תוספות לסליים פאן ' - versions: גרסאות מותקנות - settings: 'הגדרות & מידע ' - languages: בחר את השפה המועדפת עליך - bugs: דיווחי שגיאות - source: קוד מקור - back: - guide: חזור למדריך סליים פאן - title: חזור - settings: חזור ללוח ההגדרות - tooltips: - wiki: ראה פריט זה באתר הרשימי של סליים פאן ויקי - recipes: - climbing-pick: משטחים שאפשר לטפס עליהם - machine: מתכונים שנעשו במכונה זו - miner: משאבים שתוכלו להשיג אצל כורה זה - generator: סוגי דלק זמינים - gold-pan: משאבים שתוכלו להשיג - open-category: לחץ לפתיחה - versions-notice: אלה חשובים מאוד כשמדווחים על באגים! - work-in-progress: תכונה זו עדיין לא הושלמה במלואה! + search: + message: מה תרצה לחפש? + name: "&7חפש...." + tooltip: "&b לחץ לחפש פריט" + inventory: "%item% מחפש עבור: " + cheat: + no-multiblocks: "&4 אתה לא יכול לרמות בריבוי מבנים אתה חייב לבנות אותם!" languages: - change: לחץ כדי לבחור שפה חדשה - description: - - "&7כעת יש לך אפשרות לשנות" - - "&7השפה שבה סליים פאן" - - "&7יוצג בפניך. פריטים" - - "&7לא ניתן לתרגם לעת עתה." updated: "&a :השפה שלך הוגדרה בהצלחה ל &b%lang%" translations: name: "&aIs משהו חסר?" @@ -68,13 +44,23 @@ guide: select: 'לחץ כדי לבחור שפה זאת ' select-default: לחץ לבחירת שפת ברירת המחדל selected-language: 'נבחר כעת:' - credits: - open: לחץ כדי לראות את התורמים שלנו + change: לחץ כדי לבחור שפה חדשה description: - - "&7 סליים פאן הוא פרויקט קוד פתוח " - - "&7ומתוחזק על ידי קהילה גדולה של אנשים." - - "&7על &e%contributors% &7אנשים עבדו" - - "&7.סליים פאן לאורך כל השנים האלה " + - "&7כעת יש לך אפשרות לשנות" + - "&7השפה שבה סליים פאן" + - "&7יוצג בפניך. פריטים" + - "&7לא ניתן לתרגם לעת עתה." + title: + main: סליים פאן מדריך + settings: 'הגדרות & מידע ' + languages: בחר את השפה המועדפת עליך + credits: סליים פאן4 תורמים + wiki: סליים פאן4 ויקי + addons: 'תוספות לסליים פאן ' + bugs: דיווחי שגיאות + source: קוד מקור + versions: גרסאות מותקנות + credits: commit: להתחייב commits: מתחייב roles: @@ -83,32 +69,60 @@ guide: resourcepack: "&c אמן חבילת משאבים" translator: "&9מתרגם" profile-link: "לחץ כדי לבקר את הפרופיל שלהם \nב -GitHub" - search: - message: &b מה תרצה לחפש? - name: "&7חפש...." - tooltip: "&b לחץ לחפש פריט" - inventory: "%item% מחפש עבור: " - cheat: - no-multiblocks: "&4 אתה לא יכול לרמות בריבוי מבנים אתה חייב לבנות אותם!" + open: לחץ כדי לראות את התורמים שלנו + description: + - "&7 סליים פאן הוא פרויקט קוד פתוח " + - "&7ומתוחזק על ידי קהילה גדולה של אנשים." + - "&7על &e%contributors% &7אנשים עבדו" + - "&7.סליים פאן לאורך כל השנים האלה " pages: previous: עמוד קודם next: עמוד הבא + tooltips: + open-category: לחץ לפתיחה + versions-notice: אלה חשובים מאוד כשמדווחים על באגים! + wiki: ראה פריט זה באתר הרשימי של סליים פאן ויקי + recipes: + machine: מתכונים שנעשו במכונה זו + miner: משאבים שתוכלו להשיג אצל כורה זה + generator: סוגי דלק זמינים + gold-pan: משאבים שתוכלו להשיג + climbing-pick: משטחים שאפשר לטפס עליהם + back: + title: חזור + guide: חזור למדריך סליים פאן + settings: חזור ללוח ההגדרות locked: נעול locked-category: - כדי לבטל את הנעילה של קטגוריה זו - 'צריך לפתוח את כל הפריטים מה ' - הקטגוריות הבאות + work-in-progress: תכונה זו עדיין לא הושלמה במלואה! messages: + not-researched: "&4אין לך מספיק ידע להבין זאת " not-enough-xp: "&4אין לך מספיק נקודות ניסיון\nכדי לפתוח את זה " + unlocked: "&b אתה פתחת %research% " + only-players: "&4 פקודה זו מיועדת רק לשחקנים" + unknown-player: "&4 :שחקן לא מוכר &c%player%" + no-permission: "&4 אין לך את ההרשאה הנדרשת לעשות זאת" + usage: "&4 שימוש: &c %שימוש%" + not-online: "&4 %שחקן%cis לא ברשת!" + given-item: '&b ניתן לך סכום &a %amount% &7"%item%7' + give-item: "&b %ניתן לך %amount% &a %item%" + give-research: '&b נתת %player% את המח"%research%&7"' + hungry: "&cאתה רעב מדיי כדי לעשות את זה!" + disabled-in-world: "&4 פריט זה הושבת בעולם זה" + disabled-item: "&4 פריט זה הושבת איך בכלל השגת את זה ?" + no-tome-yourself: "&c אינך יכול להשתמש ב- 4 כרך של מידע צמך...." + multimeter: "&bStored Energy: &3%stored% &b/ &3%capacity%" talisman: - angel: "&a&o הקמע שלך הציל אותך מלקבל נזק נפילה" - fire: "&a&oהקמע שלך הציל אותך מלהישרף למוות" - caveman: "&a&oהקמע שלך נתן לך מהירות" anvil: "&a&o הקמע שלך הציל את הכלי שלך מלהישבר" miner: "&a&o הקמע שלך בכפיל את הפריטים הנופלים" hunter: "&a&o הקמע שלך בכפיל את הפריטים הנופלים" lava: "&a&oהקמע שלך הציל אותך מלהישרף למוות" water: "&a&oהקמע שלך הציל אותך מלטבוע " + angel: "&a&o הקמע שלך הציל אותך מלקבל נזק נפילה" + fire: "&a&oהקמע שלך הציל אותך מלהישרף למוות" magician: "&a%o הקמע שלך העניק לך כישוף נוסף" traveller: "&a&o הקמע שלך נתן לך דחיפת מהירות" warrior: "&a&oהקמע שלך שיפר את כוחך לזמן מה" @@ -116,54 +130,8 @@ messages: whirlwind: "&a&o הקמע שלך שיקף את הטיל" wizard: "&a&o הקמע שלך העניק לך רמת הון טובה יותר אבל אולי גם הוריד כמה רמות הקסם אחרות" - fortune-cookie: - - "&7 עזור לי, אני כלוא במפעל לעוגיות " - - "&7אתה תמות מחר על ידי.... קריפר " - - "&7 בשלב מסוים בחיים שלך משהו רע יקרה!!!" - - "&7בשבוע הבא תבחין שזה לא העולם האמיתי, אתה נמצא במשחק מחשב" - - "עוגיה זו תהיה טעימה תוך כמה שניות &7" - - '&7 המילה האחרונה שתשמע תהיה "להשמיד !!!"' - - "&7מה שלא תעשה אל תחבק קריפר ניסיתי. זה מרגיש טוב,אבל לא שווה את זה" - - "&7התשובה היא 42" - - "&7 וולשי ביום ירחיקו את הצרות." - - "&7 לעולם אל תחפור ישר למטה!" - - "&7זו רק שריטה!" - - "&7תמיד תסתכל על הצד הטוב שבחיים" - - "&7זה היה למעשה ביסקוויט ולא עוגיה" - - "&7שלטי הניאון דולקים" - piglin-barter: &4 אתה לא יכול לסחור עם חזירונים באמצעות חפצי סליים פאן - enchantment-rune: - fail: "&cאת לא יכול להחליף עם חזירונים חפצים של סליים פאן." - no-enchantment: "&cלא נמצא שום קסם ישים לפריט הזה." - success: "&aהחלת בהצלחה קסם אקראי החל על פריט זה." - tape-measure: - no-anchor: "&c אתה צריך להגדיר עוגן לפני שתוכל להתחיל למדוד!" - wrong-world: "!&cנראה שהעוגן שלך נמצא בעולם אחר" - distance: "&7המדידה נלקחה &eDistance: %distance%." - anchor-set: "&aהעוגן הוגדר בהצלחה:&e %anchor%" - multi-tool: - mode-change: "&b%device% &9: המצב השתנה ל: %mode%" - not-shears: "&c מולטי טול לא יכול לשמש כמזמרה!" - climbing-pick: - dual-wielding: "&4אתה צריך להחזיק מכושי טיפוס בשתי !הידיים כדי להשתמש בהם" - wrong-material: "&cאתה לא יכול לטפס על המשטח הזה. עיין במדריך סליים פאן למידע - נוסף!" - bee-suit-slow-fall: "&eכנפי הדבורה שלך יעזרו לך להגיע לקרקע בצורה איטית ובטוחה" - not-researched: "&4אין לך מספיק ידע להבין זאת " - unlocked: "&b אתה פתחת %research% " - only-players: "&4 פקודה זו מיועדת רק לשחקנים" - unknown-player: "&4 :שחקן לא מוכר &c%player%" - no-permission: "&4 אין לך את ההרשאה הנדרשת לעשות זאת" - usage: "&4 שימוש: &c %שימוש%" - not-online: "&4 %שחקן%cis לא ברשת!" - given-item: "&b ניתן לך סכום &a %amount% &7\"%item%7" - give-item: '&b %ניתן לך %amount% &a %item%' - give-research: "&b נתת %player% את המח\"%research%&7\"" - hungry: "&cאתה רעב מדיי כדי לעשות את זה!" - disabled-in-world: "&4 פריט זה הושבת בעולם זה" - disabled-item: "&4 פריט זה הושבת איך בכלל השגת את זה ?" - no-tome-yourself: "&c אינך יכול להשתמש ב- 4 כרך של מידע צמך...." - multimeter: '&bStored Energy: &3%stored% &b/ &3%capacity%' + caveman: "&a&oהקמע שלך נתן לך מהירות" + wise: "&a&oהקמע שלך הכפיל את ירידת נקודות הניסיון שלך" soulbound-rune: fail: "&c אתה יכול לקשור פריט אחד בלבד לנשמתך בכל פעם." success: "&a אתה קושרת פריט זה בהצלחה לנשמתך! אתה תשמור עליו כשתמות." @@ -182,87 +150,43 @@ messages: ברזל!" link-prompt: "&e לחץ כאן:" diet-cookie: "&eאתה מתחיל להרגיש מרחף...." + fortune-cookie: + - "&7 עזור לי, אני כלוא במפעל לעוגיות " + - "&7אתה תמות מחר על ידי.... קריפר " + - "&7 בשלב מסוים בחיים שלך משהו רע יקרה!!!" + - "&7בשבוע הבא תבחין שזה לא העולם האמיתי, אתה נמצא במשחק מחשב" + - עוגיה זו תהיה טעימה תוך כמה שניות &7 + - '&7 המילה האחרונה שתשמע תהיה "להשמיד !!!"' + - "&7מה שלא תעשה אל תחבק קריפר ניסיתי. זה מרגיש טוב,אבל לא שווה את זה" + - "&7התשובה היא 42" + - "&7 וולשי ביום ירחיקו את הצרות." + - "&7 לעולם אל תחפור ישר למטה!" + - "&7זו רק שריטה!" + - "&7תמיד תסתכל על הצד הטוב שבחיים" + - "&7זה היה למעשה ביסקוויט ולא עוגיה" + - "&7שלטי הניאון דולקים" + piglin-barter: אתה לא יכול לסחור עם חזירונים באמצעות חפצי סליים פאן + enchantment-rune: + fail: "&cאת לא יכול להחליף עם חזירונים חפצים של סליים פאן." + no-enchantment: "&cלא נמצא שום קסם ישים לפריט הזה." + success: "&aהחלת בהצלחה קסם אקראי החל על פריט זה." + tape-measure: + no-anchor: "&c אתה צריך להגדיר עוגן לפני שתוכל להתחיל למדוד!" + wrong-world: "!&cנראה שהעוגן שלך נמצא בעולם אחר" + distance: "&7המדידה נלקחה &eDistance: %distance%." + anchor-set: "&aהעוגן הוגדר בהצלחה:&e %anchor%" + multi-tool: + mode-change: "&b%device% &9: המצב השתנה ל: %mode%" + not-shears: "&c מולטי טול לא יכול לשמש כמזמרה!" + climbing-pick: + dual-wielding: "&4אתה צריך להחזיק מכושי טיפוס בשתי !הידיים כדי להשתמש בהם" + wrong-material: "&cאתה לא יכול לטפס על המשטח הזה. עיין במדריך סליים פאן למידע + נוסף!" invalid-item: "&4%item% &cאינו פריט בר תוקף!" invalid-amount: "&4%amount% &cאינו כמות ברת תוקף : המספר חייב להיות גדול מאפס!" invalid-research: "&4%research% &cאינו מחקר בר תוקף!" -anvil: - not-working: "&4אתה לא יכול להשתמש בפרטי סליים פאן בתוך סדן" - mcmmo-salvaging: "&4אתה לא יכול להציל (לתקן) חפצי סליים פאן" -workbench: - not-enhanced: "&4 אתה לא יכול להשתמש בפרטי סליים פאן על שולחן עבודה רגיל" -gps: - geo: - scan-required: |- - &4-סורק גאולוגי נדרש! - &c סרוק את הנתח הזה באמצעות סורק !גאולוגי-קודם - waypoint: - duplicate: "&4כבר יצרת נקודת ציון בשם: &f%waypoint%" - new: "&eהקלד שם לנקודת הדרך החדשה שלך בצ'אט. (קודי צבע נתמכים!)" - added: "&a נוסף בהצלחה נקודת דרך חדשה" - max: "&4 הגעת לכמות הנקודות הדרך המרבית" - deathpoint: |- - &4נקודת מוות - &7%date% - insufficient-complexity: - - "&4אין מספיק מורכבות ברשת ה GPS: &c%complexity%" - - "&4a) אין לך הגדרות רשת GPS עדיין" - - "&4b) הגדרות ה GPS שלך לא מספיק מורכבות" -languages: - zh-CN: "(מנדרינית(סין" - tl: טגלית - default: שרת ברירת מחדל - en: אנגלית - de: 'גרמנית ' - fr: צרפתית - it: איטלקית - es: ספרדית - pl: פולנית - sv: שוודית - nl: הולנדית - cs: צ'כית - hu: הונגרית - lv: לטבית - ru: רוסית - sk: סלובקית - zh-TW: "(סינית (טייוואן" - vi: וייטנאמי - id: אינדונזית - el: יווני - he: עברית - ar: ערבית - af: אפריקנית - da: דנית - fi: פינית - uk: אוקראינית - ms: מלאית - 'no': נורווגית - ja: יפנית - fa: פרסית - th: תאילנדי - ro: רומנית - pt: "(פורטוגזית (פורטוגל" - pt-BR: "(פורטוגזית (ברזיל" - bg: בולגרית - ko: קוריאנית - tr: טורקי - hr: קרואטית - mk: מקדונית - sr: סרבית - be: בלארוסית + bee-suit-slow-fall: "&eכנפי הדבורה שלך יעזרו לך להגיע לקרקע בצורה איטית ובטוחה" machines: - GPS_CONTROL_PANEL: - title: לוח בקרה - ג'י פי אס - transmitters: סקירה משדר - waypoints: סקירת נקודות דרך - INDUSTRIAL_MINER: - no-fuel: &c לכורה התעשייתית שלך אזל הדלק! שים את הדלק שלך בתיבה מעל. - piston-facing: "&cהכורה התעשייתי שלך דורש בוכנות מופנות כלפי מעלה!" - piston-space: "&cלשתי הבוכנות צריך להיות בלוק מעליהן!" - destroyed: "&cנראה שכורה התעשייתי שלך הושמד." - already-running: "&cהכורה התעשייתית הזה עדיין פועל." - full-chest: "&cהתיבה של הכורה התעשייתי שלך מלאה!" - no-permission: נראה שאין לך אישור להפעיל כאן כורה תעשייתי!&4 - finished: "&eהכורה התעשייתי שלך סיים את !%ores% ore(s)!עבודתו! הוא חצב" pattern-not-found: "&e סליחה לא יכולתי \n .לזהות את המתכון \nאנא הכנס את \nהפריטים בדפוס הנכון לתוך המתקן " unknown-material: "&e סליחה, לא יכולתי לזהות את הפריט במתקן שלי. אנא הכנס משהו שאני @@ -273,7 +197,8 @@ machines: in-use: "&c המלאי של בלוק זה נפתח כרגע על ידי שחקן אחר." ignition-chamber-no-flint: "&c תא הצתה חסר צור ופלדה." ANCIENT_ALTAR: - not-enough-pedestals: "&4 המזבח אני מוקף בכמות המתאימה של כינים &c(%pedestals% /\n8( " + not-enough-pedestals: "&4 המזבח אני מוקף בכמות המתאימה של כינים &c(%pedestals% + /\n8( " unknown-catalyst: "&4 זרז לא ידוע! &c השתמש במתכון הנכון במקום זאת!" unknown-recipe: "&4 מתכון לא ידוע! &cהשתמש במתכון הנכון במקום!" ANCIENT_PEDESTAL: @@ -301,17 +226,50 @@ machines: time: זמן משוער CARGO_NODES: must-be-placed: "&4חייב להיות מונח על תיבה או מכונה!" -brewing_stand: - not-working: "&4אתה לא יכול לשים חפצי סליים פאן במבשלה!" -villagers: - no-trading: "&4אתה לא יכול להחליף עם ויליג'רים חפצי סליים פאן!" -cartography_table: - not-working: "&4אתה לא יכול להשתמש בחפצי סליים פאן בשולחן קרטוגרפיה!" -cauldron: - no-discoloring: "&4אתה לא יכול לשנות את הצבע של שריון סליים פאן" + GPS_CONTROL_PANEL: + title: לוח בקרה - ג'י פי אס + transmitters: סקירה משדר + waypoints: סקירת נקודות דרך + INDUSTRIAL_MINER: + no-fuel: לכורה התעשייתית שלך אזל הדלק! שים את הדלק שלך בתיבה מעל. + piston-facing: "&cהכורה התעשייתי שלך דורש בוכנות מופנות כלפי מעלה!" + piston-space: "&cלשתי הבוכנות צריך להיות בלוק מעליהן!" + destroyed: "&cנראה שכורה התעשייתי שלך הושמד." + already-running: "&cהכורה התעשייתית הזה עדיין פועל." + full-chest: "&cהתיבה של הכורה התעשייתי שלך מלאה!" + no-permission: נראה שאין לך אישור להפעיל כאן כורה תעשייתי!&4 + finished: "&eהכורה התעשייתי שלך סיים את !%ores% ore(s)!עבודתו! הוא חצב" +anvil: + not-working: "&4אתה לא יכול להשתמש בפרטי סליים פאן בתוך סדן" + mcmmo-salvaging: "&4אתה לא יכול להציל (לתקן) חפצי סליים פאן" +backpack: + already-open: "&cסליחה התרמיל הזה פתוח במקום אחר " + no-stack: "&cאתה לא יכול לערום תרמילים" +workbench: + not-enhanced: "&4 אתה לא יכול להשתמש בפרטי סליים פאן על שולחן עבודה רגיל" +gps: + deathpoint: |- + &4נקודת מוות + &7%date% + waypoint: + new: "&eהקלד שם לנקודת הדרך החדשה שלך בצ'אט. (קודי צבע נתמכים!)" + added: "&a נוסף בהצלחה נקודת דרך חדשה" + max: "&4 הגעת לכמות הנקודות הדרך המרבית" + duplicate: "&4כבר יצרת נקודת ציון בשם: &f%waypoint%" + insufficient-complexity: + - "&4אין מספיק מורכבות ברשת ה GPS: &c%complexity%" + - "&4a) אין לך הגדרות רשת GPS עדיין" + - "&4b) הגדרות ה GPS שלך לא מספיק מורכבות" + geo: + scan-required: |- + &4-סורק גאולוגי נדרש! + &c סרוק את הנתח הזה באמצעות סורק !גאולוגי-קודם +inventory: + no-access: "&4אין לך גישה לבלוק הזה" android: + started: "&7 האנדרואיד שלך ממשיך את תסריט" + stopped: "&7 האנדרואיד שלך \nעצר את התסריט " scripts: - too-long: "&c!התסריט ארוך מכדי לערוך" already-uploaded: "&4 התסריט הזה כבר הועלה." instructions: START: "&2 התחל תסריט" @@ -350,10 +308,56 @@ android: own: "&4אתה לא יכול לדרג את התסריט שלך עצמך!" already: "&4אתה כבר השארת דירוג לתסריט זה!" editor: עורך תסריט - started: "&7 האנדרואיד שלך ממשיך את תסריט" - stopped: "&7 האנדרואיד שלך \nעצר את התסריט " -backpack: - already-open: "&cסליחה התרמיל הזה פתוח במקום אחר " - no-stack: "&cאתה לא יכול לערום תרמילים" -inventory: - no-access: "&4אין לך גישה לבלוק הזה" + too-long: "&c!התסריט ארוך מכדי לערוך" +languages: + default: שרת ברירת מחדל + en: אנגלית + de: 'גרמנית ' + fr: צרפתית + it: איטלקית + es: ספרדית + pl: פולנית + sv: שוודית + nl: הולנדית + cs: צ'כית + hu: הונגרית + lv: לטבית + ru: רוסית + sk: סלובקית + zh-TW: "(מנדרינית (טייוואן" + vi: וייטנאמי + id: אינדונזית + zh-CN: "(מנדרינית(סין" + el: יווני + he: עברית + ar: ערבית + af: אפריקנית + da: דנית + fi: פינית + uk: אוקראינית + ms: מלאית + 'no': נורווגית + ja: יפנית + fa: פרסית + th: תאילנדי + ro: רומנית + pt: "(פורטוגזית (פורטוגל" + pt-BR: "(פורטוגזית (ברזיל" + bg: בולגרית + ko: קוריאנית + tr: טורקי + hr: קרואטית + mk: מקדונית + sr: סרבית + be: בלארוסית + tl: טגלית +brewing_stand: + not-working: "&4אתה לא יכול לשים חפצי סליים פאן במבשלה!" +villagers: + no-trading: "&4אתה לא יכול להחליף עם ויליג'רים חפצי סליים פאן!" +cartography_table: + not-working: "&4אתה לא יכול להשתמש בחפצי סליים פאן בשולחן קרטוגרפיה!" +cauldron: + no-discoloring: "&4אתה לא יכול לשנות את הצבע של שריון סליים פאן" +placeholderapi: + profile-loading: בטעינה... diff --git a/src/main/resources/languages/messages_ja.yml b/src/main/resources/languages/messages_ja.yml index c97fa1104..f01c7711e 100644 --- a/src/main/resources/languages/messages_ja.yml +++ b/src/main/resources/languages/messages_ja.yml @@ -319,7 +319,7 @@ languages: zh-CN: 中国語(中国) el: ギリシャ語 he: ヘブライ語 - pt-BR: ポルトガル語(ブラジル) + pt: ポルトガル語(ポルトガル) ar: アラビア語 af: アフリカーンス語 da: デンマーク語 @@ -331,7 +331,7 @@ languages: fa: ペルシア語 th: タイ語 ro: ルーマニア語 - pt: ポルトガル語(ポルトガル) + pt-BR: ポルトガル語(ブラジル) bg: ブルガリア語 ko: 韓国語 tr: トルコ語 @@ -350,3 +350,5 @@ cauldron: no-discoloring: "&4Slimefunアイテムの脱色はできません" miner: no-ores: "&e周辺には鉱石が見つかりませんでした!" +placeholderapi: + profile-loading: ロード中… diff --git a/src/main/resources/languages/messages_nl.yml b/src/main/resources/languages/messages_nl.yml index 199735711..5297d9a27 100644 --- a/src/main/resources/languages/messages_nl.yml +++ b/src/main/resources/languages/messages_nl.yml @@ -4,7 +4,6 @@ commands: cheat: Geeft je toestemming om gratis spullen in het spel te brengen give: Geef iemand een aantal Slimefun spullen guide: Geef jezelf een Slimefun Handboek - timings: Laat informatie over de server's prestaties zien teleporter: Bekijk de opgeslagen locaties van andere spelers versions: Laat een lijst met alle geïnstalleerde uitbreidingen zien search: Doorzoek de Slimefun handleiding voor een bepaald trefwoord @@ -15,6 +14,18 @@ commands: description: Ontgrendel of herstart Slimefun kennissen van een speler reset: "&cJe hebt %player%'s Slimefun kennis herstart" reset-target: "&cJe Slimefun kennis is herstart" + backpack: + description: Krijg een kopie van een al bestaande rugzak + invalid-id: "&4Het id moet een positieve nummer zijn!" + player-never-joined: "&4Er is geen speler met die naam gevonden!" + backpack-does-not-exist: "& 4De opgegeven rugzak bestaat niet!" + restored-backpack-given: "&aJouw rugzak is hersteld en is toegevoegd aan jouw + inventaris." + charge: + description: Laad het item wat je vasthoud op + charge-success: Item is opgeladen! + not-rechargeable: Dit item kan niet opgeladen worden! + timings: Laat informatie over de server's prestaties zien guide: search: message: "&bOp welk woord zou je willen zoeken?" @@ -22,8 +33,8 @@ guide: tooltip: "&bKlik om naar een item te zoeken" inventory: 'Zoeken naar: %item%' lore: - - "&bOp welk woord zou je willen zoeken?" - - "&7Type je zoekterm in het gespreksvenster" + '1': "&7Type je zoekterm in het gespreksvenster" + '0': "&bOp welk woord zou je willen zoeken?" cheat: no-multiblocks: "&4Je kan geen Slimefun machines in het spel brengen, je moet ze bouwen zoals aangegeven." @@ -34,7 +45,13 @@ guide: lore: Klik om een eigen vertaling toe the voegen select: Klik om deze taal te selecteren select-default: Klik om de standaard taal te selecteren - selected-language: 'Momenteel geselecteerd:' + selected-language: " Op dit moment geselecteerd:" + change: Klik om een nieuwe taal te kiezen + description: + '0': "&7Je hebt nu de mogelijkheid om de taal" + '1': "&7van Slimefun te veranderen" + '2': "&7aan jou wordt vertoond. Items" + '3': "&7kunnen momenteel niet vertaald worden." title: main: Slimefun Handboek settings: Instellingen & Informatie @@ -44,6 +61,7 @@ guide: addons: Uitbreidingen voor Slimefun4 bugs: Fouten rapporteren source: Source Code + versions: Geïnstalleerde versies credits: commit: Bijdrage commits: Bijdragen @@ -53,6 +71,12 @@ guide: resourcepack: "&cGrafische bundel Ontwikkelaar" translator: "&9Vertaler" profile-link: Klik om hun profielen op Github te bezoeken + open: Klik om onze bijdragers te zien + description: + '0': "&7Slimefun is een open-source project" + '1': "&7en wordt in stand gehouden door een grote gemeenschap van mensen." + '2': "&7Meer dan &e%contributors% &7mensen hebben hieraan" + '3': "&7al deze jaren gewerkt." pages: previous: Vorige bladzijde next: Volgende bladzijde @@ -65,15 +89,17 @@ guide: miner: Grondstoffen die je met deze Miner kunt verkrijgen generator: Beschikbare soorten brandstof gold-pan: Grondstoffen die je kunt verkrijgen + climbing-pick: Oppervlakken die je kunt beklimmen back: title: Terug guide: Ga terug naar de Slimefun Handleiding settings: Ga terug naar Instellingen locked: VERGRENDELD locked-category: - - Om deze categorie te ontgrendelen zul je - - alle items moeten ontgrendelen van de - - volgende categorieën + '0': Om deze categorie te ontgrendelen zul je + '1': alle items moeten ontgrendelen van de + '2': volgende categorieën + work-in-progress: Dit is nog niet helemaal klaar! messages: not-researched: "&4Je hebt niet genoeg Slimefun kennis om dit te begrijpen" not-enough-xp: "&4Je hebt niet genoeg XP om dit te ontgrendelen" @@ -83,12 +109,8 @@ messages: no-permission: "&4Je hebt geen toestemming om deze actie uit te voeren" usage: "&4Gebruik, zoals: &c%usage%" not-online: "&4%player% &cis niet online!" - invalid-item: "&4%item% &cis geen geldig voorwerp!" - invalid-amount: "&4%amount% &cis geen geldige hoeveelheid: het moet meer zijn - dan 0!" given-item: '&bJe hebt &a%amount% keer &7"%item%&7" ontvangen' give-item: '&bJe hebt %player% &a%amount% keer &7"%item%&7" gegeven' - invalid-research: "&4%research% &cis geen geldig Slimefun onderzoek" give-research: '&bJe hebt %player% de kennis over &7"%research%&7" gegeven' hungry: "&cJe hebt teveel honger om zoiets te doen!" disabled-in-world: "&4&lDit voorwerp is uitgeschakeld in deze wereld" @@ -110,6 +132,8 @@ messages: whirlwind: "&a&oJe Talisman heeft het projectiel weerkaatst" wizard: "&a&oJe Talisman heeft je een hoger level van geluk gegeven, maar heeft misschien ook de levels van andere betoveringen verlaagd" + caveman: "&a&oJe talisman gaf je haast" + wise: "&a&oJe Talisman heeft je verkregen experience punten verdubbeld" soulbound-rune: fail: "&cJe kan maar één voorwerp met je ziel verbinden op elk moment" success: "&aJe hebt dit voorwerp succesvol met je ziel verbonden! Het blijft bij @@ -129,19 +153,46 @@ messages: link-prompt: "&eKlik mij:" diet-cookie: "&eJe begint je zo ligt als een veertje te voelen..." fortune-cookie: - - "&7Hellup mij, ik zit vast in een gelukskoekjes-fabriek!" - - "&7Je overlijdt morgen... door een creeper..." - - "&7Ooit gaat er iets ergs gebeuren in je leven!!! Muhahaha" - - "&7Volgende week zal je eindelijk doorhebben dat dit niet de echte wereld is, - maar een simulatie" - - "&7Dit koekje gaat over een paar seconden heerlijk smaken" - - '&7De laatste woorden die je ooit zal horen zijn "Voor mij is deze wereld alleen - maar vals!"' - - "&7What je ook wilt worden, knuffels nooit een creeper... Ik heb het geprobeerd, - maar het is het echt niet waard" - - "&742. Het antwoord op alles is 42" - - "&7A Walshy, één dag houdt alle problemen weg" - - "&7Graaf nooit recht naar beneden!" + '0': "&7Hellup mij, ik zit vast in een gelukskoekjes-fabriek!" + '1': "&7Je overlijdt morgen... door een creeper..." + '2': "&7Ooit gaat er iets ergs gebeuren in je leven!!! Muhahaha" + '3': "&7Volgende week zal je eindelijk doorhebben dat dit niet de echte wereld + is, maar een simulatie" + '4': "&7Dit koekje gaat over een paar seconden heerlijk smaken" + '5': '&7De laatste woorden die je ooit zal horen zijn "Voor mij is deze wereld + alleen maar vals!"' + '6': "&7What je ook wilt worden, knuffels nooit een creeper... Ik heb het geprobeerd, + maar het is het echt niet waard" + '7': "&742. Het antwoord op alles is 42" + '8': "&7A Walshy, één dag houdt alle problemen weg" + '9': "&7Graaf nooit recht naar beneden!" + '10': "&7Het is slechts een vleeswonde!" + '11': "&7Kijk altijd naar de blije kant van je leven!" + '12': "&7Deze was eigenlijk een biscuitje en geen koekje" + '13': "&7Neon borden zijn LIT!" + piglin-barter: "&4Je kunt geen Slimefun spullen met piglins ruilen" + enchantment-rune: + fail: "&cJe kunt dit item niet betoveren." + no-enchantment: "&cKon geen mogelijke betoveringen vinden voor dit item." + success: "&aJe hebt succesvol een random betovering toegevoegd op dit item." + tape-measure: + no-anchor: "&cJe hebt nog een anker nodig voordat je kunt meten!" + wrong-world: "&cJe anker lijkt in een andere wereld te zitten!" + distance: "&7Afstand gemeten. &eAfstand: %distance%" + anchor-set: "&aHet is gelukt om het anker in te stellen:&e %anchor%" + multi-tool: + mode-change: "&b%device% mode veranderd naar: &9%mode%" + not-shears: "&cEen Mutli Tool kan niet gebruikt worden als een schaar!" + climbing-pick: + dual-wielding: "&4Je moet een klim-pickaxe in bijde handen hebben om hem te gebruiken!" + wrong-material: "&cJe kunt dit oppervlak niet beklimmen. Check je Slimefun Guide + voor meer info!" + invalid-item: "&4%item% &cis geen geldig voorwerp!" + invalid-amount: "&4%amount% &cis geen geldige hoeveelheid: het moet meer zijn dan + 0!" + invalid-research: "&4%research% &cis geen geldig Slimefun onderzoek" + bee-suit-slow-fall: "&eJe Bee Wings zullen je helpen om weer veilig op de grond + te komen" mode-change: "&b%device% mode is veranderd naar: &9%mode%" machines: pattern-not-found: "&eSorry, ik heb het recept niet herkend. Plaats astublieft de @@ -187,8 +238,20 @@ machines: title: GPS - Configuratiescherm transmitters: Transmitter-overzicht waypoints: Waypoint-overzicht + INDUSTRIAL_MINER: + no-fuel: "& cUw Industrial Miner heeft geen brandstof meer! Doe de brandstof in + de kist erboven." + piston-facing: "&cJe Industrial Miner moet de duwmachines naar boven hebben!" + piston-space: "&cDe twee duwmachines moeten een leeg blok boven hem hebben!" + destroyed: "&cJouw Industrial Miner lijkt vernietigt te zijn!" + already-running: "&cDeze Industrial Miner draait al!" + full-chest: "&cDe kist van je Industrial Miner is vol!" + no-permission: "&4Het lijkt er op dat je geen permissie hebt om een Industrial + Miner hier te laten werken!" + finished: "&eJe Industrial Miner is klaar! Het heeft in totaal %ores% grondstof(fen)! " anvil: not-working: "&4Je kan geen Slimefun voorwerpen gebruiken in een aambeeld!" + mcmmo-salvaging: "&4Je kunt geen Slimefun items afbreken!" backpack: already-open: "&cSorry, deze rugzak is al ergens anders geopend!" no-stack: "&cJe kan geen rugzakken stapelen" @@ -201,10 +264,11 @@ gps: &r(Kleurcodes zijn ondersteund)" added: "&aEen nieuw locatiepunt is succesvol toegevoegd" max: "&4Je hebt het maximum aantal locatiepunten bereikt" + duplicate: "&4Je hebt al een waypoint genaamd: &f%waypoint%" insufficient-complexity: - - "&4Er is te weinig GPS netwerk complexiteit: &c%complexity%" - - "&4a) Je hebt nog geen GPS netwerk opgezet" - - "&4b) Je GPS netwerk is niet complex genoeg" + '0': "&4Er is te weinig GPS netwerk complexiteit: &c%complexity%" + '1': "&4a) Je hebt nog geen GPS netwerk opgezet" + '2': "&4b) Je GPS netwerk is niet complex genoeg" geo: scan-required: "&4Een GEO-Scan is nodig! &cScan deze chunk eerst met behulp van een GEO-Scanner!" @@ -243,15 +307,15 @@ android: INTERFACE_ITEMS: "&9Geef inventaris aan de geconfronteerde interface" INTERFACE_FUEL: "&cOntvang brandstof van de geconfronteerde interface" enter-name: - - - - "&eType astublieft de gewenste naam in voor het script" + '1': "&eType astublieft de gewenste naam in voor het script" uploaded: - - "&bBezig met uploaden..." - - "&aHet script is succesvol geupload!" + '0': "&bBezig met uploaden..." + '1': "&aHet script is succesvol geupload!" rating: own: "&4Je kan je eigen script geen waardering geven!" already: "&4Je hebt aan een waardering achtergelaten voor dit script!" editor: Scripteditor + too-long: "&cDe code is te lang om te kunnen editen!" languages: default: Server-Standaard en: Engels @@ -284,10 +348,25 @@ languages: fa: Perzisch th: Thais ro: Roemeens - pt: Portugees (Portugal) + pt: Portugees (Portugal) pt-BR: Portugees (Brazilië) bg: Bulgaars ko: Koreaans tr: Turks + hr: Kroatisch + mk: Macedonisch + sr: Servisch + be: Wit-Russisch/Russisch + tl: Tagalog +brewing_stand: + not-working: "&4Je kunt geen Slimefun spullen in een brouwstandaard doen!" +villagers: + no-trading: "&4Je kunt geen Slimefun spullen met villagers ruilen!" +cartography_table: + not-working: "&4Je kunt Slimefun items niet in een cartografie tafel gebruiken!" +cauldron: + no-discoloring: "&4Je kunt de kleur van Slimefun Bescherming niet er af halen" +placeholderapi: + profile-loading: Aan het laden... miner: no-ores: "&eSorry, ik kon geen ertsen vinden dichtbij!" diff --git a/src/main/resources/languages/messages_vi.yml b/src/main/resources/languages/messages_vi.yml index a889cff2d..f78002beb 100644 --- a/src/main/resources/languages/messages_vi.yml +++ b/src/main/resources/languages/messages_vi.yml @@ -26,8 +26,8 @@ commands: not-rechargeable: Vật phẩm này không thể sạc được! timings: description: Độ trễ của slimefun và addon của nó - verbose-player: "&4Cờ dài này không thể sử dụng bới Người chơi!" please-wait: "&eVui lòng đợi một chút... Kết quả chuẩn bị đến!" + verbose-player: "&4Cờ dài này không thể sử dụng bới Người chơi!" unknown-flag: "&4Không rõ cờ: &c%flag%" guide: search: @@ -138,6 +138,7 @@ messages: wizard: "&a&oBùa hộ mệnh của bạn đã cho bạn một Cấp độ may mắn tốt hơn nhưng cũng có thể hạ thấp một số Cấp độ phù phép khác" caveman: "&a&oBùa ma thuật của bạn cho bạn hiệu ứng Đào nhanh" + wise: "&a&oBùa ma thuật đã nhân đôi số kinh nghiệm của bạn" soulbound-rune: fail: "&cBạn chỉ có thể liên kết một vật phẩm với linh hồn của bạn trong cùng một thời điểm." @@ -375,3 +376,5 @@ cauldron: no-discoloring: "&4Bạn không thể đổi màu giáp của Slimefun" miner: no-ores: "&eXin lỗi, tôi không thể tìm bất kì Khoáng sản nào xung quanh!" +placeholderapi: + profile-loading: Đang tải... diff --git a/src/main/resources/languages/messages_zh-CN.yml b/src/main/resources/languages/messages_zh-CN.yml index 3d8453412..08ef7fbee 100644 --- a/src/main/resources/languages/messages_zh-CN.yml +++ b/src/main/resources/languages/messages_zh-CN.yml @@ -319,6 +319,7 @@ languages: zh-CN: 简体中文 (中国) el: 希腊语 he: 希伯来语 + pt: 葡萄牙语 (葡萄牙) ar: 阿拉伯语 af: 南非语 da: 丹麦语 @@ -330,7 +331,6 @@ languages: fa: 波斯语 th: 泰语 ro: 罗马尼亚语 - pt: 葡萄牙语 (葡萄牙) pt-BR: 葡萄牙语 (巴西) bg: 保加利亚语 ko: 韩语 @@ -350,3 +350,5 @@ cauldron: no-discoloring: "&4你不能用炼药锅洗去 Slimefun 物品的颜色" miner: no-ores: "&e抱歉, 周围找不到矿石了!" +placeholderapi: + profile-loading: 加载中... diff --git a/src/main/resources/languages/messages_zh-TW.yml b/src/main/resources/languages/messages_zh-TW.yml index bf5967959..c3cdb0be1 100644 --- a/src/main/resources/languages/messages_zh-TW.yml +++ b/src/main/resources/languages/messages_zh-TW.yml @@ -350,3 +350,5 @@ cauldron: no-discoloring: "&4你不能把 Slimefun 裝備的顏色消除!" miner: no-ores: "&e附近沒礦了!" +placeholderapi: + profile-loading: 載入中…… diff --git a/src/main/resources/languages/recipes_cs.yml b/src/main/resources/languages/recipes_cs.yml new file mode 100644 index 000000000..48fac2597 --- /dev/null +++ b/src/main/resources/languages/recipes_cs.yml @@ -0,0 +1,168 @@ +--- +slimefun: + multiblock: + name: Multiblock + lore: + '0': Postav ukázanou konstrukci, + '1': jak je ukázáno. Nevyrábí se. + enhanced_crafting_table: + name: Enhanced Crafting Table + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za pomocí Enhanced Crafting Table + '2': Normální pracovní stůl nebude stačit! + armor_forge: + name: Armor Forge + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Armor Forge + grind_stone: + name: Brusný kámen + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití brusného kamene + smeltery: + name: Smeltery + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Smeltery + ore_crusher: + name: Ore Crusher + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Ore Crusher + mob_drop: + lore: + '0': Zabij tohle stvoření + '1': k získání tohoto předmětu + name: Mob Drop + gold_pan: + name: Gold Pan + lore: + '0': Použij Gold Pan k + '1': získání tohoto předmětu + compressor: + name: Compressor + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Compressor + pressure_chamber: + name: Pressure Chamber + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Pressure Chamber + ore_washer: + name: Ore Washer + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Ore Washer + juicer: + name: Juicer + lore: + '0': Vyrob tento džus, jak je je ukázáno, + '1': za použití Juicer + magic_workbench: + name: Magic Workbench + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Magic Workbench + ancient_altar: + name: Ancient Altar + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Ancient Altar. + '2': Podívej se na Ancient Altar pro více informací + heated_pressure_chamber: + name: Heated Pressure Chamber + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Heated Pressure Chamber + food_fabricator: + name: Food Fabricator + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Food Fabricator + food_composter: + name: Food Composter + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Food Composter + freezer: + name: Freezer + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Freezer + geo_miner: + name: GEO Miner + lore: + '0': Tento předmět lze shromažďovat + '1': pomocí GEO Miner + nuclear_reactor: + name: Nuclear Reactor + lore: + '1': při provozování v Nuclear Reactor + '0': Tento předmět je vedlejší produkt + oil_pump: + name: Oil Pump + lore: + '0': Tento předmět lze shromažďovat + '1': pomocí Oil Pump + pickaxe_of_containment: + name: Pickaxe of Containment + lore: + '1': těžbou líhně pomocí + '2': Pickaxe of Containment + '0': Tento blok lze získat + refinery: + name: Refinery + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití Rafinery + barter_drop: + name: Piglin Bartering Drop + lore: + '0': Vyměňuj s pigliny zlaté + '1': ingoty k získání tohoto předmětu +minecraft: + shaped: + name: Recept na výrobu ve tvaru + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': v normálním pracovním stole + '2': Tvar je důležitý. + shapeless: + name: U receptu nezáleží na tvaru + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': v normálním pracovním stole + '2': Tento recept je beztvarý. + furnace: + lore: + '0': Roztav tento předmět v peci + '1': k vyrobení vysněného předmětu + name: Recept na pec + blasting: + name: Recept na tavicí pec + lore: + '0': Roztav tento předmět v tavící peci + '1': k vyrobení vysněného předmětu + smoking: + name: Recept na troubu + lore: + '0': Upeč tenhle předmět v troubě + '1': k vyrobení vysněného předmětu + campfire: + lore: + '0': Upeč tenhle předmět v táboráku + '1': k vyrobení vysněného předmětu + name: Recept na táborák + stonecutting: + name: Recept na řezačku kamene + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití řezačky kamene + smithing: + name: 'Recept na kovářský stůl ' + lore: + '0': Vyrob tento předmět, jak je ukázáno, + '1': za použití kovářského stolu diff --git a/src/main/resources/languages/researches_cs.yml b/src/main/resources/languages/researches_cs.yml index 98beb4b7a..3ab80b996 100644 --- a/src/main/resources/languages/researches_cs.yml +++ b/src/main/resources/languages/researches_cs.yml @@ -1,232 +1,252 @@ --- slimefun: walking_sticks: Vycházkové hole + portable_crafter: Přenosný pracovní stůl + fortune_cookie: Sušenka štěstí + portable_dustbin: Přenosný koš meat_jerky: Sušené maso - armor_forge: Crafťák brnění + armor_forge: Kovadlina na brnění + glowstone_armor: Světlitové brnění + lumps: Kousky a magie + ender_backpack: Enderitový batoh + ender_armor: Enderitové Brnění + magic_eye_of_ender: Magické endové oko + magic_sugar: Magický cukr monster_jerky: Sušené maso z monstra - steel: Ocelová doba - jetpacks: Jetpacks - multitools: Víceúčelové nástroje - synthetic_sapphire: Syntetické Safíry - damascus_steel_armor: Brnění z Damašské Oceli - portable_crafter: Přenosný Crafťák - fortune_cookie: Sušenka Štěstí - portable_dustbin: Přenosný Koš - glowstone_armor: Světlitové Brnění - lumps: Kousky a Magie - ender_backpack: Ender Batoh - ender_armor: Ender Brnění - magic_eye_of_ender: Magické Oko Endu - magic_sugar: Magický Cukr - slime_armor: Slizové Brnění - sword_of_beheading: Meč na Sekání Hlav - basic_circuit_board: Základní Deska - advanced_circuit_board: Pokročilá Deska + slime_armor: Brnění ze slizu + sword_of_beheading: Meč na sekání hlav + basic_circuit_board: Základní deska + advanced_circuit_board: Pokročilá deska s obvody smeltery: Tavírna - misc_power_items: Důležité itemy související s elekronikou + steel: Doba ocelová + misc_power_items: Důležité předměty související s elekronikou battery: Tvoje první baterie - steel_plate: Ocelové Plátování - steel_thruster: Ocelová Tryska + steel_plate: Ocelový plát + steel_thruster: Ocelová tryska parachute: Padák - grappling_hook: Záchytný Hák - solar_panel_and_helmet: Solární Energie - elemental_staff: Hůlky Elementů - grind_stone: Kámen na Broušení - cactus_armor: Kaktusový Oblek - gold_pan: Zlatá Pánev - magical_book_cover: Magická Knižní Vazba - slimefun_metals: Nové Kovy - ore_crusher: Dvojnásobení Rud - bronze: Vytvoření Bronzu - alloys: Pokročíle Slitiny - compressor_and_carbon: Vytvoření Karbonu - gilded_iron_armor: Pozlacené Železné Brnění - synthetic_diamond: Syntetické Diamanty - pressure_chamber: Tlaková Komora - damascus_steel: Damašská Ocel - reinforced_alloy: Zesílená Slitina - carbonado: Černé Diamanty - magic_workbench: Magický Pracovní Stůl - wind_staff: Větrná Hůl - reinforced_armor: Zesílené Brnění - ore_washer: Čištič Rud - gold_carats: Čisté Zlato - silicon: Silicon Valley - fire_staff: Ohnivá Hůl - smelters_pickaxe: Hutní Krumpáč - common_talisman: Běžný Talisman - anvil_talisman: Talisman Kovadliny - miner_talisman: Talisman Horníka - hunter_talisman: Talisman Lovce - lava_talisman: Talisman Chodce po Lávě - water_talisman: Talisman Dýchače Vody - angel_talisman: Talisman Anděla - fire_talisman: Talisman Požárníka - lava_crystal: Ohnivá Situace - magician_talisman: Talisman Kouzelníka - traveller_talisman: Talisman Cestovatele - warrior_talisman: Talisman Bojovníka - knight_talisman: Talisman Rytíře - gilded_iron: Lesklé Železo - synthetic_emerald: Falešný Drahokam - chainmail_armor: Řetězová Zbroj - whirlwind_talisman: Talisman Vichřice - wizard_talisman: Talisman Čaroděje - lumber_axe: Dřevorubecká Sekera - hazmat_suit: Hazmat Oblek + grappling_hook: Vystřelující hák + jetpacks: Raketový batoh + multitools: Víceúčelové nástroje + solar_panel_and_helmet: Solární energie + elemental_staff: Elementární hůlky + grind_stone: Brusný kámen + cactus_armor: Oblek z kaktusu + gold_pan: Rýžovací miska + magical_book_cover: Magické vázání knihy + slimefun_metals: Nové kovy + ore_crusher: Zdvojování rud + bronze: Výroby bronzu + alloys: Pokročilé slitiny + compressor_and_carbon: Výroby karbonu + gilded_iron_armor: Pozlacené železné brnění + synthetic_diamond: Syntetické diamanty + pressure_chamber: Tlaková komora + synthetic_sapphire: Syntetické safíry + damascus_steel: Damašková ocel + damascus_steel_armor: Brnění z damaškové ocely + reinforced_alloy: Zpevněná slitina + carbonado: Černé diamanty + magic_workbench: Magický pracovní stůl + wind_staff: Větrná hůl + reinforced_armor: Zpěvněné brnění + ore_washer: Čištič rud + gold_carats: Čisté zlato + silicon: Křemíkové údolí + fire_staff: Ohnivá hůl + smelters_pickaxe: Hutní krumpáč + common_talisman: Běžný talisman + anvil_talisman: Talisman kovadliny + miner_talisman: Talisman horníka + hunter_talisman: Talisman lovce + lava_talisman: Talisman chodce po lávě + water_talisman: Talisman dýchání pod vodou + angel_talisman: Talisman anděla + fire_talisman: Talisman hasiče + lava_crystal: Ohnivá situace + magician_talisman: Talisman kouzelníka + traveller_talisman: Talisman cestovatele + warrior_talisman: Talisman bojovníka + knight_talisman: Talisman rytíře + gilded_iron: Lesklé železo + synthetic_emerald: Falešný drahokam + chainmail_armor: Kroužková zbroj + whirlwind_talisman: Talisman vichřice + wizard_talisman: Talisman čaroděje + lumber_axe: Dřevorubecká sekera + hazmat_suit: Hazmat oblek uranium: Radioaktivní - crushed_ore: Čištění rud - redstone_alloy: Ruditové Slitiny - carbonado_tools: Nejlepší Stroje - first_aid: První Pomoc - gold_armor: Lesklé Brnění - night_vision_googles: Brýle Nočního Vidění - pickaxe_of_containment: Krumpáč Zadržení - hercules_pickaxe: Herkulesův Krumpáč - table_saw: Stolní Pila - slime_steel_armor: Slizově-Ocelové Brnění - blade_of_vampires: Čepel Vampírů - water_staff: Vodní Hůl - 24k_gold_block: Zlaté Město - composter: Kompostování Hlíny - farmer_shoes: Boty Farmáře - explosive_tools: Výbušné Nastroje - automated_panning_machine: Automatická Zlatá Pánev - boots_of_the_stomper: Boty Dupače - pickaxe_of_the_seeker: Krumpáč Hledače + crushed_ore: Očišťování rud + redstone_alloy: Ruditové slitiny + carbonado_tools: Nejlepší stroje + first_aid: První pomoc + gold_armor: Lesklé brnění + night_vision_googles: Brýle pro noční vidění + pickaxe_of_containment: Krumpáč zadržení + hercules_pickaxe: Herkulesův krumpáč + table_saw: Stolní pila + slime_steel_armor: Brnění ze slizu a oceli + blade_of_vampires: Čepel vampírů + water_staff: Vodní hůl + 24k_gold_block: Zlaté město + composter: Kompostování hlíny + farmer_shoes: Boty farmáře + explosive_tools: Výbušné nástroje + automated_panning_machine: Automatická rýžovací miska + boots_of_the_stomper: Boty dupače + pickaxe_of_the_seeker: Krumpáč hledače backpacks: Batohy - woven_backpack: Tkaný Batoh + woven_backpack: Tkaný batoh crucible: Kotel - gilded_backpack: Vázaný Batoh - armored_jetpack: Trysky s Brněním - ender_talismans: Ender Talismany + gilded_backpack: Vázaný batoh + armored_jetpack: Obrněný raketový batoh + ender_talismans: Enderitové talismany nickel_and_cobalt: Ještě více rud magnet: Magnetické kovy - infused_magnet: Infuzovaný Magnet - cobalt_pickaxe: Urychlený Krumpáč - essence_of_afterlife: Necromancie - bound_backpack: Duší-vázané Ůložistě - jetboots: Tryskové Boty - armored_jetboots: Obrněné Tryskové Boty - seismic_axe: Seizmická Sekera - pickaxe_of_vein_mining: Krumpáč Těžení Nalezišť - bound_weapons: Duší-vázané Zbraně - bound_tools: Duší-vázané Nástroje - bound_armor: Duší-vázané Brnění - juicer: Výborné Pití - repaired_spawner: Opravování Spawnerů - enhanced_furnace: Vylepšená Pec - more_enhanced_furnaces: Lepší Pece - high_tier_enhanced_furnaces: Nejlepší Pece - reinforced_furnace: Vyztužená Pec - carbonado_furnace: Carbonado Lemováná Pec + infused_magnet: Naplněný magnet + cobalt_pickaxe: Zrychlený krumpáč + essence_of_afterlife: Černá magie + bound_backpack: Uložiště spoutané duší + jetboots: Raketové boty + armored_jetboots: Obrněné raketové boty + seismic_axe: Seizmická sekera + pickaxe_of_vein_mining: Krumpáč těžby rud + bound_weapons: Zbraně spoutané duší + bound_tools: Nástroje spoutané duší + bound_armor: Brnění spoutané duší + juicer: Výborné pití + repaired_spawner: Opravování líhní + enhanced_furnace: Vylepšená pec + more_enhanced_furnaces: Lepší pece + high_tier_enhanced_furnaces: Nejlepší pece + reinforced_furnace: Zesílená pec + carbonado_furnace: Pec lemovaná černými diamanty electric_motor: Zahřívání - block_placer: Pokládač Bloků - scroll_of_dimensional_teleposition: Otáčení věcí kolem + block_placer: Pokládač bloků + scroll_of_dimensional_teleposition: Otáčí věcí kolem special_bows: Robin Hood - tome_of_knowledge_sharing: Dělení z přátely - flask_of_knowledge: XP Úložistě - hardened_glass: Odoláválí Výbuchům - golden_apple_juice: Zlatý Lektrvar - cooler: Přenášení Nápojů - ancient_altar: Starověký Oltář - wither_proof_obsidian: Obsidian co vydrží Withera - ancient_runes: Elementální Rudy - special_runes: Purple Rudy - infernal_bonemeal: Pekelný Bonemeal - rainbow_blocks: duhové Bloky - infused_hopper: Vylepšený Hopper - wither_proof_glass: Sklo co vydrží Withera - duct_tape: Lepící Páska + tome_of_knowledge_sharing: Dělení s přáteli + flask_of_knowledge: XP uložistě + hardened_glass: Odolávání výbuchům + golden_apple_juice: Zlatý lektvar + cooler: Přenašeč nápojů + ancient_altar: Starověký oltář + wither_proof_obsidian: Pevný obsidián proti witherovi + ancient_runes: Elementální rudy + special_runes: Fialové rudy + infernal_bonemeal: Pekelná kostní moučka + rainbow_blocks: Duhové bloky + infused_hopper: Vylepšená násypka + wither_proof_glass: Pevné sklo proti witherovi + duct_tape: Lepící páska plastic_sheet: Plast - android_memory_core: Memory Core + android_memory_core: Paměťové jádro oil: Olej fuel: Palivo hologram_projector: Hologramy - capacitors: Tier 1 Kondenzátory - high_tier_capacitors: Tier 2 Kondenzátory - solar_generators: Solární Elektrárna - electric_furnaces: Elektrická Pec - electric_ore_grinding: Drcení a Broušení - heated_pressure_chamber: Vyhřívaná Tlaková Komora - coal_generator: Uhelná Elektrárna - bio_reactor: Bio-Reactor - auto_enchanting: Automatická Enchantování and Oddělávání Enchantů - auto_anvil: Automatická Kovadlina - multimeter: Měření Energie - gps_setup: Základní GPS Nastavení - gps_emergency_transmitter: GPS Nouzový Cestovní Bod - programmable_androids: Programovatelní Androidi - android_interfaces: Androidové Rozhraní - geo_scanner: GEO-Skeny - combustion_reactor: Spalovací Reactor - teleporter: Teleportovač - Základní Komponenty - teleporter_activation_plates: Teleportovač - Aktivace - better_solar_generators: Vylepšené Solární Panely - better_gps_transmitters: Vylepšené Vysílače + capacitors: Kondenzátory 1. stupně + high_tier_capacitors: Kondenzátory 2. stupně + solar_generators: Solární elektrárna + electric_furnaces: Elektrická pec + electric_ore_grinding: Drcení a broušení + heated_pressure_chamber: Vytápěná tlaková komora + coal_generator: Uhelná elektrárna + bio_reactor: Bio reaktor + auto_enchanting: Automatické očarovávání a odčarovávání + auto_anvil: Automatická kovadlina + multimeter: Měření energie + gps_setup: Základní GPS nastavení + gps_emergency_transmitter: GPS nouzový záchytný bod + programmable_androids: Programovatelné androidy + android_interfaces: Rozhraní androidu + geo_scanner: GEO snímače + combustion_reactor: Spalovací reaktor + teleporter: Základní komponenty pro teleportér + teleporter_activation_plates: Aktivace teleportéru + better_solar_generators: Vylepšené solární panely + better_gps_transmitters: Vylepšené vysílače elevator: Výtahy - energized_solar_generator: 24/7 Solární Energie - energized_gps_transmitter: Nejlepší Trasmitter - energy_regulator: Energické Sítě 101 - butcher_androids: Android - Řezník - organic_food: Organické Jídlo - auto_breeder: Automatické Krmení - advanced_android: Pokročilý Androidi - advanced_butcher_android: Pokročílý Androidi - Řezníci - advanced_fisherman_android: Pokročílý Androidi - Rybář - animal_growth_accelerator: Manipulase Růstu Zvýřat - xp_collector: Zběrač XP - organic_fertilizer: Organické Hnojivo - crop_growth_accelerator: Zrychelní Růstu Plodin - better_crop_growth_accelerator: Vylepšené Zrychelní Růstu Plodin - reactor_essentials: Důležité Části Reaktoru - nuclear_reactor: Nuclearní Elektrárna - freezer: Pan Mražák - cargo_basics: Základy Carga - cargo_nodes: Nastavení Carga - electric_ingot_machines: Electrické Vyrábění Ingotů - high_tier_electric_ingot_machines: Super Rychlá Vyrábění Ingotů - automated_crafting_chamber: Automatické Crafťění - better_food_fabricator: Vylepšené Vyrábění Jídla - reactor_access_port: Interakce s Reactorem - fluid_pump: Pumpa - better_freezer: Vylepšený Mrazák - boosted_uranium: Nikdy Nekončící Kruh - trash_can: Odpatky - advanced_output_node: Vylepšený Výstupní Uzel - carbon_press: Uhlíkový Lis - electric_smeltery: Elektrická Huť - better_electric_furnace: Vylepšená Elektrická Pec - better_carbon_press: Vylepšený Uhlíkový Lis - empowered_android: Super-nabití Androidi - empowered_butcher_android: Super-nabití Androidi - Řezník - empowered_fisherman_android: Super-nabití Androidi - Rybář - high_tier_carbon_press: Ultimátní Uhlíkový Lis - wither_assembler: Automatický Zabíječ Wihera - better_heated_pressure_chamber: Vylepšená Vyhřívaná Tlaková Komora - elytra: Elytry - special_elytras: Speciální Elytry - electric_crucible: Elekryzovaný Kotel - better_electric_crucibles: Horké Kotly - advanced_electric_smeltery: Vylepšená Elekrická Huť - advanced_farmer_android: Vylepšení Androidi - Farmář - lava_generator: Generátor Energie z Lávy - nether_ice: Pekelná-Levodá Chladící Kapalina - nether_star_reactor: Nether Star Reactor - blistering_ingots: Žíravá Radioactivita - automatic_ignition_chamber: Automatická Zápalná Komora - output_chest: Základní výstup do truhly - copper_wire: Snížená Vodivost - radiant_backpack: Zářivý Batoh - auto_drier: Suchý Den - diet_cookie: Dientní Sušenka - storm_staff: Bouřková Hole - soulbound_rune: Duševně-vázaná Runa - geo_miner: GEO-Ťežič - lightning_rune: Runa Blesku - totem_of_undying: Totem Nesmrtelnosti + energized_solar_generator: Nezastavitelná solární energie + energized_gps_transmitter: Nejlepší vysílač + energy_regulator: Energické sítě 101 + butcher_androids: Řeznické androidy + organic_food: Organické jídlo + auto_breeder: Automatické krmení + advanced_android: Pokročilé androidy + advanced_butcher_android: Pokročilé řeznické androidy + advanced_fisherman_android: Pokročilé rybářské androidy + animal_growth_accelerator: Manipulace s růstem zvířat + xp_collector: Sběrač XP + organic_fertilizer: Organické hnojivo + crop_growth_accelerator: Urychlovač růstu plodin + better_crop_growth_accelerator: Vylepšený urychlovač růstu plodin + reactor_essentials: Důležité části reaktoru + nuclear_reactor: Jaderná elektrárna + freezer: Mrazák + cargo_basics: Základy nákladu + cargo_nodes: Nastavení nákladu + electric_ingot_machines: Elektrická výroba ingotů + high_tier_electric_ingot_machines: Super rychlá výroba ingotů + automated_crafting_chamber: Automatická výroba + better_food_fabricator: Vylepšená výroba jídla + reactor_access_port: Interakce s reaktorem + fluid_pump: Pumpa tekutin + better_freezer: Vylepšený mrazák + boosted_uranium: Nekonečný kruh + trash_can: Koš + advanced_output_node: Vylepšený výstupní uzel + carbon_press: Uhlíkový lis + electric_smeltery: Elektrická huť + better_electric_furnace: Vylepšená elektrická pec + better_carbon_press: Vylepšený uhlíkový lis + empowered_android: Super nabité androidy + empowered_butcher_android: Super nabité řeznické androidy + empowered_fisherman_android: Super nabité rybářské androidy + high_tier_carbon_press: Ultimátní uhlíkový lis + wither_assembler: Automatický zabiják withera + better_heated_pressure_chamber: Vylepšená vytápěná tlaková komora + elytra: Krovky + special_elytras: Speciální krovky + electric_crucible: Elektrický kotel + better_electric_crucibles: Horké kotle + advanced_electric_smeltery: Vylepšená elektrická tavírna + advanced_farmer_android: Vylepšené farmářské androidy + lava_generator: Generátor energie z lávy + nether_ice: Netherová chladící kapalina + nether_star_reactor: Netherový hvězdný reaktor + blistering_ingots: Sžíravá radioaktivita + automatic_ignition_chamber: Automatická zápalná komora + output_chest: Výstupní truhla základního zařízení + copper_wire: Snížená vodivost + radiant_backpack: Zářivý batoh + auto_drier: Suchý den + diet_cookie: Dientní sušenka + storm_staff: Bouřková hole + soulbound_rune: Runa spoutaná duší + geo_miner: GEO horník + lightning_rune: Runa blesku + totem_of_undying: Totem nesmrtelnosti charging_bench: Nabíječka - nether_gold_pan: Pekelná Zlatá Pánev - electric_press: Electrický Lis - magnesium_generator: Energie z Magnézia - kelp_cookie: Chutná Řasa + nether_gold_pan: Netherová rýžovací miska + electric_press: Elektrický lis + magnesium_generator: Energie z magnézia + kelp_cookie: Chutná řasa + advanced_industrial_miner: Lepší těžení + magical_zombie_pills: Dezombifikace + enchantment_rune: Antická očarování + climbing_pick: Blokace nájezdníků + caveman_talisman: Talisman jeskynního člověka + even_higher_tier_capacitors: Kondenzátory 3. stupně + elytra_cap: Popraskané brnění + energy_connectors: Drátové připojení + bee_armor: Včelí zbroj + wise_talisman: Talisman moudrosti + book_binder: Vázání knihy očarování + makeshift_smeltery: Vylepšená tavírna + tree_growth_accelerator: Rychlejší stromy + lead_clothing: Olověné oblečení + tape_measure: Svinovací metr + iron_golem_assembler: Automatická farma na železné golemy + shulker_shell: Syntetičtí shulkeři + villager_rune: Obnova vesnických obchodů + industrial_miner: Průmyslové těžení + auto_brewer: Průmyslový pivovar diff --git a/src/main/resources/languages/researches_de.yml b/src/main/resources/languages/researches_de.yml index e934cddbb..c8f40955e 100644 --- a/src/main/resources/languages/researches_de.yml +++ b/src/main/resources/languages/researches_de.yml @@ -249,3 +249,4 @@ slimefun: energy_connectors: Kupferkabel bee_armor: Bienen-Rüstung wise_talisman: Stein der Weisen + book_binder: Verzaubertes Bücherbinden diff --git a/src/main/resources/languages/researches_he.yml b/src/main/resources/languages/researches_he.yml index d355acc5e..0e1872d80 100644 --- a/src/main/resources/languages/researches_he.yml +++ b/src/main/resources/languages/researches_he.yml @@ -3,29 +3,18 @@ slimefun: walking_sticks: מקלות הליכה portable_crafter: שולחן מלאכה נייד fortune_cookie: עוגיית מזל - ender_armor: שריון אנדר - magic_eye_of_ender: עין אנדר קסומה - magic_sugar: סוכר קסום - slime_armor: שריון רפש - sword_of_beheading: חרב העריפות - parachute: מצנח - bronze: יצירת ברונזה - reinforced_alloy: סגסוגת מחוזקת - magic_workbench: שולחן מלאכה קסום - wind_staff: מטה רוח - gold_carats: זהב טהור - fire_staff: מטה אש - first_aid: עזרה ראשונה - water_staff: מטה מים - farmer_shoes: נעלי איכר - backpacks: תיקי גב portable_dustbin: פח אשפה נייד meat_jerky: בשר מלוח armor_forge: יצירת שריון glowstone_armor: שריון גלוסטון lumps: גושים וקסמים ender_backpack: תיק גב אנדר + ender_armor: שריון אנדר + magic_eye_of_ender: עין אנדר קסומה + magic_sugar: סוכר קסום monster_jerky: בשר מפלצת מלוח + slime_armor: שריון רפש + sword_of_beheading: חרב העריפות basic_circuit_board: לוח מגעים בסיסי advanced_circuit_board: לוח מגעים מתקדם smeltery: תנור התכה @@ -34,6 +23,7 @@ slimefun: battery: הסוללה הראשונה שלך steel_plate: ציפוי פלדה steel_thruster: דוחף פלדה + parachute: מצנח grappling_hook: וו אחיזה jetpacks: תרמיל רחיפה multitools: רב כלים @@ -45,6 +35,7 @@ slimefun: magical_book_cover: כריכת ספרים קסומה slimefun_metals: מתכות חדשות ore_crusher: הכפלת עפרת + bronze: יצירת ברונזה alloys: סגסוגות מתקדמות compressor_and_carbon: יצירת פחמן gilded_iron_armor: שריון ברזל מוזהב @@ -53,10 +44,15 @@ slimefun: synthetic_sapphire: ספיר סינטטי damascus_steel: פלדת דמשק damascus_steel_armor: שריון פלדת דמשק + reinforced_alloy: סגסוגת מחוזקת carbonado: יהלומים שחורים + magic_workbench: שולחן מלאכה קסום + wind_staff: מטה רוח reinforced_armor: שריון מחוזק ore_washer: שוטף עופרת + gold_carats: זהב טהור silicon: עמק הסיליקון + fire_staff: מטה אש smelters_pickaxe: מכוש התכה common_talisman: קמע נפוץ anvil_talisman: קמע הסדן @@ -82,6 +78,7 @@ slimefun: crushed_ore: טיהור עפרת redstone_alloy: סגסוגת רדסטון carbonado_tools: מכונות ברמה עליונה + first_aid: עזרה ראשונה gold_armor: שריון מבריק night_vision_googles: משקפי ראיית לילה pickaxe_of_containment: מקוש הכלה @@ -89,12 +86,15 @@ slimefun: table_saw: מסור שולחני slime_steel_armor: שריון פלדה רזה blade_of_vampires: להב הערפדים + water_staff: מטה מים 24k_gold_block: עיר מוזהבת composter: עפר קומפוסטציה + farmer_shoes: נעלי איכר explosive_tools: כלי נפץ automated_panning_machine: מסננת אוטומטית boots_of_the_stomper: מגפי הרוקע pickaxe_of_the_seeker: מכוש המחפש + backpacks: תיקי גב woven_backpack: תיק גב ארוג crucible: כור היתוך gilded_backpack: תיק גב מוזהב @@ -133,6 +133,7 @@ slimefun: wither_proof_obsidian: בזלת עמידה לוויד'ר ancient_runes: רונות אלמנטריות special_runes: רונות סגולות + infernal_bonemeal: אינפרנל בואונמיל rainbow_blocks: בלוקים צבעוניים infused_hopper: משפך חדור wither_proof_glass: זכוכית עמידה לוויד'ר @@ -247,4 +248,5 @@ slimefun: elytra_cap: גלגל שיניים מרסק energy_connectors: חיבור קווי bee_armor: שריון דבורים - infernal_bonemeal: אינפרנל בואונמיל + wise_talisman: קמע של החכמה + book_binder: כריכת ספר קסום diff --git a/src/main/resources/languages/researches_vi.yml b/src/main/resources/languages/researches_vi.yml index e6259c773..c920b3499 100644 --- a/src/main/resources/languages/researches_vi.yml +++ b/src/main/resources/languages/researches_vi.yml @@ -248,3 +248,5 @@ slimefun: elytra_cap: Mũ lượn energy_connectors: Đầu nối bee_armor: Giáp ong + wise_talisman: Bùa ma thuật của sự Tinh Khôn + book_binder: Sách phù phép Ràng Buộc diff --git a/src/main/resources/languages/researches_zh-CN.yml b/src/main/resources/languages/researches_zh-CN.yml index 12899cf16..302ba9d67 100644 --- a/src/main/resources/languages/researches_zh-CN.yml +++ b/src/main/resources/languages/researches_zh-CN.yml @@ -249,3 +249,4 @@ slimefun: energy_connectors: 有线连接 bee_armor: 蜜蜂服 wise_talisman: 智者的护身符 + book_binder: 附魔融合 diff --git a/src/main/resources/tags/fungus_soil.json b/src/main/resources/tags/fungus_soil.json new file mode 100644 index 000000000..b943c9e59 --- /dev/null +++ b/src/main/resources/tags/fungus_soil.json @@ -0,0 +1,17 @@ +{ + "values" : [ + "#slimefun:dirt_variants", + { + "id" : "minecraft:soul_soil", + "required" : false + }, + { + "id" : "minecraft:crimson_nylium", + "required" : false + }, + { + "id" : "minecraft:warped_nylium", + "required" : false + } + ] +} diff --git a/src/main/resources/tags/miner_talisman_triggers.json b/src/main/resources/tags/miner_talisman_triggers.json new file mode 100644 index 000000000..8dfd56669 --- /dev/null +++ b/src/main/resources/tags/miner_talisman_triggers.json @@ -0,0 +1,9 @@ +{ + "values" : [ + "#slimefun:fortune_compatible_ores", + { + "id" : "minecraft:gilded_blackstone", + "required" : false + } + ] +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java index 6a715312f..9f4f88bac 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java @@ -10,7 +10,6 @@ import org.bukkit.entity.Player; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -54,7 +53,6 @@ class TestResearchUnlocking { @ParameterizedTest @DisplayName("Test Unlocking Researches") - @Disabled(value = "Blocked by a concurrency issue in MockBukkit") @ValueSource(booleans = { true, false }) void testUnlock(boolean instant) throws InterruptedException { SlimefunPlugin.getRegistry().setResearchingEnabled(true); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java index bf2b4aa09..4a52485c6 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java @@ -1,12 +1,7 @@ package io.github.thebusybiscuit.slimefun4.testing.tests.utils; -import java.util.Arrays; import java.util.Collections; -import be.seeseemelk.mockbukkit.MockBukkit; -import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.utils.ChargeUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -17,6 +12,11 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import be.seeseemelk.mockbukkit.MockBukkit; +import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.utils.ChargeUtils; + class TestChargeUtils { @BeforeAll diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestInfiniteBlockGenerators.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestInfiniteBlockGenerators.java new file mode 100644 index 000000000..7c1fa3b93 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestInfiniteBlockGenerators.java @@ -0,0 +1,167 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.utils; + +import java.util.Arrays; +import java.util.stream.Stream; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.event.block.BlockFormEvent; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import be.seeseemelk.mockbukkit.WorldMock; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator; + +class TestInfiniteBlockGenerators { + + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + MockBukkit.load(SlimefunPlugin.class); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + @Test + @DisplayName("Test if invalid Cobblestone generators are ignored") + void testInvalidCobblestoneGenerator() { + World world = new WorldMock(); + Block block = world.getBlockAt(0, 100, 0); + + block.setType(Material.STONE); + Assertions.assertFalse(InfiniteBlockGenerator.COBBLESTONE_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + + block.setType(Material.COBBLESTONE); + Assertions.assertFalse(InfiniteBlockGenerator.COBBLESTONE_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + } + + @ParameterizedTest + @MethodSource(value = "provideFaces") + @DisplayName("Test if a Cobblestone Generator can be detected") + void testValidCobblestoneGenerator(BlockFace water, BlockFace lava) { + InfiniteBlockGenerator generator = InfiniteBlockGenerator.COBBLESTONE_GENERATOR; + + World world = new WorldMock(); + Block block = world.getBlockAt(0, 100, 0); + + block.setType(Material.COBBLESTONE); + block.getRelative(water).setType(Material.WATER); + block.getRelative(lava).setType(Material.LAVA); + + Assertions.assertTrue(generator.test(block)); + Assertions.assertNotNull(generator.callEvent(block)); + + server.getPluginManager().assertEventFired(BlockFormEvent.class); + server.getPluginManager().clearEvents(); + + Assertions.assertEquals(generator, InfiniteBlockGenerator.findAt(block)); + } + + @Test + @DisplayName("Test if invalid Basalt generators are ignored") + void testInvalidBasaltGenerator() { + World world = new WorldMock(); + Block block = world.getBlockAt(0, 100, 0); + + block.setType(Material.COBBLESTONE); + Assertions.assertFalse(InfiniteBlockGenerator.BASALT_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + + block.setType(Material.BASALT); + Assertions.assertFalse(InfiniteBlockGenerator.BASALT_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + + block.getRelative(BlockFace.DOWN).setType(Material.SOUL_SOIL); + Assertions.assertFalse(InfiniteBlockGenerator.BASALT_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + } + + @ParameterizedTest + @MethodSource(value = "provideFaces") + @DisplayName("Test if a Basalt Generator can be detected") + void testValidBasaltGenerator(BlockFace ice, BlockFace lava) { + InfiniteBlockGenerator generator = InfiniteBlockGenerator.BASALT_GENERATOR; + + World world = new WorldMock(); + Block block = world.getBlockAt(0, 100, 0); + + block.setType(Material.BASALT); + block.getRelative(BlockFace.DOWN).setType(Material.SOUL_SOIL); + block.getRelative(ice).setType(Material.BLUE_ICE); + block.getRelative(lava).setType(Material.LAVA); + + Assertions.assertTrue(generator.test(block)); + Assertions.assertNotNull(generator.callEvent(block)); + + server.getPluginManager().assertEventFired(BlockFormEvent.class); + server.getPluginManager().clearEvents(); + + Assertions.assertEquals(generator, InfiniteBlockGenerator.findAt(block)); + } + + @Test + @DisplayName("Test if invalid Stone generators are ignored") + void testInvalidStoneGenerator() { + World world = new WorldMock(); + Block block = world.getBlockAt(0, 100, 0); + + block.setType(Material.COBBLESTONE); + Assertions.assertFalse(InfiniteBlockGenerator.STONE_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + + block.setType(Material.STONE); + Assertions.assertFalse(InfiniteBlockGenerator.STONE_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + + block.getRelative(BlockFace.UP).setType(Material.LAVA); + Assertions.assertFalse(InfiniteBlockGenerator.STONE_GENERATOR.test(block)); + Assertions.assertNull(InfiniteBlockGenerator.findAt(block)); + } + + @ParameterizedTest + @EnumSource(value = BlockFace.class, names = { "NORTH", "EAST", "SOUTH", "WEST" }) + @DisplayName("Test if a Stone Generator can be detected") + void testValidStoneGenerator(BlockFace water) { + InfiniteBlockGenerator generator = InfiniteBlockGenerator.STONE_GENERATOR; + + World world = new WorldMock(); + Block block = world.getBlockAt(0, 100, 0); + + block.setType(Material.STONE); + block.getRelative(BlockFace.UP).setType(Material.LAVA); + block.getRelative(water).setType(Material.WATER); + + Assertions.assertTrue(generator.test(block)); + Assertions.assertNotNull(generator.callEvent(block)); + + server.getPluginManager().assertEventFired(BlockFormEvent.class); + server.getPluginManager().clearEvents(); + + Assertions.assertEquals(generator, InfiniteBlockGenerator.findAt(block)); + } + + private static Stream provideFaces() { + BlockFace[] faces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST }; + Stream stream = Arrays.stream(faces); + return stream.flatMap(a -> Arrays.stream(faces).filter(b -> a != b).map(b -> Arguments.of(a, b))); + } +}