Merge pull request #392 from Rsl1122/4.0.3

Pull Request for 4.0.4
This commit is contained in:
Rsl1122 2017-10-31 20:22:50 +02:00 committed by GitHub
commit 7087c11239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 480 additions and 82 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.djrapitops</groupId>
<artifactId>Plan</artifactId>
<version>4.0.3</version>
<version>4.0.4</version>
<packaging>jar</packaging>
<repositories>
<repository>

View File

@ -181,6 +181,7 @@ public class Plan extends BukkitPlugin<Plan> implements IPlan {
if (!reloading) {
registerListeners();
}
PlanPlayerListener.setCountKicks(true);
registerTasks();
this.api = new API(this);

View File

@ -23,7 +23,7 @@ public enum Settings {
SHOW_ALTERNATIVE_IP("Commands.AlternativeIP.Enabled"),
LOG_UNKNOWN_COMMANDS("Data.Commands.LogUnknownCommands"),
COMBINE_COMMAND_ALIASES("Data.Commands.CombineCommandAliases"),
WRITE_NEW_LOCALE("Plugin.WriteNewLocaleFileOnStart"),
WRITE_NEW_LOCALE("Plugin.WriteNewLocaleFileOnEnable"),
DEV_MODE("Plugin.Dev"),
USE_SERVER_TIME("Customization.UseServerTime"),
DISPLAY_SESSIONS_AS_TABLE("Customization.Display.SessionsAsTable"),
@ -99,6 +99,8 @@ public enum Settings {
// StringList
HIDE_FACTIONS("Plugins.Factions.HideFactions"),
HIDE_TOWNS("Plugins.Towny.HideTowns"),
// Config section
WORLD_ALIASES("Customization.WorldAliases"),
//
// Bungee
BUNGEE_IP("Server.IP"),

View File

@ -0,0 +1,77 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.HashMap;
import java.util.Map;
/**
* Class responsible for managing Bukkit side config settings for World Aliases.
*
* @author Rsl1122
*/
public class WorldAliasSettings {
private final Plan plugin;
/**
* Constructor.
*
* @param plugin Current instance of Plan.
*/
public WorldAliasSettings(Plan plugin) {
this.plugin = plugin;
}
/**
* Used to get all World aliases in the config
*
* @return Map: Original name, Alias
*/
public Map<String, String> getAliases() {
ConfigurationSection aliasSect = getAliasSection();
Map<String, String> aliasMap = new HashMap<>();
for (String world : aliasSect.getKeys(false)) {
aliasMap.put(world, aliasSect.getString(world));
}
return aliasMap;
}
private ConfigurationSection getAliasSection() {
FileConfiguration config = plugin.getConfig();
return config.getConfigurationSection(Settings.WORLD_ALIASES.getPath());
}
/**
* Adds a new World to the config section.
* <p>
* If exists does not override old value.
*
* @param world World name
*/
public void addWorld(String world) {
ConfigurationSection aliasSect = getAliasSection();
Object previousValue = aliasSect.get(world);
if (previousValue == null) {
aliasSect.set(world, world);
}
plugin.saveConfig();
}
/**
* Used to get alias of a single world.
*
* @param world World name.
* @return Alias.
*/
public String getAlias(String world) {
return getAliasSection().getString(world);
}
}

View File

@ -44,5 +44,6 @@ public class ManageCommand extends TreeCommand<Plan> {
commands.add(new ManageClearCommand(plugin));
commands.add(new ManageDumpCommand(plugin));
commands.add(new ManageSetupCommand(plugin));
commands.add(new ManageDisableCommand());
}
}

View File

@ -3,6 +3,8 @@ package main.java.com.djrapitops.plan.command.commands;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.TreeCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.PlanBungee;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.command.commands.webuser.WebCheckCommand;
import main.java.com.djrapitops.plan.command.commands.webuser.WebDeleteCommand;
@ -19,14 +21,22 @@ import main.java.com.djrapitops.plan.locale.Msg;
*/
public class WebUserCommand extends TreeCommand<IPlan> {
public WebUserCommand(IPlan plugin, RegisterCommand register) {
public WebUserCommand(Plan plugin, RegisterCommand register) {
super(plugin, "webuser, web",
CommandType.CONSOLE,
Permissions.MANAGE_WEB.getPerm(),
Locale.get(Msg.CMD_USG_WEB).toString(),
"plan web");
commands.add(register);
}
public WebUserCommand(PlanBungee plugin, RegisterCommand register) {
super(plugin, "webuser, web",
CommandType.CONSOLE,
Permissions.MANAGE_WEB.getPerm(),
Locale.get(Msg.CMD_USG_WEB).toString(),
"planbungee web");
commands.add(register);
}
@Override

View File

@ -0,0 +1,45 @@
package main.java.com.djrapitops.plan.command.commands.manage;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.systems.listeners.PlanPlayerListener;
import main.java.com.djrapitops.plan.utilities.Check;
/**
* This manage SubCommand is used to disable some features of the plugin temporarily.
*
* @author Rsl1122
* @since 4.0.4
*/
public class ManageDisableCommand extends SubCommand {
/**
* Class Constructor.
*/
public ManageDisableCommand() {
super("disable",
CommandType.CONSOLE_WITH_ARGUMENTS,
Permissions.MANAGE.getPermission(),
"Used to disable some features of the Plugin temporarily",
"<feature>");
}
@Override
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
if (!Check.isTrue(args.length >= 1, Locale.get(Msg.CMD_FAIL_REQ_ARGS).parse(this.getArguments()), sender)) {
return true;
}
switch (args[0].toLowerCase()) {
case "kickcount":
PlanPlayerListener.setCountKicks(false);
sender.sendMessage("§aDisabled Kick Counting temporarily until next plugin reload.");
break;
default:
sender.sendMessage("§eDefine a feature to disable! (currently supports only kickCount)");
}
return true;
}
}

View File

@ -103,8 +103,11 @@ public abstract class TimeKeeper {
}
public long getTime(String state) {
Long time = times.get(state);
return time != null ? time : 0L;
return times.getOrDefault(state, 0L);
}
public void addTime(String state, long time) {
times.put(state, times.getOrDefault(state, 0L) + time);
}
public long getTotal() {

View File

@ -679,4 +679,8 @@ public class SessionsTable extends UserIDTable {
session.setSessionID(savedSession.getSessionID());
}
}
String getcolumnServerID() {
return columnServerID;
}
}

View File

@ -5,8 +5,10 @@ import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.database.databases.SQLDB;
import main.java.com.djrapitops.plan.database.processing.ExecStatement;
import main.java.com.djrapitops.plan.database.processing.QueryAllStatement;
import main.java.com.djrapitops.plan.database.processing.QueryStatement;
import main.java.com.djrapitops.plan.database.sql.Sql;
import main.java.com.djrapitops.plan.database.sql.TableSqlParser;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -111,5 +113,43 @@ public class WorldTable extends Table {
return columnWorldName;
}
public Set<String> getWorldNames() throws SQLException {
return getWorldNames(MiscUtils.getIPlan().getServerUuid());
}
public Set<String> getWorldNames(UUID serverUUID) throws SQLException {
WorldTimesTable worldTimesTable = db.getWorldTimesTable();
SessionsTable sessionsTable = db.getSessionsTable();
ServerTable serverTable = db.getServerTable();
String statementSelectServerID = serverTable.statementSelectServerID;
String worldIDColumn = worldTimesTable + "." + worldTimesTable.getColumnWorldId();
String worldSessionIDColumn = worldTimesTable + "." + worldTimesTable.getColumnSessionID();
String sessionIDColumn = sessionsTable + "." + sessionsTable.getColumnID();
String sessionServerIDColumn = sessionsTable + "." + sessionsTable.getcolumnServerID();
String sql = "SELECT DISTINCT " +
columnWorldName + " FROM " +
tableName +
" JOIN " + worldTimesTable + " on " + worldIDColumn + "=" + tableName + "." + columnWorldId +
" JOIN " + sessionsTable + " on " + worldSessionIDColumn + "=" + sessionIDColumn +
" WHERE " + statementSelectServerID + "=" + sessionServerIDColumn;
return query(new QueryStatement<Set<String>>(sql, 1000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
}
@Override
public Set<String> processResults(ResultSet set) throws SQLException {
Set<String> worldNames = new HashSet<>();
while (set.next()) {
worldNames.add(set.getString(columnWorldName));
}
return worldNames;
}
});
}
}

View File

@ -351,4 +351,12 @@ public class WorldTimesTable extends UserIDTable {
}
});
}
String getColumnWorldId() {
return columnWorldId;
}
String getColumnSessionID() {
return columnSessionID;
}
}

View File

@ -13,7 +13,6 @@ import main.java.com.djrapitops.plan.data.Action;
import main.java.com.djrapitops.plan.data.PlayerKill;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.UserInfo;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.tables.SessionsTable;
@ -157,15 +156,7 @@ public class InspectPageParser extends PageParser {
String punchCardData = PunchCardGraphCreator.createDataSeries(allSessions);
WorldTimes worldTimes = db.getWorldTimesTable().getWorldTimesOfUser(uuid);
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
for (String world : db.getWorldTable().getWorlds()) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
AnalysisUtils.addMissingWorlds(worldTimes);
String[] worldPieData = WorldPieCreator.createSeriesData(worldTimes);

View File

@ -1,6 +1,7 @@
package main.java.com.djrapitops.plan.systems.listeners;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.WorldAliasSettings;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.bukkit.entity.Player;
@ -46,6 +47,8 @@ public class PlanGamemodeChangeListener implements Listener {
String gameMode = event.getNewGameMode().name();
String worldName = p.getWorld().getName();
new WorldAliasSettings(plugin).addWorld(worldName);
Optional<Session> cachedSession = plugin.getDataCache().getCachedSession(uuid);
cachedSession.ifPresent(session -> session.changeState(worldName, gameMode, time));
}

View File

@ -26,6 +26,8 @@ import java.util.UUID;
*/
public class PlanPlayerListener implements Listener {
private static boolean countKicks = true;
private final Plan plugin;
private final DataCache cache;
@ -61,7 +63,7 @@ public class PlanPlayerListener implements Listener {
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerKick(PlayerKickEvent event) {
if (event.isCancelled()) {
if (!countKicks || event.isCancelled()) {
return;
}
UUID uuid = event.getPlayer().getUniqueId();
@ -132,4 +134,8 @@ public class PlanPlayerListener implements Listener {
plugin.addToProcessQueue(new FirstLeaveProcessor(uuid, time, messagesSent));
}
}
public static void setCountKicks(boolean value) {
countKicks = value;
}
}

View File

@ -1,6 +1,7 @@
package main.java.com.djrapitops.plan.systems.listeners;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.WorldAliasSettings;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.bukkit.entity.Player;
@ -28,6 +29,8 @@ public class PlanWorldChangeListener implements Listener {
String gameMode = p.getGameMode().name();
long time = MiscUtils.getTime();
new WorldAliasSettings(plugin).addWorld(worldName);
Optional<Session> cachedSession = plugin.getDataCache().getCachedSession(uuid);
cachedSession.ifPresent(session -> session.changeState(worldName, gameMode, time));
}

View File

@ -1,7 +1,6 @@
package main.java.com.djrapitops.plan.systems.webserver.response;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.systems.webserver.theme.Theme;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
@ -43,7 +42,7 @@ public class PlayersPageResponse extends Response {
int i = 1;
for (String name : names) {
String link = Html.LINK.parse(Plan.getPlanAPI().getPlayerInspectPageLink(name), name);
String link = Html.LINK.parse("../player/" + name, name);
html.append("<td>").append(link).append("</td>");

View File

@ -29,7 +29,11 @@ public class PostHtmlWebAPI extends WebAPI {
@Override
public Response onRequest(IPlan plugin, Map<String, String> variables) {
try {
String html = variables.get("html");
String htmlVariable = variables.get("html");
if (htmlVariable == null) {
return badRequest("Html was null");
}
String html = "<!DOCTYPE html>" + htmlVariable.split("<!DOCTYPE html>", 2)[1];
String target = variables.get("target");
InformationManager infoManager = plugin.getInfoManager();
switch (target) {
@ -60,8 +64,8 @@ public class PostHtmlWebAPI extends WebAPI {
public void sendInspectHtml(String address, UUID uuid, String html) throws WebAPIException {
addVariable("uuid", uuid.toString());
addVariable("html", html);
addVariable("target", "inspectPage");
addVariable("html", html);
super.sendRequest(address);
}

View File

@ -94,48 +94,72 @@ public class FormatUtils {
long hours = x % 24;
x /= 24;
long days = x % 365;
long months = days % 30;
days -= months * 30;
x /= 365;
long years = x;
String fYear = Settings.FORMAT_YEAR.toString();
String fYears = Settings.FORMAT_YEARS.toString();
String fMonth = Settings.FORMAT_MONTH.toString();
String fMonths = Settings.FORMAT_MONTHS.toString();
String fDay = Settings.FORMAT_DAY.toString();
String fDays = Settings.FORMAT_DAYS.toString();
String fHours = Settings.FORMAT_HOURS.toString();
String fMinutes = Settings.FORMAT_MINUTES.toString();
String fSeconds = Settings.FORMAT_SECONDS.toString();
if (years != 0) {
if (years == 1) {
builder.append(Settings.FORMAT_YEAR.toString());
builder.append(fYear);
} else {
builder.append(Settings.FORMAT_YEARS.toString().replace("%years%", String.valueOf(years)));
builder.append(fYears.replace("%years%", String.valueOf(years)));
}
}
if (months != 0) {
if (months == 1) {
builder.append(fMonth);
} else {
builder.append(fMonths.replace("%months%", String.valueOf(months)));
}
}
if (days != 0) {
if (days == 1) {
builder.append(Settings.FORMAT_DAY.toString());
builder.append(fDay);
} else {
builder.append(Settings.FORMAT_DAYS.toString().replace("%days%", String.valueOf(days)));
builder.append(fDays.replace("%days%", String.valueOf(days)));
}
}
if (hours != 0) {
String h = Settings.FORMAT_HOURS.toString().replace("%hours%", String.valueOf(hours));
String h = fHours.replace("%hours%", String.valueOf(hours));
if (h.contains("%zero%") && String.valueOf(hours).length() == 1) {
builder.append('0');
}
builder.append(h);
}
if (minutes != 0) {
String m = Settings.FORMAT_MINUTES.toString().replace("%minutes%", String.valueOf(minutes));
String m = fMinutes.replace("%minutes%", String.valueOf(minutes));
if (hours == 0 && m.contains("%hours%")) {
m = m.replace("%hours%", Settings.FORMAT_MINUTES.toString().replace("%zero%", "0") + "0");
} else {
m = m.replace("%hours", "");
builder.append(fHours.replace("%zero%", "0").replace("%hours%", "0"));
m = m.replace("%hours%", "");
}
m = m.replace("%hours%", "");
if (m.contains("%zero%") && String.valueOf(minutes).length() == 1) {
builder.append('0');
}
builder.append(m);
}
if (seconds != 0) {
String s = Settings.FORMAT_SECONDS.toString().replace("%seconds%", String.valueOf(seconds));
String s = fSeconds.replace("%seconds%", String.valueOf(seconds));
if (minutes == 0 && s.contains("%minutes%")) {
s = s.replace("%minutes%", Settings.FORMAT_MINUTES.toString().replace("%hours", "").replace("%zero%", "0") + 0);
} else {
s = s.replace("%minutes%", "");
if (hours == 0 && fMinutes.contains("%hours%")) {
builder.append(fHours.replace("%zero%", "0").replace("%hours%", "0"));
}
builder.append(fMinutes.replace("%hours%", "").replace("%zero%", "0").replace("%minutes%", "0"));
}
s = s.replace("%minutes%", "");
if (s.contains("%zero%") && String.valueOf(seconds).length() == 1) {
builder.append('0');
}

View File

@ -11,7 +11,6 @@ import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.analysis.*;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.tables.TPSTable;
@ -296,15 +295,7 @@ public class Analysis {
killPart.addKills(playerKills);
WorldTimes worldTimes = db.getWorldTimesTable().getWorldTimesOfServer();
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
for (String world : db.getWorldTable().getWorlds()) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
AnalysisUtils.addMissingWorlds(worldTimes);
worldPart.setWorldTimes(worldTimes);

View File

@ -1,15 +1,19 @@
package main.java.com.djrapitops.plan.utilities.analysis;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.comparators.SessionLengthComparator;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -292,4 +296,20 @@ public class AnalysisUtils {
}
return 0;
}
public static void addMissingWorlds(WorldTimes worldTimes) {
try {
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
IPlan plugin = MiscUtils.getIPlan();
for (String world : plugin.getDB().getWorldTable().getWorldNames(plugin.getServerUuid())) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
} catch (SQLException e) {
Log.toLog("AnalysisUtils.addMissingWorlds", e);
}
}
}

View File

@ -52,7 +52,7 @@ public enum Html {
TABLE_START_3("<table class=\"sortable table\"><thead><tr><th>${0}</th><th>${1}</th><th>${2}</th></tr></thead><tbody>"),
TABLE_START_4("<table class=\"sortable table\"><thead><tr><th>${0}</th><th>${1}</th><th>${2}</th><th>${3}</th></tr></thead><tbody>"),
TABLE_SESSIONS(DIV_W_CLASS_STYLE.parse("box-footer scrollbar", "padding: 2px;",
TABLE_START_4.parse("Player", "Started", "Length", "World - Time") + "${0}" + TABLE_END.parse())
TABLE_START_4.parse("Player", "Started", "Length", "World - Time") + "${3}" + TABLE_END.parse())
),
TABLE_SESSIONS_START(TABLE_START_3.parse("Session Started", "Session Ended", "Session Length")),
TABLE_KILLS_START(TABLE_START_3.parse(FONT_AWESOME_ICON.parse("clock-o") + " Time", "Killed", "With")),
@ -90,7 +90,7 @@ public enum Html {
}
StrSubstitutor sub = new StrSubstitutor(replaceMap);
sub.setEnableSubstitutionInVariables(false);
return sub.replace(html);
}
}

View File

@ -1,12 +1,11 @@
package main.java.com.djrapitops.plan.utilities.html.graphs;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.WorldAliasSettings;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
public class WorldPieCreator {
@ -28,14 +27,16 @@ public class WorldPieCreator {
Map<String, Long> playtimePerWorld = worldTimes.getWorldTimes().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getTotal()));
List<String> worlds = new ArrayList<>(playtimePerWorld.keySet());
Map<String, Long> playtimePerAlias = transformToAliases(playtimePerWorld);
List<String> worlds = new ArrayList<>(playtimePerAlias.keySet());
Collections.sort(worlds);
int size = playtimePerWorld.size();
for (String worldName : worlds) {
seriesBuilder.append("{name:'").append(worldName)
.append("',y:").append(playtimePerWorld.getOrDefault(worldName, 0L))
.append(",drilldown: '").append(worldName).append("'");
int size = playtimePerAlias.size();
for (String alias : worlds) {
seriesBuilder.append("{name:'").append(alias)
.append("',y:").append(playtimePerAlias.getOrDefault(alias, 0L))
.append(",drilldown: '").append(alias).append("'");
seriesBuilder.append("}");
if (i < size - 1) {
@ -52,6 +53,28 @@ public class WorldPieCreator {
return new String[]{seriesData, drilldownData};
}
private static Map<String, Long> transformToAliases(Map<String, Long> playtimePerWorld) {
// TODO Optimization is possible
WorldAliasSettings aliasSettings = new WorldAliasSettings(Plan.getInstance());
Map<String, String> aliases = aliasSettings.getAliases();
Map<String, Long> playtimePerAlias = new HashMap<>();
for (Map.Entry<String, Long> entry : playtimePerWorld.entrySet()) {
String worldName = entry.getKey();
long playtime = entry.getValue();
if (!aliases.containsKey(worldName)) {
aliases.put(worldName, worldName);
aliasSettings.addWorld(worldName);
}
String alias = aliases.get(worldName);
playtimePerAlias.put(alias, playtimePerAlias.getOrDefault(alias, 0L) + playtime);
}
return playtimePerAlias;
}
private static String createDrilldownData(WorldTimes worldTimes) {
StringBuilder drilldownBuilder = new StringBuilder();
int i = 0;
@ -60,15 +83,17 @@ public class WorldPieCreator {
if (gmTimesMap.isEmpty()) {
return "[]";
}
Map<String, GMTimes> gmTimesAliasMap = transformToGMAliases(gmTimesMap);
int size = gmTimesMap.size();
drilldownBuilder.append("[");
for (Map.Entry<String, GMTimes> world : gmTimesMap.entrySet()) {
drilldownBuilder.append("{name:'").append(world.getKey())
.append("', id:'").append(world.getKey())
for (Map.Entry<String, GMTimes> worldAlias : gmTimesAliasMap.entrySet()) {
drilldownBuilder.append("{name:'").append(worldAlias.getKey())
.append("', id:'").append(worldAlias.getKey())
.append("',colors: gmPieColors,");
drilldownBuilder.append("data: [");
appendGMTimesForWorld(drilldownBuilder, world);
appendGMTimesForWorld(drilldownBuilder, worldAlias);
if (i < size - 1) {
drilldownBuilder.append(",");
@ -79,6 +104,35 @@ public class WorldPieCreator {
return drilldownBuilder.toString();
}
private static Map<String, GMTimes> transformToGMAliases(Map<String, GMTimes> gmTimesMap) {
// TODO Optimization is possible
WorldAliasSettings aliasSettings = new WorldAliasSettings(Plan.getInstance());
Map<String, String> aliases = aliasSettings.getAliases();
Map<String, GMTimes> gmTimesPerAlias = new HashMap<>();
String[] gms = GMTimes.getGMKeyArray();
for (Map.Entry<String, GMTimes> entry : gmTimesMap.entrySet()) {
String worldName = entry.getKey();
GMTimes gmTimes = entry.getValue();
if (!aliases.containsKey(worldName)) {
aliases.put(worldName, worldName);
aliasSettings.addWorld(worldName);
}
String alias = aliases.get(worldName);
GMTimes aliasGMtimes = gmTimesPerAlias.getOrDefault(alias, new GMTimes());
for (String gm : gms) {
aliasGMtimes.addTime(gm, gmTimes.getTime(gm));
}
gmTimesPerAlias.put(alias, aliasGMtimes);
}
return gmTimesPerAlias;
}
private static void appendGMTimesForWorld(StringBuilder drilldownBuilder, Map.Entry<String, GMTimes> world) {
Map<String, Long> gmTimes = world.getValue().getTimes();
int smallSize = gmTimes.size();

View File

@ -5,15 +5,13 @@
package main.java.com.djrapitops.plan.utilities.html.structure;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.analysis.JoinInfoPart;
import main.java.com.djrapitops.plan.data.time.GMTimes;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import main.java.com.djrapitops.plan.utilities.comparators.SessionStartComparator;
import main.java.com.djrapitops.plan.utilities.html.Html;
import main.java.com.djrapitops.plan.utilities.html.HtmlStructure;
@ -21,7 +19,6 @@ import main.java.com.djrapitops.plan.utilities.html.graphs.WorldPieCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.KillsTableCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.SessionsTableCreator;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
@ -37,7 +34,7 @@ public class SessionTabStructureCreator {
Map<Integer, UUID> uuidsByID = generateIDtoUUIDMap(sessions);
if (Settings.DISPLAY_SESSIONS_AS_TABLE.isTrue()) {
return new String[]{Html.TABLE_SESSIONS.parse(SessionsTableCreator.createTable(uuidsByID, allSessions)[0]), ""};
return new String[]{Html.TABLE_SESSIONS.parse("", "", "", SessionsTableCreator.createTable(uuidsByID, allSessions)[0]), ""};
}
if (Verify.isEmpty(allSessions)) {
@ -113,19 +110,7 @@ public class SessionTabStructureCreator {
html.append("<div id=\"").append(id).append("\" style=\"width: 100%; height: 400px;\"></div>");
WorldTimes worldTimes = session.getWorldTimes();
try {
// Add 0 time for worlds not present.
Set<String> nonZeroWorlds = worldTimes.getWorldTimes().keySet();
for (String world : MiscUtils.getIPlan().getDB().getWorldTable().getWorlds()) {
if (nonZeroWorlds.contains(world)) {
continue;
}
worldTimes.setGMTimesForWorld(world, new GMTimes());
}
} catch (SQLException e) {
Log.toLog("SessionTabStructureCreator", e);
}
AnalysisUtils.addMissingWorlds(worldTimes);
String[] worldData = WorldPieCreator.createSeriesData(worldTimes);

View File

@ -1,4 +1,4 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.PlanBungee
version: 4.0.3
version: 4.0.4

View File

@ -67,6 +67,8 @@ Customization:
Minutes: '%minutes%m '
Seconds: '%seconds%s'
Zero: '0s'
WorldAliases:
world: world
Theme:
Base: Default

View File

@ -85,8 +85,8 @@
${playersActive} Active Players<br>
${playersTotal} Total Players<br>
<br>
Peak Time: ${lastPeakTime}<br>
Last Peak: ${playersLastPeak} Players<br>
<b>Last Peak:</b>
${lastPeakTime}: ${playersLastPeak} Players<br>
<br>
<b>All Time Peak:</b><br>
${bestPeakTime}: ${playersBestPeak} Players

View File

@ -0,0 +1,118 @@
Analysis - Third Party || Analyse | Analyse des sources de données supplémentaires (tierce partie).
Analysis FAIL - Fetch Exception || Analyse | Échec de lextraction des données pour lanalyse, une exception s'est produite.
Analysis FAIL - No Data || Analyse | L'analyse a échoué, aucune donnée dans la base de données.
Analysis FAIL - No Players || Analyse | L'analyse a échoué, aucun joueur connu.
Analysis - Fetch Phase || Analyse | Récupération des données..
Analysis - Fetch Phase Start || Analyse | Vérification des joueurs disponibles..
Analysis - Complete || Analyse | Analyse terminée. (En ${0}ms) ${1}
Analysis - Begin Analysis || Analyse | Données récupérées (${0} utilisateurs, en ${1}ms), début Analyse des données..
Analysis - Start || Analyse | Début de l'analyse des données utilisateur..
>Constant - CMD Footer || §f»
>Constant - List Ball || §7 •§2
Cmd FAIL - No Data View || §e[Plan] Aucun moyen de voir les données disponibles.
Cmd FAIL - No Permission || §c[Plan] Vous n'avez pas la permission requise.
Cmd FAIL - Requires Arguments || §c[Plan] La commande nécessite des arguments. ${0}
Cmd FAIL - Require only one Argument || §c[Plan] La commande nécessite un argument.
Cmd FAIL - Timeout || §c[Plan] ${0} La commande a expiré ! Vérifiez avec '/plan status' et la console.
Cmd FAIL - Unknown Username || §c[Plan] Joueur introuvable dans la base de données.
Cmd FAIL - Unseen Username || §c[Plan] Ce joueur n'a pas joué sur ce serveur.
Cmd FAIL - Invalid Username || §c[Plan] Ce joueur n'existe pas.
Cmd Header - Analysis || §f»§2 Player Analytics - Résultats de lanalyse
Cmd Header - Info || §f»§2 Player Analytics - Info
Cmd Header - Inspect || §f»§2 Player Analytics - Résultats de linspection
Cmd Header - Search || §f»§2 Player Analytics - Résultats de la recherche:
In Depth Help - /plan analyze ? || §2Commande danalyse\§f Utilisé pour actualiser le cache d'analyse et accéder à la page de résultats\§7 /plan status peut être utilisé pour vérifier le statut de l'analyse pendant son exécution.\§7 Alias: analyze, analyse, analysis, a
In Depth Help - /plan inspect ? || §2Commande dinspection\§f Utilisé pour obtenir un lien vers la page d'inspection dun utilisateur.\§7 Votre propre page d'inspection peut être consultée avec /plan inspect\§7 Alias: /plan <nom>
In Depth Help - /plan list ? || §2Commande de listing\§f Utilisé pour obtenir un lien vers la page des joueurs.\§7 La page des joueurs contient des liens vers toutes les pages d'inspection mises en cache.\§7 Alias: /plan pl
In Depth Help - /plan manage ? || §2Commande de gestion\§f Utilisé pour gérer la base de données du plugin.\§7 Alias: /plan m\§7 /plan m - Liste des sous-commandes\§7 /plan m <sous-commande> ? - aide approfondie
In Depth Help - /plan manage clear ? || §2Gestion: Commande deffacement.\§f Utilisé pour supprimer TOUTES les données dans la base de données active.\§7 Le plugin doit être rechargé après leffacement terminé.\§7 Alias: /plan pl
In Depth Help - /plan manage dump ? || §2Gestion: Commande de listage\§f Utilisé pour lister des données importantes pour le rapport de bug à hastebin.
In Depth Help - /plan manage hotswap ? || §2Gestion: Commande de Hotswap\§f Utilisé pour modifier la base de données en cours d'utilisation.\§7 Ne change pas la base de données si la connexion échoue.
In Depth Help - /plan manage import ? || §2Gestion: Commande d'importation\§f Utilisé pour importer des données d'autres sources\§7 L'analyse sera désactivée pendant l'importation.
In Depth Help - /plan manage remove ? || §2Gestion: Commande de suppression\§f Utilisé pour supprimer les données de l'utilisateur de la base de données active.
In Depth Help - /plan ? || §2/plan - Commande principale\§f Utilisé pour accéder à toutes les sous-commandes et aide\§7 /plan - Liste des sous-commandes\§7 /plan <sous-commande> ? - aide approfondie
In Depth Help - /plan qanalyze ? || §2Commande d'analyse rapide\§f Utilisé pour obtenir des informations en jeu sur l'analyse.\§7 A moins d'informations que la page Web d'analyse complète.\§7 Alias: qanalyze, ganalyse, qanalysis, qa
In Depth Help - /plan qinspect ? || §2Commande d'inspection rapide\§f Utilisé pour obtenir des informations d'inspection en jeu.\§7 A moins d'informations que la page Web d'inspection complète.\§7 Alias: /plan qi
In Depth Help - /plan search ? || §2Commande de recherche\§f Utilisé pour obtenir une liste des noms de joueurs qui correspondent à l'argument donné.\§7 Exemple: /plan search 123 - Trouve tous les utilisateurs avec 123 dans leur nom.
In Depth Help - /plan webuser ? || §2Commande de gestion des utilisateurs Web\§f Utilisé pour gérer les utilisateurs Web du plugin\§7 Les utilisateurs ont un niveau de permission:\§f 0 - Accès à toutes les pages\§f 1 - Accès à /players et toutes les pages d'inspection\§f 2 - Accès à sa propre page d'inspection\§7 Alias: /plan web
In Depth Help - /plan webuser register ? || §2Commande Web Register\§f Utilisé pour enregistrer un nouvel utilisateur pour le serveur Web.\§7 L'inscription d'un utilisateur pour un autre joueur nécessite la permission plan.webmanage.\§7 Les mots de passe sont hachés avec PBKDF2 (64,000 itérations de SHA1) en utilisant un sel cryptographiquement aléatoire.
Analysis NOTIFY - Temporary Disable || §eL'analyse a été temporairement désactivée en raison dun charge trop importante, faites /plan status pour plus d'informations.
Cmd - Click Me || Cliquez ici
Cmd - Fetch Data || §f»§2 Récupération des données dans le cache..
Cmd - Link || §7 • §2Lien: §f
Cmd - No Results || §7 • §2Aucun résultat pour §7${0}§2.
Cmd - Reload Success || §a[Plan] Recharge terminée.
Cmd - Results || §7 Joueurs correspondants: §f
Cmd - Searching || §f»§2Recherche..
Cmd - Usage /plan analyze || Voir l'analyse du serveur
Cmd - Usage /plan help || Afficher la liste des commandes.
Cmd - Usage /plan info || Vérifier la version de of Plan
Cmd - Usage /plan inspect || Inspecter les données du joueur
Cmd - Usage /plan list || Liste à tous les joueurs mis en cache
Cmd - Usage /plan manage || Commande de gestion de base de données
Cmd - Usage /plan manage backup || Sauvegarder une base de données dans un fichier .db
Cmd - Usage /plan manage clean || Effacer les anciennes données de la base de données
Cmd - Usage /plan manage clear || Effacer TOUTES les données de la base de données
Cmd - Usage /plan manage dump || Créez un journal Hastebin pour les développeurs pour faciliter le rapport de bug
Cmd - Usage /plan manage hotswap || Hot Swap à une autre base de données et redémarrer le plugin
Cmd - Usage /plan manage import || Importer des données depuis les plugins pris en charge vers la base de données active.
Cmd - Usage /plan manage move || Copier les données d'une base de données à une autre et remplacer les valeurs
Cmd - Usage /plan manage remove || Supprimer les données des joueurs de la base de données active.
Cmd - Usage /plan manage restore || Restaurer une base de données à partir d'un fichier de sauvegarde
Cmd - Usage /plan qanalyze || Voir l'analyse du serveur sous forme de texte
Cmd - Usage /plan qinspect || Inspecter les données du joueur sous forme de texte
Cmd - Usage /plan reload || Redémarrer le plugin (Recharge la configuration)
Cmd - Usage /plan search || Rechercher un joueur
Cmd - Usage /plan webuser || Gérer les utilisateurs Web
Cmd - Usage /plan webuser check || Vérifiez un utilisateur Web et son niveau de permission.
Cmd - Usage /plan webuser delete || Supprimer un utilisateur Web
Cmd - Usage /plan webuser level || Informations sur les niveaux de permission.
Cmd - Usage /plan webuser register || Enregistrer un utilisateur pour le serveur Web
Disable || Player Analytics Désactivé.
Disable - Save || Sauvegarde des données mises en cache..
Disable - WebServer || Arrêt du serveur Web..
Enable || Player Analytics Activé.
Enable - Boot Analysis 30s Notify || Analyse | Analyse de démarrage dans 30 secondes..
Enable - Boot Analysis Notify || Analyse | Démarrage l'analyse de démarrage..
Enable Db FAIL - Disable Info || L'initialisation de la base de données a échoué, désactivation de Plan.
Enable - Db Info || ${0}-connexion à la base de données établie.
Enable - Db || Initialisation de la base de données..
Enable FAIL-Db || ${0}-Connexion à la base de données échouée: ${1}
Enable FAIL - Wrong Db Type || Ce type de base de données n'existe pas.
Enable Notify - ChatListener || §eÉcouteur de chat désactivé, information de pseudo inexacte.
Enable Notify - Disabled CommandListener || §eÉcouteur d'utilisation des commandes désactivé.
Enable Notify - Disabled DeathListener || §eÉcouteur de morts désactivé, morts de joueur et de mob non enregistrées..
Enable Notify-Empty IP || §eLIP dans server.properties est vide et AlternativeServerIP n'est pas utilisé, des liens incorrects seront donnés !
Enable Notify - No data view || §eServeur Web désactivé mais AlternativeIP non utilisé, aucun moyen d'afficher les données !
Enable - WebServer || Initialisation du serveur Web..
Enable - WebServer Info || Serveur Web en cours d'exécution sur le PORT ${0}
Html - Active || Le joueur est actif
Html - Banned || | <span class="darkred">Banni</span>
Html - Inactive || Le joueur est inactif
Html - No Extra Plugins || <p>Aucun plugin supplémentaire enregistré.</p>
Html - Offline || | <span class="darkred">Hors ligne</span>
Html - Online || | <span class="darkgreen">En ligne</span>
Html - OP || , Opérateur (Op)
Html - Table No Kills || Pas de kills
Manage FAIL - Confirm Action || §c[Plan] Ajoutez -a pour confirmer l'exécution ! ${0}
Manage FAIL - Faulty DB Connection || §c[Plan] Une des bases de données n'a pas été initialisée correctement.
Manage FAIL - Backup File Not Found || §c[Plan] Le fichier de sauvegarde n'existe pas !
Manage FAIL - Incorrect DB || §c[Plan] Base de données incorrecte ! (sqlite/mysql accepté):
Manage FAIL - Incorrect Plugin || §c[Plan] Plugin non supporté:
Manage FAIL - Empty DB || §c[Plan] La base de données n'a pas de données de joueur !
Manage FAIL - Unenabled Plugin || §c[Plan] Le plugin n'est pas activé:
Manage FAIL - Same DB || §c[Plan] Impossible de passer à la même base de données !
Manage - Clear Success || §a[Plan] Toutes les données ont été effacées avec succès!
Manage - Remind Config Change || §e[Plan] N'oubliez pas de basculer vers la nouvelle base de données et de recharger le plugin
Manage - Copy Success || §a[Plan] Toutes les données ont été copiées avec succès !
Manage - Process Fail || §c[Plan] Quelque chose s'est mal passé pendant le traitement des données !
Manage - Import || §f» §2 Importation de données..
Manage - Move Success || §a[Plan] Toutes les données ont été déplacées avec succès !
Manage - Remove Success || §f» §2Les données de §f${0}§2 ont été supprimées de la base de données §f${1}§2.
Manage - Start || »§7 Traitement des données..
Manage - Success || §f» §2 Succès !
Manage NOTIFY - Overwrite || Les données dans la base de données ${0} seront écrasées !
Manage NOTIFY - Partial Overwrite || Quelques données dans la base de données ${0} seront écrasées !
Manage NOTIFY - Remove || Les données dans la base de données ${0} seront supprimées !
Manage NOTIFY - Rewrite || Les données dans la base de données ${0} seront réécrites !
WARN - Too Small Queue Size || La taille de la file d'attente est trop petite ! (${0}), changez le réglage à un nombre plus élevé ! (Actuellement ${1})

View File

@ -219,7 +219,9 @@ th.text {
}
tr:nth-child(even) {background: #e2e2e2}
tr:nth-child(odd) {background: #eee}
tr {
color: #000;
}
.main-limiter {
width: 100%;

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.Plan
version: 4.0.3
version: 4.0.4
softdepend:
- OnTime
- EssentialsX

View File

@ -876,4 +876,9 @@ public class DatabaseTest {
assertTrue(db.getUsersTable().isRegistered(uuid));
assertTrue(db.getUserInfoTable().isRegistered(uuid));
}
@Test
public void testWorldTableGetWorldNamesNoException() throws SQLException {
Set<String> worldNames = db.getWorldTable().getWorldNames();
}
}