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,411 +40,411 @@ 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
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class Level extends Addon {
|
public class Level extends Addon {
|
||||||
|
|
||||||
// The 10 in top ten
|
// The 10 in top ten
|
||||||
public static final int TEN = 10;
|
public static final int TEN = 10;
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
private ConfigSettings settings;
|
private ConfigSettings settings;
|
||||||
private Config<ConfigSettings> configObject = new Config<>(this, ConfigSettings.class);
|
private Config<ConfigSettings> configObject = new Config<>(this, ConfigSettings.class);
|
||||||
private BlockConfig blockConfig;
|
private BlockConfig blockConfig;
|
||||||
private Pipeliner pipeliner;
|
private Pipeliner pipeliner;
|
||||||
private LevelsManager manager;
|
private LevelsManager manager;
|
||||||
private boolean stackersEnabled;
|
private boolean stackersEnabled;
|
||||||
private boolean advChestEnabled;
|
private boolean advChestEnabled;
|
||||||
private boolean roseStackersEnabled;
|
private boolean roseStackersEnabled;
|
||||||
private boolean ultimateStackerEnabled;
|
private boolean ultimateStackerEnabled;
|
||||||
private final List<GameModeAddon> registeredGameModes = new ArrayList<>();
|
private final List<GameModeAddon> registeredGameModes = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local variable that stores if warpHook is present.
|
* Local variable that stores if warpHook is present.
|
||||||
*/
|
*/
|
||||||
private Warp warpHook;
|
private Warp warpHook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local variable that stores if visitHook is present.
|
* Local variable that stores if visitHook is present.
|
||||||
*/
|
*/
|
||||||
private VisitAddon visitHook;
|
private VisitAddon visitHook;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
// Save the default config from config.yml
|
||||||
|
saveDefaultConfig();
|
||||||
|
if (loadSettings()) {
|
||||||
|
// Disable
|
||||||
|
logError("Level settings could not load! Addon disabled.");
|
||||||
|
setState(State.DISABLED);
|
||||||
|
} else {
|
||||||
|
configObject.saveConfigObject(settings);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
// Save existing panels.
|
||||||
public void onLoad() {
|
this.saveResource("panels/top_panel.yml", false);
|
||||||
// Save the default config from config.yml
|
this.saveResource("panels/detail_panel.yml", false);
|
||||||
saveDefaultConfig();
|
this.saveResource("panels/value_panel.yml", false);
|
||||||
if (loadSettings()) {
|
}
|
||||||
// Disable
|
|
||||||
logError("Level settings could not load! Addon disabled.");
|
|
||||||
setState(State.DISABLED);
|
|
||||||
} else {
|
|
||||||
configObject.saveConfigObject(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save existing panels.
|
private boolean loadSettings() {
|
||||||
this.saveResource("panels/top_panel.yml", false);
|
// Load settings again to get worlds
|
||||||
this.saveResource("panels/detail_panel.yml", false);
|
settings = configObject.loadConfigObject();
|
||||||
this.saveResource("panels/value_panel.yml", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean loadSettings() {
|
return settings == null;
|
||||||
// Load settings again to get worlds
|
}
|
||||||
settings = configObject.loadConfigObject();
|
|
||||||
|
|
||||||
return settings == null;
|
@Override
|
||||||
}
|
public void onEnable() {
|
||||||
|
loadBlockSettings();
|
||||||
|
// Start pipeline
|
||||||
|
pipeliner = new Pipeliner(this);
|
||||||
|
// Start Manager
|
||||||
|
manager = new LevelsManager(this);
|
||||||
|
// Register listeners
|
||||||
|
this.registerListener(new IslandActivitiesListeners(this));
|
||||||
|
this.registerListener(new JoinLeaveListener(this));
|
||||||
|
this.registerListener(new MigrationListener(this));
|
||||||
|
|
||||||
@Override
|
// Register commands for GameModes
|
||||||
public void onEnable() {
|
registeredGameModes.clear();
|
||||||
loadBlockSettings();
|
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||||
// Start pipeline
|
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
|
||||||
pipeliner = new Pipeliner(this);
|
log("Level hooking into " + gm.getDescription().getName());
|
||||||
// Start Manager
|
registerCommands(gm);
|
||||||
manager = new LevelsManager(this);
|
new PlaceholderManager(this).registerPlaceholders(gm);
|
||||||
// Register listeners
|
registeredGameModes.add(gm);
|
||||||
this.registerListener(new IslandActivitiesListeners(this));
|
});
|
||||||
this.registerListener(new JoinLeaveListener(this));
|
// Register request handlers
|
||||||
this.registerListener(new MigrationListener(this));
|
registerRequestHandler(new LevelRequestHandler(this));
|
||||||
|
registerRequestHandler(new TopTenRequestHandler(this));
|
||||||
|
|
||||||
// Register commands for GameModes
|
// Check if WildStackers is enabled on the server
|
||||||
registeredGameModes.clear();
|
// I only added support for counting blocks into the island level
|
||||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
// Someone else can PR if they want spawners added to the Leveling system :)
|
||||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName()))
|
if (!settings.getDisabledPluginHooks().contains("WildStacker")) {
|
||||||
.forEach(gm -> {
|
stackersEnabled = Bukkit.getPluginManager().isPluginEnabled("WildStacker");
|
||||||
log("Level hooking into " + gm.getDescription().getName());
|
if (stackersEnabled) {
|
||||||
registerCommands(gm);
|
log("Hooked into WildStackers.");
|
||||||
new PlaceholderManager(this).registerPlaceholders(gm);
|
}
|
||||||
registeredGameModes.add(gm);
|
}
|
||||||
});
|
|
||||||
// Register request handlers
|
|
||||||
registerRequestHandler(new LevelRequestHandler(this));
|
|
||||||
registerRequestHandler(new TopTenRequestHandler(this));
|
|
||||||
|
|
||||||
// Check if WildStackers is enabled on the server
|
// Check if AdvancedChests is enabled on the server
|
||||||
// I only added support for counting blocks into the island level
|
if (!settings.getDisabledPluginHooks().contains("AdvancedChests")) {
|
||||||
// Someone else can PR if they want spawners added to the Leveling system :)
|
Plugin advChest = Bukkit.getPluginManager().getPlugin("AdvancedChests");
|
||||||
if ( !settings.getDisabledPluginHooks().contains("WildStacker") ) {
|
advChestEnabled = advChest != null;
|
||||||
stackersEnabled = Bukkit.getPluginManager().isPluginEnabled("WildStacker");
|
if (advChestEnabled) {
|
||||||
if (stackersEnabled) {
|
// Check version
|
||||||
log("Hooked into WildStackers.");
|
if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) {
|
||||||
}
|
log("Hooked into AdvancedChests.");
|
||||||
}
|
} else {
|
||||||
|
logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion()
|
||||||
|
+ " - requires version 23.0 or later");
|
||||||
|
advChestEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if AdvancedChests is enabled on the server
|
// Check if RoseStackers is enabled
|
||||||
if ( !settings.getDisabledPluginHooks().contains("AdvancedChests") ) {
|
if (!settings.getDisabledPluginHooks().contains("RoseStacker")) {
|
||||||
Plugin advChest = Bukkit.getPluginManager().getPlugin("AdvancedChests");
|
roseStackersEnabled = Bukkit.getPluginManager().isPluginEnabled("RoseStacker");
|
||||||
advChestEnabled = advChest != null;
|
if (roseStackersEnabled) {
|
||||||
if (advChestEnabled) {
|
log("Hooked into RoseStackers.");
|
||||||
// Check version
|
}
|
||||||
if (compareVersions(advChest.getDescription().getVersion(), "23.0") > 0) {
|
}
|
||||||
log("Hooked into AdvancedChests.");
|
|
||||||
} else {
|
|
||||||
logError("Could not hook into AdvancedChests " + advChest.getDescription().getVersion() + " - requires version 23.0 or later");
|
|
||||||
advChestEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if RoseStackers is enabled
|
// Check if UltimateStacker is enabled
|
||||||
if ( !settings.getDisabledPluginHooks().contains("RoseStacker") ) {
|
if (!settings.getDisabledPluginHooks().contains("UltimateStacker")) {
|
||||||
roseStackersEnabled = Bukkit.getPluginManager().isPluginEnabled("RoseStacker");
|
ultimateStackerEnabled = Bukkit.getPluginManager().isPluginEnabled("UltimateStacker");
|
||||||
if (roseStackersEnabled) {
|
if (ultimateStackerEnabled) {
|
||||||
log("Hooked into RoseStackers.");
|
log("Hooked into UltimateStacker.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if UltimateStacker is enabled
|
@Override
|
||||||
if ( !settings.getDisabledPluginHooks().contains("UltimateStacker") ) {
|
public void allLoaded() {
|
||||||
ultimateStackerEnabled = Bukkit.getPluginManager().isPluginEnabled("UltimateStacker");
|
super.allLoaded();
|
||||||
if (ultimateStackerEnabled) {
|
|
||||||
log("Hooked into UltimateStacker.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (this.isEnabled()) {
|
||||||
public void allLoaded()
|
this.hookExtensions();
|
||||||
{
|
}
|
||||||
super.allLoaded();
|
}
|
||||||
|
|
||||||
if (this.isEnabled())
|
/**
|
||||||
{
|
* This method tries to hook into addons and plugins
|
||||||
this.hookExtensions();
|
*/
|
||||||
}
|
private void hookExtensions() {
|
||||||
}
|
// Try to find Visit addon and if it does not exist, display a warning
|
||||||
|
this.getAddonByName("Visit").ifPresentOrElse(addon -> {
|
||||||
|
this.visitHook = (VisitAddon) addon;
|
||||||
|
this.log("Level Addon hooked into Visit addon.");
|
||||||
|
}, () -> this.visitHook = null);
|
||||||
|
|
||||||
|
// Try to find Warps addon and if it does not exist, display a warning
|
||||||
|
this.getAddonByName("Warps").ifPresentOrElse(addon -> {
|
||||||
|
this.warpHook = (Warp) addon;
|
||||||
|
this.log("Level Addon hooked into Warps addon.");
|
||||||
|
}, () -> this.warpHook = null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method tries to hook into addons and plugins
|
* Compares versions
|
||||||
*/
|
*
|
||||||
private void hookExtensions()
|
* @param version1 version 1
|
||||||
{
|
* @param version2 version 2
|
||||||
// Try to find Visit addon and if it does not exist, display a warning
|
* @return {@code <0 if version 1 is older than version 2, =0 if the same, >0 if version 1 is newer than version 2}
|
||||||
this.getAddonByName("Visit").ifPresentOrElse(addon ->
|
*/
|
||||||
{
|
public static int compareVersions(String version1, String version2) {
|
||||||
this.visitHook = (VisitAddon) addon;
|
int comparisonResult = 0;
|
||||||
this.log("Level Addon hooked into Visit addon.");
|
|
||||||
}, () -> this.visitHook = null);
|
|
||||||
|
|
||||||
// Try to find Warps addon and if it does not exist, display a warning
|
String[] version1Splits = version1.split("\\.");
|
||||||
this.getAddonByName("Warps").ifPresentOrElse(addon ->
|
String[] version2Splits = version2.split("\\.");
|
||||||
{
|
int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length);
|
||||||
this.warpHook = (Warp) addon;
|
|
||||||
this.log("Level Addon hooked into Warps addon.");
|
|
||||||
}, () -> this.warpHook = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (int i = 0; i < maxLengthOfVersionSplits; i++) {
|
||||||
|
Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0;
|
||||||
|
Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0;
|
||||||
|
int compare = v1.compareTo(v2);
|
||||||
|
if (compare != 0) {
|
||||||
|
comparisonResult = compare;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comparisonResult;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private void registerCommands(GameModeAddon gm) {
|
||||||
* Compares versions
|
gm.getAdminCommand().ifPresent(adminCommand -> {
|
||||||
* @param version1 version 1
|
new AdminLevelCommand(this, adminCommand);
|
||||||
* @param version2 version 2
|
new AdminTopCommand(this, adminCommand);
|
||||||
* @return {@code <0 if version 1 is older than version 2, =0 if the same, >0 if version 1 is newer than version 2}
|
new AdminLevelStatusCommand(this, adminCommand);
|
||||||
*/
|
if (getSettings().isZeroNewIslandLevels()) {
|
||||||
public static int compareVersions(String version1, String version2) {
|
new AdminSetInitialLevelCommand(this, adminCommand);
|
||||||
int comparisonResult = 0;
|
}
|
||||||
|
new AdminStatsCommand(this, adminCommand);
|
||||||
|
});
|
||||||
|
gm.getPlayerCommand().ifPresent(playerCmd -> {
|
||||||
|
new IslandLevelCommand(this, playerCmd);
|
||||||
|
new IslandTopCommand(this, playerCmd);
|
||||||
|
new IslandValueCommand(this, playerCmd);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
String[] version1Splits = version1.split("\\.");
|
@Override
|
||||||
String[] version2Splits = version2.split("\\.");
|
public void onDisable() {
|
||||||
int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length);
|
// Stop the pipeline
|
||||||
|
this.getPipeliner().stop();
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < maxLengthOfVersionSplits; i++){
|
private void loadBlockSettings() {
|
||||||
Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0;
|
// Save the default blockconfig.yml
|
||||||
Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0;
|
this.saveResource("blockconfig.yml", false);
|
||||||
int compare = v1.compareTo(v2);
|
|
||||||
if (compare != 0) {
|
|
||||||
comparisonResult = compare;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return comparisonResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerCommands(GameModeAddon gm) {
|
YamlConfiguration blockValues = new YamlConfiguration();
|
||||||
gm.getAdminCommand().ifPresent(adminCommand -> {
|
try {
|
||||||
new AdminLevelCommand(this, adminCommand);
|
File file = new File(this.getDataFolder(), "blockconfig.yml");
|
||||||
new AdminTopCommand(this, adminCommand);
|
blockValues.load(file);
|
||||||
new AdminLevelStatusCommand(this, adminCommand);
|
// Load the block config class
|
||||||
if (getSettings().isZeroNewIslandLevels()) {
|
blockConfig = new BlockConfig(this, blockValues, file);
|
||||||
new AdminSetInitialLevelCommand(this, adminCommand);
|
} catch (IOException | InvalidConfigurationException e) {
|
||||||
}
|
// Disable
|
||||||
});
|
logError("Level blockconfig.yml settings could not load! Addon disabled.");
|
||||||
gm.getPlayerCommand().ifPresent(playerCmd -> {
|
setState(State.DISABLED);
|
||||||
new IslandLevelCommand(this, playerCmd);
|
}
|
||||||
new IslandTopCommand(this, playerCmd);
|
|
||||||
new IslandValueCommand(this, playerCmd);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
}
|
||||||
public void onDisable() {
|
|
||||||
// Stop the pipeline
|
|
||||||
this.getPipeliner().stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadBlockSettings() {
|
/**
|
||||||
// Save the default blockconfig.yml
|
* @return the blockConfig
|
||||||
this.saveResource("blockconfig.yml", false);
|
*/
|
||||||
|
public BlockConfig getBlockConfig() {
|
||||||
|
return blockConfig;
|
||||||
|
}
|
||||||
|
|
||||||
YamlConfiguration blockValues = new YamlConfiguration();
|
/**
|
||||||
try {
|
* @return the settings
|
||||||
File file = new File(this.getDataFolder(), "blockconfig.yml");
|
*/
|
||||||
blockValues.load(file);
|
public ConfigSettings getSettings() {
|
||||||
// Load the block config class
|
return settings;
|
||||||
blockConfig = new BlockConfig(this, blockValues, file);
|
}
|
||||||
} catch (IOException | InvalidConfigurationException e) {
|
|
||||||
// Disable
|
|
||||||
logError("Level blockconfig.yml settings could not load! Addon disabled.");
|
|
||||||
setState(State.DISABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* @return the pipeliner
|
||||||
|
*/
|
||||||
|
public Pipeliner getPipeliner() {
|
||||||
|
return pipeliner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the manager
|
||||||
|
*/
|
||||||
|
public LevelsManager getManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the blockConfig
|
* Set the config settings - used for tests only
|
||||||
*/
|
*
|
||||||
public BlockConfig getBlockConfig() {
|
* @param configSettings - config settings
|
||||||
return blockConfig;
|
*/
|
||||||
}
|
void setSettings(ConfigSettings configSettings) {
|
||||||
|
this.settings = configSettings;
|
||||||
|
|
||||||
/**
|
}
|
||||||
* @return the settings
|
|
||||||
*/
|
|
||||||
public ConfigSettings getSettings() {
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the pipeliner
|
* @return the stackersEnabled
|
||||||
*/
|
*/
|
||||||
public Pipeliner getPipeliner() {
|
public boolean isStackersEnabled() {
|
||||||
return pipeliner;
|
return stackersEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the manager
|
* @return the advChestEnabled
|
||||||
*/
|
*/
|
||||||
public LevelsManager getManager() {
|
public boolean isAdvChestEnabled() {
|
||||||
return manager;
|
return advChestEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the config settings - used for tests only
|
* Get level from cache for a player.
|
||||||
* @param configSettings - config settings
|
*
|
||||||
*/
|
* @param targetPlayer - target player UUID
|
||||||
void setSettings(ConfigSettings configSettings) {
|
* @return Level of player or zero if player is unknown or UUID is null
|
||||||
this.settings = configSettings;
|
*/
|
||||||
|
public long getIslandLevel(World world, @Nullable UUID targetPlayer) {
|
||||||
|
return getManager().getIslandLevel(world, targetPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Sets the player's level to a value
|
||||||
|
*
|
||||||
|
* @param world - world
|
||||||
|
* @param targetPlayer - target player
|
||||||
|
* @param level - level
|
||||||
|
*/
|
||||||
|
public void setIslandLevel(World world, UUID targetPlayer, long level) {
|
||||||
|
getManager().setIslandLevel(world, targetPlayer, level);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the stackersEnabled
|
* Zeros the initial island level
|
||||||
*/
|
*
|
||||||
public boolean isStackersEnabled() {
|
* @param island - island
|
||||||
return stackersEnabled;
|
* @param level - initial calculated island level
|
||||||
}
|
*/
|
||||||
|
public void setInitialIslandLevel(@NonNull Island island, long level) {
|
||||||
|
getManager().setInitialIslandLevel(island, level);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the advChestEnabled
|
* Get the initial island level
|
||||||
*/
|
*
|
||||||
public boolean isAdvChestEnabled() {
|
* @param island - island
|
||||||
return advChestEnabled;
|
* @return level or 0 by default
|
||||||
}
|
*/
|
||||||
|
public long getInitialIslandLevel(@NonNull Island island) {
|
||||||
|
return getManager().getInitialLevel(island);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get level from cache for a player.
|
* Calculates a user's island
|
||||||
* @param targetPlayer - target player UUID
|
*
|
||||||
* @return Level of player or zero if player is unknown or UUID is null
|
* @param world - the world where this island is
|
||||||
*/
|
* @param user - not used! See depecration message
|
||||||
public long getIslandLevel(World world, @Nullable UUID targetPlayer) {
|
* @param playerUUID - the target island member's UUID
|
||||||
return getManager().getIslandLevel(world, targetPlayer);
|
* @deprecated Do not use this anymore. Use
|
||||||
}
|
* getManager().calculateLevel(playerUUID, island)
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "2.3.0", forRemoval = true)
|
||||||
|
public void calculateIslandLevel(World world, @Nullable User user, @NonNull UUID playerUUID) {
|
||||||
|
Island island = getIslands().getIsland(world, playerUUID);
|
||||||
|
if (island != null)
|
||||||
|
getManager().calculateLevel(playerUUID, island);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the player's level to a value
|
* Provide the levels data for the target player
|
||||||
* @param world - world
|
*
|
||||||
* @param targetPlayer - target player
|
* @param targetPlayer - UUID of target player
|
||||||
* @param level - level
|
* @return LevelsData object or null if not found. Only island levels are set!
|
||||||
*/
|
* @deprecated Do not use this anymore. Use {@link #getIslandLevel(World, UUID)}
|
||||||
public void setIslandLevel(World world, UUID targetPlayer, long level) {
|
*/
|
||||||
getManager().setIslandLevel(world, targetPlayer, level);
|
@Deprecated(since = "2.3.0", forRemoval = true)
|
||||||
}
|
public LevelsData getLevelsData(UUID targetPlayer) {
|
||||||
|
LevelsData ld = new LevelsData(targetPlayer);
|
||||||
|
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
||||||
|
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
|
||||||
|
if (getSettings().isZeroNewIslandLevels()) {
|
||||||
|
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
|
||||||
|
if (island != null) {
|
||||||
|
ld.setInitialLevel(gm.getOverWorld(), this.getInitialIslandLevel(island));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ld.setLevel(gm.getOverWorld(), this.getIslandLevel(gm.getOverWorld(), targetPlayer));
|
||||||
|
});
|
||||||
|
return ld;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zeros the initial island level
|
* @return the registeredGameModes
|
||||||
* @param island - island
|
*/
|
||||||
* @param level - initial calculated island level
|
public List<GameModeAddon> getRegisteredGameModes() {
|
||||||
*/
|
return registeredGameModes;
|
||||||
public void setInitialIslandLevel(@NonNull Island island, long level) {
|
}
|
||||||
getManager().setInitialIslandLevel(island, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the initial island level
|
* Check if Level addon is active in game mode
|
||||||
* @param island - island
|
*
|
||||||
* @return level or 0 by default
|
* @param gm Game Mode Addon
|
||||||
*/
|
* @return true if active, false if not
|
||||||
public long getInitialIslandLevel(@NonNull Island island) {
|
*/
|
||||||
return getManager().getInitialLevel(island);
|
public boolean isRegisteredGameMode(GameModeAddon gm) {
|
||||||
}
|
return registeredGameModes.contains(gm);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates a user's island
|
* Checks if Level addon is active in world
|
||||||
* @param world - the world where this island is
|
*
|
||||||
* @param user - not used! See depecration message
|
* @param world world
|
||||||
* @param playerUUID - the target island member's UUID
|
* @return true if active, false if not
|
||||||
* @deprecated Do not use this anymore. Use getManager().calculateLevel(playerUUID, island)
|
*/
|
||||||
*/
|
public boolean isRegisteredGameModeWorld(World world) {
|
||||||
@Deprecated(since="2.3.0", forRemoval=true)
|
return registeredGameModes.stream().map(GameModeAddon::getOverWorld).anyMatch(w -> Util.sameWorld(world, w));
|
||||||
public void calculateIslandLevel(World world, @Nullable User user, @NonNull UUID playerUUID) {
|
}
|
||||||
Island island = getIslands().getIsland(world, playerUUID);
|
|
||||||
if (island != null) getManager().calculateLevel(playerUUID, island);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide the levels data for the target player
|
* @return the roseStackersEnabled
|
||||||
* @param targetPlayer - UUID of target player
|
*/
|
||||||
* @return LevelsData object or null if not found. Only island levels are set!
|
public boolean isRoseStackersEnabled() {
|
||||||
* @deprecated Do not use this anymore. Use {@link #getIslandLevel(World, UUID)}
|
return roseStackersEnabled;
|
||||||
*/
|
}
|
||||||
@Deprecated(since="2.3.0", forRemoval=true)
|
|
||||||
public LevelsData getLevelsData(UUID targetPlayer) {
|
|
||||||
LevelsData ld = new LevelsData(targetPlayer);
|
|
||||||
getPlugin().getAddonsManager().getGameModeAddons().stream()
|
|
||||||
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName()))
|
|
||||||
.forEach(gm -> {
|
|
||||||
if (getSettings().isZeroNewIslandLevels()) {
|
|
||||||
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
|
|
||||||
if (island != null) {
|
|
||||||
ld.setInitialLevel(gm.getOverWorld(), this.getInitialIslandLevel(island));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ld.setLevel(gm.getOverWorld(), this.getIslandLevel(gm.getOverWorld(), targetPlayer));
|
|
||||||
});
|
|
||||||
return ld;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the registeredGameModes
|
* @return the ultimateStackerEnabled
|
||||||
*/
|
*/
|
||||||
public List<GameModeAddon> getRegisteredGameModes() {
|
public boolean isUltimateStackerEnabled() {
|
||||||
return registeredGameModes;
|
return ultimateStackerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Level addon is active in game mode
|
* Method Level#getVisitHook returns the visitHook of this object.
|
||||||
* @param gm Game Mode Addon
|
*
|
||||||
* @return true if active, false if not
|
* @return {@code Visit} of this object, {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isRegisteredGameMode(GameModeAddon gm) {
|
public VisitAddon getVisitHook() {
|
||||||
return registeredGameModes.contains(gm);
|
return this.visitHook;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if Level addon is active in world
|
* Method Level#getWarpHook returns the warpHook of this object.
|
||||||
* @param world world
|
*
|
||||||
* @return true if active, false if not
|
* @return {@code Warp} of this object, {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isRegisteredGameModeWorld(World world) {
|
public Warp getWarpHook() {
|
||||||
return registeredGameModes.stream().map(GameModeAddon::getOverWorld).anyMatch(w -> Util.sameWorld(world, w));
|
return this.warpHook;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the roseStackersEnabled
|
|
||||||
*/
|
|
||||||
public boolean isRoseStackersEnabled() {
|
|
||||||
return roseStackersEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the ultimateStackerEnabled
|
|
||||||
*/
|
|
||||||
public boolean isUltimateStackerEnabled() {
|
|
||||||
return ultimateStackerEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method Level#getVisitHook returns the visitHook of this object.
|
|
||||||
*
|
|
||||||
* @return {@code Visit} of this object, {@code null} otherwise.
|
|
||||||
*/
|
|
||||||
public VisitAddon getVisitHook()
|
|
||||||
{
|
|
||||||
return this.visitHook;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method Level#getWarpHook returns the warpHook of this object.
|
|
||||||
*
|
|
||||||
* @return {@code Warp} of this object, {@code null} otherwise.
|
|
||||||
*/
|
|
||||||
public Warp getWarpHook()
|
|
||||||
{
|
|
||||||
return this.warpHook;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,417 +31,453 @@ 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;
|
||||||
private static final BigInteger THOUSAND = BigInteger.valueOf(1000);
|
private static final BigInteger THOUSAND = BigInteger.valueOf(1000);
|
||||||
static {
|
static {
|
||||||
LEVELS = new TreeMap<>();
|
LEVELS = new TreeMap<>();
|
||||||
|
|
||||||
LEVELS.put(THOUSAND, "k");
|
LEVELS.put(THOUSAND, "k");
|
||||||
LEVELS.put(THOUSAND.pow(2), "M");
|
LEVELS.put(THOUSAND.pow(2), "M");
|
||||||
LEVELS.put(THOUSAND.pow(3), "G");
|
LEVELS.put(THOUSAND.pow(3), "G");
|
||||||
LEVELS.put(THOUSAND.pow(4), "T");
|
LEVELS.put(THOUSAND.pow(4), "T");
|
||||||
}
|
}
|
||||||
private final Level addon;
|
private final Level addon;
|
||||||
|
|
||||||
// Database handler for level data
|
// Database handler for level data
|
||||||
private final Database<IslandLevels> handler;
|
private final Database<IslandLevels> handler;
|
||||||
// A cache of island levels.
|
// A cache of island levels.
|
||||||
private final Map<String, IslandLevels> levelsCache;
|
private final Map<String, IslandLevels> levelsCache;
|
||||||
// Top ten lists
|
// Top ten lists
|
||||||
private final Map<World,TopTenData> topTenLists;
|
private final Map<World, TopTenData> topTenLists;
|
||||||
|
|
||||||
|
public LevelsManager(Level addon) {
|
||||||
|
this.addon = addon;
|
||||||
|
// Get the BentoBox database
|
||||||
|
// Set up the database handler to store and retrieve data
|
||||||
|
// Note that these are saved by the BentoBox database
|
||||||
|
handler = new Database<>(addon, IslandLevels.class);
|
||||||
|
// Initialize the cache
|
||||||
|
levelsCache = new HashMap<>();
|
||||||
|
// Initialize top ten lists
|
||||||
|
topTenLists = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
public LevelsManager(Level addon) {
|
public void migrate() {
|
||||||
this.addon = addon;
|
Database<LevelsData> oldDb = new Database<>(addon, LevelsData.class);
|
||||||
// Get the BentoBox database
|
oldDb.loadObjects().forEach(ld -> {
|
||||||
// Set up the database handler to store and retrieve data
|
try {
|
||||||
// Note that these are saved by the BentoBox database
|
UUID owner = UUID.fromString(ld.getUniqueId());
|
||||||
handler = new Database<>(addon, IslandLevels.class);
|
// Step through each world
|
||||||
// Initialize the cache
|
ld.getLevels().keySet().stream()
|
||||||
levelsCache = new HashMap<>();
|
// World
|
||||||
// Initialize top ten lists
|
.map(Bukkit::getWorld).filter(Objects::nonNull)
|
||||||
topTenLists = new ConcurrentHashMap<>();
|
// Island
|
||||||
}
|
.map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull).forEach(i -> {
|
||||||
|
// Make new database entry
|
||||||
|
World w = i.getWorld();
|
||||||
|
IslandLevels il = new IslandLevels(i.getUniqueId());
|
||||||
|
il.setInitialLevel(ld.getInitialLevel(w));
|
||||||
|
il.setLevel(ld.getLevel(w));
|
||||||
|
il.setMdCount(ld.getMdCount(w));
|
||||||
|
il.setPointsToNextLevel(ld.getPointsToNextLevel(w));
|
||||||
|
il.setUwCount(ld.getUwCount(w));
|
||||||
|
// Save it
|
||||||
|
handler.saveObjectAsync(il);
|
||||||
|
});
|
||||||
|
// Now delete the old database entry
|
||||||
|
oldDb.deleteID(ld.getUniqueId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
addon.logError("Could not migrate level data database! " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void migrate() {
|
/**
|
||||||
Database<LevelsData> oldDb = new Database<>(addon, LevelsData.class);
|
* Add a score to the top players list
|
||||||
oldDb.loadObjects().forEach(ld -> {
|
*
|
||||||
try {
|
* @param world - world
|
||||||
UUID owner = UUID.fromString(ld.getUniqueId());
|
* @param targetPlayer - target player
|
||||||
// Step through each world
|
* @param lv - island level
|
||||||
ld.getLevels().keySet().stream()
|
*/
|
||||||
// World
|
private void addToTopTen(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
||||||
.map(Bukkit::getWorld).filter(Objects::nonNull)
|
// Get top ten
|
||||||
// Island
|
Map<UUID, Long> topTen = topTenLists.computeIfAbsent(world, k -> new TopTenData(world)).getTopTen();
|
||||||
.map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull)
|
// Remove this player from the top list no matter what (we'll put them back
|
||||||
.forEach(i -> {
|
// later if required)
|
||||||
// Make new database entry
|
topTen.remove(targetPlayer);
|
||||||
World w = i.getWorld();
|
|
||||||
IslandLevels il = new IslandLevels(i.getUniqueId());
|
|
||||||
il.setInitialLevel(ld.getInitialLevel(w));
|
|
||||||
il.setLevel(ld.getLevel(w));
|
|
||||||
il.setMdCount(ld.getMdCount(w));
|
|
||||||
il.setPointsToNextLevel(ld.getPointsToNextLevel(w));
|
|
||||||
il.setUwCount(ld.getUwCount(w));
|
|
||||||
// Save it
|
|
||||||
handler.saveObjectAsync(il);
|
|
||||||
});
|
|
||||||
// Now delete the old database entry
|
|
||||||
oldDb.deleteID(ld.getUniqueId());
|
|
||||||
} catch (Exception e) {
|
|
||||||
addon.logError("Could not migrate level data database! " + e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Get the island
|
||||||
* Add a score to the top players list
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
* @param world - world
|
if (island != null && island.getOwner() != null && hasTopTenPerm(world, island.getOwner())) {
|
||||||
* @param targetPlayer - target player
|
// Insert the owner into the top ten
|
||||||
* @param lv - island level
|
topTen.put(island.getOwner(), lv);
|
||||||
*/
|
}
|
||||||
private void addToTopTen(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
}
|
||||||
// Get top ten
|
|
||||||
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)
|
|
||||||
topTen.remove(targetPlayer);
|
|
||||||
|
|
||||||
// Get the island
|
/**
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
* Add an island to a top ten
|
||||||
if (island != null && island.getOwner() != null && hasTopTenPerm(world, island.getOwner())) {
|
*
|
||||||
// Insert the owner into the top ten
|
* @param island - island to add
|
||||||
topTen.put(island.getOwner(), lv);
|
* @param lv - level
|
||||||
}
|
* @return true if successful, false if not added
|
||||||
}
|
*/
|
||||||
|
private boolean addToTopTen(Island island, long lv) {
|
||||||
|
if (island != null && island.getOwner() != null && hasTopTenPerm(island.getWorld(), island.getOwner())) {
|
||||||
|
topTenLists.computeIfAbsent(island.getWorld(), k -> new TopTenData(island.getWorld())).getTopTen()
|
||||||
|
.put(island.getOwner(), lv);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an island to a top ten
|
* Calculate the island level, set all island member's levels to the result and
|
||||||
* @param island - island to add
|
* try to add the owner to the top ten
|
||||||
* @param lv - level
|
*
|
||||||
* @return true if successful, false if not added
|
* @param targetPlayer - uuid of targeted player - owner or team member
|
||||||
*/
|
* @param island - island to calculate
|
||||||
private boolean addToTopTen(Island island, long lv) {
|
* @return completable future with the results of the calculation
|
||||||
if (island != null && island.getOwner() != null && hasTopTenPerm(island.getWorld(), island.getOwner())) {
|
*/
|
||||||
topTenLists.computeIfAbsent(island.getWorld(), k -> new TopTenData(island.getWorld()))
|
public CompletableFuture<Results> calculateLevel(UUID targetPlayer, Island island) {
|
||||||
.getTopTen().put(island.getOwner(), lv);
|
CompletableFuture<Results> result = new CompletableFuture<>();
|
||||||
return true;
|
// Fire pre-level calc event
|
||||||
}
|
IslandPreLevelEvent e = new IslandPreLevelEvent(targetPlayer, island);
|
||||||
return false;
|
Bukkit.getPluginManager().callEvent(e);
|
||||||
}
|
if (e.isCancelled()) {
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
// Add island to the pipeline
|
||||||
|
addon.getPipeliner().addIsland(island).thenAccept(r -> {
|
||||||
|
// Results are irrelevant because the island is unowned or deleted, or
|
||||||
|
// IslandLevelCalcEvent is cancelled
|
||||||
|
if (r == null || fireIslandLevelCalcEvent(targetPlayer, island, r)) {
|
||||||
|
result.complete(null);
|
||||||
|
}
|
||||||
|
// Save result
|
||||||
|
setIslandResults(island.getWorld(), island.getOwner(), r);
|
||||||
|
// Save the island scan details
|
||||||
|
result.complete(r);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the island level, set all island member's levels to the result and try to add the owner to the top ten
|
* Fires the IslandLevelCalculatedEvent and returns true if it is canceled
|
||||||
* @param targetPlayer - uuid of targeted player - owner or team member
|
*
|
||||||
* @param island - island to calculate
|
* @param targetPlayer - target player
|
||||||
* @return completable future with the results of the calculation
|
* @param island - island
|
||||||
*/
|
* @param results - results set
|
||||||
public CompletableFuture<Results> calculateLevel(UUID targetPlayer, Island island) {
|
* @return true if canceled
|
||||||
CompletableFuture<Results> result = new CompletableFuture<>();
|
*/
|
||||||
// Fire pre-level calc event
|
private boolean fireIslandLevelCalcEvent(UUID targetPlayer, Island island, Results results) {
|
||||||
IslandPreLevelEvent e = new IslandPreLevelEvent(targetPlayer, island);
|
// Fire post calculation event
|
||||||
Bukkit.getPluginManager().callEvent(e);
|
IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, results);
|
||||||
if (e.isCancelled()) {
|
Bukkit.getPluginManager().callEvent(ilce);
|
||||||
return CompletableFuture.completedFuture(null);
|
if (ilce.isCancelled())
|
||||||
}
|
return true;
|
||||||
// Add island to the pipeline
|
// Set the values if they were altered
|
||||||
addon.getPipeliner().addIsland(island).thenAccept(r -> {
|
results.setLevel((Long) ilce.getKeyValues().getOrDefault("level", results.getLevel()));
|
||||||
// Results are irrelevant because the island is unowned or deleted, or IslandLevelCalcEvent is cancelled
|
results.setInitialLevel((Long) ilce.getKeyValues().getOrDefault("initialLevel", results.getInitialLevel()));
|
||||||
if (r == null || fireIslandLevelCalcEvent(targetPlayer, island, r)) {
|
results.setDeathHandicap((int) ilce.getKeyValues().getOrDefault("deathHandicap", results.getDeathHandicap()));
|
||||||
result.complete(null);
|
results.setPointsToNextLevel(
|
||||||
}
|
(Long) ilce.getKeyValues().getOrDefault("pointsToNextLevel", results.getPointsToNextLevel()));
|
||||||
// Save result
|
results.setTotalPoints((Long) ilce.getKeyValues().getOrDefault("totalPoints", results.getTotalPoints()));
|
||||||
setIslandResults(island.getWorld(), island.getOwner(), r);
|
return ((Boolean) ilce.getKeyValues().getOrDefault("isCancelled", false));
|
||||||
// Save the island scan details
|
}
|
||||||
result.complete(r);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires the IslandLevelCalculatedEvent and returns true if it is canceled
|
* Get the string representation of the level. May be converted to shorthand
|
||||||
* @param targetPlayer - target player
|
* notation, e.g., 104556 = 10.5k
|
||||||
* @param island - island
|
*
|
||||||
* @param results - results set
|
* @param lvl - long value to represent
|
||||||
* @return true if canceled
|
* @return string of the level.
|
||||||
*/
|
*/
|
||||||
private boolean fireIslandLevelCalcEvent(UUID targetPlayer, Island island, Results results) {
|
public String formatLevel(@Nullable Long lvl) {
|
||||||
// Fire post calculation event
|
if (lvl == null)
|
||||||
IslandLevelCalculatedEvent ilce = new IslandLevelCalculatedEvent(targetPlayer, island, results);
|
return "";
|
||||||
Bukkit.getPluginManager().callEvent(ilce);
|
String level = String.valueOf(lvl);
|
||||||
if (ilce.isCancelled()) return true;
|
// Asking for the level of another player
|
||||||
// Set the values if they were altered
|
if (addon.getSettings().isShorthand()) {
|
||||||
results.setLevel((Long)ilce.getKeyValues().getOrDefault("level", results.getLevel()));
|
BigInteger levelValue = BigInteger.valueOf(lvl);
|
||||||
results.setInitialLevel((Long)ilce.getKeyValues().getOrDefault("initialLevel", results.getInitialLevel()));
|
|
||||||
results.setDeathHandicap((int)ilce.getKeyValues().getOrDefault("deathHandicap", results.getDeathHandicap()));
|
|
||||||
results.setPointsToNextLevel((Long)ilce.getKeyValues().getOrDefault("pointsToNextLevel", results.getPointsToNextLevel()));
|
|
||||||
results.setTotalPoints((Long)ilce.getKeyValues().getOrDefault("totalPoints", results.getTotalPoints()));
|
|
||||||
return ((Boolean)ilce.getKeyValues().getOrDefault("isCancelled", false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
Map.Entry<BigInteger, String> stage = LEVELS.floorEntry(levelValue);
|
||||||
* Get the string representation of the level. May be converted to shorthand notation, e.g., 104556 = 10.5k
|
|
||||||
* @param lvl - long value to represent
|
|
||||||
* @return string of the level.
|
|
||||||
*/
|
|
||||||
public String formatLevel(@Nullable Long lvl) {
|
|
||||||
if (lvl == null) return "";
|
|
||||||
String level = String.valueOf(lvl);
|
|
||||||
// Asking for the level of another player
|
|
||||||
if(addon.getSettings().isShorthand()) {
|
|
||||||
BigInteger levelValue = BigInteger.valueOf(lvl);
|
|
||||||
|
|
||||||
Map.Entry<BigInteger, String> stage = LEVELS.floorEntry(levelValue);
|
if (stage != null) { // level > 1000
|
||||||
|
// 1 052 -> 1.0k
|
||||||
|
// 1 527 314 -> 1.5M
|
||||||
|
// 3 874 130 021 -> 3.8G
|
||||||
|
// 4 002 317 889 -> 4.0T
|
||||||
|
level = new DecimalFormat("#.#").format(
|
||||||
|
levelValue.divide(stage.getKey().divide(THOUSAND)).doubleValue() / 1000.0) + stage.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
if (stage != null) { // level > 1000
|
/**
|
||||||
// 1 052 -> 1.0k
|
* Get the initial level of the island. Used to zero island levels
|
||||||
// 1 527 314 -> 1.5M
|
*
|
||||||
// 3 874 130 021 -> 3.8G
|
* @param island - island
|
||||||
// 4 002 317 889 -> 4.0T
|
* @return initial level of island
|
||||||
level = new DecimalFormat("#.#").format(levelValue.divide(stage.getKey().divide(THOUSAND)).doubleValue()/1000.0) + stage.getValue();
|
*/
|
||||||
}
|
public long getInitialLevel(Island island) {
|
||||||
}
|
return getLevelsData(island).getInitialLevel();
|
||||||
return level;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the initial level of the island. Used to zero island levels
|
* Get level of island from cache for a player.
|
||||||
* @param island - island
|
*
|
||||||
* @return initial level of island
|
* @param world - world where the island is
|
||||||
*/
|
* @param targetPlayer - target player UUID
|
||||||
public long getInitialLevel(Island island) {
|
* @return Level of the player's island or zero if player is unknown or UUID is
|
||||||
return getLevelsData(island).getInitialLevel();
|
* null
|
||||||
}
|
*/
|
||||||
|
public long getIslandLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
|
if (targetPlayer == null)
|
||||||
|
return 0L;
|
||||||
|
// Get the island
|
||||||
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
|
return island == null ? 0L : getLevelsData(island).getLevel();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get level of island from cache for a player.
|
* Get the maximum level ever given to this island
|
||||||
* @param world - world where the island is
|
*
|
||||||
* @param targetPlayer - target player UUID
|
* @param world - world where the island is
|
||||||
* @return Level of the player's island or zero if player is unknown or UUID is null
|
* @param targetPlayer - target player UUID
|
||||||
*/
|
* @return Max level of the player's island or zero if player is unknown or UUID
|
||||||
public long getIslandLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
* is null
|
||||||
if (targetPlayer == null) return 0L;
|
*/
|
||||||
// Get the island
|
public long getIslandMaxLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
if (targetPlayer == null)
|
||||||
return island == null ? 0L : getLevelsData(island).getLevel();
|
return 0L;
|
||||||
}
|
// Get the island
|
||||||
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
|
return island == null ? 0L : getLevelsData(island).getMaxLevel();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum level ever given to this island
|
* Returns a formatted string of the target player's island level
|
||||||
* @param world - world where the island is
|
*
|
||||||
* @param targetPlayer - target player UUID
|
* @param world - world where the island is
|
||||||
* @return Max level of the player's island or zero if player is unknown or UUID is null
|
* @param targetPlayer - target player's UUID
|
||||||
*/
|
* @return Formatted level of player or zero if player is unknown or UUID is
|
||||||
public long getIslandMaxLevel(@NonNull World world, @Nullable UUID targetPlayer) {
|
* null
|
||||||
if (targetPlayer == null) return 0L;
|
*/
|
||||||
// Get the island
|
public String getIslandLevelString(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
return formatLevel(getIslandLevel(world, targetPlayer));
|
||||||
return island == null ? 0L : getLevelsData(island).getMaxLevel();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a formatted string of the target player's island level
|
* Load a level data for the island from the cache or database.
|
||||||
* @param world - world where the island is
|
*
|
||||||
* @param targetPlayer - target player's UUID
|
* @param island - UUID of island
|
||||||
* @return Formatted level of player or zero if player is unknown or UUID is null
|
* @return IslandLevels object
|
||||||
*/
|
*/
|
||||||
public String getIslandLevelString(@NonNull World world, @Nullable UUID targetPlayer) {
|
@NonNull
|
||||||
return formatLevel(getIslandLevel(world, targetPlayer));
|
public IslandLevels getLevelsData(@NonNull Island island) {
|
||||||
}
|
String id = island.getUniqueId();
|
||||||
|
if (levelsCache.containsKey(id)) {
|
||||||
|
return levelsCache.get(id);
|
||||||
|
}
|
||||||
|
// Get from database if not in cache
|
||||||
|
if (handler.objectExists(id)) {
|
||||||
|
IslandLevels ld = handler.loadObject(id);
|
||||||
|
if (ld != null) {
|
||||||
|
levelsCache.put(id, ld);
|
||||||
|
} else {
|
||||||
|
handler.deleteID(id);
|
||||||
|
levelsCache.put(id, new IslandLevels(id));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
levelsCache.put(id, new IslandLevels(id));
|
||||||
|
}
|
||||||
|
// Return cached value
|
||||||
|
return levelsCache.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a level data for the island from the cache or database.
|
* Get the number of points required until the next level since the last level
|
||||||
* @param island - UUID of island
|
* calc
|
||||||
* @return IslandLevels object
|
*
|
||||||
*/
|
* @param world - world where the island is
|
||||||
@NonNull
|
* @param targetPlayer - target player UUID
|
||||||
public IslandLevels getLevelsData(@NonNull Island island) {
|
* @return string with the number required or blank if the player is unknown
|
||||||
String id = island.getUniqueId();
|
*/
|
||||||
if (levelsCache.containsKey(id)) {
|
public String getPointsToNextString(@NonNull World world, @Nullable UUID targetPlayer) {
|
||||||
return levelsCache.get(id);
|
if (targetPlayer == null)
|
||||||
}
|
return "";
|
||||||
// Get from database if not in cache
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
if (handler.objectExists(id)) {
|
return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel());
|
||||||
IslandLevels ld = handler.loadObject(id);
|
}
|
||||||
if (ld != null) {
|
|
||||||
levelsCache.put(id, ld);
|
|
||||||
} else {
|
|
||||||
handler.deleteID(id);
|
|
||||||
levelsCache.put(id, new IslandLevels(id));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
levelsCache.put(id, new IslandLevels(id));
|
|
||||||
}
|
|
||||||
// Return cached value
|
|
||||||
return levelsCache.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of points required until the next level since the last level calc
|
* Get the top ten for this world. Returns offline players or players with the
|
||||||
* @param world - world where the island is
|
* intopten permission.
|
||||||
* @param targetPlayer - target player UUID
|
*
|
||||||
* @return string with the number required or blank if the player is unknown
|
* @param world - world requested
|
||||||
*/
|
* @param size - size of the top ten
|
||||||
public String getPointsToNextString(@NonNull World world, @Nullable UUID targetPlayer) {
|
* @return sorted top ten map
|
||||||
if (targetPlayer == null) return "";
|
*/
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
@NonNull
|
||||||
return island == null ? "" : String.valueOf(getLevelsData(island).getPointsToNextLevel());
|
public Map<UUID, Long> getTopTen(@NonNull World world, int size) {
|
||||||
}
|
createAndCleanRankings(world);
|
||||||
|
// Return the sorted map
|
||||||
|
return Collections.unmodifiableMap(topTenLists.get(world).getTopTen().entrySet().stream()
|
||||||
|
.filter(e -> addon.getIslands().hasIsland(world, e.getKey())).filter(l -> l.getValue() > 0)
|
||||||
|
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).limit(size)
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
void createAndCleanRankings(@NonNull World world) {
|
||||||
* Get the top ten for this world. Returns offline players or players with the intopten permission.
|
topTenLists.computeIfAbsent(world, TopTenData::new);
|
||||||
* @param world - world requested
|
// Remove player from top ten if they are online and do not have the perm
|
||||||
* @param size - size of the top ten
|
topTenLists.get(world).getTopTen().keySet().removeIf(u -> !hasTopTenPerm(world, u));
|
||||||
* @return sorted top ten map
|
}
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public Map<UUID, Long> getTopTen(@NonNull World world, int size) {
|
|
||||||
createAndCleanRankings(world);
|
|
||||||
// Return the sorted map
|
|
||||||
return Collections.unmodifiableMap(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())).limit(size)
|
|
||||||
.collect(Collectors.toMap(
|
|
||||||
Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void createAndCleanRankings(@NonNull World world) {
|
/**
|
||||||
topTenLists.computeIfAbsent(world, TopTenData::new);
|
* @return the topTenLists
|
||||||
// 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));
|
public Map<World, TopTenData> getTopTenLists() {
|
||||||
}
|
return topTenLists;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the topTenLists
|
* Get the rank of the player in the rankings
|
||||||
*/
|
*
|
||||||
protected Map<World, TopTenData> getTopTenLists() {
|
* @param world - world
|
||||||
return topTenLists;
|
* @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<Entry<UUID, Long>> 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 (int) (stream.takeWhile(x -> !x.getKey().equals(uuid)).map(Map.Entry::getKey).count() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rank of the player in the rankings
|
* Checks if player has the correct top ten perm to have their level saved
|
||||||
* @param world - world
|
*
|
||||||
* @param uuid - player UUID
|
* @param world
|
||||||
* @return rank placing - note - placing of 1 means top ranked
|
* @param targetPlayer
|
||||||
*/
|
* @return true if player has the perm or the player is offline
|
||||||
public int getRank(@NonNull World world, UUID uuid) {
|
*/
|
||||||
createAndCleanRankings(world);
|
boolean hasTopTenPerm(@NonNull World world, @NonNull UUID targetPlayer) {
|
||||||
Stream<Entry<UUID, Long>> stream = topTenLists.get(world).getTopTen().entrySet().stream()
|
String permPrefix = addon.getPlugin().getIWM().getPermissionPrefix(world);
|
||||||
.filter(e -> addon.getIslands().isOwner(world, e.getKey()))
|
return Bukkit.getPlayer(targetPlayer) == null
|
||||||
.filter(l -> l.getValue() > 0)
|
|| Bukkit.getPlayer(targetPlayer).hasPermission(permPrefix + INTOPTEN);
|
||||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
|
}
|
||||||
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
|
* Loads all the top tens from the database
|
||||||
* @param world
|
*/
|
||||||
* @param targetPlayer
|
public void loadTopTens() {
|
||||||
* @return true if player has the perm or the player is offline
|
topTenLists.clear();
|
||||||
*/
|
Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> {
|
||||||
boolean hasTopTenPerm(@NonNull World world, @NonNull UUID targetPlayer) {
|
addon.log("Generating rankings");
|
||||||
String permPrefix = addon.getPlugin().getIWM().getPermissionPrefix(world);
|
handler.loadObjects().forEach(il -> {
|
||||||
return Bukkit.getPlayer(targetPlayer) == null || Bukkit.getPlayer(targetPlayer).hasPermission(permPrefix + INTOPTEN);
|
if (il.getLevel() > 0) {
|
||||||
}
|
addon.getIslands().getIslandById(il.getUniqueId())
|
||||||
|
.ifPresent(i -> this.addToTopTen(i, il.getLevel()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
topTenLists.keySet().forEach(w -> addon.log("Generated rankings for " + w.getName()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all the top tens from the database
|
* Removes a player from a world's top ten and removes world from player's level
|
||||||
*/
|
* data
|
||||||
public void loadTopTens() {
|
*
|
||||||
topTenLists.clear();
|
* @param world - world
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> {
|
* @param uuid - the player's uuid
|
||||||
addon.log("Generating rankings");
|
*/
|
||||||
handler.loadObjects().forEach(il -> {
|
public void removeEntry(World world, UUID uuid) {
|
||||||
if (il.getLevel() > 0) {
|
if (topTenLists.containsKey(world)) {
|
||||||
addon.getIslands().getIslandById(il.getUniqueId()).ifPresent(i -> this.addToTopTen(i, il.getLevel()));
|
topTenLists.get(world).getTopTen().remove(uuid);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
topTenLists.keySet().forEach(w -> addon.log("Generated rankings for " + w.getName()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Removes a player from a world's top ten and removes world from player's level data
|
|
||||||
* @param world - world
|
|
||||||
* @param uuid - the player's uuid
|
|
||||||
*/
|
|
||||||
public void removeEntry(World world, UUID uuid) {
|
|
||||||
if (topTenLists.containsKey(world)) {
|
|
||||||
topTenLists.get(world).getTopTen().remove(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Set an initial island level
|
||||||
|
*
|
||||||
|
* @param island - the island to set. Must have a non-null world
|
||||||
|
* @param lv - initial island level
|
||||||
|
*/
|
||||||
|
public void setInitialIslandLevel(@NonNull Island island, long lv) {
|
||||||
|
if (island.getWorld() == null)
|
||||||
|
return;
|
||||||
|
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv);
|
||||||
|
handler.saveObjectAsync(levelsCache.get(island.getUniqueId()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an initial island level
|
* Set the island level for the owner of the island that targetPlayer is a
|
||||||
* @param island - the island to set. Must have a non-null world
|
* member
|
||||||
* @param lv - initial island level
|
*
|
||||||
*/
|
* @param world - world
|
||||||
public void setInitialIslandLevel(@NonNull Island island, long lv) {
|
* @param targetPlayer - player, may be a team member
|
||||||
if (island.getWorld() == null) return;
|
* @param lv - level
|
||||||
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv);
|
*/
|
||||||
handler.saveObjectAsync(levelsCache.get(island.getUniqueId()));
|
public void setIslandLevel(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
||||||
}
|
// Get the island
|
||||||
|
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
||||||
|
if (island != null) {
|
||||||
|
String id = island.getUniqueId();
|
||||||
|
IslandLevels il = levelsCache.computeIfAbsent(id, IslandLevels::new);
|
||||||
|
// Remove the initial level
|
||||||
|
if (addon.getSettings().isZeroNewIslandLevels()) {
|
||||||
|
il.setLevel(lv - il.getInitialLevel());
|
||||||
|
} else {
|
||||||
|
il.setLevel(lv);
|
||||||
|
}
|
||||||
|
handler.saveObjectAsync(levelsCache.get(id));
|
||||||
|
// Update TopTen
|
||||||
|
addToTopTen(world, targetPlayer, levelsCache.get(id).getLevel());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Set the island level for the owner of the island that targetPlayer is a member
|
|
||||||
* @param world - world
|
|
||||||
* @param targetPlayer - player, may be a team member
|
|
||||||
* @param lv - level
|
|
||||||
*/
|
|
||||||
public void setIslandLevel(@NonNull World world, @NonNull UUID targetPlayer, long lv) {
|
|
||||||
// Get the island
|
|
||||||
Island island = addon.getIslands().getIsland(world, targetPlayer);
|
|
||||||
if (island != null) {
|
|
||||||
String id = island.getUniqueId();
|
|
||||||
IslandLevels il = levelsCache.computeIfAbsent(id, IslandLevels::new);
|
|
||||||
// Remove the initial level
|
|
||||||
if (addon.getSettings().isZeroNewIslandLevels()) {
|
|
||||||
il.setLevel(lv - il.getInitialLevel());
|
|
||||||
} else {
|
|
||||||
il.setLevel(lv);
|
|
||||||
}
|
|
||||||
handler.saveObjectAsync(levelsCache.get(id));
|
|
||||||
// Update TopTen
|
|
||||||
addToTopTen(world, targetPlayer, levelsCache.get(id).getLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Set the island level for the owner of the island that targetPlayer is a
|
||||||
|
* member
|
||||||
|
*
|
||||||
|
* @param world - world
|
||||||
|
* @param owner - owner of the island
|
||||||
|
* @param r - results of the calculation
|
||||||
|
*/
|
||||||
|
private void setIslandResults(World world, @NonNull UUID owner, Results r) {
|
||||||
|
// Get the island
|
||||||
|
Island island = addon.getIslands().getIsland(world, owner);
|
||||||
|
if (island == null)
|
||||||
|
return;
|
||||||
|
IslandLevels ld = levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new);
|
||||||
|
ld.setLevel(r.getLevel());
|
||||||
|
ld.setUwCount(Maps.asMap(r.getUwCount().elementSet(), elem -> r.getUwCount().count(elem)));
|
||||||
|
ld.setMdCount(Maps.asMap(r.getMdCount().elementSet(), elem -> r.getMdCount().count(elem)));
|
||||||
|
ld.setPointsToNextLevel(r.getPointsToNextLevel());
|
||||||
|
ld.setTotalPoints(r.getTotalPoints());
|
||||||
|
levelsCache.put(island.getUniqueId(), ld);
|
||||||
|
handler.saveObjectAsync(ld);
|
||||||
|
// Update TopTen
|
||||||
|
addToTopTen(world, owner, ld.getLevel());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the island level for the owner of the island that targetPlayer is a member
|
* Removes island from cache when it is deleted
|
||||||
* @param world - world
|
*
|
||||||
* @param owner - owner of the island
|
* @param uniqueId - id of island
|
||||||
* @param r - results of the calculation
|
*/
|
||||||
*/
|
public void deleteIsland(String uniqueId) {
|
||||||
private void setIslandResults(World world, @NonNull UUID owner, Results r) {
|
levelsCache.remove(uniqueId);
|
||||||
// Get the island
|
handler.deleteID(uniqueId);
|
||||||
Island island = addon.getIslands().getIsland(world, owner);
|
}
|
||||||
if (island == null) return;
|
|
||||||
IslandLevels ld = levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new);
|
|
||||||
ld.setLevel(r.getLevel());
|
|
||||||
ld.setUwCount(Maps.asMap(r.getUwCount().elementSet(), elem -> r.getUwCount().count(elem)));
|
|
||||||
ld.setMdCount(Maps.asMap(r.getMdCount().elementSet(), elem -> r.getMdCount().count(elem)));
|
|
||||||
ld.setPointsToNextLevel(r.getPointsToNextLevel());
|
|
||||||
ld.setTotalPoints(r.getTotalPoints());
|
|
||||||
levelsCache.put(island.getUniqueId(), ld);
|
|
||||||
handler.saveObjectAsync(ld);
|
|
||||||
// Update TopTen
|
|
||||||
addToTopTen(world, owner, ld.getLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes island from cache when it is deleted
|
|
||||||
* @param uniqueId - id of island
|
|
||||||
*/
|
|
||||||
public void deleteIsland(String uniqueId) {
|
|
||||||
levelsCache.remove(uniqueId);
|
|
||||||
handler.deleteID(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