diff --git a/.github/configs/yaml-linter.yml b/.github/configs/yaml-linter.yml index 90060a83c..3f056f2a1 100644 --- a/.github/configs/yaml-linter.yml +++ b/.github/configs/yaml-linter.yml @@ -6,10 +6,13 @@ yaml-files: rules: - ## A warning is sufficient here - line-length: - max: 180 - level: warning + ## Don't warn for line lengths + line-length: disable + + truthy: + allowed-values: ['true', 'false'] + ## We don't want it to trigger for the 'on' in our workflows + check-keys: false ## We don't need indentation warnings indentation: disable diff --git a/.github/workflows/maven-compiler.yml b/.github/workflows/maven-compiler.yml index 1e041876b..9b02b166c 100644 --- a/.github/workflows/maven-compiler.yml +++ b/.github/workflows/maven-compiler.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@master with: diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 20e965f91..d9c720087 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -16,7 +16,7 @@ jobs: steps: - name: TOC Generator - uses: technote-space/toc-generator@v2.4.0 + uses: technote-space/toc-generator@v2.6.1 with: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} TARGET_PATHS: 'CHANGELOG.md' diff --git a/.github/workflows/url-checker.yml b/.github/workflows/url-checker.yml index 523248f00..42483c750 100644 --- a/.github/workflows/url-checker.yml +++ b/.github/workflows/url-checker.yml @@ -6,7 +6,7 @@ on: - master jobs: - build: + check: name: URL Checker runs-on: ubuntu-latest @@ -17,7 +17,7 @@ jobs: with: git_path: https://github.com/Slimefun/Slimefun4 file_types: .md,.java,.yml - print_all: False + print_all: false retry_count: 2 ## These URLs will always be correct, even if their services may be offline right now white_listed_patterns: http://textures.minecraft.net/texture/,https://pastebin.com/,https://www.spigotmc.org/threads/spigot-bungeecord-1-16-1.447405/#post-3852349,https://gitlocalize.com/repo/3841 diff --git a/.github/workflows/yaml-linter.yml b/.github/workflows/yaml-linter.yml index 00f94e27c..2c34456f9 100644 --- a/.github/workflows/yaml-linter.yml +++ b/.github/workflows/yaml-linter.yml @@ -16,8 +16,8 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: YAML Linter - uses: ibiqlik/action-yamllint@v1.0.0 + uses: ibiqlik/action-yamllint@v2.0.0 with: config_file: '.github/configs/yaml-linter.yml' diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ea71ada5..35cbdb690 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ **Table of contents** -- [Release Candidate 17 (TBD)](#release-candidate-17-tbd) +- [Release Candidate 18 (TBD)](#release-candidate-18-tbd) +- [Release Candidate 17 (17 Oct 2020)](#release-candidate-17-17-oct-2020) - [Release Candidate 16 (07 Sep 2020)](#release-candidate-16-07-sep-2020) - [Release Candidate 15 (01 Aug 2020)](#release-candidate-15-01-aug-2020) - [Release Candidate 14 (12 Jul 2020)](#release-candidate-14-12-jul-2020) @@ -22,7 +23,33 @@ -## Release Candidate 17 (TBD) +## Release Candidate 18 (TBD) + +#### Additions + +#### Changes +* Removed 1.13 support +* Cooling Units can no longer be placed down +* Heating Coils can no longer be placed down +* Electric Motors can no longer be placed down +* Cargo Motors can no longer be placed down +* Magnets can no longer be placed down +* Electromagnets can no longer be placed down + +#### Fixes +* Fixed #2448 +* Fixed #2470 +* Fixed #2478 +* Fixed #2493 +* Fixed a missing slot in the contributors menu +* Fixed color codes in script downloading screen +* Fixed #2505 +* Fixed contributors not showing correctly +* Fixed #2469 +* Fixed #2509 +* Fixed #2499 + +## Release Candidate 17 (17 Oct 2020) #### Additions * Added /sf charge @@ -40,6 +67,10 @@ * (API) Added custom tags for developers * The range of the Seeker Pickaxe is now configurable * Added Energy Connector +* Blackstone can now be turned into lava using a Crucible +* Basalt can now be turned into lava using a Crucible +* Added "Tainted Sheep" (You can dye a Sheep using Strange Nether Goo) +* Added mcMMO support/integration #### Changes * Improved Auto-Updater (Multi-Threading and more) @@ -81,6 +112,14 @@ * Fixed #2450 * Fixed Steel Thrusters being used to milk cows * Fixed #2424 +* Fixed #2468 +* Fixed #2414 +* Fixed #2454 +* Fixed #2457 +* Fixed #2411 +* Fixed #2423 +* Fixed #2452 +* Fixed a dupe bug with mcMMO ## Release Candidate 16 (07 Sep 2020) https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#16 diff --git a/README.md b/README.md index 80f30248b..f531b510d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Here is a full summary of the differences between the two different versions of | | development (latest) | "stable" | | ------------------ | -------- | -------- | -| **Minecraft version(s)** | :video_game: **1.13.\* - 1.16.\*** | :video_game: **1.13.\* - 1.16.\*** | +| **Minecraft version(s)** | :video_game: **1.14.\* - 1.16.\*** | :video_game: **1.13.\* - 1.16.\*** | | **automatic updates** | :heavy_check_mark: | :heavy_check_mark: | | **frequent updates** | :heavy_check_mark: | :x: | | **latest content** | :heavy_check_mark: | :x: | diff --git a/pom.xml b/pom.xml index 217f7b2a1..0073cdbbc 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,10 @@ 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/ @@ -311,7 +315,7 @@ com.github.seeseemelk MockBukkit-v1.16 - 0.10.2 + 0.13.0 test @@ -325,7 +329,7 @@ org.mockito mockito-core - 3.5.13 + 3.6.0 test @@ -345,7 +349,7 @@ com.konghq unirest-java - 3.11.01 + 3.11.02 compile @@ -368,6 +372,32 @@ de.schlichtherle truezip + + net.java.truevfs + truevfs-profile-default_2.13 + + + + + com.gmail.nossr50.mcMMO + mcMMO + 2.1.150 + provided + + + + + org.jetbrains + annotations + + + com.sk89q.worldguard + worldguard-core + + + com.sk89q.worldguard + worldguard-legacy + diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java index 9cb5793b9..3f49247a9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/MinecraftVersion.java @@ -14,12 +14,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; */ public enum MinecraftVersion { - /** - * This constant represents Minecraft (Java Edition) Version 1.14 - * (The Update Aquatic) - */ - MINECRAFT_1_13("1.13.x"), - /** * This constant represents Minecraft (Java Edition) Version 1.14 * (The "Village & Pillage" Update) 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 ae85b19ab..538a1dc49 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java @@ -22,14 +22,12 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.collections.KeyMap; import io.github.thebusybiscuit.cscorelib2.config.Config; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlock; import io.github.thebusybiscuit.slimefun4.core.researching.Research; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide; @@ -100,7 +98,7 @@ public final class SlimefunRegistry { researchRanks.addAll(cfg.getStringList("research-ranks")); - backwardsCompatibility = cfg.getBoolean("options.backwards-compatibility") || SlimefunPlugin.getMinecraftVersion().isBefore(MinecraftVersion.MINECRAFT_1_14); + backwardsCompatibility = cfg.getBoolean("options.backwards-compatibility"); freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode"); researchFireworks = cfg.getBoolean("researches.enable-fireworks"); logDuplicateBlockEntries = cfg.getBoolean("options.log-duplicate-block-entries"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RechargeableHelper.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RechargeableHelper.java index f19af55a5..b0e47b1a5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RechargeableHelper.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/RechargeableHelper.java @@ -13,7 +13,6 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; import net.md_5.bungee.api.ChatColor; @@ -39,9 +38,7 @@ final class RechargeableHelper { BigDecimal decimal = BigDecimal.valueOf(charge).setScale(2, RoundingMode.HALF_UP); float value = decimal.floatValue(); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - meta.getPersistentDataContainer().set(CHARGE_KEY, PersistentDataType.FLOAT, value); - } + meta.getPersistentDataContainer().set(CHARGE_KEY, PersistentDataType.FLOAT, value); List lore = meta.hasLore() ? meta.getLore() : new ArrayList<>(); for (int i = 0; i < lore.size(); i++) { @@ -59,13 +56,11 @@ final class RechargeableHelper { } static float getCharge(@Nonnull ItemMeta meta) { - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - Float value = meta.getPersistentDataContainer().get(CHARGE_KEY, PersistentDataType.FLOAT); + Float value = meta.getPersistentDataContainer().get(CHARGE_KEY, PersistentDataType.FLOAT); - // If persistent data is available, we just return this value - if (value != null) { - return value; - } + // If persistent data is available, we just return this value + if (value != null) { + return value; } // If no persistent data exists, we will just fall back to the lore diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/ContributorsMenu.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/ContributorsMenu.java index df5d74cf0..5ed9c6918 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/ContributorsMenu.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/ContributorsMenu.java @@ -37,7 +37,7 @@ final class ContributorsMenu { menu.setEmptySlotsClickable(false); menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F)); - ChestMenuUtils.drawBackground(menu, 0, 2, 3, 4, 5, 6, 7, 8, 45, 47, 48, 49, 50, 51, 52); + ChestMenuUtils.drawBackground(menu, 0, 2, 3, 4, 5, 6, 7, 8, 45, 47, 48, 49, 50, 51, 53); menu.addItem(1, new CustomItem(ChestMenuUtils.getBackButton(p, "", "&7" + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.settings")))); menu.addMenuClickHandler(1, (pl, slot, item, action) -> { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java index 7c132d44f..1ed862a13 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java @@ -12,7 +12,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; import io.github.thebusybiscuit.slimefun4.core.services.localization.Language; @@ -41,11 +40,8 @@ public final class SlimefunGuideSettings { static { options.add(new GuideLayoutOption()); - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - options.add(new FireworksOption()); - options.add(new PlayerLanguageOption()); - } + options.add(new FireworksOption()); + options.add(new PlayerLanguageOption()); } private SlimefunGuideSettings() {} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlock.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlock.java index 61d96ebf9..49b80dd9a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlock.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlock.java @@ -41,10 +41,8 @@ public class MultiBlock { SUPPORTED_TAGS.add(Tag.LOGS); SUPPORTED_TAGS.add(Tag.WOODEN_TRAPDOORS); SUPPORTED_TAGS.add(Tag.WOODEN_SLABS); + SUPPORTED_TAGS.add(Tag.WOODEN_FENCES); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - SUPPORTED_TAGS.add(Tag.WOODEN_FENCES); - } if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) { SUPPORTED_TAGS.add(Tag.FIRE); } 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 81c8051c2..b7e5fabab 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 @@ -18,10 +18,10 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; +import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import io.papermc.lib.PaperLib; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -54,6 +54,10 @@ final class CargoUtils { Material type = block.getType(); + if (SlimefunTag.SHULKER_BOXES.isTagged(type)) { + return true; + } + switch (type) { case CHEST: case TRAPPED_CHEST: @@ -62,28 +66,13 @@ final class CargoUtils { case DROPPER: case HOPPER: case BREWING_STAND: - case SHULKER_BOX: + case BARREL: + case BLAST_FURNACE: + case SMOKER: return true; default: - break; + return false; } - - if (type.name().endsWith("_SHULKER_BOX")) { - return true; - } - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - switch (type) { - case BARREL: - case BLAST_FURNACE: - case SMOKER: - return true; - default: - break; - } - } - - return false; } static int[] getInputSlotRange(@Nonnull Inventory inv, @Nullable ItemStack item) { 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 9dd1449f8..14b39c042 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 @@ -2,6 +2,10 @@ package io.github.thebusybiscuit.slimefun4.core.services; import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.commons.lang.Validate; import org.bukkit.Keyed; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -11,8 +15,8 @@ import org.bukkit.block.TileState; import org.bukkit.persistence.PersistentDataHolder; import org.bukkit.plugin.Plugin; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.papermc.lib.PaperLib; +import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult; /** * The {@link BlockDataService} is similar to the {@link CustomItemDataService}, @@ -27,7 +31,17 @@ public class BlockDataService implements PersistentDataService, Keyed { private final NamespacedKey namespacedKey; - public BlockDataService(Plugin plugin, String key) { + /** + * This creates a new {@link BlockDataService} for the given {@link Plugin}. + * The {@link Plugin} and key will together form a {@link NamespacedKey} used to store + * data on a {@link TileState}. + * + * @param plugin + * The {@link Plugin} responsible for this service + * @param key + * The key under which to store data + */ + public BlockDataService(@Nonnull Plugin plugin, @Nonnull String key) { namespacedKey = new NamespacedKey(plugin, key); } @@ -44,12 +58,19 @@ public class BlockDataService implements PersistentDataService, Keyed { * @param value * The value to store */ - public void setBlockData(Block b, String value) { - BlockState state = b.getState(); + public void setBlockData(@Nonnull Block b, @Nonnull String value) { + Validate.notNull(b, "The block cannot be null!"); + Validate.notNull(value, "The value cannot be null!"); + + BlockStateSnapshotResult result = PaperLib.getBlockState(b, false); + BlockState state = result.getState(); if (state instanceof TileState) { setString((TileState) state, namespacedKey, value); - state.update(); + + if (result.isSnapshot()) { + state.update(); + } } } @@ -60,8 +81,10 @@ public class BlockDataService implements PersistentDataService, Keyed { * The {@link Block} to retrieve data from * @return The stored value */ - public Optional getBlockData(Block b) { - BlockState state = b.getState(); + public Optional getBlockData(@Nonnull Block b) { + Validate.notNull(b, "The block cannot be null!"); + + BlockState state = PaperLib.getBlockState(b, false).getState(); if (state instanceof TileState) { return getString((TileState) state, namespacedKey); @@ -80,12 +103,12 @@ public class BlockDataService implements PersistentDataService, Keyed { * * @param type * The {@link Material} to check for + * * @return Whether the given {@link Material} is considered a Tile Entity */ - public boolean isTileEntity(Material type) { - if (type == null || !SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - // We can only store data on Tile Entities in 1.14+ - // So we will just return false here in that case. + public boolean isTileEntity(@Nullable Material type) { + if (type == null || type.isAir()) { + // Cannot store data on air return false; } @@ -108,10 +131,12 @@ public class BlockDataService implements PersistentDataService, Keyed { 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; } } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomItemDataService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomItemDataService.java index b2ca07a7c..aed4e5d3e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomItemDataService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomItemDataService.java @@ -2,6 +2,10 @@ package io.github.thebusybiscuit.slimefun4.core.services; import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.commons.lang.Validate; import org.bukkit.Keyed; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -35,7 +39,7 @@ public class CustomItemDataService implements PersistentDataService, Keyed { * @param key * The key under which to store data */ - public CustomItemDataService(Plugin plugin, String key) { + public CustomItemDataService(@Nonnull Plugin plugin, @Nonnull String key) { // Null-Validation is performed in the NamespacedKey constructor namespacedKey = new NamespacedKey(plugin, key); } @@ -45,13 +49,37 @@ public class CustomItemDataService implements PersistentDataService, Keyed { return namespacedKey; } - public void setItemData(ItemStack item, String id) { + /** + * This method stores the given id on the provided {@link ItemStack} via + * persistent data. + * + * @param item + * The {@link ItemStack} to store data on + * @param id + * The id to store on the {@link ItemStack} + */ + public void setItemData(@Nonnull ItemStack item, @Nonnull String id) { + Validate.notNull(item, "The Item cannot be null!"); + Validate.notNull(id, "Cannot store null on an Item!"); + ItemMeta im = item.getItemMeta(); setItemData(im, id); item.setItemMeta(im); } - public void setItemData(ItemMeta im, String id) { + /** + * This method stores the given id on the provided {@link ItemMeta} via + * persistent data. + * + * @param im + * The {@link ItemMeta} to store data on + * @param id + * The id to store on the {@link ItemMeta} + */ + public void setItemData(@Nonnull ItemMeta im, @Nonnull String id) { + Validate.notNull(im, "The ItemMeta cannot be null!"); + Validate.notNull(id, "Cannot store null on an ItemMeta!"); + setString(im, namespacedKey, id); } @@ -65,7 +93,8 @@ public class CustomItemDataService implements PersistentDataService, Keyed { * * @return An {@link Optional} describing the result */ - public Optional getItemData(ItemStack item) { + @Nonnull + public Optional getItemData(@Nullable ItemStack item) { if (item == null || item.getType() == Material.AIR || !item.hasItemMeta()) { return Optional.empty(); } @@ -82,7 +111,10 @@ public class CustomItemDataService implements PersistentDataService, Keyed { * * @return An {@link Optional} describing the result */ - public Optional getItemData(ItemMeta meta) { + @Nonnull + public Optional getItemData(@Nonnull ItemMeta meta) { + Validate.notNull(meta, "Cannot read data from null!"); + return getString(meta, namespacedKey); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java index b94cecf1d..3caea1cbb 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java @@ -10,8 +10,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import io.github.thebusybiscuit.cscorelib2.config.Config; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; @@ -30,6 +28,12 @@ public class CustomTextureService { private String version = null; private boolean modified = false; + /** + * This creates a new {@link CustomTextureService} for the provided {@link Config} + * + * @param config + * The {@link Config} to read custom model data from + */ public CustomTextureService(@Nonnull Config config) { this.config = config; config.getConfiguration().options().header("This file is used to assign items from Slimefun or any of its addons\n" + "the 'CustomModelData' NBT tag. This can be used in conjunction with a custom resource pack\n" + "to give items custom textures.\n0 means there is no data assigned to that item.\n\n" + "There is no official Slimefun resource pack at the moment."); @@ -51,6 +55,8 @@ public class CustomTextureService { config.setDefaultValue("SLIMEFUN_GUIDE", 0); config.setDefaultValue("_UI_BACKGROUND", 0); + config.setDefaultValue("_UI_NO_PERMISSION", 0); + config.setDefaultValue("_UI_NOT_RESEARCHED", 0); config.setDefaultValue("_UI_INPUT_SLOT", 0); config.setDefaultValue("_UI_OUTPUT_SLOT", 0); config.setDefaultValue("_UI_BACK", 0); @@ -84,27 +90,62 @@ public class CustomTextureService { return version; } + /** + * This returns true if any custom model data was configured. + * If every item id has no configured custom model data, it will return false. + * + * @return Whether any custom model data was configured + */ public boolean isActive() { return modified; } + /** + * This returns the configured custom model data for a given id. + * + * @param id + * The id to get the data for + * + * @return The configured custom model data + */ public int getModelData(@Nonnull String id) { Validate.notNull(id, "Cannot get the ModelData for 'null'"); return config.getInt(id); } + /** + * This method sets the custom model data for this {@link ItemStack} + * to the value configured for the provided item id. + * + * @param item + * The {@link ItemStack} to set the custom model data for + * @param id + * The id for which to get the configured model data + */ public void setTexture(@Nonnull ItemStack item, @Nonnull String id) { + Validate.notNull(item, "The Item cannot be null!"); + Validate.notNull(id, "Cannot store null on an Item!"); + ItemMeta im = item.getItemMeta(); setTexture(im, id); item.setItemMeta(im); } + /** + * This method sets the custom model data for this {@link ItemMeta} + * to the value configured for the provided item id. + * + * @param im + * The {@link ItemMeta} to set the custom model data for + * @param id + * The id for which to get the configured model data + */ public void setTexture(@Nonnull ItemMeta im, @Nonnull String id) { - int data = getModelData(id); + Validate.notNull(im, "The ItemMeta cannot be null!"); + Validate.notNull(id, "Cannot store null on an ItemMeta!"); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - im.setCustomModelData(data == 0 ? null : data); - } + int data = getModelData(id); + im.setCustomModelData(data == 0 ? null : data); } } 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 5835e9f86..74ddcd2e1 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 @@ -34,9 +34,26 @@ import kong.unirest.UnirestException; */ public class MetricsService { + /** + * The URL pointing towards the GitHub API. + */ private static final String API_URL = "https://api.github.com/"; + + /** + * The Name of our repository + */ private static final String REPO_NAME = "MetricsModule"; + + /** + * The URL pointing towards the /releases/ endpoint of our + * Metrics repository + */ private static final String RELEASES_URL = API_URL + "repos/Slimefun/" + REPO_NAME + "/releases/latest"; + + /** + * The URL pointing towards the download location for a + * GitHub release of our Metrics repository + */ private static final String DOWNLOAD_URL = "https://github.com/Slimefun/" + REPO_NAME + "/releases/download"; private final SlimefunPlugin plugin; @@ -48,9 +65,22 @@ public class MetricsService { private boolean hasDownloadedUpdate = false; static { - Unirest.config().concurrency(2, 1).setDefaultHeader("User-Agent", "MetricsModule Auto-Updater").setDefaultHeader("Accept", "application/vnd.github.v3+json").enableCookieManagement(false).cookieSpec("ignoreCookies"); + // @formatter:off (We want this to stay this nicely aligned :D ) + Unirest.config() + .concurrency(2, 1) + .setDefaultHeader("User-Agent", "MetricsModule Auto-Updater") + .setDefaultHeader("Accept", "application/vnd.github.v3+json") + .enableCookieManagement(false) + .cookieSpec("ignoreCookies"); + // @formatter:on } + /** + * This constructs a new instance of our {@link MetricsService}. + * + * @param plugin + * Our {@link SlimefunPlugin} instance + */ public MetricsService(@Nonnull SlimefunPlugin plugin) { this.plugin = plugin; this.parentFolder = new File(plugin.getDataFolder(), "cache" + File.separatorChar + "modules"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PersistentDataService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PersistentDataService.java index 8a1035d74..b1792f546 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PersistentDataService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PersistentDataService.java @@ -7,32 +7,29 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataHolder; import org.bukkit.persistence.PersistentDataType; +import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; /** * This interface is used to defer calls to Persistent Data and make sure they are only called * if the {@link MinecraftVersion} supports it. * * @author TheBusyBiscuit + * + * @deprecated This is redundant, we can use {@link PersistentDataAPI} instead. * */ +@Deprecated interface PersistentDataService { default void setString(Object obj, NamespacedKey key, String value) { - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14) && obj instanceof PersistentDataHolder) { - PersistentDataContainer container = ((PersistentDataHolder) obj).getPersistentDataContainer(); - container.set(key, PersistentDataType.STRING, value); - } + PersistentDataContainer container = ((PersistentDataHolder) obj).getPersistentDataContainer(); + container.set(key, PersistentDataType.STRING, value); } default Optional getString(Object obj, NamespacedKey key) { - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14) && obj instanceof PersistentDataHolder) { - PersistentDataContainer container = ((PersistentDataHolder) obj).getPersistentDataContainer(); - return Optional.ofNullable(container.get(key, PersistentDataType.STRING)); - } - - return Optional.empty(); + PersistentDataContainer container = ((PersistentDataHolder) obj).getPersistentDataContainer(); + return Optional.ofNullable(container.get(key, PersistentDataType.STRING)); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java index f38e0c035..3d2368cea 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/ContributionsConnector.java @@ -16,11 +16,28 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; class ContributionsConnector extends GitHubConnector { - // GitHub Bots that do not count as Contributors - // (includes "invalid-email-address" because it is an invalid contributor) - private static final List blacklist = Arrays.asList("invalid-email-address", "renovate-bot", "TheBusyBot", "ImgBotApp", "imgbot", "imgbot[bot]", "github-actions[bot]", "gitlocalize-app", "gitlocalize-app[bot]", "mt-gitlocalize"); + /* + * @formatter:off + * GitHub Bots that do not count as Contributors + * (includes "invalid-email-address" because it is an invalid contributor) + */ + private static final List blacklist = Arrays.asList( + "invalid-email-address", + "renovate-bot", + "TheBusyBot", + "ImgBotApp", + "imgbot", + "imgbot[bot]", + "github-actions[bot]", + "gitlocalize-app", + "gitlocalize-app[bot]", + "mt-gitlocalize" + ); - // Matches a GitHub name with a Minecraft name. + /* + * @formatter:on + * Matches a GitHub name with a Minecraft name. + */ private static final Map aliases = new HashMap<>(); // Should probably be switched to UUIDs at some point... @@ -82,8 +99,16 @@ class ContributionsConnector extends GitHubConnector { } @Override - public String getURLSuffix() { - return "/contributors?per_page=100&page=" + page; + public String getEndpoint() { + return "/contributors"; + } + + @Override + public Map getParameters() { + Map parameters = new HashMap<>(); + parameters.put("per_page", 100); + parameters.put("page", page); + return parameters; } private void computeContributors(@Nonnull JSONArray array) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java index e55fc722e..33b6d23e1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubActivityConnector.java @@ -1,6 +1,8 @@ package io.github.thebusybiscuit.slimefun4.core.services.github; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; @@ -35,8 +37,13 @@ class GitHubActivityConnector extends GitHubConnector { } @Override - public String getURLSuffix() { + public String getEndpoint() { return ""; } + @Override + public Map getParameters() { + return new HashMap<>(); + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java index 0f9e3e317..e06e00129 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubConnector.java @@ -6,12 +6,13 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.Map; import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; import kong.unirest.HttpResponse; import kong.unirest.JsonNode; @@ -31,22 +32,49 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; abstract class GitHubConnector { private static final String API_URL = "https://api.github.com/"; + private static final String USER_AGENT = "Slimefun4 (https://github.com/Slimefun)"; - protected File file; - protected String repository; protected final GitHubService github; + private final String url; + private File file; - @ParametersAreNonnullByDefault - public GitHubConnector(GitHubService github, String repository) { + /** + * This creates a new {@link GitHubConnector} for the given repository. + * + * @param github + * Our instance of {@link GitHubService} + * @param repository + * The repository we want to connect to + */ + GitHubConnector(@Nonnull GitHubService github, @Nonnull String repository) { this.github = github; - this.repository = repository; + this.url = API_URL + "repos/" + repository + getEndpoint(); } + /** + * This returns the name of our cache {@link File}. + * + * @return The cache {@link File} name + */ @Nonnull public abstract String getFileName(); + /** + * This is our {@link URL} endpoint. + * It is the suffix of the {@link URL} we want to connect to. + * + * @return Our endpoint + */ @Nonnull - public abstract String getURLSuffix(); + public abstract String getEndpoint(); + + /** + * This {@link Map} contains the query parameters for our {@link URL}. + * + * @return A {@link Map} with our query parameters + */ + @Nonnull + public abstract Map getParameters(); /** * This method is called when the connection finished successfully. @@ -63,7 +91,12 @@ abstract class GitHubConnector { // Don't do anything by default } - public void pullFile() { + /** + * This method will connect to GitHub and store the received data inside a local + * cache {@link File}. + * Make sure to call this method asynchronously! + */ + void download() { file = new File("plugins/Slimefun/cache/github/" + getFileName() + ".json"); if (github.isLoggingEnabled()) { @@ -71,16 +104,19 @@ abstract class GitHubConnector { } try { - HttpResponse resp = Unirest.get(API_URL + "repos/" + repository + getURLSuffix()) - .header("User-Agent", "Slimefun4 (https://github.com/Slimefun)") + // @formatter:off + HttpResponse response = Unirest.get(url) + .queryString(getParameters()) + .header("User-Agent", USER_AGENT) .asJson(); + // @formatter:on - if (resp.isSuccess()) { - onSuccess(resp.getBody()); - writeCacheFile(resp.getBody()); + if (response.isSuccess()) { + onSuccess(response.getBody()); + writeCacheFile(response.getBody()); } else { if (github.isLoggingEnabled()) { - Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { repository + getURLSuffix(), resp.getStatus(), resp.getBody() }); + Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.getStatus(), response.getBody() }); } // It has the cached file, let's just read that then diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java index b22d9f491..38335e529 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesConnector.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.services.github; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import javax.annotation.Nonnull; @@ -50,8 +52,15 @@ class GitHubIssuesConnector extends GitHubConnector { } @Override - public String getURLSuffix() { - return "/issues?per_page=100"; + public String getEndpoint() { + return "/issues"; + } + + @Override + public Map getParameters() { + Map parameters = new HashMap<>(); + parameters.put("per_page", 100); + return parameters; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubService.java index b7a2fc07d..f7d103f24 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubService.java @@ -57,7 +57,8 @@ public class GitHubService { } public void start(@Nonnull SlimefunPlugin plugin) { - plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new GitHubTask(this), 80L, 60 * 60 * 20L); + GitHubTask task = new GitHubTask(this); + plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, task, 80L, 60 * 60 * 20L); } /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java index 932bf7060..151afa635 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.core.services.github; +import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -38,10 +39,14 @@ class GitHubTask implements Runnable { @Override public void run() { - gitHubService.getConnectors().forEach(GitHubConnector::pullFile); + gitHubService.getConnectors().forEach(GitHubConnector::download); grabTextures(); } + /** + * This method will pull the skin textures for every {@link Contributor} and store + * the {@link UUID} and received skin inside a local cache {@link File}. + */ private void grabTextures() { // Store all queried usernames to prevent 429 responses for pinging the // same URL twice in one run. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ClearLagHook.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ClearLagIntegration.java similarity index 75% rename from src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ClearLagHook.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ClearLagIntegration.java index 3722fcfd6..212bb1f3f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ClearLagHook.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ClearLagIntegration.java @@ -11,11 +11,19 @@ import org.bukkit.event.Listener; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import me.minebuilders.clearlag.Clearlag; import me.minebuilders.clearlag.events.EntityRemoveEvent; -class ClearLagHook implements Listener { +/** + * This handles all integrations with {@link Clearlag}. + * We don't want it to clear our altar items. + * + * @author TheBusyBiscuit + * + */ +class ClearLagIntegration implements Listener { - ClearLagHook(@Nonnull SlimefunPlugin plugin) { + ClearLagIntegration(@Nonnull SlimefunPlugin plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java index ecd2fd7b0..486c59af8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java @@ -12,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; import me.mrCookieSlime.EmeraldEnchants.EnchantmentGuide; +@Deprecated class EmeraldEnchantsCategory extends FlexCategory { public EmeraldEnchantsCategory(@Nonnull NamespacedKey key) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/McMMOIntegration.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/McMMOIntegration.java new file mode 100644 index 000000000..553627469 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/McMMOIntegration.java @@ -0,0 +1,60 @@ +package io.github.thebusybiscuit.slimefun4.core.services.plugins; + +import javax.annotation.Nonnull; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.events.skills.salvage.McMMOPlayerSalvageCheckEvent; + +import io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This handles all integrations with {@link mcMMO}. + * + * @author TheBusyBiscuit + * + */ +class McMMOIntegration implements Listener { + + McMMOIntegration(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @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()); + } + + @EventHandler(ignoreCancelled = true) + public void onItemSalvage(McMMOPlayerSalvageCheckEvent e) { + // Prevent Slimefun items from being salvaged + if (!isSalvageable(e.getSalvageItem())) { + e.setCancelled(true); + SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "anvil.mcmmo-salvaging"); + } + } + + /** + * This method checks if an {@link ItemStack} can be salvaged or not. + * We basically don't want players to salvage any {@link SlimefunItem} unless + * it is a {@link VanillaItem}. + * + * @param item + * The {@link ItemStack} to check + * + * @return Whether this item can be safely salvaged + */ + private boolean isSalvageable(@Nonnull ItemStack item) { + SlimefunItem sfItem = SlimefunItem.getByItem(item); + return sfItem == null || sfItem instanceof VanillaItem; + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIIntegration.java similarity index 93% rename from src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIIntegration.java index 892729663..d49426458 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIIntegration.java @@ -13,14 +13,21 @@ import org.bukkit.entity.Player; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.expansion.PlaceholderExpansion; -class PlaceholderAPIHook extends PlaceholderExpansion { +/** + * This is our integration for {@link PlaceholderAPI}. + * + * @author TheBusyBiscuit + * + */ +class PlaceholderAPIIntegration extends PlaceholderExpansion { private final String version; private final String author; - public PlaceholderAPIHook(@Nonnull SlimefunPlugin plugin) { + public PlaceholderAPIIntegration(@Nonnull SlimefunPlugin plugin) { this.version = plugin.getDescription().getVersion(); this.author = plugin.getDescription().getAuthors().toString(); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java index 877aac6b1..4bf85071f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java @@ -5,12 +5,16 @@ import java.util.function.Function; import java.util.logging.Level; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; +import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; +import com.gmail.nossr50.events.fake.FakeBlockBreakEvent; + import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; @@ -31,25 +35,41 @@ public class ThirdPartyPluginService { private final SlimefunPlugin plugin; + private boolean initialized = false; private boolean isExoticGardenInstalled = false; private boolean isChestTerminalInstalled = false; private boolean isEmeraldEnchantsInstalled = false; - private boolean isCoreProtectInstalled = false; - private boolean isPlaceholderAPIInstalled = false; + private boolean isMcMMOInstalled = false; - // Overridden if ExoticGarden is loaded + /** + * This gets overridden if ExoticGarden is loaded + */ private Function> exoticGardenIntegration = b -> Optional.empty(); + /** + * This initializes the {@link ThirdPartyPluginService} + * + * @param plugin + * Our instance of {@link SlimefunPlugin} + */ public ThirdPartyPluginService(@Nonnull SlimefunPlugin plugin) { this.plugin = plugin; } + /** + * This method initializes all third party integrations. + */ public void start() { + if (initialized) { + throw new UnsupportedOperationException("Third Party Integrations have already been initialized!"); + } + + initialized = true; + if (isPluginInstalled("PlaceholderAPI")) { try { - PlaceholderAPIHook hook = new PlaceholderAPIHook(plugin); + PlaceholderAPIIntegration hook = new PlaceholderAPIIntegration(plugin); hook.register(); - isPlaceholderAPIInstalled = true; } catch (Exception | LinkageError x) { String version = plugin.getServer().getPluginManager().getPlugin("PlaceholderAPI").getDescription().getVersion(); @@ -69,7 +89,7 @@ public class ThirdPartyPluginService { if (isPluginInstalled("WorldEdit")) { try { Class.forName("com.sk89q.worldedit.extent.Extent"); - new WorldEditHook(); + new WorldEditIntegration(); } catch (Exception | LinkageError x) { String version = plugin.getServer().getPluginManager().getPlugin("WorldEdit").getDescription().getVersion(); @@ -78,6 +98,21 @@ public class ThirdPartyPluginService { } } + // mcMMO Integration + if (isPluginInstalled("mcMMO")) { + try { + // This makes sure that the FakeEvent interface is present. + // Class.forName("com.gmail.nossr50.events.fake.FakeEvent"); + + new McMMOIntegration(plugin); + isMcMMOInstalled = true; + } catch (Exception | LinkageError x) { + String version = plugin.getServer().getPluginManager().getPlugin("mcMMO").getDescription().getVersion(); + Slimefun.getLogger().log(Level.WARNING, "Maybe consider updating mcMMO or Slimefun?"); + Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to hook into mcMMO v" + version); + } + } + /* * These Items are not marked as soft-dependencies and * therefore need to be loaded after the Server has finished @@ -85,7 +120,7 @@ public class ThirdPartyPluginService { */ plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { if (isPluginInstalled("ClearLag")) { - new ClearLagHook(plugin); + new ClearLagIntegration(plugin); } isChestTerminalInstalled = isPluginInstalled("ChestTerminal"); @@ -101,6 +136,7 @@ public class ThirdPartyPluginService { } } + @ParametersAreNonnullByDefault public void loadExoticGarden(Plugin plugin, Function> method) { if (plugin.getName().equals("ExoticGarden")) { isExoticGardenInstalled = true; @@ -120,16 +156,22 @@ public class ThirdPartyPluginService { return isEmeraldEnchantsInstalled; } - public boolean isCoreProtectInstalled() { - return isCoreProtectInstalled; - } - - public boolean isPlaceholderAPIInstalled() { - return isPlaceholderAPIInstalled; - } - public Optional harvestExoticGardenPlant(Block block) { return exoticGardenIntegration.apply(block); } + /** + * This checks if one of our third party integrations faked an {@link Event}. + * Faked {@link Event Events} should be ignored in our logic. + * + * @param event + * The {@link Event} to test + * + * @return Whether this is a fake event + */ + public boolean isEventFaked(@Nonnull Event event) { + // TODO: Change this to FakeEvent once the new mcMMO build was released + return isMcMMOInstalled && event instanceof FakeBlockBreakEvent; + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/WorldEditHook.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/WorldEditIntegration.java similarity index 86% rename from src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/WorldEditHook.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/WorldEditIntegration.java index 3b134df92..38af34726 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/WorldEditHook.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/WorldEditIntegration.java @@ -14,9 +14,16 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import me.mrCookieSlime.Slimefun.api.BlockStorage; -class WorldEditHook { +/** + * This handles all integrations with {@link WorldEdit}. + * If an are is cleared, we also wanna clear all Slimefun-related block data. + * + * @author TheBusyBiscuit + * + */ +class WorldEditIntegration { - WorldEditHook() { + WorldEditIntegration() { WorldEdit.getInstance().getEventBus().register(this); } 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 5dbbed514..ed827eae7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -394,7 +394,7 @@ public final class SlimefunItems { public static final SlimefunItemStack PLASTIC_SHEET = new SlimefunItemStack("PLASTIC_SHEET", Material.PAPER, "&fPlastic Sheet"); public static final SlimefunItemStack MAGNET = new SlimefunItemStack("MAGNET", HeadTexture.MAGNET, "&cMagnet"); - public static final SlimefunItemStack NECROTIC_SKULL = new SlimefunItemStack("NECROTIC_SKULL", Material.WITHER_SKELETON_SKULL, "&cNecrotic Skull"); + public static final SlimefunItemStack NECROTIC_SKULL = new SlimefunItemStack("NECROTIC_SKULL", HeadTexture.NECROTIC_SKULL, "&cNecrotic Skull"); public static final SlimefunItemStack ESSENCE_OF_AFTERLIFE = new SlimefunItemStack("ESSENCE_OF_AFTERLIFE", Material.GUNPOWDER, "&4Essence of Afterlife"); public static final SlimefunItemStack STRANGE_NETHER_GOO = new SlimefunItemStack("STRANGE_NETHER_GOO", Material.PURPLE_DYE, "&5Strange Nether Goo", "", "&fA strange bio matter that", "&fcan be acquired from", "&fbartering with Piglins"); public static final SlimefunItemStack ELECTRO_MAGNET = new SlimefunItemStack("ELECTRO_MAGNET", HeadTexture.MAGNET, "&cElectromagnet"); @@ -569,14 +569,14 @@ public final class SlimefunItems { public static final SlimefunItemStack ENHANCED_CRAFTING_TABLE = new SlimefunItemStack("ENHANCED_CRAFTING_TABLE", Material.CRAFTING_TABLE, "&eEnhanced Crafting Table", "", "&aA regular Crafting Table cannot", "&ahold this massive Amount of Power..."); public static final SlimefunItemStack GRIND_STONE = new SlimefunItemStack("GRIND_STONE", Material.DISPENSER, "&bGrind Stone", "", "&aGrinds items down into other items"); public static final SlimefunItemStack ARMOR_FORGE = new SlimefunItemStack("ARMOR_FORGE", Material.ANVIL, "&6Armor Forge", "", "&aGives you the ability to create powerful armor"); - public static final SlimefunItemStack MAKESHIFT_SMELTERY; + public static final SlimefunItemStack MAKESHIFT_SMELTERY = new SlimefunItemStack("MAKESHIFT_SMELTERY", Material.BLAST_FURNACE, "&eMakeshift Smeltery", "", "&fImprovised version of the Smeltery", "&fthat only allows you to", "&fsmelt dusts into ingots"); public static final SlimefunItemStack SMELTERY = new SlimefunItemStack("SMELTERY", Material.FURNACE, "&6Smeltery", "", "&fA high-temperature furnace", "&fthat allows you to smelt dusts", "&finto ingots and create alloys."); public static final SlimefunItemStack ORE_CRUSHER = new SlimefunItemStack("ORE_CRUSHER", Material.DISPENSER, "&bOre Crusher", "", "&aCrushes ores to double them"); public static final SlimefunItemStack COMPRESSOR = new SlimefunItemStack("COMPRESSOR", Material.PISTON, "&bCompressor", "", "&aCompresses Items"); public static final SlimefunItemStack PRESSURE_CHAMBER = new SlimefunItemStack("PRESSURE_CHAMBER", Material.GLASS, "&bPressure Chamber", "", "&aCompresses Items even further"); public static final SlimefunItemStack MAGIC_WORKBENCH = new SlimefunItemStack("MAGIC_WORKBENCH", Material.CRAFTING_TABLE, "&6Magic Workbench", "", "&dInfuses Items with magical Energy"); public static final SlimefunItemStack ORE_WASHER = new SlimefunItemStack("ORE_WASHER", Material.CAULDRON, "&6Ore Washer", "", "&aWashes Sifted Ore to filter Ores", "&aand gives you small Stone Chunks"); - public static final SlimefunItemStack TABLE_SAW; + public static final SlimefunItemStack TABLE_SAW = new SlimefunItemStack("TABLE_SAW", Material.STONECUTTER, "&6Table Saw", "", "&aAllows you to get 8 planks from 1 Log", "&a(Works with all log types)"); public static final SlimefunItemStack JUICER = new SlimefunItemStack("JUICER", Material.GLASS_BOTTLE, "&aJuicer", "", "&aAllows you to create delicious Juice"); public static final SlimefunItemStack AUTOMATED_PANNING_MACHINE = new SlimefunItemStack("AUTOMATED_PANNING_MACHINE", Material.BOWL, "&eAutomated Panning Machine", "", "&fA MultiBlock Version of the Gold Pan", "&fand Nether Gold Pan combined in one machine."); @@ -664,12 +664,12 @@ public final class SlimefunItems { public static final SlimefunItemStack ELECTRIC_ORE_GRINDER = new SlimefunItemStack("ELECTRIC_ORE_GRINDER", Material.FURNACE, "&cElectric Ore Grinder", "", "&fWorks as an Ore Crusher and Grind Stone", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(12)); public static final SlimefunItemStack ELECTRIC_ORE_GRINDER_2 = new SlimefunItemStack("ELECTRIC_ORE_GRINDER_2", Material.FURNACE, "&cElectric Ore Grinder &7(&eII&7)", "", "&fWorks as an Ore Crusher and Grind Stone", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), LoreBuilder.speed(4), LoreBuilder.powerPerSecond(30)); public static final SlimefunItemStack ELECTRIC_INGOT_PULVERIZER = new SlimefunItemStack("ELECTRIC_INGOT_PULVERIZER", Material.FURNACE, "&cElectric Ingot Pulverizer", "", "&fPulverizes Ingots into Dust", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(14)); - public static final SlimefunItemStack AUTO_DRIER; + public static final SlimefunItemStack AUTO_DRIER = new SlimefunItemStack("AUTO_DRIER", Material.SMOKER, "&6Auto Drier", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(10)); public static final SlimefunItemStack AUTO_ENCHANTER = new SlimefunItemStack("AUTO_ENCHANTER", Material.ENCHANTING_TABLE, "&5Auto Enchanter", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(18)); public static final SlimefunItemStack AUTO_DISENCHANTER = new SlimefunItemStack("AUTO_DISENCHANTER", Material.ENCHANTING_TABLE, "&5Auto Disenchanter", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(18)); public static final SlimefunItemStack AUTO_ANVIL = new SlimefunItemStack("AUTO_ANVIL", Material.IRON_BLOCK, "&7Auto Anvil", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &7Repair Factor: 10%", LoreBuilder.powerPerSecond(24)); public static final SlimefunItemStack AUTO_ANVIL_2 = new SlimefunItemStack("AUTO_ANVIL_2", Material.IRON_BLOCK, "&7Auto Anvil Mk.II", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), "&8\u21E8 &7Repair Factor: 25%", LoreBuilder.powerPerSecond(32)); - public static final SlimefunItemStack AUTO_BREWER; + public static final SlimefunItemStack AUTO_BREWER = new SlimefunItemStack("AUTO_BREWER", Material.SMOKER, "&6Auto Brewer", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(12)); public static final SlimefunItemStack BIO_REACTOR = new SlimefunItemStack("BIO_REACTOR", Material.LIME_TERRACOTTA, "&2Bio Reactor", "", LoreBuilder.machine(MachineTier.AVERAGE, MachineType.GENERATOR), LoreBuilder.powerBuffer(128), LoreBuilder.powerPerSecond(8)); public static final SlimefunItemStack MULTIMETER = new SlimefunItemStack("MULTIMETER", Material.CLOCK, "&eMultimeter", "", "&fMeasures the Amount of stored", "&fEnergy in a Block"); @@ -843,17 +843,5 @@ public final class SlimefunItems { static { INFUSED_ELYTRA.addUnsafeEnchantment(Enchantment.MENDING, 1); - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - TABLE_SAW = new SlimefunItemStack("TABLE_SAW", Material.STONECUTTER, "&6Table Saw", "", "&aAllows you to get 8 planks from 1 Log", "&a(Works with all log types)"); - MAKESHIFT_SMELTERY = new SlimefunItemStack("MAKESHIFT_SMELTERY", Material.BLAST_FURNACE, "&eMakeshift Smeltery", "", "&fImprovised version of the Smeltery", "&fthat only allows you to", "&fsmelt dusts into ingots"); - AUTO_DRIER = new SlimefunItemStack("AUTO_DRIER", Material.SMOKER, "&6Auto Drier", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(10)); - AUTO_BREWER = new SlimefunItemStack("AUTO_BREWER", Material.SMOKER, "&6Auto Brewer", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(12)); - } else { - TABLE_SAW = null; - MAKESHIFT_SMELTERY = new SlimefunItemStack("MAKESHIFT_SMELTERY", Material.FURNACE, "&eMakeshift Smeltery", "", "&fImprovised version of the Smeltery", "&fthat only allows you to", "&fsmelt dusts into ingots"); - AUTO_DRIER = new SlimefunItemStack("AUTO_DRIER", Material.FURNACE, "&6Auto Drier", "", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(10)); - AUTO_BREWER = new SlimefunItemStack("AUTO_BREWER", Material.BREWING_STAND, "&6Auto Brewer", LoreBuilder.machine(MachineTier.MEDIUM, MachineType.MACHINE), LoreBuilder.speed(1), LoreBuilder.powerPerSecond(12)); - } } } 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 b2656d623..2d14d4f21 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java @@ -89,10 +89,15 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunItemL import io.github.thebusybiscuit.slimefun4.implementation.listeners.SoulboundListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.TalismanListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.VampireBladeListener; -import io.github.thebusybiscuit.slimefun4.implementation.listeners.VanillaMachinesListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.VillagerTradingListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.WitherListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.WorldListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.AnvilListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.BrewingStandListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CartographyTableListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CauldronListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CraftingTableListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.GrindstoneListener; import io.github.thebusybiscuit.slimefun4.implementation.resources.GEOResourcesSetup; import io.github.thebusybiscuit.slimefun4.implementation.setup.PostSetup; import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup; @@ -176,9 +181,14 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { command.register(); registry.load(config); } else if (getServer().getPluginManager().isPluginEnabled("CS-CoreLib")) { + getLogger().log(Level.INFO, "CS-CoreLib was detected!"); long timestamp = System.nanoTime(); PaperLib.suggestPaper(this); + if (PaperLib.isPaper()) { + getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied."); + } + // We wanna ensure that the Server uses a compatible version of Minecraft if (isVersionUnsupported()) { getServer().getPluginManager().disablePlugin(this); @@ -270,7 +280,10 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { autoSavingService.start(this, config.getInt("options.auto-save-delay-in-minutes")); ticker.start(this); + + getLogger().log(Level.INFO, "Loading Third-Party plugin integrations..."); thirdPartySupportService.start(); + gitHubService.start(this); // Hooray! @@ -445,7 +458,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new DeathpointListener(this); new ExplosionsListener(this); new DebugFishListener(this); - new VanillaMachinesListener(this); new FireworksListener(this); new WitherListener(this); new IronGolemListener(this); @@ -453,6 +465,12 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new MobDropListener(this); new VillagerTradingListener(this); new ElytraCrashListener(this); + new CraftingTableListener(this); + new AnvilListener(this); + new BrewingStandListener(this); + new CauldronListener(this); + new GrindstoneListener(this); + new CartographyTableListener(this); if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) { new BeeListener(this); @@ -469,6 +487,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new AncientAltarListener(this, (AncientAltar) SlimefunItems.ANCIENT_ALTAR.getItem(), (AncientPedestal) SlimefunItems.ANCIENT_PEDESTAL.getItem()); grapplingHookListener.register(this, (GrapplingHook) SlimefunItems.GRAPPLING_HOOK.getItem()); bowListener.register(this); + backpackListener.register(this); // Toggleable Listeners for performance reasons if (config.getBoolean("items.talismans")) { @@ -479,10 +498,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new SoulboundListener(this); } - if (config.getBoolean("items.backpacks")) { - backpackListener.register(this); - } - // Handle Slimefun Guide being given on Join new SlimefunGuideListener(this, config.getBoolean("guide.receive-on-first-join")); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java index 4f346f291..d88a295bf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java @@ -1,7 +1,5 @@ package io.github.thebusybiscuit.slimefun4.implementation.guide; -import javax.annotation.Nonnull; - import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -10,6 +8,9 @@ import java.util.Locale; import java.util.Optional; import java.util.logging.Level; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; @@ -26,7 +27,6 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatInput; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.recipes.MinecraftRecipe; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory; @@ -65,21 +65,15 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; public class ChestSlimefunGuide implements SlimefunGuideImplementation { private static final int CATEGORY_SIZE = 36; + private static final Sound sound = Sound.ITEM_BOOK_PAGE_TURN; - private final ItemStack item; private final int[] recipeSlots = { 3, 4, 5, 12, 13, 14, 21, 22, 23 }; - private final Sound sound; + private final ItemStack item; private final boolean showVanillaRecipes; - public ChestSlimefunGuide(boolean vanillaRecipes) { - showVanillaRecipes = vanillaRecipes; + public ChestSlimefunGuide(boolean showVanillaRecipes) { + this.showVanillaRecipes = showVanillaRecipes; item = new SlimefunGuideItem(this, "&aSlimefun Guide &7(Chest GUI)"); - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - sound = Sound.ITEM_BOOK_PAGE_TURN; - } else { - sound = Sound.ENTITY_BAT_TAKEOFF; - } } @Override @@ -132,7 +126,6 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation { } ChestMenu menu = create(p); - List categories = getVisibleCategories(p, profile); int index = 9; @@ -278,10 +271,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation { if (isSurvivalMode() && !Slimefun.hasPermission(p, sfitem, false)) { List message = SlimefunPlugin.getPermissionsService().getLore(sfitem); - menu.addItem(index, new CustomItem(Material.BARRIER, sfitem.getItemName(), message.toArray(new String[0]))); + menu.addItem(index, new CustomItem(ChestMenuUtils.getNoPermissionItem(), sfitem.getItemName(), message.toArray(new String[0]))); menu.addMenuClickHandler(index, ChestMenuUtils.getEmptyClickHandler()); } else if (isSurvivalMode() && research != null && !profile.hasUnlocked(research)) { - menu.addItem(index, new CustomItem(Material.BARRIER, ChatColor.WHITE + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level(s)")); + menu.addItem(index, new CustomItem(ChestMenuUtils.getNotResearchedItem(), ChatColor.WHITE + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level(s)")); menu.addMenuClickHandler(index, (pl, slot, item, action) -> { if (!SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().contains(pl.getUniqueId())) { if (research.canUnlock(pl)) { @@ -341,26 +334,14 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation { int index = 9; // Find items and add them for (SlimefunItem slimefunItem : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) { - String itemName = ChatColor.stripColor(slimefunItem.getItemName()).toLowerCase(Locale.ROOT); - if (index == 44) { break; } - if (!itemName.isEmpty() && (itemName.equals(searchTerm) || itemName.contains(searchTerm))) { + if (isSearchFilterApplicable(slimefunItem, searchTerm)) { ItemStack itemstack = new CustomItem(slimefunItem.getItem(), meta -> { - List lore = null; Category category = slimefunItem.getCategory(); - - if (category != null) { - ItemStack categoryItem = category.getItem(p); - - if (categoryItem != null && categoryItem.hasItemMeta() && categoryItem.getItemMeta().hasDisplayName()) { - lore = Arrays.asList("", ChatColor.DARK_GRAY + "\u21E8 " + ChatColor.WHITE + categoryItem.getItemMeta().getDisplayName()); - } - } - - meta.setLore(lore); + meta.setLore(Arrays.asList("", ChatColor.DARK_GRAY + "\u21E8 " + ChatColor.WHITE + category.getDisplayName(p))); meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_POTION_EFFECTS); }); @@ -386,6 +367,12 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation { menu.open(p); } + @ParametersAreNonnullByDefault + private boolean isSearchFilterApplicable(SlimefunItem slimefunItem, String searchTerm) { + String itemName = ChatColor.stripColor(slimefunItem.getItemName()).toLowerCase(Locale.ROOT); + return !itemName.isEmpty() && (itemName.equals(searchTerm) || itemName.contains(searchTerm)); + } + @Override public void displayItem(PlayerProfile profile, ItemStack item, int index, boolean addToHistory) { Player p = profile.getPlayer(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidType.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidType.java index 61e7a2eaa..732c998a3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidType.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidType.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids; +import javax.annotation.Nonnull; + /** * This enum holds all the different types a {@link ProgrammableAndroid} can represent. * @@ -55,7 +57,7 @@ public enum AndroidType { */ NON_FIGHTER; - boolean isType(AndroidType type) { + boolean isType(@Nonnull AndroidType type) { return type == NONE || type == this || (type == NON_FIGHTER && this != FIGHTER); } 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 060bb6b81..e46721c84 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 @@ -10,8 +10,6 @@ import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; @@ -57,10 +55,6 @@ public class FarmerAndroid extends ProgrammableAndroid { private ItemStack getDropFromCrop(Material crop) { Random random = ThreadLocalRandom.current(); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14) && crop == Material.SWEET_BERRY_BUSH) { - return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1); - } - switch (crop) { case WHEAT: return new ItemStack(Material.WHEAT, random.nextInt(2) + 1); @@ -74,6 +68,8 @@ public class FarmerAndroid extends ProgrammableAndroid { 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/FisherAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FisherAndroid.java index d2e9ce0c3..de83525a7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FisherAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FisherAndroid.java @@ -10,8 +10,6 @@ import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.collections.RandomizedSet; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; @@ -37,10 +35,7 @@ public class FisherAndroid extends ProgrammableAndroid { fishingLoot.add(new ItemStack(Material.STICK), 5); fishingLoot.add(new ItemStack(Material.ROTTEN_FLESH), 3); fishingLoot.add(new ItemStack(Material.LEATHER), 2); - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - fishingLoot.add(new ItemStack(Material.BAMBOO), 3); - } + fishingLoot.add(new ItemStack(Material.BAMBOO), 3); // "loot" fishingLoot.add(new ItemStack(Material.SADDLE), 1); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java index 4a2083b05..6c707c979 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.function.Predicate; import org.apache.commons.lang.Validate; +import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Ageable; @@ -20,126 +21,223 @@ import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; -enum Instruction { +/** + * This enum holds every {@link Instruction} for the {@link ProgrammableAndroid} + * added by Slimefun itself. + * + * @author TheBusyBiscuit + * + */ +public enum Instruction { - // Start and End Parts + /** + * This {@link Instruction} is the starting point of a {@link Script}. + */ START(AndroidType.NONE, HeadTexture.SCRIPT_START), + + /** + * This {@link Instruction} is the end token of a {@link Script}. + * Once this {@link Instruction} is reached, the {@link Script} will start again. + */ REPEAT(AndroidType.NONE, HeadTexture.SCRIPT_REPEAT), + + /** + * This {@link Instruction} will make the {@link ProgrammableAndroid} wait + * for one Slimefun tick. + */ WAIT(AndroidType.NONE, HeadTexture.SCRIPT_WAIT), - // Movement + /** + * This will make the {@link ProgrammableAndroid} go forward. + */ GO_FORWARD(AndroidType.NON_FIGHTER, HeadTexture.SCRIPT_FORWARD, (android, b, inv, face) -> { Block target = b.getRelative(face); android.move(b, face, target); }), + /** + * This will make the {@link ProgrammableAndroid} go up. + */ GO_UP(AndroidType.NON_FIGHTER, HeadTexture.SCRIPT_UP, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.UP); android.move(b, face, target); }), + /** + * This will make the {@link ProgrammableAndroid} go down. + */ GO_DOWN(AndroidType.NON_FIGHTER, HeadTexture.SCRIPT_DOWN, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.DOWN); android.move(b, face, target); }), - // Directions + /** + * This will make the {@link ProgrammableAndroid} rotate to the left side. + */ TURN_LEFT(AndroidType.NONE, HeadTexture.SCRIPT_LEFT, (android, b, inv, face) -> { int mod = -1; android.rotate(b, face, mod); }), + /** + * This will make the {@link ProgrammableAndroid} rotate to the right side. + */ TURN_RIGHT(AndroidType.NONE, HeadTexture.SCRIPT_RIGHT, (android, b, inv, face) -> { int mod = 1; android.rotate(b, face, mod); }), - // Action - Pickaxe + /** + * This will make a {@link MinerAndroid} dig the {@link Block} above. + */ DIG_UP(AndroidType.MINER, HeadTexture.SCRIPT_DIG_UP, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.UP); android.dig(b, inv, target); }), + /** + * This will make a {@link MinerAndroid} dig the {@link Block} ahead. + */ DIG_FORWARD(AndroidType.MINER, HeadTexture.SCRIPT_DIG_FORWARD, (android, b, inv, face) -> { Block target = b.getRelative(face); android.dig(b, inv, target); }), + /** + * This will make a {@link MinerAndroid} dig the {@link Block} below. + */ DIG_DOWN(AndroidType.MINER, HeadTexture.SCRIPT_DIG_DOWN, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.DOWN); android.dig(b, inv, target); }), + /** + * This will make a {@link MinerAndroid} dig the {@link Block} above + * and then move itself to that new {@link Location}. + */ MOVE_AND_DIG_UP(AndroidType.MINER, HeadTexture.SCRIPT_DIG_UP, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.UP); android.moveAndDig(b, inv, face, target); }), + /** + * This will make a {@link MinerAndroid} dig the {@link Block} ahead + * and then move itself to that new {@link Location}. + */ MOVE_AND_DIG_FORWARD(AndroidType.MINER, HeadTexture.SCRIPT_DIG_FORWARD, (android, b, inv, face) -> { Block target = b.getRelative(face); android.moveAndDig(b, inv, face, target); }), + /** + * This will make a {@link MinerAndroid} dig the {@link Block} below + * and then move itself to that new {@link Location}. + */ MOVE_AND_DIG_DOWN(AndroidType.MINER, HeadTexture.SCRIPT_DIG_DOWN, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.DOWN); android.moveAndDig(b, inv, face, target); }), - // Action - Sword + /** + * This will make a {@link ButcherAndroid} attack any {@link LivingEntity} + * ahead of them. + */ ATTACK_MOBS_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> { Predicate predicate = e -> true; android.attack(b, face, predicate); }), + /** + * This will make a {@link ButcherAndroid} attack any {@link Monster} + * ahead of them. + */ ATTACK_MOBS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> { Predicate predicate = e -> e instanceof Monster; android.attack(b, face, predicate); }), + /** + * This will make a {@link ButcherAndroid} attack any {@link Animals Animal} + * ahead of them. + */ ATTACK_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> { Predicate predicate = e -> e instanceof Animals; android.attack(b, face, predicate); }), + /** + * This will make a {@link ButcherAndroid} attack any adult + * {@link Animals Animal} ahead of them. + */ ATTACK_ANIMALS_ADULT(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> { - Predicate predicate = e -> e instanceof Animals && e instanceof Ageable && ((Ageable) e).isAdult(); + Predicate predicate = e -> e instanceof Animals && ((Ageable) e).isAdult(); android.attack(b, face, predicate); }), - // Action - Axe + /** + * This will make a {@link WoodcutterAndroid} chop down the tree in front of them. + */ CHOP_TREE(AndroidType.WOODCUTTER, HeadTexture.SCRIPT_CHOP_TREE), - // Action - Fishing Rod + /** + * This {@link Instruction} makes a {@link FisherAndroid} try to catch fish from + * the water below. + */ CATCH_FISH(AndroidType.FISHERMAN, HeadTexture.SCRIPT_FISH, (android, b, inv, face) -> android.fish(b, inv)), - // Action - Hoe + /** + * This {@link Instruction} will make a {@link FarmerAndroid} try to harvest + * the {@link Block} in front of them. + */ FARM_FORWARD(AndroidType.FARMER, HeadTexture.SCRIPT_FARM_FORWARD, (android, b, inv, face) -> { Block target = b.getRelative(face); android.farm(inv, target); }), + /** + * This {@link Instruction} will make a {@link FarmerAndroid} try to harvest + * the {@link Block} below. + */ FARM_DOWN(AndroidType.FARMER, HeadTexture.SCRIPT_FARM_DOWN, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.DOWN); android.farm(inv, target); }), - // Action - ExoticGarden + /** + * This {@link Instruction} will make a {@link FarmerAndroid} try to harvest + * the {@link Block} in front of them. + * + * This includes plants from ExoticGarden. + */ FARM_EXOTIC_FORWARD(AndroidType.ADVANCED_FARMER, HeadTexture.SCRIPT_FARM_FORWARD, (android, b, inv, face) -> { Block target = b.getRelative(face); android.exoticFarm(inv, target); }), + /** + * This {@link Instruction} will make a {@link FarmerAndroid} try to harvest + * the {@link Block} below. + * + * This includes plants from ExoticGarden. + */ FARM_EXOTIC_DOWN(AndroidType.ADVANCED_FARMER, HeadTexture.SCRIPT_FARM_DOWN, (android, b, inv, face) -> { Block target = b.getRelative(BlockFace.DOWN); android.exoticFarm(inv, target); }), - // Action - Interface + /** + * This {@link Instruction} will force the {@link ProgrammableAndroid} to push their + * items into an {@link AndroidInterface} ahead of them. + */ INTERFACE_ITEMS(AndroidType.NONE, HeadTexture.SCRIPT_PUSH_ITEMS, (android, b, inv, face) -> { Block target = b.getRelative(face); android.depositItems(inv, target); }), + /** + * This {@link Instruction} will force the {@link ProgrammableAndroid} to pull + * fuel from an {@link AndroidInterface} ahead of them. + */ INTERFACE_FUEL(AndroidType.NONE, HeadTexture.SCRIPT_PULL_FUEL, (android, b, inv, face) -> { Block target = b.getRelative(face); android.refuel(inv, target); 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 b57b449e4..07d828f96 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 @@ -58,6 +58,7 @@ 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.Slimefun; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; @@ -69,6 +70,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 24, 25, 26, 27, 33, 35, 36, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 }; private static final int[] OUTPUT_BORDER = { 10, 11, 12, 13, 14, 19, 23, 28, 32, 37, 38, 39, 40, 41 }; private static final String DEFAULT_SCRIPT = "START-TURN_LEFT-REPEAT"; + private static final int MAX_SCRIPT_LENGTH = 54; protected final List fuelTypes = new ArrayList<>(); protected final String texture; @@ -407,19 +409,23 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, } else { Script script = scripts.get(target); menu.addItem(index, script.getAsItemStack(this, p), (player, slot, stack, action) -> { - if (action.isShiftClicked()) { - if (script.isAuthor(player)) { - SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.own", true); - } else if (script.canRate(player)) { - script.rate(player, !action.isRightClicked()); - openScriptDownloader(player, b, page); - } else { - SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.already", true); + try { + if (action.isShiftClicked()) { + if (script.isAuthor(player)) { + SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.own", true); + } else if (script.canRate(player)) { + script.rate(player, !action.isRightClicked()); + openScriptDownloader(player, b, page); + } else { + SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.already", true); + } + } else if (!action.isRightClicked()) { + script.download(); + setScript(b.getLocation(), script.getSourceCode()); + openScriptEditor(player, b); } - } else if (!action.isRightClicked()) { - script.download(); - setScript(b.getLocation(), script.getSourceCode()); - openScriptEditor(player, b); + } catch (Exception x) { + Slimefun.getLogger().log(Level.SEVERE, "An Exception was thrown when a User tried to download a Script!", x); } return false; @@ -534,12 +540,19 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, } @Nonnull - protected String getScript(@Nonnull Location l) { + public String getScript(@Nonnull Location l) { + Validate.notNull(l, "Location for android not specified"); String script = BlockStorage.getLocationInfo(l, "script"); return script != null ? script : DEFAULT_SCRIPT; } - protected void setScript(@Nonnull Location l, @Nonnull String script) { + public void setScript(@Nonnull Location l, @Nonnull String script) { + Validate.notNull(l, "Location for android not specified"); + Validate.notNull(script, "No script given"); + Validate.isTrue(script.startsWith(Instruction.START.name() + '-'), "A script must begin with a 'START' token."); + Validate.isTrue(script.endsWith('-' + Instruction.REPEAT.name()), "A script must end with a 'REPEAT' token."); + Validate.isTrue(PatternUtils.DASH.split(script).length <= MAX_SCRIPT_LENGTH, "Scripts may not have more than " + MAX_SCRIPT_LENGTH + " segments"); + BlockStorage.addBlockInfo(l, "script", script); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java index 5d97975f7..7ee370638 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java @@ -130,18 +130,19 @@ public final class Script { @Nonnull ItemStack getAsItemStack(@Nonnull ProgrammableAndroid android, @Nonnull Player p) { List lore = new LinkedList<>(); - lore.add("&7by &r" + getAuthor()); + lore.add("&7by &f" + getAuthor()); lore.add(""); - lore.add("&7Downloads: &r" + getDownloads()); + lore.add("&7Downloads: &f" + getDownloads()); lore.add("&7Rating: " + getScriptRatingPercentage()); lore.add("&a" + getUpvotes() + " \u263A &7| &4\u2639 " + getDownvotes()); lore.add(""); - lore.add("&eLeft Click &rto download this Script"); + lore.add("&eLeft Click &fto download this Script"); lore.add("&4(This will override your current Script)"); if (canRate(p)) { - lore.add("&eShift + Left Click &rto leave a positive Rating"); - lore.add("&eShift + Right Click &rto leave a negative Rating"); + lore.add(""); + lore.add("&eShift + Left Click &fto leave a positive Rating"); + lore.add("&eShift + Right Click &fto leave a negative Rating"); } return new CustomItem(android.getItem(), "&b" + getName(), lore.toArray(new String[0])); 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 ee8f5c6df..73cd1902f 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 @@ -18,6 +18,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; @@ -72,6 +73,14 @@ public class Crucible extends SimpleSlimefunItem implements Rec items.add(new ItemStack(Material.LAVA_BUCKET)); } + if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) { + items.add(new ItemStack(Material.BLACKSTONE, 8)); + items.add(new ItemStack(Material.LAVA_BUCKET)); + + items.add(new ItemStack(Material.BASALT, 12)); + items.add(new ItemStack(Material.LAVA_BUCKET)); + } + return items; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/AbstractEnergyProvider.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/AbstractEnergyProvider.java index cc16f0db6..b7767796b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/AbstractEnergyProvider.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/AbstractEnergyProvider.java @@ -8,6 +8,7 @@ import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import org.apache.commons.lang.Validate; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -89,11 +90,12 @@ public abstract class AbstractEnergyProvider extends SlimefunItem implements Inv } public void registerFuel(@Nonnull MachineFuel fuel) { + Validate.notNull(fuel, "Machine Fuel cannot be null!"); fuelTypes.add(fuel); } @Nonnull - public Set getFuelTypes() { + public Set getFuelTypes2() { return fuelTypes; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/BioGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/BioGenerator.java index 18a864221..e1c624ede 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/BioGenerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/BioGenerator.java @@ -48,15 +48,12 @@ public abstract class BioGenerator extends AGenerator { registerFuel(new MachineFuel(20, new ItemStack(Material.DRIED_KELP_BLOCK))); registerFuel(new MachineFuel(1, new ItemStack(Material.SEAGRASS))); registerFuel(new MachineFuel(2, new ItemStack(Material.SEA_PICKLE))); + registerFuel(new MachineFuel(1, new ItemStack(Material.BAMBOO))); + registerFuel(new MachineFuel(2, new ItemStack(Material.SWEET_BERRIES))); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - registerFuel(new MachineFuel(1, new ItemStack(Material.BAMBOO))); - registerFuel(new MachineFuel(2, new ItemStack(Material.SWEET_BERRIES))); - - // Small Flowers (formally just dandelions and poppies). - for (Material m : Tag.SMALL_FLOWERS.getValues()) { - registerFuel(new MachineFuel(1, new ItemStack(m))); - } + // Small Flowers (formally just dandelions and poppies). + for (Material m : Tag.SMALL_FLOWERS.getValues()) { + registerFuel(new MachineFuel(1, new ItemStack(m))); } if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_15)) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java index 1f0499a61..886164817 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java @@ -74,7 +74,7 @@ public abstract class CoalGenerator extends AGenerator { } // Signs - for (Material mat : Tag.SIGNS.getValues()) { + for (Material mat : Tag.STANDING_SIGNS.getValues()) { registerFuel(new MachineFuel(2, new ItemStack(mat))); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectrifiedCrucible.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectrifiedCrucible.java index f0d7c128d..e26b0c9ea 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectrifiedCrucible.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectrifiedCrucible.java @@ -4,6 +4,8 @@ import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.inventory.ItemStack; +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; @@ -29,6 +31,11 @@ public abstract class ElectrifiedCrucible extends AContainer { for (Material leaves : Tag.LEAVES.getValues()) { registerRecipe(10, new ItemStack[] { new ItemStack(Material.BUCKET), new ItemStack(leaves, 16) }, new ItemStack[] { new ItemStack(Material.WATER_BUCKET) }); } + + if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) { + registerRecipe(10, new ItemStack[] { new ItemStack(Material.BUCKET), new ItemStack(Material.BLACKSTONE, 8) }, new ItemStack[] { new ItemStack(Material.LAVA_BUCKET) }); + registerRecipe(10, new ItemStack[] { new ItemStack(Material.BUCKET), new ItemStack(Material.BASALT, 12) }, new ItemStack[] { new ItemStack(Material.LAVA_BUCKET) }); + } } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodComposter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodComposter.java index 8f7988af3..a7ef3c4b8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodComposter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodComposter.java @@ -3,10 +3,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.misc.OrganicFertilizer; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; @@ -30,10 +28,7 @@ public abstract class FoodComposter extends AContainer implements RecipeDisplayI registerRecipe(30, new ItemStack[] { SlimefunItems.APPLE_ORGANIC_FOOD }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.APPLE_FERTILIZER, OrganicFertilizer.OUTPUT) }); registerRecipe(30, new ItemStack[] { SlimefunItems.KELP_ORGANIC_FOOD }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.KELP_FERTILIZER, OrganicFertilizer.OUTPUT) }); registerRecipe(30, new ItemStack[] { SlimefunItems.COCOA_ORGANIC_FOOD }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.COCOA_FERTILIZER, OrganicFertilizer.OUTPUT) }); - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - registerRecipe(30, new ItemStack[] { SlimefunItems.SWEET_BERRIES_ORGANIC_FOOD }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.SWEET_BERRIES_FERTILIZER, OrganicFertilizer.OUTPUT) }); - } + registerRecipe(30, new ItemStack[] { SlimefunItems.SWEET_BERRIES_ORGANIC_FOOD }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.SWEET_BERRIES_FERTILIZER, OrganicFertilizer.OUTPUT) }); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodFabricator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodFabricator.java index 03fec44c6..ecc8a3e2a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodFabricator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FoodFabricator.java @@ -3,9 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.misc.OrganicFood; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; @@ -29,10 +27,7 @@ public abstract class FoodFabricator extends AContainer { registerRecipe(12, new ItemStack[] { SlimefunItems.TIN_CAN, new ItemStack(Material.APPLE) }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.APPLE_ORGANIC_FOOD, OrganicFood.OUTPUT) }); registerRecipe(12, new ItemStack[] { SlimefunItems.TIN_CAN, new ItemStack(Material.DRIED_KELP) }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.KELP_ORGANIC_FOOD, OrganicFood.OUTPUT) }); registerRecipe(12, new ItemStack[] { SlimefunItems.TIN_CAN, new ItemStack(Material.COCOA_BEANS) }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.COCOA_ORGANIC_FOOD, OrganicFood.OUTPUT) }); - - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - registerRecipe(12, new ItemStack[] { SlimefunItems.TIN_CAN, new ItemStack(Material.SWEET_BERRIES) }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.SWEET_BERRIES_ORGANIC_FOOD, OrganicFood.OUTPUT) }); - } + registerRecipe(12, new ItemStack[] { SlimefunItems.TIN_CAN, new ItemStack(Material.SWEET_BERRIES) }, new ItemStack[] { new SlimefunItemStack(SlimefunItems.SWEET_BERRIES_ORGANIC_FOOD, OrganicFood.OUTPUT) }); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/EnderTalisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/EnderTalisman.java index ee66d564f..296b423c1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/EnderTalisman.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/EnderTalisman.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.NamespacedKey; import org.bukkit.block.EnderChest; import org.bukkit.inventory.ItemStack; @@ -21,12 +23,13 @@ class EnderTalisman extends Talisman { private static final LockedCategory ENDER_TALISMANS_CATEGORY = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance(), "ender_talismans"), new CustomItem(SlimefunItems.ENDER_TALISMAN, "&7Talismans - &aTier II"), 3, Talisman.TALISMANS_CATEGORY.getKey()); + @ParametersAreNonnullByDefault public EnderTalisman(Talisman parent, SlimefunItemStack item) { super(ENDER_TALISMANS_CATEGORY, item, new ItemStack[] { SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3, null, parent.getItem(), null, SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3 }, parent.isConsumable(), parent.isEventCancelled(), parent.getMessageSuffix(), parent.getChance(), parent.getEffects()); } @Override - public void createEnderTalisman() { + void loadEnderTalisman() { // Let's override that, otherwise we would be creating Ender Talismans // for every Ender Talisman } 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 976941ae9..befa9b567 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 @@ -7,6 +7,7 @@ import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.ChatColor; import org.bukkit.NamespacedKey; @@ -48,19 +49,23 @@ public class Talisman extends SlimefunItem { protected final PotionEffect[] effects; protected final int chance; - public Talisman(SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, String messageSuffix, PotionEffect... effects) { + @ParametersAreNonnullByDefault + public Talisman(SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, @Nullable String messageSuffix, PotionEffect... effects) { this(item, recipe, consumable, cancelEvent, messageSuffix, 100, effects); } - public Talisman(SlimefunItemStack item, ItemStack[] recipe, String messageSuffix, int chance, PotionEffect... effects) { + @ParametersAreNonnullByDefault + public Talisman(SlimefunItemStack item, ItemStack[] recipe, @Nullable String messageSuffix, int chance, PotionEffect... effects) { this(item, recipe, true, true, messageSuffix, chance, effects); } - public Talisman(SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, String messageSuffix, int chance, PotionEffect... effects) { + @ParametersAreNonnullByDefault + public Talisman(SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, @Nullable String messageSuffix, int chance, PotionEffect... effects) { this(TALISMANS_CATEGORY, item, recipe, consumable, cancelEvent, messageSuffix, chance, effects); } - protected Talisman(Category category, SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, String messageSuffix, int chance, PotionEffect... effects) { + @ParametersAreNonnullByDefault + protected Talisman(Category category, SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, @Nullable String messageSuffix, int chance, PotionEffect... effects) { super(category, item, RecipeType.MAGIC_WORKBENCH, recipe, new CustomItem(item, consumable ? 4 : 1)); this.consumable = consumable; @@ -85,14 +90,26 @@ public class Talisman extends SlimefunItem { } } + /** + * This returns whether the {@link Talisman} will be consumed upon use. + * + * @return Whether this {@link Talisman} is consumed on use. + */ public boolean isConsumable() { return consumable; } + /** + * This returns the chance of this {@link Talisman} activating. + * The chance will be between 1 and 100. + * + * @return The chance of this {@link Talisman} activating. + */ public int getChance() { return chance; } + @Nonnull public PotionEffect[] getEffects() { return effects; } @@ -105,6 +122,7 @@ public class Talisman extends SlimefunItem { return cancel; } + @Nullable private SlimefunItemStack getEnderVariant() { return enderTalisman; } @@ -118,10 +136,10 @@ public class Talisman extends SlimefunItem { @Override public void load() { super.load(); - createEnderTalisman(); + loadEnderTalisman(); } - protected void createEnderTalisman() { + void loadEnderTalisman() { EnderTalisman talisman = (EnderTalisman) SlimefunItem.getByItem(getEnderVariant()); Optional research = Research.getResearch(new NamespacedKey(SlimefunPlugin.instance(), "ender_talismans")); @@ -130,7 +148,7 @@ public class Talisman extends SlimefunItem { } } - private static boolean hasMessage(Talisman talisman) { + private static boolean hasMessage(@Nonnull Talisman talisman) { return talisman.getMessageSuffix() != null; } @@ -165,14 +183,14 @@ public class Talisman extends SlimefunItem { ItemStack possibleTalisman = retrieveTalismanFromInventory(p.getInventory(), talisman); if (possibleTalisman != null && Slimefun.hasUnlocked(p, talisman, true)) { - activateTalisman(e, p, p.getInventory(), talisman); + activateTalisman(e, p, p.getInventory(), talisman, possibleTalisman); return possibleTalisman; } possibleTalisman = retrieveTalismanFromInventory(p.getEnderChest(), talisman); if (possibleTalisman != null && Slimefun.hasUnlocked(p, talisman, true)) { - activateTalisman(e, p, p.getEnderChest(), talisman); + activateTalisman(e, p, p.getEnderChest(), talisman, possibleTalisman); return possibleTalisman; } @@ -182,6 +200,7 @@ public class Talisman extends SlimefunItem { @Nullable private static ItemStack retrieveTalismanFromInventory(@Nonnull Inventory inv, @Nonnull Talisman talisman) { ItemStack[] contents = inv.getContents(); + for (int i = 0; i < contents.length; i++) { ItemStack item = contents[i]; @@ -193,50 +212,47 @@ public class Talisman extends SlimefunItem { return null; } - private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman) { - consumeItem(inv, talisman); + @ParametersAreNonnullByDefault + private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismanItem) { + consumeItem(inv, talisman, talismanItem); applyTalismanEffects(p, talisman); cancelEvent(e, talisman); sendMessage(p, talisman); } + @ParametersAreNonnullByDefault private static void applyTalismanEffects(Player p, Talisman talisman) { for (PotionEffect effect : talisman.getEffects()) { p.addPotionEffect(effect); } } + @ParametersAreNonnullByDefault private static void cancelEvent(Event e, Talisman talisman) { if (e instanceof Cancellable && talisman.isEventCancelled()) { ((Cancellable) e).setCancelled(true); } } + @ParametersAreNonnullByDefault private static void sendMessage(Player p, Talisman talisman) { if (hasMessage(talisman)) { SlimefunPlugin.getLocalization().sendMessage(p, "messages.talisman." + talisman.getMessageSuffix(), true); } } - private static void consumeItem(Inventory inv, Talisman talisman) { + @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, talisman.getItem(), true, false)) { - ItemUtils.consumeItem(item, false); - return; - } - } + ItemUtils.consumeItem(talismanItem, false); } } - private static Player getPlayerByEventType(Event e) { + @Nullable + private static Player getPlayerByEventType(@Nonnull Event e) { if (e instanceof PlayerDeathEvent) { return ((PlayerDeathEvent) e).getEntity(); - } - else if (e instanceof EntityDeathEvent) { + } else if (e instanceof EntityDeathEvent) { return ((EntityDeathEvent) e).getEntity().getKiller(); } else if (e instanceof BlockBreakEvent) { return ((BlockBreakEvent) e).getPlayer(); @@ -253,7 +269,7 @@ public class Talisman extends SlimefunItem { return null; } - private static boolean pass(Player p, SlimefunItem talisman) { + private static boolean pass(@Nonnull Player p, @Nonnull SlimefunItem talisman) { for (PotionEffect effect : ((Talisman) talisman).getEffects()) { if (effect != null && p.hasPotionEffect(effect.getType())) { return false; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/StrangeNetherGoo.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/StrangeNetherGoo.java index a1b0ab966..f5f79532f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/StrangeNetherGoo.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/StrangeNetherGoo.java @@ -1,14 +1,25 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.misc; +import javax.annotation.Nonnull; +import java.util.Optional; + +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.GameMode; import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.entity.Piglin; +import org.bukkit.entity.Sheep; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; -import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.core.attributes.PiglinBarterDrop; +import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler; +import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.VillagerRune; import me.mrCookieSlime.Slimefun.Lists.RecipeType; @@ -16,9 +27,6 @@ import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; -import javax.annotation.Nonnull; -import java.util.Optional; - /** * This {@link SlimefunItem} can only be obtained via bartering with a {@link Piglin}, its * only current uses is the recipe for crafting the {@link VillagerRune}. @@ -37,6 +45,7 @@ public class StrangeNetherGoo extends SimpleSlimefunItem impleme super(category, item, recipeType, recipe); addItemSetting(chance); + addItemHandler(onRightClickEntity()); } @Override @@ -56,4 +65,27 @@ public class StrangeNetherGoo extends SimpleSlimefunItem impleme }; } + private EntityInteractHandler onRightClickEntity() { + return (e, item, hand) -> { + if (e.getRightClicked() instanceof Sheep) { + Sheep s = (Sheep) e.getRightClicked(); + + if (s.getCustomName() != null) { + e.setCancelled(true); + return; + } + + if (e.getPlayer().getGameMode() != GameMode.CREATIVE) { + ItemUtils.consumeItem(item, false); + } + + // Give Sheep color, name and effect + s.addPotionEffect(new PotionEffect(PotionEffectType.POISON, 60, 2)); + s.setColor(DyeColor.PURPLE); + s.setCustomName(ChatColor.DARK_PURPLE + "Tainted Sheep"); + e.setCancelled(true); + + } + }; + } } 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 1cb865b36..608a0e2f5 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 @@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks; import java.util.List; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; @@ -14,7 +16,6 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; -import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.papermc.lib.PaperLib; @@ -23,7 +24,7 @@ import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; -public class ArmorForge extends MultiBlockMachine { +public class ArmorForge extends BackpackCrafter { public ArmorForge(Category category, SlimefunItemStack item) { super(category, item, new ItemStack[] { null, null, null, null, new ItemStack(Material.ANVIL), null, null, new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), null }, BlockFace.SELF); @@ -31,8 +32,8 @@ public class ArmorForge extends MultiBlockMachine { @Override public void onInteract(Player p, Block b) { - Block dispBlock = b.getRelative(BlockFace.DOWN); - BlockState state = PaperLib.getBlockState(dispBlock, false).getState(); + Block dispenser = b.getRelative(BlockFace.DOWN); + BlockState state = PaperLib.getBlockState(dispenser, false).getState(); if (state instanceof Dispenser) { Dispenser disp = (Dispenser) state; @@ -44,13 +45,7 @@ public class ArmorForge extends MultiBlockMachine { ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone(); if (Slimefun.hasUnlocked(p, output, true)) { - Inventory outputInv = findOutputInventory(output, dispBlock, inv); - - if (outputInv != null) { - craft(p, output, inv, outputInv); - } else { - SlimefunPlugin.getLocalization().sendMessage(p, "machines.full-inventory", true); - } + craft(p, output, inv, dispenser); } return; @@ -71,26 +66,35 @@ public class ArmorForge extends MultiBlockMachine { return true; } - private void craft(Player p, ItemStack output, Inventory inv, Inventory outputInv) { - for (int j = 0; j < 9; j++) { - ItemStack item = inv.getContents()[j]; + @ParametersAreNonnullByDefault + private void craft(Player p, ItemStack output, Inventory inv, Block dispenser) { + Inventory fakeInv = createVirtualInventory(inv); + Inventory outputInv = findOutputInventory(output, dispenser, inv, fakeInv); - if (item != null && item.getType() != Material.AIR) { - ItemUtils.consumeItem(item, true); - } - } + if (outputInv != null) { + for (int j = 0; j < 9; j++) { + ItemStack item = inv.getContents()[j]; - for (int j = 0; j < 4; j++) { - int current = j; - - SlimefunPlugin.runSync(() -> { - if (current < 3) { - p.getWorld().playSound(p.getLocation(), Sound.BLOCK_ANVIL_USE, 1F, 2F); - } else { - p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F); - outputInv.addItem(output); + if (item != null && item.getType() != Material.AIR) { + ItemUtils.consumeItem(item, true); } - }, j * 20L); + } + + for (int j = 0; j < 4; j++) { + int current = j; + + SlimefunPlugin.runSync(() -> { + if (current < 3) { + p.getWorld().playSound(p.getLocation(), Sound.BLOCK_ANVIL_USE, 1F, 2F); + } else { + p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F); + outputInv.addItem(output); + } + }, j * 20L); + } + + } else { + SlimefunPlugin.getLocalization().sendMessage(p, "machines.full-inventory", true); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/BackpackCrafter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/BackpackCrafter.java index 1a7615221..baf52187a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/BackpackCrafter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/BackpackCrafter.java @@ -32,6 +32,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; * * @see EnhancedCraftingTable * @see MagicWorkbench + * @see ArmorForge * */ abstract class BackpackCrafter extends MultiBlockMachine { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/PressureChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/PressureChamber.java index 4395387c8..e3173af17 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/PressureChamber.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/PressureChamber.java @@ -15,7 +15,6 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; @@ -27,8 +26,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; public class PressureChamber extends MultiBlockMachine { public PressureChamber(Category category, SlimefunItemStack item) { - super(category, item, new ItemStack[] { SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14) ? new ItemStack(Material.SMOOTH_STONE_SLAB) : new ItemStack(Material.STONE_SLAB), new CustomItem(Material.DISPENSER, "Dispenser (Facing down)"), SlimefunPlugin.getMinecraftVersion() - .isAtLeast(MinecraftVersion.MINECRAFT_1_14) ? new ItemStack(Material.SMOOTH_STONE_SLAB) : new ItemStack(Material.STONE_SLAB), new ItemStack(Material.PISTON), new ItemStack(Material.GLASS), new ItemStack(Material.PISTON), new ItemStack(Material.PISTON), new ItemStack(Material.CAULDRON), new ItemStack(Material.PISTON) }, BlockFace.UP); + super(category, item, new ItemStack[] { new ItemStack(Material.SMOOTH_STONE_SLAB), new CustomItem(Material.DISPENSER, "Dispenser (Facing down)"), new ItemStack(Material.SMOOTH_STONE_SLAB), new ItemStack(Material.PISTON), new ItemStack(Material.GLASS), new ItemStack(Material.PISTON), new ItemStack(Material.PISTON), new ItemStack(Material.CAULDRON), new ItemStack(Material.PISTON) }, BlockFace.UP); } @Override 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 c0dc2775d..157b26954 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 @@ -52,7 +52,7 @@ public class IndustrialMiner extends MultiBlockMachine { private final ItemSetting canMineAncientDebris = new ItemSetting<>("can-mine-ancient-debris", false); public IndustrialMiner(Category category, SlimefunItemStack item, Material baseMaterial, boolean silkTouch, int range) { - super(category, item, new ItemStack[] { null, null, null, new CustomItem(Material.PISTON, "Piston (facing up)"), new ItemStack(Material.CHEST), new CustomItem(Material.PISTON, "Piston (facing up)"), new ItemStack(baseMaterial), new ItemStack(SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14) ? Material.BLAST_FURNACE : Material.FURNACE), new ItemStack(baseMaterial) }, BlockFace.UP); + super(category, item, new ItemStack[] { null, null, null, new CustomItem(Material.PISTON, "Piston (facing up)"), new ItemStack(Material.CHEST), new CustomItem(Material.PISTON, "Piston (facing up)"), new ItemStack(baseMaterial), new ItemStack(Material.BLAST_FURNACE), new ItemStack(baseMaterial) }, BlockFace.UP); this.range = range; this.silkTouch = silkTouch; 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 d452896f3..33d3f9cc5 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 @@ -55,7 +55,7 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla Player p = e.getPlayer(); Block b = e.getBlock(); - b.getWorld().createExplosion(b.getLocation(), 0.0F); + b.getWorld().createExplosion(b.getLocation(), 0); b.getWorld().playSound(b.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 0.2F, 1F); List blocks = findBlocks(b); @@ -122,8 +122,9 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla private void breakBlock(Player p, ItemStack item, Block b, int fortune, List drops) { SlimefunPlugin.getProtectionManager().logAction(p, b, ProtectableAction.BREAK_BLOCK); + Material material = b.getType(); - b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType()); + b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, material); SlimefunItem sfItem = BlockStorage.check(b); if (sfItem != null && !sfItem.useVanillaBlockBreaking()) { @@ -132,10 +133,10 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla if (handler != null && !handler.onBreak(p, b, sfItem, UnregisterReason.PLAYER_BREAK)) { drops.add(BlockStorage.retrieve(b)); } - } else if (b.getType() == Material.PLAYER_HEAD || b.getType() == Material.SHULKER_BOX || b.getType().name().endsWith("_SHULKER_BOX")) { + } else if (material == Material.PLAYER_HEAD || SlimefunTag.SHULKER_BOXES.isTagged(material)) { b.breakNaturally(item); } else { - boolean applyFortune = b.getType().name().endsWith("_ORE") && b.getType() != Material.IRON_ORE && b.getType() != Material.GOLD_ORE; + boolean applyFortune = SlimefunTag.FORTUNE_COMPATIBLE_ORES.isTagged(material); for (ItemStack drop : b.getDrops(getItem())) { // For some reason this check is necessary with Paper 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 023a8df4c..815cb6c6e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java @@ -39,6 +39,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; * and {@link BlockBreakEvent}. * * @author TheBusyBiscuit + * @author Linox * * @see BlockPlaceHandler * @see BlockBreakHandler @@ -51,17 +52,22 @@ public class BlockListener implements Listener { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent e) { + @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... if (BlockStorage.hasBlockInfo(e.getBlock())) { e.setCancelled(true); - return; } + } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent e) { ItemStack item = e.getItemInHand(); - SlimefunItem sfItem = SlimefunItem.getByItem(item); - if (sfItem != null && Slimefun.isEnabled(e.getPlayer(), sfItem, true) && !(sfItem instanceof NotPlaceable)) { + + if (sfItem != null && !(sfItem instanceof NotPlaceable) && Slimefun.isEnabled(e.getPlayer(), sfItem, true)) { if (!Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) { e.setCancelled(true); } else { @@ -75,8 +81,13 @@ public class BlockListener implements Listener { } } - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent e) { + if (SlimefunPlugin.getThirdPartySupportService().isEventFaked(e)) { + // This is a "fake" event, we can ignore it. + return; + } + checkForSensitiveBlockAbove(e.getPlayer(), e.getBlock()); ItemStack item = e.getPlayer().getInventory().getItemInMainHand(); @@ -94,6 +105,7 @@ public class BlockListener implements Listener { dropItems(e, drops); } + @ParametersAreNonnullByDefault private void callToolHandler(BlockBreakEvent e, ItemStack item, int fortune, List drops) { SlimefunItem tool = SlimefunItem.getByItem(item); @@ -106,6 +118,7 @@ public class BlockListener implements Listener { } } + @ParametersAreNonnullByDefault private void callBlockHandler(BlockBreakEvent e, ItemStack item, int fortune, List drops) { SlimefunItem sfItem = BlockStorage.check(e.getBlock()); @@ -183,16 +196,19 @@ public class BlockListener implements Listener { } private int getBonusDropsWithFortune(@Nullable ItemStack item, @Nonnull Block b) { - int fortune = 1; + int amount = 1; - if (item != null && item.getEnchantments().containsKey(Enchantment.LOOT_BONUS_BLOCKS) && !item.getEnchantments().containsKey(Enchantment.SILK_TOUCH)) { - Random random = ThreadLocalRandom.current(); + if (item != null) { int fortuneLevel = item.getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS); - fortune = Math.max(1, random.nextInt(fortuneLevel + 2) - 1); - fortune = (b.getType() == Material.LAPIS_ORE ? 4 + random.nextInt(5) : 1) * (fortune + 1); + if (fortuneLevel > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) { + Random random = ThreadLocalRandom.current(); + + amount = Math.max(1, random.nextInt(fortuneLevel + 2) - 1); + amount = (b.getType() == Material.LAPIS_ORE ? 4 + random.nextInt(5) : 1) * (amount + 1); + } } - return fortune; + return amount; } } 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 777b7c141..9d24ff2f5 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 @@ -39,15 +39,19 @@ public class SlimefunBootsListener implements Listener { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onDamage(EntityDamageEvent e) { - if (e.getEntity() instanceof Player) { - if (e.getCause() == DamageCause.FALL) { - onFallDamage(e); - } else if (e instanceof EntityDamageByEntityEvent) { - EntityDamageByEntityEvent event = (EntityDamageByEntityEvent) e; + if (e.getEntity() instanceof Player && e.getCause() == DamageCause.FALL) { + onFallDamage(e); + } + } - if (event.getDamager() instanceof EnderPearl) { - onEnderPearlDamage(e); - } + @EventHandler + public void onEnderPearlDamage(EntityDamageByEntityEvent e) { + if (e.getDamager() instanceof EnderPearl && e.getEntity() instanceof Player) { + Player p = (Player) e.getEntity(); + SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots()); + + if (boots != null && boots.getId().equals("ENDER_BOOTS") && Slimefun.hasUnlocked(p, boots, true)) { + e.setCancelled(true); } } } @@ -71,15 +75,6 @@ public class SlimefunBootsListener implements Listener { } } - private void onEnderPearlDamage(@Nonnull EntityDamageEvent e) { - Player p = (Player) e.getEntity(); - SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots()); - - if (boots != null && boots.getId().equals("ENDER_BOOTS") && Slimefun.hasUnlocked(p, boots, true)) { - e.setCancelled(true); - } - } - @EventHandler public void onTrample(PlayerInteractEvent e) { if (e.getAction() == Action.PHYSICAL) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VanillaMachinesListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VanillaMachinesListener.java deleted file mode 100644 index e4e5b49ee..000000000 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VanillaMachinesListener.java +++ /dev/null @@ -1,158 +0,0 @@ -package io.github.thebusybiscuit.slimefun4.implementation.listeners; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.bukkit.block.BrewingStand; -import org.bukkit.entity.Player; -import org.bukkit.event.Event.Result; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.CraftItemEvent; -import org.bukkit.event.inventory.InventoryAction; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.inventory.PrepareItemCraftEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; - -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; -import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; -import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; - -/** - * This {@link Listener} prevents any {@link SlimefunItem} from being used in a vanilla - * machine like the workbench, grindstone, brewing stand or an anvil. - * - * @author TheBusyBiscuit - * @author NathanAdhitya - * @author Steve - * @author VoidAngel - * - */ -public class VanillaMachinesListener implements Listener { - - public VanillaMachinesListener(@Nonnull SlimefunPlugin plugin) { - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @EventHandler(ignoreCancelled = true) - public void onGrindstone(InventoryClickEvent e) { - // The Grindstone was only ever added in MC 1.14 - if (!SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - return; - } - - if (e.getRawSlot() == 2 && e.getWhoClicked() instanceof Player && e.getInventory().getType() == InventoryType.GRINDSTONE) { - ItemStack item1 = e.getInventory().getContents()[0]; - ItemStack item2 = e.getInventory().getContents()[1]; - - if (checkForUnallowedItems(item1, item2)) { - e.setResult(Result.DENY); - } - } - - } - - @EventHandler - public void onCraft(CraftItemEvent e) { - for (ItemStack item : e.getInventory().getContents()) { - SlimefunItem sfItem = SlimefunItem.getByItem(item); - - if (sfItem != null && !sfItem.isUseableInWorkbench()) { - e.setResult(Result.DENY); - SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "workbench.not-enhanced", true); - break; - } - } - } - - @EventHandler - public void onPrepareCraft(PrepareItemCraftEvent e) { - if (e.getInventory().getResult() != null) { - for (ItemStack item : e.getInventory().getContents()) { - SlimefunItem sfItem = SlimefunItem.getByItem(item); - - if (sfItem != null && !sfItem.isUseableInWorkbench()) { - e.getInventory().setResult(null); - break; - } - } - } - } - - @EventHandler(ignoreCancelled = true) - public void onAnvil(InventoryClickEvent e) { - if (e.getRawSlot() == 2 && e.getInventory().getType() == InventoryType.ANVIL && e.getWhoClicked() instanceof Player) { - ItemStack item1 = e.getInventory().getContents()[0]; - ItemStack item2 = e.getInventory().getContents()[1]; - - if (checkForUnallowedItems(item1, item2)) { - e.setResult(Result.DENY); - SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "anvil.not-working", true); - } - } - } - - @EventHandler(ignoreCancelled = true) - public void onCartographyTable(InventoryClickEvent e) { - // The Cartography Table was only ever added in MC 1.14 - if (!SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - return; - } - - if (e.getRawSlot() == 2 && e.getInventory().getType() == InventoryType.CARTOGRAPHY && e.getWhoClicked() instanceof Player) { - ItemStack item1 = e.getInventory().getContents()[0]; - ItemStack item2 = e.getInventory().getContents()[1]; - - if (checkForUnallowedItems(item1, item2)) { - e.setResult(Result.DENY); - SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "cartography_table.not-working", true); - } - } - } - - @EventHandler(ignoreCancelled = true) - public void onPreBrew(InventoryClickEvent e) { - Inventory clickedInventory = e.getClickedInventory(); - Inventory topInventory = e.getView().getTopInventory(); - - if (clickedInventory != null && topInventory.getType() == InventoryType.BREWING && topInventory.getHolder() instanceof BrewingStand) { - if (e.getAction() == InventoryAction.HOTBAR_SWAP) { - e.setCancelled(true); - return; - } - - if (clickedInventory.getType() == InventoryType.BREWING) { - e.setCancelled(isUnallowed(SlimefunItem.getByItem(e.getCursor()))); - } else { - e.setCancelled(isUnallowed(SlimefunItem.getByItem(e.getCurrentItem()))); - } - - if (e.getResult() == Result.DENY) { - SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "brewing_stand.not-working", true); - } - } - } - - private boolean checkForUnallowedItems(@Nullable ItemStack item1, @Nullable ItemStack item2) { - if (SlimefunGuide.isGuideItem(item1) || SlimefunGuide.isGuideItem(item2)) { - return true; - } else { - SlimefunItem sfItem1 = SlimefunItem.getByItem(item1); - SlimefunItem sfItem2 = SlimefunItem.getByItem(item2); - - if (isUnallowed(sfItem1) || isUnallowed(sfItem2)) { - return true; - } - } - - return false; - } - - private boolean isUnallowed(@Nullable SlimefunItem item) { - return item != null && !(item instanceof VanillaItem) && !item.isDisabled(); - } -} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/AnvilListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/AnvilListener.java new file mode 100644 index 000000000..4df3a82eb --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/AnvilListener.java @@ -0,0 +1,43 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nonnull; + +import org.bukkit.block.BrewingStand; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This {@link Listener} prevents any {@link SlimefunItem} from being used in a + * {@link BrewingStand}. + * + * @author TheBusyBiscuit + * + */ +public class AnvilListener implements SlimefunCraftingListener { + + public AnvilListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(ignoreCancelled = true) + public void onAnvil(InventoryClickEvent e) { + if (e.getRawSlot() == 2 && e.getInventory().getType() == InventoryType.ANVIL && e.getWhoClicked() instanceof Player) { + ItemStack item1 = e.getInventory().getContents()[0]; + ItemStack item2 = e.getInventory().getContents()[1]; + + if (hasUnallowedItems(item1, item2)) { + e.setResult(Result.DENY); + SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "anvil.not-working", true); + } + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/BrewingStandListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/BrewingStandListener.java new file mode 100644 index 000000000..60a4594af --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/BrewingStandListener.java @@ -0,0 +1,55 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nonnull; + +import org.bukkit.block.BrewingStand; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; + +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This {@link Listener} prevents any {@link SlimefunItem} from being used in a + * {@link BrewingStand}. + * + * @author VoidAngel + * @author SoSeDiK + * + */ +public class BrewingStandListener implements SlimefunCraftingListener { + + public BrewingStandListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(ignoreCancelled = true) + public void onPreBrew(InventoryClickEvent e) { + Inventory clickedInventory = e.getClickedInventory(); + Inventory topInventory = e.getView().getTopInventory(); + + if (clickedInventory != null && topInventory.getType() == InventoryType.BREWING && topInventory.getHolder() instanceof BrewingStand) { + if (e.getAction() == InventoryAction.HOTBAR_SWAP) { + e.setCancelled(true); + return; + } + + if (clickedInventory.getType() == InventoryType.BREWING) { + e.setCancelled(isUnallowed(SlimefunItem.getByItem(e.getCursor()))); + } else { + e.setCancelled(isUnallowed(SlimefunItem.getByItem(e.getCurrentItem()))); + } + + if (e.getResult() == Result.DENY) { + SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "brewing_stand.not-working", true); + } + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CartographyTableListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CartographyTableListener.java new file mode 100644 index 000000000..9586fdeb2 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CartographyTableListener.java @@ -0,0 +1,42 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This {@link Listener} prevents any {@link SlimefunItem} from being used in a + * cartography table. + * + * @author poma123 + * + */ +public class CartographyTableListener implements SlimefunCraftingListener { + + public CartographyTableListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(ignoreCancelled = true) + public void onCartographyTable(InventoryClickEvent e) { + if (e.getRawSlot() == 2 && e.getInventory().getType() == InventoryType.CARTOGRAPHY && e.getWhoClicked() instanceof Player) { + ItemStack item1 = e.getInventory().getContents()[0]; + ItemStack item2 = e.getInventory().getContents()[1]; + + if (hasUnallowedItems(item1, item2)) { + e.setResult(Result.DENY); + SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "cartography_table.not-working", true); + } + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CauldronListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CauldronListener.java new file mode 100644 index 000000000..8fd51fc8a --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CauldronListener.java @@ -0,0 +1,52 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nonnull; + +import org.bukkit.Material; +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.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This {@link Listener} prevents any {@link SlimefunItem} from being used in a + * Cauldron. + * This is mainly used to prevent the discoloring of leather armor. + * + * @author TheBusyBiscuit + * + */ +public class CauldronListener implements SlimefunCraftingListener { + + public CauldronListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onCauldronUse(PlayerInteractEvent e) { + if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { + Block block = e.getClickedBlock(); + + if (block.getType() == Material.CAULDRON) { + ItemStack item = e.getItem(); + + if (item != null && SlimefunTag.LEATHER_ARMOR.isTagged(item.getType())) { + SlimefunItem sfItem = SlimefunItem.getByItem(item); + + if (isUnallowed(sfItem)) { + e.setCancelled(true); + SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "cauldron.no-discoloring"); + } + } + } + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CraftingTableListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CraftingTableListener.java new file mode 100644 index 000000000..e18b64d11 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/CraftingTableListener.java @@ -0,0 +1,56 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.CraftItemEvent; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This {@link Listener} prevents any {@link SlimefunItem} from being used in a + * crafting table. + * + * @author TheBusyBiscuit + * + */ +public class CraftingTableListener implements SlimefunCraftingListener { + + public CraftingTableListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onCraft(CraftItemEvent e) { + for (ItemStack item : e.getInventory().getContents()) { + SlimefunItem sfItem = SlimefunItem.getByItem(item); + + if (sfItem != null && !sfItem.isUseableInWorkbench()) { + e.setResult(Result.DENY); + SlimefunPlugin.getLocalization().sendMessage((Player) e.getWhoClicked(), "workbench.not-enhanced", true); + break; + } + } + } + + @EventHandler + public void onPrepareCraft(PrepareItemCraftEvent e) { + if (e.getInventory().getResult() != null) { + for (ItemStack item : e.getInventory().getContents()) { + SlimefunItem sfItem = SlimefunItem.getByItem(item); + + if (sfItem != null && !sfItem.isUseableInWorkbench()) { + e.getInventory().setResult(null); + break; + } + } + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/GrindstoneListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/GrindstoneListener.java new file mode 100644 index 000000000..36db7e6eb --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/GrindstoneListener.java @@ -0,0 +1,42 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +/** + * This {@link Listener} prevents any {@link SlimefunItem} from being used in a + * cartography table. + * + * @author NathanAdhitya + * + */ +public class GrindstoneListener implements SlimefunCraftingListener { + + public GrindstoneListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler(ignoreCancelled = true) + public void onGrindstone(InventoryClickEvent e) { + if (e.getRawSlot() == 2 && e.getWhoClicked() instanceof Player && e.getInventory().getType() == InventoryType.GRINDSTONE) { + ItemStack item1 = e.getInventory().getContents()[0]; + ItemStack item2 = e.getInventory().getContents()[1]; + + if (hasUnallowedItems(item1, item2)) { + e.setResult(Result.DENY); + } + } + + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/SlimefunCraftingListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/SlimefunCraftingListener.java new file mode 100644 index 000000000..6fdba5ab0 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/SlimefunCraftingListener.java @@ -0,0 +1,42 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; + +import javax.annotation.Nullable; + +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +interface SlimefunCraftingListener extends Listener { + + default boolean hasUnallowedItems(@Nullable ItemStack item1, @Nullable ItemStack item2) { + if (SlimefunGuide.isGuideItem(item1) || SlimefunGuide.isGuideItem(item2)) { + return true; + } else { + SlimefunItem sfItem1 = SlimefunItem.getByItem(item1); + SlimefunItem sfItem2 = SlimefunItem.getByItem(item2); + + if (isUnallowed(sfItem1) || isUnallowed(sfItem2)) { + return true; + } + } + + return false; + } + + default boolean isUnallowed(@Nullable ItemStack item) { + if (item == null) { + return false; + } + + SlimefunItem sfItem = SlimefunItem.getByItem(item); + return !(sfItem instanceof VanillaItem) && !sfItem.isDisabled(); + } + + default boolean isUnallowed(@Nullable SlimefunItem item) { + return item != null && !(item instanceof VanillaItem) && !item.isDisabled(); + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/package-info.java new file mode 100644 index 000000000..8c8f08ecc --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/package-info.java @@ -0,0 +1,5 @@ +/** + * This package holds every {@link org.bukkit.event.Listener} which is responsible for preventing that a + * {@link me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem} is used in an unallowed crafting operation + */ +package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting; \ No newline at end of file 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 723d8a548..e65701e5c 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 @@ -207,27 +207,8 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; * */ public final class SlimefunItemSetup { - - private static final Material RED_DYE; - private static final Material YELLOW_DYE; - private static final Material BLACK_DYE; - private static final Material GREEN_DYE; - + private static boolean registeredItems = false; - - static { - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - RED_DYE = Material.RED_DYE; - YELLOW_DYE = Material.YELLOW_DYE; - BLACK_DYE = Material.BLACK_DYE; - GREEN_DYE = Material.GREEN_DYE; - } else { - RED_DYE = Material.valueOf("ROSE_RED"); - YELLOW_DYE = Material.valueOf("DANDELION_YELLOW"); - BLACK_DYE = Material.valueOf("INK_SAC"); - GREEN_DYE = Material.valueOf("CACTUS_GREEN"); - } - } private SlimefunItemSetup() {} @@ -238,7 +219,8 @@ public final class SlimefunItemSetup { registeredItems = true; DefaultCategories categories = new DefaultCategories(); - + + // @formatter:off (We will need to refactor this one day) new SlimefunItem(categories.weapons, SlimefunItems.GRANDMAS_WALKING_STICK, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null}) .register(plugin); @@ -797,21 +779,19 @@ public final class SlimefunItemSetup { new ItemStack[] {null, null, SlimefunItems.LAVA_CRYSTAL, null, SlimefunItems.STAFF_ELEMENTAL, null, SlimefunItems.STAFF_ELEMENTAL, null, null}) .register(plugin); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - new StormStaff(categories.magicalGadgets, SlimefunItems.STAFF_STORM, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {SlimefunItems.LIGHTNING_RUNE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.LIGHTNING_RUNE, SlimefunItems.STAFF_WATER, SlimefunItems.MAGIC_SUGAR, SlimefunItems.STAFF_WIND, SlimefunItems.LIGHTNING_RUNE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.LIGHTNING_RUNE}) - .register(plugin); - - ItemStack weaknessPotion = new ItemStack(Material.POTION); - PotionMeta meta = (PotionMeta) weaknessPotion.getItemMeta(); - meta.setBasePotionData(new PotionData(PotionType.WEAKNESS, false, false)); - weaknessPotion.setItemMeta(meta); - - new MagicalZombiePills(categories.magicalGadgets, SlimefunItems.MAGICAL_ZOMBIE_PILLS, RecipeType.MAGIC_WORKBENCH, - new ItemStack[] {new ItemStack(Material.GOLD_INGOT), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.GOLD_INGOT), new ItemStack(Material.APPLE), weaknessPotion, new ItemStack(Material.APPLE), new ItemStack(Material.GOLD_INGOT), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.GOLD_INGOT)}, - new SlimefunItemStack(SlimefunItems.MAGICAL_ZOMBIE_PILLS, 2)) - .register(plugin); - } + new StormStaff(categories.magicalGadgets, SlimefunItems.STAFF_STORM, RecipeType.ANCIENT_ALTAR, + new ItemStack[] {SlimefunItems.LIGHTNING_RUNE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.LIGHTNING_RUNE, SlimefunItems.STAFF_WATER, SlimefunItems.MAGIC_SUGAR, SlimefunItems.STAFF_WIND, SlimefunItems.LIGHTNING_RUNE, SlimefunItems.ENDER_LUMP_3, SlimefunItems.LIGHTNING_RUNE}) + .register(plugin); + + ItemStack weaknessPotion = new ItemStack(Material.POTION); + PotionMeta meta = (PotionMeta) weaknessPotion.getItemMeta(); + meta.setBasePotionData(new PotionData(PotionType.WEAKNESS, false, false)); + weaknessPotion.setItemMeta(meta); + + new MagicalZombiePills(categories.magicalGadgets, SlimefunItems.MAGICAL_ZOMBIE_PILLS, RecipeType.MAGIC_WORKBENCH, + new ItemStack[] {new ItemStack(Material.GOLD_INGOT), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.GOLD_INGOT), new ItemStack(Material.APPLE), weaknessPotion, new ItemStack(Material.APPLE), new ItemStack(Material.GOLD_INGOT), SlimefunItems.MAGIC_LUMP_2, new ItemStack(Material.GOLD_INGOT)}, + new SlimefunItemStack(SlimefunItems.MAGICAL_ZOMBIE_PILLS, 2)) + .register(plugin); new SmeltersPickaxe(categories.tools, SlimefunItems.SMELTERS_PICKAXE, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.LAVA_CRYSTAL, SlimefunItems.LAVA_CRYSTAL, SlimefunItems.LAVA_CRYSTAL, null, SlimefunItems.FERROSILICON, null, null, SlimefunItems.FERROSILICON, null}) @@ -1036,9 +1016,7 @@ public final class SlimefunItemSetup { new ItemStack[] {SlimefunItems.HARDENED_METAL_INGOT, SlimefunItems.HARDENED_METAL_INGOT, SlimefunItems.HARDENED_METAL_INGOT, null, SlimefunItems.FERROSILICON, null, null, SlimefunItems.FERROSILICON, null}) .register(plugin); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - new TableSaw(categories.basicMachines, SlimefunItems.TABLE_SAW).register(plugin); - } + new TableSaw(categories.basicMachines, SlimefunItems.TABLE_SAW).register(plugin); new SlimefunArmorPiece(categories.magicalArmor, SlimefunItems.SLIME_HELMET_STEEL, RecipeType.ARMOR_FORGE, new ItemStack[] {new ItemStack(Material.SLIME_BALL), SlimefunItems.STEEL_PLATE, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), null, new ItemStack(Material.SLIME_BALL), null, null, null}, null) @@ -1125,7 +1103,7 @@ public final class SlimefunItemSetup { new RestoredBackpack(categories.usefulItems).register(plugin); - new SlimefunItem(categories.technicalComponents, SlimefunItems.MAGNET, RecipeType.SMELTERY, + new UnplaceableBlock(categories.technicalComponents, SlimefunItems.MAGNET, RecipeType.SMELTERY, new ItemStack[] {SlimefunItems.NICKEL_INGOT, SlimefunItems.ALUMINUM_DUST, SlimefunItems.IRON_DUST, SlimefunItems.COBALT_INGOT, null, null, null, null, null}) .register(plugin); @@ -1268,11 +1246,9 @@ public final class SlimefunItemSetup { new ItemStack[] {new ItemStack(Material.PUMPKIN), null, null, null, null, null, null, null, null}) .register(plugin); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - new Juice(categories.food, SlimefunItems.SWEET_BERRY_JUICE, RecipeType.JUICER, - new ItemStack[] {new ItemStack(Material.SWEET_BERRIES), null, null, null, null, null, null, null, null}) - .register(plugin); - } + new Juice(categories.food, SlimefunItems.SWEET_BERRY_JUICE, RecipeType.JUICER, + new ItemStack[] {new ItemStack(Material.SWEET_BERRIES), null, null, null, null, null, null, null, null}) + .register(plugin); new Juice(categories.food, SlimefunItems.GOLDEN_APPLE_JUICE, RecipeType.JUICER, new ItemStack[] {new ItemStack(Material.GOLDEN_APPLE), null, null, null, null, null, null, null, null}) @@ -1338,15 +1314,15 @@ public final class SlimefunItemSetup { new ItemStack[] {SlimefunItems.CARBONADO, SlimefunItems.BASIC_CIRCUIT_BOARD, SlimefunItems.CARBONADO, SlimefunItems.HEATING_COIL, SlimefunItems.REINFORCED_FURNACE, SlimefunItems.HEATING_COIL, SlimefunItems.CARBONADO, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.CARBONADO}) .register(plugin); - new SlimefunItem(categories.technicalComponents, SlimefunItems.ELECTRO_MAGNET, RecipeType.ENHANCED_CRAFTING_TABLE, + new UnplaceableBlock(categories.technicalComponents, SlimefunItems.ELECTRO_MAGNET, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.NICKEL_INGOT, SlimefunItems.MAGNET, SlimefunItems.COBALT_INGOT, null, SlimefunItems.BATTERY, null, null, null, null}) .register(plugin); - new SlimefunItem(categories.technicalComponents, SlimefunItems.ELECTRIC_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE, + new UnplaceableBlock(categories.technicalComponents, SlimefunItems.ELECTRIC_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, null, SlimefunItems.ELECTRO_MAGNET, null, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE}) .register(plugin); - new SlimefunItem(categories.technicalComponents, SlimefunItems.HEATING_COIL, RecipeType.ENHANCED_CRAFTING_TABLE, + new UnplaceableBlock(categories.technicalComponents, SlimefunItems.HEATING_COIL, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE}) .register(plugin); @@ -1490,7 +1466,7 @@ public final class SlimefunItemSetup { new SlimefunItemStack(SlimefunItems.HARDENED_GLASS, 16)) .register(plugin); - new SlimefunItem(categories.technicalComponents, SlimefunItems.COOLING_UNIT, RecipeType.ENHANCED_CRAFTING_TABLE, + new UnplaceableBlock(categories.technicalComponents, SlimefunItems.COOLING_UNIT, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {new ItemStack(Material.ICE), new ItemStack(Material.ICE), new ItemStack(Material.ICE), SlimefunItems.ALUMINUM_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_INGOT, new ItemStack(Material.ICE), new ItemStack(Material.ICE), new ItemStack(Material.ICE)}) .register(plugin); @@ -1999,11 +1975,9 @@ public final class SlimefunItemSetup { }.register(plugin); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - new AutoDrier(categories.electricity, SlimefunItems.AUTO_DRIER, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[]{null, null, null, SlimefunItems.HEATING_COIL, new ItemStack(Material.SMOKER), SlimefunItems.HEATING_COIL, null, new ItemStack(Material.CAMPFIRE), null}) - .register(plugin); - } + new AutoDrier(categories.electricity, SlimefunItems.AUTO_DRIER, RecipeType.ENHANCED_CRAFTING_TABLE, + new ItemStack[]{null, null, null, SlimefunItems.HEATING_COIL, new ItemStack(Material.SMOKER), SlimefunItems.HEATING_COIL, null, new ItemStack(Material.CAMPFIRE), null}) + .register(plugin); new AutoBrewer(categories.electricity, SlimefunItems.AUTO_BREWER, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, SlimefunItems.HEATING_COIL, null, SlimefunItems.REINFORCED_PLATE, new ItemStack(Material.BREWING_STAND), SlimefunItems.REINFORCED_PLATE, null, SlimefunItems.ELECTRIC_MOTOR, null}) { @@ -2292,7 +2266,7 @@ public final class SlimefunItemSetup { .register(plugin); new SlimefunItem(categories.magicalResources, SlimefunItems.RAINBOW_RUNE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.CYAN_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.ENDER_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(YELLOW_DYE), SlimefunItems.ENDER_LUMP_3, new ItemStack(Material.MAGENTA_DYE)}) + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.CYAN_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.ENDER_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.YELLOW_DYE), SlimefunItems.ENDER_LUMP_3, new ItemStack(Material.MAGENTA_DYE)}) .register(plugin); new SoulboundRune(categories.magicalResources, SlimefunItems.SOULBOUND_RUNE, RecipeType.ANCIENT_ALTAR, @@ -2361,96 +2335,96 @@ public final class SlimefunItemSetup { // Christmas new RainbowBlock(categories.christmas, SlimefunItems.RAINBOW_WOOL_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(GREEN_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL_XMAS, 2), new RainbowTickHandler(Material.RED_WOOL, Material.GREEN_WOOL)) .register(plugin); new RainbowBlock(categories.christmas, SlimefunItems.RAINBOW_GLASS_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_XMAS, 2), new RainbowTickHandler(Material.RED_STAINED_GLASS, Material.GREEN_STAINED_GLASS)) .register(plugin); new RainbowBlock(categories.christmas, SlimefunItems.RAINBOW_GLASS_PANE_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE_XMAS, 2), new RainbowTickHandler(Material.RED_STAINED_GLASS_PANE, Material.GREEN_STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(categories.christmas, SlimefunItems.RAINBOW_CLAY_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(GREEN_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY_XMAS, 2), new RainbowTickHandler(Material.RED_TERRACOTTA, Material.GREEN_TERRACOTTA)) .register(plugin); new RainbowBlock(categories.christmas, SlimefunItems.RAINBOW_CONCRETE_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(GREEN_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE_XMAS, 2), new RainbowTickHandler(Material.RED_CONCRETE, Material.GREEN_CONCRETE)) .register(plugin); new RainbowBlock(categories.christmas, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_XMAS, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(GREEN_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.GREEN_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.GREEN_DYE), SlimefunItems.CHRISTMAS_COOKIE, new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_XMAS, 2), new RainbowTickHandler(Material.RED_GLAZED_TERRACOTTA, Material.GREEN_GLAZED_TERRACOTTA)) .register(plugin); // Valentines Day new RainbowBlock(categories.valentinesDay, SlimefunItems.RAINBOW_WOOL_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_WOOL, Material.PINK_WOOL)) .register(plugin); new RainbowBlock(categories.valentinesDay, SlimefunItems.RAINBOW_GLASS_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_STAINED_GLASS, Material.PINK_STAINED_GLASS)) .register(plugin); new RainbowBlock(categories.valentinesDay, SlimefunItems.RAINBOW_GLASS_PANE_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_STAINED_GLASS_PANE, Material.PINK_STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(categories.valentinesDay, SlimefunItems.RAINBOW_CLAY_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_TERRACOTTA, Material.PINK_TERRACOTTA)) .register(plugin); new RainbowBlock(categories.valentinesDay, SlimefunItems.RAINBOW_CONCRETE_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_CONCRETE, Material.PINK_CONCRETE)) .register(plugin); new RainbowBlock(categories.valentinesDay, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_VALENTINE, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(RED_DYE)}, + new ItemStack[] {new ItemStack(Material.RED_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.PINK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.PINK_DYE), new ItemStack(Material.POPPY), new ItemStack(Material.RED_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_VALENTINE, 2), new RainbowTickHandler(Material.MAGENTA_GLAZED_TERRACOTTA, Material.PINK_GLAZED_TERRACOTTA)) .register(plugin); // Halloween new RainbowBlock(categories.halloween, SlimefunItems.RAINBOW_WOOL_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(BLACK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_WOOL), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_WOOL), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_WOOL_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_WOOL, Material.BLACK_WOOL)) .register(plugin); new RainbowBlock(categories.halloween, SlimefunItems.RAINBOW_GLASS_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_STAINED_GLASS, Material.BLACK_STAINED_GLASS)) .register(plugin); new RainbowBlock(categories.halloween, SlimefunItems.RAINBOW_GLASS_PANE_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_STAINED_GLASS_PANE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_STAINED_GLASS_PANE), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLASS_PANE_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_STAINED_GLASS_PANE, Material.BLACK_STAINED_GLASS_PANE)) .register(plugin); new RainbowBlock(categories.halloween, SlimefunItems.RAINBOW_CLAY_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(BLACK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_TERRACOTTA), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CLAY_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_TERRACOTTA, Material.BLACK_TERRACOTTA)) .register(plugin); new RainbowBlock(categories.halloween, SlimefunItems.RAINBOW_CONCRETE_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(BLACK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_CONCRETE), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_CONCRETE), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_CONCRETE_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_CONCRETE, Material.BLACK_CONCRETE)) .register(plugin); new RainbowBlock(categories.halloween, SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_HALLOWEEN, RecipeType.ANCIENT_ALTAR, - new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(BLACK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, + new ItemStack[] {new ItemStack(Material.ORANGE_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), SlimefunItems.RAINBOW_RUNE, new ItemStack(Material.WHITE_GLAZED_TERRACOTTA), new ItemStack(Material.BLACK_DYE), new ItemStack(Material.PUMPKIN), new ItemStack(Material.ORANGE_DYE)}, new SlimefunItemStack(SlimefunItems.RAINBOW_GLAZED_TERRACOTTA_HALLOWEEN, 2), new RainbowTickHandler(Material.ORANGE_GLAZED_TERRACOTTA, Material.BLACK_GLAZED_TERRACOTTA)) .register(plugin); @@ -2688,10 +2662,8 @@ public final class SlimefunItemSetup { new OrganicFood(categories.misc, SlimefunItems.APPLE_ORGANIC_FOOD, Material.APPLE) .register(plugin); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - new OrganicFood(categories.misc, SlimefunItems.SWEET_BERRIES_ORGANIC_FOOD, Material.SWEET_BERRIES) - .register(plugin); - } + new OrganicFood(categories.misc, SlimefunItems.SWEET_BERRIES_ORGANIC_FOOD, Material.SWEET_BERRIES) + .register(plugin); new OrganicFood(categories.misc, SlimefunItems.KELP_ORGANIC_FOOD, Material.DRIED_KELP) .register(plugin); @@ -2906,7 +2878,7 @@ public final class SlimefunItemSetup { }.register(plugin); - new SlimefunItem(categories.cargo, SlimefunItems.CARGO_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE, + new UnplaceableBlock(categories.cargo, SlimefunItems.CARGO_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS, SlimefunItems.SILVER_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.SILVER_INGOT, SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS}, new SlimefunItemStack(SlimefunItems.CARGO_MOTOR, 4)) .register(plugin); @@ -3069,11 +3041,9 @@ public final class SlimefunItemSetup { new ItemStack[] {SlimefunItems.BLISTERING_INGOT_3, new ItemStack(Material.NETHER_STAR), SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ANDROID_MEMORY_CORE, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.CARBONADO_EDGED_CAPACITOR}) .register(plugin); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - new TapeMeasure(categories.usefulItems, SlimefunItems.TAPE_MEASURE, RecipeType.ENHANCED_CRAFTING_TABLE, - new ItemStack[] {SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), new ItemStack(Material.STRING), new ItemStack(Material.YELLOW_DYE), SlimefunItems.GILDED_IRON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON}) - .register(plugin); - } + new TapeMeasure(categories.usefulItems, SlimefunItems.TAPE_MEASURE, RecipeType.ENHANCED_CRAFTING_TABLE, + new ItemStack[] {SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), new ItemStack(Material.STRING), new ItemStack(Material.YELLOW_DYE), SlimefunItems.GILDED_IRON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON}) + .register(plugin); if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) { new StrangeNetherGoo(categories.magicalResources, SlimefunItems.STRANGE_NETHER_GOO, RecipeType.BARTER_DROP, @@ -3089,6 +3059,8 @@ public final class SlimefunItemSetup { new ElytraCap(categories.magicalArmor, SlimefunItems.ELYTRA_CAP, RecipeType.ARMOR_FORGE, new ItemStack[]{new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), SlimefunItems.ELYTRA_SCALE, SlimefunItems.ELYTRA_SCALE, SlimefunItems.ELYTRA_SCALE, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.LEATHER_HELMET), new ItemStack(Material.SLIME_BALL)}) .register(plugin); + + // @formatter:on } private static void registerArmorSet(Category category, ItemStack baseComponent, ItemStack[] items, String idSyntax, boolean vanilla, PotionEffect[][] effects, SlimefunAddon addon) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java index 7f566db35..0cb2ea26f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java @@ -29,6 +29,9 @@ public final class ChestMenuUtils { private static final ItemStack INPUT_SLOT = new SlimefunItemStack("_UI_INPUT_SLOT", Material.CYAN_STAINED_GLASS_PANE, " "); private static final ItemStack OUTPUT_SLOT = new SlimefunItemStack("_UI_OUTPUT_SLOT", Material.ORANGE_STAINED_GLASS_PANE, " "); + private static final ItemStack NO_PERMISSION = new SlimefunItemStack("_UI_NO_PERMISSION", Material.BARRIER, "No Permission"); + private static final ItemStack NOT_RESEARCHED = new SlimefunItemStack("_UI_NOT_RESEARCHED", Material.BARRIER, "Not researched"); + private static final ItemStack BACK_BUTTON = new SlimefunItemStack("_UI_BACK", Material.ENCHANTED_BOOK, "&7\u21E6 Back", meta -> meta.addItemFlags(ItemFlag.HIDE_ENCHANTS)); private static final ItemStack MENU_BUTTON = new SlimefunItemStack("_UI_MENU", Material.COMPARATOR, "&eSettings / Info", "", "&7\u21E8 Click to see more"); private static final ItemStack SEARCH_BUTTON = new SlimefunItemStack("_UI_SEARCH", Material.NAME_TAG, "&bSearch"); @@ -46,6 +49,16 @@ public final class ChestMenuUtils { return UI_BACKGROUND; } + @Nonnull + public static ItemStack getNoPermissionItem() { + return NO_PERMISSION; + } + + @Nonnull + public static ItemStack getNotResearchedItem() { + return NOT_RESEARCHED; + } + @Nonnull public static ItemStack getInputSlotTexture() { return INPUT_SLOT; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterials.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterials.java index 274f0ed09..7b4f8de31 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterials.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterials.java @@ -4,6 +4,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; + +import org.apache.commons.lang.Validate; import org.bukkit.Material; import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; @@ -24,11 +27,13 @@ public final class ColoredMaterials { * constructor to be private. */ private ColoredMaterials() {} + + // @formatter:off (We want this to stay formatted like this) /** * This {@link List} contains all wool colors ordered by their appearance ingame. */ - public static final List WOOL = Collections.unmodifiableList(Arrays.asList( + public static final List WOOL = asList(new Material[] { Material.WHITE_WOOL, Material.ORANGE_WOOL, Material.MAGENTA_WOOL, @@ -45,12 +50,12 @@ public final class ColoredMaterials { Material.GREEN_WOOL, Material.RED_WOOL, Material.BLACK_WOOL - )); + }); /** * This {@link List} contains all stained glass colors ordered by their appearance ingame. */ - public static final List STAINED_GLASS = Collections.unmodifiableList(Arrays.asList( + public static final List STAINED_GLASS = asList(new Material[] { Material.WHITE_STAINED_GLASS, Material.ORANGE_STAINED_GLASS, Material.MAGENTA_STAINED_GLASS, @@ -67,12 +72,12 @@ public final class ColoredMaterials { Material.GREEN_STAINED_GLASS, Material.RED_STAINED_GLASS, Material.BLACK_STAINED_GLASS - )); + }); /** * This {@link List} contains all stained glass pane colors ordered by their appearance ingame. */ - public static final List STAINED_GLASS_PANE = Collections.unmodifiableList(Arrays.asList( + public static final List STAINED_GLASS_PANE = asList(new Material[] { Material.WHITE_STAINED_GLASS_PANE, Material.ORANGE_STAINED_GLASS_PANE, Material.MAGENTA_STAINED_GLASS_PANE, @@ -89,12 +94,12 @@ public final class ColoredMaterials { Material.GREEN_STAINED_GLASS_PANE, Material.RED_STAINED_GLASS_PANE, Material.BLACK_STAINED_GLASS_PANE - )); + }); /** * This {@link List} contains all terracotta colors ordered by their appearance ingame. */ - public static final List TERRACOTTA = Collections.unmodifiableList(Arrays.asList( + public static final List TERRACOTTA = asList(new Material[] { Material.WHITE_TERRACOTTA, Material.ORANGE_TERRACOTTA, Material.MAGENTA_TERRACOTTA, @@ -111,12 +116,12 @@ public final class ColoredMaterials { Material.GREEN_TERRACOTTA, Material.RED_TERRACOTTA, Material.BLACK_TERRACOTTA - )); + }); /** * This {@link List} contains all glazed terracotta colors ordered by their appearance ingame. */ - public static final List GLAZED_TERRACOTTA = Collections.unmodifiableList(Arrays.asList( + public static final List GLAZED_TERRACOTTA = asList(new Material[] { Material.WHITE_GLAZED_TERRACOTTA, Material.ORANGE_GLAZED_TERRACOTTA, Material.MAGENTA_GLAZED_TERRACOTTA, @@ -133,12 +138,12 @@ public final class ColoredMaterials { Material.GREEN_GLAZED_TERRACOTTA, Material.RED_GLAZED_TERRACOTTA, Material.BLACK_GLAZED_TERRACOTTA - )); + }); /** * This {@link List} contains all concrete colors ordered by their appearance ingame. */ - public static final List CONCRETE = Collections.unmodifiableList(Arrays.asList( + public static final List CONCRETE = asList(new Material[] { Material.WHITE_CONCRETE, Material.ORANGE_CONCRETE, Material.MAGENTA_CONCRETE, @@ -155,6 +160,16 @@ public final class ColoredMaterials { Material.GREEN_CONCRETE, Material.RED_CONCRETE, Material.BLACK_CONCRETE - )); + }); + + // @formatter:on + + @Nonnull + private static List asList(@Nonnull Material[] materials) { + Validate.noNullElements(materials, "The List cannot contain any null elements"); + Validate.isTrue(materials.length == 16, "Expected 16, received: " + materials.length + ". Did you miss a color?"); + + return Collections.unmodifiableList(Arrays.asList(materials)); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/HeadTexture.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/HeadTexture.java index ea095a5d7..ee8a849d0 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/HeadTexture.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/HeadTexture.java @@ -108,7 +108,8 @@ public enum HeadTexture { CARGO_ARROW_RIGHT("c2f910c47da042e4aa28af6cc81cf48ac6caf37dab35f88db993accb9dfe516"), ADD_NEW_LANGUAGE("3edd20be93520949e6ce789dc4f43efaeb28c717ee6bfcbbe02780142f716"), IRON_GOLEM("89091d79ea0f59ef7ef94d7bba6e5f17f2f7d4572c44f90f76c4819a714"), - PIGLIN_HEAD("2882af1294a74023e6919a31d1a027310f2e142afb4667d230d155e7f21dbb41"); + PIGLIN_HEAD("2882af1294a74023e6919a31d1a027310f2e142afb4667d230d155e7f21dbb41"), + NECROTIC_SKULL("7953b6c68448e7e6b6bf8fb273d7203acd8e1be19e81481ead51f45de59a8"); public static final HeadTexture[] valuesCache = values(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java index a84293946..d752b5ec8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java @@ -1,6 +1,7 @@ package io.github.thebusybiscuit.slimefun4.utils; import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.time.Duration; import java.time.LocalDateTime; @@ -12,16 +13,51 @@ import javax.annotation.Nullable; import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; +/** + * This class contains various utilities related to numbers and number formatting. + * + * @author TheBusyBiscuit + * @author Walshy + * + */ public final class NumberUtils { - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); + /** + * This is our {@link DecimalFormat} for decimal values. + */ + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ROOT)); + /** + * We do not want any instance of this to be created. + */ private NumberUtils() {} - public static String formatBigNumber(int i) { - return NumberFormat.getNumberInstance(Locale.US).format(i); + /** + * This method formats a given {@link Integer} to be displayed nicely with + * decimal digit grouping. + * {@code 1000000} for example will return {@code "1,000,000"} as a {@link String}. + * It uses the american (US) {@link Locale} for this transformation. + * + * @param number + * Your {@link Integer} + * + * @return The formatted String + */ + @Nonnull + public static String formatBigNumber(int number) { + return NumberFormat.getNumberInstance(Locale.US).format(number); } + /** + * This method transforms a String representation of a {@link LocalDateTime} + * from GitHub's API back into a {@link LocalDateTime} object + * + * @param date + * The formatted String version of a date from GitHub + * + * @return The {@link LocalDateTime} for the given input + */ + @Nonnull public static LocalDateTime parseGitHubDate(@Nonnull String date) { Validate.notNull(date, "Provided date was null"); return LocalDateTime.parse(date.substring(0, date.length() - 1)); @@ -37,6 +73,7 @@ public final class NumberUtils { * * @return A representative {@link ChatColor} */ + @Nonnull public static ChatColor getColorFromPercentage(float percentage) { if (percentage < 16.0F) { return ChatColor.DARK_RED; @@ -53,13 +90,51 @@ public final class NumberUtils { } } + /** + * This returns the elapsed time since the given {@link LocalDateTime}. + * The output will be nicely formatted based on the elapsed hours or days since the + * given {@link LocalDateTime}. + * + * If a {@link LocalDateTime} from yesterday was passed it will return {@code "1d"}. + * One hour later it will read {@code "1d 1h"}. For values smaller than an hour {@code "< 1h"} + * will be returned instead. + * + * @param date + * The {@link LocalDateTime}. + * + * @return The elapsed time as a {@link String} + */ + @Nonnull public static String getElapsedTime(@Nonnull LocalDateTime date) { - Validate.notNull(date, "Provided date was null"); - long hours = Duration.between(date, LocalDateTime.now()).toHours(); + return getElapsedTime(LocalDateTime.now(), date); + } + + /** + * This returns the elapsed time between the two given {@link LocalDateTime LocalDateTimes}. + * The output will be nicely formatted based on the elapsed hours or days between the + * given {@link LocalDateTime LocalDateTime}. + * + * If a {@link LocalDateTime} from today and yesterday (exactly 24h apart) was passed it + * will return {@code "1d"}. + * One hour later it will read {@code "1d 1h"}. For values smaller than an hour {@code "< 1h"} + * will be returned instead. + * + * @param start + * The starting {@link LocalDateTime}. + * @param end + * The ending {@link LocalDateTime}. + * + * @return The elapsed time as a {@link String} + */ + @Nonnull + public static String getElapsedTime(@Nonnull LocalDateTime start, @Nonnull LocalDateTime end) { + Validate.notNull(start, "Provided start was null"); + Validate.notNull(end, "Provided end was null"); + long hours = Duration.between(start, end).toHours(); if (hours == 0) { return "< 1h"; - } else if ((hours / 24) == 0) { + } else if (hours / 24 == 0) { return (hours % 24) + "h"; } else if (hours % 24 == 0) { return (hours / 24) + "d"; @@ -68,10 +143,12 @@ public final class NumberUtils { } } + @Nonnull public static String getTimeLeft(int seconds) { String timeleft = ""; int minutes = (int) (seconds / 60L); + if (minutes > 0) { timeleft += minutes + "m "; } @@ -80,14 +157,27 @@ public final class NumberUtils { return timeleft + seconds + "s"; } - public static int getInt(String str, int defaultValue) { + /** + * This method parses a {@link String} into an {@link Integer}. + * If the {@link String} could not be parsed correctly, the provided + * default value will be returned instead. + * + * @param str + * The {@link String} to parse + * @param defaultValue + * The default value for when the {@link String} could not be parsed + * + * @return The resulting {@link Integer} + */ + public static int getInt(@Nonnull String str, int defaultValue) { if (PatternUtils.NUMERIC.matcher(str).matches()) { return Integer.parseInt(str); + } else { + return defaultValue; } - - return defaultValue; } + @Nonnull public static String getAsMillis(long nanoseconds) { if (nanoseconds == 0) { return "0ms"; @@ -129,6 +219,8 @@ public final class NumberUtils { * The value to clamp * @param max * The maximum value + * + * @return The clamped value */ public static int clamp(int min, int value, int max) { if (value < min) { 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 8c90ef203..05046d5d8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java @@ -121,7 +121,7 @@ public final class SlimefunUtils { } private static boolean hasSoulboundFlag(@Nullable ItemMeta meta) { - if (meta != null && SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { + if (meta != null) { PersistentDataContainer container = meta.getPersistentDataContainer(); if (container.has(SOULBOUND_KEY, PersistentDataType.BYTE)) { @@ -154,16 +154,14 @@ public final class SlimefunUtils { boolean isSoulbound = isSoulbound(item); ItemMeta meta = item.getItemMeta(); - if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14)) { - PersistentDataContainer container = meta.getPersistentDataContainer(); + PersistentDataContainer container = meta.getPersistentDataContainer(); - if (makeSoulbound && !isSoulbound) { - container.set(SOULBOUND_KEY, PersistentDataType.BYTE, (byte) 1); - } + if (makeSoulbound && !isSoulbound) { + container.set(SOULBOUND_KEY, PersistentDataType.BYTE, (byte) 1); + } - if (!makeSoulbound && isSoulbound) { - container.remove(SOULBOUND_KEY); - } + if (!makeSoulbound && isSoulbound) { + container.remove(SOULBOUND_KEY); } List lore = meta.hasLore() ? meta.getLore() : new ArrayList<>(); 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 98e0340b5..289314298 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 @@ -35,9 +35,9 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.tools.SmeltersPic * extensions of the default Minecraft tags. * The actual tag files are located in the {@literal /src/main/resources/tags} directory * and follow Minecraft's tags.json format. - * + * * @author TheBusyBiscuit - * + * * @see TagParser * */ @@ -48,6 +48,11 @@ public enum SlimefunTag implements Tag { */ ORES, + /** + * All minecraft ores that can be affected by fortune. + */ + FORTUNE_COMPATIBLE_ORES, + /** * All Shulker boxes, normal and colored. */ @@ -63,6 +68,11 @@ public enum SlimefunTag implements Tag { */ MUSHROOMS, + /** + * All leather armor materials + */ + LEATHER_ARMOR, + /** * Every glass variant, includes both blocks and panes. * Also stained glass and stained glass panes. @@ -99,12 +109,28 @@ public enum SlimefunTag implements Tag { */ STONE_VARIANTS, + /** + * All dirt variants. Dirt, coarse dirt, grass, mycelium. + * This also includes farmland and grass paths. + */ + DIRT_VARIANTS, + /** * All variants of concrete powder. * Can you believe there is no tag for this already? */ CONCRETE_POWDERS, + /** + * All the types of pressure plates. + */ + PRESSURE_PLATES, + + /** + * All tall flowers because minecraft doesn't have a tag for this + */ + TALL_FLOWERS, + /** * Materials which are sensitive to break. * Things like Saplings or Pressure plates which break as well when you break @@ -203,7 +229,7 @@ public enum SlimefunTag implements Tag { /** * This method reloads this {@link SlimefunTag} from our resources directory. - * + * * @throws TagMisconfigurationException * This is thrown whenever a {@link SlimefunTag} could not be parsed properly */ @@ -220,11 +246,11 @@ public enum SlimefunTag implements Tag { /** * This method reloads every single {@link SlimefunTag} from the resources directory. * It is equivalent to running {@link #reload()} on every single {@link SlimefunTag} manually. - * + * * Do keep in mind though that any misconfigured {@link SlimefunTag} will abort the entire * method and throw a {@link TagMisconfigurationException}. So one faulty {@link SlimefunTag} * will stop the reloading process. - * + * * @throws TagMisconfigurationException * This is thrown if one of the {@link SlimefunTag SlimefunTags} could not be parsed correctly */ @@ -277,9 +303,9 @@ public enum SlimefunTag implements Tag { /** * This returns a {@link Set} of {@link Tag Tags} which are children of this {@link SlimefunTag}, * these can be other {@link SlimefunTag SlimefunTags} or regular {@link Tag Tags}. - * + * * The returned {@link Set} is immutable - * + * * @return An immutable {@link Set} of all sub tags. */ @Nonnull @@ -289,7 +315,7 @@ public enum SlimefunTag implements Tag { /** * This method returns an Array representation for this {@link SlimefunTag}. - * + * * @return A {@link Material} array for this {@link Tag} */ @Nonnull @@ -299,7 +325,7 @@ public enum SlimefunTag implements Tag { /** * This returns a {@link Stream} of {@link Material Materials} for this {@link SlimefunTag}. - * + * * @return A {@link Stream} of {@link Material Materials} */ @Nonnull @@ -315,7 +341,7 @@ public enum SlimefunTag implements Tag { * * @param value * The value which you would like to look up. - * + * * @return The {@link SlimefunTag} or null if it does not exist. */ @Nullable diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java index c69a682ec..8c788e94f 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java @@ -134,6 +134,7 @@ public class Category implements Keyed { * * @param p * The Player to create this {@link ItemStack} for + * * @return A localized display item for this {@link Category} */ @Nonnull @@ -166,6 +167,26 @@ public class Category implements Keyed { return ChatColor.stripColor(item.getItemMeta().getDisplayName()); } + /** + * This returns the localized display name of this {@link Category} for the given {@link Player}. + * The method will fall back to {@link #getUnlocalizedName()} if no translation was found. + * + * @param p + * The {@link Player} who to translate the name for + * + * @return The localized name of this {@link Category} + */ + @Nonnull + public String getDisplayName(@Nonnull Player p) { + String localized = SlimefunPlugin.getLocalization().getCategoryName(p, getKey()); + + if (localized != null) { + return localized; + } else { + return getUnlocalizedName(); + } + } + /** * Returns all instances of {@link SlimefunItem} bound to this {@link Category}. * diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java index daf180de3..b6e36dcd8 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AContainer.java @@ -5,9 +5,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -238,31 +241,30 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock, BlockMenu inv = BlockStorage.getInventory(b); if (isProcessing(b)) { - int timeleft = progress.get(b); - if (timeleft > 0) { - ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(b).getTicks(), getProgressBar()); + if (takeCharge(b.getLocation())) { - if (isChargeable()) { - if (getCharge(b.getLocation()) < getEnergyConsumption()) { - return; + int timeleft = progress.get(b); + + if (timeleft > 0) { + ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(b).getTicks(), getProgressBar()); + + progress.put(b, timeleft - 1); + } else { + + inv.replaceExistingItem(22, new CustomItem(Material.BLACK_STAINED_GLASS_PANE, " ")); + + for (ItemStack output : processing.get(b).getOutput()) { + inv.pushItem(output.clone(), getOutputSlots()); } - removeCharge(b.getLocation(), getEnergyConsumption()); + Bukkit.getPluginManager().callEvent(new AsyncMachineProcessCompleteEvent(b.getLocation(), AContainer.this, getProcessing(b))); + + progress.remove(b); + processing.remove(b); } - progress.put(b, timeleft - 1); - } else { - inv.replaceExistingItem(22, new CustomItem(Material.BLACK_STAINED_GLASS_PANE, " ")); - - for (ItemStack output : processing.get(b).getOutput()) { - inv.pushItem(output.clone(), getOutputSlots()); - } - - Bukkit.getPluginManager().callEvent(new AsyncMachineProcessCompleteEvent(b.getLocation(), AContainer.this, getProcessing(b))); - - progress.remove(b); - processing.remove(b); } + } else { MachineRecipe next = findNextRecipe(inv); @@ -273,6 +275,26 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock, } } + /** + * This method will remove charge from a location if it is chargeable. + * + * @param l + * location to try to remove charge from + * @return Whether charge was taken if its chargeable + */ + protected boolean takeCharge(@Nonnull Location l) { + Validate.notNull(l, "Can't attempt to take charge from a null location!"); + + if (isChargeable()) { + if (getCharge(l) < getEnergyConsumption()) { + return false; + } + + removeCharge(l, getEnergyConsumption()); + } + return true; + } + protected MachineRecipe findNextRecipe(BlockMenu inv) { Map inventory = new HashMap<>(); 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 8de896dc1..de0c283a3 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 @@ -19,7 +19,7 @@ import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; * @deprecated This interface is not designed to be used by addons. * */ -@Deprecated +// @Deprecated - commented out because we are not ready to send out warnings yet public interface InventoryBlock { /** diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index bad81f55d..c9090a91c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -40,7 +40,6 @@ networks: items: talismans: true - backpacks: true soulbound: true metrics: diff --git a/src/main/resources/languages/categories_he.yml b/src/main/resources/languages/categories_he.yml index 70c1547a9..492b733a6 100644 --- a/src/main/resources/languages/categories_he.yml +++ b/src/main/resources/languages/categories_he.yml @@ -23,3 +23,4 @@ slimefun: easter: חג הפסחא (אפריל) birthday: יום הולדתו של TheBusyBiscuit (26 באוקטובר) halloween: ליל כל הקדושים (31 באוקטובר) + androids: רובוטים ניתנים לתכנות diff --git a/src/main/resources/languages/messages_en.yml b/src/main/resources/languages/messages_en.yml index 99df15b23..6962c5e67 100644 --- a/src/main/resources/languages/messages_en.yml +++ b/src/main/resources/languages/messages_en.yml @@ -265,6 +265,7 @@ machines: anvil: not-working: '&4You cannot use Slimefun items in an anvil!' + mcmmo-salvaging: '&4You cannot salvage Slimefun items!' brewing_stand: not-working: '&4You cannot use Slimefun items in a brewing stand!' @@ -282,6 +283,9 @@ backpack: workbench: not-enhanced: '&4You cannot use Slimefun items in a normal workbench' +cauldron: + no-discoloring: '&4You cannot discolor Slimefun Armor' + gps: deathpoint: '&4Deathpoint &7%date%' waypoint: diff --git a/src/main/resources/languages/messages_fr.yml b/src/main/resources/languages/messages_fr.yml index 80d93db36..797238f77 100644 --- a/src/main/resources/languages/messages_fr.yml +++ b/src/main/resources/languages/messages_fr.yml @@ -255,6 +255,7 @@ machines: anvil: not-working: "&4Vous ne pouvez pas utiliser des objets Slimefun dans une enclume !" + mcmmo-salvaging: "&4Vous ne pouvez pas recycler des objets Slimefun !" backpack: already-open: "&cDésolé, ce Backpack est ouvert quelque part ailleurs !" no-stack: "&cVous ne pouvez pas stack les Backpacks" @@ -340,6 +341,7 @@ languages: zh-CN: Chinois (Chine) el: Grec he: Hébreu + pt: Portugais (Portugal) ar: Arabe af: Afrikaans da: Danois @@ -351,7 +353,6 @@ languages: fa: Persan th: Thaï ro: Roumain - pt: Portugais (Portugal) pt-BR: Portugais (Brésil) bg: Bulgare ko: Coréen @@ -369,5 +370,7 @@ villagers: cartography_table: not-working: "&4Vous ne pouvez pas utiliser d'objets Slimefun dans une table de cartographie !" +cauldron: + no-discoloring: "&4Vous ne pouvez pas décolorer une armure Slimefun" miner: no-ores: "&eDésolé, je n'ai pas pu trouver de minerai à proximité !" diff --git a/src/main/resources/languages/messages_hu.yml b/src/main/resources/languages/messages_hu.yml index 8320c757b..5bfa56bdd 100644 --- a/src/main/resources/languages/messages_hu.yml +++ b/src/main/resources/languages/messages_hu.yml @@ -244,6 +244,7 @@ machines: finished: Az Industrial Miner-ed kész! Összesen %ores% ércet szerzett! anvil: not-working: "&4Nem használhatsz Slimefun tárgyakat az üllőben!" + mcmmo-salvaging: "&4Nem hasznosíthatsz újra Slimefun tárgyakat!" backpack: already-open: "&cSajnáljuk, ez a hátizsák valahol máshol már nyitva van!" no-stack: "&cNem halmozhatsz hátizsákokat" @@ -306,7 +307,7 @@ android: rating: own: "&4Nem értékelheted a saját szkriptedet!" already: "&4Ezt a szkriptet már értékelted!" - editor: Szkript Szerkesztő + editor: Szkript szerkesztő languages: default: Szerver-alapértelmezett en: Angol @@ -328,7 +329,6 @@ languages: zh-CN: Kínai (Kína) el: Görög he: Héber - pt-BR: Portugál (Brazília) ar: Arab af: Afrikaans da: Dán @@ -341,6 +341,7 @@ languages: th: Thai ro: Román pt: Portugál (Portugália) + pt-BR: Portugál (Brazília) bg: Bolgár ko: Koreai tr: Török @@ -355,5 +356,7 @@ villagers: no-trading: "&4Nem cserélhetsz Slimefun tárgyakat falusiakkal!" cartography_table: not-working: "&4Nem használhatsz Slimefun tárgyakat térképasztalban." +cauldron: + no-discoloring: "&4Nem színteleníthetsz Slimefun páncélt!" miner: no-ores: "&eSajnálom, nem találtam semmilyen ércet a közelben!" diff --git a/src/main/resources/languages/messages_ja.yml b/src/main/resources/languages/messages_ja.yml index ec99efcc2..c34c65548 100644 --- a/src/main/resources/languages/messages_ja.yml +++ b/src/main/resources/languages/messages_ja.yml @@ -228,6 +228,7 @@ machines: finished: "&eIndustrial Minerの稼働完了!合計で%ores%個の鉱石を入手しました!" anvil: not-working: "&4Slimefunアイテムは金床を利用できません!" + mcmmo-salvaging: "&4Slimefunアイテムはサルベージできません!" backpack: already-open: "&cこのバックパックはどこかで使用中です!" no-stack: "&cバックパックはスタックされていると使用できません!" @@ -312,7 +313,6 @@ languages: el: ギリシャ語 he: ヘブライ語 pt: ポルトガル語(ポルトガル) - pt-BR: ポルトガル語(ブラジル) ar: アラビア語 af: アフリカーンス語 da: デンマーク語 @@ -324,6 +324,7 @@ languages: fa: ペルシア語 th: タイ語 ro: ルーマニア語 + pt-BR: ポルトガル語(ブラジル) bg: ブルガリア語 ko: 韓国語 tr: トルコ語 @@ -338,5 +339,7 @@ villagers: no-trading: "&4Slimefunアイテムは村人との取引に使用できません!" cartography_table: not-working: "&4Slimefunアイテムは製図台を使用できません!" +cauldron: + no-discoloring: "&4Slimefunアイテムの脱色はできません" miner: no-ores: "&e周辺には鉱石が見つかりませんでした!" diff --git a/src/main/resources/languages/messages_ru.yml b/src/main/resources/languages/messages_ru.yml index f1989d92a..addbf80bb 100644 --- a/src/main/resources/languages/messages_ru.yml +++ b/src/main/resources/languages/messages_ru.yml @@ -20,6 +20,10 @@ commands: player-never-joined: "&4Игрок с таким ником не найден!" backpack-does-not-exist: "&4Указанный рюкзак не существует!" restored-backpack-given: "&aРюкзак был восстановлен и добавлен в Ваш инвентарь!" + charge: + description: Заряжает предмет, который Вы держите + charge-success: Предмет заряжен! + not-rechargeable: Этот предмет не может быть заряжен! guide: search: message: "&bЧто бы Вы хотели найти?" @@ -83,6 +87,7 @@ guide: miner: Ресурсы, добываемые этим шахтёром generator: Доступные виды топлива gold-pan: Ресурсы, которые Вы можете получить + climbing-pick: Поверхности для карабканья back: title: Назад guide: Вернуться к руководству Slimefun @@ -129,6 +134,7 @@ messages: whirlwind: "&a&oВаш талисман отразил снаряд" wizard: "&a&oТалисман повысил уровень зачарования «Удача», но мог также ухудшить другие зачарования" + caveman: "&a&oВаш талисман выдал Вам «Спешку»" soulbound-rune: fail: "&cВы можете привязать к себе только один предмет за раз." success: "&aВы успешно привязали этот предмет к себе! Он останется при Вас после @@ -177,6 +183,10 @@ messages: multi-tool: mode-change: "&bРежим «%device%» изменён на: &9%mode%" not-shears: "&cМультиинструмент не может быть использован в качестве ножниц!" + climbing-pick: + dual-wielding: "&4Вы должны держать кирку для скалолазания в обеих руках!" + wrong-material: "&cВы не можете карабкаться по этой поверхности. Проверьте руководство + Slimefun для большей информации!" mode-change: "&b%device% | Режим изменён на: &9%mode%" machines: pattern-not-found: "&eК сожалению, не удалось распознать этот рецепт. Пожалуйста, @@ -320,6 +330,7 @@ languages: zh-CN: Китайский (Китай) el: Греческий he: Иврит + pt: Португальский (Португалия) pt-BR: Португальский (Бразилия) ar: Арабский af: Бурский @@ -332,7 +343,6 @@ languages: fa: Персидский th: Тайский ro: Румынский - pt: Португальский (Португалия) bg: Болгарский ko: Корейский tr: Турецкий @@ -345,5 +355,7 @@ brewing_stand: not-working: "&4Вы не можете использовать Slimefun предметы в варочной стойке!" villagers: no-trading: "&4Вы не можете торговаться с крестьянами Slimefun предметами!" +cartography_table: + not-working: "&4Вы не можете использовать Slimefun предметы в столе картографа!" miner: no-ores: "&eК сожалению, не удалось найти какую-либо руду поблизости!" diff --git a/src/main/resources/languages/messages_tl.yml b/src/main/resources/languages/messages_tl.yml index fa284c8f7..cb9531d74 100644 --- a/src/main/resources/languages/messages_tl.yml +++ b/src/main/resources/languages/messages_tl.yml @@ -21,6 +21,10 @@ commands: backpack-does-not-exist: "&4Ang tinukoy na backpack ay hindi umiiral!" restored-backpack-given: "&aAng iyong backpack ay naibalik at naidagdag sa iyong imbentaryo!" + charge: + description: I-chacharge ang item ng iyong hinahawakan. + charge-success: Na-charge na ang item! + not-rechargeable: Hindi puedeng i-charge ang item na ito. guide: search: message: "&bAno ang hinahanap mo?" @@ -53,6 +57,7 @@ guide: addons: Ang mga Addons para sa Slimefun4 bugs: Mga Bug Reports source: Ang Source Code + versions: Mga na-install na versions credits: commit: Commit commits: Mga Commits @@ -62,6 +67,12 @@ guide: resourcepack: "&cResourcepack Artist" translator: "&9Translator" profile-link: I-click ito upang bisitahin ang kanilang profile sa GitHub. + open: Pindutin ito upang makita ang aming mga nag-ambag + description: + - "&7Ang Slimefun ay isang proyekto na bukas na mapagkukunan" + - "&7at pinapanatili ng isang malaking pamayanan ng mga tao." + - "&7Mga hanggang &e%contributors% &7na mga tao ang tumutulong sa" + - "&7Slimefun sa buong lahat ng mga taong ito." pages: previous: Nakaraang pahina. next: Susunod na pahina. @@ -74,6 +85,7 @@ guide: miner: Mga mapagkukunan na maaari mong makuha sa Miner na ito. generator: Magagamit na mga uri ng gasolina. gold-pan: Mga mapagkukunan na maaari mong makuha. + climbing-pick: Mga ibabaw na maaari mong akyatin back: title: Balik guide: Bumalik sa Slimefun Guide @@ -175,6 +187,11 @@ messages: multi-tool: mode-change: "&b%device% napalitan ang mode sa: &9%mode%" not-shears: "&cBawal gamitin ang Multi-Tool bilang shears!" + climbing-pick: + dual-wielding: "&4Kailangan mong hawakan ang Climbing Picks ng dalawang kamay + upang magamit ito!" + wrong-material: "&cHindi ka maaaring umakyat sa ibabaw na ito. Suriin ang iyong + Slimefun Guide para sa karagdagang impormasyon!" mode-change: "&b%device% mode ay pinalitan ng: &9%mode%" machines: pattern-not-found: "&ePasensiya na, hindi ko maintindihan ang Recipe na ito. Pakilagay @@ -239,6 +256,7 @@ machines: %ores% ore(s)!" anvil: not-working: "&4Hindi puwedeng gamitin ang mga Slimefun Aytem sa isang Anvil!" + mcmmo-salvaging: "&4Bawal i-salvage ang mga Slimefun items!" backpack: already-open: "&cSorry, ang backpack na ito ay nakabukas na sa ibang lugar!" no-stack: "&cHindi puwedeng i-stack ang mga Backpack." @@ -349,3 +367,7 @@ brewing_stand: not-working: "&4Hindi ka maaaring gumamit ng mga Item ng Slimefun sa Brewing Stand!" villagers: no-trading: "&4Hindi ka maaaring mag-trade ng mga Slimefun Items sa mga villagers!" +cartography_table: + not-working: "&4Hindi mo puedeng gamitin ang mga Slimefun items sa cartography table!" +cauldron: + no-discoloring: "&4Hindi mo puedeng i-discolor ang Slimefun Armor." diff --git a/src/main/resources/languages/messages_zh-CN.yml b/src/main/resources/languages/messages_zh-CN.yml index b0b631128..34134c21d 100644 --- a/src/main/resources/languages/messages_zh-CN.yml +++ b/src/main/resources/languages/messages_zh-CN.yml @@ -20,6 +20,10 @@ commands: player-never-joined: "&4找不到叫这个名字的玩家!" backpack-does-not-exist: "&4你指定的背包不存在!" restored-backpack-given: "&a你的背包已被恢复并且已经放入了你的物品栏!" + charge: + description: 为你手持的物品充电 + charge-success: 充电完成! + not-rechargeable: 这个物品不能充电! guide: search: message: "&b你想要搜索什么?" @@ -127,6 +131,7 @@ messages: knight: "&a&o你的护身符给予了你 5 秒的生命恢复" whirlwind: "&a&o你的护身符反弹了所有的弹射物" wizard: "&a&o你的护身符使一个附魔的等级提高了, 同时其他附魔等级将会下降" + caveman: "&a&o你的护身符给予了你急迫效果" soulbound-rune: fail: "&c一次只能灵魂绑定一个物品." success: "&a物品绑定成功! 在你死亡后此物品将不会掉落." @@ -223,6 +228,7 @@ machines: finished: "&e你的工业矿机采矿已完成! 总共开采了 %ores% 个矿石!" anvil: not-working: "&4你不能在铁砧里使用 Slimefun 的物品" + mcmmo-salvaging: "&4你不能分解 Slimefun 物品!" backpack: already-open: "&c抱歉, 这个背包已在别处打开了!" no-stack: "&c你不能同时手持两个背包" @@ -331,5 +337,9 @@ brewing_stand: not-working: "&4你不能在酿造台中使用 Slimefun 物品!" villagers: no-trading: "&4你不能用 Slimefun 的物品和村民交易!" +cartography_table: + not-working: "&4你不能在制图台中使用 Slimefun 物品!" +cauldron: + no-discoloring: "&4你不能用炼药锅清洗 Slimefun 物品上的颜色" miner: no-ores: "&e抱歉, 周围找不到矿石了!" diff --git a/src/main/resources/languages/researches_hu.yml b/src/main/resources/languages/researches_hu.yml index 2715e2184..f1bf8cedc 100644 --- a/src/main/resources/languages/researches_hu.yml +++ b/src/main/resources/languages/researches_hu.yml @@ -246,3 +246,4 @@ slimefun: caveman_talisman: Az Ősember talizmánja even_higher_tier_capacitors: 3. szintű kondenzátorok elytra_cap: Ütközésvédelem + energy_connectors: Vezetékes csatlakozás diff --git a/src/main/resources/languages/researches_ja.yml b/src/main/resources/languages/researches_ja.yml index 7b2c59fda..27fccbf1a 100644 --- a/src/main/resources/languages/researches_ja.yml +++ b/src/main/resources/languages/researches_ja.yml @@ -246,3 +246,4 @@ slimefun: caveman_talisman: 洞窟暮らしのタリスマン even_higher_tier_capacitors: キャパシタⅢ elytra_cap: 衝撃緩和装備 + energy_connectors: 有線接続 diff --git a/src/main/resources/languages/researches_ru.yml b/src/main/resources/languages/researches_ru.yml index ee494c173..991111a09 100644 --- a/src/main/resources/languages/researches_ru.yml +++ b/src/main/resources/languages/researches_ru.yml @@ -240,3 +240,10 @@ slimefun: lead_clothing: Свинцовое обмундирование tape_measure: Рулетка iron_golem_assembler: Образователь железных големов + climbing_pick: Покоритель поверхностей + shulker_shell: Синтетические шалкеры + villager_rune: Сбрасывание торговли + caveman_talisman: Талисман шахтёра + even_higher_tier_capacitors: Большой накопитель энергии + elytra_cap: Противоударная экипировка + energy_connectors: Проводные соединения diff --git a/src/main/resources/languages/researches_tl.yml b/src/main/resources/languages/researches_tl.yml index a3d68ee89..de6c28d36 100644 --- a/src/main/resources/languages/researches_tl.yml +++ b/src/main/resources/languages/researches_tl.yml @@ -240,3 +240,10 @@ slimefun: lead_clothing: Lead Clothing tape_measure: Tape Measure iron_golem_assembler: Automated Iron Golems + climbing_pick: Block Raider + shulker_shell: Synthetic Shulkers + villager_rune: Reset Villager Trades + caveman_talisman: Talisman of the Caveman + even_higher_tier_capacitors: Tier 3 Capacitors + elytra_cap: Crash Gear + energy_connectors: Wired Connections diff --git a/src/main/resources/languages/researches_tr.yml b/src/main/resources/languages/researches_tr.yml index cb141f0e2..3c68ccd73 100644 --- a/src/main/resources/languages/researches_tr.yml +++ b/src/main/resources/languages/researches_tr.yml @@ -246,3 +246,4 @@ slimefun: caveman_talisman: Mağara Adamı Tılsımı even_higher_tier_capacitors: Seviye 3 Kapasitörler elytra_cap: İniş Takımı + energy_connectors: Kablolu Bağlantı diff --git a/src/main/resources/languages/researches_zh-CN.yml b/src/main/resources/languages/researches_zh-CN.yml index b0db0509e..3b2187c3a 100644 --- a/src/main/resources/languages/researches_zh-CN.yml +++ b/src/main/resources/languages/researches_zh-CN.yml @@ -243,3 +243,6 @@ slimefun: climbing_pick: 古块丽影 shulker_shell: 人造潜影贝 villager_rune: 防奸商神器 + caveman_talisman: 穴居人护身符 + even_higher_tier_capacitors: 三级电容器 + energy_connectors: 有线连接 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f0aaf77fd..04a127c8a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,9 +5,9 @@ description: Slimefun basically turns your entire Server into a FTB modpack with website: https://github.com/Slimefun main: io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin -softdepend: [CS-CoreLib, PlaceholderAPI, WorldEdit, EmeraldEnchants] +softdepend: [CS-CoreLib, PlaceholderAPI, WorldEdit, EmeraldEnchants, mcMMO] -api-version: '1.13' +api-version: '1.14' commands: slimefun: diff --git a/src/main/resources/tags/block_placer_ignored_materials.json b/src/main/resources/tags/block_placer_ignored_materials.json index a41e8050e..0e84d9d81 100644 --- a/src/main/resources/tags/block_placer_ignored_materials.json +++ b/src/main/resources/tags/block_placer_ignored_materials.json @@ -1,24 +1,62 @@ { "values" : [ "#slimefun:sensitive_materials", + "#slimefun:tall_flowers", "#slimefun:mushrooms", - { - "id" : "#minecraft:tall_flowers", - "required" : false - }, - { - "id" : "#minecraft:beds", - "required" : false - }, - { - "id" : "#minecraft:doors", - "required" : false - }, + "#minecraft:beds", + "#minecraft:buttons", + "#minecraft:signs", + "#minecraft:doors", + "#minecraft:rails", + "#minecraft:small_flowers", + "#minecraft:coral_blocks", + "#minecraft:corals", + "#minecraft:carpets", + "#minecraft:banners", "minecraft:sugar_cane", + "minecraft:cactus", + "minecraft:bamboo", + "minecraft:vine", + "minecraft:ladder", + "minecraft:chorus_plant", + "minecraft:chorus_flower", + "minecraft:snow", + "minecraft:lever", + "minecraft:repeater", + "minecraft:tripwire_hook", "minecraft:lily_pad", "minecraft:dead_bush", + "minecraft:fern", + "minecraft:grass", + "minecraft:sea_pickle", + "minecraft:nether_wart", + "minecraft:seagrass", + "minecraft:tall_seagrass", + "minecraft:kelp", + "minecraft:bell", + "minecraft:lantern", { - "id" : "minecraft:bamboo", + "id" : "minecraft:soul_lantern", + "required" : false + }, + { + "id" : "minecraft:nether_sprouts", + "required" : false + }, + { + "id" : "minecraft:crimson_roots", + "required": false + }, + { + "id" : "minecraft:twisting_vines", + "required" : false + }, + { + "id" : "minecraft:warped_roots", + "required" : false + }, + { + "id" : "minecraft:weeping_vines", "required" : false } ] diff --git a/src/main/resources/tags/crop_growth_accelerator_blocks.json b/src/main/resources/tags/crop_growth_accelerator_blocks.json index 97af19e67..e0be360b6 100644 --- a/src/main/resources/tags/crop_growth_accelerator_blocks.json +++ b/src/main/resources/tags/crop_growth_accelerator_blocks.json @@ -12,9 +12,6 @@ "minecraft:pumpkin_stem", "minecraft:nether_wart", "minecraft:cocoa", - { - "id" : "minecraft:sweet_berry_bush", - "required" : false - } + "minecraft:sweet_berry_bush" ] } diff --git a/src/main/resources/tags/dirt_variants.json b/src/main/resources/tags/dirt_variants.json new file mode 100644 index 000000000..d551913f7 --- /dev/null +++ b/src/main/resources/tags/dirt_variants.json @@ -0,0 +1,11 @@ +{ + "values" : [ + "minecraft:dirt", + "minecraft:coarse_dirt", + "minecraft:grass_block", + "minecraft:grass_path", + "minecraft:farmland", + "minecraft:podzol", + "minecraft:mycelium" + ] +} diff --git a/src/main/resources/tags/explosive_shovel_blocks.json b/src/main/resources/tags/explosive_shovel_blocks.json index da0f980ff..17ceed4e0 100644 --- a/src/main/resources/tags/explosive_shovel_blocks.json +++ b/src/main/resources/tags/explosive_shovel_blocks.json @@ -1,10 +1,8 @@ { "values" : [ "#minecraft:sand", - "#minecraft:dirt_like", "#slimefun:concrete_powders", - "minecraft:farmland", - "minecraft:grass_path", + "#slimefun:dirt_variants", "minecraft:snow", "minecraft:snow_block", "minecraft:gravel", diff --git a/src/main/resources/tags/fortune_compatible_ores.json b/src/main/resources/tags/fortune_compatible_ores.json new file mode 100644 index 000000000..bdf61d641 --- /dev/null +++ b/src/main/resources/tags/fortune_compatible_ores.json @@ -0,0 +1,10 @@ +{ + "values" : [ + "minecraft:coal_ore", + "minecraft:lapis_ore", + "minecraft:diamond_ore", + "minecraft:redstone_ore", + "minecraft:emerald_ore", + "minecraft:nether_quartz_ore" + ] +} diff --git a/src/main/resources/tags/leather_armor.json b/src/main/resources/tags/leather_armor.json new file mode 100644 index 000000000..9001f3385 --- /dev/null +++ b/src/main/resources/tags/leather_armor.json @@ -0,0 +1,8 @@ +{ + "values" : [ + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots" + ] +} diff --git a/src/main/resources/tags/ores.json b/src/main/resources/tags/ores.json index b4c76a1a4..fd4c45729 100644 --- a/src/main/resources/tags/ores.json +++ b/src/main/resources/tags/ores.json @@ -6,11 +6,6 @@ }, "minecraft:gold_ore", "minecraft:iron_ore", - "minecraft:coal_ore", - "minecraft:lapis_ore", - "minecraft:diamond_ore", - "minecraft:redstone_ore", - "minecraft:emerald_ore", - "minecraft:nether_quartz_ore" + "#slimefun:fortune_compatible_ores" ] } diff --git a/src/main/resources/tags/pressure_plates.json b/src/main/resources/tags/pressure_plates.json new file mode 100644 index 000000000..b8bdb7667 --- /dev/null +++ b/src/main/resources/tags/pressure_plates.json @@ -0,0 +1,12 @@ +{ + "values" : [ + "#minecraft:wooden_pressure_plates", + "minecraft:stone_pressure_plate", + "minecraft:light_weighted_pressure_plate", + "minecraft:heavy_weighted_pressure_plate", + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "required" : false + } + ] +} diff --git a/src/main/resources/tags/sensitive_materials.json b/src/main/resources/tags/sensitive_materials.json index bd782e1e6..daae5c94f 100644 --- a/src/main/resources/tags/sensitive_materials.json +++ b/src/main/resources/tags/sensitive_materials.json @@ -1,11 +1,8 @@ { "values" : [ "#minecraft:saplings", - "#minecraft:wooden_pressure_plates", "#slimefun:torches", - "minecraft:stone_pressure_plate", - "minecraft:light_weighted_pressure_plate", - "minecraft:heavy_weighted_pressure_plate", + "#slimefun:pressure_plates", "minecraft:cake" ] } diff --git a/src/main/resources/tags/tall_flowers.json b/src/main/resources/tags/tall_flowers.json new file mode 100644 index 000000000..61958b5de --- /dev/null +++ b/src/main/resources/tags/tall_flowers.json @@ -0,0 +1,10 @@ +{ + "values" : [ + "minecraft:lilac", + "minecraft:rose_bush", + "minecraft:peony", + "minecraft:tall_grass", + "minecraft:large_fern", + "minecraft:sunflower" + ] +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestAnvilListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestAnvilListener.java new file mode 100644 index 000000000..ba3784350 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestAnvilListener.java @@ -0,0 +1,80 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.AnvilListener; +import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +public class TestAnvilListener { + + private static SlimefunPlugin plugin; + private static AnvilListener listener; + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + listener = new AnvilListener(plugin); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + private InventoryClickEvent mockAnvilEvent(ItemStack item) { + Player player = server.addPlayer(); + Inventory inv = TestUtilities.mockInventory(InventoryType.ANVIL, item, null, new ItemStack(Material.IRON_CHESTPLATE)); + InventoryView view = player.openInventory(inv); + InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 2, ClickType.LEFT, InventoryAction.PICKUP_ONE); + + listener.onAnvil(event); + return event; + } + + @Test + public void testAnvilWithoutSlimefunItems() { + InventoryClickEvent event = mockAnvilEvent(new ItemStack(Material.IRON_SWORD)); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + + @Test + public void testAnvilWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCKED_IRON_SWORD", new CustomItem(Material.IRON_SWORD, "&6Mock")); + item.register(plugin); + + InventoryClickEvent event = mockAnvilEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event.getResult()); + } + + @Test + public void testAnvilWithVanillaItem() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.IRON_SWORD, true); + item.register(plugin); + + InventoryClickEvent event = mockAnvilEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestBrewingStandListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestBrewingStandListener.java new file mode 100644 index 000000000..708261165 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestBrewingStandListener.java @@ -0,0 +1,84 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; + +import org.bukkit.Material; +import org.bukkit.block.BrewingStand; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.BrewingStandListener; +import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +public class TestBrewingStandListener { + + private static SlimefunPlugin plugin; + private static BrewingStandListener listener; + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + listener = new BrewingStandListener(plugin); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + private InventoryClickEvent mockBrewingEvent(ItemStack item) { + Player player = server.addPlayer(); + Inventory inv = TestUtilities.mockInventory(InventoryType.BREWING); + Mockito.when(inv.getHolder()).thenReturn(Mockito.mock(BrewingStand.class)); + Mockito.when(inv.getSize()).thenReturn(5); + + InventoryView view = player.openInventory(inv); + view.setCursor(item); + InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 1, ClickType.LEFT, InventoryAction.PICKUP_ONE); + listener.onPreBrew(event); + return event; + } + + @Test + public void testBrewingWithoutSlimefunItems() { + InventoryClickEvent event = mockBrewingEvent(new ItemStack(Material.BLAZE_POWDER)); + Assertions.assertEquals(Result.ALLOW, event.getResult()); + } + + @Test + public void testBrewingWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCK_POWDER", new CustomItem(Material.BLAZE_POWDER, "&6Magic Mock Powder")); + item.register(plugin); + + InventoryClickEvent event = mockBrewingEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event.getResult()); + } + + @Test + public void testBrewingWithVanillaItem() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.BLAZE_POWDER, true); + item.register(plugin); + + InventoryClickEvent event = mockBrewingEvent(item.getItem()); + Assertions.assertEquals(Result.ALLOW, event.getResult()); + } +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCartographyTableListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCartographyTableListener.java new file mode 100644 index 000000000..d32e217b7 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCartographyTableListener.java @@ -0,0 +1,74 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CartographyTableListener; +import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +public class TestCartographyTableListener { + + private static SlimefunPlugin plugin; + private static CartographyTableListener listener; + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + listener = new CartographyTableListener(plugin); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + private InventoryClickEvent mockCartographyTableEvent(ItemStack item) { + Player player = server.addPlayer(); + Inventory inv = TestUtilities.mockInventory(InventoryType.CARTOGRAPHY, new ItemStack(Material.FILLED_MAP), item, new ItemStack(Material.FILLED_MAP)); + InventoryView view = player.openInventory(inv); + InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 2, ClickType.LEFT, InventoryAction.PICKUP_ONE); + + listener.onCartographyTable(event); + return event; + } + + @Test + public void testCartographyTableWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCKED_PAPER", new CustomItem(Material.PAPER, "&6Mock")); + item.register(plugin); + + InventoryClickEvent event = mockCartographyTableEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event.getResult()); + } + + @Test + public void testCartographyTableWithVanillaItem() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.PAPER, true); + item.register(plugin); + + InventoryClickEvent event = mockCartographyTableEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCauldronListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCauldronListener.java new file mode 100644 index 000000000..dbe1ad358 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCauldronListener.java @@ -0,0 +1,106 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import be.seeseemelk.mockbukkit.block.BlockMock; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CauldronListener; +import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +class TestCauldronListener { + + private static SlimefunPlugin plugin; + private static CauldronListener listener; + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + listener = new CauldronListener(plugin); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + private PlayerInteractEvent mockCauldronEvent(ItemStack item) { + Player player = server.addPlayer(); + Block block = new BlockMock(Material.CAULDRON); + PlayerInteractEvent event = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, block, BlockFace.UP, EquipmentSlot.HAND); + + listener.onCauldronUse(event); + return event; + } + + @Test + @DisplayName("Test Cauldron handling null") + void testCauldronWithNull() { + PlayerInteractEvent event = mockCauldronEvent(null); + Assertions.assertEquals(Result.DEFAULT, event.useItemInHand()); + } + + @Test + @DisplayName("Test Cauldron working as normal with unrelated items") + void testCauldronWithNormalItem() { + PlayerInteractEvent event = mockCauldronEvent(new ItemStack(Material.GOLD_BLOCK)); + Assertions.assertEquals(Result.DEFAULT, event.useItemInHand()); + } + + @Test + @DisplayName("Test Cauldron working as normal with normal leather armor") + void testCauldronWithNormalLeatherArmor() { + PlayerInteractEvent event = mockCauldronEvent(new ItemStack(Material.LEATHER_BOOTS)); + Assertions.assertEquals(Result.DEFAULT, event.useItemInHand()); + } + + @Test + @DisplayName("Test Cauldron working as normal with non-leather slimefun items") + void testCauldronWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CAULDRON_TEST_MOCK", new CustomItem(Material.GOLDEN_APPLE, "&6Mock")); + item.register(plugin); + + PlayerInteractEvent event = mockCauldronEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.useItemInHand()); + } + + @Test + @DisplayName("Test Cauldron being cancelled with slimefun leather armor") + void testCauldronWithSlimefunLeatherArmor() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CAULDRON_TEST_MOCK_LEATHER", new CustomItem(Material.LEATHER_BOOTS, "&6Mock")); + item.register(plugin); + + PlayerInteractEvent event = mockCauldronEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event.useItemInHand()); + } + + @Test + @DisplayName("Test Cauldron working as normal with vanilla slimefun leather armor") + void testCauldronWithVanillaLeatherArmor() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.LEATHER_CHESTPLATE, true); + item.register(plugin); + + PlayerInteractEvent event = mockCauldronEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.useItemInHand()); + } + +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCraftingTableListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCraftingTableListener.java new file mode 100644 index 000000000..03f543411 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestCraftingTableListener.java @@ -0,0 +1,149 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; + +import org.apache.commons.lang.mutable.MutableObject; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.CraftItemEvent; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.CraftingInventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CraftingTableListener; +import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +public class TestCraftingTableListener { + + private static SlimefunPlugin plugin; + private static CraftingTableListener listener; + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + listener = new CraftingTableListener(plugin); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + private CraftItemEvent mockCraftingEvent(ItemStack item) { + Recipe recipe = new ShapedRecipe(new NamespacedKey(plugin, "test_recipe"), new ItemStack(Material.EMERALD)); + Player player = server.addPlayer(); + + CraftingInventory inv = Mockito.mock(CraftingInventory.class); + Mockito.when(inv.getContents()).thenReturn(new ItemStack[] { item, null, null, null, null, null, null, null, null }); + + InventoryView view = player.openInventory(inv); + CraftItemEvent event = new CraftItemEvent(recipe, view, SlotType.RESULT, 9, ClickType.LEFT, InventoryAction.PICKUP_ALL); + + listener.onCraft(event); + return event; + } + + private PrepareItemCraftEvent mockPreCraftingEvent(ItemStack item) { + Player player = server.addPlayer(); + + CraftingInventory inv = Mockito.mock(CraftingInventory.class); + MutableObject result = new MutableObject(new ItemStack(Material.EMERALD)); + + Mockito.doAnswer(invocation -> { + ItemStack argument = invocation.getArgument(0); + result.setValue(argument); + return null; + }).when(inv).setResult(Mockito.any()); + + Mockito.when(inv.getResult()).thenAnswer(invocation -> result.getValue()); + Mockito.when(inv.getContents()).thenReturn(new ItemStack[] { null, null, item, null, null, null, null, null, null }); + + InventoryView view = player.openInventory(inv); + PrepareItemCraftEvent event = new PrepareItemCraftEvent(inv, view, false); + + listener.onPrepareCraft(event); + return event; + } + + @Test + public void testCraftEventWithoutSlimefunItems() { + CraftItemEvent event = mockCraftingEvent(new ItemStack(Material.DIAMOND)); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + + @Test + public void testCraftEventWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCK_DIAMOND", new CustomItem(Material.DIAMOND, "&cMock Diamond")); + item.register(plugin); + + CraftItemEvent event = mockCraftingEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event.getResult()); + } + + @Test + public void testCraftEventWithChangingSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CHANGING_ITEM", new CustomItem(Material.DIAMOND, "&dChanging Diamond")); + item.register(plugin); + + item.setUseableInWorkbench(true); + CraftItemEvent event = mockCraftingEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + + item.setUseableInWorkbench(false); + CraftItemEvent event2 = mockCraftingEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event2.getResult()); + } + + @Test + public void testCraftEventWithVanillaItem() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.DIAMOND, true); + item.register(plugin); + + CraftItemEvent event = mockCraftingEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + + @Test + public void testPreCraftEventWithoutSlimefunItems() { + PrepareItemCraftEvent event = mockPreCraftingEvent(new ItemStack(Material.DIAMOND)); + Assertions.assertNotNull(event.getInventory().getResult()); + } + + @Test + public void testPreCraftEventWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCK_DIAMOND2", new CustomItem(Material.DIAMOND, "&cMock Diamond")); + item.register(plugin); + + PrepareItemCraftEvent event = mockPreCraftingEvent(item.getItem()); + Assertions.assertNull(event.getInventory().getResult()); + } + + @Test + public void testPreCraftEventWithVanillaItem() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.GOLD_INGOT, true); + item.register(plugin); + + PrepareItemCraftEvent event = mockPreCraftingEvent(item.getItem()); + Assertions.assertNotNull(event.getInventory().getResult()); + } + +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestGrindstoneListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestGrindstoneListener.java new file mode 100644 index 000000000..19a74a5dc --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestGrindstoneListener.java @@ -0,0 +1,91 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.ServerMock; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; +import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.GrindstoneListener; +import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +public class TestGrindstoneListener { + + private static SlimefunPlugin plugin; + private static GrindstoneListener listener; + private static ServerMock server; + + @BeforeAll + public static void load() { + server = MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + listener = new GrindstoneListener(plugin); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + private InventoryClickEvent mockGrindStoneEvent(ItemStack item) { + Player player = server.addPlayer(); + Inventory inv = TestUtilities.mockInventory(InventoryType.GRINDSTONE, item, null); + InventoryView view = player.openInventory(inv); + InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 2, ClickType.LEFT, InventoryAction.PICKUP_ONE); + + listener.onGrindstone(event); + return event; + } + + @Test + public void testGrindStoneWithoutSlimefunItems() { + InventoryClickEvent event = mockGrindStoneEvent(new ItemStack(Material.ENCHANTED_BOOK)); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + + @Test + public void testGrindStoneWithSlimefunItem() { + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ENCHANTED_MOCK_BOOK", new CustomItem(Material.ENCHANTED_BOOK, "&6Mock")); + item.register(plugin); + + InventoryClickEvent event = mockGrindStoneEvent(item.getItem()); + Assertions.assertEquals(Result.DENY, event.getResult()); + } + + @Test + public void testGrindStoneWithVanillaItem() { + VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.ENCHANTED_BOOK, true); + item.register(plugin); + + InventoryClickEvent event = mockGrindStoneEvent(item.getItem()); + Assertions.assertEquals(Result.DEFAULT, event.getResult()); + } + + @ParameterizedTest + @EnumSource(SlimefunGuideLayout.class) + public void testGrindStoneWithSlimefunGuide(SlimefunGuideLayout layout) { + InventoryClickEvent event = mockGrindStoneEvent(SlimefunGuide.getItem(layout)); + Assertions.assertEquals(Result.DENY, event.getResult()); + } + +} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestItemPickupListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestItemPickupListener.java index 7ee7b04f8..55e58b067 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestItemPickupListener.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestItemPickupListener.java @@ -19,7 +19,7 @@ import org.junit.jupiter.params.provider.ValueSource; import be.seeseemelk.mockbukkit.MockBukkit; import be.seeseemelk.mockbukkit.ServerMock; import be.seeseemelk.mockbukkit.entity.ItemEntityMock; -import be.seeseemelk.mockbukkit.inventory.ChestInventoryMock; +import be.seeseemelk.mockbukkit.inventory.HopperInventoryMock; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal; import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener; @@ -63,7 +63,7 @@ class TestItemPickupListener { @ParameterizedTest @ValueSource(booleans = { true, false }) void testNoPickupFlagForInventories(boolean flag) { - Inventory inventory = new ChestInventoryMock(null, 5); + Inventory inventory = new HopperInventoryMock(null); Item item = new ItemEntityMock(server, UUID.randomUUID(), new ItemStack(Material.COMPASS)); if (flag) { @@ -107,7 +107,7 @@ class TestItemPickupListener { @ParameterizedTest @ValueSource(booleans = { true, false }) void testAltarProbeForInventories(boolean flag) { - Inventory inventory = new ChestInventoryMock(null, 5); + Inventory inventory = new HopperInventoryMock(null); ItemStack stack; if (flag) { diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestVanillaMachinesListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestVanillaMachinesListener.java deleted file mode 100644 index b87f39a25..000000000 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestVanillaMachinesListener.java +++ /dev/null @@ -1,302 +0,0 @@ -package io.github.thebusybiscuit.slimefun4.testing.tests.listeners; - -import org.apache.commons.lang.mutable.MutableObject; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.block.BrewingStand; -import org.bukkit.entity.Player; -import org.bukkit.event.Event.Result; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.event.inventory.CraftItemEvent; -import org.bukkit.event.inventory.InventoryAction; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.inventory.InventoryType.SlotType; -import org.bukkit.event.inventory.PrepareItemCraftEvent; -import org.bukkit.inventory.CraftingInventory; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryView; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.ShapedRecipe; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.mockito.Mockito; - -import be.seeseemelk.mockbukkit.MockBukkit; -import be.seeseemelk.mockbukkit.ServerMock; -import io.github.thebusybiscuit.cscorelib2.item.CustomItem; -import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; -import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; -import io.github.thebusybiscuit.slimefun4.implementation.listeners.VanillaMachinesListener; -import io.github.thebusybiscuit.slimefun4.testing.TestUtilities; -import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; - -public class TestVanillaMachinesListener { - - private static SlimefunPlugin plugin; - private static VanillaMachinesListener listener; - private static ServerMock server; - - @BeforeAll - public static void load() { - server = MockBukkit.mock(); - plugin = MockBukkit.load(SlimefunPlugin.class); - listener = new VanillaMachinesListener(plugin); - } - - @AfterAll - public static void unload() { - MockBukkit.unmock(); - } - - private InventoryClickEvent mockGrindStoneEvent(ItemStack item) { - Player player = server.addPlayer(); - Inventory inv = TestUtilities.mockInventory(InventoryType.GRINDSTONE, item, null); - InventoryView view = player.openInventory(inv); - InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 2, ClickType.LEFT, InventoryAction.PICKUP_ONE); - - listener.onGrindstone(event); - return event; - } - - private InventoryClickEvent mockAnvilEvent(ItemStack item) { - Player player = server.addPlayer(); - Inventory inv = TestUtilities.mockInventory(InventoryType.ANVIL, item, null, new ItemStack(Material.IRON_CHESTPLATE)); - InventoryView view = player.openInventory(inv); - InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 2, ClickType.LEFT, InventoryAction.PICKUP_ONE); - - listener.onAnvil(event); - return event; - } - - private InventoryClickEvent mockCartographyTableEvent(ItemStack item) { - Player player = server.addPlayer(); - Inventory inv = TestUtilities.mockInventory(InventoryType.CARTOGRAPHY, new ItemStack(Material.FILLED_MAP), item, new ItemStack(Material.FILLED_MAP)); - InventoryView view = player.openInventory(inv); - InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 2, ClickType.LEFT, InventoryAction.PICKUP_ONE); - - listener.onCartographyTable(event); - return event; - } - - private InventoryClickEvent mockBrewingEvent(ItemStack item) { - Player player = server.addPlayer(); - Inventory inv = TestUtilities.mockInventory(InventoryType.BREWING); - Mockito.when(inv.getHolder()).thenReturn(Mockito.mock(BrewingStand.class)); - Mockito.when(inv.getSize()).thenReturn(5); - - InventoryView view = player.openInventory(inv); - view.setCursor(item); - InventoryClickEvent event = new InventoryClickEvent(view, SlotType.CONTAINER, 1, ClickType.LEFT, InventoryAction.PICKUP_ONE); - listener.onPreBrew(event); - return event; - } - - private CraftItemEvent mockCraftingEvent(ItemStack item) { - Recipe recipe = new ShapedRecipe(new NamespacedKey(plugin, "test_recipe"), new ItemStack(Material.EMERALD)); - Player player = server.addPlayer(); - - CraftingInventory inv = Mockito.mock(CraftingInventory.class); - Mockito.when(inv.getContents()).thenReturn(new ItemStack[] { item, null, null, null, null, null, null, null, null }); - - InventoryView view = player.openInventory(inv); - CraftItemEvent event = new CraftItemEvent(recipe, view, SlotType.RESULT, 9, ClickType.LEFT, InventoryAction.PICKUP_ALL); - - listener.onCraft(event); - return event; - } - - private PrepareItemCraftEvent mockPreCraftingEvent(ItemStack item) { - Player player = server.addPlayer(); - - CraftingInventory inv = Mockito.mock(CraftingInventory.class); - MutableObject result = new MutableObject(new ItemStack(Material.EMERALD)); - - Mockito.doAnswer(invocation -> { - ItemStack argument = invocation.getArgument(0); - result.setValue(argument); - return null; - }).when(inv).setResult(Mockito.any()); - - Mockito.when(inv.getResult()).thenAnswer(invocation -> result.getValue()); - Mockito.when(inv.getContents()).thenReturn(new ItemStack[] { null, null, item, null, null, null, null, null, null }); - - InventoryView view = player.openInventory(inv); - PrepareItemCraftEvent event = new PrepareItemCraftEvent(inv, view, false); - - listener.onPrepareCraft(event); - return event; - } - - @Test - public void testGrindStoneWithoutSlimefunItems() { - InventoryClickEvent event = mockGrindStoneEvent(new ItemStack(Material.ENCHANTED_BOOK)); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testGrindStoneWithSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "ENCHANTED_MOCK_BOOK", new CustomItem(Material.ENCHANTED_BOOK, "&6Mock")); - item.register(plugin); - - InventoryClickEvent event = mockGrindStoneEvent(item.getItem()); - Assertions.assertEquals(Result.DENY, event.getResult()); - } - - @Test - public void testGrindStoneWithVanillaItem() { - VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.ENCHANTED_BOOK, true); - item.register(plugin); - - InventoryClickEvent event = mockGrindStoneEvent(item.getItem()); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @ParameterizedTest - @EnumSource(SlimefunGuideLayout.class) - public void testGrindStoneWithSlimefunGuide(SlimefunGuideLayout layout) { - InventoryClickEvent event = mockGrindStoneEvent(SlimefunGuide.getItem(layout)); - Assertions.assertEquals(Result.DENY, event.getResult()); - } - - @Test - public void testCraftEventWithoutSlimefunItems() { - CraftItemEvent event = mockCraftingEvent(new ItemStack(Material.DIAMOND)); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testCraftEventWithSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCK_DIAMOND", new CustomItem(Material.DIAMOND, "&cMock Diamond")); - item.register(plugin); - - CraftItemEvent event = mockCraftingEvent(item.getItem()); - Assertions.assertEquals(Result.DENY, event.getResult()); - } - - @Test - public void testCraftEventWithChangingSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CHANGING_ITEM", new CustomItem(Material.DIAMOND, "&dChanging Diamond")); - item.register(plugin); - - item.setUseableInWorkbench(true); - CraftItemEvent event = mockCraftingEvent(item.getItem()); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - - item.setUseableInWorkbench(false); - CraftItemEvent event2 = mockCraftingEvent(item.getItem()); - Assertions.assertEquals(Result.DENY, event2.getResult()); - } - - @Test - public void testCraftEventWithVanillaItem() { - VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.DIAMOND, true); - item.register(plugin); - - CraftItemEvent event = mockCraftingEvent(item.getItem()); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testPreCraftEventWithoutSlimefunItems() { - PrepareItemCraftEvent event = mockPreCraftingEvent(new ItemStack(Material.DIAMOND)); - Assertions.assertNotNull(event.getInventory().getResult()); - } - - @Test - public void testPreCraftEventWithSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCK_DIAMOND2", new CustomItem(Material.DIAMOND, "&cMock Diamond")); - item.register(plugin); - - PrepareItemCraftEvent event = mockPreCraftingEvent(item.getItem()); - Assertions.assertNull(event.getInventory().getResult()); - } - - @Test - public void testPreCraftEventWithVanillaItem() { - VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.GOLD_INGOT, true); - item.register(plugin); - - PrepareItemCraftEvent event = mockPreCraftingEvent(item.getItem()); - Assertions.assertNotNull(event.getInventory().getResult()); - } - - @Test - public void testAnvilWithoutSlimefunItems() { - InventoryClickEvent event = mockAnvilEvent(new ItemStack(Material.IRON_SWORD)); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testAnvilWithSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCKED_IRON_SWORD", new CustomItem(Material.IRON_SWORD, "&6Mock")); - item.register(plugin); - - InventoryClickEvent event = mockAnvilEvent(item.getItem()); - Assertions.assertEquals(Result.DENY, event.getResult()); - } - - @Test - public void testAnvilWithVanillaItem() { - VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.IRON_SWORD, true); - item.register(plugin); - - InventoryClickEvent event = mockAnvilEvent(item.getItem()); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testCartographyTableWithoutSlimefunItems() { - InventoryClickEvent event = mockCartographyTableEvent(new ItemStack(Material.PAPER)); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testCartographyTableWithSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCKED_PAPER", new CustomItem(Material.PAPER, "&6Mock")); - item.register(plugin); - - InventoryClickEvent event = mockCartographyTableEvent(item.getItem()); - Assertions.assertEquals(Result.DENY, event.getResult()); - } - - @Test - public void testCartographyTableWithVanillaItem() { - VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.PAPER, true); - item.register(plugin); - - InventoryClickEvent event = mockCartographyTableEvent(item.getItem()); - Assertions.assertEquals(Result.DEFAULT, event.getResult()); - } - - @Test - public void testBrewingWithoutSlimefunItems() { - InventoryClickEvent event = mockBrewingEvent(new ItemStack(Material.BLAZE_POWDER)); - Assertions.assertEquals(Result.ALLOW, event.getResult()); - } - - @Test - public void testBrewingWithSlimefunItem() { - SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "MOCK_POWDER", new CustomItem(Material.BLAZE_POWDER, "&6Magic Mock Powder")); - item.register(plugin); - - InventoryClickEvent event = mockBrewingEvent(item.getItem()); - Assertions.assertEquals(Result.DENY, event.getResult()); - } - - @Test - public void testBrewingWithVanillaItem() { - VanillaItem item = TestUtilities.mockVanillaItem(plugin, Material.BLAZE_POWDER, true); - item.register(plugin); - - InventoryClickEvent event = mockBrewingEvent(item.getItem()); - Assertions.assertEquals(Result.ALLOW, event.getResult()); - } -} diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/tags/TestSlimefunTags.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/tags/TestSlimefunTags.java index 7c2a6f51f..139c5c998 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/tags/TestSlimefunTags.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/tags/TestSlimefunTags.java @@ -63,6 +63,7 @@ class TestSlimefunTags { // Inclusion through a Slimefun Tag Assertions.assertTrue(SlimefunTag.SENSITIVE_MATERIALS.isTagged(Material.TORCH)); + Assertions.assertTrue(SlimefunTag.SENSITIVE_MATERIALS.isTagged(Material.OAK_PRESSURE_PLATE)); } @Test diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestMinecraftVersion.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestMinecraftVersion.java index 35664ada5..1bdb43a44 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestMinecraftVersion.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestMinecraftVersion.java @@ -11,10 +11,10 @@ class TestMinecraftVersion { @Test @DisplayName("Test if Minecraft versions match themselves") void testMatches() { - Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_13.matches("v1_13_R1")); Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_14.matches("v1_14_R2")); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_15.matches("v1_15_R1")); - Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_13.matches("v1_14_R2")); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_15.matches("v1_14_R2")); Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_14.matches("1.14.x")); Assertions.assertThrows(IllegalArgumentException.class, () -> MinecraftVersion.MINECRAFT_1_14.matches(null)); } @@ -22,18 +22,18 @@ class TestMinecraftVersion { @Test @DisplayName("Test if Minecraft versions are ordered correctly (#atLeast)") void testAtLeast() { - Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_15.isAtLeast(MinecraftVersion.MINECRAFT_1_13)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_16.isAtLeast(MinecraftVersion.MINECRAFT_1_14)); Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_15.isAtLeast(MinecraftVersion.MINECRAFT_1_14)); Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_15.isAtLeast(MinecraftVersion.MINECRAFT_1_15)); - Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_13.isAtLeast(MinecraftVersion.MINECRAFT_1_14)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_15.isAtLeast(MinecraftVersion.MINECRAFT_1_16)); } @Test @DisplayName("Test correct behaviour for MinecraftVersion.UNKNOWN.isAtleast(...)") void testAtLeastUnknown() { // Unknown should always fall back to false - Assertions.assertFalse(MinecraftVersion.UNKNOWN.isAtLeast(MinecraftVersion.MINECRAFT_1_13)); + Assertions.assertFalse(MinecraftVersion.UNKNOWN.isAtLeast(MinecraftVersion.MINECRAFT_1_14)); Assertions.assertFalse(MinecraftVersion.UNKNOWN.isAtLeast(MinecraftVersion.MINECRAFT_1_15)); Assertions.assertThrows(IllegalArgumentException.class, () -> MinecraftVersion.MINECRAFT_1_14.isAtLeast(null)); @@ -42,19 +42,18 @@ class TestMinecraftVersion { @Test @DisplayName("Test if Minecraft versions are ordered correctly (#isBefore)") void testIsBefore() { - Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_13.isBefore(MinecraftVersion.MINECRAFT_1_14)); - Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_13.isBefore(MinecraftVersion.MINECRAFT_1_15)); Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_14.isBefore(MinecraftVersion.MINECRAFT_1_15)); + Assertions.assertTrue(MinecraftVersion.MINECRAFT_1_14.isBefore(MinecraftVersion.MINECRAFT_1_16)); Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_15.isBefore(MinecraftVersion.MINECRAFT_1_15)); - Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_15.isBefore(MinecraftVersion.MINECRAFT_1_13)); + Assertions.assertFalse(MinecraftVersion.MINECRAFT_1_15.isBefore(MinecraftVersion.MINECRAFT_1_14)); } @Test @DisplayName("Test correct behaviour for MinecraftVersion.UNKNOWN.isBefore(...)") void testIsBeforeUnknown() { // Unknown should always fall back to true - Assertions.assertTrue(MinecraftVersion.UNKNOWN.isBefore(MinecraftVersion.MINECRAFT_1_13)); + Assertions.assertTrue(MinecraftVersion.UNKNOWN.isBefore(MinecraftVersion.MINECRAFT_1_14)); Assertions.assertTrue(MinecraftVersion.UNKNOWN.isBefore(MinecraftVersion.MINECRAFT_1_15)); Assertions.assertThrows(IllegalArgumentException.class, () -> MinecraftVersion.MINECRAFT_1_14.isBefore(null)); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestNumberUtils.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestNumberUtils.java new file mode 100644 index 000000000..6b33de558 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestNumberUtils.java @@ -0,0 +1,78 @@ +package io.github.thebusybiscuit.slimefun4.testing.tests.utils; + +import java.time.LocalDateTime; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; + +class TestNumberUtils { + + @Test + @DisplayName("Test NumberUtils.clamp(...)") + void testHumanize() { + // Below minimum + Assertions.assertEquals(2, NumberUtils.clamp(2, 0, 5)); + + // Normal + Assertions.assertEquals(3, NumberUtils.clamp(0, 3, 5)); + + // Above maximum + Assertions.assertEquals(20, NumberUtils.clamp(1, 100, 20)); + } + + @Test + @DisplayName("Test elapsed time string") + void testElapsedTime() { + LocalDateTime start = LocalDateTime.now(); + + LocalDateTime a = start.plusDays(1); + Assertions.assertEquals("1d", NumberUtils.getElapsedTime(start, a)); + + LocalDateTime b = start.plusHours(25); + Assertions.assertEquals("1d 1h", NumberUtils.getElapsedTime(start, b)); + + LocalDateTime c = start.plusHours(1); + Assertions.assertEquals("1h", NumberUtils.getElapsedTime(start, c)); + + LocalDateTime d = start.plusMinutes(12); + Assertions.assertEquals("< 1h", NumberUtils.getElapsedTime(start, d)); + } + + @Test + @DisplayName("Test Integer parsing") + void testIntegerParsing() { + Assertions.assertEquals(6, NumberUtils.getInt("6", 0)); + Assertions.assertEquals(12, NumberUtils.getInt("I am a String", 12)); + } + + @Test + @DisplayName("Test nullable Long") + void testNullableLong() { + Assertions.assertEquals(10, NumberUtils.getLong(10L, 20L)); + Assertions.assertEquals(20, NumberUtils.getLong(null, 20L)); + } + + @Test + @DisplayName("Test nullable Int") + void testNullableInt() { + Assertions.assertEquals(10, NumberUtils.getInt(10, 20)); + Assertions.assertEquals(20, NumberUtils.getInt((Integer) null, 20)); + } + + @Test + @DisplayName("Test nullable Float") + void testNullableFloat() { + Assertions.assertEquals(10, NumberUtils.getFloat(10F, 20F)); + Assertions.assertEquals(20, NumberUtils.getFloat(null, 20F)); + } + + @Test + @DisplayName("Test decimal rounding") + void testRounding() { + Assertions.assertEquals("5.25", NumberUtils.roundDecimalNumber(5.249999999999)); + } + +}