diff --git a/src/main/java/world/bentobox/level/CustomSpliterator.java b/src/main/java/world/bentobox/level/CustomSpliterator.java new file mode 100644 index 0000000..e7e31c8 --- /dev/null +++ b/src/main/java/world/bentobox/level/CustomSpliterator.java @@ -0,0 +1,38 @@ +package world.bentobox.level; + +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * Java 8 version of Java 9's forWhile + * https://www.baeldung.com/java-break-stream-foreach + * @author tastybento + * + * @param + */ +public class CustomSpliterator extends Spliterators.AbstractSpliterator { + + private Spliterator splitr; + private Predicate predicate; + private boolean isMatched = true; + + public CustomSpliterator(Spliterator splitr, Predicate predicate) { + super(splitr.estimateSize(), 0); + this.splitr = splitr; + this.predicate = predicate; + } + + @Override + public synchronized boolean tryAdvance(Consumer consumer) { + boolean hadNext = splitr.tryAdvance(elem -> { + if (predicate.test(elem) && isMatched) { + consumer.accept(elem); + } else { + isMatched = false; + } + }); + return hadNext && isMatched; + } +} \ No newline at end of file diff --git a/src/main/java/world/bentobox/level/LevelsManager.java b/src/main/java/world/bentobox/level/LevelsManager.java index 6e62f8e..d67ba1b 100644 --- a/src/main/java/world/bentobox/level/LevelsManager.java +++ b/src/main/java/world/bentobox/level/LevelsManager.java @@ -14,7 +14,10 @@ import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -274,7 +277,7 @@ public class LevelsManager { private void addSelf(World world, User user, PanelBuilder panel) { if (addon.getIslands().hasIsland(world, user) || addon.getIslands().inTeam(world, user.getUniqueId())) { - PanelItem head = getHead(0, this.getIslandLevel(world, user.getUniqueId()), user.getUniqueId(), user, world); + PanelItem head = getHead(this.getRank(world, user.getUniqueId()), this.getIslandLevel(world, user.getUniqueId()), user.getUniqueId(), user, world); setClickHandler(head, user, world); panel.item(49, head); } @@ -406,9 +409,7 @@ public class LevelsManager { */ @NonNull public Map getTopTen(@NonNull World world, int size) { - topTenLists.computeIfAbsent(world, TopTenData::new); - // Remove player from top ten if they are online and do not have the perm - topTenLists.get(world).getTopTen().keySet().removeIf(u -> !hasTopTenPerm(world, u)); + createAndCleanRankings(world); // Return the sorted map return Collections.unmodifiableMap(topTenLists.get(world).getTopTen().entrySet().stream() .filter(e -> addon.getIslands().isOwner(world, e.getKey())) @@ -417,7 +418,46 @@ public class LevelsManager { .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new))); } + + void createAndCleanRankings(@NonNull World world) { + topTenLists.computeIfAbsent(world, TopTenData::new); + // Remove player from top ten if they are online and do not have the perm + topTenLists.get(world).getTopTen().keySet().removeIf(u -> !hasTopTenPerm(world, u)); + } + /** + * @return the topTenLists + */ + protected Map getTopTenLists() { + return topTenLists; + } + + /** + * Get the rank of the player in the rankings + * @param world - world + * @param uuid - player UUID + * @return rank placing - note - placing of 1 means top ranked + */ + public int getRank(@NonNull World world, UUID uuid) { + createAndCleanRankings(world); + Stream> stream = topTenLists.get(world).getTopTen().entrySet().stream() + .filter(e -> addon.getIslands().isOwner(world, e.getKey())) + .filter(l -> l.getValue() > 0) + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())); + return takeWhile(stream, x -> !x.getKey().equals(uuid)).map(Map.Entry::getKey).collect(Collectors.toList()).size() + 1; + } + + /** + * Java 8's version of Java 9's takeWhile + * @param stream + * @param predicate + * @return stream + */ + public static Stream takeWhile(Stream stream, Predicate predicate) { + CustomSpliterator customSpliterator = new CustomSpliterator<>(stream.spliterator(), predicate); + return StreamSupport.stream(customSpliterator, false); + } + /** * Checks if player has the correct top ten perm to have their level saved * @param world diff --git a/src/test/java/world/bentobox/level/LevelsManagerTest.java b/src/test/java/world/bentobox/level/LevelsManagerTest.java index d6b1e16..ec4c184 100644 --- a/src/test/java/world/bentobox/level/LevelsManagerTest.java +++ b/src/test/java/world/bentobox/level/LevelsManagerTest.java @@ -63,6 +63,7 @@ import world.bentobox.level.calculators.Pipeliner; import world.bentobox.level.calculators.Results; import world.bentobox.level.config.ConfigSettings; import world.bentobox.level.objects.IslandLevels; +import world.bentobox.level.objects.TopTenData; /** * @author tastybento @@ -442,5 +443,26 @@ public class LevelsManagerTest { } */ } + + /** + * Test method for {@link world.bentobox.level.LevelsManager#getRank(World, UUID)} + */ + @Test + public void testGetRank() { + lm.createAndCleanRankings(world); + Map ttl = lm.getTopTenLists(); + Map tt = ttl.get(world).getTopTen(); + for (long i = 100; i < 150; i++) { + tt.put(UUID.randomUUID(), i); + } + // Put player as lowest rank + tt.put(uuid, 10L); + assertEquals(51, lm.getRank(world, uuid)); + // Put player as highest rank + tt.put(uuid, 1000L); + assertEquals(1, lm.getRank(world, uuid)); + // Unknown UUID - lowest rank + 1 + assertEquals(52, lm.getRank(world, UUID.randomUUID())); + } }