Merge pull request #432 from Rsl1122/4.1.0

Pull Request for 4.1.0
This commit is contained in:
Rsl1122 2017-12-02 16:37:44 +02:00 committed by GitHub
commit 37283c5b44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
637 changed files with 138817 additions and 8377 deletions

View File

@ -1,13 +0,0 @@
<component name="libraryTable">
<library name="Maven: com.destroystokyo.paper:paper:1.12-R0.1-SNAPSHOT">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/destroystokyo/paper/paper/1.12-R0.1-SNAPSHOT/paper-1.12-R0.1-20170725.202533-1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/destroystokyo/paper/paper/1.12-R0.1-SNAPSHOT/paper-1.12-R0.1-20170725.202533-1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/destroystokyo/paper/paper/1.12-R0.1-SNAPSHOT/paper-1.12-R0.1-20170725.202533-1-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.djrapitops</groupId>
<artifactId>Plan</artifactId>
<version>4.0.7</version>
<version>4.1.0</version>
<packaging>jar</packaging>
<repositories>
<repository>
@ -17,15 +17,29 @@
</repository>
<repository>
<id>paper-repo</id>
<url>https://repo.destroystokyo.com/content/repositories/snapshots/</url>
<url>https://repo.destroystokyo.com/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<!-- PaperSpigot -->
<!-- Framework for easier plugin development -->
<dependency>
<groupId>com.djrapitops</groupId>
<artifactId>abstract-plugin-framework</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>
<!-- SoftDepended Plugins -->
<dependency>
<groupId>com.djrapitops</groupId>
<artifactId>PlanPluginBridge</artifactId>
<version>4.1.0</version>
<scope>compile</scope>
</dependency>
<!-- Full PaperSpigot JAR -->
<dependency>
<groupId>com.destroystokyo.paper</groupId>
<artifactId>paper-api</artifactId>
<version>LATEST</version>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Spigot -->
@ -36,6 +50,12 @@
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- BungeeCord -->
<dependency>
<groupId>net.md-5</groupId>
@ -57,13 +77,6 @@
<artifactId>geoip2</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Framework for easier plugin development -->
<dependency>
<groupId>com.djrapitops</groupId>
<artifactId>abstract-plugin-framework</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>
<!-- Connection Pool -->
<dependency>
<groupId>org.apache.commons</groupId>
@ -83,13 +96,6 @@
<version>1.2</version>
<scope>compile</scope>
</dependency>
<!-- SoftDepended Plugins -->
<dependency>
<groupId>com.djrapitops</groupId>
<artifactId>PlanPluginBridge</artifactId>
<version>4.0.5</version>
<scope>compile</scope>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.powermock</groupId>
@ -158,29 +164,17 @@
<targetPath>.</targetPath>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>*.keystore</include>
<include>*.css</include>
<include>*.yml</include>
<include>*.html</include>
<include>**/*.keystore</include>
<include>**/*.css</include>
<include>**/*.yml</include>
<include>**/*.html</include>
<include>**/*.js</include>
<include>**/*.css</include>
</includes>
<excludes>
<exclude>licence.yml</exclude>
</excludes>
</resource>
<resource>
<targetPath>.</targetPath>
<directory>${basedir}/src/main/resources/html</directory>
<includes>
<include>*.html</include>
</includes>
</resource>
<resource>
<targetPath>.</targetPath>
<directory>${basedir}/src/main/resources/js</directory>
<includes>
<include>*.js</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>

View File

@ -1,21 +1,21 @@
/*
* Player Analytics Bukkit plugin for monitoring server activity.
* Copyright (C) 2017 Risto Lahtela / Rsl1122
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Plan License. (licence.yml)
* Modified software can only be redistributed if allowed in the licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License for more details.
*
* You should have received a copy of the License
* along with this program.
* If not it should be visible on the distribution page.
* Or here
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/licence.yml
* Player Analytics Bukkit plugin for monitoring server activity.
* Copyright (C) 2017 Risto Lahtela / Rsl1122
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Plan License. (licence.yml)
* Modified software can only be redistributed if allowed in the licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License for more details.
*
* You should have received a copy of the License
* along with this program.
* If not it should be visible on the distribution page.
* Or here
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/licence.yml
*/
package main.java.com.djrapitops.plan;
@ -40,12 +40,14 @@ import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.api.exceptions.PlanEnableException;
import main.java.com.djrapitops.plan.command.PlanCommand;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.plugin.HookHandler;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.MySQLDB;
import main.java.com.djrapitops.plan.database.databases.SQLiteDB;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.settings.theme.Theme;
import main.java.com.djrapitops.plan.systems.cache.DataCache;
import main.java.com.djrapitops.plan.systems.cache.GeolocationCache;
import main.java.com.djrapitops.plan.systems.info.BukkitInformationManager;
@ -60,6 +62,7 @@ import main.java.com.djrapitops.plan.systems.tasks.TPSCountTimer;
import main.java.com.djrapitops.plan.systems.webserver.PageCache;
import main.java.com.djrapitops.plan.systems.webserver.WebServer;
import main.java.com.djrapitops.plan.utilities.file.FileUtil;
import main.java.com.djrapitops.plan.utilities.file.export.HtmlExport;
import main.java.com.djrapitops.plan.utilities.metrics.BStats;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
@ -86,6 +89,7 @@ public class Plan extends BukkitPlugin implements IPlan {
private API api;
private Config config;
private Theme theme;
private ProcessingQueue processingQueue;
private HookHandler hookHandler; // Manages 3rd party data sources
@ -144,7 +148,9 @@ public class Plan extends BukkitPlugin implements IPlan {
public void onEnable() {
super.onEnable();
try {
File configFile = new File(getDataFolder(), "config.yml");
File dataFolder = getDataFolder();
dataFolder.mkdirs();
File configFile = new File(dataFolder, "config.yml");
config = new Config(configFile);
config.copyDefaults(FileUtil.lines(this, "config.yml"));
config.save();
@ -179,6 +185,8 @@ public class Plan extends BukkitPlugin implements IPlan {
new Locale(this).loadLocale();
theme = new Theme();
Benchmark.start("Reading server variables");
serverVariableHolder = new ServerVariableHolder(getServer());
Benchmark.stop("Enable", "Reading server variables");
@ -198,7 +206,12 @@ public class Plan extends BukkitPlugin implements IPlan {
webServer.initServer();
if (!webServer.isEnabled()) {
Log.error("WebServer was not successfully initialized. Is the port (" + Settings.WEBSERVER_PORT.getNumber() + ") in use?");
if (Settings.WEBSERVER_DISABLED.isTrue()) {
Log.warn("WebServer was not initialized. (WebServer.DisableWebServer: true)");
} else {
Log.error("WebServer was not initialized successfully. Is the port (" + Settings.WEBSERVER_PORT.getNumber() + ") in use?");
}
}
serverInfoManager.updateServerInfo();
@ -239,6 +252,9 @@ public class Plan extends BukkitPlugin implements IPlan {
Log.info(Locale.get(Msg.ENABLED).toString());
StaticHolder.saveInstance(ShutdownHook.class, this.getClass());
new ShutdownHook(this);
if (Settings.ANALYSIS_EXPORT.isTrue()) {
RunnableFactory.createNew(new HtmlExport(this)).runTaskAsynchronously();
}
} catch (Exception e) {
Log.error("Plugin Failed to Initialize Correctly.");
Log.toLog(this.getClass().getName(), e);
@ -560,4 +576,9 @@ public class Plan extends BukkitPlugin implements IPlan {
public API getApi() {
return api;
}
@Override
public Theme getTheme() {
return theme;
}
}

View File

@ -21,8 +21,10 @@ import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.command.PlanBungeeCommand;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.MySQLDB;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.settings.theme.Theme;
import main.java.com.djrapitops.plan.systems.info.BungeeInformationManager;
import main.java.com.djrapitops.plan.systems.info.InformationManager;
import main.java.com.djrapitops.plan.systems.info.server.BungeeServerInfoManager;
@ -32,6 +34,7 @@ import main.java.com.djrapitops.plan.systems.queue.ProcessingQueue;
import main.java.com.djrapitops.plan.systems.tasks.TPSCountTimer;
import main.java.com.djrapitops.plan.systems.webserver.WebServer;
import main.java.com.djrapitops.plan.utilities.file.FileUtil;
import main.java.com.djrapitops.plan.utilities.file.export.HtmlExport;
import net.md_5.bungee.api.ChatColor;
import java.io.File;
@ -48,6 +51,7 @@ import java.util.UUID;
public class PlanBungee extends BungeePlugin implements IPlan {
private Config config;
private Theme theme;
private WebServer webServer;
private Database db;
@ -87,6 +91,8 @@ public class PlanBungee extends BungeePlugin implements IPlan {
new Locale(this).loadLocale();
theme = new Theme();
Log.info(Locale.get(Msg.ENABLE_DB_INIT).toString());
initDatabase();
@ -136,6 +142,9 @@ public class PlanBungee extends BungeePlugin implements IPlan {
Log.logDebug("Enable", "WebServer Initialization");
Log.info(Locale.get(Msg.ENABLED).toString());
if (Settings.ANALYSIS_EXPORT.isTrue()) {
RunnableFactory.createNew(new HtmlExport(this)).runTaskAsynchronously();
}
} catch (Exception e) {
Log.error("Plugin Failed to Initialize Correctly.");
Log.toLog(this.getClass().getName(), e);
@ -257,4 +266,8 @@ public class PlanBungee extends BungeePlugin implements IPlan {
return serverInfoManager.getServerUUID();
}
@Override
public Theme getTheme() {
return theme;
}
}

View File

@ -1,5 +1,6 @@
package main.java.com.djrapitops.plan;
import main.java.com.djrapitops.plan.settings.Settings;
import net.md_5.bungee.api.ProxyServer;
import org.bukkit.Server;

View File

@ -7,8 +7,8 @@ package main.java.com.djrapitops.plan;
import com.djrapitops.plugin.StaticHolder;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.data.Action;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.container.Action;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.database.databases.SQLDB;
import main.java.com.djrapitops.plan.database.tables.Actions;
import main.java.com.djrapitops.plan.database.tables.SessionsTable;

View File

@ -3,8 +3,7 @@ package main.java.com.djrapitops.plan.api;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.AnalysisData;
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.plugin.PluginData;
import main.java.com.djrapitops.plan.systems.info.BukkitInformationManager;
import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;
import org.bukkit.OfflinePlayer;
@ -82,8 +81,8 @@ public class API {
* @return {@code ../player/PlayerName}
*/
public String getPlayerInspectPageLink(String name) {
String link = "../player/" + name;
return link.replace(" ", "%20").replace(".", "%2E");
String link = "../player/" + name.replace(" ", "%20").replace(".", "%2E");
return link;
}
/**

View File

@ -9,6 +9,7 @@ import com.djrapitops.plugin.api.config.Config;
import com.djrapitops.plugin.settings.ColorScheme;
import main.java.com.djrapitops.plan.ServerVariableHolder;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.settings.theme.Theme;
import main.java.com.djrapitops.plan.systems.info.InformationManager;
import main.java.com.djrapitops.plan.systems.processing.Processor;
import main.java.com.djrapitops.plan.systems.queue.ProcessingQueue;
@ -45,4 +46,6 @@ public interface IPlan extends IPlugin {
Config getMainConfig();
ColorScheme getColorScheme();
Theme getTheme();
}

View File

@ -3,11 +3,11 @@ package main.java.com.djrapitops.plan.command;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.TreeCommand;
import com.djrapitops.plugin.command.defaultcmds.StatusCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.PlanBungee;
import main.java.com.djrapitops.plan.command.commands.*;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* TreeCommand for the /plan command, and all subcommands.

View File

@ -3,12 +3,12 @@ package main.java.com.djrapitops.plan.command;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.TreeCommand;
import com.djrapitops.plugin.command.defaultcmds.StatusCommand;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.command.commands.*;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* TreeCommand for the /plan command, and all subcommands.

View File

@ -8,10 +8,10 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.info.InformationManager;
import main.java.com.djrapitops.plan.systems.info.server.ServerInfo;
import org.bukkit.ChatColor;

View File

@ -9,8 +9,8 @@ import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.WebAPIException;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.webserver.webapi.WebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.InspectWebAPI;
import main.java.com.djrapitops.plan.utilities.Condition;

View File

@ -4,10 +4,10 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* This subcommand is used to view the version and the database type in use.

View File

@ -8,11 +8,11 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.command.ConditionUtils;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.processing.info.InspectCacheRequestProcessor;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.MiscUtils;

View File

@ -4,9 +4,9 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.CommandUtils;
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.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
/**

View File

@ -5,10 +5,10 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import java.sql.SQLException;
import java.util.Map;
@ -45,7 +45,7 @@ public class ListServersCommand extends SubCommand {
String tCol = colorScheme.getTertiaryColor();
try {
sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString() + mCol + " Servers");
Map<Integer, String> serverNames = plugin.getDB().getServerTable().getServerNames();
Map<Integer, String> serverNames = plugin.getDB().getServerTable().getServerNamesByID();
for (Map.Entry<Integer, String> entry : serverNames.entrySet()) {
sender.sendMessage(" " + tCol + entry.getKey() + sCol + " : " + entry.getValue());
}

View File

@ -2,11 +2,11 @@ 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.command.commands.manage.*;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* This command is used to manage the database of the plugin.
@ -43,7 +43,6 @@ public class ManageCommand extends TreeCommand<Plan> {
new ManageImportCommand(plugin),
new ManageRemoveCommand(plugin),
new ManageClearCommand(plugin),
new ManageDumpCommand(plugin),
new ManageSetupCommand(plugin),
new ManageDisableCommand()
);

View File

@ -4,10 +4,10 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.CommandUtils;
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.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* Command used to display link to the player list webpage.

View File

@ -0,0 +1,123 @@
package main.java.com.djrapitops.plan.command.commands;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import com.djrapitops.plugin.settings.DefaultMessages;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.command.ConditionUtils;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;
import java.sql.SQLException;
import java.util.UUID;
/**
* This command is used to cache UserInfo to InspectCache and display the link.
*
* @author Rsl1122
* @since 1.0.0
*/
public class QInspectCommand extends SubCommand {
private final Plan plugin;
/**
* Class Constructor.
*
* @param plugin Current instance of Plan
*/
public QInspectCommand(Plan plugin) {
super("qinspect",
CommandType.PLAYER_OR_ARGS,
Permissions.QUICK_INSPECT.getPermission(),
Locale.get(Msg.CMD_USG_QINSPECT).toString(),
"<player>");
this.plugin = plugin;
}
@Override
public String[] addHelp() {
return Locale.get(Msg.CMD_HELP_QINSPECT).toArray();
}
@Override
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
String playerName = MiscUtils.getPlayerName(args, sender, Permissions.QUICK_INSPECT_OTHER);
runInspectTask(playerName, sender);
return true;
}
private void runInspectTask(String playerName, ISender sender) {
RunnableFactory.createNew(new AbsRunnable("InspectTask") {
@Override
public void run() {
try {
UUID uuid = UUIDUtility.getUUIDOf(playerName);
if (!Condition.isTrue(Verify.notNull(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_VALID).toString(), sender)) {
return;
}
if (!Condition.isTrue(ConditionUtils.playerHasPlayed(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_SEEN).toString(), sender)) {
return;
}
if (!Condition.isTrue(plugin.getDB().wasSeenBefore(uuid), Locale.get(Msg.CMD_FAIL_USERNAME_NOT_KNOWN).toString(), sender)) {
return;
}
PlayerProfile playerProfile = plugin.getDB().getPlayerProfile(uuid);
sendMsgs(sender, playerProfile);
} catch (SQLException ex) {
Log.toLog(this.getClass().getName(), ex);
} finally {
this.cancel();
}
}
}).runTaskAsynchronously();
}
private void sendMsgs(ISender sender, PlayerProfile profile) {
long now = MiscUtils.getTime();
ColorScheme colorScheme = plugin.getColorScheme();
String colM = colorScheme.getMainColor();
String colS = colorScheme.getSecondaryColor();
String colT = colorScheme.getTertiaryColor();
String ball = DefaultMessages.BALL.parse();
sender.sendMessage(Locale.get(Msg.CMD_HEADER_INSPECT).toString() + ": " + colT + profile.getName());
double activityIndex = profile.getActivityIndex(now);
sender.sendMessage(colT + ball + " " + colM + " Activity Index: " + colS + FormatUtils.cutDecimals(activityIndex) + " | " + FormatUtils.readableActivityIndex(activityIndex)[1]);
sender.sendMessage(colT + ball + " " + colM + " Registered: " + colS + profile.getRegistered());
sender.sendMessage(colT + ball + " " + colM + " Last Seen: " + colS + profile.getLastSeen());
sender.sendMessage(colT + ball + " " + colM + " Logged in from: " + colS + profile.getMostRecentGeoInfo().getGeolocation());
sender.sendMessage(colT + ball + " " + colM + " Playtime: " + colS + profile.getTotalPlaytime());
sender.sendMessage(colT + ball + " " + colM + " Longest Session: " + colS + profile.getLongestSession(0, now));
sender.sendMessage(colT + ball + " " + colM + " Times Kicked: " + colS + profile.getTimesKicked());
sender.sendMessage("");
sender.sendMessage(colT + ball + " " + colM + " Player Kills : " + colS + profile.getPlayerKills().count());
sender.sendMessage(colT + ball + " " + colM + " Mob Kills : " + colS + profile.getMobKillCount());
sender.sendMessage(colT + ball + " " + colM + " Deaths : " + colS + profile.getDeathCount());
sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString());
}
}

View File

@ -8,12 +8,12 @@ import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;

View File

@ -1,12 +1,13 @@
package main.java.com.djrapitops.plan.command.commands;
import com.djrapitops.plugin.api.utility.log.Log;
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.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* This subcommand is used to reload the plugin.
@ -34,7 +35,14 @@ public class ReloadCommand extends SubCommand {
@Override
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
plugin.reloadPlugin(true);
try {
plugin.reloadPlugin(true);
} catch (Exception e) {
sender.sendMessage("§cSomething went wrong during reload of the plugin, a restart is recommended.");
String address = plugin.getWebServer().getAccessAddress() + "/debug";
sender.sendLink("More info can be found at ", address, address);
Log.toLog(this.getClass().getName(), e);
}
sender.sendMessage(Locale.get(Msg.CMD_INFO_RELOAD_COMPLETE).toString());
return true;
}

View File

@ -7,10 +7,10 @@ import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.FormatUtils;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.MiscUtils;

View File

@ -2,7 +2,6 @@ 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;
@ -10,8 +9,9 @@ import main.java.com.djrapitops.plan.command.commands.webuser.WebCheckCommand;
import main.java.com.djrapitops.plan.command.commands.webuser.WebDeleteCommand;
import main.java.com.djrapitops.plan.command.commands.webuser.WebLevelCommand;
import main.java.com.djrapitops.plan.command.commands.webuser.WebListUsersCommand;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* Web subcommand used to manage Web users.

View File

@ -7,12 +7,12 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.ManageUtils;

View File

@ -7,13 +7,13 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.cache.DataCache;
import main.java.com.djrapitops.plan.systems.cache.SessionCache;
import main.java.com.djrapitops.plan.utilities.Condition;

View File

@ -3,9 +3,9 @@ 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.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.listeners.PlanPlayerListener;
import main.java.com.djrapitops.plan.utilities.Condition;

View File

@ -1,63 +0,0 @@
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 com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.utilities.file.dump.DumpUtils;
/**
* This manage subcommand is used to dump important data to pastebin, so it's
* easier to write an issue.
*
* @author Fuzzlemann
* @since 3.7.0
*/
public class ManageDumpCommand extends SubCommand {
private final Plan plugin;
/**
* Class Constructor.
*
* @param plugin Current instance of Plan
*/
public ManageDumpCommand(Plan plugin) {
super("dump",
CommandType.CONSOLE,
Permissions.MANAGE.getPermission(),
Locale.get(Msg.CMD_USG_MANAGE_DUMP).toString());
this.plugin = plugin;
}
@Override
public String[] addHelp() {
return Locale.get(Msg.CMD_HELP_MANAGE_DUMP).toArray();
}
@Override
public boolean onCommand(ISender sender, String commandLabel, String[] args) {
dump(sender);
return true;
}
private void dump(ISender sender) {
RunnableFactory.createNew(new AbsRunnable("DumpTask") {
@Override
public void run() {
try {
sender.sendLink("Link to the Dump", DumpUtils.dump(plugin));
sender.sendLink("Report Issues here", "https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/new");
} finally {
this.cancel();
}
}
}).runTaskAsynchronously();
}
}

View File

@ -6,12 +6,12 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.ManageUtils;

View File

@ -5,10 +5,10 @@ import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.info.ImporterManager;
import main.java.com.djrapitops.plan.utilities.Condition;
@ -22,8 +22,6 @@ import main.java.com.djrapitops.plan.utilities.Condition;
*/
public class ManageImportCommand extends SubCommand {
private final Plan plugin;
/**
* Class Constructor.
*
@ -35,9 +33,6 @@ public class ManageImportCommand extends SubCommand {
Permissions.MANAGE.getPermission(),
Locale.get(Msg.CMD_USG_MANAGE_IMPORT).toString(),
"<plugin>/list [import args]");
this.plugin = plugin;
}
@Override

View File

@ -7,11 +7,11 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.ManageUtils;

View File

@ -7,11 +7,11 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.cache.DataCache;
import main.java.com.djrapitops.plan.systems.cache.SessionCache;
import main.java.com.djrapitops.plan.utilities.Condition;

View File

@ -7,12 +7,12 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.SQLiteDB;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import main.java.com.djrapitops.plan.utilities.ManageUtils;

View File

@ -5,12 +5,12 @@ import com.djrapitops.plugin.api.utility.log.Log;
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.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.exceptions.WebAPIException;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bungee.RequestSetupWebAPI;
import main.java.com.djrapitops.plan.utilities.Condition;

View File

@ -6,12 +6,12 @@ import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import org.bukkit.ChatColor;

View File

@ -6,11 +6,11 @@ import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.Condition;
import net.md_5.bungee.api.ChatColor;

View File

@ -4,10 +4,10 @@ import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
/**
* Subcommand for info about permission levels.

View File

@ -7,11 +7,11 @@ import com.djrapitops.plugin.command.SubCommand;
import com.djrapitops.plugin.settings.ColorScheme;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.locale.Locale;
import main.java.com.djrapitops.plan.settings.locale.Msg;
import main.java.com.djrapitops.plan.utilities.comparators.WebUserComparator;
import java.util.List;

View File

@ -1,15 +1,36 @@
package main.java.com.djrapitops.plan.data;
import com.djrapitops.plugin.api.Benchmark;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.data.analysis.*;
import com.djrapitops.plugin.api.TimeAmount;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.data.container.StickyData;
import main.java.com.djrapitops.plan.data.container.TPS;
import main.java.com.djrapitops.plan.data.element.AnalysisContainer;
import main.java.com.djrapitops.plan.data.element.HealthNotes;
import main.java.com.djrapitops.plan.data.plugin.PluginData;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.theme.Theme;
import main.java.com.djrapitops.plan.settings.theme.ThemeVal;
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.analysis.MathUtils;
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.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.html.graphs.ActivityStackGraphCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.PunchCardGraphCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldMapCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.line.*;
import main.java.com.djrapitops.plan.utilities.html.graphs.pie.ActivityPieCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.pie.WorldPieCreator;
import main.java.com.djrapitops.plan.utilities.html.structure.AnalysisPluginsTabContentCreator;
import main.java.com.djrapitops.plan.utilities.html.structure.SessionTabStructureCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.CommandUseTableCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.SessionsTableCreator;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
* Big container object for Data.
@ -27,119 +48,317 @@ import java.util.Map;
*/
public class AnalysisData extends RawData {
private final ActivityPart activityPart;
private final CommandUsagePart commandUsagePart;
private final GeolocationPart geolocationPart;
private final JoinInfoPart joinInfoPart;
private final KillPart killPart;
private final PlayerCountPart playerCountPart;
private final PlaytimePart playtimePart;
private final TPSPart tpsPart;
private final WorldPart worldPart;
private long refreshDate;
private String pluginsTabLayout;
private Map<String, Serializable> additionalDataReplaceMap;
private String playersTable;
private Map<String, Long> analyzedValues;
private Set<StickyData> stickyMonthData;
private List<PlayerProfile> players;
public AnalysisData() {
commandUsagePart = new CommandUsagePart();
geolocationPart = new GeolocationPart();
joinInfoPart = new JoinInfoPart();
playerCountPart = new PlayerCountPart();
playtimePart = new PlaytimePart();
killPart = new KillPart(joinInfoPart);
tpsPart = new TPSPart();
activityPart = new ActivityPart(playerCountPart, joinInfoPart, tpsPart);
worldPart = new WorldPart();
analyzedValues = new HashMap<>();
stickyMonthData = new HashSet<>();
}
public ActivityPart getActivityPart() {
return activityPart;
public void parsePluginsSection(Map<PluginData, AnalysisContainer> containers) {
String[] navAndTabs = AnalysisPluginsTabContentCreator.createContent(containers);
addValue("navPluginsTabs", navAndTabs[0]);
addValue("tabsPlugins", navAndTabs[1]);
}
public CommandUsagePart getCommandUsagePart() {
return commandUsagePart;
}
public GeolocationPart getGeolocationPart() {
return geolocationPart;
}
public JoinInfoPart getJoinInfoPart() {
return joinInfoPart;
}
public KillPart getKillPart() {
return killPart;
}
public PlayerCountPart getPlayerCountPart() {
return playerCountPart;
}
public PlaytimePart getPlaytimePart() {
return playtimePart;
}
public TPSPart getTpsPart() {
return tpsPart;
}
public WorldPart getWorldPart() {
return worldPart;
}
public List<RawData> getAllParts() {
return Arrays.asList(activityPart, commandUsagePart, geolocationPart,
joinInfoPart, killPart, playerCountPart, playtimePart, tpsPart,
worldPart);
}
public void setPluginsTabLayout(String pluginsTabLayout) {
this.pluginsTabLayout = pluginsTabLayout;
}
public void setAdditionalDataReplaceMap(Map<String, Serializable> additionalDataReplaceMap) {
this.additionalDataReplaceMap = additionalDataReplaceMap;
}
public void setPlayersTable(String playersTable) {
this.playersTable = playersTable;
}
@Override
protected void analyse() {
if (playersTable == null) {
playersTable = "";
}
if (pluginsTabLayout == null) {
pluginsTabLayout = "";
}
addValue("tableBodyPlayerList", playersTable);
private void addConstants() {
addValue("version", MiscUtils.getIPlan().getVersion());
addValue("worldPieColors", Theme.getValue(ThemeVal.GRAPH_WORLD_PIE));
addValue("gmPieColors", Theme.getValue(ThemeVal.GRAPH_GM_PIE));
addValue("serverName", Settings.SERVER_NAME.toString());
addValue("timeZone", MiscUtils.getTimeZoneOffsetHours());
addValue("refresh", FormatUtils.formatTimeStamp(refreshDate));
final List<RawData> parts = getAllParts();
parts.forEach(part -> {
try {
Benchmark.start(part.getClass().getSimpleName());
part.analyseData();
Benchmark.stop("Analysis", part.getClass().getSimpleName());
if (part.isAnalysed()) {
addValues(part.getReplaceMap());
}
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
}
});
refreshDate = MiscUtils.getTime();
}
addValue("activityPieColors", Theme.getValue(ThemeVal.GRAPH_ACTIVITY_PIE));
addValue("playersGraphColor", Theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE));
addValue("tpsHighColor", Theme.getValue(ThemeVal.GRAPH_TPS_HIGH));
addValue("tpsMediumColor", Theme.getValue(ThemeVal.GRAPH_TPS_MED));
addValue("tpsLowColor", Theme.getValue(ThemeVal.GRAPH_TPS_LOW));
addValue("tpsMedium", Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber());
addValue("tpsHigh", Settings.THEME_GRAPH_TPS_THRESHOLD_HIGH.getNumber());
public String replacePluginsTabLayout() {
return HtmlUtils.replacePlaceholders(pluginsTabLayout, additionalDataReplaceMap);
addValue("playersMax", ServerProfile.getPlayersMax());
addValue("playersOnline", ServerProfile.getPlayersOnline());
}
public long getRefreshDate() {
return refreshDate;
}
public void analyze(ServerProfile profile) {
addConstants();
long now = MiscUtils.getTime();
refreshDate = now;
long dayAgo = now - TimeAmount.DAY.ms();
long weekAgo = now - TimeAmount.WEEK.ms();
long monthAgo = now - TimeAmount.MONTH.ms();
got("now", now);
got("dayAgo", dayAgo);
got("weekAgo", weekAgo);
got("monthAgo", monthAgo);
Map<UUID, List<Session>> sessions = profile.getSessions();
List<Session> allSessions = profile.getAllSessions();
allSessions.sort(new SessionStartComparator());
players = profile.getPlayers();
List<PlayerProfile> ops = profile.getOps().collect(Collectors.toList());
long playersTotal = got("playersTotal", players.size());
List<TPS> tpsData = profile.getTPSData(0, now).collect(Collectors.toList());
List<TPS> tpsDataDay = profile.getTPSData(dayAgo, now).collect(Collectors.toList());
List<TPS> tpsDataWeek = profile.getTPSData(weekAgo, now).collect(Collectors.toList());
List<TPS> tpsDataMonth = profile.getTPSData(monthAgo, now).collect(Collectors.toList());
List<String> geoLocations = profile.getGeoLocations();
Map<String, Integer> commandUsage = profile.getCommandUsage();
directProfileVariables(profile);
performanceTab(tpsData, tpsDataDay, tpsDataWeek, tpsDataMonth);
sessionData(monthAgo, sessions, allSessions);
onlineActivityNumbers(profile, sessions, players);
geolocationsTab(geoLocations);
commandUsage(commandUsage);
addValue("ops", ops.size());
addValue("playersTotal", playersTotal);
healthTab(now, players, tpsDataMonth);
long totalPlaytime = profile.getTotalPlaytime();
addValue("playtimeTotal", playersTotal != 0 ? FormatUtils.formatTimeAmount(totalPlaytime) : "No Players");
addValue("playtimeAverage", playersTotal != 0 ? FormatUtils.formatTimeAmount(MathUtils.averageLong(totalPlaytime, playersTotal)) : "-");
}
private void healthTab(long now, List<PlayerProfile> players, List<TPS> tpsDataMonth) {
TreeMap<Long, Map<String, Set<UUID>>> activityData = AnalysisUtils.turnToActivityDataMap(now, players);
Map<String, Set<UUID>> activityNow = activityData.getOrDefault(now, new HashMap<>());
String[] activityStackSeries = ActivityStackGraphCreator.createSeries(activityData);
String activityPieSeries = ActivityPieCreator.createSeriesData(activityNow);
addValue("activityStackCategories", activityStackSeries[0]);
addValue("activityStackSeries", activityStackSeries[1]);
addValue("activityPieSeries", activityPieSeries);
Set<UUID> veryActiveNow = activityNow.getOrDefault("Very Active", new HashSet<>());
Set<UUID> activeNow = activityNow.getOrDefault("Active", new HashSet<>());
Set<UUID> regularNow = activityNow.getOrDefault("Regular", new HashSet<>());
addValue("playersRegular", (veryActiveNow.size() + activeNow.size() + regularNow.size()));
HealthNotes healthNotes = new HealthNotes(this, activityData, tpsDataMonth, now);
healthNotes.analyzeHealth();
addValue("healthNotes", healthNotes.parse());
addValue("healthIndex", healthNotes.getServerHealth());
}
private void commandUsage(Map<String, Integer> commandUsage) {
addValue("commandUniqueCount", String.valueOf(commandUsage.size()));
addValue("commandCount", MathUtils.sumInt(commandUsage.values().stream().map(i -> (int) i)));
addValue("tableBodyCommands", HtmlUtils.removeXSS(CommandUseTableCreator.createTable(commandUsage)));
}
private void geolocationsTab(List<String> geoLocations) {
addValue("geoMapSeries", WorldMapCreator.createDataSeries(geoLocations));
}
private void onlineActivityNumbers(ServerProfile profile, Map<UUID, List<Session>> sessions, List<PlayerProfile> players) {
long now = value("now");
long dayAgo = value("dayAgo");
long weekAgo = value("weekAgo");
long monthAgo = value("monthAgo");
List<PlayerProfile> newDay = profile.getPlayersWhoRegistered(dayAgo, now).collect(Collectors.toList());
List<PlayerProfile> newWeek = profile.getPlayersWhoRegistered(weekAgo, now).collect(Collectors.toList());
List<PlayerProfile> newMonth = profile.getPlayersWhoRegistered(monthAgo, now).collect(Collectors.toList());
List<PlayerProfile> uniqueDay = profile.getPlayersWhoPlayedBetween(dayAgo, now).collect(Collectors.toList());
List<PlayerProfile> uniqueWeek = profile.getPlayersWhoPlayedBetween(weekAgo, now).collect(Collectors.toList());
List<PlayerProfile> uniqueMonth = profile.getPlayersWhoPlayedBetween(monthAgo, now).collect(Collectors.toList());
int uniqD = uniqueDay.size();
int uniqW = uniqueWeek.size();
int uniqM = uniqueMonth.size();
long newD = got("newD", newDay.size());
long newW = got("newW", newWeek.size());
long newM = got("newM", newMonth.size());
long playersTotal = value("playersTotal");
addValue("playersDay", uniqD);
addValue("playersWeek", uniqW);
addValue("playersMonth", uniqM);
addValue("playersNewDay", newD);
addValue("playersNewWeek", newW);
addValue("playersNewMonth", newM);
addValue("playersAverage", AnalysisUtils.getUniqueJoinsPerDay(sessions, -1));
addValue("playersAverageDay", AnalysisUtils.getUniqueJoinsPerDay(sessions, dayAgo));
addValue("playersAverageWeek", AnalysisUtils.getUniqueJoinsPerDay(sessions, weekAgo));
addValue("playersAverageMonth", AnalysisUtils.getUniqueJoinsPerDay(sessions, monthAgo));
addValue("playersNewAverage", AnalysisUtils.getNewUsersPerDay(toRegistered(players), -1, playersTotal));
addValue("playersNewAverageDay", AnalysisUtils.getNewUsersPerDay(toRegistered(newDay), -1, newD));
addValue("playersNewAverageWeek", AnalysisUtils.getNewUsersPerDay(toRegistered(newWeek), -1, newW));
addValue("playersNewAverageMonth", AnalysisUtils.getNewUsersPerDay(toRegistered(newMonth), -1, newM));
stickiness(now, weekAgo, monthAgo, newDay, newWeek, newMonth);
}
private void stickiness(long now, long weekAgo, long monthAgo,
List<PlayerProfile> newDay, List<PlayerProfile> newWeek, List<PlayerProfile> newMonth) {
long newD = value("newD");
long newW = value("newW");
long newM = value("newM");
long fourDaysAgo = now - TimeAmount.DAY.ms() * 4L;
long twoWeeksAgo = now - TimeAmount.WEEK.ms() * 2L;
List<PlayerProfile> playersStuckPerMonth = newMonth.stream()
.filter(p -> p.playedBetween(monthAgo, twoWeeksAgo) && p.playedBetween(twoWeeksAgo, now))
.collect(Collectors.toList());
List<PlayerProfile> playersStuckPerWeek = newWeek.stream()
.filter(p -> p.playedBetween(weekAgo, fourDaysAgo) && p.playedBetween(fourDaysAgo, now))
.collect(Collectors.toList());
int stuckPerM = playersStuckPerMonth.size();
int stuckPerW = playersStuckPerWeek.size();
got("stuckPerM", stuckPerM);
got("stuckPerW", stuckPerW);
addValue("playersStuckMonth", stuckPerM);
addValue("playersStuckWeek", stuckPerW);
addValue("playersStuckPercMonth", newM != 0 ? FormatUtils.cutDecimals(MathUtils.averageDouble(stuckPerM, newM) * 100.0) + "%" : "-");
addValue("playersStuckPercWeek", newW != 0 ? FormatUtils.cutDecimals(MathUtils.averageDouble(stuckPerW, newW) * 100.0) + "%" : "-");
stuckPerDay(newDay, newMonth, newD, playersStuckPerMonth, playersStuckPerWeek);
}
private void stuckPerDay(List<PlayerProfile> newDay, List<PlayerProfile> newMonth, long newD, List<PlayerProfile> playersStuckPerMonth, List<PlayerProfile> playersStuckPerWeek) {
if (newD != 0) {
// New Players
stickyMonthData = newMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
Set<StickyData> stickyW = playersStuckPerMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
// New Players who stayed
Set<StickyData> stickyStuckM = newMonth.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
Set<StickyData> stickyStuckW = playersStuckPerWeek.stream().map(StickyData::new).distinct().collect(Collectors.toSet());
int stuckPerD = 0;
for (PlayerProfile playerProfile : newDay) {
double probability = AnalysisUtils.calculateProbabilityOfStaying(
stickyMonthData, stickyW, stickyStuckM, stickyStuckW, playerProfile
);
if (probability >= 0.5) {
stuckPerD++;
}
}
addValue("playersStuckDay", stuckPerD);
addValue("playersStuckPercDay", FormatUtils.cutDecimals(MathUtils.averageDouble(stuckPerD, newD) * 100.0) + "%");
} else {
addValue("playersStuckDay", 0);
addValue("playersStuckPercDay", "-");
}
}
private List<Long> toRegistered(List<PlayerProfile> players) {
return players.stream().map(PlayerProfile::getRegistered).collect(Collectors.toList());
}
private void sessionData(long monthAgo, Map<UUID, List<Session>> sessions, List<Session> allSessions) {
List<Session> sessionsMonth = allSessions.stream()
.filter(s -> s.getSessionStart() >= monthAgo)
.collect(Collectors.toList());
String[] tables = SessionsTableCreator.createTable(sessions, allSessions);
String[] sessionContent = SessionTabStructureCreator.createStructure(sessions, allSessions);
addValue("sessionCount", allSessions.size());
addValue("accordionSessions", sessionContent[0]);
addValue("sessionTabGraphViewFunctions", sessionContent[1]);
addValue("tableBodySessions", tables[0]);
addValue("listRecentLogins", tables[1]);
addValue("sessionAverage", FormatUtils.formatTimeAmount(MathUtils.averageLong(allSessions.stream().map(Session::getLength))));
addValue("punchCardSeries", PunchCardGraphCreator.createDataSeries(sessionsMonth));
addValue("deaths", ServerProfile.getDeathCount(allSessions));
addValue("mobKillCount", ServerProfile.getMobKillCount(allSessions));
addValue("killCount", ServerProfile.getPlayerKills(allSessions).size());
}
private void directProfileVariables(ServerProfile profile) {
WorldTimes worldTimes = profile.getServerWorldtimes();
long allTimePeak = profile.getAllTimePeak();
long lastPeak = profile.getLastPeakDate();
addValue("tablePlayerlist", Html.TABLE_PLAYERS.parse(profile.createPlayersTableBody()));
addValue("worldTotal", FormatUtils.formatTimeAmount(worldTimes.getTotal()));
String[] seriesData = WorldPieCreator.createSeriesData(worldTimes);
addValue("worldSeries", seriesData[0]);
addValue("gmSeries", seriesData[1]);
addValue("lastPeakTime", lastPeak != -1 ? FormatUtils.formatTimeStampYear(lastPeak) : "No Data");
addValue("playersLastPeak", lastPeak != -1 ? profile.getLastPeakPlayers() : "-");
addValue("bestPeakTime", allTimePeak != -1 ? FormatUtils.formatTimeStampYear(allTimePeak) : "No Data");
addValue("playersBestPeak", allTimePeak != -1 ? profile.getAllTimePeakPlayers() : "-");
}
private void performanceTab(List<TPS> tpsData, List<TPS> tpsDataDay, List<TPS> tpsDataWeek, List<TPS> tpsDataMonth) {
got("tpsSpikeMonth", ServerProfile.getLowSpikeCount(tpsDataMonth));
got("tpsSpikeWeek", ServerProfile.getLowSpikeCount(tpsDataWeek));
got("tpsSpikeDay", ServerProfile.getLowSpikeCount(tpsDataDay));
addValue("tpsSpikeMonth", value("tpsSpikeMonth"));
addValue("tpsSpikeWeek", value("tpsSpikeWeek"));
addValue("tpsSpikeDay", value("tpsSpikeDay"));
addValue("playersOnlineSeries", PlayerActivityGraphCreator.buildSeriesDataString(tpsData));
addValue("tpsSeries", TPSGraphCreator.buildSeriesDataString(tpsData));
addValue("cpuSeries", CPUGraphCreator.buildSeriesDataString(tpsData));
addValue("ramSeries", RamGraphCreator.buildSeriesDataString(tpsData));
addValue("entitySeries", WorldLoadGraphCreator.buildSeriesDataStringEntities(tpsData));
addValue("chunkSeries", WorldLoadGraphCreator.buildSeriesDataStringChunks(tpsData));
double averageCPUMonth = MathUtils.averageDouble(tpsDataMonth.stream().map(TPS::getCPUUsage).filter(i -> i != 0));
double averageCPUWeek = MathUtils.averageDouble(tpsDataWeek.stream().map(TPS::getCPUUsage).filter(i -> i != 0));
double averageCPUDay = MathUtils.averageDouble(tpsDataDay.stream().map(TPS::getCPUUsage).filter(i -> i != 0));
addValue("tpsAverageMonth", FormatUtils.cutDecimals(MathUtils.averageDouble(tpsDataMonth.stream().map(TPS::getTicksPerSecond))));
addValue("tpsAverageWeek", FormatUtils.cutDecimals(MathUtils.averageDouble(tpsDataWeek.stream().map(TPS::getTicksPerSecond))));
addValue("tpsAverageDay", FormatUtils.cutDecimals(MathUtils.averageDouble(tpsDataDay.stream().map(TPS::getTicksPerSecond))));
addValue("cpuAverageMonth", averageCPUMonth >= 0 ? FormatUtils.cutDecimals(averageCPUMonth) + "%" : "Unavailable");
addValue("cpuAverageWeek", averageCPUWeek >= 0 ? FormatUtils.cutDecimals(averageCPUWeek) + "%" : "Unavailable");
addValue("cpuAverageDay", averageCPUDay >= 0 ? FormatUtils.cutDecimals(averageCPUDay) + "%" : "Unavailable");
addValue("ramAverageMonth", FormatUtils.cutDecimals(MathUtils.averageLong(tpsDataMonth.stream().map(TPS::getUsedMemory).filter(i -> i != 0))));
addValue("ramAverageWeek", FormatUtils.cutDecimals(MathUtils.averageLong(tpsDataWeek.stream().map(TPS::getUsedMemory).filter(i -> i != 0))));
addValue("ramAverageDay", FormatUtils.cutDecimals(MathUtils.averageLong(tpsDataDay.stream().map(TPS::getUsedMemory).filter(i -> i != 0))));
addValue("entityAverageMonth", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataMonth.stream().map(TPS::getEntityCount).filter(i -> i != 0))));
addValue("entityAverageWeek", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataWeek.stream().map(TPS::getEntityCount).filter(i -> i != 0))));
addValue("entityAverageDay", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataDay.stream().map(TPS::getEntityCount).filter(i -> i != 0))));
addValue("chunkAverageMonth", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataMonth.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
addValue("chunkAverageWeek", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataWeek.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
addValue("chunkAverageDay", FormatUtils.cutDecimals(MathUtils.averageInt(tpsDataDay.stream().map(TPS::getChunksLoaded).filter(i -> i != 0))));
}
private long got(String key, long v) {
analyzedValues.put(key, v);
return v;
}
public long value(String key) {
return analyzedValues.getOrDefault(key, 0L);
}
public Set<StickyData> getStickyMonthData() {
return stickyMonthData;
}
public List<PlayerProfile> getPlayers() {
return players;
}
}

View File

@ -0,0 +1,16 @@
/*
* 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.data;
/**
* //TODO Class Javadoc Comment
*
* @author Rsl1122
*/
public interface HasDate {
long getDate();
}

View File

@ -0,0 +1,596 @@
/*
* 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.data;
import com.djrapitops.plugin.api.TimeAmount;
import main.java.com.djrapitops.plan.data.container.Action;
import main.java.com.djrapitops.plan.data.container.GeoInfo;
import main.java.com.djrapitops.plan.data.container.PlayerKill;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.comparators.ActionComparator;
import main.java.com.djrapitops.plan.utilities.comparators.GeoInfoComparator;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Data container object for a single player.
* <p>
* Created to streamline analysis and to make it easier to understand.
*
* @author Rsl1122
*/
public class PlayerProfile implements OfflinePlayer {
// Identification
private final UUID uuid;
private final String name;
// Basic information
private final long registered;
private Map<UUID, Long> registeredMap;
private Set<UUID> bannedOnServers;
private Set<UUID> oppedOnServers;
private int timesKicked;
// Activity related information
private Map<UUID, List<Session>> sessions;
private List<Action> actions;
private Map<UUID, WorldTimes> worldTimesMap;
// Extra information
private Map<UUID, List<String>> nicknames;
private List<GeoInfo> geoInformation;
// Plugin data
private Map<String, String> pluginReplaceMap;
// Value that requires lot of processing
private Map<Long, Double> activityIndex;
public PlayerProfile(UUID uuid, String name, long registered) {
this.uuid = uuid;
this.name = name;
this.registered = registered;
registeredMap = new HashMap<>();
bannedOnServers = new HashSet<>();
oppedOnServers = new HashSet<>();
sessions = new HashMap<>();
actions = new ArrayList<>();
worldTimesMap = new HashMap<>();
nicknames = new HashMap<>();
geoInformation = new ArrayList<>();
pluginReplaceMap = new HashMap<>();
activityIndex = new HashMap<>();
}
// Calculating Getters
public double getActivityIndex(long date) {
Double activityIndx = activityIndex.get(date);
if (activityIndx != null) {
return activityIndx;
}
long week = TimeAmount.WEEK.ms();
long weekAgo = date - week;
long twoWeeksAgo = date - 2L * week;
long threeWeeksAgo = date - 3L * week;
long activePlayThreshold = Settings.ACTIVE_PLAY_THRESHOLD.getNumber() * TimeAmount.MINUTE.ms();
int activeLoginThreshold = Settings.ACTIVE_LOGIN_THRESHOLD.getNumber();
List<Session> sessionsWeek = getSessions(weekAgo, date).collect(Collectors.toList());
List<Session> sessionsWeek2 = getSessions(twoWeeksAgo, weekAgo).collect(Collectors.toList());
List<Session> sessionsWeek3 = getSessions(threeWeeksAgo, twoWeeksAgo).collect(Collectors.toList());
// Playtime per week multipliers, max out to avoid too high values.
double max = 4.0;
long playtimeWeek = PlayerProfile.getPlaytime(sessionsWeek.stream());
double weekPlay = (playtimeWeek * 1.0 / activePlayThreshold);
if (weekPlay > max) {
weekPlay = max;
}
long playtimeWeek2 = PlayerProfile.getPlaytime(sessionsWeek2.stream());
double week2Play = (playtimeWeek2 * 1.0 / activePlayThreshold);
if (week2Play > max) {
week2Play = max;
}
long playtimeWeek3 = PlayerProfile.getPlaytime(sessionsWeek3.stream());
double week3Play = (playtimeWeek3 * 1.0 / activePlayThreshold);
if (week3Play > max) {
week3Play = max;
}
double playtimeMultiplier = 1.0;
if (playtimeWeek + playtimeWeek2 + playtimeWeek3 > activeLoginThreshold * 3.0) {
playtimeMultiplier = 1.25;
}
// Reduce the harshness for new players and players who have had a vacation
if (weekPlay > 1 && week3Play > 1 && week2Play == 0.0) {
week2Play = 0.5;
}
if (weekPlay > 1 && week2Play == 0.0) {
week2Play = 0.6;
}
if (weekPlay > 1 && week3Play == 0.0) {
week3Play = 0.75;
}
double playAvg = (weekPlay + week2Play + week3Play) / 3.0;
double weekLogin = sessionsWeek.size() >= activeLoginThreshold ? 1.0 : 0.5;
double week2Login = sessionsWeek2.size() >= activeLoginThreshold ? 1.0 : 0.5;
double week3Login = sessionsWeek3.size() >= activeLoginThreshold ? 1.0 : 0.5;
double loginMultiplier = 1.0;
double loginTotal = weekLogin + week2Login + week3Login;
double loginAvg = loginTotal / 3.0;
if (loginTotal <= 2.0) {
// Reduce index for players that have not logged in the threshold amount for 2 weeks
loginMultiplier = 0.75;
}
activityIndx = playAvg * loginAvg * loginMultiplier * playtimeMultiplier;
activityIndex.put(date, activityIndx);
return activityIndx;
}
/**
* Get the total world times of the player.
*
* @return returns the WorldTimes in the "null" key of the map.
*/
public WorldTimes getWorldTimes() {
return worldTimesMap.getOrDefault(null, new WorldTimes(new HashMap<>()));
}
/**
* Get world times per server for this player.
*
* @return a copy of the WorldTimes Map without the "null" key.
*/
public Map<UUID, WorldTimes> getWorldTimesPerServer() {
Map<UUID, WorldTimes> map = new HashMap<>(worldTimesMap);
map.remove(null);
return map;
}
public UUID getFavoriteServer() {
long max = 0L;
UUID maxServer = null;
for (Map.Entry<UUID, WorldTimes> entry : getWorldTimesPerServer().entrySet()) {
long playTime = entry.getValue().getTotal();
if (playTime > max) {
max = playTime;
maxServer = entry.getKey();
}
}
return maxServer;
}
public long getLastSeen() {
return getLastSeen(getAllSessions());
}
public long getLastSeen(UUID serverUUID) {
return getLastSeen(getSessions(serverUUID).stream());
}
public long getLastSeen(Stream<Session> s) {
OptionalLong max = s.mapToLong(Session::getSessionEnd)
.max();
if (max.isPresent()) {
return max.getAsLong();
}
return 0;
}
public long getTotalPlaytime() {
return getPlaytime(-1, MiscUtils.getTime() + 1L);
}
public long getPlaytime(long after, long before) {
return getPlaytime(getSessions(after, before));
}
public long getPlaytime(UUID serverUUID) {
return getPlaytime(getSessions(serverUUID).stream());
}
public static long getPlaytime(Stream<Session> s) {
return s.map(Session::getLength)
.mapToLong(i -> i)
.sum();
}
public long getLongestSession() {
return getLongestSession(-1, MiscUtils.getTime() + 1L);
}
public long getLongestSession(int after, long before) {
return getLongestSession(getSessions(after, before));
}
public long getLongestSession(UUID serverUUID) {
return getLongestSession(getSessions(serverUUID).stream());
}
public static long getLongestSession(Stream<Session> s) {
OptionalLong longestSession = s.map(Session::getLength)
.mapToLong(i -> i)
.max();
if (longestSession.isPresent()) {
return longestSession.getAsLong();
}
return -1;
}
public long getSessionMedian() {
return getSessionMedian(-1, MiscUtils.getTime() + 1L);
}
public long getSessionMedian(int after, long before) {
return getSessionMedian(getSessions(after, before));
}
public long getSessionMedian(UUID serverUUID) {
return getSessionMedian(getSessions(serverUUID).stream());
}
public static long getSessionMedian(Stream<Session> s) {
List<Long> sessionLenghts = s.map(Session::getLength)
.sorted()
.collect(Collectors.toList());
if (sessionLenghts.isEmpty()) {
return 0;
}
return sessionLenghts.get(sessionLenghts.size() / 2);
}
public long getSessionAverage() {
return getSessionAverage(-1, MiscUtils.getTime() + 1L);
}
public long getSessionAverage(int after, long before) {
return getSessionAverage(getSessions(after, before));
}
public long getSessionAverage(UUID serverUUID) {
return getSessionAverage(getSessions(serverUUID).stream());
}
public static long getSessionAverage(Stream<Session> s) {
OptionalDouble average = s.map(Session::getLength)
.mapToLong(i -> i)
.average();
if (average.isPresent()) {
return (long) average.getAsDouble();
}
return 0L;
}
public boolean playedBetween(long after, long before) {
return getSessions(after, before).findFirst().isPresent();
}
// Special Getters
public Stream<Session> getAllSessions() {
return sessions.values().stream().flatMap(Collection::stream);
}
public Stream<Session> getSessions(long after, long before) {
return getAllSessions()
.filter(session -> session.getSessionStart() >= after && session.getSessionStart() <= before);
}
public GeoInfo getMostRecentGeoInfo() {
if (geoInformation.isEmpty()) {
return new GeoInfo("-", "Not Known", MiscUtils.getTime());
}
geoInformation.sort(new GeoInfoComparator());
return geoInformation.get(0);
}
public List<Action> getAllActions() {
List<Action> actions = new ArrayList<>(this.actions);
getPlayerKills().map(PlayerKill::convertToAction).forEach(actions::add);
actions.sort(new ActionComparator());
return actions;
}
public Stream<PlayerKill> getPlayerKills() {
return getPlayerKills(getAllSessions());
}
public Stream<PlayerKill> getPlayerKills(UUID serverUUID) {
return getPlayerKills(getSessions(serverUUID).stream());
}
public static Stream<PlayerKill> getPlayerKills(Stream<Session> s) {
return s.map(Session::getPlayerKills)
.flatMap(Collection::stream);
}
public long getPlayerKillCount() {
return getPlayerKills().count();
}
public long getPlayerKillCount(UUID serverUUID) {
return getPlayerKills(serverUUID).count();
}
public long getDeathCount() {
return getDeathCount(getAllSessions());
}
public long getDeathCount(UUID serverUUID) {
return getDeathCount(getSessions(serverUUID).stream());
}
public static long getDeathCount(Stream<Session> s) {
return s.mapToLong(Session::getDeaths)
.sum();
}
public long getMobKillCount() {
return getMobKillCount(getAllSessions());
}
public long getMobKillCount(UUID serverUUID) {
return getMobKillCount(getSessions(serverUUID).stream());
}
public static long getMobKillCount(Stream<Session> s) {
return s.mapToLong(Session::getMobKills)
.sum();
}
public long getSessionCount() {
return getAllSessions().count();
}
public long getSessionCount(UUID serverUUID) {
return getSessions(serverUUID).size();
}
public long getRegistered(UUID serverUUID) {
return registeredMap.getOrDefault(serverUUID, -1L);
}
// Setters & Adders
public void bannedOnServer(UUID serverUUID) {
bannedOnServers.add(serverUUID);
}
public void oppedOnServer(UUID serverUUID) {
oppedOnServers.add(serverUUID);
}
public void bannedOnServer(Collection<UUID> serverUUIDs) {
bannedOnServers.addAll(serverUUIDs);
}
public void oppedOnServer(Collection<UUID> serverUUIDs) {
oppedOnServers.addAll(serverUUIDs);
}
public void setSessions(UUID serverUUID, List<Session> sessions) {
this.sessions.put(serverUUID, sessions);
}
public void setSessions(Map<UUID, List<Session>> sessions) {
this.sessions.putAll(sessions);
}
public void addActiveSession(Session activeSession) {
UUID serverUUID = MiscUtils.getIPlan().getServerUuid();
List<Session> sessions = getSessions(serverUUID);
sessions.add(activeSession);
this.sessions.put(serverUUID, sessions);
}
public List<Session> getSessions(UUID serverUUID) {
return this.sessions.getOrDefault(serverUUID, new ArrayList<>());
}
public void addReplaceValue(String placeholder, Serializable value) {
pluginReplaceMap.put(placeholder, value.toString());
}
public void setWorldTimes(UUID serverUUID, WorldTimes worldTimes) {
worldTimesMap.put(serverUUID, worldTimes);
}
public void setWorldTimes(Map<UUID, WorldTimes> worldTimes) {
worldTimesMap.putAll(worldTimes);
}
public void setTotalWorldTimes(WorldTimes worldTimes) {
worldTimesMap.put(null, worldTimes);
}
public void setRegistered(UUID serverUUID, long registered) {
registeredMap.put(serverUUID, registered);
}
// Default Setters
public void setActions(List<Action> actions) {
this.actions = actions;
}
public void setNicknames(Map<UUID, List<String>> nicknames) {
this.nicknames = nicknames;
}
public void setGeoInformation(List<GeoInfo> geoInformation) {
this.geoInformation = geoInformation;
}
public void setTimesKicked(int timesKicked) {
this.timesKicked = timesKicked;
}
// Default Getters
public int getTimesKicked() {
return timesKicked;
}
public Map<UUID, List<String>> getNicknames() {
return nicknames;
}
public List<GeoInfo> getGeoInformation() {
return geoInformation;
}
public UUID getUuid() {
return uuid;
}
public String getName() {
return name;
}
public long getRegistered() {
return registered;
}
public Set<UUID> getBannedOnServers() {
return bannedOnServers;
}
public Set<UUID> getOppedOnServers() {
return oppedOnServers;
}
public Map<UUID, List<Session>> getSessions() {
return sessions;
}
public List<Action> getActions() {
return actions;
}
public Map<String, String> getPluginReplaceMap() {
return pluginReplaceMap;
}
/**
* Get the WorldTimes map.
*
* @return Map that contains WorldTimes for each server and a total in the "null" key.
*/
public Map<UUID, WorldTimes> getWorldTimesMap() {
return worldTimesMap;
}
// OfflinePlayer methods for possible PluginData analysis
@Override
public boolean isOnline() {
Player p = getPlayer();
return p != null && p.isOnline();
}
@Override
public UUID getUniqueId() {
return uuid;
}
@Override
public boolean isBanned() {
return bannedOnServers.size() != 0;
}
@Override
public boolean isWhitelisted() {
return true;
}
@Override
public void setWhitelisted(boolean b) {
/* Do nothing */
}
@Override
public Player getPlayer() {
return Bukkit.getPlayer(uuid);
}
@Override
public long getFirstPlayed() {
return registered;
}
@Override
public long getLastPlayed() {
return getLastSeen(MiscUtils.getIPlan().getServerUuid());
}
@Override
public boolean hasPlayedBefore() {
return true;
}
@Override
public Location getBedSpawnLocation() {
return null;
}
@Override
public Map<String, Object> serialize() {
return new HashMap<>();
}
@Override
public boolean isOp() {
return oppedOnServers.contains(MiscUtils.getIPlan().getServerUuid());
}
@Override
public void setOp(boolean b) {
/* Do nothing */
}
public void calculateWorldTimesPerServer() {
if (worldTimesMap.containsKey(MiscUtils.getIPlan().getServerUuid())) {
return;
}
for (Map.Entry<UUID, List<Session>> entry : sessions.entrySet()) {
UUID serverUUID = entry.getKey();
List<Session> sessions = entry.getValue();
WorldTimes times = worldTimesMap.getOrDefault(serverUUID, new WorldTimes(new HashMap<>()));
for (Session session : sessions) {
WorldTimes worldTimes = session.getWorldTimes();
times.add(worldTimes);
}
worldTimesMap.put(serverUUID, times);
}
}
}

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan.data.analysis;
package main.java.com.djrapitops.plan.data;
import com.djrapitops.plugin.utilities.Verify;
@ -16,45 +16,13 @@ public abstract class RawData {
private final Map<String, Serializable> replaceMap;
/**
* Status info for call to analyzeData method.
*/
protected boolean analysed;
/**
* Only used by subclasses.
*/
public RawData() {
replaceMap = new HashMap<>();
analysed = false;
}
/**
* Condition if analyseData() has been called.
*
* @return true if the method has been called.
*/
public boolean isAnalysed() {
return analysed;
}
/**
* Analyses the data added together.
* <p>
* Places place-holders to the replace map.
*/
public void analyseData() {
analysed = true;
this.analyse();
}
/**
* Subclasses should analyse the data added together.
* <p>
* Place-holders should be added to the replace map.
*/
protected abstract void analyse();
/**
* Adds values from an existing replaceMap.
*

View File

@ -0,0 +1,402 @@
/*
* 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.data;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.api.TimeAmount;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.PlanBungee;
import main.java.com.djrapitops.plan.data.container.GeoInfo;
import main.java.com.djrapitops.plan.data.container.PlayerKill;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.data.container.TPS;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
import main.java.com.djrapitops.plan.utilities.comparators.PlayerProfileLastPlayedComparator;
import main.java.com.djrapitops.plan.utilities.comparators.TPSComparator;
import main.java.com.djrapitops.plan.utilities.html.tables.PlayersTableCreator;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Data class for streamlining Analysis data.
* <p>
* Most of the methods are not the most efficient when multiple of them are used.
*
* @author Rsl1122
*/
public class ServerProfile {
private final UUID serverUUID;
// Database information
private List<PlayerProfile> players;
private List<TPS> tps;
private Map<String, Integer> commandUsage;
// Information calculated with SQL
private WorldTimes serverWorldtimes;
private long lastPeakDate;
private int lastPeakPlayers;
private long allTimePeak;
private int allTimePeakPlayers;
// Calculated once
private Map<UUID, PlayerProfile> playerMap;
public ServerProfile(UUID serverUUID) {
this.serverUUID = serverUUID;
players = new ArrayList<>();
tps = new ArrayList<>();
commandUsage = new HashMap<>();
allTimePeak = -1;
allTimePeakPlayers = -1;
lastPeakDate = -1;
lastPeakPlayers = -1;
}
public List<PlayerProfile> getPlayers() {
return players;
}
public void setPlayers(List<PlayerProfile> players) {
this.players = players;
}
public List<TPS> getTps() {
return tps;
}
public void setTps(List<TPS> tps) {
this.tps = tps;
}
public Map<String, Integer> getCommandUsage() {
return commandUsage;
}
public void setCommandUsage(Map<String, Integer> commandUsage) {
this.commandUsage = commandUsage;
}
public static long getLowSpikeCount(List<TPS> tpsData) {
int mediumThreshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber();
boolean wasLow = false;
long spikeCount = 0L;
for (TPS tpsObj : tpsData) {
double tps = tpsObj.getTicksPerSecond();
if (tps < mediumThreshold) {
if (!wasLow) {
spikeCount++;
wasLow = true;
}
} else {
wasLow = false;
}
}
return spikeCount;
}
public double getAverageTPS(long after, long before) {
OptionalDouble average = getTPSData(after, before)
.mapToDouble(TPS::getTicksPerSecond)
.average();
if (average.isPresent()) {
return average.getAsDouble();
}
return -1;
}
public double getAverageCPU(long after, long before) {
OptionalDouble average = getTPSData(after, before)
.mapToDouble(TPS::getCPUUsage)
.filter(num -> num >= 0)
.average();
if (average.isPresent()) {
return average.getAsDouble();
}
return -1;
}
public double getAverageRAM(long after, long before) {
OptionalDouble average = getTPSData(after, before)
.mapToDouble(TPS::getUsedMemory)
.average();
if (average.isPresent()) {
return average.getAsDouble();
}
return -1;
}
public double getAverageEntities(long after, long before) {
OptionalDouble average = getTPSData(after, before)
.mapToDouble(TPS::getEntityCount)
.average();
if (average.isPresent()) {
return average.getAsDouble();
}
return -1;
}
public double getAverageChunks(long after, long before) {
OptionalDouble average = getTPSData(after, before)
.mapToDouble(TPS::getChunksLoaded)
.average();
if (average.isPresent()) {
return average.getAsDouble();
}
return -1;
}
public long getNewPlayers(long after, long before) {
return getPlayersWhoRegistered(after, before).count();
}
public long getUniquePlayers(long after, long before) {
return getPlayersWhoPlayedBetween(after, before).count();
}
public double getNewPlayersPerDay(long after, long before) {
return getNewPlayers(after, before) * 1.0 / AnalysisUtils.getNumberOfDaysBetween(after, before);
}
public Stream<PlayerProfile> getPlayersWhoPlayedBetween(long after, long before) {
return players.stream()
.filter(player -> player.playedBetween(after, before));
}
public Stream<PlayerProfile> getPlayersWhoRegistered(long after, long before) {
return players.stream()
.filter(player -> player.getRegistered() >= after && player.getRegistered() <= before);
}
public Stream<TPS> getTPSData(long after, long before) {
return tps.stream().filter(tps -> tps.getDate() >= after && tps.getDate() <= before);
}
public String createPlayersTableBody() {
players.sort(new PlayerProfileLastPlayedComparator());
return PlayersTableCreator.createTable(players);
}
public List<String> getGeoLocations() {
return players.stream()
.map(PlayerProfile::getMostRecentGeoInfo)
.map(GeoInfo::getGeolocation)
.collect(Collectors.toList());
}
public long getTotalPlaytime() {
return serverWorldtimes.getTotal();
}
public long getAveragePlayTime() {
return MathUtils.averageLong(getTotalPlaytime(), getPlayerCount());
}
public long getPlayerCount() {
return players.size();
}
public Map<UUID, List<Session>> getSessions() {
return players.stream().collect(Collectors.toMap(PlayerProfile::getUuid, p -> p.getSessions(serverUUID)));
}
public List<Session> getAllSessions() {
return players.stream().map(p -> p.getSessions(serverUUID)).flatMap(Collection::stream).collect(Collectors.toList());
}
public static List<PlayerKill> getPlayerKills(List<Session> s) {
List<PlayerKill> kills = new ArrayList<>();
for (Session session : s) {
kills.addAll(session.getPlayerKills());
}
return kills;
}
public static long getMobKillCount(List<Session> s) {
long total = 0;
for (Session session : s) {
total += session.getMobKills();
}
return total;
}
public static long getDeathCount(List<Session> s) {
long total = 0;
for (Session session : s) {
total += session.getDeaths();
}
return total;
}
// Default setters & getters
public WorldTimes getServerWorldtimes() {
return serverWorldtimes;
}
public void setServerWorldtimes(WorldTimes serverWorldtimes) {
this.serverWorldtimes = serverWorldtimes;
}
public long getLastPeakDate() {
return lastPeakDate;
}
public void setLastPeakDate(long lastPeakDate) {
this.lastPeakDate = lastPeakDate;
}
public int getLastPeakPlayers() {
return lastPeakPlayers;
}
public void setLastPeakPlayers(int lastPeakPlayers) {
this.lastPeakPlayers = lastPeakPlayers;
}
public long getAllTimePeak() {
return allTimePeak;
}
public void setAllTimePeak(long allTimePeak) {
this.allTimePeak = allTimePeak;
}
public int getAllTimePeakPlayers() {
return allTimePeakPlayers;
}
public void setAllTimePeakPlayers(int allTimePeakPlayers) {
this.allTimePeakPlayers = allTimePeakPlayers;
}
public static int getPlayersOnline() {
if (Check.isBungeeAvailable()) {
return PlanBungee.getInstance().getProxy().getOnlineCount();
} else {
return Plan.getInstance().getServer().getOnlinePlayers().size();
}
}
public static int getPlayersMax() {
return MiscUtils.getIPlan().getVariable().getMaxPlayers();
}
public Stream<PlayerProfile> getOps() {
return players.stream().filter(PlayerProfile::isOp);
}
public Set<UUID> getUuids() {
Set<UUID> uuids = new HashSet<>();
for (PlayerProfile player : players) {
uuids.add(player.getUuid());
}
return uuids;
}
public long serverDownTime(long after, long before) {
return serverDownTime(getTPSData(after, before)
.sorted(new TPSComparator())
.collect(Collectors.toList()));
}
public static long serverDownTime(List<TPS> tpsData) {
long lastDate = -1;
long downTime = 0;
for (TPS tps : tpsData) {
long date = tps.getDate();
if (lastDate == -1) {
lastDate = date;
continue;
}
long diff = date - lastDate;
if (diff > TimeAmount.MINUTE.ms() * 3L) {
downTime += diff;
}
lastDate = date;
}
return downTime;
}
public long serverIdleTime(long after, long before) {
return serverIdleTime(getTPSData(after, before)
.sorted(new TPSComparator())
.collect(Collectors.toList()));
}
public static long serverIdleTime(List<TPS> tpsData) {
long lastDate = -1;
int lastPlayers = 0;
long idleTime = 0;
for (TPS tps : tpsData) {
long date = tps.getDate();
int players = tps.getPlayers();
if (lastDate == -1) {
lastDate = date;
lastPlayers = players;
continue;
}
long diff = date - lastDate;
if (lastPlayers == 0 && players == 0) {
idleTime += diff;
}
lastDate = date;
lastPlayers = players;
}
return idleTime;
}
public static double aboveLowThreshold(List<TPS> tpsData) {
if (tpsData.isEmpty()) {
return 1;
}
int threshold = Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber();
long count = 0;
for (TPS tps : tpsData) {
if (tps.getTicksPerSecond() >= threshold) {
count++;
}
}
return count * 1.0 / tpsData.size();
}
public PlayerProfile getPlayer(UUID uuid) {
if (playerMap == null) {
playerMap = players.stream().collect(Collectors.toMap(PlayerProfile::getUuid, Function.identity()));
}
return playerMap.get(uuid);
}
public void addActiveSessions(Map<UUID, Session> activeSessions) {
for (Map.Entry<UUID, Session> entry : activeSessions.entrySet()) {
UUID uuid = entry.getKey();
Session session = entry.getValue();
session.setSessionID((int) session.getSessionStart());
getPlayer(uuid).addActiveSession(session);
}
}
}

View File

@ -1,142 +0,0 @@
package main.java.com.djrapitops.plan.data.additional;
/**
* This class contains Enum values for different types of Analysis that can be
* performed on values of PluginData.
* <p>
* The enum determines what should be done to the return value of
* PluginData.getValue() method when the analysis is run.
* <p>
* Refer to the documentation on GitHub for additional information.
*
* @author Rsl1122
* @since 3.1.0
*/
public enum AnalysisType {
/**
* Used when the getValue() method returns an integer and average should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
INT_AVG("_avgInt", "Average "),
/**
* Used when the getValue() method returns a long and average should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_AVG("_avgLong", "Average "),
/**
* Used when the getValue() method returns double and average should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
DOUBLE_AVG("_avgDouble", "Average "),
/**
* Used when the getValue() method returns an integer and total should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
INT_TOTAL("_totalInt", "Total "),
/**
* Used when the getValue() method returns a long and total should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TOTAL("_totalLong", "Total "),
/**
* Used when the getValue() method returns a double and total should be
* calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
DOUBLE_TOTAL("_totalDouble", "Total "),
/**
* Used when the getValue() method returns an amount of milliseconds as long
* and average should be calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TIME_MS_AVG("_avgTimeMs", "Average "),
/**
* Used when the getValue() method returns an amount of milliseconds as long
* and total should be calculated.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TIME_MS_TOTAL("_totalTimeMs"),
/**
* Used when the getValue() method returns an Epoch Millisecond as long and
* average of differences between the millisecond and current millisecond
* should be calculated.
* <p>
* For example if a player has dropped a Foo on epoch ms 1494486504000 and
* that was 5s (5000ms) ago. Now you want to calculate the average
* time-since for all players. Then you use this one.
* <p>
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_EPOCH_MS_MINUS_NOW_AVG("_avgEpochMsMinusNow", "Average "),
/**
* Used to calculate %-true for the returned boolean values of getValue().
*/
BOOLEAN_PERCENTAGE("_perchBool", "Percentage "),
/**
* Used to calculate number of true values for the returned boolean values
* of getValue().
* <p>
* Will be presented as "n / total".
*/
BOOLEAN_TOTAL("_totalBool"),
/**
* Used to add html tags to the plugins tab.
* <p>
* Can be used to add Tables, Images (for example maps) and other html
* elements.
*/
HTML;
private final String modifier;
private final String placeholderModifier;
AnalysisType(String placeholderModifier, String modifier) {
this.placeholderModifier = placeholderModifier;
this.modifier = modifier;
}
AnalysisType(String placeholderModifier) {
this.placeholderModifier = placeholderModifier;
this.modifier = "";
}
AnalysisType() {
this.placeholderModifier = "";
this.modifier = "";
}
/**
* Used to get the modifier for the Prefix of the value.
* <p>
* For example: "Average Votes" when INT_AVG is used and Prefix is set as
* "Votes".
*
* @return Modifier, can be empty.
*/
public String getModifier() {
return modifier;
}
/**
* Used to get the Placeholder modifier.
*
* @return for example "_total"
*/
public String getPlaceholderModifier() {
return placeholderModifier;
}
}

View File

@ -1,354 +0,0 @@
package main.java.com.djrapitops.plan.data.additional;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.utilities.html.Html;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.Serializable;
import java.util.*;
/**
* This is an abstract class that can be used to add data from a plugin to the
* "Plugins"-tab of Analysis and Inspect pages.
* <p>
* API-section of documentation has examples on the usage of this class and how
* to register objects extending this class.
*
* @author Rsl1122
* @since 3.1.0
*/
public abstract class PluginData {
/**
* A list containing the AnalysisType enums that determine what should be
* done with the data on the analysis page.
*/
protected final List<AnalysisType> analysisTypes;
/**
* Placeholder string, for example "stepsTaken". This will be used when
* building the structure of the Plugins tab.
* <p>
* The complete placeholder also includes the plugin name and if analysis is
* run, a modifier.
* <p>
* Second parameter of any super constructor.
*/
protected final String placeholder;
/**
* Name of the plugin the data is coming from.
* <p>
* All sources of data with the same sourcePlugin will be placed in the same
* "box" in the "Plugins" tab.
* <p>
* A box has a max height of 600px, and higher than that will add a
* scrollbar.
* <p>
* First parameter of any super constructor.
*/
protected final String sourcePlugin;
/**
* Determines if the datapoint should only be used for the analysis page.
* <p>
* If set to false, the datapoint will be added to the inspect page as well.
*/
protected boolean analysisOnly;
/**
* Font Awesome icon name.
* <p>
* http://fontawesome.io/icons/
*/
protected String icon;
/**
* Prefix shown before the data, for example "Steps taken: ".
*/
protected String prefix;
/**
* Suffix shown after the data, for example " steps".
*/
protected String suffix;
/**
* Main constructor.
* <p>
* Defaults analysisOnly to true.
* <p>
* Defaults icon, prefix and suffix to "".
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
* @param analysisTypes A list containing the AnalysisType enums that
* determine what should be done with the data on the analysis page
*/
public PluginData(String sourcePlugin, String placeholder, List<AnalysisType> analysisTypes) {
this.placeholder = placeholder;
this.sourcePlugin = sourcePlugin;
analysisOnly = true;
this.analysisTypes = analysisTypes;
this.icon = "";
this.prefix = "";
this.suffix = "";
}
/**
* Constructor for accepting single, multiple and arrays of AnalysisType.
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
* @param analysisTypes AnalysisType enums that determine what should be
* done with the data on the analysis page
*/
public PluginData(String sourcePlugin, String placeholder, AnalysisType... analysisTypes) {
this(sourcePlugin, placeholder, Arrays.asList(analysisTypes));
}
/**
* Constructor for Inspect-page only data point.
* <p>
* analysisOnly will be set to false.
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
*/
public PluginData(String sourcePlugin, String placeholder) {
this(sourcePlugin, placeholder, new ArrayList<>());
analysisOnly = false;
}
/**
* Returns the list of AnalysisTypes.
* <p>
* Used by Analysis
*
* @return a list.
*/
public final List<AnalysisType> getAnalysisTypes() {
return analysisTypes;
}
/**
* This method should be used with the return values of
* getHtmlReplaceValue(String, UUID).
* <p>
* It will add the div, icon, modifier, prefix and suffix to the value.
* Modifier is for example, if calculating AnalysisType.INT_AVG "Average ",
* it is a text that helps user understand that a calculation has been made.
*
* @param modifier For example "Average " - Determined by value of
* AnalysisType's modifier-variable.
* @param contents The data, number/string/html that should be placed on the
* page.
* @return a proper format for the html.
* @see AnalysisType
*/
public final String parseContainer(String modifier, String contents) {
boolean html = analysisTypes.contains(AnalysisType.HTML);
return "<div class=\"plugin-data\">" + (html ? "" : "<p>") + (icon.isEmpty() ? "" : Html.FONT_AWESOME_ICON.parse(icon)) + " " + modifier + prefix + contents + suffix + (html ? "" : "</p>") + "</div>";
}
/**
* Used to get the full placeholder.
* <p>
* Used to avoid conflicts with existing placeholders and placeholders of
* other plugins.
*
* @param modifier Modifier determined by AnalysisType's
* placeholderModifier-variable.
* @return for example "${StepCounter_stepsTaken_total}"
* @see AnalysisType
*/
public final String getPlaceholder(String modifier) {
return "${" + getPlaceholderName(modifier) + "}";
}
/**
* Used to get the placeholder without the modifier.
*
* @return for example "${StepCounter_stepsTaken}"
* @see #getPlaceholder(String)
*/
public final String getPlaceholder() {
return "${" + getPlaceholderName() + "}";
}
/**
* Used to get the placeholder name with modifier.
*
* @return for example "StepCounter_stepsTaken_modifier"
* @see #getPlaceholder(String)
*/
public final String getPlaceholderName(String modifier) {
return getPlaceholderName() + modifier;
}
/**
* Used to get the placeholder name.
*
* @return for example "StepCounter_stepsTaken"
* @see #getPlaceholder(String)
*/
public final String getPlaceholderName() {
return sourcePlugin + "_" + placeholder;
}
/**
* Used to get the source plugin's name.
*
* @return for example "StepCounter"
*/
public final String getSourcePlugin() {
return sourcePlugin;
}
/**
* Used to get the string for the html page.
* <p>
* parseContainer(modifierPrefix, value); should be used for all return
* values so that div, icon, prefix and suffix are added.
* <p>
* This method is used when AnalysisType.HTML is set, or while getting the
* value for the inspect page.
* <p>
* When using AnalysisType.HTML a random UUID is given, so it should be
* disregarded. modifierPrefix is empty in that case.
*
* @param modifierPrefix Modifier determined by AnalysisType's
* modifier-variable.
* @param uuid UUID of the player or random UUID if AnalysisType.HTML is
* used.
* @return html for the page.
*/
public abstract String getHtmlReplaceValue(String modifierPrefix, UUID uuid);
/**
* Used to get the value for analysis. The return value is determined by
* AnalysisType you have specified. If the AnalysisType's name has a BOOLEAN
* in it, Analysis will expect boolean values etc.
* <p>
* If the Type and return value mismatch, exception is thrown and the result
* on the analysis page will say that error occurred as the value.
* <p>
* If a player has no value a -1 should be returned in the case of a Number.
* -1 is excluded from the Average calculation's size and total.
*
* @param uuid UUID of the player the value belongs to.
* @return Long, Integer, Double, Boolean or String, return -1 if the player
* has no value.
* @throws UnsupportedOperationException if implementing class has not overridden the method.
*/
public abstract Serializable getValue(UUID uuid);
public Map<UUID, Serializable> getValues(Collection<UUID> uuids) {
throw new UnsupportedOperationException("Not overridden.");
}
/**
* Used to set the Font Awesome icon.
*
* @param iconName Icon's name http://fontawesome.io/icons/
*/
public final void setIcon(String iconName) {
this.icon = iconName + " ";
}
/**
* Used to set the analysisOnly parameter.
* <p>
* true: only used for Analysis page false: used for both if AnalysisTypes
* specified, if no AnalysisTypes are specified only used for Inspect page.
*
* @param analysisOnly true/false
*/
public final void setAnalysisOnly(boolean analysisOnly) {
this.analysisOnly = analysisOnly;
}
/**
* Used to get the analysisOnly parameter.
*
* @return true/false
*/
public final boolean analysisOnly() {
return analysisOnly;
}
/**
* Used to get the prefix.
*
* @return example: "Steps Taken "
*/
public final String getPrefix() {
return prefix;
}
/**
* Used to set the prefix.
*
* @param prefix for example "Steps Taken: " or a Html start tag.
*/
public final void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Used to get the suffix.
*
* @return example: " steps"
*/
public final String getSuffix() {
return suffix;
}
/**
* Used to set the suffix.
*
* @param suffix for example " steps" or a html end tag.
*/
public final void setSuffix(String suffix) {
this.suffix = suffix;
}
public final boolean isBanData() {
return placeholder.contains("banned")
&& analysisTypes.contains(AnalysisType.BOOLEAN_TOTAL);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PluginData that = (PluginData) o;
return analysisOnly == that.analysisOnly &&
Objects.equals(analysisTypes, that.analysisTypes) &&
Objects.equals(placeholder, that.placeholder) &&
Objects.equals(sourcePlugin, that.sourcePlugin) &&
Objects.equals(icon, that.icon) &&
Objects.equals(prefix, that.prefix) &&
Objects.equals(suffix, that.suffix);
}
@Override
public int hashCode() {
return Objects.hash(analysisTypes, placeholder, sourcePlugin, analysisOnly, icon, prefix, suffix);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("analysisTypes", analysisTypes)
.append("placeholder", placeholder)
.append("sourcePlugin", sourcePlugin)
.append("analysisOnly", analysisOnly)
.append("icon", icon)
.append("prefix", prefix)
.append("suffix", suffix)
.toString();
}
protected Set<UUID> getUUIDsBeingAnalyzed() {
return Plan.getInstance().getDataCache().getUuids();
}
protected String getNameOf(UUID uuid) {
return Plan.getInstance().getDataCache().getName(uuid);
}
}

View File

@ -1,181 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.TPS;
import main.java.com.djrapitops.plan.systems.webserver.theme.Colors;
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.analysis.MathUtils;
import main.java.com.djrapitops.plan.utilities.html.graphs.PlayerActivityGraphCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.PunchCardGraphCreator;
import java.util.*;
import java.util.stream.Collectors;
/**
* Part responsible for all Player Activity related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${active} - (Number)
* ${inactive} - (Number)
* ${joinLeaver} - (Number)
* ${banned} - (Number)
* ${activityColors} - Color array
* ${playersGraphColor} - Color
* <p>
* ${playersOnlineSeries} - Data for HighCharts
* ${sessionLengthSeries} - Data for HighCharts
* ${punchCardSeries} - Data for HighCharts
* <p>
* ${sessionAverage} - Formatted Time amount
*
* @author Rsl1122
* @since 3.5.2
*/
public class ActivityPart extends RawData {
private final PlayerCountPart playerCount;
private final JoinInfoPart joins;
private final TPSPart tpsPart;
private final Set<UUID> bans;
private final Set<UUID> active;
private final Set<UUID> inactive;
private final Set<UUID> joinedOnce;
private List<String> recentPlayers;
private List<UUID> recentPlayersUUIDs;
public ActivityPart(PlayerCountPart playerCount, JoinInfoPart joins, TPSPart tps) {
this.playerCount = playerCount;
this.joins = joins;
tpsPart = tps;
bans = new HashSet<>();
active = new HashSet<>();
inactive = new HashSet<>();
joinedOnce = new HashSet<>();
}
@Override
public void analyse() {
Verify.nullCheck(recentPlayers);
Verify.nullCheck(recentPlayersUUIDs);
activityPiechart();
playerActivityGraphs();
final List<Session> sessions = joins.getAllSessions();
List<Long> lengths = AnalysisUtils.transformSessionDataToLengths(sessions);
long averageLength = MathUtils.averageLong(lengths);
addValue("sessionAverage", FormatUtils.formatTimeAmount(averageLength));
List<Session> sessionsMonth = sessions.stream()
.filter(s -> s.getSessionStart() > MiscUtils.getTime() - TimeAmount.MONTH.ms())
.collect(Collectors.toList());
addValue("punchCardSeries", PunchCardGraphCreator.createDataSeries(sessionsMonth));
}
private void playerActivityGraphs() {
List<TPS> tpsData = tpsPart.getTpsData();
addValue("playersOnlineSeries", PlayerActivityGraphCreator.buildSeriesDataString(tpsData));
addValue("playersGraphColor", Colors.PLAYERS_ONLINE.getColor());
}
private void activityPiechart() {
calculateActivityAmounts();
int[] counts = new int[]{active.size(), inactive.size(), joinedOnce.size(), bans.size()};
addValue("activityPieColors", Settings.THEME_GRAPH_ACTIVITY_PIE.toString());
addValue("playersActive", counts[0]);
addValue("active", counts[0]);
addValue("inactive", counts[1]);
addValue("joinLeaver", counts[2]);
addValue("banned", counts[3]);
}
private void calculateActivityAmounts() {
Map<UUID, List<Session>> allSessions = joins.getSessions();
for (UUID uuid : playerCount.getUuids()) {
if (bans.contains(uuid)) {
continue;
}
List<Session> sessions = allSessions.getOrDefault(uuid, new ArrayList<>());
long lastSeen = AnalysisUtils.getLastSeen(sessions);
long playtime = AnalysisUtils.getTotalPlaytime(sessions);
int sessionCount = sessions.size();
if (sessionCount <= 1) {
addJoinedOnce(uuid);
continue;
}
boolean isActive = AnalysisUtils.isActive(MiscUtils.getTime(), lastSeen, playtime, sessionCount);
if (isActive) {
addActive(uuid);
} else {
addInActive(uuid);
}
}
}
public void addBans(Collection<UUID> uuids) {
bans.addAll(uuids);
}
public void addBan(UUID uuid) {
bans.add(Verify.nullCheck(uuid));
}
public void addActive(UUID uuid) {
active.add(Verify.nullCheck(uuid));
}
public void addInActive(UUID uuid) {
inactive.add(Verify.nullCheck(uuid));
}
public void addJoinedOnce(UUID uuid) {
joinedOnce.add(Verify.nullCheck(uuid));
}
public Map<Long, Integer> getPlayersOnline() {
return tpsPart.getTpsData().stream().distinct().collect(Collectors.toMap(TPS::getDate, TPS::getPlayers));
}
public List<String> getRecentPlayers() {
return recentPlayers;
}
public void setRecentPlayers(List<String> recentPlayers) {
this.recentPlayers = recentPlayers;
}
public List<UUID> getRecentPlayersUUIDs() {
return recentPlayersUUIDs;
}
public void setRecentPlayersUUIDs(List<UUID> recentPlayersUUIDs) {
this.recentPlayersUUIDs = recentPlayersUUIDs;
}
public Set<UUID> getBans() {
return bans;
}
public Set<UUID> getActive() {
return active;
}
public Set<UUID> getInactive() {
return inactive;
}
public Set<UUID> getJoinedOnce() {
return joinedOnce;
}
}

View File

@ -1,62 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package main.java.com.djrapitops.plan.data.analysis;
import main.java.com.djrapitops.plan.utilities.html.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.html.tables.CommandUseTableCreator;
import java.util.HashMap;
import java.util.Map;
/**
* Part responsible for all CommandUsage related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${commandCount} - (Number)
* ${commandUniqueCount} - (Number)
* ${tableBodyCommands} - Table body for CommandUsage table.
*
* @author Rsl1122
* @since 3.5.2
*/
public class CommandUsagePart extends RawData {
private Map<String, Integer> commandUsage;
public CommandUsagePart() {
this.commandUsage = new HashMap<>();
}
@Override
public void analyse() {
addValue("commandUniqueCount", String.valueOf(getUniqueCommands()));
addValue("commandCount", String.valueOf(getCommandTotal()));
String commandUsageTable = CommandUseTableCreator.createTable(commandUsage);
addValue("tableBodyCommands", HtmlUtils.removeXSS(commandUsageTable));
}
public void setCommandUsage(Map<String, Integer> commandUsage) {
this.commandUsage = commandUsage;
}
public void addCommands(Map<String, Integer> commandUsage) {
this.commandUsage.putAll(commandUsage);
}
public int getUniqueCommands() {
return commandUsage.keySet().size();
}
public long getCommandTotal() {
return commandUsage.values().stream().mapToLong(i -> i).sum();
}
public Map<String, Integer> getCommandUsage() {
return commandUsage;
}
}

View File

@ -1,83 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldMapCreator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Part responsible for all Geolocation related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${geoMapSeries}
*
* @author Rsl1122
* @since 3.5.2
*/
public class GeolocationPart extends RawData {
private final Map<UUID, String> mostCommonGeolocations;
private final Map<String, String> geoCodes;
private final Map<String, Integer> geoCodeCounts;
public GeolocationPart() {
geoCodes = new HashMap<>();
geoCodeCounts = new HashMap<>();
mostCommonGeolocations = new HashMap<>();
String[] countries = new String[]{"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas, The", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burma", "Burundi", "Cabo Verde", "Cambodia", "Cameroon", "Canada", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic of the", "Congo, Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Curacao", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Islas Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Polynesia", "Gabon", "Gambia, The", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guam", "Guatemala", "Guernsey", "Guinea-Bissau", "Guinea", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, North", "Korea, South", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia, Federated States of", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Namibia", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Nigeria", "Niger", "Niue", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Puerto Rico", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia", "Saint Martin", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Sint Maarten", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Virgin Islands", "West Bank", "Yemen", "Zambia", "Zimbabwe"};
String[] codes = new String[]{"AFG", "ALB", "DZA", "ASM", "AND", "AGO", "AIA", "ATG", "ARG", "ARM", "ABW", "AUS", "AUT", "AZE", "BHM", "BHR", "BGD", "BRB", "BLR", "BEL", "BLZ", "BEN", "BMU", "BTN", "BOL", "BIH", "BWA", "BRA", "VGB", "BRN", "BGR", "BFA", "MMR", "BDI", "CPV", "KHM", "CMR", "CAN", "CYM", "CAF", "TCD", "CHL", "CHN", "COL", "COM", "COD", "COG", "COK", "CRI", "CIV", "HRV", "CUB", "CUW", "CYP", "CZE", "DNK", "DJI", "DMA", "DOM", "ECU", "EGY", "SLV", "GNQ", "ERI", "EST", "ETH", "FLK", "FRO", "FJI", "FIN", "FRA", "PYF", "GAB", "GMB", "GEO", "DEU", "GHA", "GIB", "GRC", "GRL", "GRD", "GUM", "GTM", "GGY", "GNB", "GIN", "GUY", "HTI", "HND", "HKG", "HUN", "ISL", "IND", "IDN", "IRN", "IRQ", "IRL", "IMN", "ISR", "ITA", "JAM", "JPN", "JEY", "JOR", "KAZ", "KEN", "KIR", "KOR", "PRK", "KSV", "KWT", "KGZ", "LAO", "LVA", "LBN", "LSO", "LBR", "LBY", "LIE", "LTU", "LUX", "MAC", "MKD", "MDG", "MWI", "MYS", "MDV", "MLI", "MLT", "MHL", "MRT", "MUS", "MEX", "FSM", "MDA", "MCO", "MNG", "MNE", "MAR", "MOZ", "NAM", "NPL", "NLD", "NCL", "NZL", "NIC", "NGA", "NER", "NIU", "MNP", "NOR", "OMN", "PAK", "PLW", "PAN", "PNG", "PRY", "PER", "PHL", "POL", "PRT", "PRI", "QAT", "ROU", "RUS", "RWA", "KNA", "LCA", "MAF", "SPM", "VCT", "WSM", "SMR", "STP", "SAU", "SEN", "SRB", "SYC", "SLE", "SGP", "SXM", "SVK", "SVN", "SLB", "SOM", "ZAF", "SSD", "ESP", "LKA", "SDN", "SUR", "SWZ", "SWE", "CHE", "SYR", "TWN", "TJK", "TZA", "THA", "TLS", "TGO", "TON", "TTO", "TUN", "TUR", "TKM", "TUV", "UGA", "UKR", "ARE", "GBR", "USA", "URY", "UZB", "VUT", "VEN", "VNM", "VGB", "WBG", "YEM", "ZMB", "ZWE"};
for (int i = 0; i < countries.length; i++) {
String country = countries[i];
String countryCode = codes[i];
geoCodes.put(country, countryCode);
geoCodeCounts.put(countryCode, 0);
}
}
@Override
public void analyse() {
addValue("geoMapSeries", WorldMapCreator.createDataSeries(geoCodeCounts));
}
public void addGeolocation(String country) {
String countryCode = geoCodes.get(country);
if (countryCode != null) {
geoCodeCounts.computeIfPresent(countryCode, (computedCountry, amount) -> amount + 1);
}
}
public void addGeoLocations(Map<UUID, List<String>> geolocations) {
for (Map.Entry<UUID, List<String>> entry : geolocations.entrySet()) {
String mostCommon = getMostCommon(entry.getValue());
mostCommonGeolocations.put(entry.getKey(), mostCommon);
addGeolocation(mostCommon);
}
}
private String getMostCommon(List<String> geoLocs) {
Map<String, Long> occurrences =
geoLocs.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
String mostCommon = "Not Known";
long count = -1;
for (Map.Entry<String, Long> entry : occurrences.entrySet()) {
Long value = entry.getValue();
if (value > count) {
mostCommon = entry.getKey();
count = value;
}
}
return mostCommon;
}
public Map<UUID, String> getMostCommonGeoLocations() {
return mostCommonGeolocations;
}
}

View File

@ -1,168 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.AnalysisUtils;
import main.java.com.djrapitops.plan.utilities.html.structure.SessionTabStructureCreator;
import main.java.com.djrapitops.plan.utilities.html.tables.SessionsTableCreator;
import java.util.*;
import java.util.stream.Collectors;
/**
* Part responsible for all Player player related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${playersAverage} - (Number)
* ${playersNewAverage} - (Number)
* <p>
* ${playersDay} - (Number)
* ${playersWeek} - (Number)
* ${playersMonth} - (Number)
* ${playersAverageDay} - (Number)
* ${playersAverageWeek} - (Number)
* ${playersAverageMonth} - (Number)
* ${playersNewDay} - (Number)
* ${playersNewWeek} - (Number)
* ${playersNewMonth} - (Number)
* ${playersNewAverageDay} - (Number)
* ${playersNewAverageWeek} - (Number)
* ${playersNewAverageMonth} - (Number)
*
* @author Rsl1122
* @since 3.5.2
*/
public class JoinInfoPart extends RawData {
private final Map<UUID, Session> activeSessions;
private final Map<UUID, List<Session>> sessions;
private final Map<UUID, Long> registered;
private long loginTimes;
public JoinInfoPart() {
activeSessions = new HashMap<>();
sessions = new HashMap<>();
registered = new HashMap<>();
loginTimes = 0;
}
@Override
public void analyse() {
newPlayers();
uniquePlayers();
uniquePlayersPerDay();
addValue("sessionCount", getAllSessions().size());
sessionTables();
}
private void sessionTables() {
String[] tables = SessionsTableCreator.createTable(this);
String[] sessionContent = SessionTabStructureCreator.creteStructure(this);
addValue("contentSessions", sessionContent[0]);
addValue("sessionTabGraphViewFunctions", sessionContent[1]);
addValue("tableBodySessions", tables[0]);
addValue("tableBodyRecentLogins", tables[1]);
}
private void uniquePlayers() {
int uniqueDay = AnalysisUtils.getUniqueJoins(sessions, TimeAmount.DAY.ms());
int uniqueWeek = AnalysisUtils.getUniqueJoins(sessions, TimeAmount.WEEK.ms());
int uniqueMonth = AnalysisUtils.getUniqueJoins(sessions, TimeAmount.MONTH.ms());
addValue("playersDay", uniqueDay);
addValue("playersWeek", uniqueWeek);
addValue("playersMonth", uniqueMonth);
}
private void uniquePlayersPerDay() {
int perDay = AnalysisUtils.getUniqueJoinsPerDay(sessions, -1);
int perDayDay = AnalysisUtils.getUniqueJoinsPerDay(sessions, TimeAmount.DAY.ms());
int perDayWeek = AnalysisUtils.getUniqueJoinsPerDay(sessions, TimeAmount.WEEK.ms());
int perDayMonth = AnalysisUtils.getUniqueJoinsPerDay(sessions, TimeAmount.MONTH.ms());
addValue("playersAverage", perDay);
addValue("playersAverageDay", perDayDay);
addValue("playersAverageWeek", perDayWeek);
addValue("playersAverageMonth", perDayMonth);
}
private void newPlayers() {
long now = MiscUtils.getTime();
List<Long> registeredList = getRegisteredList();
long newDay = AnalysisUtils.getNewPlayers(registeredList, TimeAmount.DAY.ms(), now);
long newWeek = AnalysisUtils.getNewPlayers(registeredList, TimeAmount.WEEK.ms(), now);
long newMonth = AnalysisUtils.getNewPlayers(registeredList, TimeAmount.MONTH.ms(), now);
addValue("playersNewDay", newDay);
addValue("playersNewWeek", newWeek);
addValue("playersNewMonth", newMonth);
long newPerDay = AnalysisUtils.getNewUsersPerDay(registeredList, -1);
long newPerDayDay = AnalysisUtils.getNewUsersPerDay(registeredList, TimeAmount.DAY.ms());
long newPerDayWeek = AnalysisUtils.getNewUsersPerDay(registeredList, TimeAmount.WEEK.ms());
long newPerDayMonth = AnalysisUtils.getNewUsersPerDay(registeredList, TimeAmount.MONTH.ms());
addValue("playersNewAverage", newPerDay);
addValue("playersNewAverageDay", newPerDayDay);
addValue("playersNewAverageWeek", newPerDayWeek);
addValue("playersNewAverageMonth", newPerDayMonth);
}
public void addToLoginTimes() {
addToLoginTimes(1);
}
public void addToLoginTimes(int amount) {
loginTimes += amount;
}
public long getLoginTimes() {
return loginTimes;
}
public Map<UUID, List<Session>> getSessions() {
return sessions;
}
public List<Session> getAllSessions() {
List<Session> sessions = MiscUtils.flatMap(this.sessions.values());
sessions.addAll(activeSessions.values());
return sessions;
}
public void addRegistered(UUID uuid, long registerDate) {
registered.put(uuid, registerDate);
}
public void addRegistered(Map<UUID, Long> registerDates) {
registered.putAll(registerDates);
}
public Map<UUID, Long> getRegistered() {
return registered;
}
public List<Long> getRegisteredList() {
return new ArrayList<>(registered.values());
}
public void addSessions(Map<UUID, List<Session>> sessions) {
this.sessions.putAll(Verify.nullCheck(sessions));
}
public void addSessions(UUID uuid, List<Session> sessions) {
Verify.nullCheck(uuid);
Verify.nullCheck(sessions);
this.sessions.put(uuid, sessions.stream().distinct().collect(Collectors.toList()));
}
public void addActiveSessions(Map<UUID, Session> activeSessions) {
this.activeSessions.putAll(activeSessions);
}
}

View File

@ -1,67 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import main.java.com.djrapitops.plan.data.PlayerKill;
import main.java.com.djrapitops.plan.data.Session;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Part responsible for all Death related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${killCount} - (Number)
* ${mobKillCount} - (Number)
* ${deathCount} - (Number)
*
* @author Rsl1122
* @since 3.5.2
*/
public class KillPart extends RawData {
private final JoinInfoPart joinInfoPart;
private long playerKills;
private long mobKills;
private long deaths;
public KillPart(JoinInfoPart joinInfoPart) {
this.joinInfoPart = joinInfoPart;
playerKills = 0;
mobKills = 0;
deaths = 0;
}
@Override
public void analyse() {
List<Session> sessions = joinInfoPart.getAllSessions();
deaths += sessions.stream().mapToLong(Session::getDeaths).sum();
mobKills += sessions.stream().mapToLong(Session::getMobKills).sum();
playerKills += sessions.stream().map(Session::getPlayerKills).mapToLong(Collection::size).sum();
addValue("deathCount", this.deaths);
addValue("mobKillCount", mobKills);
addValue("killCount", playerKills);
}
public long getPlayerKills() {
return playerKills;
}
public long getMobKills() {
return mobKills;
}
public long getDeaths() {
return deaths;
}
public void addKills(Map<UUID, List<PlayerKill>> playerKills) {
this.playerKills += playerKills.values().stream().mapToLong(Collection::size).sum();
}
}

View File

@ -1,68 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import com.djrapitops.plugin.utilities.Verify;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* Part responsible for counting players.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${playersTotal}, ${ops}
*
* @author Rsl1122
* @since 3.5.2
*/
public class PlayerCountPart extends RawData {
private final Set<UUID> uuids;
private final Set<UUID> ops;
public PlayerCountPart() {
uuids = new HashSet<>();
ops = new HashSet<>();
}
@Override
public void analyse() {
addValue("ops", ops.size());
addValue("playersTotal", uuids.size());
}
public void addPlayer(UUID uuid) {
Verify.nullCheck(uuid);
uuids.add(uuid);
}
public void addPlayers(Collection<UUID> uuids) {
Verify.nullCheck(uuids);
this.uuids.addAll(uuids);
}
public void addOPs(Collection<UUID> uuids) {
Verify.nullCheck(uuids);
this.ops.addAll(uuids);
}
public void addOP(UUID uuid) {
Verify.nullCheck(uuid);
ops.add(uuid);
}
public Set<UUID> getUuids() {
return uuids;
}
public int getPlayerCount() {
return uuids.size();
}
public Set<UUID> getOps() {
return ops;
}
}

View File

@ -1,54 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
/**
* Part responsible for all Playtime related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${playtimeTotal} - Formatted time amount
*
* @author Rsl1122
* @since 3.5.2
*/
public class PlaytimePart extends RawData {
private long totalPlaytime;
private long playtime30d;
private long playtime7d;
private long playtime24h;
public PlaytimePart() {
totalPlaytime = 0;
}
@Override
public void analyse() {
addValue("playtimeTotal", FormatUtils.formatTimeAmount(totalPlaytime));
addValue("playtimeMonth", FormatUtils.formatTimeAmount(playtime30d));
addValue("playtimeWeek", FormatUtils.formatTimeAmount(playtime7d));
addValue("playtimeDay", FormatUtils.formatTimeAmount(playtime24h));
}
public void addToPlaytime(long amount) {
totalPlaytime += amount;
}
public void setTotalPlaytime(long totalPlaytime) {
this.totalPlaytime = totalPlaytime;
}
public void setPlaytime30d(long playtime30d) {
this.playtime30d = playtime30d;
}
public void setPlaytime7d(long playtime7d) {
this.playtime7d = playtime7d;
}
public void setPlaytime24h(long playtime24h) {
this.playtime24h = playtime24h;
}
}

View File

@ -1,158 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.TPS;
import main.java.com.djrapitops.plan.systems.webserver.theme.Colors;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
import main.java.com.djrapitops.plan.utilities.html.graphs.CPUGraphCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.RamGraphCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.TPSGraphCreator;
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldLoadGraphCreator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Part responsible for all TPS related analysis.
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after being analyzed:
* ${tpsSeries} - HighCharts data
* ${cpuSeries} - HighCharts data
* ${ramSeries} - HighCharts data
* ${entitySeries} - HighCharts data
* ${chunkSeries} - HighCharts data
* <p>
* ${tpsAverageDay} - (Number)
* ${tpsAverageWeek} - (Number)
* ${cpuAverageDay} - (Number)%
* ${cpuAverageWeek} - (Number)%
* ${ramAverageDay} - (Number) MB
* ${ramAverageWeek} - (Number) MB
* ${entityAverageDay} - (Number)
* ${entityAverageWeek} - (Number)
* ${chunkAverageDay} - (Number)
* ${chunkAverageWeek} - (Number)
* <p>
* ${tpsMedium} - (Number) Color Threshold for Medium TPS
* ${tpsHigh} - (Number) Color Threshold for High TPS
* ${tpsLowColor} - Color of Low TPS
* ${tpsMediumColor} - Color of Low TPS
* ${tpsHighColor} - Color of Low TPS
*
* @author Rsl1122
* @since 3.5.2
*/
public class TPSPart extends RawData {
private final List<TPS> tpsData;
private TPS allTimePeak;
private TPS lastPeak;
public TPSPart() {
this.tpsData = new ArrayList<>();
}
@Override
public void analyse() {
long now = MiscUtils.getTime();
List<TPS> week = TPSGraphCreator.filterTPS(tpsData, now - TimeAmount.WEEK.ms());
List<TPS> day = TPSGraphCreator.filterTPS(tpsData, now - TimeAmount.DAY.ms());
tpsGraphOptions();
chartData();
averages(week, day);
peaks();
}
private void peaks() {
if (lastPeak != null) {
addValue("lastPeakTime", FormatUtils.formatTimeStampYear(lastPeak.getDate()));
addValue("playersLastPeak", lastPeak.getPlayers());
} else {
addValue("lastPeakTime", "No Data");
addValue("playersLastPeak", "-");
}
if (allTimePeak != null) {
addValue("bestPeakTime", FormatUtils.formatTimeStampYear(allTimePeak.getDate()));
addValue("playersBestPeak", allTimePeak.getPlayers());
} else {
addValue("bestPeakTime", "No Data");
addValue("playersBestPeak", "-");
}
}
private void averages(List<TPS> week, List<TPS> day) {
double averageTPSWeek = MathUtils.averageDouble(week.stream().map(TPS::getTicksPerSecond));
double averageTPSDay = MathUtils.averageDouble(day.stream().map(TPS::getTicksPerSecond));
double averageCPUWeek = MathUtils.averageDouble(week.stream().map(TPS::getCPUUsage).filter(i -> i != 0));
double averageCPUDay = MathUtils.averageDouble(day.stream().map(TPS::getCPUUsage).filter(i -> i != 0));
long averageUsedMemoryWeek = MathUtils.averageLong(week.stream().map(TPS::getUsedMemory).filter(i -> i != 0));
long averageUsedMemoryDay = MathUtils.averageLong(day.stream().map(TPS::getUsedMemory).filter(i -> i != 0));
double averageEntityCountWeek = MathUtils.averageInt(week.stream().map(TPS::getEntityCount).filter(i -> i != 0));
double averageEntityCountDay = MathUtils.averageInt(day.stream().map(TPS::getEntityCount).filter(i -> i != 0));
double averageChunksLoadedWeek = MathUtils.averageInt(week.stream().map(TPS::getChunksLoaded).filter(i -> i != 0));
double averageChunksLoadedDay = MathUtils.averageInt(day.stream().map(TPS::getChunksLoaded).filter(i -> i != 0));
addValue("tpsAverageWeek", FormatUtils.cutDecimals(averageTPSWeek));
addValue("tpsAverageDay", FormatUtils.cutDecimals(averageTPSDay));
addValue("cpuAverageWeek", averageCPUWeek >= 0 ? FormatUtils.cutDecimals(averageCPUWeek) + "%" : "Unavailable");
addValue("cpuAverageDay", averageCPUDay >= 0 ? FormatUtils.cutDecimals(averageCPUDay) + "%" : "Unavailable");
addValue("ramAverageWeek", FormatUtils.cutDecimals(averageUsedMemoryWeek));
addValue("ramAverageDay", FormatUtils.cutDecimals(averageUsedMemoryDay));
addValue("entityAverageWeek", FormatUtils.cutDecimals(averageEntityCountWeek));
addValue("entityAverageDay", FormatUtils.cutDecimals(averageEntityCountDay));
addValue("chunkAverageWeek", FormatUtils.cutDecimals(averageChunksLoadedWeek));
addValue("chunkAverageDay", FormatUtils.cutDecimals(averageChunksLoadedDay));
}
private void chartData() {
addValue("tpsSeries", TPSGraphCreator.buildSeriesDataString(tpsData));
addValue("cpuSeries", CPUGraphCreator.buildSeriesDataString(tpsData));
addValue("ramSeries", RamGraphCreator.buildSeriesDataString(tpsData));
addValue("entitySeries", WorldLoadGraphCreator.buildSeriesDataStringEntities(tpsData));
addValue("chunkSeries", WorldLoadGraphCreator.buildSeriesDataStringChunks(tpsData));
}
private void tpsGraphOptions() {
addValue("tpsHighColor", Colors.TPS_HIGH.getColor());
addValue("tpsMediumColor", Colors.TPS_MED.getColor());
addValue("tpsLowColor", Colors.TPS_LOW.getColor());
addValue("tpsMedium", Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber());
addValue("tpsHigh", Settings.THEME_GRAPH_TPS_THRESHOLD_HIGH.getNumber());
}
public List<TPS> getTpsData() {
return tpsData;
}
public void addTpsData(Collection<TPS> data) {
tpsData.addAll(Verify.nullCheck(data));
}
public void setAllTimePeak(TPS allTimePeak) {
this.allTimePeak = allTimePeak;
}
public void setLastPeak(TPS lastPeak) {
this.lastPeak = lastPeak;
}
}

View File

@ -1,49 +0,0 @@
package main.java.com.djrapitops.plan.data.analysis;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.html.graphs.WorldPieCreator;
import java.util.HashMap;
/**
* Part responsible for all World Playtime related analysis.
* <p>
* World times Pie
* <p>
* Placeholder values can be retrieved using the get method.
* <p>
* Contains following placeholders after analyzed:
* ${worldTotal} - Total playtime for all worlds
* ${worldSeries} - Data for HighCharts
*
* @author Rsl1122
* @since 3.6.0
*/
public class WorldPart extends RawData {
private WorldTimes worldTimes;
public WorldPart() {
worldTimes = new WorldTimes(new HashMap<>());
}
@Override
protected void analyse() {
addValue("worldTotal", FormatUtils.formatTimeAmount(worldTimes.getTotal()));
String[] seriesData = WorldPieCreator.createSeriesData(worldTimes);
addValue("worldSeries", seriesData[0]);
addValue("gmSeries", seriesData[1]);
addValue("worldPieColors", Settings.THEME_GRAPH_WORLD_PIE.toString());
addValue("gmPieColors", Settings.THEME_GRAPH_GM_PIE.toString());
}
public WorldTimes getWorldTimes() {
return worldTimes;
}
public void setWorldTimes(WorldTimes worldTimes) {
this.worldTimes = worldTimes;
}
}

View File

@ -2,8 +2,9 @@
* 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.data;
package main.java.com.djrapitops.plan.data.container;
import main.java.com.djrapitops.plan.data.HasDate;
import main.java.com.djrapitops.plan.database.tables.Actions;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.html.Html;
@ -15,7 +16,7 @@ import java.util.Objects;
*
* @author Rsl1122
*/
public class Action {
public class Action implements HasDate {
private final long date;
private final Actions doneAction;
private final String additionalInfo;

View File

@ -0,0 +1,57 @@
/*
* 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.data.container;
import com.google.common.base.Objects;
import main.java.com.djrapitops.plan.data.HasDate;
/**
* Data class that contains information about IP and Geolocation.
*
* @author Rsl1122
*/
public class GeoInfo implements HasDate {
private final String ip;
private final String geolocation;
private final long lastUsed;
public GeoInfo(String ip, String geolocation, long lastUsed) {
this.ip = ip;
this.geolocation = geolocation;
this.lastUsed = lastUsed;
}
public String getIp() {
return ip;
}
public String getGeolocation() {
return geolocation;
}
public long getLastUsed() {
return lastUsed;
}
@Override
public long getDate() {
return getLastUsed();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeoInfo geoInfo = (GeoInfo) o;
return Objects.equal(ip, geoInfo.ip) &&
Objects.equal(geolocation, geoInfo.geolocation);
}
@Override
public int hashCode() {
return Objects.hashCode(ip, geolocation);
}
}

View File

@ -1,6 +1,7 @@
package main.java.com.djrapitops.plan.data;
package main.java.com.djrapitops.plan.data.container;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.HasDate;
import main.java.com.djrapitops.plan.database.tables.Actions;
import org.apache.commons.lang3.builder.ToStringBuilder;
@ -13,7 +14,7 @@ import java.util.UUID;
*
* @author Rsl1122
*/
public class PlayerKill {
public class PlayerKill implements HasDate {
private final UUID victim;
private final long time;
@ -50,6 +51,11 @@ public class PlayerKill {
return time;
}
@Override
public long getDate() {
return getTime();
}
/**
* Get the Weapon used as string.
*

View File

@ -1,6 +1,8 @@
package main.java.com.djrapitops.plan.data;
package main.java.com.djrapitops.plan.data.container;
import main.java.com.djrapitops.plan.data.HasDate;
import main.java.com.djrapitops.plan.data.time.WorldTimes;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.ArrayList;
@ -26,7 +28,7 @@ import java.util.Objects;
*
* @author Rsl1122
*/
public class Session {
public class Session implements HasDate {
private final long sessionStart;
private Integer sessionID;
@ -119,6 +121,9 @@ public class Session {
* @return Long in ms.
*/
public long getLength() {
if (sessionEnd == -1) {
return MiscUtils.getTime() - sessionStart;
}
return sessionEnd - sessionStart;
}
@ -175,7 +180,7 @@ public class Session {
* @throws NullPointerException if Session was not fetched from DB. Condition using {@code isFetchedFromDB}
*/
public int getSessionID() {
return sessionID;
return sessionID != null ? sessionID : -1;
}
public void setSessionID(int sessionID) {
@ -212,4 +217,9 @@ public class Session {
.append("deaths", deaths)
.toString();
}
@Override
public long getDate() {
return getSessionStart();
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.data.container;
import com.djrapitops.plugin.api.TimeAmount;
import com.google.common.base.Objects;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import main.java.com.djrapitops.plan.database.tables.Actions;
public class StickyData {
private final double activityIndex;
private Integer messagesSent;
private Integer onlineOnJoin;
public StickyData(PlayerProfile player) {
activityIndex = player.getActivityIndex(player.getRegistered() + TimeAmount.DAY.ms());
for (Action action : player.getActions()) {
if (messagesSent == null && action.getDoneAction() == Actions.FIRST_LOGOUT) {
String additionalInfo = action.getAdditionalInfo();
String[] split = additionalInfo.split(": ");
if (split.length == 2) {
try {
messagesSent = Integer.parseInt(split[1]);
} catch (NumberFormatException ignored) {
}
}
}
if (onlineOnJoin == null && action.getDoneAction() == Actions.FIRST_SESSION) {
String additionalInfo = action.getAdditionalInfo();
String[] split = additionalInfo.split(" ");
if (split.length == 3) {
try {
onlineOnJoin = Integer.parseInt(split[1]);
} catch (NumberFormatException ignored) {
}
}
}
}
if (messagesSent == null) {
messagesSent = 0;
}
if (onlineOnJoin == null) {
onlineOnJoin = 0;
}
}
public double distance(StickyData data) {
double num = 0;
num += Math.abs(data.activityIndex - activityIndex) * 2.0;
num += Math.abs(data.onlineOnJoin - onlineOnJoin) / 10.0;
num += Math.abs(data.messagesSent - messagesSent) / 10.0;
return num;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StickyData that = (StickyData) o;
return Double.compare(that.activityIndex, activityIndex) == 0 &&
Objects.equal(messagesSent, that.messagesSent) &&
Objects.equal(onlineOnJoin, that.onlineOnJoin);
}
@Override
public int hashCode() {
return Objects.hashCode(activityIndex, messagesSent, onlineOnJoin);
}
public int getOnlineOnJoin() {
return onlineOnJoin;
}
}

View File

@ -3,8 +3,9 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package main.java.com.djrapitops.plan.data;
package main.java.com.djrapitops.plan.data.container;
import main.java.com.djrapitops.plan.data.HasDate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Objects;
@ -15,7 +16,7 @@ import java.util.Objects;
* @author Rsl1122
* @since 3.5.0
*/
public class TPS {
public class TPS implements HasDate {
private final long date;
private final double ticksPerSecond;

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan.data;
package main.java.com.djrapitops.plan.data.container;
import java.util.Objects;
import java.util.UUID;

View File

@ -0,0 +1,55 @@
/*
* 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.data.element;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
/**
* Container used to parse data for Analysis page.
* <p>
* Similar to InspectContainer, but can contain data for each player for a bigger Player data table.
* <p>
* Can contain values: addValue("Total Examples", 1) parses into ("Total Examples: 1")
* Html: addHtml(key, "{@code <html>}") parses into ("{@code <html>}")
* Tables: addTable(key, TableContainer) parses into ("{@code <table>...</table}")
* Player Data for a big table: {@code addTableData("header", Map<UUID, value>)} parses a new column to Plugin data player table.
* <p>
* Has methods for adding icons to Strings:
* getWithIcon("text", "cube") parses into {@code "<i class=\"fa fa-cube\"></i> text"}
* getWithColoredIcon("text", "cube", "light-green") parses into {@code "<i class=\"col-light-green fa fa-cube\"></i> text"}
*
* @author Rsl1122
* @see TableContainer
* @see InspectContainer
* @since 4.1.0
*/
public final class AnalysisContainer extends InspectContainer {
private TreeMap<String, Map<UUID, ? extends Serializable>> playerTableValues;
public AnalysisContainer() {
playerTableValues = new TreeMap<>();
}
public TreeMap<String, Map<UUID, ? extends Serializable>> getPlayerTableValues() {
return playerTableValues;
}
public void addPlayerTableValues(String columnName, Map<UUID, ? extends Serializable> values) {
playerTableValues.put(columnName, values);
}
@Override
public boolean isEmpty() {
return playerTableValues.isEmpty() && super.isEmpty();
}
public boolean hasPlayerTableValues() {
return !playerTableValues.isEmpty();
}
}

View File

@ -0,0 +1,252 @@
/*
* 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.data.element;
import com.djrapitops.plugin.api.TimeAmount;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import main.java.com.djrapitops.plan.data.ServerProfile;
import main.java.com.djrapitops.plan.data.container.StickyData;
import main.java.com.djrapitops.plan.data.container.TPS;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
import main.java.com.djrapitops.plan.utilities.html.Html;
import java.util.*;
import java.util.stream.Collectors;
/**
* Class in charge of Server health analysis.
*
* @author Rsl1122
*/
public class HealthNotes {
private final List<String> healthNotes;
private double serverHealth;
private final AnalysisData analysisData;
private final TreeMap<Long, Map<String, Set<UUID>>> activityData;
private final List<TPS> tpsDataMonth;
private final long now;
private final long fourWeeksAgo;
public HealthNotes(AnalysisData analysisData, TreeMap<Long, Map<String, Set<UUID>>> activityData, List<TPS> tpsDataMonth, long now) {
this.healthNotes = new ArrayList<>();
serverHealth = 100.0;
this.analysisData = analysisData;
this.activityData = activityData;
this.tpsDataMonth = tpsDataMonth;
this.now = now;
this.fourWeeksAgo = now - TimeAmount.WEEK.ms() * 4L;
}
public void analyzeHealth() {
activityChangeNote();
newPlayerNote();
activePlayerPlaytimeChange();
lowPerformance();
}
public String parse() {
StringBuilder healthNoteBuilder = new StringBuilder();
for (String healthNote : healthNotes) {
healthNoteBuilder.append(healthNote);
}
return healthNoteBuilder.toString();
}
public double getServerHealth() {
return serverHealth;
}
private void activityChangeNote() {
Map<String, Set<UUID>> activityNow = activityData.getOrDefault(now, new HashMap<>());
Set<UUID> veryActiveNow = activityNow.getOrDefault("Very Active", new HashSet<>());
Set<UUID> activeNow = activityNow.getOrDefault("Active", new HashSet<>());
Set<UUID> regularNow = activityNow.getOrDefault("Regular", new HashSet<>());
Map<String, Set<UUID>> activityFourWAgo = activityData.getOrDefault(fourWeeksAgo, new HashMap<>());
Set<UUID> veryActiveFWAG = activityFourWAgo.getOrDefault("Very Active", new HashSet<>());
Set<UUID> activeFWAG = activityFourWAgo.getOrDefault("Active", new HashSet<>());
Set<UUID> regularFWAG = activityFourWAgo.getOrDefault("Regular", new HashSet<>());
Set<UUID> regularRemainCompareSet = new HashSet<>(regularFWAG);
regularRemainCompareSet.addAll(activeFWAG);
regularRemainCompareSet.addAll(veryActiveFWAG);
int activeFWAGNum = regularRemainCompareSet.size();
regularRemainCompareSet.removeAll(regularNow);
regularRemainCompareSet.removeAll(activeNow);
regularRemainCompareSet.removeAll(veryActiveNow);
int notRegularAnymore = regularRemainCompareSet.size();
int remain = activeFWAGNum - notRegularAnymore;
double percRemain = remain * 100.0 / activeFWAGNum;
int newActive = getNewActive(veryActiveNow, activeNow, regularNow, veryActiveFWAG, activeFWAG, regularFWAG);
int change = newActive - notRegularAnymore;
String remainNote = "";
if (activeFWAGNum != 0) {
remainNote = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
if (percRemain > 50) {
remainNote += Html.GREEN_THUMB.parse();
} else if (percRemain > 20) {
remainNote += Html.YELLOW_FLAG.parse();
} else {
remainNote += Html.RED_WARN.parse();
serverHealth -= 2.5;
}
remainNote += " " + FormatUtils.cutDecimals(percRemain) + "% of regular players have remained active ("
+ remain + "/" + activeFWAGNum + ")";
}
if (change > 0) {
healthNotes.add(
"<p>" + Html.GREEN_THUMB.parse() + " Number of regular players has increased (+" + change + ")<br>" +
remainNote + "</p>");
} else if (change == 0) {
healthNotes.add(
"<p>" + Html.GREEN_THUMB.parse() + " Number of regular players has stayed the same (+" + change + ")<br>" +
remainNote + "</p>");
} else if (change > -20) {
healthNotes.add(
"<p>" + Html.YELLOW_FLAG.parse() + " Number of regular players has decreased (" + change + ")<br>" +
remainNote + "</p>");
serverHealth -= 5;
} else {
healthNotes.add(
"<p>" + Html.RED_WARN.parse() + " Number of regular players has decreased (" + change + ")<br>" +
remainNote + "</p>");
serverHealth -= 10;
}
}
private void newPlayerNote() {
double avgOnlineOnRegister = MathUtils.averageInt(analysisData.getStickyMonthData().stream().map(StickyData::getOnlineOnJoin));
if (avgOnlineOnRegister >= 1) {
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " New Players have players to play with when they join ("
+ FormatUtils.cutDecimals(avgOnlineOnRegister) + " on average)</p>");
} else {
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " New Players may not have players to play with when they join ("
+ FormatUtils.cutDecimals(avgOnlineOnRegister) + " on average)</p>");
serverHealth -= 5;
}
long newM = analysisData.value("newM");
long stuckPerM = analysisData.value("stuckPerM");
if (newM != 0) {
double stuckPerc = MathUtils.averageDouble(stuckPerM, newM) * 100;
if (stuckPerc >= 25) {
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " " + FormatUtils.cutDecimals(stuckPerc)
+ "% of new players have stuck around (" + stuckPerM + "/" + newM + ")</p>");
} else {
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " " + FormatUtils.cutDecimals(stuckPerc)
+ "% of new players have stuck around (" + stuckPerM + "/" + newM + ")</p>");
}
}
}
private void activePlayerPlaytimeChange() {
List<PlayerProfile> currentActivePlayers = analysisData.getPlayers().stream()
.filter(player -> player.getActivityIndex(now) >= 1.75)
.collect(Collectors.toList());
long twoWeeksAgo = now - TimeAmount.WEEK.ms() * 2L;
long totalFourToTwoWeeks = 0;
long totalLastTwoWeeks = 0;
for (PlayerProfile activePlayer : currentActivePlayers) {
totalFourToTwoWeeks += activePlayer.getPlaytime(analysisData.value("monthAgo"), twoWeeksAgo);
totalLastTwoWeeks += activePlayer.getPlaytime(twoWeeksAgo, now);
}
int currentlyActive = currentActivePlayers.size();
if (currentlyActive != 0) {
long avgFourToTwoWeeks = MathUtils.averageLong(totalFourToTwoWeeks, currentlyActive);
long avgLastTwoWeeks = MathUtils.averageLong(totalLastTwoWeeks, currentlyActive);
String avgLastTwoWeeksString = FormatUtils.formatTimeAmount(avgLastTwoWeeks);
String avgFourToTwoWeeksString = FormatUtils.formatTimeAmount(avgFourToTwoWeeks);
if (avgFourToTwoWeeks >= avgLastTwoWeeks) {
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " Active players to have things to do (Played "
+ avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString
+ ", last two weeks vs weeks 2-4)</p>");
} else if (avgFourToTwoWeeks - avgLastTwoWeeks > TimeAmount.HOUR.ms() * 2L) {
healthNotes.add("<p>" + Html.RED_WARN.parse() + " Active players might to be running out of things to do (Played "
+ avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString
+ ", last two weeks vs weeks 2-4)</p>");
serverHealth -= 5;
} else {
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " Active players might to be running out of things to do (Played "
+ avgLastTwoWeeksString + " vs " + avgFourToTwoWeeksString
+ ", last two weeks vs weeks 2-4)</p>");
}
}
}
private void lowPerformance() {
long serverDownTime = ServerProfile.serverDownTime(tpsDataMonth);
double aboveThreshold = ServerProfile.aboveLowThreshold(tpsDataMonth);
long tpsSpikeMonth = analysisData.value("tpsSpikeMonth");
String avgLowThresholdString = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
if (aboveThreshold >= 0.96) {
avgLowThresholdString += Html.GREEN_THUMB.parse();
} else if (aboveThreshold >= 0.9) {
avgLowThresholdString += Html.YELLOW_FLAG.parse();
serverHealth *= 0.9;
} else {
avgLowThresholdString += Html.RED_WARN.parse();
serverHealth *= 0.6;
}
avgLowThresholdString += " Average TPS was above Low Threshold "
+ FormatUtils.cutDecimals(aboveThreshold * 100.0) + "% of the time";
if (tpsSpikeMonth <= 5) {
healthNotes.add("<p>" + Html.GREEN_THUMB.parse()
+ " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" +
" " + tpsSpikeMonth + " times<br>" +
avgLowThresholdString + "</p>");
} else if (tpsSpikeMonth <= 25) {
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse()
+ " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" +
" " + tpsSpikeMonth + " times<br>" +
avgLowThresholdString + "</p>");
serverHealth *= 0.95;
} else {
healthNotes.add("<p>" + Html.RED_WARN.parse()
+ " Average TPS dropped below Low Threshold (" + Settings.THEME_GRAPH_TPS_THRESHOLD_MED.getNumber() + ")" +
" " + tpsSpikeMonth + " times<br>" +
avgLowThresholdString + "</p>");
serverHealth *= 0.8;
}
if (serverDownTime <= TimeAmount.DAY.ms()) {
healthNotes.add("<p>" + Html.GREEN_THUMB.parse() + " Total Server downtime (No Data) was "
+ FormatUtils.formatTimeAmount(serverDownTime) + "</p>");
} else if (serverDownTime <= TimeAmount.WEEK.ms()) {
healthNotes.add("<p>" + Html.YELLOW_FLAG.parse() + " Total Server downtime (No Data) was "
+ FormatUtils.formatTimeAmount(serverDownTime) + "</p>");
serverHealth *= (TimeAmount.WEEK.ms() - serverDownTime) * 1.0 / TimeAmount.WEEK.ms();
} else {
healthNotes.add("<p>" + Html.RED_WARN.parse() + " Total Server downtime (No Data) was "
+ FormatUtils.formatTimeAmount(serverDownTime) + "</p>");
serverHealth *= (TimeAmount.MONTH.ms() - serverDownTime) * 1.0 / TimeAmount.MONTH.ms();
}
}
private int getNewActive(Set<UUID> veryActiveNow, Set<UUID> activeNow, Set<UUID> regularNow, Set<UUID> veryActiveFWAG, Set<UUID> activeFWAG, Set<UUID> regularFWAG) {
Set<UUID> regularNewCompareSet = new HashSet<>(regularNow);
regularNewCompareSet.addAll(activeNow);
regularNewCompareSet.addAll(veryActiveNow);
regularNewCompareSet.removeAll(regularFWAG);
regularNewCompareSet.removeAll(activeFWAG);
regularNewCompareSet.removeAll(veryActiveFWAG);
return regularNewCompareSet.size();
}
}

View File

@ -0,0 +1,83 @@
/*
* 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.data.element;
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
/**
* Container used to parse data for Inspect page.
* <p>
* Can contain values: addValue("Total Examples", 1) parses into ("Total Examples: 1")
* Html: addHtml(key, "{@code <html>}") parses into ("{@code <html>}")
* Tables: addTable(key, TableContainer) parses into ("{@code <table>...</table}")
* <p>
* Has methods for adding icons to Strings:
* getWithIcon("text", "cube") parses into {@code "<i class=\"fa fa-cube\"></i> text"}
* getWithColoredIcon("text", "cube", "light-green") parses into {@code "<i class=\"col-light-green fa fa-cube\"></i> text"}
*
* @author Rsl1122
* @see TableContainer
* @since 4.1.0
*/
public class InspectContainer {
protected TreeMap<String, String> values;
protected TreeMap<String, String> html;
protected TreeMap<String, TableContainer> tables;
public InspectContainer() {
values = new TreeMap<>();
html = new TreeMap<>();
tables = new TreeMap<>();
}
public final void addValue(String label, Serializable value) {
values.put(label, value.toString());
}
public final void addHtml(String key, String html) {
this.html.put(key, html);
}
public final void addTable(String key, TableContainer table) {
tables.put(key, table);
}
public final String parseHtml() {
StringBuilder html = new StringBuilder();
if (!values.isEmpty()) {
html.append("<div class=\"body\">");
for (Map.Entry<String, String> entry : values.entrySet()) {
html.append("<p>").append(entry.getKey()).append(": ").append(entry.getValue()).append("</p>");
}
html.append("</div>");
}
for (Map.Entry<String, String> entry : this.html.entrySet()) {
html.append(entry.getValue());
}
for (Map.Entry<String, TableContainer> entry : tables.entrySet()) {
html.append(entry.getValue().parseHtml());
}
return html.toString();
}
public final boolean hasOnlyValues() {
return html.isEmpty() && tables.isEmpty();
}
public boolean isEmpty() {
return values.isEmpty() && html.isEmpty() && tables.isEmpty();
}
public final boolean hasValues() {
return !values.isEmpty();
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.data.element;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.html.Html;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Container used for parsing Html tables.
*
* @author Rsl1122
*/
public final class TableContainer {
private final String[] header;
private List<Serializable[]> values;
private String color;
/**
* Constructor, call with super(...).
*
* @param header Required: example {@code new TableContainer("1st", "2nd"} parses into {@code <thead><tr><th>1st</th><th>2nd</th></tr></thead}.
*/
public TableContainer(String... header) {
this.header = header;
values = new ArrayList<>();
}
public TableContainer(boolean players, String... header) {
this.header = FormatUtils.mergeArrays(new String[]{Html.FONT_AWESOME_ICON.parse("user") + " Player"}, header);
values = new ArrayList<>();
}
public void addRow(Serializable... values) {
this.values.add(values);
}
public String parseHtml() {
return Html.TABLE_SCROLL.parse() +
parseHeader() +
parseBody() +
"</table>";
}
private String parseBody() {
StringBuilder body = new StringBuilder();
if (values.isEmpty()) {
addRow("No Data");
}
for (Serializable[] row : values) {
int maxIndex = row.length - 1;
body.append("<tr>");
for (int i = 0; i < header.length; i++) {
body.append("<td>");
if (i > maxIndex) {
body.append("-");
} else {
body.append(row[i]);
}
body.append("</td>");
}
body.append("</tr>");
}
return Html.TABLE_BODY.parse(body.toString());
}
public void setColor(String color) {
this.color = color;
}
public String parseHeader() {
StringBuilder header = new StringBuilder("<thead" + (color != null ? " class=\"bg-" + color + "\"" : "") + "><tr>");
for (String title : this.header) {
header.append("<th>").append(title).append("</th>");
}
header.append("</tr></thead>");
return header.toString();
}
}

View File

@ -0,0 +1,27 @@
/*
* 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.data.plugin;
import java.util.Collection;
import java.util.UUID;
/**
* Interface for PluginData objects that affect Ban state of players.
*
* @author Rsl1122
*/
public interface BanData {
boolean isBanned(UUID uuid);
/**
* Method that should return only banned players of the given UUIDs.
*
* @param uuids UUIDs to filter.
* @return UUIDs from the collection uuids that are banned.
*/
Collection<UUID> filterBanned(Collection<UUID> uuids);
}

View File

@ -0,0 +1,17 @@
/*
* 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.data.plugin;
/**
* Enum class for PluginData to estimate the required width of the contained items.
*
* @author Rsl1122
*/
public enum ContainerSize {
THIRD,
TWO_THIRDS,
WHOLE,
TAB
}

View File

@ -1,13 +1,12 @@
package main.java.com.djrapitops.plan.data.additional;
package main.java.com.djrapitops.plan.data.plugin;
import com.djrapitops.plugin.StaticHolder;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.pluginbridge.plan.Bridge;
import main.java.com.djrapitops.plan.Plan;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.List;
/**
* Class responsible for hooking to other plugins and managing the %plugins%
@ -48,12 +47,16 @@ public class HookHandler {
* @param dataSource an object extending the PluginData class.
*/
public void addPluginDataSource(PluginData dataSource) {
if (dataSource == null) {
return;
}
try {
StaticHolder.saveInstance(dataSource.getClass(), Plan.class);
if (!configHandler.hasSection(dataSource)) {
configHandler.createSection(dataSource);
}
if (configHandler.isEnabled(dataSource)) {
Log.debug("Registered a new datasource: " + StringUtils.remove(dataSource.getPlaceholder(), '%'));
Log.debug("Registered a new datasource: " + dataSource.getSourcePlugin());
additionalDataSources.add(dataSource);
}
} catch (Exception e) {
@ -70,47 +73,4 @@ public class HookHandler {
public List<PluginData> getAdditionalDataSources() {
return additionalDataSources;
}
private List<String> getPluginNamesAnalysis() {
List<String> pluginNames = additionalDataSources.stream()
.filter(source -> !source.getAnalysisTypes().isEmpty())
.map(PluginData::getSourcePlugin)
.distinct()
.collect(Collectors.toList());
Collections.sort(pluginNames);
return pluginNames;
}
private List<String> getPluginNamesInspect() {
List<String> pluginNames = additionalDataSources.stream()
.filter(source -> !source.analysisOnly())
.map(PluginData::getSourcePlugin)
.distinct()
.collect(Collectors.toList());
Collections.sort(pluginNames);
return pluginNames;
}
/**
* Used to get the replaceMap for inspect page.
*
* @param uuid UUID of the player whose page is being inspected.
* @return Map: key|value - %placeholder%|value
*/
public Map<String, Serializable> getAdditionalInspectReplaceRules(UUID uuid) {
Map<String, Serializable> addReplace = new HashMap<>();
for (PluginData source : additionalDataSources) {
if (source.analysisOnly()) {
continue;
}
try {
addReplace.put(source.getPlaceholderName(), source.getHtmlReplaceValue("", uuid));
} catch (Exception e) {
addReplace.put(source.getPlaceholderName(), "Error occurred: " + e);
Log.error("PluginDataSource caused an exception: " + source.getSourcePlugin());
Log.toLog("PluginDataSource " + source.getSourcePlugin(), e);
}
}
return addReplace;
}
}

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan.data.additional;
package main.java.com.djrapitops.plan.data.plugin;
import com.djrapitops.plugin.api.config.ConfigNode;
import com.djrapitops.plugin.api.utility.log.Log;
@ -27,9 +27,7 @@ public class PluginConfigSectionHandler {
if (!section.getChildren().containsKey(pluginName)) {
return false;
}
ConfigNode pluginSection = section.getConfigNode(pluginName);
return pluginSection.getChildren().containsKey(dataSource.placeholder);
return section.getConfigNode(pluginName).getChildren().containsKey("Enabled");
}
private ConfigNode getPluginsSection() {
@ -39,10 +37,8 @@ public class PluginConfigSectionHandler {
public void createSection(PluginData dataSource) {
ConfigNode section = getPluginsSection();
String pluginName = dataSource.getSourcePlugin();
String source = dataSource.placeholder;
section.set(pluginName + ".Enabled", true);
section.set(pluginName + ".Data." + source, true);
try {
section.sort();
section.save();
@ -55,11 +51,6 @@ public class PluginConfigSectionHandler {
ConfigNode section = getPluginsSection();
String pluginName = dataSource.getSourcePlugin();
if (!section.getBoolean(pluginName + ".Enabled")) {
return false;
}
String source = dataSource.placeholder;
return section.getBoolean(pluginName + ".Data." + source);
return section.getBoolean(pluginName + ".Enabled");
}
}

View File

@ -0,0 +1,80 @@
package main.java.com.djrapitops.plan.data.plugin;
import com.google.common.base.Objects;
import main.java.com.djrapitops.plan.data.element.AnalysisContainer;
import main.java.com.djrapitops.plan.data.element.InspectContainer;
import main.java.com.djrapitops.plan.utilities.html.Html;
import java.util.Collection;
import java.util.UUID;
/**
* This is an abstract class that can be used to add data from a plugin to the
* "Plugins"-sections of Analysis and Inspect pages.
* <p>
* API-section of documentation has examples on the usage of this class and how
* to register objects extending this class.
*
* @author Rsl1122
* @since 4.1.0
*/
public abstract class PluginData {
private final ContainerSize size;
private final String sourcePlugin;
private String pluginIcon;
private String iconColor;
public PluginData(ContainerSize size, String sourcePlugin) {
this.size = size;
this.sourcePlugin = sourcePlugin;
}
public abstract InspectContainer getPlayerData(UUID uuid, InspectContainer fillThis) throws Exception;
public abstract AnalysisContainer getServerData(Collection<UUID> uuids, AnalysisContainer fillThis) throws Exception;
protected final void setPluginIcon(String pluginIcon) {
this.pluginIcon = pluginIcon;
}
protected final void setIconColor(String iconColor) {
this.iconColor = iconColor;
}
public final String parsePluginIcon() {
return pluginIcon != null ? Html.FA_COLORED_ICON.parse((iconColor != null ? iconColor : "black"), pluginIcon) : Html.FONT_AWESOME_ICON.parse("cube");
}
public final ContainerSize getSize() {
return size;
}
public final String getSourcePlugin() {
return sourcePlugin;
}
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PluginData that = (PluginData) o;
return size == that.size &&
Objects.equal(sourcePlugin, that.sourcePlugin) &&
Objects.equal(pluginIcon, that.pluginIcon);
}
@Override
public final int hashCode() {
return Objects.hashCode(size, sourcePlugin, pluginIcon);
}
public final String getWithIcon(String text, String icon) {
return getWithIcon(text, icon, "");
}
public final String getWithIcon(String text, String icon, String color) {
return Html.FA_COLORED_ICON.parse(color, icon) + " " + text;
}
}

View File

@ -158,4 +158,18 @@ public class WorldTimes {
public String getCurrentWorld() {
return currentWorld;
}
public void add(WorldTimes toAdd) {
Map<String, GMTimes> times = toAdd.getWorldTimes();
for (Map.Entry<String, GMTimes> entry : times.entrySet()) {
String worldName = entry.getKey();
GMTimes gmTimes = entry.getValue();
GMTimes currentGMTimes = getGMTimes(worldName);
for (String gm : GMTimes.getGMKeyArray()) {
currentGMTimes.addTime(gm, gmTimes.getTime(gm));
}
worldTimes.put(worldName, currentGMTimes);
}
}
}

View File

@ -2,6 +2,8 @@ package main.java.com.djrapitops.plan.database;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import main.java.com.djrapitops.plan.data.ServerProfile;
import main.java.com.djrapitops.plan.database.tables.*;
import org.apache.commons.lang3.StringUtils;
@ -265,4 +267,8 @@ public abstract class Database {
public boolean isUsingMySQL() {
return "mysql".equals(getConfigName());
}
public abstract PlayerProfile getPlayerProfile(UUID uuid) throws SQLException;
public abstract ServerProfile getServerProfile(UUID serverUUID) throws SQLException;
}

View File

@ -1,8 +1,8 @@
package main.java.com.djrapitops.plan.database.databases;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.settings.Settings;
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;

View File

@ -8,14 +8,18 @@ import com.djrapitops.plugin.task.ITask;
import com.djrapitops.plugin.task.RunnableFactory;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.api.exceptions.DatabaseInitException;
import main.java.com.djrapitops.plan.data.PlayerProfile;
import main.java.com.djrapitops.plan.data.ServerProfile;
import main.java.com.djrapitops.plan.data.container.*;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.tables.*;
import main.java.com.djrapitops.plan.database.tables.move.Version8TransferTable;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.UUID;
import java.util.*;
/**
* Class containing main logic for different data related save and load functionality.
@ -110,7 +114,7 @@ public abstract class SQLDB extends Database {
if (newDatabase) {
Log.info("New Database created.");
setVersion(12);
setVersion(13);
}
int version = getVersion();
@ -137,6 +141,10 @@ public abstract class SQLDB extends Database {
ipsTable.alterTableV12();
setVersion(12);
}
if (version < 13) {
ipsTable.alterTableV13();
setVersion(13);
}
} catch (SQLException e) {
throw new DatabaseInitException("Failed to set-up Database", e);
}
@ -156,7 +164,7 @@ public abstract class SQLDB extends Database {
}
/**
* Get all tables in a good order.
* Get all tables in a create order.
*
* @return Table array.
*/
@ -222,6 +230,110 @@ public abstract class SQLDB extends Database {
return versionTable.isNewDatabase();
}
@Override
public PlayerProfile getPlayerProfile(UUID uuid) throws SQLException {
if (!wasSeenBefore(uuid)) {
return null;
}
String playerName = usersTable.getPlayerName(uuid);
Optional<Long> registerDate = usersTable.getRegisterDate(uuid);
if (!registerDate.isPresent()) {
throw new IllegalStateException("User has been saved with null register date to a NOT NULL column");
}
PlayerProfile profile = new PlayerProfile(uuid, playerName, registerDate.get());
profile.setTimesKicked(usersTable.getTimesKicked(uuid));
Map<UUID, UserInfo> userInfo = userInfoTable.getAllUserInfo(uuid);
addUserInfoToProfile(profile, userInfo);
profile.setActions(actionsTable.getActions(uuid));
profile.setNicknames(nicknamesTable.getAllNicknames(uuid));
profile.setGeoInformation(ipsTable.getGeoInfo(uuid));
Map<UUID, List<Session>> sessions = sessionsTable.getSessions(uuid);
profile.setSessions(sessions);
profile.calculateWorldTimesPerServer();
profile.setTotalWorldTimes(worldTimesTable.getWorldTimesOfUser(uuid));
return profile;
}
private void addUserInfoToProfile(PlayerProfile profile, Map<UUID, UserInfo> userInfo) {
for (Map.Entry<UUID, UserInfo> entry : userInfo.entrySet()) {
UUID serverUUID = entry.getKey();
UserInfo info = entry.getValue();
profile.setRegistered(serverUUID, info.getRegistered());
if (info.isBanned()) {
profile.bannedOnServer(serverUUID);
}
if (info.isOpped()) {
profile.oppedOnServer(serverUUID);
}
}
}
@Override
public ServerProfile getServerProfile(UUID serverUUID) throws SQLException {
ServerProfile profile = new ServerProfile(serverUUID);
profile.setPlayers(getPlayers(serverUUID));
profile.setTps(tpsTable.getTPSData(serverUUID));
Optional<TPS> allTimePeak = tpsTable.getAllTimePeak(serverUUID);
if (allTimePeak.isPresent()) {
TPS peak = allTimePeak.get();
profile.setAllTimePeak(peak.getDate());
profile.setAllTimePeakPlayers(peak.getPlayers());
}
Optional<TPS> lastPeak = tpsTable.getPeakPlayerCount(serverUUID, MiscUtils.getTime() - (TimeAmount.DAY.ms() * 2L));
if (lastPeak.isPresent()) {
TPS peak = lastPeak.get();
profile.setLastPeakDate(peak.getDate());
profile.setLastPeakPlayers(peak.getPlayers());
}
profile.setCommandUsage(commandUseTable.getCommandUse(serverUUID));
profile.setServerWorldtimes(worldTimesTable.getWorldTimesOfServer(serverUUID));
return profile;
}
private List<PlayerProfile> getPlayers(UUID serverUUID) throws SQLException {
List<UserInfo> serverUserInfo = userInfoTable.getServerUserInfo(serverUUID);
Map<UUID, Integer> timesKicked = usersTable.getAllTimesKicked();
Map<UUID, List<Action>> actions = actionsTable.getServerActions(serverUUID);
Map<UUID, List<GeoInfo>> geoInfo = ipsTable.getAllGeoInfo();
Map<UUID, List<Session>> sessions = sessionsTable.getSessionInfoOfServer(serverUUID);
Map<UUID, Map<UUID, List<Session>>> map = new HashMap<>();
map.put(serverUUID, sessions);
killsTable.addKillsToSessions(map);
worldTimesTable.addWorldTimesToSessions(map);
List<PlayerProfile> players = new ArrayList<>();
for (UserInfo userInfo : serverUserInfo) {
UUID uuid = userInfo.getUuid();
PlayerProfile profile = new PlayerProfile(uuid, userInfo.getName(), userInfo.getRegistered());
profile.setTimesKicked(timesKicked.getOrDefault(uuid, 0));
if (userInfo.isBanned()) {
profile.bannedOnServer(serverUUID);
}
if (userInfo.isOpped()) {
profile.oppedOnServer(serverUUID);
}
profile.setActions(actions.getOrDefault(uuid, new ArrayList<>()));
profile.setGeoInformation(geoInfo.getOrDefault(uuid, new ArrayList<>()));
profile.setSessions(serverUUID, sessions.getOrDefault(uuid, new ArrayList<>()));
players.add(profile);
}
return players;
}
@Override
public boolean wasSeenBefore(UUID uuid) {
if (uuid == null) {
@ -299,6 +411,10 @@ public abstract class SQLDB extends Database {
if (!usingMySQL) {
connection.commit();
}
} catch (SQLException e) {
if (!e.getMessage().contains("cannot commit")) {
Log.toLog(this.getClass().getName(), e);
}
} finally {
returnToPool(connection);
}

View File

@ -7,7 +7,7 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.Action;
import main.java.com.djrapitops.plan.data.container.Action;
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;
@ -193,4 +193,43 @@ public class ActionsTable extends UserIDTable {
}
});
}
public Map<UUID, List<Action>> getServerActions(UUID serverUUID) throws SQLException {
String usersIDColumn = usersTable + "." + usersTable.getColumnID();
String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid";
String sql = "SELECT " +
columnActionID + ", " +
columnDate + ", " +
columnAdditionalInfo + ", " +
usersUUIDColumn +
" FROM " + tableName +
" JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID +
" WHERE " + serverTable.statementSelectServerID + "=" + columnServerID;
return query(new QueryStatement<Map<UUID, List<Action>>>(sql, 20000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
}
@Override
public Map<UUID, List<Action>> processResults(ResultSet set) throws SQLException {
Map<UUID, List<Action>> map = new HashMap<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString("uuid"));
List<Action> actions = map.getOrDefault(uuid, new ArrayList<>());
long date = set.getLong(columnDate);
Actions doneAction = Actions.getById(set.getInt(columnActionID));
String additionalInfo = set.getString(columnAdditionalInfo);
actions.add(new Action(date, doneAction, additionalInfo, -1));
map.put(uuid, actions);
}
return map;
}
});
}
}

View File

@ -2,6 +2,7 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.container.GeoInfo;
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;
@ -22,6 +23,7 @@ public class IPsTable extends UserIDTable {
private final String columnIP = "ip";
private final String columnGeolocation = "geolocation";
private final String columnLastUsed = "last_used";
private String insertStatement;
/**
@ -33,10 +35,11 @@ public class IPsTable extends UserIDTable {
insertStatement = "INSERT INTO " + tableName + " ("
+ columnUserID + ", "
+ columnIP + ", "
+ columnGeolocation
+ columnGeolocation + ", "
+ columnLastUsed
+ ") VALUES ("
+ usersTable.statementSelectID + ", "
+ "?, ?)";
+ "?, ?, ?)";
}
@Override
@ -45,6 +48,7 @@ public class IPsTable extends UserIDTable {
.column(columnUserID, Sql.INT).notNull()
.column(columnIP, Sql.varchar(39)).notNull()
.column(columnGeolocation, Sql.varchar(50)).notNull()
.column(columnLastUsed, Sql.LONG).notNull().defaultValue("0")
.foreignKey(columnUserID, usersTable.getTableName(), usersTable.getColumnID())
.toString()
);
@ -56,56 +60,69 @@ public class IPsTable extends UserIDTable {
}
}
/**
* @param uuid UUID of the user.
* @return Users's Login Geolocations.
* @throws SQLException when an error at retrieval happens
*/
public List<String> getGeolocations(UUID uuid) throws SQLException {
return getStringList(uuid, columnGeolocation);
public void alterTableV13() {
addColumns(columnLastUsed + " bigint NOT NULL DEFAULT 0");
}
public List<String> getIps(UUID uuid) throws SQLException {
return getStringList(uuid, columnIP);
}
private List<String> getStringList(UUID uuid, String column) throws SQLException {
String sql = "SELECT DISTINCT " + column + " FROM " + tableName +
public List<GeoInfo> getGeoInfo(UUID uuid) throws SQLException {
String sql = "SELECT DISTINCT * FROM " + tableName +
" WHERE " + columnUserID + "=" + usersTable.statementSelectID;
return query(new QueryStatement<List<String>>(sql, 100) {
return query(new QueryStatement<List<GeoInfo>>(sql, 100) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
}
@Override
public List<String> processResults(ResultSet set) throws SQLException {
List<String> stringList = new ArrayList<>();
public List<GeoInfo> processResults(ResultSet set) throws SQLException {
List<GeoInfo> geoInfo = new ArrayList<>();
while (set.next()) {
stringList.add(set.getString(column));
String ip = set.getString(columnIP);
String geolocation = set.getString(columnGeolocation);
long lastUsed = set.getLong(columnLastUsed);
geoInfo.add(new GeoInfo(ip, geolocation, lastUsed));
}
return stringList;
return geoInfo;
}
});
}
public void saveIP(UUID uuid, String ip, String geolocation) throws SQLException {
List<String> ips = getIps(uuid);
if (ips.contains(ip)) {
return;
public void saveGeoInfo(UUID uuid, GeoInfo info) throws SQLException {
List<GeoInfo> geoInfo = getGeoInfo(uuid);
if (geoInfo.contains(info)) {
updateGeoInfo(uuid, info);
}
insertIp(uuid, ip, geolocation);
insertGeoInfo(uuid, info);
}
private void insertIp(UUID uuid, String ip, String geolocation) throws SQLException {
private void insertGeoInfo(UUID uuid, GeoInfo info) throws SQLException {
execute(new ExecStatement(insertStatement) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
statement.setString(2, ip);
statement.setString(3, geolocation);
statement.setString(2, info.getIp());
statement.setString(3, info.getGeolocation());
statement.setLong(4, info.getLastUsed());
}
});
}
private void updateGeoInfo(UUID uuid, GeoInfo info) throws SQLException {
String sql = "UPDATE " + tableName + " SET "
+ columnLastUsed + "=?" +
" WHERE " + columnUserID + "=" + usersTable.statementSelectID +
" AND " + columnIP + "=?" +
" AND " + columnGeolocation + "=?";
execute(new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setLong(1, info.getLastUsed());
statement.setString(2, uuid.toString());
statement.setString(3, info.getIp());
statement.setString(4, info.getGeolocation());
}
});
}
@ -131,62 +148,39 @@ public class IPsTable extends UserIDTable {
});
}
public Map<UUID, List<String>> getAllGeolocations() throws SQLException {
public Map<UUID, List<GeoInfo>> getAllGeoInfo() throws SQLException {
String usersIDColumn = usersTable + "." + usersTable.getColumnID();
String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid";
String sql = "SELECT " +
columnIP + ", " +
columnGeolocation + ", " +
columnLastUsed + ", " +
usersUUIDColumn +
" FROM " + tableName +
" JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID;
return query(new QueryAllStatement<Map<UUID, List<String>>>(sql, 50000) {
return query(new QueryAllStatement<Map<UUID, List<GeoInfo>>>(sql, 50000) {
@Override
public Map<UUID, List<String>> processResults(ResultSet set) throws SQLException {
Map<UUID, List<String>> geoLocations = new HashMap<>();
public Map<UUID, List<GeoInfo>> processResults(ResultSet set) throws SQLException {
Map<UUID, List<GeoInfo>> geoLocations = new HashMap<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString("uuid"));
List<String> userGeoLocs = geoLocations.getOrDefault(uuid, new ArrayList<>());
userGeoLocs.add(set.getString(columnGeolocation));
geoLocations.put(uuid, userGeoLocs);
List<GeoInfo> userGeoInfo = geoLocations.getOrDefault(uuid, new ArrayList<>());
String ip = set.getString(columnIP);
String geolocation = set.getString(columnGeolocation);
long lastUsed = set.getLong(columnLastUsed);
userGeoInfo.add(new GeoInfo(ip, geolocation, lastUsed));
geoLocations.put(uuid, userGeoInfo);
}
return geoLocations;
}
});
}
public Map<UUID, Map<String, String>> getAllIPsAndGeolocations() throws SQLException {
String usersIDColumn = usersTable + "." + usersTable.getColumnID();
String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid";
String sql = "SELECT " +
columnGeolocation + ", " +
columnIP + ", " +
usersUUIDColumn +
" FROM " + tableName +
" JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID;
return query(new QueryAllStatement<Map<UUID, Map<String, String>>>(sql, 50000) {
@Override
public Map<UUID, Map<String, String>> processResults(ResultSet set) throws SQLException {
Map<UUID, Map<String, String>> map = new HashMap<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString("uuid"));
Map<String, String> userMap = map.getOrDefault(uuid, new HashMap<>());
String geoLocation = set.getString(columnGeolocation);
String ip = set.getString(columnIP);
userMap.put(ip, geoLocation);
map.put(uuid, userMap);
}
return map;
}
});
}
public void insertIPsAndGeolocations(Map<UUID, Map<String, String>> allIPsAndGeolocations) throws SQLException {
public void insertAllGeoInfo(Map<UUID, List<GeoInfo>> allIPsAndGeolocations) throws SQLException {
if (Verify.isEmpty(allIPsAndGeolocations)) {
return;
}
@ -196,14 +190,16 @@ public class IPsTable extends UserIDTable {
public void prepare(PreparedStatement statement) throws SQLException {
// Every User
for (UUID uuid : allIPsAndGeolocations.keySet()) {
// Every IP & Geolocation
for (Map.Entry<String, String> entry : allIPsAndGeolocations.get(uuid).entrySet()) {
String ip = entry.getKey();
String geoLocation = entry.getValue();
// Every GeoInfo
for (GeoInfo info : allIPsAndGeolocations.get(uuid)) {
String ip = info.getIp();
String geoLocation = info.getGeolocation();
long lastUsed = info.getLastUsed();
statement.setString(1, uuid.toString());
statement.setString(2, ip);
statement.setString(3, geoLocation);
statement.setLong(4, lastUsed);
statement.addBatch();
}

View File

@ -2,8 +2,8 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.PlayerKill;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.container.PlayerKill;
import main.java.com.djrapitops.plan.data.container.Session;
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;

View File

@ -56,37 +56,44 @@ public class NicknamesTable extends UserIDTable {
}
/**
* Get ALL nicknames of the user.
* Get ALL nicknames of the user by Server UUID.
* <p>
* Get's nicknames from other servers as well.
*
* @param uuid UUID of the Player
* @return The nicknames of the User
* @return The nicknames of the User in a map by ServerUUID
* @throws SQLException when an error at retrieval happens
*/
public List<String> getAllNicknames(UUID uuid) throws SQLException {
String sql = "SELECT " + columnNick + " FROM " + tableName +
public Map<UUID, List<String>> getAllNicknames(UUID uuid) throws SQLException {
String serverIDColumn = serverTable + "." + serverTable.getColumnID();
String serverUUIDColumn = serverTable + "." + serverTable.getColumnUUID() + " as s_uuid";
String sql = "SELECT " +
columnNick + ", " +
serverUUIDColumn +
" FROM " + tableName +
" JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID +
" WHERE (" + columnUserID + "=" + usersTable.statementSelectID + ")";
return query(new QueryStatement<List<String>>(sql, 1000) {
return query(new QueryStatement<Map<UUID, List<String>>>(sql, 5000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
}
@Override
public List<String> processResults(ResultSet set) throws SQLException {
List<String> nicknames = new ArrayList<>();
public Map<UUID, List<String>> processResults(ResultSet set) throws SQLException {
Map<UUID, List<String>> map = new HashMap<>();
while (set.next()) {
String nickname = set.getString(columnNick);
if (nickname.isEmpty()) {
continue;
}
if (!nicknames.contains(nickname)) {
nicknames.add(nickname);
}
UUID serverUUID = UUID.fromString(set.getString("s_uuid"));
List<String> nicknames = map.getOrDefault(serverUUID, new ArrayList<>());
nicknames.add(set.getString(columnNick));
map.put(serverUUID, nicknames);
}
return nicknames;
return map;
}
});
}
@ -227,4 +234,5 @@ public class NicknamesTable extends UserIDTable {
public String getColumnUserID() {
return columnUserID;
}
}

View File

@ -193,7 +193,7 @@ public class ServerTable extends Table {
});
}
public Map<Integer, String> getServerNames() throws SQLException {
public Map<Integer, String> getServerNamesByID() throws SQLException {
String sql = Select.from(tableName,
columnServerID, columnServerName)
.toString();
@ -211,6 +211,42 @@ public class ServerTable extends Table {
});
}
public Map<UUID, String> getServerNames() throws SQLException {
String sql = Select.from(tableName,
columnServerUUID, columnServerName)
.toString();
return query(new QueryAllStatement<Map<UUID, String>>(sql) {
@Override
public Map<UUID, String> processResults(ResultSet set) throws SQLException {
Map<UUID, String> names = new HashMap<>();
while (set.next()) {
UUID serverUUID = UUID.fromString(set.getString(columnServerUUID));
names.put(serverUUID, set.getString(columnServerName));
}
return names;
}
});
}
public Map<Integer, UUID> getServerUuids() throws SQLException {
String sql = Select.from(tableName,
columnServerID, columnServerUUID)
.toString();
return query(new QueryAllStatement<Map<Integer, UUID>>(sql) {
@Override
public Map<Integer, UUID> processResults(ResultSet set) throws SQLException {
Map<Integer, UUID> uuids = new HashMap<>();
while (set.next()) {
int id = set.getInt(columnServerID);
uuids.put(id, UUID.fromString(set.getString(columnServerUUID)));
}
return uuids;
}
});
}
/**
* Used to get BungeeCord WebServer info if present.
*

View File

@ -3,7 +3,7 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.container.Session;
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;
@ -151,44 +151,44 @@ public class SessionsTable extends UserIDTable {
* @return Map with Sessions that don't contain Kills or WorldTimes.
* @throws SQLException DB Error
*/
private Map<String, List<Session>> getSessionInformation(UUID uuid) throws SQLException {
Map<Integer, String> serverNames = serverTable.getServerNames();
private Map<UUID, List<Session>> getSessionInformation(UUID uuid) throws SQLException {
Map<Integer, UUID> serverUUIDs = serverTable.getServerUuids();
String sql = Select.from(tableName, "*")
.where(columnUserID + "=" + usersTable.statementSelectID)
.toString();
return query(new QueryStatement<Map<String, List<Session>>>(sql, 10000) {
return query(new QueryStatement<Map<UUID, List<Session>>>(sql, 10000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
}
@Override
public Map<String, List<Session>> processResults(ResultSet set) throws SQLException {
Map<String, List<Session>> sessionsByServer = new HashMap<>();
public Map<UUID, List<Session>> processResults(ResultSet set) throws SQLException {
Map<UUID, List<Session>> sessionsByServer = new HashMap<>();
while (set.next()) {
int id = set.getInt(columnID);
long start = set.getLong(columnSessionStart);
long end = set.getLong(columnSessionEnd);
String serverName = serverNames.get(set.getInt(columnServerID));
UUID serverUUID = serverUUIDs.get(set.getInt(columnServerID));
if (serverName == null) {
if (serverUUID == null) {
throw new IllegalStateException("Server not present");
}
int deaths = set.getInt(columnDeaths);
int mobKills = set.getInt(columnMobKills);
List<Session> sessions = sessionsByServer.getOrDefault(serverName, new ArrayList<>());
List<Session> sessions = sessionsByServer.getOrDefault(serverUUID, new ArrayList<>());
sessions.add(new Session(id, start, end, mobKills, deaths));
sessionsByServer.put(serverName, sessions);
sessionsByServer.put(serverUUID, sessions);
}
return sessionsByServer;
}
});
}
public Map<String, List<Session>> getSessions(UUID uuid) throws SQLException {
Map<String, List<Session>> sessions = getSessionInformation(uuid);
public Map<UUID, List<Session>> getSessions(UUID uuid) throws SQLException {
Map<UUID, List<Session>> sessions = getSessionInformation(uuid);
Map<Integer, Session> allSessions = sessions.values().stream().flatMap(Collection::stream).collect(Collectors.toMap(Session::getSessionID, Function.identity()));
db.getKillsTable().addKillsToSessions(uuid, allSessions);
@ -286,7 +286,7 @@ public class SessionsTable extends UserIDTable {
* @throws SQLException DB Error
*/
public Map<String, Long> getPlaytimeByServer(UUID uuid, long afterDate) throws SQLException {
Map<Integer, String> serverNames = serverTable.getServerNames();
Map<Integer, String> serverNames = serverTable.getServerNamesByID();
String sql = "SELECT " +
"(SUM(" + columnSessionEnd + ") - SUM(" + columnSessionStart + ")) as playtime, " +
columnServerID +
@ -457,15 +457,10 @@ public class SessionsTable extends UserIDTable {
}
public Map<UUID, List<Session>> getSessionInfoOfServer(UUID serverUUID) throws SQLException {
Optional<Integer> id = serverTable.getServerID(serverUUID);
if (!id.isPresent()) {
return new HashMap<>();
}
int serverID = id.get();
String usersIDColumn = usersTable + "." + usersTable.getColumnID();
String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid";
String sql = "SELECT " +
tableName + "." + columnID + ", " +
columnSessionStart + ", " +
columnSessionEnd + ", " +
columnDeaths + ", " +
@ -492,7 +487,7 @@ public class SessionsTable extends UserIDTable {
int deaths = set.getInt(columnDeaths);
int mobKills = set.getInt(columnMobKills);
List<Session> sessions = sessionsByUser.getOrDefault(uuid, new ArrayList<>());
sessions.add(new Session(serverID, start, end, mobKills, deaths));
sessions.add(new Session(set.getInt(columnID), start, end, mobKills, deaths));
sessionsByUser.put(uuid, sessions);
}
return sessionsByUser;

View File

@ -3,7 +3,7 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.TPS;
import main.java.com.djrapitops.plan.data.container.TPS;
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;
@ -76,6 +76,10 @@ public class TPSTable extends Table {
* @return @throws SQLException
*/
public List<TPS> getTPSData() throws SQLException {
return getTPSData(MiscUtils.getIPlan().getServerUuid());
}
public List<TPS> getTPSData(UUID serverUUID) throws SQLException {
String sql = Select.all(tableName)
.where(columnServerID + "=" + serverTable.statementSelectServerID)
.toString();
@ -83,7 +87,7 @@ public class TPSTable extends Table {
return query(new QueryStatement<List<TPS>>(sql, 50000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, MiscUtils.getIPlan().getServerUuid().toString());
statement.setString(1, serverUUID.toString());
}
@Override

View File

@ -4,10 +4,11 @@
*/
package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.UserInfo;
import main.java.com.djrapitops.plan.data.container.UserInfo;
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;
@ -121,39 +122,44 @@ public class UserInfoTable extends UserIDTable {
}
public UserInfo getUserInfo(UUID uuid) throws SQLException {
return getUserInfo(uuid, Plan.getServerUUID());
return getAllUserInfo(uuid).get(MiscUtils.getIPlan().getServerUuid());
}
public UserInfo getUserInfo(UUID uuid, UUID serverUUID) throws SQLException {
public Map<UUID, UserInfo> getAllUserInfo(UUID uuid) throws SQLException {
String usersIDColumn = usersTable + "." + usersTable.getColumnID();
String serverIDColumn = serverTable + "." + serverTable.getColumnID();
String usersNameColumn = usersTable + "." + usersTable.getColumnName() + " as name";
String serverUUIDColumn = serverTable + "." + serverTable.getColumnUUID() + " as s_uuid";
String sql = "SELECT " +
tableName + "." + columnRegistered + ", " +
columnOP + ", " +
columnBanned + ", " +
usersNameColumn +
columnOP + ", " +
usersNameColumn + ", " +
serverUUIDColumn +
" FROM " + tableName +
" JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID +
" WHERE " + columnUserID + "=" + usersTable.statementSelectID +
" AND " + columnServerID + "=" + serverTable.statementSelectServerID;
" JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID +
" WHERE " + columnUserID + "=" + usersTable.statementSelectID;
return query(new QueryStatement<UserInfo>(sql) {
return query(new QueryStatement<Map<UUID, UserInfo>>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, uuid.toString());
statement.setString(2, serverUUID.toString());
}
@Override
public UserInfo processResults(ResultSet set) throws SQLException {
if (set.next()) {
public Map<UUID, UserInfo> processResults(ResultSet set) throws SQLException {
Map<UUID, UserInfo> map = new HashMap<>();
while (set.next()) {
long registered = set.getLong(columnRegistered);
boolean opped = set.getBoolean(columnOP);
boolean banned = set.getBoolean(columnBanned);
String name = set.getString("name");
return new UserInfo(uuid, name, registered, opped, banned);
UUID serverUUID = UUID.fromString(set.getString("s_uuid"));
map.put(serverUUID, new UserInfo(uuid, name, registered, opped, banned));
}
return null;
return map;
}
});
}
@ -309,4 +315,31 @@ public class UserInfoTable extends UserIDTable {
}
});
}
public int getServerUserCount(UUID serverUUID) {
try {
String sql = "SELECT " +
" COUNT(" + columnRegistered + ") as c" +
" FROM " + tableName +
" WHERE " + columnServerID + "=" + serverTable.statementSelectServerID;
return query(new QueryStatement<Integer>(sql, 20000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
}
@Override
public Integer processResults(ResultSet set) throws SQLException {
if (set.next()) {
return set.getInt("c");
}
return 0;
}
});
} catch (SQLException e) {
Log.toLog(this.getClass().getName(), e);
return 0;
}
}
}

View File

@ -2,7 +2,7 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.UserInfo;
import main.java.com.djrapitops.plan.data.container.UserInfo;
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;

View File

@ -3,7 +3,7 @@ package main.java.com.djrapitops.plan.database.tables;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.container.Session;
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.databases.SQLDB;

View File

@ -6,7 +6,7 @@ package main.java.com.djrapitops.plan.database.tables.move;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
import main.java.com.djrapitops.plan.data.UserInfo;
import main.java.com.djrapitops.plan.data.container.UserInfo;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.SQLDB;
import main.java.com.djrapitops.plan.database.tables.ServerTable;
@ -107,8 +107,8 @@ public class BatchOperationTable extends Table {
if (toDB.equals(this)) {
return;
}
Log.debug("Batch Copy IPs & Geolocations");
toDB.getDb().getIpsTable().insertIPsAndGeolocations(db.getIpsTable().getAllIPsAndGeolocations());
Log.debug("Batch Copy IPs, Geolocations & Last used dates");
toDB.getDb().getIpsTable().insertAllGeoInfo(db.getIpsTable().getAllGeoInfo());
}
public void copyNicknames(BatchOperationTable toDB) throws SQLException {

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan;
package main.java.com.djrapitops.plan.settings;
/**
* Permissions class is used easily check every permission node.

View File

@ -2,11 +2,13 @@
* 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;
package main.java.com.djrapitops.plan.settings;
import com.djrapitops.plugin.api.config.Config;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.PlanBungee;
import java.io.IOException;
import java.util.Map;

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan;
package main.java.com.djrapitops.plan.settings;
import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.api.config.Config;
@ -26,11 +26,19 @@ public enum Settings {
DEV_MODE("Plugin.Dev"),
USE_SERVER_TIME("Customization.UseServerTime"),
DISPLAY_SESSIONS_AS_TABLE("Customization.Display.SessionsAsTable"),
APPEND_WORLD_PERC("Customization.Display.LargestWorldPercInSessionTitle"),
ORDER_WORLD_PIE_BY_PERC("Customization.Display.OrderWorldPieByPercentage"),
WEBSERVER_DISABLED("WebServer.DisableWebServer"),
// Integer
WEBSERVER_PORT("WebServer.Port"),
DB_PORT("Database.MySQL.Port"),
ANALYSIS_AUTO_REFRESH("Analysis.AutoRefreshPeriod"),
ACTIVE_PLAY_THRESHOLD("Analysis.Active.PlaytimeThreshold"),
ACTIVE_LOGIN_THRESHOLD("Analysis.Active.LoginThreshold"),
MAX_SESSIONS("Customization.Display.MaxSessions"),
MAX_PLAYERS("Customization.Display.MaxPlayers"),
MAX_PLAYERS_PLAYERS_PAGE("Customization.Display.MaxPlayersPlayersPage"),
// String
DEBUG("Plugin.Debug"),
@ -47,7 +55,7 @@ public enum Settings {
WEBSERVER_CERTIFICATE_KEYPASS("WebServer.Security.SSL-Certificate.KeyPass"),
WEBSERVER_CERTIFICATE_STOREPASS("WebServer.Security.SSL-Certificate.StorePass"),
WEBSERVER_CERTIFICATE_ALIAS("WebServer.Security.SSL-Certificate.Alias"),
EXTERNAL_WEBSERVER_LINK_PROTOCOL("Analysis.Export.ExternalWebServerLinkProtocol"),
EXTERNAL_WEBSERVER_LINK("WebServer.ExternalWebServerAddress"),
//
SERVER_NAME("Server.ServerName"),
//
@ -68,33 +76,9 @@ public enum Settings {
COLOR_TER("Commands.Colors.Highlight"),
//
THEME_BASE("Theme.Base"),
THEME_FONT_STYLESHEET("Theme.Font.FontStyleSheet"),
THEME_FONT_FAMILY("Theme.Font.FontFamily"),
THEME_FONT_COLOR_DARK("Theme.Font.Color.Dark"),
THEME_FONT_COLOR_LIGHT("Theme.Font.Color.Light"),
THEME_COLOR_MAIN("Theme.Colors.Main"),
THEME_COLOR_MAIN_DARK("Theme.Colors.Main-Dark"),
THEME_COLOR_SECONDARY("Theme.Colors.Secondary"),
THEME_COLOR_SECONDARY_DARK("Theme.Colors.Secondary-Dark"),
THEME_COLOR_TERTIARY("Theme.Colors.Tertiary"),
THEME_COLOR_BACKGROUND("Theme.Colors.Background"),
THEME_COLOR_TABLE_DARK("Theme.Colors.Table-Dark"),
THEME_COLOR_TABLE_LIGHT("Theme.Colors.Table-Light"),
THEME_GRAPH_PUNCHCARD("Theme.Graphs.PunchCard"),
THEME_GRAPH_PLAYERS_ONLINE("Theme.Graphs.PlayersOnline"),
THEME_GRAPH_TPS_THRESHOLD_HIGH("Theme.Graphs.TPS.High-Threshold"),
THEME_GRAPH_TPS_THRESHOLD_MED("Theme.Graphs.TPS.Medium-Threshold"),
THEME_GRAPH_TPS_HIGH("Theme.Graphs.TPS.High"),
THEME_GRAPH_TPS_MED("Theme.Graphs.TPS.Medium"),
THEME_GRAPH_TPS_LOW("Theme.Graphs.TPS.Low"),
THEME_GRAPH_CPU("Theme.Graphs.CPU"),
THEME_GRAPH_RAM("Theme.Graphs.RAM"),
THEME_GRAPH_CHUNKS("Theme.Graphs.Chunks"),
THEME_GRAPH_ENTITIES("Theme.Graphs.Entities"),
THEME_GRAPH_WORLD_PIE("Theme.Graphs.WorldPie"),
THEME_GRAPH_GM_PIE("Theme.Graphs.GMDrilldown"),
THEME_GRAPH_ACTIVITY_PIE("Theme.Graphs.ActivityPie"),
THEME_GRAPH_SERVER_PREF_PIE("Theme.Graphs.ServerPreferencePie"),
// StringList
HIDE_FACTIONS("Plugins.Factions.HideFactions"),
HIDE_TOWNS("Plugins.Towny.HideTowns"),

View File

@ -2,12 +2,13 @@
* 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;
package main.java.com.djrapitops.plan.settings;
import com.djrapitops.plugin.api.config.Config;
import com.djrapitops.plugin.api.config.ConfigNode;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Plan;
import java.io.IOException;
import java.util.HashMap;

View File

@ -1,13 +1,13 @@
package main.java.com.djrapitops.plan.locale;
package main.java.com.djrapitops.plan.settings.locale;
import com.djrapitops.plugin.api.Benchmark;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.settings.ColorScheme;
import com.djrapitops.plugin.settings.DefaultMessages;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.settings.Permissions;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.utilities.comparators.LocaleEntryComparator;
import main.java.com.djrapitops.plan.utilities.comparators.StringLengthComparator;
import main.java.com.djrapitops.plan.utilities.file.FileUtil;

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan.locale;
package main.java.com.djrapitops.plan.settings.locale;
import com.djrapitops.plugin.utilities.Verify;
import org.apache.commons.lang3.text.StrSubstitutor;

View File

@ -1,4 +1,4 @@
package main.java.com.djrapitops.plan.locale;
package main.java.com.djrapitops.plan.settings.locale;
import java.util.Arrays;
import java.util.Map;

View File

@ -0,0 +1,92 @@
/*
* 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.settings.theme;
import com.djrapitops.plugin.api.utility.EnumUtility;
import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify;
import main.java.com.djrapitops.plan.api.exceptions.PlanEnableException;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import java.io.IOException;
import java.util.List;
/**
* Enum that contains available themes.
* <p>
* Change config setting Theme.Base to select one.
*
* @author Rsl1122
*/
public class Theme {
private final ThemeConfig config;
public Theme() throws PlanEnableException {
String themeName = Settings.THEME_BASE.toString();
try {
config = new ThemeConfig(themeName);
} catch (IOException e) {
throw new PlanEnableException("Default theme could not be loaded.", e);
}
}
public String getColor(ThemeVal variable) {
String path = variable.getThemePath();
try {
String value = config.getString(path);
if (value.contains(".")) {
return "url(\"" + value + "\")";
} else {
return value;
}
} catch (Exception | NoSuchFieldError e) {
Log.error("Something went wrong with getting variable " + variable.name() + " for: " + path);
}
return variable.getDefaultValue();
}
public String replaceThemeColors(String resourceString) {
String replaced = resourceString;
List<ThemeVal> themeVariables = EnumUtility.getSupportedEnumValues(ThemeVal.class, "RED", "PINK", "PURPLE",
"DEEP_PURPLE", "INDIGO", "BLUE", "LIGHT_BLUE", "CYAN", "TEAL", "GREEN", "LIGHT_GREEN", "LIME",
"YELLOW", "AMBER", "ORANGE", "DEEP_ORANGE", "BROWN", "GREY", "BLUE_GREY", "BLACK", "WHITE",
"GRAPH_PUNCHCARD", "GRAPH_PLAYERS_ONLINE", "GRAPH_TPS_HIGH", "GRAPH_TPS_MED", "GRAPH_TPS_LOW",
"GRAPH_CPU", "GRAPH_RAM", "GRAPH_CHUNKS", "GRAPH_ENTITIES", "GRAPH_WORLD_PIE", "GRAPH_GM_PIE",
"GRAPH_ACTIVITY_PIE", "GRAPH_SERVER_PREF_PIE", "FONT_STYLESHEET", "FONT_FAMILY");
for (ThemeVal variable : themeVariables) {
String value = getColor(variable);
String defaultValue = variable.getDefaultValue();
if (Verify.equalsOne(value, defaultValue)) {
continue;
}
if (value.contains("url")) {
String[] colorAndUrl = value.split(" ");
if (colorAndUrl.length >= 2) {
replaced = replaced.replace("background: " + defaultValue, "background: " + colorAndUrl[1]);
replaced = replaced.replace(defaultValue, colorAndUrl[0]);
return replaced;
}
} else {
replaced = replaced.replace(defaultValue, value);
}
}
return replaced;
}
public String getThemeValue(ThemeVal color) {
return config.getString(color.getThemePath());
}
public static String getValue(ThemeVal variable) {
return MiscUtils.getIPlan().getTheme().getThemeValue(variable);
}
public static String replaceColors(String resourceString) {
return MiscUtils.getIPlan().getTheme().replaceThemeColors(resourceString);
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.settings.theme;
import com.djrapitops.plugin.api.config.Config;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.api.IPlan;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.file.FileUtil;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Config that keeps track of theme.yml.
*
* @author Rsl1122
*/
public class ThemeConfig extends Config {
private ThemeConfig(File file, List<String> defaults) {
super(file, defaults);
}
public ThemeConfig(String fileName) throws IOException {
this(getConfigFile(), getDefaults(fileName));
save();
}
private static List<String> getDefaults(String fileName) throws IOException {
String fileLocation = getFileLocation(fileName);
IPlan plugin = MiscUtils.getIPlan();
try {
return FileUtil.lines(plugin, fileLocation);
} catch (IOException e) {
Log.error("Could not find theme " + fileLocation + ". Attempting to use default.");
return FileUtil.lines(plugin, "themes/theme.yml");
}
}
private static String getFileLocation(String fileName) {
switch (fileName.toLowerCase()) {
case "mute":
case "lowsaturation":
return "themes/mute.yml";
case "pastel":
case "bright":
case "harsh":
case "saturated":
case "high":
return "themes/pastel.yml";
case "sepia":
case "brown":
return "themes/sepia.yml";
case "grey":
case "gray":
case "greyscale":
case "grayscale":
return "themes/greyscale.yml";
default:
return "themes/theme.yml";
}
}
private static File getConfigFile() throws IOException {
File folder = MiscUtils.getIPlan().getDataFolder();
if (!folder.exists()) {
folder.mkdirs();
}
File themeFile = new File(folder, "theme.yml");
if (!themeFile.exists()) {
themeFile.createNewFile();
}
return themeFile;
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.settings.theme;
/**
* Enum class used for getting the Html colors that match the config settings.
*
* @author Rsl1122
*/
public enum ThemeVal {
THEME_DEFAULT("DefaultColor", "light-green"),
//
FONT_STYLESHEET("Font.FontStyleSheet", "https://fonts.googleapis.com/css?family=Roboto:400,700&subset=latin,cyrillic-ext"),
FONT_FAMILY("Font.FontFamily", "\"Roboto\", sans-serif"),
//
RED("Colors.red", "#E91E63"),
PINK("Colors.pink", "#F44336"),
PURPLE("Colors.purple", "#9C27B0"),
DEEP_PURPLE("Colors.deep-purple", "#673AB7"),
INDIGO("Colors.indigo", "#3F51B5"),
BLUE("Colors.blue", "#2196F3"),
LIGHT_BLUE("Colors.light-blue", "#03A9F4"),
CYAN("Colors.cyan", "#00BCD4"),
TEAL("Colors.teal", "#009688"),
GREEN("Colors.green", "#4CAF50"),
LIGHT_GREEN("Colors.light-green", "#8BC34A"),
LIME("Colors.lime", "#CDDC39"),
YELLOW("Colors.yellow", "#ffe821"),
AMBER("Colors.amber", "#FFC107"),
ORANGE("Colors.orange", "#FF9800"),
DEEP_ORANGE("Colors.deep-orange", "#FF5722"),
BROWN("Colors.brown", "#795548"),
GREY("Colors.grey", "#9E9E9E"),
BLUE_GREY("Colors.blue-grey", "#607D8B"),
BLACK("Colors.black", "#000000"),
WHITE("Colors.Extra.White", "#fff"),
//
GRAPH_PUNCHCARD("GraphColors.PunchCard", "#222"),
GRAPH_PLAYERS_ONLINE("GraphColors.PlayersOnline", "#1E90FF"),
GRAPH_TPS_HIGH("GraphColors.TPS.High", "#267F00"),
GRAPH_TPS_MED("GraphColors.TPS.Medium", "#e5cc12"),
GRAPH_TPS_LOW("GraphColors.TPS.Low", "#b74343"),
GRAPH_CPU("GraphColors.CPU", "#e0d264"),
GRAPH_RAM("GraphColors.RAM", "#7dcc24"),
GRAPH_CHUNKS("GraphColors.Chunks", "#b58310"),
GRAPH_ENTITIES("GraphColors.Entities", "#ac69ef"),
GRAPH_WORLD_PIE("GraphColors.WorldPie", "\"#0099C6\", \"#66AA00\", \"#316395\", \"#994499\", \"#22AA99\", \"#AAAA11\", \"#6633CC\", \"#E67300\", \"#329262\", \"#5574A6\""),
GRAPH_GM_PIE("GraphColors.GMDrilldown", "\"#438c99\", \"#639A67\", \"#D8EBB5\", \"#D9BF77\""),
GRAPH_ACTIVITY_PIE("GraphColors.ActivityPie", "\"#4CAF50\", \"#8BC34A\", \"#CDDC39\", \"#FFC107\", \"#607D8B\""),
GRAPH_SERVER_PREF_PIE("GraphColors.ServerPreferencePie", "\"#0099C6\", \"#66AA00\", \"#316395\", \"#994499\", \"#22AA99\", \"#AAAA11\", \"#6633CC\", \"#E67300\", \"#329262\", \"#5574A6\""),
//
PARSED_SESSION_ACCORDION("ParsedElements.SessionAccordion", "teal"),
PARSED_SERVER_ACCORDION("ParsedElements.ServerAccordion", "light-green");
private final String themePath;
private final String defaultValue;
ThemeVal(String themePath, String defaultValue) {
this.themePath = themePath;
this.defaultValue = defaultValue;
}
public String getThemePath() {
return themePath;
}
public String getDefaultValue() {
return defaultValue;
}
}

View File

@ -25,6 +25,7 @@ public class DataCache extends SessionCache {
private static final Map<UUID, Integer> firstSessionInformation = new HashMap<>();
private final Database db;
private final Map<UUID, String> playerNames;
private final Map<String, UUID> uuids;
private final Map<UUID, String> displayNames;
/**
@ -38,6 +39,7 @@ public class DataCache extends SessionCache {
playerNames = new HashMap<>();
displayNames = new HashMap<>();
uuids = new HashMap<>();
}
/**
@ -48,13 +50,22 @@ public class DataCache extends SessionCache {
* @param displayName DisplayName of the player.
*/
public void updateNames(UUID uuid, String playerName, String displayName) {
playerNames.put(uuid, playerName);
displayNames.put(uuid, displayName);
if (playerName != null) {
playerNames.put(uuid, playerName);
uuids.put(playerName, uuid);
}
if (displayName != null) {
displayNames.put(uuid, displayName);
}
}
public void cacheSavedNames() {
try {
playerNames.putAll(db.getUsersTable().getPlayerNames());
Map<UUID, String> playerNames = db.getUsersTable().getPlayerNames();
this.playerNames.putAll(playerNames);
for (Map.Entry<UUID, String> entry : playerNames.entrySet()) {
uuids.put(entry.getValue(), entry.getKey());
}
} catch (SQLException e) {
Log.toLog(this.getClass().getName(), e);
}
@ -144,4 +155,8 @@ public class DataCache extends SessionCache {
public Map<UUID, Integer> getFirstSessionMsgCounts() {
return firstSessionInformation;
}
public UUID getUUIDof(String playerName) {
return uuids.get(playerName);
}
}

View File

@ -6,7 +6,6 @@ import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CountryResponse;
import com.maxmind.geoip2.record.Country;
import main.java.com.djrapitops.plan.api.exceptions.PlanEnableException;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import java.io.File;
@ -105,7 +104,7 @@ public class GeolocationCache {
/**
* Checks if the DB exists, if not, it downloads it
*
* @throws PlanEnableException when an error at download or saving the DB happens
* @throws IOException when an error at download or saving the DB happens
*/
public static void checkDB() throws IOException {
if (geolocationDB.exists()) {

View File

@ -2,7 +2,7 @@ package main.java.com.djrapitops.plan.systems.cache;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.Session;
import main.java.com.djrapitops.plan.data.container.Session;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import java.sql.SQLException;
@ -30,12 +30,11 @@ public class SessionCache {
}
public void cacheSession(UUID uuid, Session session) {
Log.debug("Caching a session: " + session.getSessionStart());
activeSessions.put(uuid, session);
plugin.getInfoManager().cachePlayer(uuid);
}
public void endSession(UUID uuid, long time) {
Log.debug("Ending a session: " + time);
try {
Session session = activeSessions.get(uuid);
if (session == null) {
@ -46,8 +45,8 @@ public class SessionCache {
} catch (SQLException e) {
Log.toLog(this.getClass().getName(), e);
} finally {
Log.debug("Removing session from cache: " + time);
activeSessions.remove(uuid);
plugin.getInfoManager().cachePlayer(uuid);
}
}

View File

@ -7,12 +7,14 @@ package main.java.com.djrapitops.plan.systems.info;
import com.djrapitops.plugin.api.utility.log.ErrorLogger;
import com.djrapitops.plugin.api.utility.log.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.exceptions.*;
import main.java.com.djrapitops.plan.command.commands.AnalyzeCommand;
import main.java.com.djrapitops.plan.data.AnalysisData;
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.element.InspectContainer;
import main.java.com.djrapitops.plan.data.plugin.HookHandler;
import main.java.com.djrapitops.plan.data.plugin.PluginData;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.settings.theme.Theme;
import main.java.com.djrapitops.plan.systems.cache.DataCache;
import main.java.com.djrapitops.plan.systems.info.parsing.AnalysisPageParser;
import main.java.com.djrapitops.plan.systems.info.parsing.InspectPageParser;
@ -20,7 +22,6 @@ import main.java.com.djrapitops.plan.systems.processing.Processor;
import main.java.com.djrapitops.plan.systems.webserver.PageCache;
import main.java.com.djrapitops.plan.systems.webserver.WebServer;
import main.java.com.djrapitops.plan.systems.webserver.response.*;
import main.java.com.djrapitops.plan.systems.webserver.theme.Theme;
import main.java.com.djrapitops.plan.systems.webserver.webapi.WebAPIManager;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalysisReadyWebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.AnalyzeWebAPI;
@ -29,10 +30,11 @@ import main.java.com.djrapitops.plan.systems.webserver.webapi.bungee.*;
import main.java.com.djrapitops.plan.systems.webserver.webapi.universal.PingWebAPI;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.Analysis;
import main.java.com.djrapitops.plan.utilities.file.export.HtmlExport;
import main.java.com.djrapitops.plan.utilities.html.HtmlStructure;
import main.java.com.djrapitops.plan.utilities.html.structure.InspectPluginsTabContentCreator;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.*;
@ -53,7 +55,7 @@ public class BukkitInformationManager extends InformationManager {
private String analysisPluginsTab;
private Long refreshDate;
private final Map<UUID, String> pluginsTabContents;
private final Map<UUID, String[]> pluginsTabContents;
public BukkitInformationManager(Plan plugin) {
this.plugin = plugin;
@ -94,6 +96,10 @@ public class BukkitInformationManager extends InformationManager {
@Override
public void cachePlayer(UUID uuid) {
if (uuid == null) {
Log.debug("BukkitInformationManager.cachePlayer: UUID was null");
return;
}
if (usingAnotherWebServer) {
try {
getWebAPI().getAPI(PostHtmlWebAPI.class).sendInspectHtml(webServerAddress, uuid, getPlayerHtml(uuid));
@ -105,6 +111,9 @@ public class BukkitInformationManager extends InformationManager {
}
} else {
PageCache.cachePage("inspectPage: " + uuid, () -> new InspectPageResponse(this, uuid));
if (Settings.ANALYSIS_EXPORT.isTrue()) {
HtmlExport.exportPlayer(plugin, uuid);
}
}
plugin.addToProcessQueue(new Processor<UUID>(uuid) {
@Override
@ -132,13 +141,26 @@ public class BukkitInformationManager extends InformationManager {
String serverName = plugin.getServerInfoManager().getServerName();
HookHandler hookHandler = plugin.getHookHandler();
List<PluginData> plugins = hookHandler.getAdditionalDataSources();
Map<String, Serializable> replaceMap = hookHandler.getAdditionalInspectReplaceRules(uuid);
String contents = HtmlStructure.createInspectPluginsTabContent(serverName, plugins, replaceMap);
cacheInspectPluginsTab(uuid, contents);
Map<PluginData, InspectContainer> containers = new HashMap<>();
for (PluginData pluginData : plugins) {
InspectContainer inspectContainer = new InspectContainer();
try {
InspectContainer container = pluginData.getPlayerData(uuid, inspectContainer);
if (container != null && !container.isEmpty()) {
containers.put(pluginData, container);
}
} catch (Exception e) {
String sourcePlugin = pluginData.getSourcePlugin();
Log.error("PluginData caused exception: " + sourcePlugin);
Log.toLog(this.getClass().getName() + " " + sourcePlugin, e);
}
}
cacheInspectPluginsTab(uuid, InspectPluginsTabContentCreator.createContent(containers));
}
}
public void cacheInspectPluginsTab(UUID uuid, String contents) {
public void cacheInspectPluginsTab(UUID uuid, String[] contents) {
if (usingAnotherWebServer) {
try {
getWebAPI().getAPI(PostInspectPluginsTabWebAPI.class).sendPluginsTab(webServerAddress, uuid, contents);
@ -158,8 +180,8 @@ public class BukkitInformationManager extends InformationManager {
}
@Override
public String getPluginsTabContent(UUID uuid) {
String calculating = HtmlStructure.createInspectPageTabContentCalculating();
public String[] getPluginsTabContent(UUID uuid) {
String[] calculating = HtmlStructure.createInspectPageTabContentCalculating();
return pluginsTabContents.getOrDefault(uuid, calculating);
}
@ -271,7 +293,11 @@ public class BukkitInformationManager extends InformationManager {
cacheAnalysisHtml(html);
}
} else {
PageCache.cachePage("analysisPage:" + Plan.getServerUUID(), () -> new AnalysisPageResponse(html));
UUID serverUUID = Plan.getServerUUID();
PageCache.cachePage("analysisPage:" + serverUUID, () -> new AnalysisPageResponse(html));
if (Settings.ANALYSIS_EXPORT.isTrue()) {
HtmlExport.exportServer(plugin, serverUUID);
}
}
}

View File

@ -11,6 +11,7 @@ import main.java.com.djrapitops.plan.api.exceptions.ParseException;
import main.java.com.djrapitops.plan.api.exceptions.WebAPIConnectionFailException;
import main.java.com.djrapitops.plan.api.exceptions.WebAPIException;
import main.java.com.djrapitops.plan.api.exceptions.WebAPINotFoundException;
import main.java.com.djrapitops.plan.settings.Settings;
import main.java.com.djrapitops.plan.systems.cache.DataCache;
import main.java.com.djrapitops.plan.systems.info.parsing.NetworkPageParser;
import main.java.com.djrapitops.plan.systems.info.server.BungeeServerInfoManager;
@ -24,6 +25,7 @@ import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.InspectWebA
import main.java.com.djrapitops.plan.systems.webserver.webapi.bukkit.IsOnlineWebAPI;
import main.java.com.djrapitops.plan.systems.webserver.webapi.bungee.RequestPluginsTabWebAPI;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.file.export.HtmlExport;
import main.java.com.djrapitops.plan.utilities.html.HtmlStructure;
import java.io.IOException;
@ -43,7 +45,7 @@ public class BungeeInformationManager extends InformationManager {
private Map<UUID, ServerInfo> bukkitServers;
private final Map<UUID, String> networkPageContent;
private final Map<UUID, Map<UUID, String>> pluginsTabContent;
private final Map<UUID, Map<UUID, String[]>> pluginsTabContent;
private final BungeeServerInfoManager serverInfoManager;
public BungeeInformationManager(PlanBungee plugin) throws SQLException {
@ -174,6 +176,8 @@ public class BungeeInformationManager extends InformationManager {
try {
getWebAPI().getAPI(IsOnlineWebAPI.class).sendRequest(server.getWebAddress(), uuid);
return server;
} catch (WebAPIConnectionFailException e) {
serverInfoManager.serverHasGoneOffline(server.getUuid());
} catch (WebAPINotFoundException ignored) {
/*continue*/
} catch (WebAPIException e) {
@ -182,7 +186,7 @@ public class BungeeInformationManager extends InformationManager {
}
}
Optional<ServerInfo> bukkitServer = onlineServers.stream().findAny();
Optional<ServerInfo> bukkitServer = serverInfoManager.getOnlineBukkitServers().stream().findAny();
if (bukkitServer.isPresent()) {
return bukkitServer.get();
}
@ -246,10 +250,10 @@ public class BungeeInformationManager extends InformationManager {
*/
@Override
public String getPlayerHtml(UUID uuid) {
Response response = PageCache.loadPage("inspectPage:" + uuid,
Response response = PageCache.copyPage("inspectPage:" + uuid,
() -> new NotFoundResponse("No Bukkit Servers were online to process this request"));
if (response instanceof InspectPageResponse) {
((InspectPageResponse) response).setInspectPagePluginsTab(pluginsTabContent.get(uuid));
((InspectPageResponse) response).setInspectPagePluginsTab(getPluginsTabContent(uuid));
}
return response.getContent();
}
@ -275,17 +279,28 @@ public class BungeeInformationManager extends InformationManager {
* @return Html string.
*/
@Override
public String getPluginsTabContent(UUID uuid) {
Map<UUID, String> pluginsTab = pluginsTabContent.get(uuid);
public String[] getPluginsTabContent(UUID uuid) {
Map<UUID, String[]> pluginsTab = pluginsTabContent.get(uuid);
if (pluginsTab == null) {
return HtmlStructure.createInspectPageTabContentCalculating();
}
StringBuilder builder = new StringBuilder();
for (String tab : pluginsTab.values()) {
builder.append(tab);
List<String[]> order = new ArrayList<>(pluginsTab.values());
// Sort serverNames alphabetically
order.sort(new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
return o1[0].compareTo(o2[1]);
}
});
StringBuilder nav = new StringBuilder();
StringBuilder tabs = new StringBuilder();
for (String[] tab : order) {
nav.append(tab[0]);
tabs.append(tab[1]);
}
return builder.toString();
return new String[]{nav.toString(), tabs.toString()};
}
/**
@ -295,8 +310,8 @@ public class BungeeInformationManager extends InformationManager {
* @param uuid UUID of the player
* @param html Plugins tab html for the player on the server
*/
public void cachePluginsTabContent(UUID serverUUID, UUID uuid, String html) {
Map<UUID, String> perServerPluginsTab = pluginsTabContent.getOrDefault(uuid, new HashMap<>());
public void cachePluginsTabContent(UUID serverUUID, UUID uuid, String[] html) {
Map<UUID, String[]> perServerPluginsTab = pluginsTabContent.getOrDefault(uuid, new HashMap<>());
perServerPluginsTab.put(serverUUID, html);
pluginsTabContent.put(uuid, perServerPluginsTab);
Response inspectResponse = PageCache.loadPage("inspectPage: " + uuid);
@ -356,7 +371,11 @@ public class BungeeInformationManager extends InformationManager {
@Override
public void updateNetworkPageContent() {
PageCache.cachePage("analysisPage:" + MiscUtils.getIPlan().getServerUuid(), () -> new AnalysisPageResponse(this));
UUID serverUUID = MiscUtils.getIPlan().getServerUuid();
PageCache.cachePage("analysisPage:" + serverUUID, () -> new AnalysisPageResponse(this));
if (Settings.ANALYSIS_EXPORT.isTrue()) {
HtmlExport.exportServer(plugin, serverUUID);
}
}
public void sendConfigSettings() {

View File

@ -70,7 +70,7 @@ public abstract class InformationManager {
analysisNotification.put(serverUUID, notify);
}
public abstract String getPluginsTabContent(UUID uuid);
public abstract String[] getPluginsTabContent(UUID uuid);
public boolean isUsingAnotherWebServer() {
return usingAnotherWebServer;

Some files were not shown because too many files have changed in this diff Show More