From c463170fdd2dd9397fedf1b545d8fd753c3def09 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 19 Apr 2020 14:02:45 -0700 Subject: [PATCH] Removed uncaching as async saving can cause race condition Fixed tests. --- src/main/java/world/bentobox/level/Level.java | 126 ++++++++++-------- .../level/listeners/JoinLeaveListener.java | 9 +- .../level/placeholders/LevelPlaceholder.java | 3 - .../bentobox/level/LevelPresenterTest.java | 8 +- .../java/world/bentobox/level/LevelTest.java | 25 +++- 5 files changed, 96 insertions(+), 75 deletions(-) diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java index d45d86d..6ee3eab 100644 --- a/src/main/java/world/bentobox/level/Level.java +++ b/src/main/java/world/bentobox/level/Level.java @@ -16,6 +16,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.api.addons.Addon; +import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.configuration.Config; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.Database; @@ -47,6 +48,13 @@ public class Level extends Addon { private ConfigSettings settings; private Config configObject = new Config<>(this, ConfigSettings.class); + /** + * @param settings the settings to set + */ + public void setSettings(ConfigSettings settings) { + this.settings = settings; + } + // Database handler for level data private Database handler; @@ -89,6 +97,7 @@ public class Level extends Addon { * @param targetPlayer - UUID of target player * @return LevelsData object or null if not found */ + @Nullable public LevelsData getLevelsData(@NonNull UUID targetPlayer) { // Get from database if not in cache if (!levelsCache.containsKey(targetPlayer) && handler.objectExists(targetPlayer.toString())) { @@ -182,54 +191,19 @@ public class Level extends Addon { // Start the top ten and register it for clicks topTen = new TopTen(this); registerListener(topTen); - // Register commands for AcidIsland and BSkyBlock + // Register commands for GameModes getPlugin().getAddonsManager().getGameModeAddons().stream() - .filter(gm -> settings.getGameModes().contains(gm.getDescription().getName())) + .filter(gm -> settings + .getGameModes() + .contains(gm + .getDescription() + .getName())) .forEach(gm -> { log("Level hooking into " + gm.getDescription().getName()); - gm.getAdminCommand().ifPresent(adminCommand -> { - new AdminLevelCommand(this, adminCommand); - new AdminTopCommand(this, adminCommand); - }); - gm.getPlayerCommand().ifPresent(playerCmd -> { - new IslandLevelCommand(this, playerCmd); - new IslandTopCommand(this, playerCmd); - new IslandValueCommand(this, playerCmd); - }); + registerCommands(gm); // Register placeholders if (getPlugin().getPlaceholdersManager() != null) { - // Island Level - getPlugin().getPlaceholdersManager().registerPlaceholder(this, - gm.getDescription().getName().toLowerCase() + "_island_level", - user -> getLevelPresenter().getLevelString(getIslandLevel(gm.getOverWorld(), user.getUniqueId()))); - - // Visited Island Level - getPlugin().getPlaceholdersManager().registerPlaceholder(this, - gm.getDescription().getName().toLowerCase() + "_visited_island_level", - user -> getPlugin().getIslands().getIslandAt(user.getLocation()) - .map(island -> getIslandLevel(gm.getOverWorld(), island.getOwner())) - .map(level -> getLevelPresenter().getLevelString(level)) - .orElse("0")); - - // Top Ten - for (int i = 1; i <= 10; i++) { - final int rank = i; - // Value - getPlugin().getPlaceholdersManager().registerPlaceholder(this, - gm.getDescription().getName().toLowerCase() + "_top_value_" + rank, - user -> { - Collection values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); - return values.size() < rank ? "" : values.stream().skip(rank - 1).findFirst().map(String::valueOf).orElse(""); - }); - - // Name - getPlugin().getPlaceholdersManager().registerPlaceholder(this, - gm.getDescription().getName().toLowerCase() + "_top_name_" + rank, - user -> { - Collection values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet(); - return values.size() < rank ? "" : getPlayers().getName(values.stream().skip(rank - 1).findFirst().orElse(null)); - }); - } + registerPlaceholders(gm); } }); @@ -242,15 +216,64 @@ public class Level extends Addon { registerRequestHandler(new TopTenRequestHandler(this)); // Check if WildStackers is enabled on the server - if (Bukkit.getPluginManager().getPlugin("WildStacker") != null) { - // I only added support for counting blocks into the island level - // Someone else can PR if they want spawners added to the Leveling system :) - CalcIslandLevel.stackersEnabled = true; - } else CalcIslandLevel.stackersEnabled = false; + // I only added support for counting blocks into the island level + // Someone else can PR if they want spawners added to the Leveling system :) + CalcIslandLevel.stackersEnabled = Bukkit.getPluginManager().getPlugin("WildStacker") != null; // Done } + private void registerPlaceholders(GameModeAddon gm) { + // Island Level + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_island_level", + user -> getLevelPresenter().getLevelString(getIslandLevel(gm.getOverWorld(), user.getUniqueId()))); + + // Visited Island Level + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_visited_island_level", user -> getVisitedIslandLevel(gm, user)); + + // Top Ten + for (int i = 1; i <= 10; i++) { + final int rank = i; + // Value + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_top_value_" + rank, + user -> { + Collection values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().values(); + return values.size() < rank ? "" : values.stream().skip(rank - 1).findFirst().map(String::valueOf).orElse(""); + }); + + // Name + getPlugin().getPlaceholdersManager().registerPlaceholder(this, + gm.getDescription().getName().toLowerCase() + "_top_name_" + rank, + user -> { + Collection values = getTopTen().getTopTenList(gm.getOverWorld()).getTopTen().keySet(); + return values.size() < rank ? "" : getPlayers().getName(values.stream().skip(rank - 1).findFirst().orElse(null)); + }); + } + + } + + private String getVisitedIslandLevel(GameModeAddon gm, User user) { + return getIslands().getIslandAt(user.getLocation()) + .map(island -> getIslandLevel(gm.getOverWorld(), island.getOwner())) + .map(level -> getLevelPresenter().getLevelString(level)) + .orElse("0"); + } + + private void registerCommands(GameModeAddon gm) { + gm.getAdminCommand().ifPresent(adminCommand -> { + new AdminLevelCommand(this, adminCommand); + new AdminTopCommand(this, adminCommand); + }); + gm.getPlayerCommand().ifPresent(playerCmd -> { + new IslandLevelCommand(this, playerCmd); + new IslandTopCommand(this, playerCmd); + new IslandValueCommand(this, playerCmd); + }); + } + /** * Save the levels to the database */ @@ -316,13 +339,6 @@ public class Level extends Addon { return handler; } - public void uncachePlayer(@Nullable UUID uniqueId) { - if (levelsCache.containsKey(uniqueId) && levelsCache.get(uniqueId) != null) { - handler.saveObject(levelsCache.get(uniqueId)); - } - levelsCache.remove(uniqueId); - } - public static Addon getInstance() { return addon; } diff --git a/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java b/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java index ca6d170..8717eb5 100644 --- a/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java +++ b/src/main/java/world/bentobox/level/listeners/JoinLeaveListener.java @@ -4,12 +4,11 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; import world.bentobox.level.Level; /** - * Listens for when players join and leave + * Listens for when players join * @author tastybento * */ @@ -36,10 +35,4 @@ public class JoinLeaveListener implements Listener { } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerQuit(PlayerQuitEvent e) { - addon.uncachePlayer(e.getPlayer().getUniqueId()); - } - - } diff --git a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java index 964a4c6..e9cef31 100644 --- a/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java +++ b/src/main/java/world/bentobox/level/placeholders/LevelPlaceholder.java @@ -7,10 +7,7 @@ import world.bentobox.level.Level; /** * @author tastybento - * - * @deprecated As of 1.9.0, for removal. */ -@Deprecated public class LevelPlaceholder implements PlaceholderReplacer { private final Level addon; diff --git a/src/test/java/world/bentobox/level/LevelPresenterTest.java b/src/test/java/world/bentobox/level/LevelPresenterTest.java index 8e84cdd..681c372 100644 --- a/src/test/java/world/bentobox/level/LevelPresenterTest.java +++ b/src/test/java/world/bentobox/level/LevelPresenterTest.java @@ -23,6 +23,7 @@ import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.level.calculators.PlayerLevel; import world.bentobox.level.config.BlockConfig; +import world.bentobox.level.config.ConfigSettings; /** * @author tastybento @@ -39,7 +40,9 @@ public class LevelPresenterTest { @Mock private PlayerLevel pl; @Mock - private BlockConfig settings; + private ConfigSettings settings; + @Mock + private BlockConfig blockConfig; @Before public void setUp() throws Exception { @@ -60,6 +63,7 @@ public class LevelPresenterTest { // Settings when(addon.getSettings()).thenReturn(settings); + when(addon.getBlockConfig()).thenReturn(blockConfig); } /** @@ -99,7 +103,7 @@ public class LevelPresenterTest { */ @Test public void testGetLevelStringLongShorthand() { - when(settings.isShortHand()).thenReturn(true); + when(settings.isShorthand()).thenReturn(true); LevelPresenter lp = new LevelPresenter(addon, plugin); assertEquals("123.5M", lp.getLevelString(123456789L)); assertEquals("1.2k", lp.getLevelString(1234L)); diff --git a/src/test/java/world/bentobox/level/LevelTest.java b/src/test/java/world/bentobox/level/LevelTest.java index 5336caa..d65af4c 100644 --- a/src/test/java/world/bentobox/level/LevelTest.java +++ b/src/test/java/world/bentobox/level/LevelTest.java @@ -65,6 +65,8 @@ import world.bentobox.bentobox.managers.FlagsManager; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.PlaceholdersManager; +import world.bentobox.level.config.BlockConfig; +import world.bentobox.level.config.ConfigSettings; import world.bentobox.level.listeners.IslandTeamListeners; import world.bentobox.level.listeners.JoinLeaveListener; @@ -94,8 +96,6 @@ public class LevelTest { private AddonsManager am; @Mock private BukkitScheduler scheduler; - @Mock - private Settings settings; private Level addon; @@ -113,14 +113,23 @@ public class LevelTest { @Mock private PluginManager pim; + @Mock + private BlockConfig blockConfig; + @Mock + private Settings pluginSettings; @BeforeClass public static void beforeClass() throws IOException { + // Make the addon jar jFile = new File("addon.jar"); // Copy over config file from src folder Path fromPath = Paths.get("src/main/resources/config.yml"); Path path = Paths.get("config.yml"); Files.copy(fromPath, path); + // Copy over block config file from src folder + fromPath = Paths.get("src/main/resources/blockconfig.yml"); + path = Paths.get("blockconfig.yml"); + Files.copy(fromPath, path); try (JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(jFile))) { //Added the new files to the jar. try (FileInputStream fis = new FileInputStream(path.toFile())) { @@ -185,6 +194,7 @@ public class LevelTest { addon.setFile(jFile); AddonDescription desc = new AddonDescription.Builder("bentobox", "Level", "1.3").description("test").authors("tastybento").build(); addon.setDescription(desc); + addon.setSettings(new ConfigSettings()); // Addons manager when(plugin.getAddonsManager()).thenReturn(am); // One game mode @@ -205,9 +215,9 @@ public class LevelTest { when(fm.getFlags()).thenReturn(Collections.emptyList()); // The database type has to be created one line before the thenReturn() to work! - when(plugin.getSettings()).thenReturn(settings); DatabaseType value = DatabaseType.JSON; - when(settings.getDatabaseType()).thenReturn(value); + when(plugin.getSettings()).thenReturn(pluginSettings); + when(pluginSettings.getDatabaseType()).thenReturn(value); // Bukkit PowerMockito.mockStatic(Bukkit.class); @@ -243,6 +253,7 @@ public class LevelTest { public static void cleanUp() throws Exception { new File("addon.jar").delete(); new File("config.yml").delete(); + new File("blockconfig.yml").delete(); deleteAll(new File("addons")); } @@ -261,7 +272,7 @@ public class LevelTest { @Test public void testOnEnable() { addon.onEnable(); - verify(plugin).logWarning("[Level] Level Addon: No such world in config.yml : acidisland_world"); + verify(plugin).logWarning("[Level] Level Addon: No such world in blockconfig.yml : acidisland_world"); verify(plugin).log("[Level] Level hooking into BSkyBlock"); verify(cmd, times(3)).getAddon(); // Three commands verify(adminCmd, times(2)).getAddon(); // Two commands @@ -311,8 +322,8 @@ public class LevelTest { @Test public void testGetSettings() { addon.onEnable(); - world.bentobox.level.config.BlockConfig s = addon.getSettings(); - assertEquals(100, s.getDeathPenalty()); + ConfigSettings s = addon.getSettings(); + assertEquals(100, s.getLevelCost()); } /**