Skip to content

Commit

Permalink
Added more placeholders. #296
Browse files Browse the repository at this point in the history
Refactored how the top ten maps are structured. In the future, it may be
best to have the key be the island.
  • Loading branch information
tastybento committed Nov 24, 2023
1 parent 9d1a5c7 commit 117d15f
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 63 deletions.
35 changes: 35 additions & 0 deletions src/main/java/world/bentobox/level/LevelsManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -293,6 +294,40 @@ public String getPointsToNextString(@NonNull World world, @Nullable UUID targetP
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<Island, Long> getWeightedTopTen(@NonNull World world, int size) {
createAndCleanRankings(world);
Map<Island, Long> 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.
Expand Down
101 changes: 53 additions & 48 deletions src/main/java/world/bentobox/level/PlaceholderManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand Down Expand Up @@ -66,19 +65,29 @@ protected void registerPlaceholders(GameModeAddon gm) {
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
Expand All @@ -89,13 +98,18 @@ protected void registerPlaceholders(GameModeAddon gm) {
/**
* 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);
Expand All @@ -106,27 +120,42 @@ String getRankName(World world, int rank) {
/**
* 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("");
}

/**
* 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> island = addon.getManager().getTopTen(world, Level.TEN).keySet().stream().skip(rank - 1L)
.limit(1L).findFirst().flatMap(addon.getIslands()::getIslandById);

Expand All @@ -140,44 +169,20 @@ String getRankMembers(World world, int rank) {
}

/**
* 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<String, Long> 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<String, Long> 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));
}
Expand Down
13 changes: 13 additions & 0 deletions src/test/java/world/bentobox/level/LevelsManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,19 @@ public void testGetTopTen() {
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<Island, Long> 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)}.
Expand Down
49 changes: 34 additions & 15 deletions src/test/java/world/bentobox/level/PlaceholderManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ public class PlaceholderManagerTest {
names.put(UUID.randomUUID(), "vicky");
}
private Map<String, Island> islands = new HashMap<>();
private Map<String, Long> map = new HashMap<>();
private Map<String, Long> map = new LinkedHashMap<>();
private Map<Island, Long> map2 = new LinkedHashMap<>();
private @NonNull IslandLevels data;
@Mock
private PlayersManager pm;
Expand All @@ -105,13 +106,14 @@ public void setUp() throws Exception {
int i = 0;
for (Entry<UUID, String> 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()
Expand Down Expand Up @@ -145,6 +147,7 @@ public void setUp() throws Exception {
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<String>) invocation -> invocation.getArgument(0, Long.class).toString());

data = new IslandLevels("uniqueId");
Expand Down Expand Up @@ -206,12 +209,12 @@ public void testRegisterPlaceholders() {
@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));
}

}
Expand All @@ -223,12 +226,12 @@ public void testGetRankName() {
@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));
}

}
Expand All @@ -240,11 +243,11 @@ public void testGetRankIslandName() {
@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));
}
}

Expand All @@ -261,11 +264,27 @@ void check(int indicator, String list) {
@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));
}

}
Expand Down

0 comments on commit 117d15f

Please sign in to comment.