Version 2.1.0 update - More Customization

This update brings more customization options, couple bugfixes and extra
slice to the player composition pie that tells how many players have
only joined once, but never returned (previously counted as inactive).

In more detail:
Added "Unknown" slice to the Player Composition Pie (Players who have
joined only once)
ServerData and UserData now saved with seperate timers to avoid loss of
player activity data with less dense cache saves.
Added possibility to turn off the WebServer.
- API will return HTML without webserver if the server is off.
- If AlternativeIP is in use, all commands will use that as link,
otherwise:
- Analysis & Search commands are disabled if the webserver is off.
- If PlanLite is installed and is used as alternative UI (config),
Inspect command is passed to PlanLite.
Added possibility to use PlanLite as an alternative UI.
- Use /plan lite inspect <player> to view the data in the chatbox.
- Graphs, piecharts & list available only on the web UI.
- Analysis not yet available in PlanLite UI.
Added possibility to change all colors of the Web UI and command
messages.
- Changes in the color settings require plugin restart, fix for this in
the future.
- Web UI Colors use the HTML Color Codes without the # (hashtag)
Added possibility to translate & add/remove Demographics triggers
Bugfixes:
- Fixed ConcurrentModificationException when data is being cleared after
a save.
- Attempted fix of PlanLite balance analysis by rewriting a formatting
utility method.
This commit is contained in:
Rsl1122 2017-01-19 12:01:18 +02:00
parent cda0148380
commit 0dfb2570e8
25 changed files with 408 additions and 166 deletions

View File

@ -1,6 +1,7 @@
package com.djrapitops.plan; package com.djrapitops.plan;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/** /**
* *
@ -13,13 +14,26 @@ public enum Phrase {
USERNAME_NOT_VALID(ChatColor.RED + "This Player doesn't exist."), USERNAME_NOT_VALID(ChatColor.RED + "This Player doesn't exist."),
USERNAME_NOT_SEEN(ChatColor.RED + "This Player has not played on this server."), USERNAME_NOT_SEEN(ChatColor.RED + "This Player has not played on this server."),
USERNAME_NOT_KNOWN(ChatColor.RED + "Player not found from the database."), USERNAME_NOT_KNOWN(ChatColor.RED + "Player not found from the database."),
COLOR_MAIN(ChatColor.DARK_GREEN), COLOR_MAIN(ChatColor.getByChar(getPlugin(Plan.class).getConfig().getString("Customization.Colors.Commands.Main").charAt(1))),
COLOR_SEC(ChatColor.GRAY), COLOR_SEC(ChatColor.getByChar(getPlugin(Plan.class).getConfig().getString("Customization.Colors.Commands.Secondary").charAt(1))),
COLOR_TER(ChatColor.WHITE), COLOR_TER(ChatColor.getByChar(getPlugin(Plan.class).getConfig().getString("Customization.Colors.Commands.Highlight").charAt(1))),
HCOLOR_ACT_ONL(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.ActivityGraph.OnlinePlayers")),
HCOLOR_ACT_NEW(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.ActivityGraph.NewPlayers")),
HCOLOR_GMP_0(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.GamemodePie.Survival")),
HCOLOR_GMP_1(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.GamemodePie.Creative")),
HCOLOR_GMP_2(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.GamemodePie.Adventure")),
HCOLOR_GMP_3(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.GamemodePie.Spectator")),
HCOLOR_ACTP_ACT(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.ActivityPie.Active")),
HCOLOR_ACTP_BAN(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.ActivityPie.Banned")),
HCOLOR_ACTP_INA(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.ActivityPie.Inactive")),
HCOLOR_ACTP_JON(getPlugin(Plan.class).getConfig().getString("Customization.Colors.HTML.ActivityPie.JoinedOnce")),
ARROWS_RIGHT("»"), ARROWS_RIGHT("»"),
BALL(""), BALL(""),
ERROR_PLANLITE("PlanLite not found, if you're have plugins using PlanAPI v1.6.0 download PlanLite."), ERROR_PLANLITE("PlanLite not found, if you're have plugins using PlanAPI v1.6.0 download PlanLite."),
ERROR_NO_USERNAME("INSPECT-GETNAME\nNo username given, returned empty username.\n"), ERROR_NO_DATA_VIEW(ChatColor.YELLOW + "Webserver disabled but Alternative IP/PlanLite not used, no way to view data!"),
ERROR_WEBSERVER_OFF_ANALYSIS(ChatColor.YELLOW + "[Plan] This command can be only used if the webserver is running on this server."),
ERROR_WEBSERVER_OFF_INSPECT(ChatColor.YELLOW + "[Plan] This command can be only used if webserver/planlite is enabled on this server."),
COMMAND_SENDER_NOT_PLAYER(ChatColor.RED + "[Plan] This command can be only used as a player."), COMMAND_SENDER_NOT_PLAYER(ChatColor.RED + "[Plan] This command can be only used as a player."),
COMMAND_REQUIRES_ARGUMENTS(ChatColor.RED + "[Plan] Command requires arguments."), COMMAND_REQUIRES_ARGUMENTS(ChatColor.RED + "[Plan] Command requires arguments."),
COMMAND_REQUIRES_ARGUMENTS_ONE(ChatColor.RED + "[Plan] Command requires one argument."), COMMAND_REQUIRES_ARGUMENTS_ONE(ChatColor.RED + "[Plan] Command requires one argument."),

View File

@ -20,6 +20,31 @@ import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
/* TODO 2.1.0
Placeholder API
Html getter without webserver
Webserver off setting
Immutable InspectCache ?
Join-leavers to activity pie.
Recent players
Customizability
Colors, chat, analysis
Demographics triggers
Optimize db with batch processing (commanduse, ips, nicks)
Manage command
Database cleaning
Server & user data saved seperately with different times
Alternative ip & webserver off check warning, check for PlanLite too.
Fix PlanLite balance.
PlanLite Top 20 richest
PlanLite Top 20 most votes
Top 20 most active
Clear setting multiper (InspectCache)
Clear check for existing clear task. (InspectCache)
ErrorManager
(Alternative ui) ? Push data to PlanLite (setting)
DataBase init message
*/
public class Plan extends JavaPlugin { public class Plan extends JavaPlugin {
private API api; private API api;
@ -61,7 +86,9 @@ public class Plan extends JavaPlugin {
saveConfig(); saveConfig();
log("Database init..");
initDatabase(); initDatabase();
log("Database initiated.");
hookPlanLite(); hookPlanLite();
this.handler = new DataCacheHandler(this); this.handler = new DataCacheHandler(this);
@ -76,11 +103,9 @@ public class Plan extends JavaPlugin {
this.api = new API(this); this.api = new API(this);
handler.handleReload(); handler.handleReload();
if (getConfig().getBoolean("Settings.WebServer.Enabled")) {
uiServer = new WebSocketServer(this); uiServer = new WebSocketServer(this);
uiServer.initServer(); uiServer.initServer();
log("Player Analytics Enabled.");
if (getConfig().getBoolean("Settings.Cache.AnalysisCache.RefreshAnalysisCacheOnEnable")) { if (getConfig().getBoolean("Settings.Cache.AnalysisCache.RefreshAnalysisCacheOnEnable")) {
log("Analysis | Boot analysis in 30 seconds.."); log("Analysis | Boot analysis in 30 seconds..");
(new BukkitRunnable() { (new BukkitRunnable() {
@ -92,6 +117,13 @@ public class Plan extends JavaPlugin {
} }
}).runTaskLater(this, 30 * 20); }).runTaskLater(this, 30 * 20);
} }
} else if (!(getConfig().getBoolean("Settings.WebServer.ShowAlternativeServerIP")
|| (getConfig().getBoolean("Settings.PlanLite.UseAsAlternativeUI")
&& planLiteHook.isEnabled()))) {
Bukkit.getServer().getConsoleSender().sendMessage("[Plan] "
+ Phrase.ERROR_NO_DATA_VIEW);
}
log("Player Analytics Enabled.");
} }
public void hookPlanLite() { public void hookPlanLite() {
@ -106,13 +138,15 @@ public class Plan extends JavaPlugin {
public void onDisable() { public void onDisable() {
uiServer.stop(); uiServer.stop();
Bukkit.getScheduler().cancelTasks(this); Bukkit.getScheduler().cancelTasks(this);
if (handler != null) {
log("Saving cached data.."); log("Saving cached data..");
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.execute(() -> { scheduler.execute(() -> {
handler.saveCacheOnDisable(); handler.saveCacheOnDisable();
}); });
scheduler.shutdown();
scheduler.shutdown();
}
log("Player Analytics Disabled."); log("Player Analytics Disabled.");
} }

View File

@ -1,20 +1,28 @@
package com.djrapitops.plan; package com.djrapitops.plan;
import com.djrapitops.plan.data.UserData;
import com.djrapitops.plan.data.cache.InspectCacheHandler;
import com.djrapitops.plan.utilities.AnalysisUtils;
import com.djrapitops.planlite.PlanLite; import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.API; import com.djrapitops.planlite.api.API;
import com.djrapitops.planlite.api.DataPoint; import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import com.djrapitops.planlite.api.Hook;
import java.util.HashMap; import java.util.HashMap;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin; import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/** /**
* *
* @author Rsl1122 * @author Rsl1122
*/ */
public class PlanLiteHook { public class PlanLiteHook implements Hook{
private PlanLite planLite; private PlanLite planLite;
private Plan plugin; private Plan plugin;
@ -31,7 +39,8 @@ public class PlanLiteHook {
*/ */
public PlanLiteHook(Plan plugin) { public PlanLiteHook(Plan plugin) {
this.plugin = plugin; this.plugin = plugin;
if (plugin.getConfig().getBoolean("Settings.PlanLite.Enabled")) { FileConfiguration config = plugin.getConfig();
if (config.getBoolean("Settings.PlanLite.Enabled")) {
if (Bukkit.getPluginManager().isPluginEnabled("PlanLite")) { if (Bukkit.getPluginManager().isPluginEnabled("PlanLite")) {
try { try {
this.planLite = getPlugin(PlanLite.class); this.planLite = getPlugin(PlanLite.class);
@ -40,6 +49,9 @@ public class PlanLiteHook {
} }
enabled = true; enabled = true;
planLiteApi = planLite.getAPI(); planLiteApi = planLite.getAPI();
if (config.getBoolean("Settings.PlanLite.UseAsAlternativeUI")) {
planLite.addExtraHook("Plan", this);
}
} catch (Exception e) { } catch (Exception e) {
} }
} else { } else {
@ -85,4 +97,31 @@ public class PlanLiteHook {
public boolean hasVault() { public boolean hasVault() {
return getEnabledHooksNames().contains("Vault"); return getEnabledHooksNames().contains("Vault");
} }
@Override
public HashMap<String, DataPoint> getData(String playername) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
UUID uuid = UUIDFetcher.getUUIDOf(playername);
if (uuid != null) {
InspectCacheHandler inspectCache = plugin.getInspectCache();
inspectCache.cache(uuid);
UserData uData = inspectCache.getFromCache(uuid);
HashMap<String, String> userData = AnalysisUtils.getInspectReplaceRules(uData);
for (String key : userData.keySet()) {
if (key.equals("%planlite%") || key.equals("%gmpiechart%")) {
continue;
}
data.put("PLA-"+key.toUpperCase().substring(1, key.length()-1), new DataPoint(userData.get(key), DataType.OTHER));
}
}
} catch (Exception e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String playername) throws Exception {
return getData(playername);
}
} }

View File

@ -4,10 +4,12 @@ import com.djrapitops.plan.Plan;
import com.djrapitops.plan.PlanLiteHook; import com.djrapitops.plan.PlanLiteHook;
import com.djrapitops.plan.data.AnalysisData; import com.djrapitops.plan.data.AnalysisData;
import com.djrapitops.plan.data.UserData; import com.djrapitops.plan.data.UserData;
import com.djrapitops.plan.ui.DataRequestHandler;
import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.FormatUtils;
import com.djrapitops.planlite.UUIDFetcher; import com.djrapitops.planlite.UUIDFetcher;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer;
/** /**
* *
@ -98,6 +100,8 @@ public class API {
* Returns the ip:port/player/playername html as a string so it can be * Returns the ip:port/player/playername html as a string so it can be
* integrated into other webserver plugins. * integrated into other webserver plugins.
* *
* Should use cacheUserDataToInspectCache(UUID uuid) before using this method.
*
* If UserData of the specified player is not in the Cache returns <h1>404 * If UserData of the specified player is not in the Cache returns <h1>404
* Data was not found in cache</h1> * Data was not found in cache</h1>
* *
@ -105,7 +109,12 @@ public class API {
* @return html as a string or a single error line html. * @return html as a string or a single error line html.
*/ */
public String getPlayerHtmlAsString(UUID uuid) { public String getPlayerHtmlAsString(UUID uuid) {
return plugin.getUiServer().getDataReqHandler().getDataHtml(uuid); WebSocketServer server = plugin.getUiServer();
if (server != null) {
return server.getDataReqHandler().getDataHtml(uuid);
}
DataRequestHandler reqH = new DataRequestHandler(plugin);
return reqH.getDataHtml(uuid);
} }
/** /**
@ -120,13 +129,20 @@ public class API {
* Returns the ip:port/server html as a string so it can be integrated into * Returns the ip:port/server html as a string so it can be integrated into
* other webserver plugins. * other webserver plugins.
* *
* Should use updateAnalysisCache() before using this method.
*
* If AnalysisData is not in the AnalysisCache: returns <h1>404 Data was not * If AnalysisData is not in the AnalysisCache: returns <h1>404 Data was not
* found in cache</h1> * found in cache</h1>
* *
* @return html as a string or a single error line html. * @return html as a string or a single error line html.
*/ */
public String getAnalysisHtmlAsString() { public String getAnalysisHtmlAsString() {
return plugin.getUiServer().getDataReqHandler().getAnalysisHtml(); WebSocketServer server = plugin.getUiServer();
if (server != null) {
return server.getDataReqHandler().getAnalysisHtml();
}
DataRequestHandler reqH = new DataRequestHandler(plugin);
return reqH.getAnalysisHtml();
} }
/** /**
@ -141,6 +157,7 @@ public class API {
/** /**
* Returns AnalysisData from the AnalysisCache * Returns AnalysisData from the AnalysisCache
*
* @return AnalysisData in the AnalysisCache or null if not found * @return AnalysisData in the AnalysisCache or null if not found
*/ */
public AnalysisData getAnalysisDataFromCache() { public AnalysisData getAnalysisDataFromCache() {

View File

@ -9,6 +9,7 @@ import java.util.Date;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -48,22 +49,41 @@ public class AnalyzeCommand extends SubCommand {
*/ */
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
FileConfiguration config = plugin.getConfig();
if (!config.getBoolean("Settings.WebServer.Enabled")) {
if (!config.getBoolean("Settings.WebServer.ShowAlternativeServerIP")) {
sender.sendMessage(Phrase.ERROR_WEBSERVER_OFF_ANALYSIS.toString());
return true;
} else {
sendAnalysisMessage(sender, config);
return true;
}
}
if (!analysisCache.isCached()) { if (!analysisCache.isCached()) {
analysisCache.updateCache(); analysisCache.updateCache();
} else if (new Date().getTime() - analysisCache.getData().getRefreshDate() > 60000) { } else if (new Date().getTime() - analysisCache.getData().getRefreshDate() > 60000) {
analysisCache.updateCache(); analysisCache.updateCache();
} }
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
FileConfiguration config = plugin.getConfig();
final boolean useAlternativeIP = config.getBoolean("Settings.WebServer.ShowAlternativeServerIP");
final int port = config.getInt("Settings.WebServer.Port");
final String alternativeIP = config.getString("Settings.WebServer.AlternativeIP").replaceAll("%port%", "" + port);
(new BukkitRunnable() { (new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
if (analysisCache.isCached()) { if (analysisCache.isCached()) {
sendAnalysisMessage(sender, config);
this.cancel();
}
}
}).runTaskTimer(plugin, 1 * 20, 5 * 20);
return true;
}
public void sendAnalysisMessage(CommandSender sender, FileConfiguration config) throws CommandException {
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
final boolean useAlternativeIP = config.getBoolean("Settings.WebServer.ShowAlternativeServerIP");
final int port = config.getInt("Settings.WebServer.Port");
final String alternativeIP = config.getString("Settings.WebServer.AlternativeIP").replaceAll("%port%", "" + port);
// Header // Header
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor
+ " Player Analytics - Analysis results"); + " Player Analytics - Analysis results");
@ -84,10 +104,5 @@ public class AnalyzeCommand extends SubCommand {
} }
// Footer // Footer
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString()); sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
this.cancel();
}
}
}).runTaskTimer(plugin, 1 * 20, 5 * 20);
return true;
} }
} }

View File

@ -26,9 +26,9 @@ public class InfoCommand extends SubCommand {
ChatColor hColor = Phrase.COLOR_TER.color(); ChatColor hColor = Phrase.COLOR_TER.color();
String[] messages = { String[] messages = {
hColor + Phrase.ARROWS_RIGHT.toString() + oColor + "Player Analytics - Info", hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics - Info",
tColor + " " + Phrase.BALL.toString() + oColor + "Version: " + tColor + plugin.getDescription().getVersion(), tColor + " " + Phrase.BALL.toString() + oColor + " Version: " + tColor + plugin.getDescription().getVersion(),
tColor + " " + Phrase.BALL.toString() + tColor + MiscUtils.checkVersion(), tColor + " " + Phrase.BALL.toString() + tColor +" "+ MiscUtils.checkVersion(),
hColor + Phrase.ARROWS_RIGHT.toString() hColor + Phrase.ARROWS_RIGHT.toString()
}; };
sender.sendMessage(messages); sender.sendMessage(messages);

View File

@ -2,13 +2,13 @@ package com.djrapitops.plan.command.commands;
import com.djrapitops.plan.Phrase; import com.djrapitops.plan.Phrase;
import com.djrapitops.plan.Plan; import com.djrapitops.plan.Plan;
import com.djrapitops.plan.PlanLiteHook;
import com.djrapitops.plan.utilities.UUIDFetcher; import com.djrapitops.plan.utilities.UUIDFetcher;
import com.djrapitops.plan.command.CommandType; import com.djrapitops.plan.command.CommandType;
import com.djrapitops.plan.command.SubCommand; import com.djrapitops.plan.command.SubCommand;
import java.util.Date; import java.util.Date;
import com.djrapitops.plan.data.cache.InspectCacheHandler; import com.djrapitops.plan.data.cache.InspectCacheHandler;
import com.djrapitops.plan.utilities.FormatUtils;
import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plan.utilities.MiscUtils;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -58,6 +58,19 @@ public class InspectCommand extends SubCommand {
*/ */
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
FileConfiguration config = plugin.getConfig();
if (!config.getBoolean("Settings.WebServer.Enabled")) {
if (!config.getBoolean("Settings.WebServer.ShowAlternativeServerIP")) {
PlanLiteHook planLiteHook = plugin.getPlanLiteHook();
if (config.getBoolean("Settings.PlanLite.UseAsAlternativeUI") && planLiteHook.isEnabled()) {
sender.sendMessage(ChatColor.YELLOW + "[Plan] Passing to PlanLite..");
planLiteHook.passCommand(sender, cmd, commandLabel, args);
} else {
sender.sendMessage(Phrase.ERROR_WEBSERVER_OFF_INSPECT.toString());
}
return true;
}
}
String playerName = MiscUtils.getPlayerDisplayname(args, sender); String playerName = MiscUtils.getPlayerDisplayname(args, sender);
UUID uuid; UUID uuid;
@ -80,12 +93,10 @@ public class InspectCommand extends SubCommand {
return true; return true;
} }
Date refreshDate = new Date();
inspectCache.cache(uuid); inspectCache.cache(uuid);
ChatColor oColor = Phrase.COLOR_MAIN.color(); ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color(); ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color(); ChatColor hColor = Phrase.COLOR_TER.color();
FileConfiguration config = plugin.getConfig();
final boolean useAlternativeIP = config.getBoolean("Settings.WebServer.ShowAlternativeServerIP"); final boolean useAlternativeIP = config.getBoolean("Settings.WebServer.ShowAlternativeServerIP");
final int port = config.getInt("Settings.WebServer.Port"); final int port = config.getInt("Settings.WebServer.Port");

View File

@ -26,5 +26,4 @@ public class LiteCommand extends SubCommand {
} }
return false; return false;
} }
} }

View File

@ -21,7 +21,7 @@ public class ReloadCommand extends SubCommand {
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
plugin.reloadConfig(); plugin.reloadConfig();
plugin.getHandler().saveCachedData(); plugin.getHandler().saveCachedUserData();
plugin.hookPlanLite(); plugin.hookPlanLite();
sender.sendMessage(ChatColor.GREEN + "[Plan] Reload complete."); sender.sendMessage(ChatColor.GREEN + "[Plan] Reload complete.");

View File

@ -52,8 +52,13 @@ public class SearchCommand extends SubCommand {
*/ */
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (!plugin.getConfig().getBoolean("Settings.WebServer.Enabled")) {
sender.sendMessage(Phrase.ERROR_WEBSERVER_OFF_ANALYSIS.toString());
return true;
}
if (args.length != 1) { if (args.length != 1) {
sender.sendMessage(Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE.toString()); sender.sendMessage(Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE.toString());
return true;
} }
ChatColor oColor = Phrase.COLOR_MAIN.color(); ChatColor oColor = Phrase.COLOR_MAIN.color();

View File

@ -28,6 +28,7 @@ public class AnalysisData {
private int banned; private int banned;
private int active; private int active;
private int inactive; private int inactive;
private int joinleaver;
private int total; private int total;
private int totalPlayers; private int totalPlayers;
@ -42,6 +43,14 @@ public class AnalysisData {
// Getters and setters v---------------------------------v // Getters and setters v---------------------------------v
public int getJoinleaver() {
return joinleaver;
}
public void setJoinleaver(int joinleaver) {
this.joinleaver = joinleaver;
}
public boolean isPlanLiteEnabled() { public boolean isPlanLiteEnabled() {
return planLiteEnabled; return planLiteEnabled;
} }

View File

@ -6,12 +6,13 @@ import com.djrapitops.plan.data.*;
import com.djrapitops.plan.data.handlers.*; import com.djrapitops.plan.data.handlers.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import static org.bukkit.Bukkit.getPlayer; import static org.bukkit.Bukkit.getPlayer;
import static org.bukkit.Bukkit.getPlayer;
/** /**
* *
@ -66,6 +67,10 @@ public class DataCacheHandler {
if (minutes <= 0) { if (minutes <= 0) {
minutes = 5; minutes = 5;
} }
int sMinutes = plugin.getConfig().getInt("Settings.Cache.DataCache.SaveServerDataEveryXMinutes");
if (sMinutes <= 0) {
sMinutes = 5;
}
final int clearAfterXsaves; final int clearAfterXsaves;
int configValue = plugin.getConfig().getInt("Settings.Cache.DataCache.ClearCacheEveryXSaves"); int configValue = plugin.getConfig().getInt("Settings.Cache.DataCache.ClearCacheEveryXSaves");
if (configValue <= 1) { if (configValue <= 1) {
@ -78,13 +83,21 @@ public class DataCacheHandler {
public void run() { public void run() {
DataCacheHandler handler = plugin.getHandler(); DataCacheHandler handler = plugin.getHandler();
handler.saveHandlerDataToCache(); handler.saveHandlerDataToCache();
handler.saveCachedData(); handler.saveCachedUserData();
if (timesSaved % clearAfterXsaves == 0) { if (timesSaved % clearAfterXsaves == 0) {
handler.clearCache(); handler.clearCache();
} }
handler.clearNulls();
timesSaved++; timesSaved++;
} }
}).runTaskTimerAsynchronously(plugin, 60 * 20 * minutes, 60 * 20 * minutes); }).runTaskTimerAsynchronously(plugin, 60 * 20 * minutes, 60 * 20 * minutes);
(new BukkitRunnable() {
@Override
public void run() {
serverData.updatePlayerCount();
saveServerData();
}
}).runTaskTimerAsynchronously(plugin, 60 * 20 * sMinutes, 60 * 20 * sMinutes);
} }
/** /**
@ -134,12 +147,10 @@ public class DataCacheHandler {
/** /**
* Saves all data in the cache to Database with AsyncTasks * Saves all data in the cache to Database with AsyncTasks
*/ */
public void saveCachedData() { public void saveCachedUserData() {
dataCache.keySet().stream().forEach((uuid) -> { dataCache.keySet().stream().forEach((uuid) -> {
saveCachedData(uuid); saveCachedData(uuid);
}); });
serverData.updatePlayerCount();
saveServerData();
timesSaved++; timesSaved++;
} }
@ -219,10 +230,9 @@ public class DataCacheHandler {
* Clears all UserData from the HashMap * Clears all UserData from the HashMap
*/ */
public void clearCache() { public void clearCache() {
Set<UUID> uuidSet = dataCache.keySet(); Iterator<Map.Entry<UUID, UserData>> clearIterator = dataCache.entrySet().iterator();
Iterator<UUID> uuidIterator = uuidSet.iterator(); while (clearIterator.hasNext()) {
while (uuidIterator.hasNext()) { clearFromCache(clearIterator.next());
clearFromCache(uuidIterator.next());
} }
} }
@ -251,6 +261,36 @@ public class DataCacheHandler {
} }
} }
/**
* Setting entry value to null, clearing it from memory.
*
* This method is used to avoid ConcurrentModificationException when
* clearing the cache.
*
* @param entry An entry from the cache HashMap that is being iterated over.
*/
public void clearFromCache(Map.Entry<UUID, UserData> entry) {
if (entry != null) {
if (entry.getValue() != null) {
if (entry.getValue().isAccessed()) {
(new BukkitRunnable() {
@Override
public void run() {
if (entry.getValue().isAccessed()) {
entry.setValue(null);
plugin.log("Cleared " + entry.getKey().toString() + " from Cache. (Delay task)");
this.cancel();
}
}
}).runTaskTimer(plugin, 30 * 20, 30 * 20);
} else {
entry.setValue(null);
plugin.log("Cleared " + entry.getKey().toString() + " from Cache.");
}
}
}
}
/** /**
* Creates a new UserData instance and saves it to the Database * Creates a new UserData instance and saves it to the Database
* *
@ -371,4 +411,13 @@ public class DataCacheHandler {
public int getMaxPlayers() { public int getMaxPlayers() {
return maxPlayers; return maxPlayers;
} }
private void clearNulls() {
Iterator<UUID> clearIterator = dataCache.keySet().iterator();
while (clearIterator.hasNext()) {
if (dataCache.get(clearIterator.next()) == null) {
clearIterator.remove();
}
}
}
} }

View File

@ -21,6 +21,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
public class DemographicsHandler { public class DemographicsHandler {
private final DataCacheHandler handler; private final DataCacheHandler handler;
private final Plan plugin;
/** /**
* Class Constructor * Class Constructor
@ -30,6 +31,7 @@ public class DemographicsHandler {
*/ */
public DemographicsHandler(Plan plugin, DataCacheHandler h) { public DemographicsHandler(Plan plugin, DataCacheHandler h) {
this.handler = h; this.handler = h;
this.plugin = plugin;
} }
/** /**
@ -42,10 +44,10 @@ public class DemographicsHandler {
* @param data UserData corresponding to player of this event. * @param data UserData corresponding to player of this event.
*/ */
public void handleChatEvent(AsyncPlayerChatEvent event, UserData data) { public void handleChatEvent(AsyncPlayerChatEvent event, UserData data) {
List<String> triggers = Arrays.asList("i\'m", "am", "im"); List<String> triggers = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.Trigger").split(", "));
List<String> female = Arrays.asList("female", "girl", "gurl", "woman", "gal", "mrs", "she", "miss"); List<String> female = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.Female").split(", "));
List<String> male = Arrays.asList("male", "boy", "man", "boe", "sir", "mr", "guy", "he"); List<String> male = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.Male").split(", "));
List<String> ignore = Arrays.asList("sure", "think", "with", "are"); List<String> ignore = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.IgnoreWhen").split(", "));
String message = event.getMessage(); String message = event.getMessage();
String[] messageA = message.toLowerCase().split("\\s+"); String[] messageA = message.toLowerCase().split("\\s+");

View File

@ -9,6 +9,7 @@ import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import static org.bukkit.Bukkit.getOfflinePlayer;
/** /**
* *

View File

@ -44,9 +44,20 @@ public class PlanLiteHandler {
return; return;
} }
Set<String> enabledHooks = hook.getEnabledHooksNames(); Set<String> enabledHooks = hook.getEnabledHooksNames();
HashMap<String, DataPoint> liteData = hook.getAllData(playerName, true);
PlanLitePlayerData plData = new PlanLitePlayerData(); PlanLitePlayerData plData = new PlanLitePlayerData();
// Avoiding StackOverFlow
if (plugin.getConfig().getBoolean("Settings.PlanLite.UseAsAlternativeUI")
&& plugin.getPlanLiteHook().isEnabled()) {
data.setPlanLiteFound(false);
plData.setTowny(false);
plData.setFactions(false);
plData.setSuperbVote(false);
plData.setVault(false);
data.setPlanLiteData(plData);
} else {
HashMap<String, DataPoint> liteData = hook.getAllData(playerName, true);
plData.setTowny(enabledHooks.contains("Towny")); plData.setTowny(enabledHooks.contains("Towny"));
plData.setFactions(enabledHooks.contains("Factions")); plData.setFactions(enabledHooks.contains("Factions"));
plData.setSuperbVote(enabledHooks.contains("SuperbVote")); plData.setSuperbVote(enabledHooks.contains("SuperbVote"));
@ -82,4 +93,5 @@ public class PlanLiteHandler {
data.setPlanLiteFound(true); data.setPlanLiteFound(true);
data.setPlanLiteData(plData); data.setPlanLiteData(plData);
} }
}
} }

View File

@ -1,5 +1,6 @@
package main.java.com.djrapitops.plan.ui.graphs; package main.java.com.djrapitops.plan.ui.graphs;
import com.djrapitops.plan.Phrase;
import com.googlecode.charts4j.Color; import com.googlecode.charts4j.Color;
import com.googlecode.charts4j.GCharts; import com.googlecode.charts4j.GCharts;
import com.googlecode.charts4j.PieChart; import com.googlecode.charts4j.PieChart;
@ -17,27 +18,30 @@ public class ActivityPieChartCreator {
* @param totalBanned Number of Banned Players * @param totalBanned Number of Banned Players
* @param active Number of Active Players * @param active Number of Active Players
* @param inactive Number of Inactive Players * @param inactive Number of Inactive Players
* @param joinleaver Number of players who have joined only once
* @return Url to Image link. * @return Url to Image link.
*/ */
public static String createChart(int totalBanned, int active, int inactive) { public static String createChart(int totalBanned, int active, int inactive, int joinleaver) {
int total = totalBanned + active + inactive; int total = totalBanned + active + inactive;
int banPerc = (int) ((totalBanned * 1.0 / total) * 100); int banPerc = (int) ((totalBanned * 1.0 / total) * 100);
int inacPerc = (int) ((inactive * 1.0 / total) * 100); int inacPerc = (int) ((inactive * 1.0 / total) * 100);
int actPerc = (int) ((active * 1.0 / total) * 100); int actPerc = (int) ((active * 1.0 / total) * 100);
while (banPerc + inacPerc + actPerc < 100) { int joinlPerc = (int) ((joinleaver * 1.0 / total) * 100);
while (banPerc + inacPerc + actPerc + joinlPerc < 100) {
actPerc++; actPerc++;
} }
while (banPerc + inacPerc + actPerc > 100) { while (banPerc + inacPerc + actPerc + joinlPerc > 100) {
actPerc--; actPerc--;
} }
Slice s1 = Slice.newSlice((int) (banPerc), Color.newColor("951800"), "Banned", "Banned"); Slice bannedSlice = Slice.newSlice((int) (banPerc), Color.newColor(Phrase.HCOLOR_ACTP_BAN+""), "Banned", "Banned");
Slice s3 = Slice.newSlice((int) (inacPerc), Color.newColor("A9A9A9"), "Inactive", "Inactive"); Slice joinLeaverSlice = Slice.newSlice((int) (joinlPerc), Color.newColor(Phrase.HCOLOR_ACTP_JON+""), "Unknown", "Unknown");
Slice s4 = Slice.newSlice((int) (actPerc), Color.newColor("228B22"), "Active", "Active"); Slice inactiveSlice = Slice.newSlice((int) (inacPerc), Color.newColor(Phrase.HCOLOR_ACTP_INA+""), "Inactive", "Inactive");
Slice activeSlice = Slice.newSlice((int) (actPerc), Color.newColor(Phrase.HCOLOR_ACTP_ACT+""), "Active", "Active");
PieChart refChart = GCharts.newPieChart(s4, s3, s1); PieChart refChart = GCharts.newPieChart(activeSlice, bannedSlice, inactiveSlice, joinLeaverSlice);
refChart.setSize(400, 150); refChart.setSize(400, 150);
refChart.setThreeD(true); refChart.setThreeD(true);
String refURL = refChart.toURLString(); String refURL = refChart.toURLString();

View File

@ -1,5 +1,6 @@
package com.djrapitops.plan.ui.graphs; package com.djrapitops.plan.ui.graphs;
import com.djrapitops.plan.Phrase;
import com.googlecode.charts4j.Color; import com.googlecode.charts4j.Color;
import com.googlecode.charts4j.GCharts; import com.googlecode.charts4j.GCharts;
import com.googlecode.charts4j.PieChart; import com.googlecode.charts4j.PieChart;
@ -53,10 +54,10 @@ public class GMTimesPieChartCreator {
one--; one--;
} }
Slice s1 = Slice.newSlice(zero, Color.newColor("951800"), "Survival", "Survival"); Slice s1 = Slice.newSlice(zero, Color.newColor(Phrase.HCOLOR_GMP_0 + ""), "Survival", "Survival");
Slice s2 = Slice.newSlice(one, Color.newColor("01A1DB"), "Creative", "Creative"); Slice s2 = Slice.newSlice(one, Color.newColor(Phrase.HCOLOR_GMP_1+""), "Creative", "Creative");
Slice s3 = Slice.newSlice(two, Color.newColor("FFFF33"), "Adventure", "Adventure"); Slice s3 = Slice.newSlice(two, Color.newColor(Phrase.HCOLOR_GMP_2+""), "Adventure", "Adventure");
Slice s4 = Slice.newSlice(three, Color.newColor("228B22"), "Spectator", "Spectator"); Slice s4 = Slice.newSlice(three, Color.newColor(Phrase.HCOLOR_GMP_3+""), "Spectator", "Spectator");
PieChart refChart = GCharts.newPieChart(s1, s2, s3, s4); PieChart refChart = GCharts.newPieChart(s1, s2, s3, s4);
refChart.setSize(400, 150); refChart.setSize(400, 150);

View File

@ -1,5 +1,6 @@
package main.java.com.djrapitops.plan.ui.graphs; package main.java.com.djrapitops.plan.ui.graphs;
import com.djrapitops.plan.Phrase;
import com.djrapitops.plan.Plan; import com.djrapitops.plan.Plan;
import com.djrapitops.plan.data.ServerData; import com.djrapitops.plan.data.ServerData;
import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.FormatUtils;
@ -84,8 +85,8 @@ public class PlayerActivityGraphCreator {
Data pYData = Data.newData(pYList); Data pYData = Data.newData(pYList);
Data nYData = Data.newData(nYList); Data nYData = Data.newData(nYList);
XYLine playerLine = Plots.newXYLine(xData, pYData, Color.BLUE, "Online Players"); XYLine playerLine = Plots.newXYLine(xData, pYData, Color.newColor(Phrase.HCOLOR_ACT_ONL + ""), "Online Players");
XYLine newPlayerLine = Plots.newXYLine(xData, nYData, Color.GREEN, "New Players"); XYLine newPlayerLine = Plots.newXYLine(xData, nYData, Color.newColor(Phrase.HCOLOR_ACT_NEW + ""), "New Players");
LineChart chart = GCharts.newLineChart(playerLine, newPlayerLine); LineChart chart = GCharts.newLineChart(playerLine, newPlayerLine);
chart.addXAxisLabels(xAxisLabels); chart.addXAxisLabels(xAxisLabels);
chart.addTopAxisLabels(AxisLabelsFactory.newAxisLabels("Players", 1)); chart.addTopAxisLabels(AxisLabelsFactory.newAxisLabels("Players", 1));

View File

@ -75,25 +75,23 @@ public class Analysis {
rawServerData = plugin.getDB().getServerDataHashMap(); rawServerData = plugin.getDB().getServerDataHashMap();
plugin.log("Analysis | Data Fetched, beginning Analysis of data.."); plugin.log("Analysis | Data Fetched, beginning Analysis of data..");
AnalysisData data = new AnalysisData(); AnalysisData data = new AnalysisData();
long scaleMonth = (long) 2592000 * (long) 1000;
String playerActivityHtmlMonth = AnalysisUtils.createPlayerActivityGraph(rawServerData, scaleMonth); createPlayerActivityGraphs(data);
data.setPlayersChartImgHtmlMonth(playerActivityHtmlMonth);
long scaleWeek = 604800 * 1000; // Create empty Dataset
String playerActivityHtmlWeek = AnalysisUtils.createPlayerActivityGraph(rawServerData, scaleWeek);
data.setPlayersChartImgHtmlWeek(playerActivityHtmlWeek);
long scaleDay = 86400 * 1000;
String playerActivityHtmlDay = AnalysisUtils.createPlayerActivityGraph(rawServerData, scaleDay);
data.setPlayersChartImgHtmlDay(playerActivityHtmlDay);
long gmZero = 0; long gmZero = 0;
long gmOne = 0; long gmOne = 0;
long gmTwo = 0; long gmTwo = 0;
long gmThree = 0; long gmThree = 0;
long totalPlaytime = 0;
int totalBanned = 0;
long totalLoginTimes = 0; long totalLoginTimes = 0;
long totalPlaytime = 0;
int totalBanned = 0;
int active = 0; int active = 0;
int joinleaver = 0;
int inactive = 0; int inactive = 0;
int ops = 0; int ops = 0;
List<Integer> ages = new ArrayList<>(); List<Integer> ages = new ArrayList<>();
@ -105,6 +103,7 @@ public class Analysis {
int totalVotes = 0; int totalVotes = 0;
int totalMoney = 0; int totalMoney = 0;
// Fill Dataset with userdata.
for (UserData uData : rawData) { for (UserData uData : rawData) {
if (planLiteEnabled) { if (planLiteEnabled) {
PlanLitePlayerData litePlayerData = uData.getPlanLiteData(); PlanLitePlayerData litePlayerData = uData.getPlanLiteData();
@ -138,12 +137,13 @@ public class Analysis {
if (uData.isBanned()) { if (uData.isBanned()) {
totalBanned++; totalBanned++;
} else if (uData.getLoginTimes() == 1) {
joinleaver++;
} else if (AnalysisUtils.isActive(uData.getLastPlayed(), uData.getPlayTime(), uData.getLoginTimes())) { } else if (AnalysisUtils.isActive(uData.getLastPlayed(), uData.getPlayTime(), uData.getLoginTimes())) {
active++; active++;
} else { } else {
inactive++; inactive++;
} }
} }
if (planLiteEnabled) { if (planLiteEnabled) {
@ -159,29 +159,30 @@ public class Analysis {
data.setTotalLoginTimes(totalLoginTimes); data.setTotalLoginTimes(totalLoginTimes);
String activityPieChartHtml = AnalysisUtils.createActivityPieChart(totalBanned, active, inactive); String activityPieChartHtml = AnalysisUtils.createActivityPieChart(totalBanned, active, inactive, joinleaver);
data.setActivityChartImgHtml(activityPieChartHtml); data.setActivityChartImgHtml(activityPieChartHtml);
data.setActive(active); data.setActive(active);
data.setInactive(inactive); data.setInactive(inactive);
data.setBanned(totalBanned); data.setBanned(totalBanned);
data.setTotal(offlinePlayers.length); data.setJoinleaver(joinleaver);
data.setTotal(offlinePlayers.length);
data.setOps(ops); data.setOps(ops);
data.setTotalPlayTime(totalPlaytime); data.setTotalPlayTime(totalPlaytime);
long averagePlaytime = totalPlaytime / rawData.size(); data.setAveragePlayTime(totalPlaytime / rawData.size());
data.setAveragePlayTime(averagePlaytime);
int totalAge = 0; int totalAge = 0;
for (int age : ages) { for (int age : ages) {
totalAge += age; totalAge += age;
} }
double averageAge; double averageAge;
if (ages.size() != 0) { if (!ages.isEmpty()) {
averageAge = totalAge * 1.0 / ages.size(); averageAge = totalAge * 1.0 / ages.size();
} else { } else {
averageAge = -1; averageAge = -1;
} }
data.setAverageAge(averageAge); data.setAverageAge(averageAge);
long gmTotal = gmZero + gmOne + gmTwo + gmThree; long gmTotal = gmZero + gmOne + gmTwo + gmThree;
HashMap<GameMode, Long> totalGmTimes = new HashMap<>(); HashMap<GameMode, Long> totalGmTimes = new HashMap<>();
totalGmTimes.put(GameMode.SURVIVAL, gmZero); totalGmTimes.put(GameMode.SURVIVAL, gmZero);
@ -213,6 +214,18 @@ public class Analysis {
plugin.log("Analysis | Analysis Complete."); plugin.log("Analysis | Analysis Complete.");
this.cancel(); this.cancel();
} }
private void createPlayerActivityGraphs(AnalysisData data) {
long scaleMonth = (long) 2592000 * (long) 1000;
String playerActivityHtmlMonth = AnalysisUtils.createPlayerActivityGraph(rawServerData, scaleMonth);
data.setPlayersChartImgHtmlMonth(playerActivityHtmlMonth);
long scaleWeek = 604800 * 1000;
String playerActivityHtmlWeek = AnalysisUtils.createPlayerActivityGraph(rawServerData, scaleWeek);
data.setPlayersChartImgHtmlWeek(playerActivityHtmlWeek);
long scaleDay = 86400 * 1000;
String playerActivityHtmlDay = AnalysisUtils.createPlayerActivityGraph(rawServerData, scaleDay);
data.setPlayersChartImgHtmlDay(playerActivityHtmlDay);
}
}).runTaskAsynchronously(plugin); }).runTaskAsynchronously(plugin);
} }
} }

View File

@ -91,6 +91,7 @@ public class AnalysisUtils {
replaceMap.put("%active%", "" + data.getActive()); replaceMap.put("%active%", "" + data.getActive());
replaceMap.put("%banned%", "" + data.getBanned()); replaceMap.put("%banned%", "" + data.getBanned());
replaceMap.put("%inactive%", "" + data.getInactive()); replaceMap.put("%inactive%", "" + data.getInactive());
replaceMap.put("%joinleaver%", ""+data.getJoinleaver());
replaceMap.put("%activitytotal%", "" + data.getTotal()); replaceMap.put("%activitytotal%", "" + data.getTotal());
replaceMap.put("%playerchartmonth%", data.getPlayersChartImgHtmlMonth()); replaceMap.put("%playerchartmonth%", data.getPlayersChartImgHtmlMonth());
replaceMap.put("%playerchartweek%", data.getPlayersChartImgHtmlWeek()); replaceMap.put("%playerchartweek%", data.getPlayersChartImgHtmlWeek());
@ -124,8 +125,8 @@ public class AnalysisUtils {
return false; return false;
} }
static String createActivityPieChart(int totalBanned, int active, int inactive) { static String createActivityPieChart(int totalBanned, int active, int inactive, int joinleaver) {
String url = ActivityPieChartCreator.createChart(totalBanned, active, inactive); String url = ActivityPieChartCreator.createChart(totalBanned, active, inactive, joinleaver);
return "<img src=\"" + url + "\">"; return "<img src=\"" + url + "\">";
} }

View File

@ -1,6 +1,7 @@
package com.djrapitops.plan.utilities; package com.djrapitops.plan.utilities;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -38,19 +39,7 @@ public class FormatUtils {
// Removes letters from a string leaving only numbers and dots. // Removes letters from a string leaving only numbers and dots.
public static String removeLetters(String dataPoint) { public static String removeLetters(String dataPoint) {
String numbers = "0123456789."; return dataPoint.replaceAll("[^\\d.]", "");
List<Character> numList = new ArrayList<>();
char[] numberArray = numbers.toCharArray();
for (char c : numberArray) {
numList.add(c);
}
String returnString = "";
for (int i = 0; i < dataPoint.length(); i++) {
if (numList.contains(dataPoint.charAt(i))) {
returnString += dataPoint.charAt(i);
}
}
return returnString;
} }
// Formats long in milliseconds into d:h:m:s string // Formats long in milliseconds into d:h:m:s string

View File

@ -39,7 +39,7 @@
<p>The average of known player ages is %avgage%.</p> <p>The average of known player ages is %avgage%.</p>
<br/><h4>Playerbase composition</h4> <br/><h4>Playerbase composition</h4>
%activitypiechart% %activitypiechart%
<p>Active %active% | Inactive %inactive% | Banned %banned% | Total Players: %activitytotal%</p> <p>Active %active% | Inactive %inactive% | Banned %banned% | Joined once %joinleaver% | Total: %activitytotal%</p>
<br/><h4>Gamemode Usage</h4> <br/><h4>Gamemode Usage</h4>
%gmpiechart% %gmpiechart%
<p>Survival: %gm0% | Creative: %gm1% | Adventure: %gm2% | Spectator: %gm3%</p> <p>Survival: %gm0% | Creative: %gm1% | Adventure: %gm2% | Spectator: %gm3%</p>

View File

@ -5,19 +5,45 @@ Settings:
AnalysisCache: AnalysisCache:
RefreshAnalysisCacheOnEnable: true RefreshAnalysisCacheOnEnable: true
InspectCache: InspectCache:
ClearFromInspectCacheAfterXMinutes: 3 ClearFromInspectCacheAfterXMinutes: 5
DataCache: DataCache:
SaveEveryXMinutes: 5 SaveEveryXMinutes: 5
SaveServerDataEveryXMinutes: 5
ClearCacheEveryXSaves: 5 ClearCacheEveryXSaves: 5
WebServer: WebServer:
Enabled: true
Port: 8804 Port: 8804
ShowAlternativeServerIP: false ShowAlternativeServerIP: false
AlternativeIP: your.ip.here:%port% AlternativeIP: your.ip.here:%port%
PlanLite: PlanLite:
Enabled: true Enabled: true
UseAsAlternativeUI: false
Customization:
Colors:
Commands:
Main: '&2'
Secondary: '&7'
Highlight: '&f'
HTML:
ActivityGraph:
OnlinePlayers: '1E90FF'
NewPlayers: '228B22'
GamemodePie:
Survival: '951800'
Creative: '01A1DB'
Adventure: 'FFFF33'
Spectator: '228B22'
ActivityPie:
Active: '228B22'
Banned: '951800'
Inactive: 'A9A9A9'
JoinedOnce: '808080'
DemographicsTriggers:
Trigger: "i'm, am, im"
Female: 'female, girl, gurl, woman, gal, mrs, she, miss'
Male: 'male, boy, man, boe, sir, mr, guy, he'
IgnoreWhen: 'sure, think, with, are, you'
database: database:
type: sqlite type: sqlite

View File

@ -1,7 +1,7 @@
name: Plan name: Plan
author: Rsl1122 author: Rsl1122
main: com.djrapitops.plan.Plan main: com.djrapitops.plan.Plan
version: 2.0.0 version: 2.1.0
commands: commands:
plan: plan:

View File

@ -1 +1 @@
version: 2.0.0 version: 1.6.3