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 05db626b2..ea89443dd 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; @@ -161,15 +162,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; @@ -302,12 +324,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); 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 @@ -367,65 +460,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" }; @@ -515,7 +549,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/utils/NumberUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java index 3162ec345..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,19 +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"); + 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(end, start).toHours(); + long hours = Duration.between(priorDate, current).toHours(); if (hours == 0) { return "< 1h"; 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/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/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