diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e0473ab3..1f856a24f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,9 @@ * (API) Added PlayerPreResearchEvent * Added a config option to disable network visualizations * (API) Added CoolerFeedPlayerEvent +* Added a config option to delete excess cargo network items +* Added an item setting to configure the Wind Staff velocity +* Added an item setting to the Infused Hopper to toggle it with redstone #### Changes * Removed 1.13 support @@ -40,6 +43,10 @@ * Magnets can no longer be placed down * Electromagnets can no longer be placed down * Performance improvements to Cargo network visualizations +* General performance improvements +* Improved performance for radioactive items +* Memory/GC improvements for the profiler +* Performance improvements for the Fluid Pump #### Fixes * Fixed #2448 @@ -59,6 +66,17 @@ * Fixed Magician Talisman sometimes drawing invalid enchantments * Fixed id conflicts for external Enchantment sources (e.g. plugins) for the Magician Talisman settings * Fixed network visualizers spawning particles for other player heads +* Fixed #2418 +* Fixed #2446 +* Fixed CoreProtect not recognizing Slimefun blocks getting broken +* Fixed #2447 +* Fixed #2558 +* Fixed a duplication bug with the Block Placer +* Fixed Slimefun Guide Settings showing "last activity" as a negative number +* Fixed Armor Stands getting damaged/pushed by Explosive Bow +* Fixed Sword of Beheading dropping Zombie/Skeleton Skulls from Zombie/Skeleton subvariants +* Fixed #2518 +* Fixed #2421 ## Release Candidate 17 (17 Oct 2020) diff --git a/pom.xml b/pom.xml index dff2be0e8..57e348ff5 100644 --- a/pom.xml +++ b/pom.xml @@ -315,7 +315,7 @@ com.github.seeseemelk MockBukkit-v1.16 - 0.15.0 + 0.15.1 test @@ -337,7 +337,7 @@ com.github.TheBusyBiscuit CS-CoreLib2 - 0.26 + 0.27.2 compile @@ -381,7 +381,7 @@ com.gmail.nossr50.mcMMO mcMMO - 2.1.157 + 2.1.158 provided diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerPreResearchEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerPreResearchEvent.java index 12282bda7..d80efd9b1 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerPreResearchEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerPreResearchEvent.java @@ -33,7 +33,7 @@ public class PlayerPreResearchEvent extends Event implements Cancellable { private final Research research; private final SlimefunItem slimefunItem; private boolean cancelled; - + @ParametersAreNonnullByDefault public PlayerPreResearchEvent(Player p, Research research, SlimefunItem slimefunItem) { Validate.notNull(p, "The Player cannot be null"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerRightClickEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerRightClickEvent.java index 1bfd42977..4d09ebbed 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerRightClickEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/PlayerRightClickEvent.java @@ -11,6 +11,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -19,12 +20,25 @@ import io.github.thebusybiscuit.cscorelib2.data.ComputedOptional; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.BlockStorage; -public class PlayerRightClickEvent extends Event { +/** + * The {@link PlayerRightClickEvent} is our custom version of the {@link PlayerInteractEvent}. + * But it is only triggered on right click. + * The main and (almost) sole purpose of this {@link Event} is to cache the {@link SlimefunItem} + * of the {@link ItemStack} and/or {@link Block} involved. + * This allows us (and addons) to efficiently check the used {@link SlimefunItem} without the need + * to do a heavy lookup or item comparison. + * + * @author TheBusyBiscuit + * + */ +public class PlayerRightClickEvent extends PlayerEvent { private static final HandlerList handlers = new HandlerList(); + /** + * The original {@link PlayerInteractEvent}. + */ private final PlayerInteractEvent event; - private final Player player; private final Optional itemStack; private final Optional clickedBlock; @@ -35,33 +49,45 @@ public class PlayerRightClickEvent extends Event { private ComputedOptional slimefunItem = ComputedOptional.createNew(); private ComputedOptional slimefunBlock = ComputedOptional.createNew(); - private Result itemResult = Result.DEFAULT; - private Result blockResult = Result.DEFAULT; + private Result itemResult; + private Result blockResult; - public PlayerRightClickEvent(@Nonnull PlayerInteractEvent e) { - event = e; - player = e.getPlayer(); - clickedBlock = Optional.ofNullable(e.getClickedBlock()); - face = e.getBlockFace(); - hand = e.getHand(); + /** + * This constructs a new {@link PlayerRightClickEvent} based on the original {@link PlayerInteractEvent}. + * The {@link Result} of the original {@link PlayerInteractEvent} will be copied. + * + * @param originalEvent + * The original {@link PlayerInteractEvent} + */ + public PlayerRightClickEvent(@Nonnull PlayerInteractEvent originalEvent) { + super(originalEvent.getPlayer()); - if (e.getItem() == null || e.getItem().getType() == Material.AIR || e.getItem().getAmount() == 0) { + event = originalEvent; + clickedBlock = Optional.ofNullable(originalEvent.getClickedBlock()); + face = originalEvent.getBlockFace(); + hand = originalEvent.getHand(); + + itemResult = originalEvent.useItemInHand(); + blockResult = originalEvent.useInteractedBlock(); + + if (originalEvent.getItem() == null || originalEvent.getItem().getType() == Material.AIR || originalEvent.getItem().getAmount() == 0) { itemStack = Optional.empty(); } else { - itemStack = Optional.of(e.getItem()); + itemStack = Optional.of(originalEvent.getItem()); } } + /** + * This returns the original {@link PlayerInteractEvent} that triggered this + * {@link PlayerRightClickEvent}. + * + * @return The original {@link PlayerInteractEvent} + */ @Nonnull public PlayerInteractEvent getInteractEvent() { return event; } - @Nonnull - public Player getPlayer() { - return player; - } - /** * This method returns the {@link ItemStack} that was held in the hand of the {@link Player}. * It will never return null, should there be no {@link ItemStack} then it will return @@ -121,6 +147,10 @@ public class PlayerRightClickEvent extends Event { return slimefunBlock.getAsOptional(); } + /** + * This method cancels the {@link PlayerRightClickEvent}. + * This will deny the item and block usage. + */ public void cancel() { itemResult = Result.DENY; blockResult = Result.DENY; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java index e51ff0bcb..8d0a27c14 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java @@ -113,6 +113,7 @@ public class ItemSetting { * * @param c * The class of data type you want to compare + * * @return Whether this {@link ItemSetting} stores the given type */ public boolean isType(@Nonnull Class c) { @@ -137,14 +138,19 @@ public class ItemSetting { * @param item * The {@link SlimefunItem} who called this method */ - @SuppressWarnings("unchecked") public void load(@Nonnull SlimefunItem item) { + Validate.notNull(item, "Cannot apply settings for a non-existing SlimefunItem"); + SlimefunPlugin.getItemCfg().setDefaultValue(item.getId() + '.' + getKey(), getDefaultValue()); Object configuredValue = SlimefunPlugin.getItemCfg().getValue(item.getId() + '.' + getKey()); if (defaultValue.getClass().isInstance(configuredValue)) { - if (validateInput((T) configuredValue)) { - this.value = (T) configuredValue; + // We can suppress the warning here, we did an isInstance(...) check before! + @SuppressWarnings("unchecked") + T newValue = (T) configuredValue; + + if (validateInput(newValue)) { + this.value = newValue; } else { Slimefun.getLogger().log(Level.WARNING, "Slimefun has found an invalid config setting in your Items.yml!"); Slimefun.getLogger().log(Level.WARNING, " at \"{0}.{1}\"", new Object[] { item.getId(), getKey() }); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java index 3cd3241d8..f630e5e00 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/DamageableItem.java @@ -49,7 +49,9 @@ public interface DamageableItem extends ItemAttribute { */ default void damageItem(@Nonnull Player p, @Nullable ItemStack item) { if (isDamageable() && item != null && item.getType() != Material.AIR && item.getAmount() > 0) { - if (item.getEnchantments().containsKey(Enchantment.DURABILITY) && Math.random() * 100 <= (60 + Math.floorDiv(40, (item.getEnchantmentLevel(Enchantment.DURABILITY) + 1)))) { + int unbreakingLevel = item.getEnchantmentLevel(Enchantment.DURABILITY); + + if (unbreakingLevel > 0 && Math.random() * 100 <= (60 + Math.floorDiv(40, (unbreakingLevel + 1)))) { return; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/EnergyNetComponent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/EnergyNetComponent.java index 6d2e1504d..62c1246fa 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/EnergyNetComponent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/EnergyNetComponent.java @@ -10,6 +10,7 @@ import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponen import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.BlockStorage; @@ -65,14 +66,36 @@ public interface EnergyNetComponent extends ItemAttribute { * @return The charge stored at that {@link Location} */ default int getCharge(@Nonnull Location l) { + // Emergency fallback, this cannot hold a charge, so we'll just return zero + if (!isChargeable()) { + return 0; + } + + return getCharge(l, BlockStorage.getLocationInfo(l)); + } + + /** + * This returns the currently stored charge at a given {@link Location}. + * This is a more performance saving option if you already have a {@link Config} + * object for this {@link Location}. + * + * @param l + * The target {@link Location} + * @param data + * The data at this {@link Location} + * + * @return The charge stored at that {@link Location} + */ + default int getCharge(@Nonnull Location l, @Nonnull Config data) { Validate.notNull(l, "Location was null!"); + Validate.notNull(data, "data was null!"); // Emergency fallback, this cannot hold a charge, so we'll just return zero if (!isChargeable()) { return 0; } - String charge = BlockStorage.getLocationInfo(l, "energy-charge"); + String charge = data.getString("energy-charge"); if (charge != null) { return Integer.parseInt(charge); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java index 8f6494a84..28a05cfa9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java @@ -68,8 +68,11 @@ public abstract class FlexCategory extends Category { @Override public final boolean isHidden(@Nonnull Player p) { - // We can stop this method right here. - // We provide a custom method with more parameters for this. See isVisible(...) + /** + * We can stop this method right here. + * We provide a custom method with more parameters for this. + * See isVisible(...) + */ return false; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java index 97a529e8b..69b2434cd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/LockedCategory.java @@ -153,9 +153,11 @@ public class LockedCategory extends Category { public boolean hasUnlocked(@Nonnull Player p, @Nonnull PlayerProfile profile) { for (Category category : parents) { for (SlimefunItem item : category.getItems()) { - // Should probably be replaced with Slimefun.hasUnlocked(...) - // However this will result in better performance because we don't - // request the PlayerProfile everytime + /** + * Should probably be replaced with Slimefun.hasUnlocked(...) + * However this will result in better performance because we don't + * request the PlayerProfile everytime + */ if (Slimefun.isEnabled(p, item, false) && Slimefun.hasPermission(p, item, false) && !profile.hasUnlocked(item.getResearch())) { return false; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java index 538b0aaed..4e0920d18 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java @@ -27,7 +27,7 @@ public class SeasonalCategory extends Category { private final Month month; /** - * The constructor for a SeasonCategory. + * The constructor for a {@link SeasonalCategory}. * * @param key * The {@link NamespacedKey} that is used to identify this {@link Category} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunCommand.java index 5bbc09820..04b1347d6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunCommand.java @@ -83,9 +83,12 @@ public class SlimefunCommand implements CommandExecutor, Listener { sendHelp(sender); - // We could just return true here, but if there's no subcommands, then - // something went horribly wrong anyway. This will also stop sonarcloud - // from nagging about this always returning true... + /** + * We could just return true here, but if there's no subcommands, + * then something went horribly wrong anyway. + * This will also stop sonarcloud from nagging about + * this always returning true... + */ return !commands.isEmpty(); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SubCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SubCommand.java index 28b54fd18..3bc2630bf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SubCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SubCommand.java @@ -77,6 +77,7 @@ public abstract class SubCommand { * * @param sender * The {@link CommandSender} who requested the description + * * @return A possibly localized description of this {@link SubCommand} */ @Nonnull 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 5ed9c6918..7ce154874 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 @@ -46,7 +46,7 @@ final class ContributorsMenu { }); List contributors = new ArrayList<>(SlimefunPlugin.getGitHubService().getContributors().values()); - contributors.sort(Comparator.comparingInt(Contributor::index)); + contributors.sort(Comparator.comparingInt(Contributor::getPosition)); for (int i = page * 36; i < contributors.size() && i < (page + 1) * 36; i++) { Contributor contributor = contributors.get(i); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java index 54f4d6f74..a0f7f33e7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/multiblocks/MultiBlockMachine.java @@ -117,7 +117,7 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace protected MultiBlockInteractionHandler getInteractionHandler() { return (p, mb, b) -> { if (mb.equals(getMultiBlock())) { - if (!isDisabled() && SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES) && Slimefun.hasUnlocked(p, this, true)) { + if (!isDisabled() && SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK) && Slimefun.hasUnlocked(p, this, true)) { onInteract(p, b); } 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 a7c4089a8..66216750d 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 @@ -14,6 +14,7 @@ import org.bukkit.Server; import io.github.thebusybiscuit.cscorelib2.config.Config; import io.github.thebusybiscuit.slimefun4.api.network.Network; +import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener; /** @@ -30,6 +31,7 @@ public class NetworkManager { private final int maxNodes; private final boolean enableVisualizer; + private final boolean deleteExcessItems; private final List networks = new LinkedList<>(); /** @@ -37,14 +39,29 @@ public class NetworkManager { * * @param maxStepSize * The maximum amount of nodes a {@link Network} can have + * @param enableVisualizer + * Whether the {@link Network} visualizer is enabled + * @param deleteExcessItems + * Whether excess items from a {@link CargoNet} should be voided */ - public NetworkManager(int maxStepSize, boolean enableVisualizer) { + public NetworkManager(int maxStepSize, boolean enableVisualizer, boolean deleteExcessItems) { Validate.isTrue(maxStepSize > 0, "The maximal Network size must be above zero!"); this.enableVisualizer = enableVisualizer; + this.deleteExcessItems = deleteExcessItems; maxNodes = maxStepSize; } + /** + * This creates a new {@link NetworkManager} with the given capacity. + * + * @param maxStepSize + * The maximum amount of nodes a {@link Network} can have + */ + public NetworkManager(int maxStepSize) { + this(maxStepSize, true, false); + } + /** * This method returns the limit of nodes a {@link Network} can have. * This value is read from the {@link Config} file. @@ -64,6 +81,16 @@ public class NetworkManager { return enableVisualizer; } + /** + * This returns whether excess items from a {@link CargoNet} should be voided + * instead of being dropped to the ground. + * + * @return Whether to delete excess items + */ + public boolean isItemDeletionEnabled() { + return deleteExcessItems; + } + /** * This returns a {@link List} of every {@link Network} on the {@link Server}. * @@ -81,6 +108,7 @@ public class NetworkManager { } Validate.notNull(type, "Type must not be null"); + for (Network network : networks) { if (type.isInstance(network) && network.connectsTo(l)) { return Optional.of(type.cast(network)); @@ -141,8 +169,11 @@ public class NetworkManager { public void updateAllNetworks(@Nonnull Location l) { Validate.notNull(l, "The Location cannot be null"); - for (Network network : getNetworksFromLocation(l, Network.class)) { - network.markDirty(l); + // No need to create a sublist and loop through it if there are no Networks + if (!networks.isEmpty()) { + for (Network network : getNetworksFromLocation(l, Network.class)) { + network.markDirty(l); + } } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java index 051b964d2..cfc778d13 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/cargo/CargoNetworkTask.java @@ -15,6 +15,7 @@ import org.bukkit.block.Block; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; @@ -37,6 +38,7 @@ import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu; */ class CargoNetworkTask implements Runnable { + private final NetworkManager manager; private final CargoNet network; private final Map inventories = new HashMap<>(); @@ -49,6 +51,7 @@ class CargoNetworkTask implements Runnable { @ParametersAreNonnullByDefault CargoNetworkTask(CargoNet network, Map inputs, Map> outputs, Set chestTerminalInputs, Set chestTerminalOutputs) { this.network = network; + this.manager = SlimefunPlugin.getNetworkManager(); this.inputs = inputs; this.outputs = outputs; @@ -115,7 +118,7 @@ class CargoNetworkTask implements Runnable { // Try to add the item into another available slot then ItemStack rest = inv.addItem(stack).get(0); - if (rest != null) { + if (rest != null && !manager.isItemDeletionEnabled()) { // If the item still couldn't be inserted, simply drop it on the ground inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), rest); } @@ -126,7 +129,7 @@ class CargoNetworkTask implements Runnable { if (menu != null) { if (menu.getItemInSlot(previousSlot) == null) { menu.replaceExistingItem(previousSlot, stack); - } else { + } else if (!manager.isItemDeletionEnabled()) { inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), stack); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java index 02eea2d4b..b201c5137 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java @@ -210,14 +210,14 @@ public class EnergyNet extends Network { SlimefunItem item = (SlimefunItem) provider; try { - Config config = BlockStorage.getLocationInfo(loc); - int energy = provider.getGeneratedOutput(loc, config); + Config data = BlockStorage.getLocationInfo(loc); + int energy = provider.getGeneratedOutput(loc, data); if (provider.isChargeable()) { - energy += provider.getCharge(loc); + energy += provider.getCharge(loc, data); } - if (provider.willExplode(loc, config)) { + if (provider.willExplode(loc, data)) { explodedBlocks.add(loc); BlockStorage.clearBlockInfo(loc); @@ -228,9 +228,9 @@ public class EnergyNet extends Network { } else { supply += energy; } - } catch (Exception | LinkageError t) { + } catch (Exception | LinkageError throwable) { explodedBlocks.add(loc); - new ErrorReport<>(t, loc, item); + new ErrorReport<>(throwable, loc, item); } long time = SlimefunPlugin.getProfiler().closeEntry(loc, item, timestamp); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java index 569845ac4..191d1c69f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java @@ -117,6 +117,7 @@ public class Research implements Keyed { * * @param p * The {@link Player} to translate this name for. + * * @return The localized Name of this {@link Research}. */ @Nonnull @@ -197,12 +198,18 @@ public class Research implements Keyed { * Handle what to do when a {@link Player} clicks on an un-researched item in * a {@link SlimefunGuideImplementation}. * - * @param guide The {@link SlimefunGuideImplementation} used. - * @param player The {@link Player} who clicked on the item. - * @param profile The {@link PlayerProfile} of that {@link Player}. - * @param sfItem The {@link SlimefunItem} on which the {@link Player} clicked. - * @param category The {@link Category} where the {@link Player} was. - * @param page The page number of where the {@link Player} was in the {@link Category}; + * @param guide + * The {@link SlimefunGuideImplementation} used. + * @param player + * The {@link Player} who clicked on the item. + * @param profile + * The {@link PlayerProfile} of that {@link Player}. + * @param sfItem + * The {@link SlimefunItem} on which the {@link Player} clicked. + * @param category + * The {@link Category} where the {@link Player} was. + * @param page + * The page number of where the {@link Player} was in the {@link Category}; * */ @ParametersAreNonnullByDefault @@ -230,6 +237,7 @@ public class Research implements Keyed { * * @param p * The {@link Player} to check + * * @return Whether that {@link Player} can unlock this {@link Research} */ public boolean canUnlock(@Nonnull Player p) { 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 98a8b2853..feea594a0 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 @@ -7,7 +7,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.lang.Validate; - import org.bukkit.Bukkit; import org.bukkit.Keyed; import org.bukkit.Material; @@ -20,10 +19,7 @@ import org.bukkit.persistence.PersistentDataHolder; import org.bukkit.persistence.PersistentDataType; 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; import me.mrCookieSlime.Slimefun.api.Slimefun; /** @@ -70,20 +66,17 @@ public class BlockDataService implements Keyed { Validate.notNull(b, "The block cannot be null!"); Validate.notNull(value, "The value cannot be null!"); - // Due to a bug on older versions, Persistent Data is nullable for non-snapshots - boolean useSnapshot = SlimefunPlugin.getMinecraftVersion().isBefore(MinecraftVersion.MINECRAFT_1_16); - - BlockStateSnapshotResult result = PaperLib.getBlockState(b, useSnapshot); - BlockState state = result.getState(); + /** + * Don't use PaperLib here, it seems to be quite buggy in block-placing scenarios + * and it would be too tedious to check for individual build versions to circumvent this. + */ + BlockState state = b.getState(); if (state instanceof TileState) { try { PersistentDataContainer container = ((TileState) state).getPersistentDataContainer(); container.set(namespacedKey, PersistentDataType.STRING, value); - - if (result.isSnapshot()) { - state.update(); - } + state.update(); } catch (Exception x) { Slimefun.getLogger().log(Level.SEVERE, "Please check if your Server Software is up to date!"); @@ -100,21 +93,31 @@ public class BlockDataService implements Keyed { * * @param b * The {@link Block} to retrieve data from + * * @return The stored value */ public Optional getBlockData(@Nonnull Block b) { Validate.notNull(b, "The block cannot be null!"); BlockState state = PaperLib.getBlockState(b, false).getState(); + PersistentDataContainer container = getPersistentDataContainer(state); - if (state instanceof TileState) { - PersistentDataContainer container = ((TileState) state).getPersistentDataContainer(); + if (container != null) { return Optional.ofNullable(container.get(namespacedKey, PersistentDataType.STRING)); } else { return Optional.empty(); } } + @Nullable + private PersistentDataContainer getPersistentDataContainer(@Nonnull BlockState state) { + if (state instanceof TileState) { + return ((TileState) state).getPersistentDataContainer(); + } else { + return null; + } + } + /** * This method checks whether the given {@link Material} is a Tile Entity. * This is used to determine whether the {@link Block} produced by this {@link Material} 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 3caea1cbb..854cc86ab 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 @@ -23,9 +23,22 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; */ public class CustomTextureService { + /** + * The {@link Config} object in which the Server Owner can configure the item models. + */ private final Config config; + /** + * This nullable {@link StringBuffer} represents the "version" of the used item-models file. + * This version is served with our resource pack. + */ private String version = null; + + /** + * This boolean represents whether the file was modified anyway. + * This is equivalent to at least one value being set to a number which + * is not zero! + */ private boolean modified = false; /** @@ -110,6 +123,7 @@ public class CustomTextureService { */ public int getModelData(@Nonnull String id) { Validate.notNull(id, "Cannot get the ModelData for 'null'"); + return config.getInt(id); } 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 74ddcd2e1..ad4bee64f 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 @@ -140,7 +140,7 @@ public class MetricsService { } /** - * This will close the child classloader and mark all the resources held under this no longer + * This will close the child {@link ClassLoader} and mark all the resources held under this no longer * in use, they will be cleaned up the next GC run. */ public void cleanUp() { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java index 46c409fa5..b323d3f2f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/UpdaterService.java @@ -24,8 +24,20 @@ import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; */ public class UpdaterService { + /** + * Our {@link SlimefunPlugin} instance. + */ private final SlimefunPlugin plugin; + + /** + * Our {@link Updater} implementation. + */ private final Updater updater; + + /** + * The {@link SlimefunBranch} we are currently on. + * If this is an official {@link SlimefunBranch}, auto updates will be enabled. + */ private final SlimefunBranch branch; /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/Contributor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/Contributor.java index d558502ad..0bc34a0fa 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/Contributor.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/Contributor.java @@ -38,7 +38,7 @@ public class Contributor { private final ComputedOptional headTexture = ComputedOptional.createNew(); private Optional uuid = Optional.empty(); - private boolean locked = false; + private boolean immutable = false; /** * This creates a new {@link Contributor} with the given ingame name and GitHub profile. @@ -76,7 +76,7 @@ public class Contributor { * specified role. * * @param role - * The role + * The role of this {@link Contributor} * @param commits * The amount of contributions made as that role */ @@ -84,7 +84,7 @@ public class Contributor { Validate.notNull(role, "The role cannot be null!"); Validate.isTrue(commits >= 0, "Contributions cannot be negative"); - if (!locked || role.startsWith("translator,")) { + if (!immutable || role.startsWith("translator,")) { contributions.put(role, commits); } } @@ -120,6 +120,13 @@ public class Contributor { return profileLink; } + /** + * This returns a {@link List} of contributions for this {@link Contributor}. + * Each entry consists of a {@link String} (for the role) and an {@link Integer} + * (for the amount of commits). + * + * @return A {@link List} of contributions for this {@link Contributor} + */ @Nonnull public List> getContributions() { List> list = new ArrayList<>(contributions.entrySet()); @@ -137,6 +144,8 @@ public class Contributor { * @return The amount of contributions this {@link Contributor} submitted as the given role */ public int getContributions(@Nonnull String role) { + Validate.notNull(role, "The role cannot be null!"); + return contributions.getOrDefault(role, 0); } @@ -214,16 +223,35 @@ public class Contributor { return contributions.values().stream().mapToInt(Integer::intValue).sum(); } - public int index() { - return -getTotalContributions(); - } - + /** + * This returns the final display name for this {@link Contributor}. + * The display name is basically the GitHub username but if the Minecraft username differs, + * it will be appended in brackets behind the GitHub username. + * + * @return The final display name of this {@link Contributor}. + */ @Nonnull public String getDisplayName() { return ChatColor.GRAY + githubUsername + (!githubUsername.equals(minecraftUsername) ? ChatColor.DARK_GRAY + " (MC: " + minecraftUsername + ")" : ""); } - public void lock() { - locked = true; + /** + * This returns the position on where to order this {@link Contributor}. + * This is just a convenience method for a {@link Comparator}, it is equivalent to + * {@link #getTotalContributions()} multiplied by minus one. + * + * @return The position of this {@link Contributor} in terms for positioning and ordering. + */ + public int getPosition() { + return -getTotalContributions(); + } + + /** + * This marks this {@link Contributor} as immutable. + * Immutable {@link Contributor Contributors} will no longer be assigned any contributions. + * This is useful when you want to prevent some commits from counting twice. + */ + public void setImmutable() { + immutable = true; } } 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 f7d103f24..29b66a083 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 @@ -8,6 +8,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -37,6 +38,7 @@ public class GitHubService { private boolean logging = false; private LocalDateTime lastUpdate = LocalDateTime.now(); + private int openIssues = 0; private int pendingPullRequests = 0; private int publicForks = 0; @@ -56,9 +58,18 @@ public class GitHubService { loadConnectors(false); } + /** + * This will start the {@link GitHubService} and run the asynchronous {@link GitHubTask} + * every so often to update its data. + * + * @param plugin + * Our instance of {@link SlimefunPlugin} + */ public void start(@Nonnull SlimefunPlugin plugin) { + long period = TimeUnit.HOURS.toMillis(1); GitHubTask task = new GitHubTask(this); - plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, task, 80L, 60 * 60 * 20L); + + plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, task, 80L, period); } /** @@ -215,8 +226,16 @@ public class GitHubService { texturesCache.save(); } + /** + * This returns the cached skin texture for a given username. + * + * @param username + * The minecraft username + * + * @return The cached skin texture for that user (or null) + */ @Nullable - protected String getCachedTexture(@Nonnull String name) { - return texturesCache.getString(name); + protected String getCachedTexture(@Nonnull String username) { + return texturesCache.getString(username); } } 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 151afa635..26e1f2c63 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 @@ -39,17 +39,23 @@ class GitHubTask implements Runnable { @Override public void run() { - gitHubService.getConnectors().forEach(GitHubConnector::download); + connectAndCache(); grabTextures(); } + private void connectAndCache() { + gitHubService.getConnectors().forEach(GitHubConnector::download); + } + /** * 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. + /** + * Store all queried usernames to prevent 429 responses for pinging + * the same URL twice in one run. + */ Map skins = new HashMap<>(); int requests = 0; @@ -73,8 +79,11 @@ class GitHubTask implements Runnable { } } - // We only wanna save this if all Connectors finished already - // This will run multiple times but thats okay, this way we get as much data as possible stored + /** + * We only wanna save this if all Connectors finished already. + * This will run multiple times but thats okay, this way we get as much + * data as possible stored. + */ gitHubService.saveCache(); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java index c82fea35f..ea847bb98 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Translators.java @@ -183,7 +183,7 @@ public class Translators { Contributor contributor = github.addContributor(minecraftName, "https://github.com/" + username, "translator," + lang.getLanguageId(), 0); if (lock) { - contributor.lock(); + contributor.setImmutable(); } } 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 486c59af8..511d5f6c9 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 @@ -11,7 +11,14 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; import me.mrCookieSlime.EmeraldEnchants.EnchantmentGuide; +import me.mrCookieSlime.Slimefun.Objects.Category; +/** + * This is the EmeraldEnchants {@link Category} + * + * @deprecated Support for EmeraldEnchants is being faded out + * + */ @Deprecated class EmeraldEnchantsCategory extends FlexCategory { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceRating.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceRating.java index b1417b523..130898eab 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceRating.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/PerformanceRating.java @@ -45,7 +45,7 @@ public enum PerformanceRating implements Predicate { @Override public boolean test(@Nullable Float value) { if (value == null) { - // null will only test true for UNKNOWN + // This way null will only test true for UNKNOWN return threshold < 0; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/ProfiledBlock.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/ProfiledBlock.java index 8a4e68d0d..6348d0d07 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/ProfiledBlock.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/ProfiledBlock.java @@ -1,8 +1,11 @@ package io.github.thebusybiscuit.slimefun4.core.services.profiler; +import java.util.Objects; + import javax.annotation.Nonnull; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.Block; import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; @@ -11,44 +14,129 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; /** * This represents an entry in our {@link SlimefunProfiler}. + * It is a modification of {@link BlockPosition} to be as memory-efficient as possible. * * @author TheBusyBiscuit * */ -class ProfiledBlock { +final class ProfiledBlock { - private final BlockPosition position; + /** + * The {@link World} this {@link Block} is in. + * It is fine to keep an actual reference here since this is a throwaway object anyway. + */ + private final World world; + + /** + * A {@link Long} representation of our {@link Location} (x, y, z). + */ + private final long position; + + /** + * The {@link SlimefunItem} whihc is located at this {@link Location}. + */ private final SlimefunItem item; + /** + * This creates a new {@link ProfiledBlock} for the given {@link Location} and + * the {@link SlimefunItem} found at this {@link Location}. + * + * @param l + * The {@link Location} + * @param item + * The {@link SlimefunItem} found at that {@link Location} + */ ProfiledBlock(@Nonnull Location l, @Nonnull SlimefunItem item) { - this.position = new BlockPosition(l); - this.item = item; - } - - ProfiledBlock(@Nonnull BlockPosition position, @Nonnull SlimefunItem item) { - this.position = position; + this.world = l.getWorld(); + this.position = getLocationAsLong((int) l.getX(), (int) l.getY(), (int) l.getZ()); this.item = item; } /** * This is just a dummy constructor. + * Please only use this for comparisons or lookups. * * @param b * A {@link Block} */ ProfiledBlock(@Nonnull Block b) { - this.position = new BlockPosition(b); + this.world = b.getWorld(); + this.position = getLocationAsLong(b.getX(), b.getY(), b.getZ()); this.item = null; } - public BlockPosition getPosition() { - return position; + /** + * This compresses our {@link Location} into a long for more efficient memory usage + * + * @param x + * The x value + * @param y + * The y value + * @param z + * The z value + * + * @return A {@link Long} representation of this {@link Location} + */ + private static long getLocationAsLong(int x, int y, int z) { + return ((long) (x & 0x3FFFFFF) << 38) | ((long) (z & 0x3FFFFFF) << 12) | (long) (y & 0xFFF); } + @Nonnull + public World getWorld() { + return world; + } + + /** + * Gets the x for this block. + * + * @return This blocks x coordinate. + */ + public int getX() { + return (int) (this.position >> 38); + } + + /** + * Gets the y for this block. + * + * @return This blocks y coordinate. + */ + public int getY() { + return (int) (this.position & 0xFFF); + } + + /** + * Gets the z for this block. + * + * @return This blocks z coordinate. + */ + public int getZ() { + return (int) (this.position << 26 >> 38); + } + + /** + * Gets the chunks x coordinate for this block. + * + * @return The blocks chunks x coordinate. + */ + public int getChunkX() { + return this.getX() >> 4; + } + + /** + * Gets the chunks z coordinate for this block. + * + * @return The blocks chunks z coordinate. + */ + public int getChunkZ() { + return this.getZ() >> 4; + } + + @Nonnull public String getId() { return item.getId(); } + @Nonnull public SlimefunAddon getAddon() { return item.getAddon(); } @@ -56,7 +144,8 @@ class ProfiledBlock { @Override public boolean equals(Object obj) { if (obj instanceof ProfiledBlock) { - return position.equals(((ProfiledBlock) obj).position); + ProfiledBlock block = (ProfiledBlock) obj; + return position == block.position && Objects.equals(world, block.world); } return false; @@ -64,7 +153,8 @@ class ProfiledBlock { @Override public int hashCode() { - return position.hashCode(); + long hilo = world.getUID().getMostSignificantBits() ^ world.getUID().getLeastSignificantBits(); + return (int) (position ^ (position >> 32) ^ hilo ^ (hilo >> 32)); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java index 5a0d92d9a..922fa2ff9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java @@ -42,11 +42,15 @@ import me.mrCookieSlime.Slimefun.api.Slimefun; */ public class SlimefunProfiler { - // A minecraft server tick is 50ms and Slimefun ticks are stretched across - // two ticks (sync and async blocks), so we use 100ms as a reference here + /** + * A minecraft server tick is 50ms and Slimefun ticks are stretched + * across two ticks (sync and async blocks), so we use 100ms as a reference here + */ private static final int MAX_TICK_DURATION = 100; - private final ExecutorService executor = Executors.newFixedThreadPool(5); + private final SlimefunThreadFactory threadFactory = new SlimefunThreadFactory(5); + private final ExecutorService executor = Executors.newFixedThreadPool(threadFactory.getThreadCount(), threadFactory); + private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicInteger queued = new AtomicInteger(0); @@ -139,8 +143,6 @@ public class SlimefunProfiler { return; } - // Since we got more than one Thread in our pool, - // blocking this one is (hopefully) completely fine executor.execute(this::finishReport); } @@ -151,6 +153,10 @@ public class SlimefunProfiler { // Wait for all timing results to come in while (!running.get() && queued.get() > 0) { try { + /** + * Since we got more than one Thread in our pool, + * blocking this one is (hopefully) completely fine + */ Thread.sleep(1); iterations--; @@ -162,6 +168,7 @@ public class SlimefunProfiler { iterator.next().sendMessage("Your timings report has timed out, we were still waiting for " + queued.get() + " samples to be collected :/"); iterator.remove(); } + return; } } catch (InterruptedException e) { @@ -228,9 +235,10 @@ public class SlimefunProfiler { Map map = new HashMap<>(); for (Map.Entry entry : timings.entrySet()) { - String world = entry.getKey().getPosition().getWorld().getName(); - int x = entry.getKey().getPosition().getChunkX(); - int z = entry.getKey().getPosition().getChunkZ(); + ProfiledBlock block = entry.getKey(); + String world = block.getWorld().getName(); + int x = block.getChunkX(); + int z = block.getChunkZ(); map.merge(world + " (" + x + ',' + z + ')', entry.getValue(), Long::sum); } @@ -243,9 +251,9 @@ public class SlimefunProfiler { int blocks = 0; for (ProfiledBlock block : timings.keySet()) { - String world = block.getPosition().getWorld().getName(); - int x = block.getPosition().getChunkX(); - int z = block.getPosition().getChunkZ(); + String world = block.getWorld().getName(); + int x = block.getChunkX(); + int z = block.getChunkZ(); if (chunk.equals(world + " (" + x + ',' + z + ')')) { blocks++; @@ -284,6 +292,7 @@ public class SlimefunProfiler { protected float getPercentageOfTick() { float millis = totalElapsedTime / 1000000.0F; float fraction = (millis * 100.0F) / MAX_TICK_DURATION; + return Math.round((fraction * 100.0F) / 100.0F); } @@ -305,6 +314,7 @@ public class SlimefunProfiler { return PerformanceRating.UNKNOWN; } + @Nonnull public String getTime() { return NumberUtils.getAsMillis(totalElapsedTime); } @@ -324,6 +334,7 @@ public class SlimefunProfiler { */ public boolean hasTimings(@Nonnull Block b) { Validate.notNull("Cannot get timings for a null Block"); + return timings.containsKey(new ProfiledBlock(b)); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunThreadFactory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunThreadFactory.java new file mode 100644 index 000000000..75fad3ca6 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunThreadFactory.java @@ -0,0 +1,49 @@ +package io.github.thebusybiscuit.slimefun4.core.services.profiler; + +import java.util.concurrent.ThreadFactory; + +import javax.annotation.Nonnull; + +/** + * This is our {@link ThreadFactory} for the {@link SlimefunProfiler}. + * It holds the amount of {@link Thread Threads} we dedicate towards our {@link SlimefunProfiler} + * and provides a naming convention for our {@link Thread Threads}. + * + * @author TheBusyBiscuit + * + * @see SlimefunProfiler + * + */ +final class SlimefunThreadFactory implements ThreadFactory { + + private final int threadCount; + + /** + * This constructs a new {@link SlimefunThreadFactory} with the given {@link Thread} count. + * + * @param threadCount + * The amount of {@link Thread Threads} to provide to the {@link SlimefunProfiler} + */ + SlimefunThreadFactory(int threadCount) { + this.threadCount = threadCount; + } + + /** + * This returns the amount of {@link Thread Threads} we dedicate towards + * the {@link SlimefunProfiler}. + * + * @return The {@link Thread} count + */ + int getThreadCount() { + return threadCount; + } + + /** + * This creates a new {@link Thread} for the {@link SlimefunProfiler}. + */ + @Override + public Thread newThread(@Nonnull Runnable runnable) { + return new Thread(runnable, "Slimefun Profiler"); + } + +} 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 5f68e896d..4bb3e82f5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -18,7 +18,7 @@ import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.core.attributes.MachineTier; import io.github.thebusybiscuit.slimefun4.core.attributes.MachineType; import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactivity; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.StormStaff; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.StormStaff; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; import io.github.thebusybiscuit.slimefun4.utils.LoreBuilder; @@ -403,7 +403,7 @@ public final class SlimefunItems { public static final SlimefunItemStack ELECTRIC_MOTOR = new SlimefunItemStack("ELECTRIC_MOTOR", HeadTexture.MOTOR, "&cElectric Motor"); public static final SlimefunItemStack CARGO_MOTOR = new SlimefunItemStack("CARGO_MOTOR", HeadTexture.MOTOR, "&3Cargo Motor"); public static final SlimefunItemStack SCROLL_OF_DIMENSIONAL_TELEPOSITION = new SlimefunItemStack("SCROLL_OF_DIMENSIONAL_TELEPOSITION", Material.PAPER, "&6Scroll of Dimensional Teleposition", "", "&cThis Scroll is capable of creating", "&ca temporary black Hole which pulls", "&cnearby Entities into itself and sends", "&cthem into another Dimension where", "&ceverything is turned around", "", "&fIn other words: Makes Entities turn by 180 Degrees"); - public static final SlimefunItemStack TOME_OF_KNOWLEDGE_SHARING = new SlimefunItemStack("TOME_OF_KNOWLEDGE_SHARING", Material.BOOK, "&6Tome of Knowledge Sharing", "&7Owner: &bNone", "", "&eRight Click&7 to bind this Tome to yourself", "", "", "&eRight Click&7 to obtain all Researches by", "&7the previously assigned Owner"); + public static final SlimefunItemStack TOME_OF_KNOWLEDGE_SHARING = new SlimefunItemStack("TOME_OF_KNOWLEDGE_SHARING", Material.ENCHANTED_BOOK, "&6Tome of Knowledge Sharing", "&7Owner: &bNone", "", "&eRight Click&7 to bind this Tome to yourself", "", "", "&eRight Click&7 to obtain all Researches by", "&7the previously assigned Owner"); public static final SlimefunItemStack HARDENED_GLASS = new SlimefunItemStack("HARDENED_GLASS", Material.LIGHT_GRAY_STAINED_GLASS, "&7Hardened Glass", "", "&fWithstands Explosions"); public static final SlimefunItemStack WITHER_PROOF_OBSIDIAN = new SlimefunItemStack("WITHER_PROOF_OBSIDIAN", Material.OBSIDIAN, "&5Wither-Proof Obsidian", "", "&fWithstands Explosions", "&fWithstands Wither Bosses"); public static final SlimefunItemStack WITHER_PROOF_GLASS = new SlimefunItemStack("WITHER_PROOF_GLASS", Material.PURPLE_STAINED_GLASS, "&5Wither-Proof Glass", "", "&fWithstands Explosions", "&fWithstands Wither Bosses"); 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 c6ae714e6..f1dcdae3a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java @@ -12,6 +12,7 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; @@ -75,9 +76,11 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.FireworksList import io.github.thebusybiscuit.slimefun4.implementation.listeners.GadgetsListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.GrapplingHookListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.IronGolemListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemDropListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.MobDropListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.PiglinListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.PlayerProfileListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.SeismicAxeListener; @@ -85,7 +88,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunBoots import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunBowListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunGuideListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunItemConsumeListener; -import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunItemListener; +import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunItemInteractListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.SoulboundListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.TalismanListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.VampireBladeListener; @@ -117,7 +120,6 @@ import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu; /** * This is the main class of Slimefun. * This is where all the magic starts, take a look around. - * Feel like home. * * @author TheBusyBiscuit */ @@ -162,15 +164,36 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { private final BackpackListener backpackListener = new BackpackListener(); private final SlimefunBowListener bowListener = new SlimefunBowListener(); + /** + * Our default constructor for {@link SlimefunPlugin}. + */ public SlimefunPlugin() { super(); } + /** + * This constructor is invoked in Unit Test environments only. + * + * @param loader + * Our {@link JavaPluginLoader} + * @param description + * A {@link PluginDescriptionFile} + * @param dataFolder + * The data folder + * @param file + * A {@link File} for this {@link Plugin} + */ + @ParametersAreNonnullByDefault public SlimefunPlugin(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) { super(loader, description, dataFolder, file); + + // This is only invoked during a Unit Test minecraftVersion = MinecraftVersion.UNIT_TEST; } + /** + * This is called when the {@link Plugin} has been loaded and enabled on a {@link Server}. + */ @Override public void onEnable() { instance = this; @@ -219,7 +242,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { networkSize = 1; } - networkManager = new NetworkManager(networkSize, config.getBoolean("networks.enable-visualizer")); + networkManager = new NetworkManager(networkSize, config.getBoolean("networks.enable-visualizer"), config.getBoolean("networks.delete-excess-items")); // Setting up bStats new Thread(metricsService::start, "Slimefun Metrics").start(); @@ -303,12 +326,83 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { } } + /** + * This is our start method for a Unit Test environment. + */ private void onUnitTestStart() { local = new LocalizationService(this, "", null); gpsNetwork = new GPSNetwork(); - networkManager = new NetworkManager(200, true); + networkManager = new NetworkManager(200); command.register(); registry.load(config); + loadTags(); + } + + /** + * This method gets called when the {@link Plugin} gets disabled. + * Most often it is called when the {@link Server} is shutting down or reloading. + */ + @Override + public void onDisable() { + // Slimefun never loaded successfully, so we don't even bother doing stuff here + if (instance() == null || minecraftVersion == MinecraftVersion.UNIT_TEST) { + return; + } + + // Cancel all tasks from this plugin immediately + Bukkit.getScheduler().cancelTasks(this); + + // Finishes all started movements/removals of block data + ticker.halt(); + ticker.run(); + + // Save all Player Profiles that are still in memory + PlayerProfile.iterator().forEachRemaining(profile -> { + if (profile.isDirty()) { + profile.save(); + } + }); + + // Save all registered Worlds + for (Map.Entry entry : getRegistry().getWorlds().entrySet()) { + try { + entry.getValue().saveAndRemove(); + } catch (Exception x) { + getLogger().log(Level.SEVERE, x, () -> "An Error occurred while saving Slimefun-Blocks in World '" + entry.getKey() + "' for Slimefun " + getVersion()); + } + } + + for (UniversalBlockMenu menu : registry.getUniversalInventories().values()) { + menu.save(); + } + + // Create a new backup zip + backupService.run(); + + metricsService.cleanUp(); + + /** + * Prevent Memory Leaks for reloads... + * These static Maps should really be removed at some point... + */ + AContainer.processing = null; + AContainer.progress = null; + + AGenerator.processing = null; + AGenerator.progress = null; + + Reactor.processing = null; + Reactor.progress = null; + + instance = null; + + /** + * Close all inventories on the server to prevent item dupes + * (Incase some idiot uses /reload) + */ + for (Player p : Bukkit.getOnlinePlayers()) { + p.closeInventory(); + } } @Nonnull @@ -368,65 +462,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { return list; } - @Override - public void onDisable() { - // Slimefun never loaded successfully, so we don't even bother doing stuff here - if (instance() == null || minecraftVersion == MinecraftVersion.UNIT_TEST) { - return; - } - - // Cancel all tasks from this plugin immediately - Bukkit.getScheduler().cancelTasks(this); - - // Finishes all started movements/removals of block data - ticker.halt(); - ticker.run(); - - // Save all Player Profiles that are still in memory - PlayerProfile.iterator().forEachRemaining(profile -> { - if (profile.isDirty()) { - profile.save(); - } - }); - - // Save all registered Worlds - for (Map.Entry entry : getRegistry().getWorlds().entrySet()) { - try { - entry.getValue().saveAndRemove(); - } catch (Exception x) { - getLogger().log(Level.SEVERE, x, () -> "An Error occurred while saving Slimefun-Blocks in World '" + entry.getKey() + "' for Slimefun " + getVersion()); - } - } - - for (UniversalBlockMenu menu : registry.getUniversalInventories().values()) { - menu.save(); - } - - // Create a new backup zip - backupService.run(); - - metricsService.cleanUp(); - - // Prevent Memory Leaks - // These static Maps should be removed at some point... - AContainer.processing = null; - AContainer.progress = null; - - AGenerator.processing = null; - AGenerator.progress = null; - - Reactor.processing = null; - Reactor.progress = null; - - instance = null; - - // Close all inventories on the server to prevent item dupes - // (Incase some idiot uses /reload) - for (Player p : Bukkit.getOnlinePlayers()) { - p.closeInventory(); - } - } - private void createDirectories() { String[] storageFolders = { "Players", "blocks", "stored-blocks", "stored-inventories", "stored-chunks", "universal-inventories", "waypoints", "block-backups" }; String[] pluginFolders = { "scripts", "error-reports", "cache/github", "world-settings" }; @@ -450,7 +485,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { private void registerListeners() { new SlimefunBootsListener(this); - new SlimefunItemListener(this); + new SlimefunItemInteractListener(this); new SlimefunItemConsumeListener(this); new BlockPhysicsListener(this); new CargoNodeListener(this); @@ -460,6 +495,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new BlockListener(this); new EnhancedFurnaceListener(this); new ItemPickupListener(this); + new ItemDropListener(this); new DeathpointListener(this); new ExplosionsListener(this); new DebugFishListener(this); @@ -477,6 +513,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { new GrindstoneListener(this); new CartographyTableListener(this); new HopperListener(this); + new NetworkListener(this, networkManager); if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) { new BeeListener(this); @@ -517,7 +554,10 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { private void loadTags() { for (SlimefunTag tag : SlimefunTag.valuesCache) { try { - tag.reload(); + // Only reload "empty" (or unloaded) Tags + if (tag.isEmpty()) { + tag.reload(); + } } catch (TagMisconfigurationException e) { getLogger().log(Level.SEVERE, e, () -> "Failed to load Tag: " + tag.name()); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java index 26f894046..a5c7c1d29 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java @@ -215,11 +215,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation { ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.RED, item.getItemName()) + "\n"); component.setHoverEvent(new HoverEvent(ChatColor.RESET + item.getItemName(), ChatColor.DARK_RED.toString() + ChatColor.BOLD + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", ChatColor.GREEN + "> Click to unlock", "", ChatColor.GRAY + "Cost: " + ChatColor.AQUA.toString() + research.getCost() + " Level(s)")); - component.setClickEvent(new ClickEvent(key, player -> - SlimefunPlugin.runSync(() -> - research.unlockFromGuide(this, player, profile, item, category, page) - ) - )); + component.setClickEvent(new ClickEvent(key, player -> SlimefunPlugin.runSync(() -> research.unlockFromGuide(this, player, profile, item, category, page)))); items.add(component); } else { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/armor/StomperBoots.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/armor/StomperBoots.java index ca23601bc..8438d7950 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/armor/StomperBoots.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/armor/StomperBoots.java @@ -52,7 +52,7 @@ public class StomperBoots extends SlimefunItem { n.setVelocity(velocity); // Check if it's not a Player or if PvP is enabled - if (!(n instanceof Player) || (p.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, n.getLocation(), ProtectableAction.PVP))) { + if (!(n instanceof Player) || (p.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, n.getLocation(), ProtectableAction.ATTACK_PLAYER))) { EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(p, n, DamageCause.ENTITY_ATTACK, fallDamageEvent.getDamage() / 2); Bukkit.getPluginManager().callEvent(event); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java index 810cdf699..f5800321d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java @@ -79,21 +79,25 @@ public class BlockPlacer extends SlimefunItem { Material material = e.getItem().getType(); if (SlimefunTag.SHULKER_BOXES.isTagged(material)) { - // Since vanilla Dispensers can already place Shulker boxes, we - // simply fallback to the vanilla behaviour. + /** + * Since vanilla Dispensers can already place Shulker boxes, + * we simply fallback to the vanilla behaviour. + */ return; } e.setCancelled(true); if (!material.isBlock() || SlimefunTag.BLOCK_PLACER_IGNORED_MATERIALS.isTagged(material)) { - // Some materials cannot be reliably placed, like beds, it would look - // kinda wonky, so we just ignore these altogether. - // The event has already been cancelled too, so they won't drop. + /** + * Some materials cannot be reliably placed, like beds, + * it would look kinda wonky, so we just ignore these altogether. + * The event has already been cancelled too, so they won't drop. + */ return; } - if (facedBlock.isEmpty() && !isBlacklisted(material)) { + if (facedBlock.isEmpty() && !isBlacklisted(material) && dispenser.getInventory().getViewers().isEmpty()) { SlimefunItem item = SlimefunItem.getByItem(e.getItem()); if (item != null) { @@ -123,9 +127,11 @@ public class BlockPlacer extends SlimefunItem { String owner = BlockStorage.getLocationInfo(dispenser.getLocation(), "owner"); if (owner == null) { - // If no owner was set, then we will fallback to the previous behaviour: - // Allowing block placers to bypass protection, newly placed Block placers - // will respect protection plugins. + /** + * If no owner was set, then we will fallback to the previous behaviour: + * Allowing block placers to bypass protection, newly placed Block placers + * will respect protection plugins. + */ return true; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java index a884c8733..183eb3fc3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Composter.java @@ -83,7 +83,7 @@ public class Composter extends SimpleSlimefunItem implements Re Player p = e.getPlayer(); Block b = block.get(); - if (p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES)) { + if (p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK)) { ItemStack input = e.getItem(); ItemStack output = getOutput(p, input); 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 73cd1902f..9f84d8bf9 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 @@ -95,7 +95,7 @@ public class Crucible extends SimpleSlimefunItem implements Rec Player p = e.getPlayer(); Block b = optional.get(); - if (p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES)) { + if (p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK)) { ItemStack input = e.getItem(); Block block = b.getRelative(BlockFace.UP); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractCargoNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractCargoNode.java index 723ad0df3..8f2f779c0 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractCargoNode.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractCargoNode.java @@ -65,7 +65,7 @@ abstract class AbstractCargoNode extends SlimefunItem { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.cargo.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.cargo.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java index 05791763c..8f04493dd 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java @@ -46,7 +46,7 @@ public class ReactorAccessPort extends SlimefunItem { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java index e8d5b962f..b6eb0c527 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java @@ -80,7 +80,7 @@ public abstract class AbstractEntityAssembler extends SimpleSl @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override @@ -183,7 +183,7 @@ public abstract class AbstractEntityAssembler extends SimpleSl return; } - if (lifetime % 60 == 0 && getCharge(b.getLocation()) >= getEnergyConsumption()) { + if (lifetime % 60 == 0 && getCharge(b.getLocation(), data) >= getEnergyConsumption()) { BlockMenu menu = BlockStorage.getInventory(b); boolean hasBody = findResource(menu, getBody(), bodySlots); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java index 268736c13..37a5d8f3c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java @@ -86,7 +86,7 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java index 6c29a3337..b9c8dbcc0 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricSmeltery.java @@ -53,7 +53,7 @@ public class ElectricSmeltery extends AbstractVanillaBlockInventory { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java index d5a2168ee..1190831ae 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/FluidPump.java @@ -2,6 +2,10 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -13,12 +17,12 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.blocks.Vein; -import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; @@ -49,6 +53,9 @@ public class FluidPump extends SimpleSlimefunItem implements Invent private final int[] inputBorder = { 9, 10, 11, 12, 18, 21, 27, 28, 29, 30 }; private final int[] outputBorder = { 14, 15, 16, 17, 23, 26, 32, 33, 34, 35 }; + private final ItemStack emptyBucket = new ItemStackWrapper(Material.BUCKET); + + @ParametersAreNonnullByDefault public FluidPump(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); @@ -66,16 +73,16 @@ public class FluidPump extends SimpleSlimefunItem implements Invent }); } - private void constructMenu(BlockMenuPreset preset) { + private void constructMenu(@Nonnull BlockMenuPreset preset) { for (int i : border) { - preset.addItem(i, new CustomItem(Material.GRAY_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler()); } for (int i : inputBorder) { - preset.addItem(i, new CustomItem(Material.CYAN_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(i, ChestMenuUtils.getInputSlotTexture(), ChestMenuUtils.getEmptyClickHandler()); } for (int i : outputBorder) { - preset.addItem(i, new CustomItem(Material.ORANGE_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(i, ChestMenuUtils.getOutputSlotTexture(), ChestMenuUtils.getEmptyClickHandler()); } for (int i : getOutputSlots()) { @@ -114,14 +121,14 @@ public class FluidPump extends SimpleSlimefunItem implements Invent return 512; } - protected void tick(Block b) { + protected void tick(@Nonnull Block b) { Block fluid = b.getRelative(BlockFace.DOWN); if (fluid.isLiquid() && getCharge(b.getLocation()) >= ENERGY_CONSUMPTION) { BlockMenu menu = BlockStorage.getInventory(b); for (int slot : getInputSlots()) { - if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.BUCKET), true, false)) { + if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), emptyBucket, true, false)) { ItemStack bucket = getFilledBucket(fluid); if (!menu.fits(bucket, getOutputSlots())) { @@ -143,11 +150,14 @@ public class FluidPump extends SimpleSlimefunItem implements Invent } } - private Block findNextFluid(Block fluid) { + @Nullable + private Block findNextFluid(@Nonnull Block fluid) { if (fluid.getType() == Material.WATER || fluid.getType() == Material.BUBBLE_COLUMN) { - // With water we can be sure to find an infinite source whenever we go - // further than a block, so we can just remove the water here and save - // ourselves all of that computing... + /** + * With water we can be sure to find an infinite source whenever we + * go further than a block, so we can just remove the water here and + * save ourselves all of that computing... + */ if (isSource(fluid)) { return fluid; } @@ -162,10 +172,12 @@ public class FluidPump extends SimpleSlimefunItem implements Invent } } } + return null; } - private ItemStack getFilledBucket(Block fluid) { + @Nonnull + private ItemStack getFilledBucket(@Nonnull Block fluid) { if (fluid.getType() == Material.LAVA) { return new ItemStack(Material.LAVA_BUCKET); } else if (fluid.getType() == Material.WATER || fluid.getType() == Material.BUBBLE_COLUMN) { @@ -184,7 +196,7 @@ public class FluidPump extends SimpleSlimefunItem implements Invent * * @return Whether that {@link Block} is a liquid and a source {@link Block}. */ - private boolean isSource(Block block) { + private boolean isSource(@Nonnull Block block) { if (block.isLiquid()) { BlockData data = block.getBlockData(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/HeatedPressureChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/HeatedPressureChamber.java index d013afb02..95b62ac1f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/HeatedPressureChamber.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/HeatedPressureChamber.java @@ -37,7 +37,7 @@ public class HeatedPressureChamber extends AContainer { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java index 010cee0ad..46aa72c8f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java @@ -98,7 +98,7 @@ public abstract class Reactor extends AbstractEnergyProvider { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java index 63e61042b..1c9062a55 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java @@ -45,6 +45,6 @@ public class GEOScanner extends SimpleSlimefunItem { @ParametersAreNonnullByDefault private boolean hasAccess(Player p, Location l) { - return p.hasPermission("slimefun.gps.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, l, ProtectableAction.ACCESS_INVENTORIES)); + return p.hasPermission("slimefun.gps.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, l, ProtectableAction.INTERACT_BLOCK)); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java index fb4bfe1c0..9520b89ee 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java @@ -43,7 +43,7 @@ public class OilPump extends AContainer implements RecipeDisplayItem { @Override public boolean canOpen(Block b, Player p) { - if (!(p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES))) { + if (!(p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK))) { return false; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java index aeffe8f77..1d7dc7ae0 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java @@ -36,34 +36,47 @@ import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link ElevatorPlate} is a quick way of teleportation. + * You can place multiple {@link ElevatorPlate ElevatorPlates} along the y axis + * to teleport between them. + * + * @author TheBusyBiscuit + * + */ public class ElevatorPlate extends SimpleSlimefunItem { + /** + * This is our key for storing the floor name. + */ private static final String DATA_KEY = "floor"; + + /** + * This is our {@link Set} of currently teleporting {@link Player Players}. + * It is used to prevent them from triggering the {@link ElevatorPlate} they land on. + */ private final Set users = new HashSet<>(); + @ParametersAreNonnullByDefault public ElevatorPlate(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) { super(category, item, recipeType, recipe, recipeOutput); addItemHandler(onPlace()); } + @Nonnull private BlockPlaceHandler onPlace() { return new BlockPlaceHandler(false) { @Override public void onPlayerPlace(BlockPlaceEvent e) { Block b = e.getBlock(); - BlockStorage.addBlockInfo(b, DATA_KEY, "&rFloor #0"); + BlockStorage.addBlockInfo(b, DATA_KEY, ChatColor.WHITE + "Floor #0"); BlockStorage.addBlockInfo(b, "owner", e.getPlayer().getUniqueId().toString()); } }; } - @Nonnull - public Set getUsers() { - return users; - } - @Override public BlockUseHandler getItemHandler() { return e -> { @@ -172,7 +185,7 @@ public class ElevatorPlate extends SimpleSlimefunItem { public void openEditor(Player p, Block b) { ChestMenu menu = new ChestMenu("Elevator Settings"); - menu.addItem(4, new CustomItem(Material.NAME_TAG, "&7Floor Name &e(Click to edit)", "", "&r" + ChatColors.color(BlockStorage.getLocationInfo(b.getLocation(), DATA_KEY)))); + menu.addItem(4, new CustomItem(Material.NAME_TAG, "&7Floor Name &e(Click to edit)", "", ChatColor.WHITE + ChatColors.color(BlockStorage.getLocationInfo(b.getLocation(), DATA_KEY)))); menu.addMenuClickHandler(4, (pl, slot, item, action) -> { pl.closeInventory(); pl.sendMessage(""); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java index 27d771eba..c1da15310 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java @@ -43,6 +43,6 @@ public class GPSControlPanel extends SimpleSlimefunItem { @ParametersAreNonnullByDefault private boolean hasAccess(Player p, Location l) { - return p.hasPermission("slimefun.gps.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, l, ProtectableAction.ACCESS_INVENTORIES)); + return p.hasPermission("slimefun.gps.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, l, ProtectableAction.INTERACT_BLOCK)); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java index 30d03c851..ecdf45d34 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java @@ -60,7 +60,7 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem imp @Override public void tick(Block b, SlimefunItem item, Config data) { - int charge = getCharge(b.getLocation()); + int charge = getCharge(b.getLocation(), data); UUID owner = UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner")); if (charge >= getEnergyConsumption()) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/InfusedHopper.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/InfusedHopper.java similarity index 65% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/InfusedHopper.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/InfusedHopper.java index 26f776093..84f69890a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/InfusedHopper.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/InfusedHopper.java @@ -1,10 +1,14 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.blocks; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.SoundCategory; import org.bukkit.block.Block; +import org.bukkit.block.data.type.Hopper; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.inventory.ItemStack; @@ -22,15 +26,27 @@ import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link InfusedHopper} is a special kind of {@link Hopper} which teleports any + * neaby {@link Item} to itself. + * The radius can be configured in the config. + * + * @author TheBusyBiscuit + * + * @see InfusedMagnet + * + */ public class InfusedHopper extends SimpleSlimefunItem { private final ItemSetting silent = new ItemSetting<>("silent", false); + private final ItemSetting toggleable = new ItemSetting<>("toggleable-with-redstone", false); private final ItemSetting radius = new DoubleRangeSetting("radius", 0.1, 3.5, Double.MAX_VALUE); + @ParametersAreNonnullByDefault public InfusedHopper(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); - addItemSetting(silent, radius); + addItemSetting(silent, radius, toggleable); } @Override @@ -45,17 +61,35 @@ public class InfusedHopper extends SimpleSlimefunItem { return; } - Location l = b.getLocation().add(0.5, 1.2, 0.5); - boolean sound = false; - double range = radius.getValue(); + // Check if this was enabled in the config + if (toggleable.getValue()) { + Hopper hopper = (Hopper) b.getBlockData(); + /** + * If the Hopper was disabled by a redstone signal, + * we just don't do anything. + */ + if (!hopper.isEnabled()) { + return; + } + } + + Location l = b.getLocation().add(0.5, 1.2, 0.5); + double range = radius.getValue(); + boolean playSound = false; + + // Check for any nearby Items that can be picked up for (Entity item : b.getWorld().getNearbyEntities(l, range, range, range, n -> isValidItem(l, n))) { item.setVelocity(new Vector(0, 0.1, 0)); item.teleport(l); - sound = true; + playSound = true; } - if (sound && !silent.getValue().booleanValue()) { + /** + * Play a sound if at least one item was teleported and + * the "silent" setting is set to false. + */ + if (playSound && !silent.getValue().booleanValue()) { b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.BLOCKS, 1F, 2F); } } @@ -67,7 +101,7 @@ public class InfusedHopper extends SimpleSlimefunItem { }; } - private boolean isValidItem(Location l, Entity entity) { + private boolean isValidItem(@Nonnull Location l, @Nonnull Entity entity) { if (entity instanceof Item && entity.isValid()) { Item item = (Item) entity; return !SlimefunUtils.hasNoPickupFlag(item) && item.getLocation().distanceSquared(l) > 0.25; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicalZombiePills.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicalZombiePills.java index 5a67191c2..4ce043bc6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicalZombiePills.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicalZombiePills.java @@ -1,6 +1,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.GameMode; import org.bukkit.Location; @@ -14,6 +15,7 @@ import org.bukkit.entity.ZombieVillager; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; +import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; @@ -40,6 +42,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; */ public class MagicalZombiePills extends SimpleSlimefunItem implements NotPlaceable { + @ParametersAreNonnullByDefault public MagicalZombiePills(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) { super(category, item, recipeType, recipe, recipeOutput); @@ -50,6 +53,12 @@ public class MagicalZombiePills extends SimpleSlimefunItem { Entity entity = e.getRightClicked(); + + if (e.isCancelled() || !SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), entity.getLocation(), ProtectableAction.INTERACT_ENTITY)) { + // They don't have permission to use it in this area + return; + } + Player p = e.getPlayer(); if (entity instanceof ZombieVillager) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundItem.java index 94f2d46bd..a9f854379 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundItem.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundItem.java @@ -4,6 +4,7 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes.SoulboundRune; import io.github.thebusybiscuit.slimefun4.implementation.listeners.SoulboundListener; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnchantmentRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java similarity index 99% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnchantmentRune.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java index 7cf3a4362..4ca91cec6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnchantmentRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java @@ -1,4 +1,4 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.magical; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes; import java.util.ArrayList; import java.util.Collection; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java similarity index 97% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundRune.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java index 6415c6e23..dfde7821e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/SoulboundRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java @@ -1,4 +1,4 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.magical; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes; import java.util.Collection; import java.util.Optional; @@ -14,6 +14,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound; import io.github.thebusybiscuit.slimefun4.core.handlers.ItemDropHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundItem; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/VillagerRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java similarity index 84% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/VillagerRune.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java index 16eb4550a..4c9e5c451 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/VillagerRune.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/VillagerRune.java @@ -1,4 +1,4 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.magical; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes; import java.util.concurrent.ThreadLocalRandom; @@ -10,7 +10,9 @@ import org.bukkit.entity.Villager.Profession; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; +import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler; +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; @@ -33,6 +35,11 @@ public class VillagerRune extends SimpleSlimefunItem { @Override public EntityInteractHandler getItemHandler() { return (e, item, offhand) -> { + if (e.isCancelled() || !SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), e.getRightClicked().getLocation(), ProtectableAction.INTERACT_ENTITY)) { + // They don't have permission to use it in this area + return; + } + if (e.getRightClicked() instanceof Villager) { Villager v = (Villager) e.getRightClicked(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/package-info.java new file mode 100644 index 000000000..6286c42b0 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/package-info.java @@ -0,0 +1,5 @@ +/** + * This package holds any implementation of {@link me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem} + * that is an ancient rune with functionality. + */ +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/StormStaff.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java similarity index 99% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/StormStaff.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java index 11a69daac..17a09f4b8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/StormStaff.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java @@ -1,4 +1,4 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.magical; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves; import java.util.List; @@ -72,7 +72,7 @@ public class StormStaff extends SimpleSlimefunItem { Location loc = p.getTargetBlock(null, 30).getLocation(); if (loc.getWorld() != null && loc.getChunk().isLoaded()) { - if (loc.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, loc, ProtectableAction.PVP)) { + if (loc.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, loc, ProtectableAction.ATTACK_PLAYER)) { e.cancel(); useItem(p, item, loc); } else { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/WaterStaff.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/WaterStaff.java similarity index 98% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/WaterStaff.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/WaterStaff.java index ca0f26c6d..5686a52be 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/WaterStaff.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/WaterStaff.java @@ -1,4 +1,4 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.magical; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/WindStaff.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/WindStaff.java similarity index 76% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/WindStaff.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/WindStaff.java index 6ba3cddda..4be752939 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/WindStaff.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/WindStaff.java @@ -1,4 +1,4 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.magical; +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves; import org.bukkit.Bukkit; import org.bukkit.Effect; @@ -8,6 +8,8 @@ import org.bukkit.entity.Player; import org.bukkit.event.entity.FoodLevelChangeEvent; 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.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; @@ -15,10 +17,20 @@ import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link WindStaff} is a powerful staff which launches the {@link Player} forward when right clicked. + * + * @author TheBusyBiscuit + * + */ public class WindStaff extends SimpleSlimefunItem { + private final ItemSetting multiplier = new IntRangeSetting("power", 1, 4, Integer.MAX_VALUE); + public WindStaff(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); + + addItemSetting(multiplier); } @Override @@ -27,6 +39,7 @@ public class WindStaff extends SimpleSlimefunItem { Player p = e.getPlayer(); if (p.getFoodLevel() >= 2) { + // The isItem() check is here to prevent the MultiTool from consuming hunger if (isItem(e.getItem()) && p.getGameMode() != GameMode.CREATIVE) { FoodLevelChangeEvent event = new FoodLevelChangeEvent(p, p.getFoodLevel() - 2); Bukkit.getPluginManager().callEvent(event); @@ -36,7 +49,7 @@ public class WindStaff extends SimpleSlimefunItem { } } - p.setVelocity(p.getEyeLocation().getDirection().multiply(4)); + p.setVelocity(p.getEyeLocation().getDirection().multiply(multiplier.getValue())); p.getWorld().playSound(p.getLocation(), Sound.ENTITY_TNT_PRIMED, 1, 1); p.getWorld().playEffect(p.getLocation(), Effect.SMOKE, 1); p.setFallDistance(0F); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/package-info.java new file mode 100644 index 000000000..b937f26a3 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/package-info.java @@ -0,0 +1,5 @@ +/** + * This package holds any implementation of {@link me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem} that is + * considered a "Magical Staff". + */ +package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java index 0909fb3f4..2d9ff2068 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java @@ -57,6 +57,9 @@ public class MagicianTalisman extends Talisman { * * @param item * The {@link ItemStack} to find an {@link Enchantment} for + * @param existingEnchantments + * A {@link Set} containing the {@link Enchantment Enchantments} that currently exist on the + * {@link ItemStack} * * @return An applicable {@link TalismanEnchantment} or null */ 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 f5f79532f..a8d6d5a8c 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 @@ -21,7 +21,7 @@ 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 io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes.VillagerRune; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/ExplosiveBow.java index e73b78ea3..1086221b2 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 @@ -2,9 +2,13 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.weapons; import java.util.Collection; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Bukkit; import org.bukkit.Particle; import org.bukkit.Sound; +import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -33,6 +37,7 @@ public class ExplosiveBow extends SlimefunBow { private final ItemSetting range = new IntRangeSetting("explosion-range", 1, 3, Integer.MAX_VALUE); + @ParametersAreNonnullByDefault public ExplosiveBow(Category category, SlimefunItemStack item, ItemStack[] recipe) { super(category, item, recipe); @@ -44,8 +49,9 @@ public class ExplosiveBow extends SlimefunBow { return (e, target) -> { target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation(), 1); target.getWorld().playSound(target.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1, 1); + int radius = range.getValue(); - Collection entites = target.getWorld().getNearbyEntities(target.getLocation(), range.getValue(), range.getValue(), range.getValue(), entity -> entity instanceof LivingEntity && entity.isValid()); + Collection entites = target.getWorld().getNearbyEntities(target.getLocation(), radius, radius, radius, this::canDamage); for (Entity nearby : entites) { LivingEntity entity = (LivingEntity) nearby; @@ -71,6 +77,10 @@ public class ExplosiveBow extends SlimefunBow { }; } + private boolean canDamage(@Nonnull Entity n) { + return n instanceof LivingEntity && !(n instanceof ArmorStand) && n.isValid(); + } + private double calculateDamage(double distanceSquared, double originalDamage) { if (distanceSquared <= 0.05) { return originalDamage; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java index 53d43e5c8..9f810486b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java @@ -2,6 +2,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.weapons; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Bukkit; import org.bukkit.Effect; import org.bukkit.Location; @@ -42,6 +45,7 @@ public class SeismicAxe extends SimpleSlimefunItem implements No private static final float DAMAGE = 6; private static final int RANGE = 10; + @ParametersAreNonnullByDefault public SeismicAxe(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); } @@ -96,7 +100,8 @@ public class SeismicAxe extends SimpleSlimefunItem implements No } } - private Block findGround(Block b) { + @Nonnull + private Block findGround(@Nonnull Block b) { if (b.getType() == Material.AIR) { for (int y = 0; y < b.getY(); y++) { Block block = b.getRelative(0, -y, 0); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java index 9f2d14170..aee48bdf8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java @@ -3,8 +3,11 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.weapons; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Material; import org.bukkit.entity.Creeper; +import org.bukkit.entity.Monster; import org.bukkit.entity.Player; import org.bukkit.entity.Skeleton; import org.bukkit.entity.WitherSkeleton; @@ -21,6 +24,17 @@ import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link SwordOfBeheading} is a special kind of sword which allows you to obtain + * {@link Zombie}, {@link Skeleton} and {@link Creeper} skulls when killing the respective {@link Monster}. + * Additionally, you can also obtain the head of a {@link Player} by killing them too. + * This sword also allows you to have a higher chance of getting the skull of a {@link WitherSkeleton} too. + * + * All chances are managed by an {@link ItemSetting} and can be configured. + * + * @author TheBusyBiscuit + * + */ public class SwordOfBeheading extends SimpleSlimefunItem { private final ItemSetting chanceZombie = new IntRangeSetting("chance.ZOMBIE", 0, 40, 100); @@ -29,6 +43,7 @@ public class SwordOfBeheading extends SimpleSlimefunItem { private final ItemSetting chanceCreeper = new IntRangeSetting("chance.CREEPER", 0, 40, 100); private final ItemSetting chancePlayer = new IntRangeSetting("chance.PLAYER", 0, 70, 100); + @ParametersAreNonnullByDefault public SwordOfBeheading(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); @@ -40,29 +55,40 @@ public class SwordOfBeheading extends SimpleSlimefunItem { return (e, entity, killer, item) -> { Random random = ThreadLocalRandom.current(); - if (e.getEntity() instanceof Zombie) { + switch (e.getEntityType()) { + case ZOMBIE: if (random.nextInt(100) < chanceZombie.getValue()) { e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD)); } - } else if (e.getEntity() instanceof WitherSkeleton) { - if (random.nextInt(100) < chanceWitherSkeleton.getValue()) { - e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL)); - } - } else if (e.getEntity() instanceof Skeleton) { + break; + case SKELETON: if (random.nextInt(100) < chanceSkeleton.getValue()) { e.getDrops().add(new ItemStack(Material.SKELETON_SKULL)); } - } else if (e.getEntity() instanceof Creeper) { + break; + case CREEPER: if (random.nextInt(100) < chanceCreeper.getValue()) { e.getDrops().add(new ItemStack(Material.CREEPER_HEAD)); } - } else if (e.getEntity() instanceof Player && random.nextInt(100) < chancePlayer.getValue()) { - ItemStack skull = new ItemStack(Material.PLAYER_HEAD); - ItemMeta meta = skull.getItemMeta(); - ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity()); - skull.setItemMeta(meta); + break; + case WITHER_SKELETON: + if (random.nextInt(100) < chanceWitherSkeleton.getValue()) { + e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL)); + } + break; + case PLAYER: + if (random.nextInt(100) < chancePlayer.getValue()) { + ItemStack skull = new ItemStack(Material.PLAYER_HEAD); - e.getDrops().add(skull); + ItemMeta meta = skull.getItemMeta(); + ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity()); + skull.setItemMeta(meta); + + e.getDrops().add(skull); + } + break; + default: + break; } }; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/VampireBlade.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/VampireBlade.java index f31bd37bd..16f1f2b9e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/VampireBlade.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/VampireBlade.java @@ -1,5 +1,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.weapons; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Sound; import org.bukkit.attribute.Attribute; import org.bukkit.entity.LivingEntity; @@ -28,6 +31,7 @@ public class VampireBlade extends SlimefunItem { private static final double HEALING_AMOUNT = 4.0; private final ItemSetting chance = new IntRangeSetting("chance", 0, 45, 100); + @ParametersAreNonnullByDefault public VampireBlade(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); @@ -43,7 +47,7 @@ public class VampireBlade extends SlimefunItem { return chance.getValue(); } - public void heal(Player p) { + public void heal(@Nonnull Player p) { p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 0.7F, 0.7F); double health = p.getHealth() + HEALING_AMOUNT; double maxHealth = p.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(); 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 559a7a94b..844c0d0aa 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 @@ -128,7 +128,7 @@ public class AncientAltarListener implements Listener { return; } - if (!SlimefunPlugin.getProtectionManager().hasPermission(p, pedestal, ProtectableAction.ACCESS_INVENTORIES)) { + if (!SlimefunPlugin.getProtectionManager().hasPermission(p, pedestal, ProtectableAction.INTERACT_BLOCK)) { SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); return; } @@ -162,7 +162,7 @@ public class AncientAltarListener implements Listener { } private void useAltar(@Nonnull Block altar, @Nonnull Player p) { - if (!SlimefunPlugin.getProtectionManager().hasPermission(p, altar, ProtectableAction.ACCESS_INVENTORIES)) { + if (!SlimefunPlugin.getProtectionManager().hasPermission(p, altar, ProtectableAction.INTERACT_BLOCK)) { SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); return; } 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 815cb6c6e..080372fc1 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 @@ -22,6 +22,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; +import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; @@ -152,6 +153,9 @@ public class BlockListener implements Listener { if (!drops.isEmpty()) { e.getBlock().setType(Material.AIR); + // Notify plugins like CoreProtect + SlimefunPlugin.getProtectionManager().logAction(e.getPlayer(), e.getBlock(), ProtectableAction.BREAK_BLOCK); + if (e.isDropItems()) { for (ItemStack drop : drops) { if (drop != null && drop.getType() != Material.AIR) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/EntityInteractionListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/EntityInteractionListener.java index 2fd7ad0e9..3f22f6c60 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/EntityInteractionListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/EntityInteractionListener.java @@ -10,15 +10,17 @@ import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import io.github.thebusybiscuit.slimefun4.api.items.ItemState; import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.Slimefun; /** - * The Listener class responsible for a {@link Player} interacting with an {@link Entity}. + * The {@link Listener} responsible for a {@link Player} interacting with an {@link Entity}. * * @author Linox + * @author TheBusyBiscuit * * @see EntityInteractHandler * @@ -45,8 +47,17 @@ public class EntityInteractionListener implements Listener { SlimefunItem sfItem = SlimefunItem.getByItem(itemStack); - if (sfItem != null && Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) { - sfItem.callItemHandler(EntityInteractHandler.class, handler -> handler.onInteract(e, itemStack, e.getHand() == EquipmentSlot.OFF_HAND)); + if (sfItem != null) { + if (Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) { + sfItem.callItemHandler(EntityInteractHandler.class, handler -> handler.onInteract(e, itemStack, e.getHand() == EquipmentSlot.OFF_HAND)); + } else if (sfItem.getState() != ItemState.VANILLA_FALLBACK) { + /** + * If an Item is disabled, we don't want it to fallback to the vanilla behaviour + * unless it is a Vanilla Item of course. + * Related to Issue #2446 + */ + e.setCancelled(true); + } } } } \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/FireworksListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/FireworksListener.java index 99e523b71..dab8a171a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/FireworksListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/FireworksListener.java @@ -4,13 +4,22 @@ import javax.annotation.Nonnull; import org.bukkit.ChatColor; import org.bukkit.entity.Firework; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.inventory.meta.FireworkMeta; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +/** + * This {@link Listener} makes sure that any {@link Firework} caused by a {@link Player} + * unlocking a {@link Research} does not cause damage to be dealt. + * + * @author TheBusyBiscuit + * + */ public class FireworksListener implements Listener { public FireworksListener(@Nonnull SlimefunPlugin plugin) { @@ -23,6 +32,12 @@ public class FireworksListener implements Listener { Firework firework = (Firework) e.getDamager(); FireworkMeta meta = firework.getFireworkMeta(); + /** + * We could use Peristent Data for this in the future, but ItemMeta display names + * work pretty reliably too and they don't cause any memory leaks like metadata. + * + * Entity display names do not work either as Firework cannot be named. + */ if (meta.hasDisplayName() && meta.getDisplayName().equals(ChatColor.GREEN + "Slimefun Research")) { e.setCancelled(true); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/IronGolemListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/IronGolemListener.java index 8bb6e4c2e..250f9ae99 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/IronGolemListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/IronGolemListener.java @@ -19,7 +19,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; /** * This {@link Listener} makes sure that an {@link IronGolem} cannot be healed with * a {@link SlimefunItem}. - * This fixes Issue 1332. * * @author TheBusyBiscuit * @@ -42,6 +41,7 @@ public class IronGolemListener implements Listener { item = inv.getItemInOffHand(); } + // Check if the Golem was clicked using an Iron Ingot if (item != null && item.getType() == Material.IRON_INGOT) { SlimefunItem sfItem = SlimefunItem.getByItem(item); @@ -49,8 +49,10 @@ public class IronGolemListener implements Listener { e.setCancelled(true); SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.no-iron-golem-heal"); - // This is just there to update the Inventory... - // Somehow cancelling it isn't enough. + /** + * This is just there to update the Inventory... + * Somehow cancelling it isn't enough. + */ if (e.getHand() == EquipmentSlot.HAND) { inv.setItemInMainHand(item); } else if (e.getHand() == EquipmentSlot.OFF_HAND) { @@ -61,4 +63,11 @@ public class IronGolemListener implements Listener { } } + // @EventHandler + // public void onIronGolemSpawn(PLEASE_GIMME_AN_EVENT e) { + // if (e.getBlock().getType() == Material.IRON_BLOCK) { + // e.setCancelled(true); + // } + // } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ItemDropListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ItemDropListener.java new file mode 100644 index 000000000..9141d6e68 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ItemDropListener.java @@ -0,0 +1,35 @@ +package io.github.thebusybiscuit.slimefun4.implementation.listeners; + +import javax.annotation.Nonnull; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerDropItemEvent; + +import io.github.thebusybiscuit.slimefun4.core.handlers.ItemDropHandler; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; +import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler; + +/** + * Listens to the {@link PlayerDropItemEvent} to call any {@link ItemDropHandler}. + * + * @author TheBusyBiscuit + * + * @see ItemDropHandler + */ +public class ItemDropListener implements Listener { + + public ItemDropListener(@Nonnull SlimefunPlugin plugin) { + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onItemDrop(PlayerDropItemEvent e) { + for (ItemHandler handler : SlimefunItem.getPublicItemHandlers(ItemDropHandler.class)) { + if (((ItemDropHandler) handler).onItemDrop(e, e.getPlayer(), e.getItemDrop())) { + return; + } + } + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java similarity index 66% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java index 59ca7b6a6..ee276c3d3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java @@ -7,56 +7,78 @@ import javax.annotation.ParametersAreNonnullByDefault; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.block.Block; 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.block.Action; -import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; -import io.github.thebusybiscuit.slimefun4.core.handlers.ItemDropHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; -import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu; -public class SlimefunItemListener implements Listener { +/** + * This {@link Listener} listens to the {@link PlayerInteractEvent}. + * It is also responsible for calling our {@link PlayerRightClickEvent} and triggering any + * {@link ItemUseHandler} or {@link BlockUseHandler} for the clicked {@link ItemStack} or {@link Block}. + * + * @author TheBusyBiscuit + * @author Liruxo + * + * @see PlayerRightClickEvent + * @see ItemUseHandler + * @see BlockUseHandler + * + */ +public class SlimefunItemInteractListener implements Listener { - public SlimefunItemListener(@Nonnull SlimefunPlugin plugin) { + public SlimefunItemInteractListener(@Nonnull SlimefunPlugin plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } @EventHandler public void onRightClick(PlayerInteractEvent e) { if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) { + // Exclude the Debug Fish here because it is handled in a seperate Listener if (SlimefunUtils.isItemSimilar(e.getItem(), SlimefunItems.DEBUG_FISH, true)) { return; } + // Fire our custom Event PlayerRightClickEvent event = new PlayerRightClickEvent(e); Bukkit.getPluginManager().callEvent(event); boolean itemUsed = e.getHand() == EquipmentSlot.OFF_HAND; + // Only handle the Item if it hasn't been denied if (event.useItem() != Result.DENY) { rightClickItem(e, event, itemUsed); } - if (!itemUsed && event.useBlock() != Result.DENY && !rightClickBlock(e, event)) { + if (!itemUsed && event.useBlock() != Result.DENY && !rightClickBlock(event)) { return; } + /** + * If the original Event was not denied but the custom one was, + * we also want to deny the original one. + * This only applies for non-denied events because we do not want to + * override any protective checks. + */ + if (e.useInteractedBlock() != Result.DENY) { e.setUseInteractedBlock(event.useBlock()); } @@ -67,7 +89,6 @@ public class SlimefunItemListener implements Listener { } } - @Nonnull @ParametersAreNonnullByDefault private boolean rightClickItem(PlayerInteractEvent e, PlayerRightClickEvent event, boolean defaultValue) { Optional optional = event.getSlimefunItem(); @@ -84,12 +105,12 @@ public class SlimefunItemListener implements Listener { } @ParametersAreNonnullByDefault - private boolean rightClickBlock(PlayerInteractEvent e, PlayerRightClickEvent event) { + private boolean rightClickBlock(PlayerRightClickEvent event) { Optional optional = event.getSlimefunBlock(); if (optional.isPresent()) { - if (!Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) { - e.setCancelled(true); + if (!Slimefun.hasUnlocked(event.getPlayer(), optional.get(), true)) { + event.getInteractEvent().setCancelled(true); return false; } @@ -97,10 +118,10 @@ public class SlimefunItemListener implements Listener { if (!interactable) { String id = optional.get().getId(); - Player p = e.getPlayer(); + Player p = event.getPlayer(); if (BlockMenuPreset.isInventory(id)) { - openInventory(p, id, e, event); + openInventory(p, id, event.getInteractEvent().getClickedBlock(), event); return false; } } @@ -110,22 +131,22 @@ public class SlimefunItemListener implements Listener { } @ParametersAreNonnullByDefault - private void openInventory(Player p, String id, PlayerInteractEvent e, PlayerRightClickEvent event) { - if (!p.isSneaking() || Material.AIR == event.getItem().getType()) { - e.setCancelled(true); + private void openInventory(Player p, String id, Block clickedBlock, PlayerRightClickEvent event) { + if (!p.isSneaking() || event.getItem().getType() == Material.AIR) { + event.getInteractEvent().setCancelled(true); if (BlockStorage.hasUniversalInventory(id)) { UniversalBlockMenu menu = BlockStorage.getUniversalInventory(id); - if (menu.canOpen(e.getClickedBlock(), p)) { + if (menu.canOpen(clickedBlock, p)) { menu.open(p); } else { SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); } - } else if (BlockStorage.getStorage(e.getClickedBlock().getWorld()).hasInventory(e.getClickedBlock().getLocation())) { - BlockMenu menu = BlockStorage.getInventory(e.getClickedBlock().getLocation()); + } else if (BlockStorage.getStorage(clickedBlock.getWorld()).hasInventory(clickedBlock.getLocation())) { + BlockMenu menu = BlockStorage.getInventory(clickedBlock.getLocation()); - if (menu.canOpen(e.getClickedBlock(), p)) { + if (menu.canOpen(clickedBlock, p)) { menu.open(p); } else { SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true); @@ -134,13 +155,4 @@ public class SlimefunItemListener implements Listener { } } - @EventHandler - public void onItemDrop(PlayerDropItemEvent e) { - for (ItemHandler handler : SlimefunItem.getPublicItemHandlers(ItemDropHandler.class)) { - if (((ItemDropHandler) handler).onItemDrop(e, e.getPlayer(), e.getItemDrop())) { - return; - } - } - } - } 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 3d646ae49..158d38092 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 @@ -35,6 +35,7 @@ public class TeleporterListener implements Listener { } String id = BlockStorage.checkID(e.getClickedBlock()); + if (id == null) { return; } @@ -55,7 +56,13 @@ public class TeleporterListener implements Listener { @ParametersAreNonnullByDefault private boolean isTeleporterPad(String id, Block b, UUID uuid) { - return id.equals(SlimefunItems.GPS_ACTIVATION_DEVICE_SHARED.getItemId()) || (id.equals(SlimefunItems.GPS_ACTIVATION_DEVICE_PERSONAL.getItemId()) && BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(uuid.toString())); + if (id.equals(SlimefunItems.GPS_ACTIVATION_DEVICE_SHARED.getItemId())) { + return true; + } else if (id.equals(SlimefunItems.GPS_ACTIVATION_DEVICE_PERSONAL.getItemId())) { + return BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(uuid.toString()); + } else { + return false; + } } private boolean checkForPylons(@Nonnull Block teleporter) { 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 index 9f3d40f2f..f43907fe7 100644 --- 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 @@ -9,6 +9,7 @@ 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.InventoryMoveItemEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; @@ -21,6 +22,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; * * @author VoidAngel * @author SoSeDiK + * @author CURVX * */ public class BrewingStandListener implements SlimefunCraftingListener { @@ -52,4 +54,10 @@ public class BrewingStandListener implements SlimefunCraftingListener { } } + @EventHandler + public void hopperOnBrew(InventoryMoveItemEvent e) { + if (e.getDestination().getType() == InventoryType.BREWING && isUnallowed(e.getItem())) { + e.setCancelled(true); + } + } } 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 index 6fdba5ab0..05439dbf0 100644 --- 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 @@ -17,13 +17,8 @@ interface SlimefunCraftingListener extends Listener { } else { SlimefunItem sfItem1 = SlimefunItem.getByItem(item1); SlimefunItem sfItem2 = SlimefunItem.getByItem(item2); - - if (isUnallowed(sfItem1) || isUnallowed(sfItem2)) { - return true; - } + return isUnallowed(sfItem1) || isUnallowed(sfItem2); } - - return false; } default boolean isUnallowed(@Nullable ItemStack item) { @@ -32,7 +27,7 @@ interface SlimefunCraftingListener extends Listener { } SlimefunItem sfItem = SlimefunItem.getByItem(item); - return !(sfItem instanceof VanillaItem) && !sfItem.isDisabled(); + return isUnallowed(sfItem); } default boolean isUnallowed(@Nullable SlimefunItem item) { 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 78128dd49..1efb9f43e 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 @@ -51,7 +51,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.Crucible; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.EnhancedFurnace; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HardenedGlass; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramProjector; -import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.InfusedHopper; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RainbowBlock; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RepairedSpawner; import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.UnplaceableBlock; @@ -128,20 +127,21 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.gps.GPSTransmitte import io.github.thebusybiscuit.slimefun4.implementation.items.gps.PersonalActivationPlate; import io.github.thebusybiscuit.slimefun4.implementation.items.gps.Teleporter; import io.github.thebusybiscuit.slimefun4.implementation.items.gps.TeleporterPylon; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.EnchantmentRune; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfernalBonemeal; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedHopper; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedMagnet; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.KnowledgeFlask; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.KnowledgeTome; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.MagicEyeOfEnder; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.MagicalZombiePills; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundItem; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundRune; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.StormStaff; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.TelepositionScroll; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.VillagerRune; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.WaterStaff; -import io.github.thebusybiscuit.slimefun4.implementation.items.magical.WindStaff; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes.EnchantmentRune; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes.SoulboundRune; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes.VillagerRune; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.StormStaff; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.WaterStaff; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.WindStaff; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.MagicianTalisman; import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman; import io.github.thebusybiscuit.slimefun4.implementation.items.medical.Bandage; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/PlayerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AbstractPlayerTask.java similarity index 76% rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/PlayerTask.java rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AbstractPlayerTask.java index ee1097858..a3dca4266 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/PlayerTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/AbstractPlayerTask.java @@ -7,12 +7,12 @@ import org.bukkit.entity.Player; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -abstract class PlayerTask implements Runnable { +abstract class AbstractPlayerTask implements Runnable { protected int id; protected Player p; - PlayerTask(@Nonnull Player p) { + AbstractPlayerTask(@Nonnull Player p) { this.p = p; } @@ -36,10 +36,10 @@ abstract class PlayerTask implements Runnable { } /** - * This method checks if this {@link PlayerTask} should be continued or cancelled. - * It will also cancel this {@link PlayerTask} if it became invalid. + * This method checks if this {@link AbstractPlayerTask} should be continued or cancelled. + * It will also cancel this {@link AbstractPlayerTask} if it became invalid. * - * @return Whether this {@link PlayerTask} is still valid + * @return Whether this {@link AbstractPlayerTask} is still valid */ protected boolean isValid() { if (!p.isOnline() || !p.isValid() || p.isDead() || !p.isSneaking()) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java index 8b92ac872..ed1c04fa3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java @@ -26,8 +26,10 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.SolarHelmet; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.Slimefun; +import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; /** * The {@link ArmorTask} is responsible for handling {@link PotionEffect PotionEffects} for @@ -167,8 +169,16 @@ public class ArmorTask implements Runnable { return false; } - for (SlimefunItem radioactiveItem : SlimefunPlugin.getRegistry().getRadioactiveItems()) { - if (radioactiveItem.isItem(item) && Slimefun.isEnabled(p, radioactiveItem, true)) { + Set radioactiveItems = SlimefunPlugin.getRegistry().getRadioactiveItems(); + ItemStack subject = item; + + if (!(item instanceof SlimefunItemStack) && radioactiveItems.size() > 1) { + // Performance optimization to reduce ItemMeta calls + subject = new ItemStackWrapper(item); + } + + for (SlimefunItem radioactiveItem : radioactiveItems) { + if (radioactiveItem.isItem(subject) && Slimefun.isEnabled(p, radioactiveItem, true)) { // If the item is enabled in the world, then make radioactivity do its job SlimefunPlugin.getLocalization().sendMessage(p, "messages.radiation"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/CapacitorTextureUpdateTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/CapacitorTextureUpdateTask.java new file mode 100644 index 000000000..760689e42 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/CapacitorTextureUpdateTask.java @@ -0,0 +1,71 @@ +package io.github.thebusybiscuit.slimefun4.implementation.tasks; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang.Validate; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.Block; + +import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock; +import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor; +import io.github.thebusybiscuit.slimefun4.utils.HeadTexture; + +/** + * This task is run whenever a {@link Capacitor} needs to update their texture. + * This must be executed on the main {@link Server} {@link Thread}! + * + * @author TheBusyBiscuit + * + */ +public class CapacitorTextureUpdateTask implements Runnable { + + /** + * The {@link Location} of the {@link Capacitor}. + */ + private final Location l; + + /** + * The level of how "full" this {@link Capacitor} is. + * From 0.0 to 1.0. + */ + private final double filledPercentage; + + /** + * This creates a new {@link CapacitorTextureUpdateTask} with the given parameters. + * + * @param l + * The {@link Location} of the {@link Capacitor} + * @param charge + * The amount of charge in this {@link Capacitor} + * @param capacity + * The capacity of this {@link Capacitor} + */ + public CapacitorTextureUpdateTask(@Nonnull Location l, double charge, double capacity) { + Validate.notNull(l, "The Location cannot be null"); + + this.l = l; + this.filledPercentage = charge / capacity; + } + + @Override + public void run() { + Block b = l.getBlock(); + Material type = b.getType(); + + // Ensure that this Block is still a Player Head + if (type == Material.PLAYER_HEAD || type == Material.PLAYER_WALL_HEAD) { + if (filledPercentage <= 0.25) { + SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_25.getTexture()); + } else if (filledPercentage <= 0.5) { + SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_50.getTexture()); + } else if (filledPercentage <= 0.75) { + SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_75.getTexture()); + } else { + SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_100.getTexture()); + } + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetBootsTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetBootsTask.java index 5946d5f8a..fdededc31 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetBootsTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetBootsTask.java @@ -14,7 +14,7 @@ import org.bukkit.util.Vector; import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.JetBoots; -public class JetBootsTask extends PlayerTask { +public class JetBootsTask extends AbstractPlayerTask { private static final float COST = 0.075F; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetpackTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetpackTask.java index cc0bac58a..dd7760c39 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetpackTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/JetpackTask.java @@ -11,7 +11,7 @@ import org.bukkit.util.Vector; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.Jetpack; -public class JetpackTask extends PlayerTask { +public class JetpackTask extends AbstractPlayerTask { private static final float COST = 0.08F; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/MagnetTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/MagnetTask.java index 480041401..fcd310937 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/MagnetTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/MagnetTask.java @@ -13,7 +13,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedMa import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; /** - * This {@link PlayerTask} is run when a {@link Player} carries an {@link InfusedMagnet}. + * This {@link AbstractPlayerTask} is run when a {@link Player} carries an {@link InfusedMagnet}. * It manages the automatic pickup of nearby items. * * @author TheBusyBiscuit @@ -21,7 +21,7 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; * @see InfusedMagnet * */ -public class MagnetTask extends PlayerTask { +public class MagnetTask extends AbstractPlayerTask { private final double radius; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ParachuteTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ParachuteTask.java index 2693853c2..1dcb86e17 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ParachuteTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ParachuteTask.java @@ -6,7 +6,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -public class ParachuteTask extends PlayerTask { +public class ParachuteTask extends AbstractPlayerTask { public ParachuteTask(@Nonnull Player p) { super(p); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java index 4b273a842..552b881fa 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java @@ -9,7 +9,6 @@ import org.bukkit.World; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.listeners.ButcherAndroidListener; -import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener; import io.github.thebusybiscuit.slimefun4.implementation.listeners.TeleporterListener; import io.github.thebusybiscuit.slimefun4.implementation.setup.PostSetup; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -69,10 +68,6 @@ public class SlimefunStartupTask implements Runnable { if (isEnabled("PROGRAMMABLE_ANDROID_BUTCHER", "PROGRAMMABLE_ANDROID_2_BUTCHER", "PROGRAMMABLE_ANDROID_3_BUTCHER")) { new ButcherAndroidListener(plugin); } - - if (isEnabled("ENERGY_REGULATOR", "CARGO_MANAGER")) { - new NetworkListener(plugin, SlimefunPlugin.getNetworkManager()); - } } private boolean isEnabled(String... itemIds) { @@ -83,6 +78,7 @@ public class SlimefunStartupTask implements Runnable { return true; } } + return false; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java index 1b8e09969..6bfea384f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java @@ -146,8 +146,11 @@ public class TickerTask implements Runnable { if (item.getBlockTicker().isSynchronized()) { SlimefunPlugin.getProfiler().scheduleEntries(1); item.getBlockTicker().update(); - // We are inserting a new timestamp because synchronized - // actions are always ran with a 50ms delay (1 game tick) + + /** + * We are inserting a new timestamp because synchronized actions + * are always ran with a 50ms delay (1 game tick) + */ SlimefunPlugin.runSync(() -> { Block b = l.getBlock(); tickBlock(l, b, item, data, System.nanoTime()); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java index fe1f75b28..333deeb80 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java @@ -65,6 +65,7 @@ public final class ChatUtils { * * @return A human-friendly version of the given {@link String} */ + @Nonnull public static String humanize(@Nonnull String string) { StringBuilder builder = new StringBuilder(); String[] segments = PatternUtils.UNDERSCORE.split(string.toLowerCase(Locale.ROOT)); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java index bb7836767..fb791fda3 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java @@ -159,6 +159,9 @@ public enum ColoredMaterial { // @formatter:on + /** + * This is our {@link List} of {@link Material Materials}, the backbone of this enum. + */ private final List list; /** @@ -175,11 +178,25 @@ public enum ColoredMaterial { list = Collections.unmodifiableList(Arrays.asList(materials)); } + /** + * This returns an ordered {@link List} of {@link Material Materials} + * that are part o this {@link ColoredMaterial}. + * + * @return An ordered {@link List} of {@link Material Materials} + */ @Nonnull public List asList() { return list; } + /** + * This returns the {@link Material} at the given index. + * + * @param index + * The index + * + * @return The {@link Material} at that index + */ @Nonnull public Material get(int index) { Validate.isTrue(index >= 0 && index < 16, "The index must be between 0 and 15 (inclusive)."); @@ -187,6 +204,15 @@ public enum ColoredMaterial { return list.get(index); } + /** + * This returns the {@link Material} with the given {@link DyeColor}. + * + * @param color + * The {@link DyeColor} + * + * @return The {@link Material} with that {@link DyeColor} + */ + @Nonnull public Material get(@Nonnull DyeColor color) { Validate.notNull(color, "Color cannot be null!"); 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 d752b5ec8..f94e50689 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java @@ -119,18 +119,19 @@ public final class NumberUtils { * 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}. + * @param current + * The current {@link LocalDateTime}. + * @param priorDate + * The {@link LocalDateTime} in the past. * * @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(); + public static String getElapsedTime(@Nonnull LocalDateTime current, @Nonnull LocalDateTime priorDate) { + Validate.notNull(current, "Provided current date was null"); + Validate.notNull(priorDate, "Provided past date was null"); + + long hours = Duration.between(priorDate, current).toHours(); if (hours == 0) { return "< 1h"; 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 05046d5d8..42a896ad2 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java @@ -14,7 +14,6 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.block.Block; import org.bukkit.entity.Item; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -24,7 +23,6 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import io.github.thebusybiscuit.cscorelib2.item.ImmutableItemMeta; -import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock; import io.github.thebusybiscuit.cscorelib2.skull.SkullItem; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.exceptions.PrematureCodeException; @@ -32,6 +30,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive; import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal; +import io.github.thebusybiscuit.slimefun4.implementation.tasks.CapacitorTextureUpdateTask; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.EmeraldEnchants.EmeraldEnchants; import me.mrCookieSlime.EmeraldEnchants.ItemEnchantment; @@ -337,23 +336,7 @@ public final class SlimefunUtils { Validate.notNull(l, "Cannot update a texture for null"); Validate.isTrue(capacity > 0, "Capacity must be greater than zero!"); - SlimefunPlugin.runSync(() -> { - Block b = l.getBlock(); - - if (b.getType() == Material.PLAYER_HEAD || b.getType() == Material.PLAYER_WALL_HEAD) { - double level = (double) charge / capacity; - - if (level <= 0.25) { - SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_25.getTexture()); - } else if (level <= 0.5) { - SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_50.getTexture()); - } else if (level <= 0.75) { - SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_75.getTexture()); - } else { - SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_100.getTexture()); - } - } - }); + SlimefunPlugin.runSync(new CapacitorTextureUpdateTask(l, charge, capacity)); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java index a910908ae..db31d825d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java @@ -42,6 +42,10 @@ public final class ItemStackWrapper extends ItemStack { } } + public ItemStackWrapper(@Nonnull Material material) { + this(new ItemStack(material)); + } + @Override public boolean hasItemMeta() { return hasItemMeta; 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 289314298..63332d8f7 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 @@ -300,6 +300,18 @@ public enum SlimefunTag implements Tag { } } + public boolean isEmpty() { + if (!includedMaterials.isEmpty()) { + /** + * Without even needing to generate a Set we can safely + * return false if there are directly included Materials + */ + return false; + } else { + return getValues().isEmpty(); + } + } + /** * 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}. 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 964db45ec..2572751b1 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 @@ -252,6 +252,8 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock, * identify all instances of the same {@link AContainer}. * This way we can add the recipes to all instances of the same machine. * + * This method will be deprecated and replaced in the future + * * @return The identifier of this machine */ @Nonnull @@ -384,11 +386,13 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock, Validate.notNull(l, "Can't attempt to take charge from a null location!"); if (isChargeable()) { - if (getCharge(l) < getEnergyConsumption()) { + int charge = getCharge(l); + + if (charge < getEnergyConsumption()) { return false; } - removeCharge(l, getEnergyConsumption()); + setCharge(l, charge - getEnergyConsumption()); return true; } else { return true; diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java index 88f977920..2d5bc397c 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/abstractItems/AGenerator.java @@ -63,7 +63,7 @@ public abstract class AGenerator extends AbstractEnergyProvider { @Override public boolean canOpen(Block b, Player p) { - return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES); + return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK); } @Override @@ -152,7 +152,7 @@ public abstract class AGenerator extends AbstractEnergyProvider { ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(l).getTicks(), getProgressBar()); if (isChargeable()) { - int charge = getCharge(l); + int charge = getCharge(l, data); if (getCapacity() - charge >= getEnergyProduction()) { progress.put(l, timeleft - 1); diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java index ca6417ae4..7333724c2 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java @@ -47,6 +47,7 @@ public interface ItemHandler { * * @param item * The {@link SlimefunItem} to validate + * * @return An {@link Optional} describing the result, it will contain an {@link IncompatibleItemHandlerException} * should there be an issue */ diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java index 94b7a2297..5114d5479 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java @@ -33,7 +33,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.stream.JsonWriter; -import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition; import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; @@ -677,19 +676,20 @@ public class BlockStorage { } } - public static SlimefunItem check(Block block) { - return check(block.getLocation()); + @Nullable + public static SlimefunItem check(@Nonnull Block b) { + String id = checkID(b); + return id == null ? null : SlimefunItem.getByID(id); } - public static SlimefunItem check(Location l) { - if (!hasBlockInfo(l)) { - return null; - } - - return SlimefunItem.getByID(getLocationInfo(l, "id")); + @Nullable + public static SlimefunItem check(@Nonnull Location l) { + String id = checkID(l); + return id == null ? null : SlimefunItem.getByID(id); } - public static String checkID(Block b) { + @Nullable + public static String checkID(@Nonnull Block b) { if (SlimefunPlugin.getBlockDataService().isTileEntity(b.getType())) { Optional blockData = SlimefunPlugin.getBlockDataService().getBlockData(b); @@ -714,18 +714,13 @@ public class BlockStorage { return getLocationInfo(l, "id"); } - public static boolean check(Location l, String slimefunItem) { - if (slimefunItem == null || !hasBlockInfo(l)) { + public static boolean check(@Nonnull Location l, @Nullable String slimefunItem) { + if (slimefunItem == null) { return false; } - try { - String id = getLocationInfo(l, "id"); - return id != null && id.equalsIgnoreCase(slimefunItem); - } catch (Exception x) { - Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while checking " + new BlockPosition(l) + " for: \"" + slimefunItem + "\""); - return false; - } + String id = checkID(l); + return id != null && id.equals(slimefunItem); } public static boolean isWorldRegistered(String name) { 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 9cf7d9d4d..e6d31b065 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java @@ -91,12 +91,14 @@ public class DirtyChestMenu extends ChestMenu { } public boolean fits(@Nonnull ItemStack item, int... slots) { - if (getItemInSlot(slots[0]) == null) { - // Very small optimization - return true; - } else { - return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots); + for (int slot : slots) { + // A small optimization for empty slots + if (getItemInSlot(slot) == null) { + return true; + } } + + return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots); } @Nullable diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 41c82a88a..410a7da7c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -38,6 +38,7 @@ networks: max-size: 200 cargo-ticker-delay: 0 enable-visualizer: true + delete-excess-items: false items: talismans: true 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 index dbe1ad358..75daede45 100644 --- 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 @@ -86,7 +86,7 @@ class TestCauldronListener { @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")); + SlimefunItem item = TestUtilities.mockSlimefunItem(plugin, "CAULDRON_TEST_MOCK_LEATHER", new CustomItem(Material.LEATHER_BOOTS, "&6Mock Leather Armor")); item.register(plugin); PlayerInteractEvent event = mockCauldronEvent(item.getItem()); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestNetworkListener.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestNetworkListener.java index 4e8e1b24e..9506c80af 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestNetworkListener.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/listeners/TestNetworkListener.java @@ -25,7 +25,7 @@ class TestNetworkListener { private static SlimefunPlugin plugin; private static NetworkListener listener; - private static NetworkManager manager = new NetworkManager(80, false); + private static NetworkManager manager = new NetworkManager(80); private static ServerMock server; @BeforeAll diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/networks/TestNetworkManager.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/networks/TestNetworkManager.java index 4aec2a175..161bffdc3 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/networks/TestNetworkManager.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/networks/TestNetworkManager.java @@ -11,6 +11,8 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; import be.seeseemelk.mockbukkit.MockBukkit; @@ -37,23 +39,41 @@ class TestNetworkManager { @Test @DisplayName("Test illegal network size arguments") void testIllegalNetworkSize() { - Assertions.assertThrows(IllegalArgumentException.class, () -> new NetworkManager(-100, false)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new NetworkManager(0, false)); + Assertions.assertThrows(IllegalArgumentException.class, () -> new NetworkManager(-100)); + Assertions.assertThrows(IllegalArgumentException.class, () -> new NetworkManager(0)); } @Test @DisplayName("Test maximum network size") void testGetMaxNetworkSize() { int size = 50; - NetworkManager manager = new NetworkManager(size, false); + NetworkManager manager = new NetworkManager(size); Assertions.assertEquals(size, manager.getMaxSize()); } + @ParameterizedTest + @ValueSource(booleans = { true, false }) + @DisplayName("Test visualizer setting") + void testVisualizerSetting(boolean enabled) { + NetworkManager manager = new NetworkManager(200, enabled, false); + + Assertions.assertEquals(enabled, manager.isVisualizerEnabled()); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + @DisplayName("Test item deletion setting") + void testItemDeletionSetting(boolean enabled) { + NetworkManager manager = new NetworkManager(200, true, enabled); + + Assertions.assertEquals(enabled, manager.isItemDeletionEnabled()); + } + @Test @DisplayName("Test network list") void testGetNetworkList() { - NetworkManager manager = new NetworkManager(10, false); + NetworkManager manager = new NetworkManager(10); World world = server.addSimpleWorld("Simple Network World"); Location loc = new Location(world, 0, 100, 0); @@ -82,7 +102,7 @@ class TestNetworkManager { @Test @DisplayName("Test getting a network at a location") void testGetNetworkAtLocation() { - NetworkManager manager = new NetworkManager(10, false); + NetworkManager manager = new NetworkManager(10); World world = server.addSimpleWorld("Simple Network World"); Location loc = new Location(world, 0, 100, 0); Location loc2 = new Location(world, 0, 200, 0); @@ -104,7 +124,7 @@ class TestNetworkManager { @Test @DisplayName("Test getting all networks at a location") void testGetNetworksAtLocation() { - NetworkManager manager = new NetworkManager(10, false); + NetworkManager manager = new NetworkManager(10); World world = server.addSimpleWorld("Simple Network World"); Location loc = new Location(world, 0, 100, 0); Location loc2 = new Location(world, 0, 200, 0); @@ -120,7 +140,7 @@ class TestNetworkManager { @Test @DisplayName("Test a single node network") void testSingleNodeNetwork() { - NetworkManager manager = new NetworkManager(1, false); + NetworkManager manager = new NetworkManager(1); World world = server.addSimpleWorld("Simple Network World"); Location loc = new Location(world, 0, 100, 0); @@ -134,7 +154,7 @@ class TestNetworkManager { @Test @DisplayName("Test networks connecting via corners") void testCornerConnection() { - NetworkManager manager = new NetworkManager(100, false); + NetworkManager manager = new NetworkManager(100); World world = server.addSimpleWorld("Simple Network World"); Map map = new HashMap<>(); 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 index 6b33de558..09c7a4fa1 100644 --- 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 @@ -26,19 +26,19 @@ class TestNumberUtils { @Test @DisplayName("Test elapsed time string") void testElapsedTime() { - LocalDateTime start = LocalDateTime.now(); + LocalDateTime current = LocalDateTime.now(); - LocalDateTime a = start.plusDays(1); - Assertions.assertEquals("1d", NumberUtils.getElapsedTime(start, a)); + LocalDateTime a = current.minusDays(1); + Assertions.assertEquals("1d", NumberUtils.getElapsedTime(current, a)); - LocalDateTime b = start.plusHours(25); - Assertions.assertEquals("1d 1h", NumberUtils.getElapsedTime(start, b)); + LocalDateTime b = current.minusHours(25); + Assertions.assertEquals("1d 1h", NumberUtils.getElapsedTime(current, b)); - LocalDateTime c = start.plusHours(1); - Assertions.assertEquals("1h", NumberUtils.getElapsedTime(start, c)); + LocalDateTime c = current.minusHours(1); + Assertions.assertEquals("1h", NumberUtils.getElapsedTime(current, c)); - LocalDateTime d = start.plusMinutes(12); - Assertions.assertEquals("< 1h", NumberUtils.getElapsedTime(start, d)); + LocalDateTime d = current.minusMinutes(12); + Assertions.assertEquals("< 1h", NumberUtils.getElapsedTime(current, d)); } @Test