Adds an admin stats command. See #293
This commit is contained in:
parent
eb71b35c5c
commit
3a3c8a320c
|
@ -24,6 +24,7 @@ import world.bentobox.level.calculators.Pipeliner;
|
||||||
import world.bentobox.level.commands.AdminLevelCommand;
|
import world.bentobox.level.commands.AdminLevelCommand;
|
||||||
import world.bentobox.level.commands.AdminLevelStatusCommand;
|
import world.bentobox.level.commands.AdminLevelStatusCommand;
|
||||||
import world.bentobox.level.commands.AdminSetInitialLevelCommand;
|
import world.bentobox.level.commands.AdminSetInitialLevelCommand;
|
||||||
|
import world.bentobox.level.commands.AdminStatsCommand;
|
||||||
import world.bentobox.level.commands.AdminTopCommand;
|
import world.bentobox.level.commands.AdminTopCommand;
|
||||||
import world.bentobox.level.commands.IslandLevelCommand;
|
import world.bentobox.level.commands.IslandLevelCommand;
|
||||||
import world.bentobox.level.commands.IslandTopCommand;
|
import world.bentobox.level.commands.IslandTopCommand;
|
||||||
|
@ -39,7 +40,6 @@ import world.bentobox.level.requests.TopTenRequestHandler;
|
||||||
import world.bentobox.visit.VisitAddon;
|
import world.bentobox.visit.VisitAddon;
|
||||||
import world.bentobox.warps.Warp;
|
import world.bentobox.warps.Warp;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tastybento
|
* @author tastybento
|
||||||
*
|
*
|
||||||
|
@ -71,7 +71,6 @@ public class Level extends Addon {
|
||||||
*/
|
*/
|
||||||
private VisitAddon visitHook;
|
private VisitAddon visitHook;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
// Save the default config from config.yml
|
// Save the default config from config.yml
|
||||||
|
@ -112,8 +111,7 @@ public class Level extends Addon {
|
||||||
// Register commands for GameModes
|
// Register commands for GameModes
|
||||||
registeredGameModes.clear();
|
registeredGameModes.clear();
|
||||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName()))
|
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
|
||||||
.forEach(gm -> {
|
|
||||||
log("Level hooking into " + gm.getDescription().getName());
|
log("Level hooking into " + gm.getDescription().getName());
|
||||||
registerCommands(gm);
|
registerCommands(gm);
|
||||||
new PlaceholderManager(this).registerPlaceholders(gm);
|
new PlaceholderManager(this).registerPlaceholders(gm);
|
||||||
|
@ -142,7 +140,8 @@ public class Level extends Addon {
|
||||||
if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) {
|
if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) {
|
||||||
log("Hooked into AdvancedChests.");
|
log("Hooked into AdvancedChests.");
|
||||||
} else {
|
} else {
|
||||||
logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion() + " - requires version 23.0 or later");
|
logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion()
|
||||||
|
+ " - requires version 23.0 or later");
|
||||||
advChestEnabled = false;
|
advChestEnabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,40 +165,34 @@ public class Level extends Addon {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void allLoaded()
|
public void allLoaded() {
|
||||||
{
|
|
||||||
super.allLoaded();
|
super.allLoaded();
|
||||||
|
|
||||||
if (this.isEnabled())
|
if (this.isEnabled()) {
|
||||||
{
|
|
||||||
this.hookExtensions();
|
this.hookExtensions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method tries to hook into addons and plugins
|
* This method tries to hook into addons and plugins
|
||||||
*/
|
*/
|
||||||
private void hookExtensions()
|
private void hookExtensions() {
|
||||||
{
|
|
||||||
// Try to find Visit addon and if it does not exist, display a warning
|
// Try to find Visit addon and if it does not exist, display a warning
|
||||||
this.getAddonByName("Visit").ifPresentOrElse(addon ->
|
this.getAddonByName("Visit").ifPresentOrElse(addon -> {
|
||||||
{
|
|
||||||
this.visitHook = (VisitAddon) addon;
|
this.visitHook = (VisitAddon) addon;
|
||||||
this.log("Level Addon hooked into Visit addon.");
|
this.log("Level Addon hooked into Visit addon.");
|
||||||
}, () -> this.visitHook = null);
|
}, () -> this.visitHook = null);
|
||||||
|
|
||||||
// Try to find Warps addon and if it does not exist, display a warning
|
// Try to find Warps addon and if it does not exist, display a warning
|
||||||
this.getAddonByName("Warps").ifPresentOrElse(addon ->
|
this.getAddonByName("Warps").ifPresentOrElse(addon -> {
|
||||||
{
|
|
||||||
this.warpHook = (Warp) addon;
|
this.warpHook = (Warp) addon;
|
||||||
this.log("Level Addon hooked into Warps addon.");
|
this.log("Level Addon hooked into Warps addon.");
|
||||||
}, () -> this.warpHook = null);
|
}, () -> this.warpHook = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares versions
|
* Compares versions
|
||||||
|
*
|
||||||
* @param version1 version 1
|
* @param version1 version 1
|
||||||
* @param version2 version 2
|
* @param version2 version 2
|
||||||
* @return {@code <0 if version 1 is older than version 2, =0 if the same, >0 if version 1 is newer than version 2}
|
* @return {@code <0 if version 1 is older than version 2, =0 if the same, >0 if version 1 is newer than version 2}
|
||||||
|
@ -231,6 +224,7 @@ public class Level extends Addon {
|
||||||
if (getSettings().isZeroNewIslandLevels()) {
|
if (getSettings().isZeroNewIslandLevels()) {
|
||||||
new AdminSetInitialLevelCommand(this, adminCommand);
|
new AdminSetInitialLevelCommand(this, adminCommand);
|
||||||
}
|
}
|
||||||
|
new AdminStatsCommand(this, adminCommand);
|
||||||
});
|
});
|
||||||
gm.getPlayerCommand().ifPresent(playerCmd -> {
|
gm.getPlayerCommand().ifPresent(playerCmd -> {
|
||||||
new IslandLevelCommand(this, playerCmd);
|
new IslandLevelCommand(this, playerCmd);
|
||||||
|
@ -263,7 +257,6 @@ public class Level extends Addon {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the blockConfig
|
* @return the blockConfig
|
||||||
*/
|
*/
|
||||||
|
@ -294,6 +287,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the config settings - used for tests only
|
* Set the config settings - used for tests only
|
||||||
|
*
|
||||||
* @param configSettings - config settings
|
* @param configSettings - config settings
|
||||||
*/
|
*/
|
||||||
void setSettings(ConfigSettings configSettings) {
|
void setSettings(ConfigSettings configSettings) {
|
||||||
|
@ -317,6 +311,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get level from cache for a player.
|
* Get level from cache for a player.
|
||||||
|
*
|
||||||
* @param targetPlayer - target player UUID
|
* @param targetPlayer - target player UUID
|
||||||
* @return Level of player or zero if player is unknown or UUID is null
|
* @return Level of player or zero if player is unknown or UUID is null
|
||||||
*/
|
*/
|
||||||
|
@ -326,6 +321,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the player's level to a value
|
* Sets the player's level to a value
|
||||||
|
*
|
||||||
* @param world - world
|
* @param world - world
|
||||||
* @param targetPlayer - target player
|
* @param targetPlayer - target player
|
||||||
* @param level - level
|
* @param level - level
|
||||||
|
@ -336,6 +332,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zeros the initial island level
|
* Zeros the initial island level
|
||||||
|
*
|
||||||
* @param island - island
|
* @param island - island
|
||||||
* @param level - initial calculated island level
|
* @param level - initial calculated island level
|
||||||
*/
|
*/
|
||||||
|
@ -345,6 +342,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the initial island level
|
* Get the initial island level
|
||||||
|
*
|
||||||
* @param island - island
|
* @param island - island
|
||||||
* @return level or 0 by default
|
* @return level or 0 by default
|
||||||
*/
|
*/
|
||||||
|
@ -354,19 +352,23 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates a user's island
|
* Calculates a user's island
|
||||||
|
*
|
||||||
* @param world - the world where this island is
|
* @param world - the world where this island is
|
||||||
* @param user - not used! See depecration message
|
* @param user - not used! See depecration message
|
||||||
* @param playerUUID - the target island member's UUID
|
* @param playerUUID - the target island member's UUID
|
||||||
* @deprecated Do not use this anymore. Use getManager().calculateLevel(playerUUID, island)
|
* @deprecated Do not use this anymore. Use
|
||||||
|
* getManager().calculateLevel(playerUUID, island)
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "2.3.0", forRemoval = true)
|
@Deprecated(since = "2.3.0", forRemoval = true)
|
||||||
public void calculateIslandLevel(World world, @Nullable User user, @NonNull UUID playerUUID) {
|
public void calculateIslandLevel(World world, @Nullable User user, @NonNull UUID playerUUID) {
|
||||||
Island island = getIslands().getIsland(world, playerUUID);
|
Island island = getIslands().getIsland(world, playerUUID);
|
||||||
if (island != null) getManager().calculateLevel(playerUUID, island);
|
if (island != null)
|
||||||
|
getManager().calculateLevel(playerUUID, island);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide the levels data for the target player
|
* Provide the levels data for the target player
|
||||||
|
*
|
||||||
* @param targetPlayer - UUID of target player
|
* @param targetPlayer - UUID of target player
|
||||||
* @return LevelsData object or null if not found. Only island levels are set!
|
* @return LevelsData object or null if not found. Only island levels are set!
|
||||||
* @deprecated Do not use this anymore. Use {@link #getIslandLevel(World, UUID)}
|
* @deprecated Do not use this anymore. Use {@link #getIslandLevel(World, UUID)}
|
||||||
|
@ -375,8 +377,7 @@ public class Level extends Addon {
|
||||||
public LevelsData getLevelsData(UUID targetPlayer) {
|
public LevelsData getLevelsData(UUID targetPlayer) {
|
||||||
LevelsData ld = new LevelsData(targetPlayer);
|
LevelsData ld = new LevelsData(targetPlayer);
|
||||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName()))
|
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
|
||||||
.forEach(gm -> {
|
|
||||||
if (getSettings().isZeroNewIslandLevels()) {
|
if (getSettings().isZeroNewIslandLevels()) {
|
||||||
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
|
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
|
||||||
if (island != null) {
|
if (island != null) {
|
||||||
|
@ -397,6 +398,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Level addon is active in game mode
|
* Check if Level addon is active in game mode
|
||||||
|
*
|
||||||
* @param gm Game Mode Addon
|
* @param gm Game Mode Addon
|
||||||
* @return true if active, false if not
|
* @return true if active, false if not
|
||||||
*/
|
*/
|
||||||
|
@ -406,6 +408,7 @@ public class Level extends Addon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if Level addon is active in world
|
* Checks if Level addon is active in world
|
||||||
|
*
|
||||||
* @param world world
|
* @param world world
|
||||||
* @return true if active, false if not
|
* @return true if active, false if not
|
||||||
*/
|
*/
|
||||||
|
@ -432,8 +435,7 @@ public class Level extends Addon {
|
||||||
*
|
*
|
||||||
* @return {@code Visit} of this object, {@code null} otherwise.
|
* @return {@code Visit} of this object, {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
public VisitAddon getVisitHook()
|
public VisitAddon getVisitHook() {
|
||||||
{
|
|
||||||
return this.visitHook;
|
return this.visitHook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,8 +444,7 @@ public class Level extends Addon {
|
||||||
*
|
*
|
||||||
* @return {@code Warp} of this object, {@code null} otherwise.
|
* @return {@code Warp} of this object, {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
public Warp getWarpHook()
|
public Warp getWarpHook() {
|
||||||
{
|
|
||||||
return this.warpHook;
|
return this.warpHook;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import world.bentobox.level.objects.IslandLevels;
|
||||||
import world.bentobox.level.objects.LevelsData;
|
import world.bentobox.level.objects.LevelsData;
|
||||||
import world.bentobox.level.objects.TopTenData;
|
import world.bentobox.level.objects.TopTenData;
|
||||||
|
|
||||||
|
|
||||||
public class LevelsManager {
|
public class LevelsManager {
|
||||||
private static final String INTOPTEN = "intopten";
|
private static final String INTOPTEN = "intopten";
|
||||||
private static final TreeMap<BigInteger, String> LEVELS;
|
private static final TreeMap<BigInteger, String> LEVELS;
|
||||||
|
@ -53,7 +52,6 @@ public class LevelsManager {
|
||||||
// Top ten lists
|
// Top ten lists
|
||||||
private final Map<World, TopTenData> topTenLists;
|
private final Map<World, TopTenData> topTenLists;
|
||||||
|
|
||||||
|
|
||||||
public LevelsManager(Level addon) {
|
public LevelsManager(Level addon) {
|
||||||
this.addon = addon;
|
this.addon = addon;
|
||||||
// Get the BentoBox database
|
// Get the BentoBox database
|
||||||
|
@ -76,8 +74,7 @@ public class LevelsManager {
|
||||||
// World
|
// World
|
||||||
.map(Bukkit::getWorld).filter(Objects::nonNull)
|
.map(Bukkit::getWorld).filter(Objects::nonNull)
|
||||||
// Island
|
// Island
|
||||||
.map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull)
|
.map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull).forEach(i -> {
|
||||||
.forEach(i -> {
|
|
||||||
// Make new database entry
|
// Make new database entry
|
||||||
World w = i.getWorld();
|
World w = i.getWorld();
|
||||||
IslandLevels il = new IslandLevels(i.getUniqueId());
|
IslandLevels il = new IslandLevels(i.getUniqueId());
|
||||||
|
@ -101,6 +98,7 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a score to the top players list
|
* Add a score to the top players list
|
||||||
|
*
|
||||||
* @param world - world
|
* @param world - world
|
||||||
* @param targetPlayer - target player
|
* @param targetPlayer - target player
|
||||||
* @param lv - island level
|
* @param lv - island level
|
||||||
|
@ -108,7 +106,8 @@ public class LevelsManager {
|
||||||
private void addToTopTen(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
private void addToTopTen(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
||||||
// Get top ten
|
// Get top ten
|
||||||
Map<UUID, Long> topTen = topTenLists.computeIfAbsent(world, k -> new TopTenData(world)).getTopTen();
|
Map<UUID, Long> topTen = topTenLists.computeIfAbsent(world, k -> new TopTenData(world)).getTopTen();
|
||||||
// Remove this player from the top list no matter what (we'll put them back later if required)
|
// Remove this player from the top list no matter what (we'll put them back
|
||||||
|
// later if required)
|
||||||
topTen.remove(targetPlayer);
|
topTen.remove(targetPlayer);
|
||||||
|
|
||||||
// Get the island
|
// Get the island
|
||||||
|
@ -121,21 +120,24 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an island to a top ten
|
* Add an island to a top ten
|
||||||
|
*
|
||||||
* @param island - island to add
|
* @param island - island to add
|
||||||
* @param lv - level
|
* @param lv - level
|
||||||
* @return true if successful, false if not added
|
* @return true if successful, false if not added
|
||||||
*/
|
*/
|
||||||
private boolean addToTopTen(Island island, long lv) {
|
private boolean addToTopTen(Island island, long lv) {
|
||||||
if (island != null && island.getOwner() != null && hasTopTenPerm(island.getWorld(), island.getOwner())) {
|
if (island != null && island.getOwner() != null && hasTopTenPerm(island.getWorld(), island.getOwner())) {
|
||||||
topTenLists.computeIfAbsent(island.getWorld(), k -> new TopTenData(island.getWorld()))
|
topTenLists.computeIfAbsent(island.getWorld(), k -> new TopTenData(island.getWorld())).getTopTen()
|
||||||
.getTopTen().put(island.getOwner(), lv);
|
.put(island.getOwner(), lv);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the island level, set all island member's levels to the result and try to add the owner to the top ten
|
* Calculate the island level, set all island member's levels to the result and
|
||||||
|
* try to add the owner to the top ten
|
||||||
|
*
|
||||||
* @param targetPlayer - uuid of targeted player - owner or team member
|
* @param targetPlayer - uuid of targeted player - owner or team member
|
||||||
* @param island - island to calculate
|
* @param island - island to calculate
|
||||||
* @return completable future with the results of the calculation
|
* @return completable future with the results of the calculation
|
||||||
|
@ -150,7 +152,8 @@ public class LevelsManager {
|
||||||
}
|
}
|
||||||
// Add island to the pipeline
|
// Add island to the pipeline
|
||||||
addon.getPipeliner().addIsland(island).thenAccept(r -> {
|
addon.getPipeliner().addIsland(island).thenAccept(r -> {
|
||||||
// Results are irrelevant because the island is unowned or deleted, or IslandLevelCalcEvent is cancelled
|
// Results are irrelevant because the island is unowned or deleted, or
|
||||||
|
// IslandLevelCalcEvent is cancelled
|
||||||
if (r == null || fireIslandLevelCalcEvent(targetPlayer, island, r)) {
|
if (r == null || fireIslandLevelCalcEvent(targetPlayer, island, r)) {
|
||||||
result.complete(null);
|
result.complete(null);
|
||||||
}
|
}
|
||||||
|
@ -164,6 +167,7 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires the IslandLevelCalculatedEvent and returns true if it is canceled
|
* Fires the IslandLevelCalculatedEvent and returns true if it is canceled
|
||||||
|
*
|
||||||
* @param targetPlayer - target player
|
* @param targetPlayer - target player
|
||||||
* @param island - island
|
* @param island - island
|
||||||
* @param results - results set
|
* @param results - results set
|
||||||
|
@ -173,23 +177,28 @@ public class LevelsManager {
|
||||||
// Fire post calculation event
|
// Fire post calculation event
|
||||||
IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, results);
|
IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, results);
|
||||||
Bukkit.getPluginManager().callEvent(ilce);
|
Bukkit.getPluginManager().callEvent(ilce);
|
||||||
if (ilce.isCancelled()) return true;
|
if (ilce.isCancelled())
|
||||||
|
return true;
|
||||||
// Set the values if they were altered
|
// Set the values if they were altered
|
||||||
results.setLevel((Long) ilce.getKeyValues().getOrDefault("level", results.getLevel()));
|
results.setLevel((Long) ilce.getKeyValues().getOrDefault("level", results.getLevel()));
|
||||||
results.setInitialLevel((Long) ilce.getKeyValues().getOrDefault("initialLevel", results.getInitialLevel()));
|
results.setInitialLevel((Long) ilce.getKeyValues().getOrDefault("initialLevel", results.getInitialLevel()));
|
||||||
results.setDeathHandicap((int) ilce.getKeyValues().getOrDefault("deathHandicap", results.getDeathHandicap()));
|
results.setDeathHandicap((int) ilce.getKeyValues().getOrDefault("deathHandicap", results.getDeathHandicap()));
|
||||||
results.setPointsToNextLevel((Long)ilce.getKeyValues().getOrDefault("pointsToNextLevel", results.getPointsToNextLevel()));
|
results.setPointsToNextLevel(
|
||||||
|
(Long) ilce.getKeyValues().getOrDefault("pointsToNextLevel", results.getPointsToNextLevel()));
|
||||||
results.setTotalPoints((Long) ilce.getKeyValues().getOrDefault("totalPoints", results.getTotalPoints()));
|
results.setTotalPoints((Long) ilce.getKeyValues().getOrDefault("totalPoints", results.getTotalPoints()));
|
||||||
return ((Boolean) ilce.getKeyValues().getOrDefault("isCancelled", false));
|
return ((Boolean) ilce.getKeyValues().getOrDefault("isCancelled", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the string representation of the level. May be converted to shorthand notation, e.g., 104556 = 10.5k
|
* Get the string representation of the level. May be converted to shorthand
|
||||||
|
* notation, e.g., 104556 = 10.5k
|
||||||
|
*
|
||||||
* @param lvl - long value to represent
|
* @param lvl - long value to represent
|
||||||
* @return string of the level.
|
* @return string of the level.
|
||||||
*/
|
*/
|
||||||
public String formatLevel(@Nullable Long lvl) {
|
public String formatLevel(@Nullable Long lvl) {
|
||||||
if (lvl == null) return "";
|
if (lvl == null)
|
||||||
|
return "";
|
||||||
String level = String.valueOf(lvl);
|
String level = String.valueOf(lvl);
|
||||||
// Asking for the level of another player
|
// Asking for the level of another player
|
||||||
if (addon.getSettings().isShorthand()) {
|
if (addon.getSettings().isShorthand()) {
|
||||||
|
@ -202,7 +211,8 @@ public class LevelsManager {
|
||||||
// 1 527 314 -> 1.5M
|
// 1 527 314 -> 1.5M
|
||||||
// 3 874 130 021 -> 3.8G
|
// 3 874 130 021 -> 3.8G
|
||||||
// 4 002 317 889 -> 4.0T
|
// 4 002 317 889 -> 4.0T
|
||||||
level = new DecimalFormat("#.#").format(levelValue.divide(stage.getKey().divide(THOUSAND)).doubleValue()/1000.0) + stage.getValue();
|
level = new DecimalFormat("#.#").format(
|
||||||
|
levelValue.divide(stage.getKey().divide(THOUSAND)).doubleValue() / 1000.0) + stage.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return level;
|
return level;
|
||||||
|
@ -210,6 +220,7 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the initial level of the island. Used to zero island levels
|
* Get the initial level of the island. Used to zero island levels
|
||||||
|
*
|
||||||
* @param island - island
|
* @param island - island
|
||||||
* @return initial level of island
|
* @return initial level of island
|
||||||
*/
|
*/
|
||||||
|
@ -219,12 +230,15 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get level of island from cache for a player.
|
* Get level of island from cache for a player.
|
||||||
|
*
|
||||||
* @param world - world where the island is
|
* @param world - world where the island is
|
||||||
* @param targetPlayer - target player UUID
|
* @param targetPlayer - target player UUID
|
||||||
* @return Level of the player's island or zero if player is unknown or UUID is null
|
* @return Level of the player's island or zero if player is unknown or UUID is
|
||||||
|
* null
|
||||||
*/
|
*/
|
||||||
public long getIslandLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
public long getIslandLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
if (targetPlayer == null) return 0L;
|
if (targetPlayer == null)
|
||||||
|
return 0L;
|
||||||
// Get the island
|
// Get the island
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
return island == null ? 0L : getLevelsData(island).getLevel();
|
return island == null ? 0L : getLevelsData(island).getLevel();
|
||||||
|
@ -232,12 +246,15 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum level ever given to this island
|
* Get the maximum level ever given to this island
|
||||||
|
*
|
||||||
* @param world - world where the island is
|
* @param world - world where the island is
|
||||||
* @param targetPlayer - target player UUID
|
* @param targetPlayer - target player UUID
|
||||||
* @return Max level of the player's island or zero if player is unknown or UUID is null
|
* @return Max level of the player's island or zero if player is unknown or UUID
|
||||||
|
* is null
|
||||||
*/
|
*/
|
||||||
public long getIslandMaxLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
public long getIslandMaxLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
if (targetPlayer == null) return 0L;
|
if (targetPlayer == null)
|
||||||
|
return 0L;
|
||||||
// Get the island
|
// Get the island
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
return island == null ? 0L : getLevelsData(island).getMaxLevel();
|
return island == null ? 0L : getLevelsData(island).getMaxLevel();
|
||||||
|
@ -245,9 +262,11 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a formatted string of the target player's island level
|
* Returns a formatted string of the target player's island level
|
||||||
|
*
|
||||||
* @param world - world where the island is
|
* @param world - world where the island is
|
||||||
* @param targetPlayer - target player's UUID
|
* @param targetPlayer - target player's UUID
|
||||||
* @return Formatted level of player or zero if player is unknown or UUID is null
|
* @return Formatted level of player or zero if player is unknown or UUID is
|
||||||
|
* null
|
||||||
*/
|
*/
|
||||||
public String getIslandLevelString(@NonNull World world, @Nullable UUID targetPlayer) {
|
public String getIslandLevelString(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
return formatLevel(getIslandLevel(world, targetPlayer));
|
return formatLevel(getIslandLevel(world, targetPlayer));
|
||||||
|
@ -255,6 +274,7 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a level data for the island from the cache or database.
|
* Load a level data for the island from the cache or database.
|
||||||
|
*
|
||||||
* @param island - UUID of island
|
* @param island - UUID of island
|
||||||
* @return IslandLevels object
|
* @return IslandLevels object
|
||||||
*/
|
*/
|
||||||
|
@ -281,19 +301,24 @@ public class LevelsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of points required until the next level since the last level calc
|
* Get the number of points required until the next level since the last level
|
||||||
|
* calc
|
||||||
|
*
|
||||||
* @param world - world where the island is
|
* @param world - world where the island is
|
||||||
* @param targetPlayer - target player UUID
|
* @param targetPlayer - target player UUID
|
||||||
* @return string with the number required or blank if the player is unknown
|
* @return string with the number required or blank if the player is unknown
|
||||||
*/
|
*/
|
||||||
public String getPointsToNextString(@NonNull World world, @Nullable UUID targetPlayer) {
|
public String getPointsToNextString(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
if (targetPlayer == null) return "";
|
if (targetPlayer == null)
|
||||||
|
return "";
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel());
|
return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the top ten for this world. Returns offline players or players with the intopten permission.
|
* Get the top ten for this world. Returns offline players or players with the
|
||||||
|
* intopten permission.
|
||||||
|
*
|
||||||
* @param world - world requested
|
* @param world - world requested
|
||||||
* @param size - size of the top ten
|
* @param size - size of the top ten
|
||||||
* @return sorted top ten map
|
* @return sorted top ten map
|
||||||
|
@ -303,11 +328,9 @@ public class LevelsManager {
|
||||||
createAndCleanRankings(world);
|
createAndCleanRankings(world);
|
||||||
// Return the sorted map
|
// Return the sorted map
|
||||||
return Collections.unmodifiableMap(topTenLists.get(world).getTopTen().entrySet().stream()
|
return Collections.unmodifiableMap(topTenLists.get(world).getTopTen().entrySet().stream()
|
||||||
.filter(e -> addon.getIslands().isOwner(world, e.getKey()))
|
.filter(e -> addon.getIslands().hasIsland(world, e.getKey())).filter(l -> l.getValue() > 0)
|
||||||
.filter(l -> l.getValue() > 0)
|
|
||||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(size)
|
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(size)
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)));
|
||||||
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void createAndCleanRankings(@NonNull World world) {
|
void createAndCleanRankings(@NonNull World world) {
|
||||||
|
@ -319,12 +342,13 @@ public class LevelsManager {
|
||||||
/**
|
/**
|
||||||
* @return the topTenLists
|
* @return the topTenLists
|
||||||
*/
|
*/
|
||||||
protected Map<World, TopTenData> getTopTenLists() {
|
public Map<World, TopTenData> getTopTenLists() {
|
||||||
return topTenLists;
|
return topTenLists;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rank of the player in the rankings
|
* Get the rank of the player in the rankings
|
||||||
|
*
|
||||||
* @param world - world
|
* @param world - world
|
||||||
* @param uuid - player UUID
|
* @param uuid - player UUID
|
||||||
* @return rank placing - note - placing of 1 means top ranked
|
* @return rank placing - note - placing of 1 means top ranked
|
||||||
|
@ -332,21 +356,22 @@ public class LevelsManager {
|
||||||
public int getRank(@NonNull World world, UUID uuid) {
|
public int getRank(@NonNull World world, UUID uuid) {
|
||||||
createAndCleanRankings(world);
|
createAndCleanRankings(world);
|
||||||
Stream<Entry<UUID, Long>> stream = topTenLists.get(world).getTopTen().entrySet().stream()
|
Stream<Entry<UUID, Long>> stream = topTenLists.get(world).getTopTen().entrySet().stream()
|
||||||
.filter(e -> addon.getIslands().isOwner(world, e.getKey()))
|
.filter(e -> addon.getIslands().isOwner(world, e.getKey())).filter(l -> l.getValue() > 0)
|
||||||
.filter(l -> l.getValue() > 0)
|
|
||||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
|
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
|
||||||
return (int) (stream.takeWhile(x -> !x.getKey().equals(uuid)).map(Map.Entry::getKey).count() + 1);
|
return (int) (stream.takeWhile(x -> !x.getKey().equals(uuid)).map(Map.Entry::getKey).count() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if player has the correct top ten perm to have their level saved
|
* Checks if player has the correct top ten perm to have their level saved
|
||||||
|
*
|
||||||
* @param world
|
* @param world
|
||||||
* @param targetPlayer
|
* @param targetPlayer
|
||||||
* @return true if player has the perm or the player is offline
|
* @return true if player has the perm or the player is offline
|
||||||
*/
|
*/
|
||||||
boolean hasTopTenPerm(@NonNull World world, @NonNull UUID targetPlayer) {
|
boolean hasTopTenPerm(@NonNull World world, @NonNull UUID targetPlayer) {
|
||||||
String permPrefix = addon.getPlugin().getIWM().getPermissionPrefix(world);
|
String permPrefix = addon.getPlugin().getIWM().getPermissionPrefix(world);
|
||||||
return Bukkit.getPlayer(targetPlayer) == null || Bukkit.getPlayer(targetPlayer).hasPermission(permPrefix + INTOPTEN);
|
return Bukkit.getPlayer(targetPlayer) == null
|
||||||
|
|| Bukkit.getPlayer(targetPlayer).hasPermission(permPrefix + INTOPTEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,7 +383,8 @@ public class LevelsManager {
|
||||||
addon.log("Generating rankings");
|
addon.log("Generating rankings");
|
||||||
handler.loadObjects().forEach(il -> {
|
handler.loadObjects().forEach(il -> {
|
||||||
if (il.getLevel() > 0) {
|
if (il.getLevel() > 0) {
|
||||||
addon.getIslands().getIslandById(il.getUniqueId()).ifPresent(i -> this.addToTopTen(i, il.getLevel()));
|
addon.getIslands().getIslandById(il.getUniqueId())
|
||||||
|
.ifPresent(i -> this.addToTopTen(i, il.getLevel()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
topTenLists.keySet().forEach(w -> addon.log("Generated rankings for " + w.getName()));
|
topTenLists.keySet().forEach(w -> addon.log("Generated rankings for " + w.getName()));
|
||||||
|
@ -366,7 +392,9 @@ public class LevelsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a player from a world's top ten and removes world from player's level data
|
* Removes a player from a world's top ten and removes world from player's level
|
||||||
|
* data
|
||||||
|
*
|
||||||
* @param world - world
|
* @param world - world
|
||||||
* @param uuid - the player's uuid
|
* @param uuid - the player's uuid
|
||||||
*/
|
*/
|
||||||
|
@ -379,17 +407,21 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an initial island level
|
* Set an initial island level
|
||||||
|
*
|
||||||
* @param island - the island to set. Must have a non-null world
|
* @param island - the island to set. Must have a non-null world
|
||||||
* @param lv - initial island level
|
* @param lv - initial island level
|
||||||
*/
|
*/
|
||||||
public void setInitialIslandLevel(@NonNull Island island, long lv) {
|
public void setInitialIslandLevel(@NonNull Island island, long lv) {
|
||||||
if (island.getWorld() == null) return;
|
if (island.getWorld() == null)
|
||||||
|
return;
|
||||||
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv);
|
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv);
|
||||||
handler.saveObjectAsync(levelsCache.get(island.getUniqueId()));
|
handler.saveObjectAsync(levelsCache.get(island.getUniqueId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the island level for the owner of the island that targetPlayer is a member
|
* Set the island level for the owner of the island that targetPlayer is a
|
||||||
|
* member
|
||||||
|
*
|
||||||
* @param world - world
|
* @param world - world
|
||||||
* @param targetPlayer - player, may be a team member
|
* @param targetPlayer - player, may be a team member
|
||||||
* @param lv - level
|
* @param lv - level
|
||||||
|
@ -414,7 +446,9 @@ public class LevelsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the island level for the owner of the island that targetPlayer is a member
|
* Set the island level for the owner of the island that targetPlayer is a
|
||||||
|
* member
|
||||||
|
*
|
||||||
* @param world - world
|
* @param world - world
|
||||||
* @param owner - owner of the island
|
* @param owner - owner of the island
|
||||||
* @param r - results of the calculation
|
* @param r - results of the calculation
|
||||||
|
@ -422,7 +456,8 @@ public class LevelsManager {
|
||||||
private void setIslandResults(World world, @NonNull UUID owner, Results r) {
|
private void setIslandResults(World world, @NonNull UUID owner, Results r) {
|
||||||
// Get the island
|
// Get the island
|
||||||
Island island = addon.getIslands().getIsland(world, owner);
|
Island island = addon.getIslands().getIsland(world, owner);
|
||||||
if (island == null) return;
|
if (island == null)
|
||||||
|
return;
|
||||||
IslandLevels ld = levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new);
|
IslandLevels ld = levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new);
|
||||||
ld.setLevel(r.getLevel());
|
ld.setLevel(r.getLevel());
|
||||||
ld.setUwCount(Maps.asMap(r.getUwCount().elementSet(), elem -> r.getUwCount().count(elem)));
|
ld.setUwCount(Maps.asMap(r.getUwCount().elementSet(), elem -> r.getUwCount().count(elem)));
|
||||||
|
@ -437,6 +472,7 @@ public class LevelsManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes island from cache when it is deleted
|
* Removes island from cache when it is deleted
|
||||||
|
*
|
||||||
* @param uniqueId - id of island
|
* @param uniqueId - id of island
|
||||||
*/
|
*/
|
||||||
public void deleteIsland(String uniqueId) {
|
public void deleteIsland(String uniqueId) {
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package world.bentobox.level.commands;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||||
|
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||||
|
import world.bentobox.bentobox.api.user.User;
|
||||||
|
import world.bentobox.level.Level;
|
||||||
|
import world.bentobox.level.objects.TopTenData;
|
||||||
|
|
||||||
|
public class AdminStatsCommand extends CompositeCommand {
|
||||||
|
|
||||||
|
private final Level level;
|
||||||
|
|
||||||
|
public AdminStatsCommand(Level addon, CompositeCommand parent) {
|
||||||
|
super(parent, "stats");
|
||||||
|
this.level = addon;
|
||||||
|
new AdminTopRemoveCommand(addon, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup() {
|
||||||
|
this.setPermission("admin.stats");
|
||||||
|
this.setOnlyPlayer(false);
|
||||||
|
this.setDescription("admin.stats.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(User user, String label, List<String> args) {
|
||||||
|
user.sendMessage("admin.stats.title");
|
||||||
|
for (Entry<World, TopTenData> en : level.getManager().getTopTenLists().entrySet()) {
|
||||||
|
user.sendMessage("admin.stats.world", TextVariables.NAME,
|
||||||
|
level.getPlugin().getIWM().getWorldName(en.getKey()));
|
||||||
|
Map<UUID, Long> topTen = en.getValue().getTopTen();
|
||||||
|
if (topTen.isEmpty()) {
|
||||||
|
user.sendMessage("admin.stats.no-data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculating basic statistics
|
||||||
|
long sum = 0, max = Long.MIN_VALUE, min = Long.MAX_VALUE;
|
||||||
|
Map<Long, Integer> levelFrequency = new HashMap<>();
|
||||||
|
|
||||||
|
for (Long level : topTen.values()) {
|
||||||
|
sum += level;
|
||||||
|
max = Math.max(max, level);
|
||||||
|
min = Math.min(min, level);
|
||||||
|
levelFrequency.merge(level, 1, Integer::sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
double average = sum / (double) topTen.size();
|
||||||
|
List<Long> sortedLevels = topTen.values().stream().sorted().collect(Collectors.toList());
|
||||||
|
long median = sortedLevels.get(sortedLevels.size() / 2);
|
||||||
|
Long mode = Collections.max(levelFrequency.entrySet(), Map.Entry.comparingByValue()).getKey();
|
||||||
|
|
||||||
|
// Logging basic statistics
|
||||||
|
user.sendMessage("admin.stats.average-level", TextVariables.NUMBER, String.valueOf(average));
|
||||||
|
user.sendMessage("admin.stats.median-level", TextVariables.NUMBER, String.valueOf(median));
|
||||||
|
user.sendMessage("admin.stats.mode-level", TextVariables.NUMBER, String.valueOf(mode));
|
||||||
|
user.sendMessage("admin.stats.highest-level", TextVariables.NUMBER, String.valueOf(max));
|
||||||
|
user.sendMessage("admin.stats.lowest-level", TextVariables.NUMBER, String.valueOf(min));
|
||||||
|
|
||||||
|
// Grouping data for distribution analysis
|
||||||
|
Map<String, Integer> rangeMap = new TreeMap<>();
|
||||||
|
for (Long level : topTen.values()) {
|
||||||
|
String range = getRange(level);
|
||||||
|
rangeMap.merge(range, 1, Integer::sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging distribution
|
||||||
|
user.sendMessage("admin.stats.distribution");
|
||||||
|
for (Map.Entry<String, Integer> entry : rangeMap.entrySet()) {
|
||||||
|
user.sendMessage(
|
||||||
|
entry.getKey() + ": " + entry.getValue() + " " + user.getTranslation("admin.stats.islands"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getRange(long level) {
|
||||||
|
long rangeStart = level / 100 * 100;
|
||||||
|
long rangeEnd = rangeStart + 99;
|
||||||
|
return rangeStart + "-" + rangeEnd;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,8 +22,18 @@ admin:
|
||||||
remove:
|
remove:
|
||||||
description: "remove player from Top Ten"
|
description: "remove player from Top Ten"
|
||||||
parameters: "<player>"
|
parameters: "<player>"
|
||||||
|
stats:
|
||||||
|
description: "show stats on islands on this server"
|
||||||
|
title: "Server Island Stats"
|
||||||
|
world: "&a [name]"
|
||||||
|
no-data: "&c No data to process."
|
||||||
|
average-level: "Average Island Level: [number]"
|
||||||
|
median-level: "Median Island Level: [number]"
|
||||||
|
mode-level: "Mode Island Level: [number]"
|
||||||
|
highest-level: "Highest Island Level: [number]"
|
||||||
|
lowest-level: "Lowest Island Level: [number]"
|
||||||
|
distribution: "Island Level Distribution:"
|
||||||
|
islands: "islands"
|
||||||
island:
|
island:
|
||||||
level:
|
level:
|
||||||
parameters: "[player]"
|
parameters: "[player]"
|
||||||
|
|
Loading…
Reference in New Issue