diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index 94ee3dbcf..3dd7a4b50 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -1,7 +1,6 @@ name: Auto approve -on: - pull_request +on: pull_request jobs: auto-approve: @@ -9,6 +8,9 @@ jobs: name: Auto approve Pull Request runs-on: ubuntu-latest + ## Only run this on the main repo + if: github.event.pull_request.head.repo.full_name == 'Slimefun/Slimefun4' + steps: - name: Approve via actions uses: hmarr/auto-approve-action@v2.1.0 diff --git a/.github/workflows/auto-squash.yml b/.github/workflows/auto-squash.yml index ab14135d2..489d97b89 100644 --- a/.github/workflows/auto-squash.yml +++ b/.github/workflows/auto-squash.yml @@ -17,12 +17,17 @@ jobs: name: Auto squash runs-on: ubuntu-latest + ## Only run this on the main repo + if: github.event.pull_request.head.repo.full_name == 'Slimefun/Slimefun4' + steps: - name: Auto squash - uses: pascalgn/automerge-action@v0.13.1 + uses: pascalgn/automerge-action@v0.14.1 env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - MERGE_METHOD: "squash" + GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} + UPDATE_RETRIES: 0 + MERGE_METHOD: squash MERGE_FORKS: false - MERGE_LABELS: "📄 Translations Update" - MERGE_COMMIT_MESSAGE: "[CI skip] New locale updates from Crowdin" + MERGE_DELETE_BRANCH: true + MERGE_LABELS: '📄 Translations Update' + MERGE_COMMIT_MESSAGE: '[CI skip] New locale updates from Crowdin' diff --git a/.github/workflows/discord-webhook.yml b/.github/workflows/discord-webhook.yml index ad787e29b..d76fa6610 100644 --- a/.github/workflows/discord-webhook.yml +++ b/.github/workflows/discord-webhook.yml @@ -12,13 +12,15 @@ jobs: name: Discord Webhook runs-on: ubuntu-latest + + ## Only run this on the main repo if: github.repository == 'Slimefun/Slimefun4' steps: - name: Checkout repository uses: actions/checkout@v2.3.4 - name: Set up Java JDK 11 - uses: actions/setup-java@v2.0.0 + uses: actions/setup-java@v2.1.0 with: distribution: 'adopt' java-version: '11' diff --git a/.github/workflows/maven-compiler.yml b/.github/workflows/maven-compiler.yml index 28d798574..f7937a839 100644 --- a/.github/workflows/maven-compiler.yml +++ b/.github/workflows/maven-compiler.yml @@ -24,7 +24,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - name: Set up JDK 1.8 - uses: actions/setup-java@v2.0.0 + uses: actions/setup-java@v2.1.0 with: distribution: 'adopt' java-version: '8' diff --git a/CHANGELOG.md b/CHANGELOG.md index d49150316..d7fdc738f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of contents -- [Release Candidate 23 (TBD)](#release-candidate-23-tbd) +- [Release Candidate 24 (TBD)](#release-candidate-24-tbd) +- [Release Candidate 23 (19 May 2021)](#release-candidate-23-19-may-2021) - [Release Candidate 22 (18 Apr 2021)](#release-candidate-22-18-apr-2021) - [Release Candidate 21 (14 Mar 2021)](#release-candidate-21-14-mar-2021) - [Release Candidate 20 (30 Jan 2021)](#release-candidate-20-30-jan-2021) @@ -23,7 +24,21 @@ - [Release Candidate 2 (29 Sep 2019)](#release-candidate-2-29-sep-2019) - [Release Candidate 1 (26 Sep 2019)](#release-candidate-1-26-sep-2019) -## Release Candidate 23 (TBD) +## Release Candidate 24 (TBD) + +#### Additions +* The speed of the Ancient Altar can now be configured in the `Items.yml` file + +#### Changes + +#### Fixes +* Fixed #3064 +* Fixed #2964 +* Fixed #2979 +* Fixed a permissions issue with `/sf charge` + +## Release Candidate 23 (19 May 2021) +https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#23 #### Additions * Added "Quartz Block -> 4 Quartz" recipe to Grind Stone @@ -35,8 +50,12 @@ * Added "Ender Lump Tier 3 -> 4 Ender Lump Tier 2" recipe to Grind Stone * Added Tier 2 Auto-Enchanter * Added Tier 2 Auto-Disenchanter +* (API) Added AsyncAutoEnchanterProcessEvent * (API) Added Category#setTier() to modify a category's position in the guide * Added the ability to disable auto (dis)enchanting with a lore - `use-ignored-lores` & `ignored-lores` in Items.yml +* Added an option to turn off the "researching animation" in the `config.yml` +* Added the option to turn off the "researching animation" within your Slimefun Guide +* Added Portable Teleporter #### Changes * Renamed "Solar Panel" to "Photovoltaic Cell" to avoid confusions with solar generators @@ -47,6 +66,7 @@ * (API) Removed deprecated "SlimefunBlockHandler" * (API) Refactored "Machine Process" API * Removed Automated Crafting Chamber +* Memory and performance improvements for Cargo and Energy networks #### Fixes * Fixed #2987 @@ -58,9 +78,13 @@ * Fixed #2927 * Fixed #3007 * Fixed #3012 +* Fixed #3013 * Fixed #3027 * Fixed #2978 +* Fixed #3041 +* Fixed #3036 * Possibly fixed #2927 +* Fixed #3060 ## Release Candidate 22 (18 Apr 2021) https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#22 diff --git a/pom.xml b/pom.xml index 984234b44..88f38419d 100644 --- a/pom.xml +++ b/pom.xml @@ -230,7 +230,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.3.0 ${project.basedir} @@ -343,19 +343,19 @@ org.junit.jupiter junit-jupiter - 5.7.1 + 5.7.2 test org.mockito mockito-core - 3.9.0 + 3.10.0 test com.github.seeseemelk MockBukkit-v1.16 - 0.34.2 + 1.0.1 test @@ -370,7 +370,7 @@ - com.github.TheBusyBiscuit + com.github.thebusybiscuit CS-CoreLib2 0.31.0 compile @@ -470,7 +470,7 @@ com.github.LoneDev6 itemsadder-api - 2.3.3 + 2.3.8 provided diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncAutoEnchanterProcessEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncAutoEnchanterProcessEvent.java new file mode 100644 index 000000000..ca1958b5c --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncAutoEnchanterProcessEvent.java @@ -0,0 +1,92 @@ +package io.github.thebusybiscuit.slimefun4.api.events; + +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter; +import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; + +import org.apache.commons.lang.Validate; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nonnull; + +/** + * An {@link Event} that is called whenever an {@link AutoEnchanter} is + * enchanting an {@link ItemStack}. + * + * @author StarWishsama + */ +public class AsyncAutoEnchanterProcessEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + private final ItemStack item; + private final ItemStack enchantedBook; + private final BlockMenu menu; + + private boolean cancelled; + + public AsyncAutoEnchanterProcessEvent(@Nonnull ItemStack item, @Nonnull ItemStack enchantedBook, @Nonnull BlockMenu menu) { + super(true); + + Validate.notNull(item, "The item to enchant cannot be null!"); + Validate.notNull(enchantedBook, "The enchanted book to enchant cannot be null!"); + Validate.notNull(menu, "The menu of auto-enchanter cannot be null!"); + + this.item = item; + this.enchantedBook = enchantedBook; + this.menu = menu; + } + + /** + * This returns the {@link ItemStack} that is being enchanted. + * + * @return The {@link ItemStack} that is being enchanted + */ + @Nonnull + public ItemStack getItem() { + return item; + } + + /** + * This returns the {@link ItemStack} that is being used enchanted book + * + * @return The {@link ItemStack} that is being used enchanted book + */ + @Nonnull + public ItemStack getEnchantedBook() { + return enchantedBook; + } + + /** + * This returns the {@link AutoEnchanter}'s {@link BlockMenu} + * + * @return The {@link BlockMenu} of {@link AutoEnchanter} that is enchanting item + */ + @Nonnull + public BlockMenu getMenu() { + return menu; + } + + @Nonnull + public static HandlerList getHandlerList() { + return handlers; + } + + @Nonnull + @Override + public HandlerList getHandlers() { + return getHandlerList(); + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java index fa292e098..c918b34bb 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/TeleportationManager.java @@ -51,12 +51,24 @@ public final class TeleportationManager { */ private final Set teleporterUsers = new HashSet<>(); + /** + * Opens the GUI of the teleporter and calculates the network complexity of the {@link Player} + * + * @param p {@link Player} to be teleported + * @param ownerUUID {@link UUID} of the {@link Player} who owns the teleporter device + * @param b {@link Block} from where the {@link Player} is being teleported + */ @ParametersAreNonnullByDefault - public void openTeleporterGUI(Player p, UUID uuid, Block b, int complexity) { + public void openTeleporterGUI(Player p, UUID ownerUUID, Block b) { + openTeleporterGUI(p, ownerUUID, b, SlimefunPlugin.getGPSNetwork().getNetworkComplexity(ownerUUID)); + } + + @ParametersAreNonnullByDefault + public void openTeleporterGUI(Player p, UUID ownerUUID, Block b, int complexity) { if (teleporterUsers.add(p.getUniqueId())) { p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1F, 1F); - PlayerProfile.fromUUID(uuid, profile -> { + PlayerProfile.fromUUID(ownerUUID, profile -> { ChestMenu menu = new ChestMenu("&3Teleporter"); menu.addMenuCloseHandler(pl -> teleporterUsers.remove(pl.getUniqueId())); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java index 015279689..cd9c81bec 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/Network.java @@ -4,14 +4,18 @@ import java.util.ArrayDeque; import java.util.HashSet; import java.util.Queue; import java.util.Set; +import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.lang.Validate; +import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Particle; +import org.bukkit.World; +import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener; @@ -20,6 +24,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListen * An abstract Network class to manage networks in a stateful way * * @author meiamsome + * @author TheBusyBiscuit * * @see NetworkListener * @see NetworkManager @@ -37,8 +42,19 @@ public abstract class Network { */ protected Location regulator; + /** + * The {@link UUID} of the {@link World} this {@link Network} exists within. + */ + private final UUID worldId; + + /** + * This {@link Set} holds all {@link Network} positions that are part of this {@link Network}. + * The {@link World} should be equal for all positions, therefore we can save memory by simply + * storing {@link BlockPosition#getAsLong(int, int, int)}. + */ + private final Set positions = new HashSet<>(); + private final Queue nodeQueue = new ArrayDeque<>(); - protected final Set connectedLocations = new HashSet<>(); protected final Set regulatorNodes = new HashSet<>(); protected final Set connectorNodes = new HashSet<>(); protected final Set terminusNodes = new HashSet<>(); @@ -57,8 +73,9 @@ public abstract class Network { this.manager = manager; this.regulator = regulator; + this.worldId = regulator.getWorld().getUID(); - connectedLocations.add(regulator); + positions.add(BlockPosition.getAsLong(regulator)); nodeQueue.add(regulator.clone()); } @@ -115,7 +132,10 @@ public abstract class Network { * The {@link Location} to add */ protected void addLocationToNetwork(@Nonnull Location l) { - if (connectedLocations.add(l.clone())) { + Validate.notNull(l, "You cannot add a Location to a Network which is null!"); + Validate.isTrue(l.getWorld().getUID().equals(worldId), "Networks cannot exist in multiple worlds!"); + + if (positions.add(BlockPosition.getAsLong(l))) { markDirty(l); } } @@ -144,10 +164,14 @@ public abstract class Network { * @return Whether the given {@link Location} is part of this {@link Network} */ public boolean connectsTo(@Nonnull Location l) { - if (regulator.equals(l)) { + Validate.notNull(l, "The Location cannot be null."); + + if (this.regulator.equals(l)) { return true; + } else if (!l.getWorld().getUID().equals(this.worldId)) { + return false; } else { - return connectedLocations.contains(l); + return positions.contains(BlockPosition.getAsLong(l)); } } @@ -225,7 +249,8 @@ public abstract class Network { */ public void display() { if (manager.isVisualizerEnabled()) { - SlimefunPlugin.runSync(new NetworkVisualizer(this)); + // TODO: Make Color configurable / network-dependent + SlimefunPlugin.runSync(new NetworkVisualizer(this, Color.BLUE)); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java index 7933c51ab..14ab69c85 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/network/NetworkVisualizer.java @@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.api.network; import javax.annotation.Nonnull; +import org.apache.commons.lang.Validate; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Particle; @@ -18,7 +19,7 @@ class NetworkVisualizer implements Runnable { /** * The {@link DustOptions} define the {@link Color} and size of our particles. */ - private final DustOptions options = new DustOptions(Color.BLUE, 3.5F); + private final DustOptions particleOptions; /** * This is our {@link Network} instance. @@ -31,8 +32,12 @@ class NetworkVisualizer implements Runnable { * @param network * The {@link Network} to visualize */ - NetworkVisualizer(@Nonnull Network network) { + NetworkVisualizer(@Nonnull Network network, @Nonnull Color color) { + Validate.notNull(network, "The network should not be null."); + Validate.notNull(color, "The color cannot be null."); + this.network = network; + this.particleOptions = new DustOptions(color, 3F); } @Override @@ -53,7 +58,7 @@ class NetworkVisualizer implements Runnable { * The {@link Location} of our node */ private void spawnParticles(@Nonnull Location l) { - l.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5, l.getY() + 0.5, l.getZ() + 0.5, 1, 0, 0, 0, 1, options); + l.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5, l.getY() + 0.5, l.getZ() + 0.5, 1, 0, 0, 0, 1, particleOptions); } } 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 e6c146590..6658c3b69 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java @@ -69,6 +69,7 @@ public final class SlimefunRegistry { private boolean enableResearches; private boolean freeCreativeResearches; private boolean researchFireworks; + private boolean disableLearningAnimation; private boolean logDuplicateBlockEntries; private boolean talismanActionBarMessages; @@ -109,6 +110,7 @@ public final class SlimefunRegistry { backwardsCompatibility = cfg.getBoolean("options.backwards-compatibility"); freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode"); researchFireworks = cfg.getBoolean("researches.enable-fireworks"); + disableLearningAnimation = cfg.getBoolean("researches.disable-learning-animation"); logDuplicateBlockEntries = cfg.getBoolean("options.log-duplicate-block-entries"); talismanActionBarMessages = cfg.getBoolean("talismans.use-actionbar"); } @@ -238,6 +240,15 @@ public final class SlimefunRegistry { return researchFireworks; } + /** + * Returns whether the research learning animations is disabled + * + * @return Whether the research learning animations is disabled + */ + public boolean isLearningAnimationDisabled() { + return disableLearningAnimation; + } + /** * This method returns a {@link List} of every enabled {@link MultiBlock}. * diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/BackpackCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/BackpackCommand.java index cdc65a340..d1914e667 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/BackpackCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/BackpackCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; @@ -11,10 +13,22 @@ import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.RestoredBackpack; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; +/** + * This command that allows for backpack retrieval in the event they are lost. + * The command accepts a name and id, if those match up it spawns a Medium Backpack + * with the correct lore set in the sender's inventory. + * + * @author Sfiguz7 + * + * @see RestoredBackpack + * + */ class BackpackCommand extends SubCommand { + @ParametersAreNonnullByDefault BackpackCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "backpack", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ChargeCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ChargeCommand.java index 8d3a64f09..c06d5fbd1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ChargeCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ChargeCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -19,6 +21,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; */ class ChargeCommand extends SubCommand { + @ParametersAreNonnullByDefault ChargeCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "charge", false); } @@ -31,10 +34,11 @@ class ChargeCommand extends SubCommand { @Override public void onExecute(CommandSender sender, String[] args) { if (sender instanceof Player) { - if (sender.hasPermission("slimefun.charge.command")) { + if (sender.hasPermission("slimefun.command.charge")) { Player p = (Player) sender; ItemStack item = p.getInventory().getItemInMainHand(); SlimefunItem slimefunItem = SlimefunItem.getByItem(item); + if (slimefunItem instanceof Rechargeable) { Rechargeable rechargeableItem = (Rechargeable) slimefunItem; rechargeableItem.setItemCharge(item, rechargeableItem.getMaxItemCharge(item)); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/CheatCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/CheatCommand.java index 3a4e18aca..659023daa 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/CheatCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/CheatCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -10,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class CheatCommand extends SubCommand { + @ParametersAreNonnullByDefault CheatCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "cheat", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/DebugFishCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/DebugFishCommand.java index 1900a471d..619b6d2ec 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/DebugFishCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/DebugFishCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -10,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class DebugFishCommand extends SubCommand { + @ParametersAreNonnullByDefault DebugFishCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "debug_fish", true); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java index dc3e4f00d..f0efe22d0 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java @@ -16,12 +16,15 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; +import javax.annotation.ParametersAreNonnullByDefault; + class GiveCommand extends SubCommand { private static final String PLACEHOLDER_PLAYER = "%player%"; private static final String PLACEHOLDER_ITEM = "%item%"; private static final String PLACEHOLDER_AMOUNT = "%amount%"; + @ParametersAreNonnullByDefault GiveCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "give", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GuideCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GuideCommand.java index c0f6a1949..94b49f630 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GuideCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GuideCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -11,6 +13,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class GuideCommand extends SubCommand { + @ParametersAreNonnullByDefault GuideCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "guide", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/HelpCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/HelpCommand.java index 43e43feb3..6ff08892f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/HelpCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/HelpCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; @@ -8,6 +10,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class HelpCommand extends SubCommand { + @ParametersAreNonnullByDefault HelpCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "help", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/OpenGuideCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/OpenGuideCommand.java index 8947d989f..7e4b88d7b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/OpenGuideCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/OpenGuideCommand.java @@ -13,6 +13,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class OpenGuideCommand extends SubCommand { + @ParametersAreNonnullByDefault OpenGuideCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "open_guide", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java index 9c3d29889..59dbd7dd4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java @@ -3,6 +3,9 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; import java.util.Optional; import java.util.function.UnaryOperator; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -18,6 +21,7 @@ class ResearchCommand extends SubCommand { private static final String PLACEHOLDER_PLAYER = "%player%"; private static final String PLACEHOLDER_RESEARCH = "%research%"; + @ParametersAreNonnullByDefault ResearchCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "research", false); } @@ -57,6 +61,7 @@ class ResearchCommand extends SubCommand { } } + @ParametersAreNonnullByDefault private void giveResearch(CommandSender sender, Player p, String input) { Optional research = getResearchFromString(input); @@ -70,6 +75,7 @@ class ResearchCommand extends SubCommand { } } + @ParametersAreNonnullByDefault private void researchAll(CommandSender sender, PlayerProfile profile, Player p) { for (Research res : SlimefunPlugin.getRegistry().getResearches()) { if (!profile.hasUnlocked(res)) { @@ -80,6 +86,7 @@ class ResearchCommand extends SubCommand { } } + @ParametersAreNonnullByDefault private void reset(PlayerProfile profile, Player p) { for (Research research : SlimefunPlugin.getRegistry().getResearches()) { profile.setResearched(research, false); @@ -88,7 +95,8 @@ class ResearchCommand extends SubCommand { SlimefunPlugin.getLocalization().sendMessage(p, "commands.research.reset", true, msg -> msg.replace(PLACEHOLDER_PLAYER, p.getName())); } - private Optional getResearchFromString(String input) { + @Nonnull + private Optional getResearchFromString(@Nonnull String input) { if (!input.contains(":")) { return Optional.empty(); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SearchCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SearchCommand.java index c52927221..56a4faaa1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SearchCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SearchCommand.java @@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; import java.util.Arrays; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -14,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class SearchCommand extends SubCommand { + @ParametersAreNonnullByDefault SearchCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "search", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SlimefunSubCommands.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SlimefunSubCommands.java index 10378c3ff..488750f99 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SlimefunSubCommands.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/SlimefunSubCommands.java @@ -4,6 +4,8 @@ import java.util.Collection; import java.util.LinkedList; import java.util.List; +import javax.annotation.Nonnull; + import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; @@ -20,7 +22,8 @@ public final class SlimefunSubCommands { private SlimefunSubCommands() {} - public static Collection getAllCommands(SlimefunCommand cmd) { + @Nonnull + public static Collection getAllCommands(@Nonnull SlimefunCommand cmd) { SlimefunPlugin plugin = cmd.getPlugin(); List commands = new LinkedList<>(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/StatsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/StatsCommand.java index 1bb18b3e6..a6e3651fb 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/StatsCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/StatsCommand.java @@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; import java.util.Optional; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; @@ -14,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class StatsCommand extends SubCommand { + @ParametersAreNonnullByDefault StatsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "stats", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TeleporterCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TeleporterCommand.java index 2d7d56ba5..fbd31fe07 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TeleporterCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TeleporterCommand.java @@ -1,5 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockFace; @@ -12,6 +14,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; class TeleporterCommand extends SubCommand { + @ParametersAreNonnullByDefault TeleporterCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "teleporter", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java index 3673f48a6..849abbef4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/TimingsCommand.java @@ -24,6 +24,7 @@ class TimingsCommand extends SubCommand { private static final String FLAG_PREFIX = "--"; private final Set flags = new HashSet<>(Arrays.asList("verbose")); + @ParametersAreNonnullByDefault TimingsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "timings", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java index 63d9f13e9..7c69fbaae 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java @@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands; import java.util.Collection; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -29,6 +30,7 @@ import net.md_5.bungee.api.chat.hover.content.Text; */ class VersionsCommand extends SubCommand { + @ParametersAreNonnullByDefault VersionsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) { super(plugin, cmd, "versions", false); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java index 873ce5105..8dceaa855 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java @@ -3,12 +3,14 @@ package io.github.thebusybiscuit.slimefun4.core.guide; import java.util.function.Consumer; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings; import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide; @@ -18,7 +20,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; /** * This interface is used for the different implementations that add behaviour * to the {@link SlimefunGuide}. - * + * * @author TheBusyBiscuit * * @see SlimefunGuideMode @@ -30,7 +32,7 @@ public interface SlimefunGuideImplementation { /** * Every {@link SlimefunGuideImplementation} can be associated with a * {@link SlimefunGuideMode}. - * + * * @return The mode this {@link SlimefunGuideImplementation} represents */ @Nonnull @@ -40,22 +42,28 @@ public interface SlimefunGuideImplementation { * Returns the {@link ItemStack} representation for this {@link SlimefunGuideImplementation}. * In other words: The {@link ItemStack} you hold in your hand and that you use to * open your {@link SlimefunGuide} - * + * * @return The {@link ItemStack} representation for this {@link SlimefunGuideImplementation} */ @Nonnull ItemStack getItem(); + @ParametersAreNonnullByDefault void openMainMenu(PlayerProfile profile, int page); + @ParametersAreNonnullByDefault void openCategory(PlayerProfile profile, Category category, int page); + @ParametersAreNonnullByDefault void openSearch(PlayerProfile profile, String input, boolean addToHistory); + @ParametersAreNonnullByDefault void displayItem(PlayerProfile profile, ItemStack item, int index, boolean addToHistory); + @ParametersAreNonnullByDefault void displayItem(PlayerProfile profile, SlimefunItem item, boolean addToHistory); + @ParametersAreNonnullByDefault default void unlockItem(Player p, SlimefunItem sfitem, Consumer callback) { Research research = sfitem.getResearch(); @@ -63,7 +71,9 @@ public interface SlimefunGuideImplementation { research.unlock(p, true, callback); } else { p.setLevel(p.getLevel() - research.getCost()); - research.unlock(p, false, callback); + + boolean skipLearningAnimation = SlimefunPlugin.getRegistry().isLearningAnimationDisabled() || !SlimefunGuideSettings.hasLearningAnimationEnabled(p); + research.unlock(p, skipLearningAnimation, callback); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/LearningAnimationOption.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/LearningAnimationOption.java new file mode 100644 index 000000000..2b949d429 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/LearningAnimationOption.java @@ -0,0 +1,74 @@ +package io.github.thebusybiscuit.slimefun4.core.guide.options; + +import java.util.List; +import java.util.Optional; + +import javax.annotation.Nonnull; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; + +/** + * {@link LearningAnimationOption} represents a setting in the Slimefun guide book. + * It allows users to disable/enable the "learning animation", + * the information in chat when doing a Slimefun research. + * + * @author martinbrom + */ +class LearningAnimationOption implements SlimefunGuideOption { + + @Nonnull + @Override + public SlimefunAddon getAddon() { + return SlimefunPlugin.instance(); + } + + @Nonnull + @Override + public NamespacedKey getKey() { + return new NamespacedKey(SlimefunPlugin.instance(), "research_learning_animation"); + } + + @Nonnull + @Override + public Optional getDisplayItem(@Nonnull Player p, @Nonnull ItemStack guide) { + if (SlimefunPlugin.getRegistry().isLearningAnimationDisabled()) { + return Optional.empty(); + } else { + boolean enabled = getSelectedOption(p, guide).orElse(true); + String optionState = enabled ? "enabled" : "disabled"; + List lore = SlimefunPlugin.getLocalization().getMessages(p, "guide.options.learning-animation." + optionState + ".text"); + lore.add(""); + lore.add("&7\u21E8 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.options.learning-animation." + optionState + ".click")); + + ItemStack item = new CustomItem(enabled ? Material.MAP : Material.PAPER, lore); + return Optional.of(item); + } + } + + @Override + public void onClick(@Nonnull Player p, @Nonnull ItemStack guide) { + setSelectedOption(p, guide, !getSelectedOption(p, guide).orElse(true)); + SlimefunGuideSettings.openSettings(p, guide); + } + + @Override + public Optional getSelectedOption(@Nonnull Player p, @Nonnull ItemStack guide) { + NamespacedKey key = getKey(); + boolean value = !PersistentDataAPI.hasByte(p, key) || PersistentDataAPI.getByte(p, key) == (byte) 1; + return Optional.of(value); + } + + @Override + public void setSelectedOption(@Nonnull Player p, @Nonnull ItemStack guide, @Nonnull Boolean value) { + PersistentDataAPI.setByte(p, getKey(), (byte) (value.booleanValue() ? 1 : 0)); + } + +} 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 6662fcb22..7c74f80a8 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 @@ -47,6 +47,7 @@ public final class SlimefunGuideSettings { static { options.add(new GuideModeOption()); options.add(new FireworksOption()); + options.add(new LearningAnimationOption()); options.add(new PlayerLanguageOption()); } @@ -238,15 +239,51 @@ public final class SlimefunGuideSettings { * @return Whether this {@link Player} wants to see fireworks when unlocking a {@link Research} */ public static boolean hasFireworksEnabled(@Nonnull Player p) { + return getOptionValue(p, FireworksOption.class, true); + } + + /** + * This method checks if the given {@link Player} has enabled the {@link LearningAnimationOption} + * in their {@link SlimefunGuide}. + * If they enabled this setting, they will see messages in chat about the progress of their {@link Research}. + * + * @param p + * The {@link Player} + * + * @return Whether this {@link Player} wants to info messages in chat when unlocking a {@link Research} + */ + public static boolean hasLearningAnimationEnabled(@Nonnull Player p) { + return getOptionValue(p, LearningAnimationOption.class, true); + } + + /** + * Helper method to get the value of a {@link SlimefunGuideOption} that the {@link Player} + * has set in their {@link SlimefunGuide} + * + * @param p + * The {@link Player} + * @param optionsClass + * Class of the {@link SlimefunGuideOption} to get the value of + * @param defaultValue + * Default value to return in case the option is not found at all or has no value set + * @param + * Type of the {@link SlimefunGuideOption} + * @param + * Type of the {@link SlimefunGuideOption} value + * + * @return The value of given {@link SlimefunGuideOption} + */ + @Nonnull + private static , V> V getOptionValue(@Nonnull Player p, @Nonnull Class optionsClass, @Nonnull V defaultValue) { for (SlimefunGuideOption option : options) { - if (option instanceof FireworksOption) { - FireworksOption fireworks = (FireworksOption) option; + if (optionsClass.isInstance(option)) { + T o = optionsClass.cast(option); ItemStack guide = SlimefunGuide.getItem(SlimefunGuideMode.SURVIVAL_MODE); - return fireworks.getSelectedOption(p, guide).orElse(true); + return o.getSelectedOption(p, guide).orElse(defaultValue); } } - return true; + return defaultValue; } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java index 66216750d..dd726af28 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/NetworkManager.java @@ -1,9 +1,11 @@ package io.github.thebusybiscuit.slimefun4.core.networks; import java.util.ArrayList; -import java.util.LinkedList; +import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -12,16 +14,21 @@ import org.apache.commons.lang.Validate; import org.bukkit.Location; import org.bukkit.Server; +import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; import io.github.thebusybiscuit.cscorelib2.config.Config; +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.network.Network; import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener; +import me.mrCookieSlime.Slimefun.api.BlockStorage; /** * The {@link NetworkManager} is responsible for holding all instances of {@link Network} * and providing some utility methods that would have probably been static otherwise. * * @author TheBusyBiscuit + * @author meiamsome * * @see Network * @see NetworkListener @@ -32,7 +39,16 @@ public class NetworkManager { private final int maxNodes; private final boolean enableVisualizer; private final boolean deleteExcessItems; - private final List networks = new LinkedList<>(); + + /** + * Fixes #3041 + * + * We use a {@link CopyOnWriteArrayList} here to ensure thread-safety. + * This {@link List} is also much more frequently read than being written to. + * Therefore a {@link CopyOnWriteArrayList} should be perfect for this, even + * if insertions come at a slight cost. + */ + private final List networks = new CopyOnWriteArrayList<>(); /** * This creates a new {@link NetworkManager} with the given capacity. @@ -93,12 +109,13 @@ public class NetworkManager { /** * This returns a {@link List} of every {@link Network} on the {@link Server}. + * The returned {@link List} is not modifiable. * * @return A {@link List} containing every {@link Network} on the {@link Server} */ @Nonnull public List getNetworkList() { - return networks; + return Collections.unmodifiableList(networks); } @Nonnull @@ -169,11 +186,30 @@ public class NetworkManager { public void updateAllNetworks(@Nonnull Location l) { Validate.notNull(l, "The Location cannot be null"); - // No need to create a sublist and loop through it if there are no Networks - if (!networks.isEmpty()) { + try { + /* + * No need to create a sublist and loop through it if + * there aren't even any networks on the server. + */ + if (networks.isEmpty()) { + return; + } + + /* + * Only a Slimefun block can be part of a Network. + * This check helps to speed up performance. + * + * (Skip for Unit Tests as they don't support block info yet) + */ + if (!BlockStorage.hasBlockInfo(l) && SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) { + return; + } + for (Network network : getNetworksFromLocation(l, Network.class)) { network.markDirty(l); } + } catch (Exception x) { + SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception was thrown while causing a networks update @ " + new BlockPosition(l)); } } 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 28d766fb4..7e5b166e1 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 @@ -74,6 +74,7 @@ class ContributionsConnector extends GitHubConnector { aliases.put("bverhoeven", "soczol"); aliases.put("ramdon-person", "ramdon_person"); aliases.put("NCBPFluffyBear", "FluffyBear_"); + aliases.put("martinbrom", "OneTime97"); } /** 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 051a427fe..129c285b2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -745,6 +745,7 @@ public final class SlimefunItems { public static final SlimefunItemStack GPS_TELEPORTATION_MATRIX = new SlimefunItemStack("GPS_TELEPORTATION_MATRIX", Material.IRON_BLOCK, "&bGPS Teleporter Matrix", "", "&fThis is your Teleporter's Main Component", "&fThis Matrix allows Players to choose from all", "&fWaypoints made by the Player who has placed", "&fthis Device."); public static final SlimefunItemStack GPS_ACTIVATION_DEVICE_SHARED = new SlimefunItemStack("GPS_ACTIVATION_DEVICE_SHARED", Material.STONE_PRESSURE_PLATE, "&fGPS Activation Device &3(Shared)", "", "&fPlace this onto a Teleportation Matrix", "&fand step onto this Plate to activate", "&fthe Teleportation Process"); public static final SlimefunItemStack GPS_ACTIVATION_DEVICE_PERSONAL = new SlimefunItemStack("GPS_ACTIVATION_DEVICE_PERSONAL", Material.STONE_PRESSURE_PLATE, "&fGPS Activation Device &a(Personal)", "", "&fPlace this onto a Teleportation Matrix", "&fand step onto this Plate to activate", "&fthe Teleportation Process", "", "&fThis Version only allows the Person who", "&fplaced this Device to use it"); + public static final SlimefunItemStack PORTABLE_TELEPORTER = new SlimefunItemStack("PORTABLE_TELEPORTER", Material.COMPASS, "&bPortable Teleporter", "", "&fThis device allows you to teleport", "&fto your waypoints from anywhere", "", LoreBuilder.powerCharged(0, 50), "", "&eRight Click&7 to use"); public static final SlimefunItemStack ELEVATOR_PLATE = new SlimefunItemStack("ELEVATOR_PLATE", Material.STONE_PRESSURE_PLATE, "&bElevator Plate", "", "&fPlace an Elevator Plate on every floor", "&fand you will be able to teleport between them.", "", "&eRight Click this Block &7to name it"); public static final SlimefunItemStack INFUSED_HOPPER = new SlimefunItemStack("INFUSED_HOPPER", Material.HOPPER, "&5Infused Hopper", "", "&fAutomatically picks up nearby Items in a 7x7x7", "&fRadius when placed."); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientAltar.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientAltar.java index 232d2a215..9c1382e31 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientAltar.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/altar/AncientAltar.java @@ -3,9 +3,14 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.altar; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.events.AncientAltarCraftEvent; +import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; +import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener; import io.github.thebusybiscuit.slimefun4.implementation.tasks.AncientAltarTask; import me.mrCookieSlime.Slimefun.Lists.RecipeType; @@ -17,41 +22,47 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; * The {@link AncientAltar} is a multiblock structure. * The altar itself stands in the center, surrounded by {@link AncientPedestal Pedestals}, it is used * to craft various magical items. - * + * * @author TheBusyBiscuit - * + * @author martinbrom + * * @see AncientAltarListener * @see AncientAltarTask * @see AncientAltarCraftEvent * @see AncientPedestal - * */ public class AncientAltar extends SlimefunItem { - private final int speed; + /** + * This number represents a delay in ticks between two ritual steps. + * The whole ritual process consists of 36 steps, an item is consumed every 4 steps (8 times) + * and the output is spawned after the 36th step completes. + */ + private static final int DEFAULT_STEP_DELAY = 8; + private final List recipes = new ArrayList<>(); - public AncientAltar(Category category, int speed, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + private final ItemSetting stepDelay = new IntRangeSetting(this, "step-delay", 0, DEFAULT_STEP_DELAY, Integer.MAX_VALUE); + + @ParametersAreNonnullByDefault + public AncientAltar(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); - if (speed < 1) { - throw new IllegalArgumentException("The speed must be at least 1."); - } - - this.speed = speed; + addItemSetting(stepDelay); } /** - * This returns the speed of this {@link AncientAltar}. - * This number determines how much ticks happen inbetween a step in the ritual animation. - * The default is 8 ticks. - * - * @return The speed of this {@link AncientAltar} + * This returns the delay of this {@link AncientAltar}. + * This number determines how many ticks happen in between a step in the ritual animation. + * The default is {@value #DEFAULT_STEP_DELAY} ticks. + * + * @return The delay between two ritual steps of this {@link AncientAltar} */ - public int getSpeed() { - return speed; + public int getStepDelay() { + return stepDelay.getValue(); } + @Nonnull public List getRecipes() { return recipes; } 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 d8fda27ae..890113721 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 @@ -684,7 +684,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, if ("false".equals(data.getString("paused"))) { BlockMenu menu = BlockStorage.getInventory(b); - + String fuelData = data.getString("fuel"); float fuel = fuelData == null ? 0 : Float.parseFloat(fuelData); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java index eb5775bf1..eb7499f78 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java @@ -67,15 +67,16 @@ public class WoodcutterAndroid extends ProgrammableAndroid { private void breakLog(Block log, Block android, BlockMenu menu, BlockFace face) { ItemStack drop = new ItemStack(log.getType()); - if (menu.fits(drop, getOutputSlots())) { - menu.pushItem(drop, getOutputSlots()); - log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType()); + // We try to push the log into the android's inventory, but nothing happens if it does not fit + menu.pushItem(drop, getOutputSlots()); - if (log.getY() == android.getRelative(face).getY()) { - replant(log); - } else { - log.setType(Material.AIR); - } + log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType()); + + // If the android just chopped the bottom log, we replant the appropriate sapling + if (log.getY() == android.getRelative(face).getY()) { + replant(log); + } else { + log.setType(Material.AIR); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java index 45cfb447f..274bf6337 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java @@ -1,18 +1,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting; -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nullable; -import javax.annotation.ParametersAreNonnullByDefault; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; - import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils; +import io.github.thebusybiscuit.slimefun4.api.events.AsyncAutoEnchanterProcessEvent; import io.github.thebusybiscuit.slimefun4.api.events.AutoEnchantEvent; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; @@ -20,6 +9,16 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.HashMap; +import java.util.Map; /** * The {@link AutoEnchanter}, in contrast to the {@link AutoDisenchanter}, adds @@ -65,10 +64,10 @@ public class AutoEnchanter extends AbstractEnchantmentMachine { return null; } - ItemStack secondItem = menu.getItemInSlot(slot); + ItemStack enchantedBook = menu.getItemInSlot(slot); - if (secondItem != null && secondItem.getType() == Material.ENCHANTED_BOOK) { - return enchant(menu, item, secondItem); + if (enchantedBook != null && enchantedBook.getType() == Material.ENCHANTED_BOOK) { + return enchant(menu, item, enchantedBook); } } @@ -78,6 +77,14 @@ public class AutoEnchanter extends AbstractEnchantmentMachine { @Nullable @ParametersAreNonnullByDefault protected MachineRecipe enchant(BlockMenu menu, ItemStack target, ItemStack enchantedBook) { + // Call an event so other Plugins can modify it. + AsyncAutoEnchanterProcessEvent event = new AsyncAutoEnchanterProcessEvent(target, enchantedBook, menu); + Bukkit.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return null; + } + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) enchantedBook.getItemMeta(); Map enchantments = new HashMap<>(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/teleporter/PortableTeleporter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/teleporter/PortableTeleporter.java new file mode 100644 index 000000000..8057f4c6b --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/teleporter/PortableTeleporter.java @@ -0,0 +1,61 @@ +package io.github.thebusybiscuit.slimefun4.implementation.items.teleporter; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; +import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; +import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable; +import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import me.mrCookieSlime.Slimefun.Lists.RecipeType; +import me.mrCookieSlime.Slimefun.Objects.Category; +import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; + +/** + * This item allows a {@link Player} to access and teleport to his waypoints + * from anywhere. + * + * @author martinbrom + * + * @see Teleporter + */ +public class PortableTeleporter extends SimpleSlimefunItem implements Rechargeable { + + private static final int CAPACITY = 50; + private static final int DEFAULT_COST = 10; + + private final ItemSetting cost = new IntRangeSetting(this, "teleportation-cost", 0, DEFAULT_COST, CAPACITY); + + @ParametersAreNonnullByDefault + public PortableTeleporter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(category, item, recipeType, recipe); + + addItemSetting(cost); + } + + @Nonnull + @Override + public ItemUseHandler getItemHandler() { + return e -> { + ItemStack item = e.getItem(); + e.cancel(); + + if (removeItemCharge(item, cost.getValue())) { + Player p = e.getPlayer(); + SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI( + p, p.getUniqueId(), p.getLocation().getBlock().getRelative(BlockFace.DOWN)); + } + }; + } + + @Override + public float getMaxItemCharge(ItemStack item) { + return CAPACITY; + } +} 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 e3befeae2..3036f2484 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 @@ -156,7 +156,14 @@ public class ExplosiveTool extends SimpleSlimefunItem implements */ BlockBreakEvent dummyEvent = new BlockBreakEvent(b, e.getPlayer()); - if (!sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops)) && !dummyEvent.isCancelled()) { + /* + * Fixes #3036 and handling in general. + * Call the BlockBreakHandler if the block has one to allow for proper handling. + */ + sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops)); + + // Make sure the event wasn't cancelled by the BlockBreakHandler. + if (!dummyEvent.isCancelled()) { drops.addAll(sfItem.getDrops(p)); b.setType(Material.AIR); BlockStorage.clearBlockInfo(b); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java index c2cada5b9..0ad368509 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java @@ -94,7 +94,9 @@ public class GoldPan extends SimpleSlimefunItem implements Recip randomizer.clear(); for (GoldPanDrop setting : drops) { - randomizer.add(setting.getOutput(), setting.getValue()); + if (setting.getValue() > 0) { + randomizer.add(setting.getOutput(), setting.getValue()); + } } } @@ -112,11 +114,13 @@ public class GoldPan extends SimpleSlimefunItem implements Recip return item != null ? item : new ItemStack(Material.AIR); } + @Nonnull @Override public String getLabelLocalPath() { return "guide.tooltips.recipes.gold-pan"; } + @Nonnull @Override public ItemUseHandler getItemHandler() { return e -> { @@ -158,6 +162,7 @@ public class GoldPan extends SimpleSlimefunItem implements Recip }; } + @Nonnull @Override public List getDisplayRecipes() { List recipes = new LinkedList<>(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java index e11429d39..10d9661d2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java @@ -44,6 +44,7 @@ public class ExplosiveBow extends SlimefunBow { addItemSetting(range); } + @Nonnull @Override public BowShootHandler onShoot() { return (e, target) -> { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java index 78f176113..1c74652cd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/IcyBow.java @@ -1,10 +1,12 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.weapons; +import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.Effect; import org.bukkit.Material; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; @@ -16,8 +18,9 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; /** * The {@link IcyBow} is a special kind of bow which slows down any * {@link LivingEntity} it hits. - * + * * @author TheBusyBiscuit + * @author martinbrom * */ public class IcyBow extends SlimefunBow { @@ -27,9 +30,19 @@ public class IcyBow extends SlimefunBow { super(category, item, recipe); } + @Nonnull @Override public BowShootHandler onShoot() { return (e, n) -> { + if (n instanceof Player) { + Player p = (Player) n; + + // Fixes #3060 - Don't apply effects if the arrow was successfully blocked. + if (p.isBlocking() && e.getFinalDamage() <= 0) { + return; + } + } + n.getWorld().playEffect(n.getLocation(), Effect.STEP_SOUND, Material.ICE); n.getWorld().playEffect(n.getEyeLocation(), Effect.STEP_SOUND, Material.ICE); n.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 10)); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java index d2dfd5534..81e683b8d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java @@ -225,7 +225,7 @@ public class AncientAltarListener implements Listener { b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1); - AncientAltarTask task = new AncientAltarTask(this, b, altarItem.getSpeed(), result.get(), pedestals, consumed, p); + AncientAltarTask task = new AncientAltarTask(this, b, altarItem.getStepDelay(), result.get(), pedestals, consumed, p); SlimefunPlugin.runSync(task, 10L); } else { altars.remove(b); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/NetworkListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/NetworkListener.java index 98b55adfb..605fc2022 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/NetworkListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/NetworkListener.java @@ -2,12 +2,14 @@ package io.github.thebusybiscuit.slimefun4.implementation.listeners; import javax.annotation.Nonnull; +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.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent; import io.github.thebusybiscuit.slimefun4.api.network.Network; import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; @@ -16,6 +18,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; * This {@link Listener} is responsible for all updates to a {@link Network}. * * @author meiamsome + * @author TheBusyBiscuit * * @see Network * @see NetworkManager @@ -23,6 +26,9 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; */ public class NetworkListener implements Listener { + /** + * Our {@link NetworkManager} instance. + */ private final NetworkManager manager; public NetworkListener(@Nonnull SlimefunPlugin plugin, @Nonnull NetworkManager manager) { @@ -39,4 +45,12 @@ public class NetworkListener implements Listener { public void onBlockPlace(BlockPlaceEvent e) { manager.updateAllNetworks(e.getBlock().getLocation()); } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onExplosiveToolUse(ExplosiveToolBreakBlocksEvent e) { + // Fixes #3013 - Also update networks when using an explosive tool + for (Block b : e.getAdditionalBlocks()) { + manager.updateAllNetworks(b.getLocation()); + } + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TeleporterListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TeleporterListener.java index a22a795be..daec58682 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TeleporterListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TeleporterListener.java @@ -59,7 +59,7 @@ public class TeleporterListener implements Listener { if (teleporter instanceof Teleporter && checkForPylons(b.getRelative(BlockFace.DOWN))) { Block block = b.getRelative(BlockFace.DOWN); UUID owner = UUID.fromString(BlockStorage.getLocationInfo(block.getLocation(), "owner")); - SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI(p, owner, block, SlimefunPlugin.getGPSNetwork().getNetworkComplexity(owner)); + SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI(p, owner, block); } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java index 8c8015aee..dbe200ead 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java @@ -287,6 +287,7 @@ public final class ResearchSetup { register("improved_generators", 275, "Improved Generators", 24, SlimefunItems.COAL_GENERATOR_2, SlimefunItems.LAVA_GENERATOR_2); register("ingredients_and_cheese", 276, "Slimefun Cuisine", 5, SlimefunItems.SALT, SlimefunItems.WHEAT_FLOUR, SlimefunItems.HEAVY_CREAM, SlimefunItems.CHEESE, SlimefunItems.BUTTER); register("medium_tier_auto_enchanting", 277, "Fast Automatic Enchanting and Disenchanting", 48, SlimefunItems.AUTO_ENCHANTER_2, SlimefunItems.AUTO_DISENCHANTER_2); + register("portable_teleporter", 278, "Teleportation from Anywhere", 42, SlimefunItems.PORTABLE_TELEPORTER); } @ParametersAreNonnullByDefault 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 44fc8316e..a47fa8df0 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 @@ -182,6 +182,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.miner import io.github.thebusybiscuit.slimefun4.implementation.items.seasonal.ChristmasPresent; import io.github.thebusybiscuit.slimefun4.implementation.items.seasonal.EasterEgg; import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.PersonalActivationPlate; +import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.PortableTeleporter; import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.SharedActivationPlate; import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.Teleporter; import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.TeleporterPylon; @@ -1492,7 +1493,7 @@ public final class SlimefunItemSetup { new SlimefunItemStack(SlimefunItems.ANCIENT_PEDESTAL, 4)) .register(plugin); - new AncientAltar(categories.magicalGadgets, 8, SlimefunItems.ANCIENT_ALTAR, RecipeType.MAGIC_WORKBENCH, + new AncientAltar(categories.magicalGadgets, SlimefunItems.ANCIENT_ALTAR, RecipeType.MAGIC_WORKBENCH, new ItemStack[] {null, new ItemStack(Material.ENCHANTING_TABLE), null, SlimefunItems.MAGIC_LUMP_3, SlimefunItems.GOLD_8K, SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN)}) .register(plugin); @@ -2221,6 +2222,10 @@ public final class SlimefunItemSetup { new ItemStack[] {SlimefunItems.GPS_TELEPORTER_PYLON, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.GPS_TELEPORTER_PYLON, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.GPS_CONTROL_PANEL, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.GPS_TELEPORTER_PYLON, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.GPS_TELEPORTER_PYLON}) .register(plugin); + new PortableTeleporter(categories.gps, SlimefunItems.PORTABLE_TELEPORTER, RecipeType.ENHANCED_CRAFTING_TABLE, + new ItemStack[] {SlimefunItems.ELECTRO_MAGNET, SlimefunItems.GPS_TRANSMITTER_3, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.REINFORCED_PLATE, SlimefunItems.GPS_TELEPORTATION_MATRIX, SlimefunItems.REINFORCED_PLATE, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.MEDIUM_CAPACITOR, SlimefunItems.BLISTERING_INGOT_3}) + .register(plugin); + new SharedActivationPlate(categories.gps, SlimefunItems.GPS_ACTIVATION_DEVICE_SHARED, RecipeType.ENHANCED_CRAFTING_TABLE, new ItemStack[] {null, new ItemStack(Material.STONE_PRESSURE_PLATE), null, new ItemStack(Material.REDSTONE), SlimefunItems.GPS_TRANSMITTER, new ItemStack(Material.REDSTONE), SlimefunItems.BILLON_INGOT, SlimefunItems.BILLON_INGOT, SlimefunItems.BILLON_INGOT}) .register(plugin); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java index 3cb89b6da..ca53ab578 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AncientAltarTask.java @@ -46,7 +46,7 @@ public class AncientAltarTask implements Runnable { private final AncientPedestal pedestalItem = (AncientPedestal) SlimefunItems.ANCIENT_PEDESTAL.getItem(); private final Block altar; - private final int speed; + private final int stepDelay; private final Location dropLocation; private final ItemStack output; private final List pedestals; @@ -60,10 +60,10 @@ public class AncientAltarTask implements Runnable { private final Player player; @ParametersAreNonnullByDefault - public AncientAltarTask(AncientAltarListener listener, Block altar, int speed, ItemStack output, List pedestals, List items, Player player) { + public AncientAltarTask(AncientAltarListener listener, Block altar, int stepDelay, ItemStack output, List pedestals, List items, Player player) { this.listener = listener; this.dropLocation = altar.getLocation().add(0.5, 1.3, 0.5); - this.speed = speed; + this.stepDelay = stepDelay; this.altar = altar; this.output = output; this.pedestals = pedestals; @@ -102,7 +102,7 @@ public class AncientAltarTask implements Runnable { } this.stage += 1; - SlimefunPlugin.runSync(this, speed); + SlimefunPlugin.runSync(this, stepDelay); } private boolean checkLockedItems() { diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java index 5c75ac863..59694e842 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java @@ -59,6 +59,8 @@ public class BlockStorage { private final Map blocksCache = new ConcurrentHashMap<>(); private static int chunkChanges = 0; + private static boolean chunksLoaded = false; + private static boolean universalInventoriesLoaded = false; private int changes = 0; private AtomicBoolean isMarkedForRemoval = new AtomicBoolean(false); @@ -214,6 +216,12 @@ public class BlockStorage { } private void loadChunks() { + if (chunksLoaded) { + return; + } + + chunksLoaded = true; + File chunks = new File(PATH_CHUNKS + "chunks.sfc"); if (chunks.exists()) { @@ -237,6 +245,12 @@ public class BlockStorage { if (file.getName().startsWith(world.getName()) && file.getName().endsWith(".sfi")) { try { Location l = deserializeLocation(file.getName().replace(".sfi", "")); + + // We only want to only load this world's menus + if (world != l.getWorld()) { + continue; + } + io.github.thebusybiscuit.cscorelib2.config.Config cfg = new io.github.thebusybiscuit.cscorelib2.config.Config(file); BlockMenuPreset preset = BlockMenuPreset.getPreset(cfg.getString("preset")); @@ -253,6 +267,12 @@ public class BlockStorage { } } + if (universalInventoriesLoaded) { + return; + } + + universalInventoriesLoaded = true; + for (File file : new File("data-storage/Slimefun/universal-inventories").listFiles()) { if (file.getName().endsWith(".sfi")) { try { diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java deleted file mode 100644 index 936a7096a..000000000 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java +++ /dev/null @@ -1,84 +0,0 @@ -package me.mrCookieSlime.Slimefun.api; - -import org.bukkit.entity.Player; - -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; - -/** - * Provides a few static convenience methods. - * - * @deprecated This class is slowly getting stripped away in favour of a more object-oriented approach. - * - * @author TheBusyBiscuit - * @author Walshy - * @author Poslovitch - */ -@Deprecated -public final class Slimefun { - - private Slimefun() {} - - /** - * Checks if this player has the permission to use this item. - * - * @param p - * the player to check, not null - * @param item - * the item to check, null returns true - * @param message - * whether a message should be sent to the player or not - * - * @deprecated This method will soon be removed. - * - * @return true if the item is not null and if the player has the permission to use it, - * false otherwise. - */ - @Deprecated - public static boolean hasPermission(Player p, SlimefunItem item, boolean message) { - if (item == null) { - return true; - } else if (SlimefunPlugin.getPermissionsService().hasPermission(p, item)) { - return true; - } else { - if (message) { - SlimefunPlugin.getLocalization().sendMessage(p, "messages.no-permission", true); - } - - return false; - } - } - - /** - * Checks if this item is enabled in the world this player is in. - * - * @param p - * the player to get the world he is in, not null - * @param sfItem - * the item to check, not null - * @param message - * whether a message should be sent to the player or not - * - * @deprecated Please use {@link SlimefunItem#isDisabledIn(org.bukkit.World)} instead. - * - * @return true if the item is enabled in the world the player is in, - * false otherwise. - */ - @Deprecated - public static boolean isEnabled(Player p, SlimefunItem sfItem, boolean message) { - if (sfItem.isDisabled()) { - if (message) { - SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-item", true); - } - - return false; - } else if (!SlimefunPlugin.getWorldSettingsService().isEnabled(p.getWorld(), sfItem)) { - if (message) { - SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-in-world", true); - } - - return false; - } - return true; - } -} \ No newline at end of file diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java index 3c5412f66..9307b0cab 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java @@ -86,6 +86,17 @@ public class DirtyChestMenu extends ChestMenu { return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots); } + /** + * Adds given {@link ItemStack} to any of the given inventory slots. + * Items will be added to the inventory slots based on their order in the function argument. + * Items will be added either to any empty inventory slots or any partially filled slots, in which case + * as many items as can fit will be added to that specific spot. + * + * @param item {@link ItemStack} to be added to the inventory + * @param slots Numbers of slots to add the {@link ItemStack} to + * @return {@link ItemStack} with any items that did not fit into the inventory + * or null when everything had fit + */ @Nullable public ItemStack pushItem(ItemStack item, int... slots) { if (item == null || item.getType() == Material.AIR) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a0f9cd53a..a0240c6d4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,6 +26,7 @@ guide: researches: free-in-creative-mode: true enable-fireworks: true + disable-learning-animation: false URID: info-delay: 3000 diff --git a/src/main/resources/languages/de/messages.yml b/src/main/resources/languages/de/messages.yml index dc9381eab..e1d95a960 100644 --- a/src/main/resources/languages/de/messages.yml +++ b/src/main/resources/languages/de/messages.yml @@ -75,6 +75,24 @@ guide: translations: name: '&aFehlt etwas?' lore: 'Klicke um eine Übersetzung hinzuzufügen' + options: + learning-animation: + enabled: + text: + - '&bLern-Animation: &aAn' + - '' + - '&7Du kannst nun entscheiden, ob' + - '&7du eine Animation beim Freischalten von' + - '&7Items sehen wirst.' + click: '&eKlicke um die Lern-Animation zu deaktivieren' + disabled: + text: + - '&bLern-Animation: &4Aus' + - '' + - '&7Du kannst nun entscheiden, ob' + - '&7du eine Animation beim Freischalten von' + - '&7Items sehen wirst.' + click: '&eKlicke um die Lern-Animation zu aktivieren' title: main: 'Slimefun-Handbuch' settings: 'Einstellungen & Infos' @@ -139,6 +157,11 @@ messages: - '' - '&eLeft Click &7to temporarily disable the recipe' - '&eRight Click &7to remove this recipe' + disabled: + - '&cDieses Rezept ist momentan deaktiviert' + - '' + - '&eLeft Click &7to re-enable this recipe' + - '&eRight Click &7to remove this recipe' talisman: anvil: '&a&oDein Talisman hat dein Werkzeug vor dem Zerfall gerettet' miner: '&a&oDein Talisman hat soeben die Drops verdoppelt' @@ -197,6 +220,8 @@ messages: - '&7Always look on the bright side of life!' - '&7Ist das jetzt ein Keks, Cookie oder ein Biscuit?' - '&7Jetzt auch zuckerfrei!' + pickaxe-of-the-seeker: + no-ores: '&cEs konnten keine Erze in deiner Nähe gefunden werden!' machines: pattern-not-found: '&eEs tut mir leid, aber ich konnte kein passendes Rezept finden.' unknown-material: '&eEs tut mir leid, aber ich erkenne das Item in meinem Werfer nicht, probier ein anderes Item aus.' diff --git a/src/main/resources/languages/en/messages.yml b/src/main/resources/languages/en/messages.yml index ae6bbac0e..39ffbc636 100644 --- a/src/main/resources/languages/en/messages.yml +++ b/src/main/resources/languages/en/messages.yml @@ -91,6 +91,25 @@ guide: name: '&aIs something missing?' lore: 'Click to add your own translation' + options: + learning-animation: + enabled: + text: + - '&bLearning Animation: &aYes' + - '' + - '&7You can now toggle whether you' + - '&7will see information about your pondering in chat' + - '&7upon researching an item.' + click: '&eClick to disable your learning animation' + disabled: + text: + - '&bLearning Animation: &4No' + - '' + - '&7You can now toggle whether you' + - '&7will see information about your pondering in chat' + - '&7upon researching an item.' + click: '&eClick to enable your learning animation' + title: main: 'Slimefun Guide' settings: 'Settings & Info' diff --git a/src/main/resources/languages/en/researches.yml b/src/main/resources/languages/en/researches.yml index 123388cd6..12964f3ca 100644 --- a/src/main/resources/languages/en/researches.yml +++ b/src/main/resources/languages/en/researches.yml @@ -255,3 +255,4 @@ slimefun: improved_generators: Improved Generators ingredients_and_cheese: Slimefun Cuisine medium_tier_auto_enchanting: Fast Automatic Enchanting and Disenchanting + portable_teleporter: Teleportation from Anywhere diff --git a/src/main/resources/languages/lv/messages.yml b/src/main/resources/languages/lv/messages.yml index ab2848c44..2595400e5 100644 --- a/src/main/resources/languages/lv/messages.yml +++ b/src/main/resources/languages/lv/messages.yml @@ -35,7 +35,7 @@ guide: languages: 'Izvēlies savu vēlamo valodu,' credits: 'Slimefun4 Ieguldītāji' credits: - commit: "Ieguldījums" + commit: 'Ieguldījums' commits: 'Ieguldījumi' profile-link: 'Spied, lai apmeklētu GitHub profilu' roles: