From 117d15f3d021dc88d0546c6a00766789f90184af Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 24 Nov 2023 09:33:16 -0800 Subject: [PATCH] Added more placeholders. #296 Refactored how the top ten maps are structured. In the future, it may be best to have the key be the island. --- .../world/bentobox/level/LevelsManager.java | 35 ++++++ .../bentobox/level/PlaceholderManager.java | 101 +++++++++--------- .../bentobox/level/LevelsManagerTest.java | 13 +++ .../level/PlaceholderManagerTest.java | 49 ++++++--- 4 files changed, 135 insertions(+), 63 deletions(-) diff --git a/src/main/java/world/bentobox/level/LevelsManager.java b/src/main/java/world/bentobox/level/LevelsManager.java index e9193d7..f3532aa 100644 --- a/src/main/java/world/bentobox/level/LevelsManager.java +++ b/src/main/java/world/bentobox/level/LevelsManager.java @@ -2,6 +2,7 @@ package world.bentobox.level; import java.math.BigInteger; import java.text.DecimalFormat; +import java.util.AbstractMap; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -293,6 +294,40 @@ public class LevelsManager { return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel()); } + /** + * Get the weighted top ten for this world. Weighting is based on number of + * players per team. + * + * @param world - world requested + * @param size - size of the top ten + * @return sorted top ten map. The key is the island unique ID + */ + @NonNull + public Map getWeightedTopTen(@NonNull World world, int size) { + createAndCleanRankings(world); + Map weightedTopTen = topTenLists.get(world).getTopTen().entrySet().stream() + .map(en -> addon.getIslands().getIslandById(en.getKey()).map(island -> { + + long value = (long) (en.getValue() / (double) Math.max(1, island.getMemberSet().size())); // Calculate + // weighted + // value + return new AbstractMap.SimpleEntry<>(island, value); + }).orElse(null)) // Handle islands that do not exist according to this ID - old deleted ones + .filter(Objects::nonNull) // Filter out null entries + .filter(en -> en.getValue() > 0) // Filter out entries with non-positive values + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) // Sort in descending order of values + .limit(size) // Limit to the top 'size' entries + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, // In case of key + // collision, choose + // the first one + LinkedHashMap::new // Preserves the order of entries + )); + + // Return the unmodifiable map + return Collections.unmodifiableMap(weightedTopTen); + + } + /** * Get the top ten for this world. Returns offline players or players with the * intopten permission. diff --git a/src/main/java/world/bentobox/level/PlaceholderManager.java b/src/main/java/world/bentobox/level/PlaceholderManager.java index 8277a64..5f0bd17 100644 --- a/src/main/java/world/bentobox/level/PlaceholderManager.java +++ b/src/main/java/world/bentobox/level/PlaceholderManager.java @@ -2,7 +2,6 @@ package world.bentobox.level; import java.util.Collections; import java.util.Map; -import java.util.Map.Entry; import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @@ -66,19 +65,29 @@ public class PlaceholderManager { final int rank = i; // Name bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_name_" + i, - u -> getRankName(gm.getOverWorld(), rank)); + u -> getRankName(gm.getOverWorld(), rank, false)); // Island Name bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_island_name_" + i, - u -> getRankIslandName(gm.getOverWorld(), rank)); + u -> getRankIslandName(gm.getOverWorld(), rank, false)); // Members bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_members_" + i, - u -> getRankMembers(gm.getOverWorld(), rank)); + u -> getRankMembers(gm.getOverWorld(), rank, false)); // Level bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_value_" + i, - u -> getRankLevel(gm.getOverWorld(), rank)); + u -> getRankLevel(gm.getOverWorld(), rank, false)); + // Weighted Level Name (Level / number of members) + bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_weighted_name_" + i, + u -> getRankName(gm.getOverWorld(), rank, true)); + // Weighted Island Name + bpm.registerPlaceholder(addon, + gm.getDescription().getName().toLowerCase() + "_top_weighted_island_name_" + i, + u -> getRankIslandName(gm.getOverWorld(), rank, true)); + // Weighted Members + bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_weighted_members_" + i, + u -> getRankMembers(gm.getOverWorld(), rank, true)); // Weighted Level (Level / number of members) bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_top_weighted_value_" + i, - u -> getWeightedRankLevel(gm.getOverWorld(), rank)); + u -> getRankLevel(gm.getOverWorld(), rank, true)); } // Personal rank @@ -89,13 +98,18 @@ public class PlaceholderManager { /** * Get the name of the owner of the island who holds the rank in this world. * - * @param world world - * @param rank rank 1 to 10 + * @param world world + * @param rank rank 1 to 10 + * @param weighted if true, then the weighted rank name is returned * @return rank name */ - String getRankName(World world, int rank) { + String getRankName(World world, int rank, boolean weighted) { // Ensure rank is within bounds rank = Math.max(1, Math.min(rank, Level.TEN)); + if (weighted) { + return addon.getManager().getWeightedTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L) + .findFirst().map(Island::getOwner).map(addon.getPlayers()::getName).orElse(""); + } @Nullable UUID owner = addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L) .findFirst().flatMap(addon.getIslands()::getIslandById).map(Island::getOwner).orElse(null); @@ -106,13 +120,18 @@ public class PlaceholderManager { /** * Get the island name for this rank * - * @param world world - * @param rank rank 1 to 10 + * @param world world + * @param rank rank 1 to 10 + * @param weighted if true, then the weighted rank name is returned * @return name of island or nothing if there isn't one */ - String getRankIslandName(World world, int rank) { + String getRankIslandName(World world, int rank, boolean weighted) { // Ensure rank is within bounds rank = Math.max(1, Math.min(rank, Level.TEN)); + if (weighted) { + return addon.getManager().getWeightedTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L) + .findFirst().map(Island::getName).orElse(""); + } return addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L).findFirst() .flatMap(addon.getIslands()::getIslandById).map(Island::getName).orElse(""); } @@ -120,13 +139,23 @@ public class PlaceholderManager { /** * Gets a comma separated string of island member names * - * @param world world - * @param rank rank to request + * @param world world + * @param rank rank to request + * @param weighted if true, then the weighted rank name is returned * @return comma separated string of island member names */ - String getRankMembers(World world, int rank) { + String getRankMembers(World world, int rank, boolean weighted) { // Ensure rank is within bounds rank = Math.max(1, Math.min(rank, Level.TEN)); + if (weighted) { + return addon.getManager().getWeightedTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L).limit(1L) + .findFirst() + .map(is -> is.getMembers().entrySet().stream().filter(e -> e.getValue() >= RanksManager.MEMBER_RANK) + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).map(Map.Entry::getKey) + .map(addon.getPlayers()::getName).collect(Collectors.joining(","))) + .orElse(""); + } + Optional island = addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L) .limit(1L).findFirst().flatMap(addon.getIslands()::getIslandById); @@ -140,44 +169,20 @@ public class PlaceholderManager { } /** - * Gets the weighted level, which is the level / number of players + * Get the level for the rank requested * - * @param world world - * @param rank level - * @return weighted level + * @param world world + * @param rank rank wanted + * @param weighted true if weighted (level/number of team members) + * @return level for the rank requested */ - String getWeightedRankLevel(World world, int rank) { + String getRankLevel(World world, int rank, boolean weighted) { // Ensure rank is within bounds rank = Math.max(1, Math.min(rank, Level.TEN)); - - // Retrieve the top ten entries - Map topTen = addon.getManager().getTopTen(world, Level.TEN); - if (topTen.isEmpty()) { - return ""; + if (weighted) { + return addon.getManager().formatLevel(addon.getManager().getWeightedTopTen(world, Level.TEN).values() + .stream().skip(rank - 1L).limit(1L).findFirst().orElse(null)); } - - // Find the entry corresponding to the rank - Entry entry = topTen.entrySet().stream().skip(rank - 1).findFirst().orElse(null); - if (entry == null) { - return ""; - } - - // Calculate the score - Island island = addon.getIslands().getIslandById(entry.getKey()).orElse(null); - if (island == null || island.getMemberSet().isEmpty()) { - return ""; - } - - double score = (double) entry.getValue() / island.getMemberSet().size(); - - // Format and return the level - return addon.getManager().formatLevel((long) score); - - } - - String getRankLevel(World world, int rank) { - // Ensure rank is within bounds - rank = Math.max(1, Math.min(rank, Level.TEN)); return addon.getManager().formatLevel(addon.getManager().getTopTen(world, Level.TEN).values().stream() .skip(rank - 1L).limit(1L).findFirst().orElse(null)); } diff --git a/src/test/java/world/bentobox/level/LevelsManagerTest.java b/src/test/java/world/bentobox/level/LevelsManagerTest.java index 44b1b9b..551c573 100644 --- a/src/test/java/world/bentobox/level/LevelsManagerTest.java +++ b/src/test/java/world/bentobox/level/LevelsManagerTest.java @@ -364,6 +364,19 @@ public class LevelsManagerTest { assertEquals(1, lm.getTopTen(world, 1).size()); } + /** + * Test method for + * {@link world.bentobox.level.LevelsManager#getWeightedTopTen(org.bukkit.World, int)}. + */ + @Test + public void testGetWeightedTopTen() { + testLoadTopTens(); + Map tt = lm.getWeightedTopTen(world, Level.TEN); + assertFalse(tt.isEmpty()); + assertEquals(1, tt.size()); + assertEquals(1, lm.getTopTen(world, 1).size()); + } + /** * Test method for * {@link world.bentobox.level.LevelsManager#hasTopTenPerm(org.bukkit.World, java.util.UUID)}. diff --git a/src/test/java/world/bentobox/level/PlaceholderManagerTest.java b/src/test/java/world/bentobox/level/PlaceholderManagerTest.java index 63cc597..56f0a1d 100644 --- a/src/test/java/world/bentobox/level/PlaceholderManagerTest.java +++ b/src/test/java/world/bentobox/level/PlaceholderManagerTest.java @@ -83,7 +83,8 @@ public class PlaceholderManagerTest { names.put(UUID.randomUUID(), "vicky"); } private Map islands = new HashMap<>(); - private Map map = new HashMap<>(); + private Map map = new LinkedHashMap<>(); + private Map map2 = new LinkedHashMap<>(); private @NonNull IslandLevels data; @Mock private PlayersManager pm; @@ -105,13 +106,14 @@ public class PlaceholderManagerTest { int i = 0; for (Entry n : names.entrySet()) { UUID uuid = UUID.randomUUID(); // Random island ID - map.put(uuid.toString(), (long)(100 - i++)); // level + Long value = (long)(100 - i++); + map.put(uuid.toString(), value); // level Island is = new Island(); is.setUniqueId(uuid.toString()); is.setOwner(n.getKey()); is.setName(n.getValue() + "'s island"); islands.put(uuid.toString(), is); - + map2.put(is, value); } // Sort map = map.entrySet().stream() @@ -145,6 +147,7 @@ public class PlaceholderManagerTest { when(lm.getPointsToNextString(any(), any())).thenReturn("1234567"); when(lm.getIslandMaxLevel(any(), any())).thenReturn(987654L); when(lm.getTopTen(world, Level.TEN)).thenReturn(map); + when(lm.getWeightedTopTen(world, Level.TEN)).thenReturn(map2); when(lm.formatLevel(any())).thenAnswer((Answer) invocation -> invocation.getArgument(0, Long.class).toString()); data = new IslandLevels("uniqueId"); @@ -206,12 +209,12 @@ public class PlaceholderManagerTest { @Test public void testGetRankName() { // Test extremes - assertEquals("tasty", phm.getRankName(world, 0)); - assertEquals("vicky", phm.getRankName(world, 100)); + assertEquals("tasty", phm.getRankName(world, 0, false)); + assertEquals("vicky", phm.getRankName(world, 100, false)); // Test the ranks int rank = 1; for (String name : names.values()) { - assertEquals(name, phm.getRankName(world, rank++)); + assertEquals(name, phm.getRankName(world, rank++, false)); } } @@ -223,12 +226,12 @@ public class PlaceholderManagerTest { @Test public void testGetRankIslandName() { // Test extremes - assertEquals("tasty's island", phm.getRankIslandName(world, 0)); - assertEquals("vicky's island", phm.getRankIslandName(world, 100)); + assertEquals("tasty's island", phm.getRankIslandName(world, 0, false)); + assertEquals("vicky's island", phm.getRankIslandName(world, 100, false)); // Test the ranks int rank = 1; for (String name : names.values()) { - assertEquals(name + "'s island", phm.getRankIslandName(world, rank++)); + assertEquals(name + "'s island", phm.getRankIslandName(world, rank++, false)); } } @@ -240,11 +243,11 @@ public class PlaceholderManagerTest { @Test public void testGetRankMembers() { // Test extremes - check(1, phm.getRankMembers(world, 0)); - check(2, phm.getRankMembers(world, 100)); + check(1, phm.getRankMembers(world, 0, false)); + check(2, phm.getRankMembers(world, 100, false)); // Test the ranks for (int rank = 1; rank < 11; rank++) { - check(3, phm.getRankMembers(world, rank)); + check(3, phm.getRankMembers(world, rank, false)); } } @@ -261,11 +264,27 @@ public class PlaceholderManagerTest { @Test public void testGetRankLevel() { // Test extremes - assertEquals("100", phm.getRankLevel(world, 0)); - assertEquals("91", phm.getRankLevel(world, 100)); + assertEquals("100", phm.getRankLevel(world, 0, false)); + assertEquals("91", phm.getRankLevel(world, 100, false)); // Test the ranks for (int rank = 1; rank < 11; rank++) { - assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank)); + assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, false)); + } + + } + + /** + * Test method for + * {@link world.bentobox.level.PlaceholderManager#getRankLevel(org.bukkit.World, int)}. + */ + @Test + public void testGetWeightedRankLevel() { + // Test extremes + assertEquals("100", phm.getRankLevel(world, 0, true)); + assertEquals("91", phm.getRankLevel(world, 100, true)); + // Test the ranks + for (int rank = 1; rank < 11; rank++) { + assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, true)); } }