mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-23 09:37:54 +01:00
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:
parent
cda0148380
commit
0dfb2570e8
@ -1,6 +1,7 @@
|
||||
package com.djrapitops.plan;
|
||||
|
||||
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_SEEN(ChatColor.RED + "This Player has not played on this server."),
|
||||
USERNAME_NOT_KNOWN(ChatColor.RED + "Player not found from the database."),
|
||||
COLOR_MAIN(ChatColor.DARK_GREEN),
|
||||
COLOR_SEC(ChatColor.GRAY),
|
||||
COLOR_TER(ChatColor.WHITE),
|
||||
COLOR_MAIN(ChatColor.getByChar(getPlugin(Plan.class).getConfig().getString("Customization.Colors.Commands.Main").charAt(1))),
|
||||
COLOR_SEC(ChatColor.getByChar(getPlugin(Plan.class).getConfig().getString("Customization.Colors.Commands.Secondary").charAt(1))),
|
||||
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("»"),
|
||||
BALL("•"),
|
||||
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_REQUIRES_ARGUMENTS(ChatColor.RED + "[Plan] Command requires arguments."),
|
||||
COMMAND_REQUIRES_ARGUMENTS_ONE(ChatColor.RED + "[Plan] Command requires one argument."),
|
||||
|
@ -20,6 +20,31 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
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 {
|
||||
|
||||
private API api;
|
||||
@ -61,7 +86,9 @@ public class Plan extends JavaPlugin {
|
||||
|
||||
saveConfig();
|
||||
|
||||
log("Database init..");
|
||||
initDatabase();
|
||||
log("Database initiated.");
|
||||
|
||||
hookPlanLite();
|
||||
this.handler = new DataCacheHandler(this);
|
||||
@ -76,11 +103,9 @@ public class Plan extends JavaPlugin {
|
||||
this.api = new API(this);
|
||||
handler.handleReload();
|
||||
|
||||
if (getConfig().getBoolean("Settings.WebServer.Enabled")) {
|
||||
uiServer = new WebSocketServer(this);
|
||||
uiServer.initServer();
|
||||
|
||||
log("Player Analytics Enabled.");
|
||||
|
||||
if (getConfig().getBoolean("Settings.Cache.AnalysisCache.RefreshAnalysisCacheOnEnable")) {
|
||||
log("Analysis | Boot analysis in 30 seconds..");
|
||||
(new BukkitRunnable() {
|
||||
@ -92,6 +117,13 @@ public class Plan extends JavaPlugin {
|
||||
}
|
||||
}).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() {
|
||||
@ -106,13 +138,15 @@ public class Plan extends JavaPlugin {
|
||||
public void onDisable() {
|
||||
uiServer.stop();
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
if (handler != null) {
|
||||
log("Saving cached data..");
|
||||
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
scheduler.execute(() -> {
|
||||
handler.saveCacheOnDisable();
|
||||
});
|
||||
scheduler.shutdown();
|
||||
|
||||
scheduler.shutdown();
|
||||
}
|
||||
log("Player Analytics Disabled.");
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,28 @@
|
||||
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.UUIDFetcher;
|
||||
import com.djrapitops.planlite.api.API;
|
||||
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.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlanLiteHook {
|
||||
public class PlanLiteHook implements Hook{
|
||||
|
||||
private PlanLite planLite;
|
||||
private Plan plugin;
|
||||
@ -31,7 +39,8 @@ public class PlanLiteHook {
|
||||
*/
|
||||
public PlanLiteHook(Plan 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")) {
|
||||
try {
|
||||
this.planLite = getPlugin(PlanLite.class);
|
||||
@ -40,6 +49,9 @@ public class PlanLiteHook {
|
||||
}
|
||||
enabled = true;
|
||||
planLiteApi = planLite.getAPI();
|
||||
if (config.getBoolean("Settings.PlanLite.UseAsAlternativeUI")) {
|
||||
planLite.addExtraHook("Plan", this);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
} else {
|
||||
@ -85,4 +97,31 @@ public class PlanLiteHook {
|
||||
public boolean hasVault() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,12 @@ import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.PlanLiteHook;
|
||||
import com.djrapitops.plan.data.AnalysisData;
|
||||
import com.djrapitops.plan.data.UserData;
|
||||
import com.djrapitops.plan.ui.DataRequestHandler;
|
||||
import com.djrapitops.plan.utilities.FormatUtils;
|
||||
import com.djrapitops.planlite.UUIDFetcher;
|
||||
import java.util.Date;
|
||||
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
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* other webserver plugins.
|
||||
*
|
||||
* Should use updateAnalysisCache() before using this method.
|
||||
*
|
||||
* If AnalysisData is not in the AnalysisCache: returns <h1>404 Data was not
|
||||
* found in cache</h1>
|
||||
*
|
||||
* @return html as a string or a single error line html.
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @return AnalysisData in the AnalysisCache or null if not found
|
||||
*/
|
||||
public AnalysisData getAnalysisDataFromCache() {
|
||||
|
@ -9,6 +9,7 @@ import java.util.Date;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandException;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -48,22 +49,41 @@ public class AnalyzeCommand extends SubCommand {
|
||||
*/
|
||||
@Override
|
||||
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()) {
|
||||
analysisCache.updateCache();
|
||||
} else if (new Date().getTime() - analysisCache.getData().getRefreshDate() > 60000) {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
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
|
||||
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor
|
||||
+ " Player Analytics - Analysis results");
|
||||
@ -84,10 +104,5 @@ public class AnalyzeCommand extends SubCommand {
|
||||
}
|
||||
// Footer
|
||||
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}).runTaskTimer(plugin, 1 * 20, 5 * 20);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ public class InfoCommand extends SubCommand {
|
||||
ChatColor hColor = Phrase.COLOR_TER.color();
|
||||
|
||||
String[] messages = {
|
||||
hColor + Phrase.ARROWS_RIGHT.toString() + oColor + "Player Analytics - Info",
|
||||
tColor + " " + Phrase.BALL.toString() + oColor + "Version: " + tColor + plugin.getDescription().getVersion(),
|
||||
tColor + " " + Phrase.BALL.toString() + tColor + MiscUtils.checkVersion(),
|
||||
hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics - Info",
|
||||
tColor + " " + Phrase.BALL.toString() + oColor + " Version: " + tColor + plugin.getDescription().getVersion(),
|
||||
tColor + " " + Phrase.BALL.toString() + tColor +" "+ MiscUtils.checkVersion(),
|
||||
hColor + Phrase.ARROWS_RIGHT.toString()
|
||||
};
|
||||
sender.sendMessage(messages);
|
||||
|
@ -2,13 +2,13 @@ package com.djrapitops.plan.command.commands;
|
||||
|
||||
import com.djrapitops.plan.Phrase;
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.PlanLiteHook;
|
||||
import com.djrapitops.plan.utilities.UUIDFetcher;
|
||||
import com.djrapitops.plan.command.CommandType;
|
||||
import com.djrapitops.plan.command.SubCommand;
|
||||
|
||||
import java.util.Date;
|
||||
import com.djrapitops.plan.data.cache.InspectCacheHandler;
|
||||
import com.djrapitops.plan.utilities.FormatUtils;
|
||||
import com.djrapitops.plan.utilities.MiscUtils;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -58,6 +58,19 @@ public class InspectCommand extends SubCommand {
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
|
||||
UUID uuid;
|
||||
@ -80,12 +93,10 @@ public class InspectCommand extends SubCommand {
|
||||
return true;
|
||||
}
|
||||
|
||||
Date refreshDate = new Date();
|
||||
inspectCache.cache(uuid);
|
||||
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");
|
||||
|
@ -26,5 +26,4 @@ public class LiteCommand extends SubCommand {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public class ReloadCommand extends SubCommand {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
||||
plugin.reloadConfig();
|
||||
plugin.getHandler().saveCachedData();
|
||||
plugin.getHandler().saveCachedUserData();
|
||||
plugin.hookPlanLite();
|
||||
sender.sendMessage(ChatColor.GREEN + "[Plan] Reload complete.");
|
||||
|
||||
|
@ -52,8 +52,13 @@ public class SearchCommand extends SubCommand {
|
||||
*/
|
||||
@Override
|
||||
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) {
|
||||
sender.sendMessage(Phrase.COMMAND_REQUIRES_ARGUMENTS_ONE.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
ChatColor oColor = Phrase.COLOR_MAIN.color();
|
||||
|
@ -28,6 +28,7 @@ public class AnalysisData {
|
||||
private int banned;
|
||||
private int active;
|
||||
private int inactive;
|
||||
private int joinleaver;
|
||||
private int total;
|
||||
|
||||
private int totalPlayers;
|
||||
@ -42,6 +43,14 @@ public class AnalysisData {
|
||||
|
||||
// Getters and setters v---------------------------------v
|
||||
|
||||
public int getJoinleaver() {
|
||||
return joinleaver;
|
||||
}
|
||||
|
||||
public void setJoinleaver(int joinleaver) {
|
||||
this.joinleaver = joinleaver;
|
||||
}
|
||||
|
||||
public boolean isPlanLiteEnabled() {
|
||||
return planLiteEnabled;
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ import com.djrapitops.plan.data.*;
|
||||
import com.djrapitops.plan.data.handlers.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import static org.bukkit.Bukkit.getPlayer;
|
||||
import static org.bukkit.Bukkit.getPlayer;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -66,6 +67,10 @@ public class DataCacheHandler {
|
||||
if (minutes <= 0) {
|
||||
minutes = 5;
|
||||
}
|
||||
int sMinutes = plugin.getConfig().getInt("Settings.Cache.DataCache.SaveServerDataEveryXMinutes");
|
||||
if (sMinutes <= 0) {
|
||||
sMinutes = 5;
|
||||
}
|
||||
final int clearAfterXsaves;
|
||||
int configValue = plugin.getConfig().getInt("Settings.Cache.DataCache.ClearCacheEveryXSaves");
|
||||
if (configValue <= 1) {
|
||||
@ -78,13 +83,21 @@ public class DataCacheHandler {
|
||||
public void run() {
|
||||
DataCacheHandler handler = plugin.getHandler();
|
||||
handler.saveHandlerDataToCache();
|
||||
handler.saveCachedData();
|
||||
handler.saveCachedUserData();
|
||||
if (timesSaved % clearAfterXsaves == 0) {
|
||||
handler.clearCache();
|
||||
}
|
||||
handler.clearNulls();
|
||||
timesSaved++;
|
||||
}
|
||||
}).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
|
||||
*/
|
||||
public void saveCachedData() {
|
||||
public void saveCachedUserData() {
|
||||
dataCache.keySet().stream().forEach((uuid) -> {
|
||||
saveCachedData(uuid);
|
||||
});
|
||||
serverData.updatePlayerCount();
|
||||
saveServerData();
|
||||
timesSaved++;
|
||||
}
|
||||
|
||||
@ -219,10 +230,9 @@ public class DataCacheHandler {
|
||||
* Clears all UserData from the HashMap
|
||||
*/
|
||||
public void clearCache() {
|
||||
Set<UUID> uuidSet = dataCache.keySet();
|
||||
Iterator<UUID> uuidIterator = uuidSet.iterator();
|
||||
while (uuidIterator.hasNext()) {
|
||||
clearFromCache(uuidIterator.next());
|
||||
Iterator<Map.Entry<UUID, UserData>> clearIterator = dataCache.entrySet().iterator();
|
||||
while (clearIterator.hasNext()) {
|
||||
clearFromCache(clearIterator.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
|
||||
*
|
||||
@ -371,4 +411,13 @@ public class DataCacheHandler {
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
private void clearNulls() {
|
||||
Iterator<UUID> clearIterator = dataCache.keySet().iterator();
|
||||
while (clearIterator.hasNext()) {
|
||||
if (dataCache.get(clearIterator.next()) == null) {
|
||||
clearIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
public class DemographicsHandler {
|
||||
|
||||
private final DataCacheHandler handler;
|
||||
private final Plan plugin;
|
||||
|
||||
/**
|
||||
* Class Constructor
|
||||
@ -30,6 +31,7 @@ public class DemographicsHandler {
|
||||
*/
|
||||
public DemographicsHandler(Plan plugin, DataCacheHandler h) {
|
||||
this.handler = h;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,10 +44,10 @@ public class DemographicsHandler {
|
||||
* @param data UserData corresponding to player of this event.
|
||||
*/
|
||||
public void handleChatEvent(AsyncPlayerChatEvent event, UserData data) {
|
||||
List<String> triggers = Arrays.asList("i\'m", "am", "im");
|
||||
List<String> female = Arrays.asList("female", "girl", "gurl", "woman", "gal", "mrs", "she", "miss");
|
||||
List<String> male = Arrays.asList("male", "boy", "man", "boe", "sir", "mr", "guy", "he");
|
||||
List<String> ignore = Arrays.asList("sure", "think", "with", "are");
|
||||
List<String> triggers = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.Trigger").split(", "));
|
||||
List<String> female = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.Female").split(", "));
|
||||
List<String> male = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.Male").split(", "));
|
||||
List<String> ignore = Arrays.asList(plugin.getConfig().getString("Customization.DemographicsTriggers.IgnoreWhen").split(", "));
|
||||
|
||||
String message = event.getMessage();
|
||||
String[] messageA = message.toLowerCase().split("\\s+");
|
||||
|
@ -9,6 +9,7 @@ import static org.bukkit.Bukkit.getOfflinePlayer;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import static org.bukkit.Bukkit.getOfflinePlayer;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -44,9 +44,20 @@ public class PlanLiteHandler {
|
||||
return;
|
||||
}
|
||||
Set<String> enabledHooks = hook.getEnabledHooksNames();
|
||||
HashMap<String, DataPoint> liteData = hook.getAllData(playerName, true);
|
||||
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.setFactions(enabledHooks.contains("Factions"));
|
||||
plData.setSuperbVote(enabledHooks.contains("SuperbVote"));
|
||||
@ -82,4 +93,5 @@ public class PlanLiteHandler {
|
||||
data.setPlanLiteFound(true);
|
||||
data.setPlanLiteData(plData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package main.java.com.djrapitops.plan.ui.graphs;
|
||||
|
||||
import com.djrapitops.plan.Phrase;
|
||||
import com.googlecode.charts4j.Color;
|
||||
import com.googlecode.charts4j.GCharts;
|
||||
import com.googlecode.charts4j.PieChart;
|
||||
@ -17,27 +18,30 @@ public class ActivityPieChartCreator {
|
||||
* @param totalBanned Number of Banned Players
|
||||
* @param active Number of Active Players
|
||||
* @param inactive Number of Inactive Players
|
||||
* @param joinleaver Number of players who have joined only once
|
||||
* @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 banPerc = (int) ((totalBanned * 1.0 / total) * 100);
|
||||
int inacPerc = (int) ((inactive * 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++;
|
||||
}
|
||||
while (banPerc + inacPerc + actPerc > 100) {
|
||||
while (banPerc + inacPerc + actPerc + joinlPerc > 100) {
|
||||
actPerc--;
|
||||
}
|
||||
|
||||
Slice s1 = Slice.newSlice((int) (banPerc), Color.newColor("951800"), "Banned", "Banned");
|
||||
Slice s3 = Slice.newSlice((int) (inacPerc), Color.newColor("A9A9A9"), "Inactive", "Inactive");
|
||||
Slice s4 = Slice.newSlice((int) (actPerc), Color.newColor("228B22"), "Active", "Active");
|
||||
Slice bannedSlice = Slice.newSlice((int) (banPerc), Color.newColor(Phrase.HCOLOR_ACTP_BAN+""), "Banned", "Banned");
|
||||
Slice joinLeaverSlice = Slice.newSlice((int) (joinlPerc), Color.newColor(Phrase.HCOLOR_ACTP_JON+""), "Unknown", "Unknown");
|
||||
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.setThreeD(true);
|
||||
String refURL = refChart.toURLString();
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.djrapitops.plan.ui.graphs;
|
||||
|
||||
import com.djrapitops.plan.Phrase;
|
||||
import com.googlecode.charts4j.Color;
|
||||
import com.googlecode.charts4j.GCharts;
|
||||
import com.googlecode.charts4j.PieChart;
|
||||
@ -53,10 +54,10 @@ public class GMTimesPieChartCreator {
|
||||
one--;
|
||||
}
|
||||
|
||||
Slice s1 = Slice.newSlice(zero, Color.newColor("951800"), "Survival", "Survival");
|
||||
Slice s2 = Slice.newSlice(one, Color.newColor("01A1DB"), "Creative", "Creative");
|
||||
Slice s3 = Slice.newSlice(two, Color.newColor("FFFF33"), "Adventure", "Adventure");
|
||||
Slice s4 = Slice.newSlice(three, Color.newColor("228B22"), "Spectator", "Spectator");
|
||||
Slice s1 = Slice.newSlice(zero, Color.newColor(Phrase.HCOLOR_GMP_0 + ""), "Survival", "Survival");
|
||||
Slice s2 = Slice.newSlice(one, Color.newColor(Phrase.HCOLOR_GMP_1+""), "Creative", "Creative");
|
||||
Slice s3 = Slice.newSlice(two, Color.newColor(Phrase.HCOLOR_GMP_2+""), "Adventure", "Adventure");
|
||||
Slice s4 = Slice.newSlice(three, Color.newColor(Phrase.HCOLOR_GMP_3+""), "Spectator", "Spectator");
|
||||
|
||||
PieChart refChart = GCharts.newPieChart(s1, s2, s3, s4);
|
||||
refChart.setSize(400, 150);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package main.java.com.djrapitops.plan.ui.graphs;
|
||||
|
||||
import com.djrapitops.plan.Phrase;
|
||||
import com.djrapitops.plan.Plan;
|
||||
import com.djrapitops.plan.data.ServerData;
|
||||
import com.djrapitops.plan.utilities.FormatUtils;
|
||||
@ -84,8 +85,8 @@ public class PlayerActivityGraphCreator {
|
||||
Data pYData = Data.newData(pYList);
|
||||
Data nYData = Data.newData(nYList);
|
||||
|
||||
XYLine playerLine = Plots.newXYLine(xData, pYData, Color.BLUE, "Online Players");
|
||||
XYLine newPlayerLine = Plots.newXYLine(xData, nYData, Color.GREEN, "New Players");
|
||||
XYLine playerLine = Plots.newXYLine(xData, pYData, Color.newColor(Phrase.HCOLOR_ACT_ONL + ""), "Online Players");
|
||||
XYLine newPlayerLine = Plots.newXYLine(xData, nYData, Color.newColor(Phrase.HCOLOR_ACT_NEW + ""), "New Players");
|
||||
LineChart chart = GCharts.newLineChart(playerLine, newPlayerLine);
|
||||
chart.addXAxisLabels(xAxisLabels);
|
||||
chart.addTopAxisLabels(AxisLabelsFactory.newAxisLabels("Players", 1));
|
||||
|
@ -75,25 +75,23 @@ public class Analysis {
|
||||
rawServerData = plugin.getDB().getServerDataHashMap();
|
||||
plugin.log("Analysis | Data Fetched, beginning Analysis of data..");
|
||||
AnalysisData data = new AnalysisData();
|
||||
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);
|
||||
|
||||
createPlayerActivityGraphs(data);
|
||||
|
||||
// Create empty Dataset
|
||||
long gmZero = 0;
|
||||
long gmOne = 0;
|
||||
long gmTwo = 0;
|
||||
long gmThree = 0;
|
||||
|
||||
long totalPlaytime = 0;
|
||||
int totalBanned = 0;
|
||||
long totalLoginTimes = 0;
|
||||
long totalPlaytime = 0;
|
||||
|
||||
int totalBanned = 0;
|
||||
int active = 0;
|
||||
int joinleaver = 0;
|
||||
int inactive = 0;
|
||||
|
||||
int ops = 0;
|
||||
List<Integer> ages = new ArrayList<>();
|
||||
|
||||
@ -105,6 +103,7 @@ public class Analysis {
|
||||
int totalVotes = 0;
|
||||
int totalMoney = 0;
|
||||
|
||||
// Fill Dataset with userdata.
|
||||
for (UserData uData : rawData) {
|
||||
if (planLiteEnabled) {
|
||||
PlanLitePlayerData litePlayerData = uData.getPlanLiteData();
|
||||
@ -138,12 +137,13 @@ public class Analysis {
|
||||
|
||||
if (uData.isBanned()) {
|
||||
totalBanned++;
|
||||
} else if (uData.getLoginTimes() == 1) {
|
||||
joinleaver++;
|
||||
} else if (AnalysisUtils.isActive(uData.getLastPlayed(), uData.getPlayTime(), uData.getLoginTimes())) {
|
||||
active++;
|
||||
} else {
|
||||
inactive++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (planLiteEnabled) {
|
||||
@ -159,29 +159,30 @@ public class Analysis {
|
||||
|
||||
data.setTotalLoginTimes(totalLoginTimes);
|
||||
|
||||
String activityPieChartHtml = AnalysisUtils.createActivityPieChart(totalBanned, active, inactive);
|
||||
String activityPieChartHtml = AnalysisUtils.createActivityPieChart(totalBanned, active, inactive, joinleaver);
|
||||
data.setActivityChartImgHtml(activityPieChartHtml);
|
||||
data.setActive(active);
|
||||
data.setInactive(inactive);
|
||||
data.setBanned(totalBanned);
|
||||
data.setTotal(offlinePlayers.length);
|
||||
data.setJoinleaver(joinleaver);
|
||||
|
||||
data.setTotal(offlinePlayers.length);
|
||||
data.setOps(ops);
|
||||
|
||||
data.setTotalPlayTime(totalPlaytime);
|
||||
long averagePlaytime = totalPlaytime / rawData.size();
|
||||
data.setAveragePlayTime(averagePlaytime);
|
||||
data.setAveragePlayTime(totalPlaytime / rawData.size());
|
||||
int totalAge = 0;
|
||||
for (int age : ages) {
|
||||
totalAge += age;
|
||||
}
|
||||
double averageAge;
|
||||
if (ages.size() != 0) {
|
||||
if (!ages.isEmpty()) {
|
||||
averageAge = totalAge * 1.0 / ages.size();
|
||||
} else {
|
||||
averageAge = -1;
|
||||
}
|
||||
data.setAverageAge(averageAge);
|
||||
|
||||
long gmTotal = gmZero + gmOne + gmTwo + gmThree;
|
||||
HashMap<GameMode, Long> totalGmTimes = new HashMap<>();
|
||||
totalGmTimes.put(GameMode.SURVIVAL, gmZero);
|
||||
@ -213,6 +214,18 @@ public class Analysis {
|
||||
plugin.log("Analysis | Analysis Complete.");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ public class AnalysisUtils {
|
||||
replaceMap.put("%active%", "" + data.getActive());
|
||||
replaceMap.put("%banned%", "" + data.getBanned());
|
||||
replaceMap.put("%inactive%", "" + data.getInactive());
|
||||
replaceMap.put("%joinleaver%", ""+data.getJoinleaver());
|
||||
replaceMap.put("%activitytotal%", "" + data.getTotal());
|
||||
replaceMap.put("%playerchartmonth%", data.getPlayersChartImgHtmlMonth());
|
||||
replaceMap.put("%playerchartweek%", data.getPlayersChartImgHtmlWeek());
|
||||
@ -124,8 +125,8 @@ public class AnalysisUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
static String createActivityPieChart(int totalBanned, int active, int inactive) {
|
||||
String url = ActivityPieChartCreator.createChart(totalBanned, active, inactive);
|
||||
static String createActivityPieChart(int totalBanned, int active, int inactive, int joinleaver) {
|
||||
String url = ActivityPieChartCreator.createChart(totalBanned, active, inactive, joinleaver);
|
||||
return "<img src=\"" + url + "\">";
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.djrapitops.plan.utilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.bukkit.Location;
|
||||
@ -38,19 +39,7 @@ public class FormatUtils {
|
||||
|
||||
// Removes letters from a string leaving only numbers and dots.
|
||||
public static String removeLetters(String dataPoint) {
|
||||
String numbers = "0123456789.";
|
||||
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;
|
||||
return dataPoint.replaceAll("[^\\d.]", "");
|
||||
}
|
||||
|
||||
// Formats long in milliseconds into d:h:m:s string
|
||||
|
@ -39,7 +39,7 @@
|
||||
<p>The average of known player ages is %avgage%.</p>
|
||||
<br/><h4>Playerbase composition</h4>
|
||||
%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>
|
||||
%gmpiechart%
|
||||
<p>Survival: %gm0% | Creative: %gm1% | Adventure: %gm2% | Spectator: %gm3%</p>
|
||||
|
@ -5,19 +5,45 @@ Settings:
|
||||
AnalysisCache:
|
||||
RefreshAnalysisCacheOnEnable: true
|
||||
InspectCache:
|
||||
ClearFromInspectCacheAfterXMinutes: 3
|
||||
ClearFromInspectCacheAfterXMinutes: 5
|
||||
DataCache:
|
||||
SaveEveryXMinutes: 5
|
||||
SaveServerDataEveryXMinutes: 5
|
||||
ClearCacheEveryXSaves: 5
|
||||
WebServer:
|
||||
Enabled: true
|
||||
Port: 8804
|
||||
ShowAlternativeServerIP: false
|
||||
AlternativeIP: your.ip.here:%port%
|
||||
PlanLite:
|
||||
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:
|
||||
type: sqlite
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
name: Plan
|
||||
author: Rsl1122
|
||||
main: com.djrapitops.plan.Plan
|
||||
version: 2.0.0
|
||||
version: 2.1.0
|
||||
|
||||
commands:
|
||||
plan:
|
||||
|
@ -1 +1 @@
|
||||
version: 2.0.0
|
||||
version: 1.6.3
|
||||
|
Loading…
Reference in New Issue
Block a user