mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-12-23 09:37:54 +01:00
Unique Players, Outlier removal, Gender pie removed
This commit is contained in:
parent
a2af65349a
commit
0b061f0a5e
@ -16,6 +16,7 @@ public enum Settings {
|
|||||||
ANALYSIS_REFRESH_ON_ENABLE("Settings.Cache.AnalysisCache.RefreshAnalysisCacheOnEnable"),
|
ANALYSIS_REFRESH_ON_ENABLE("Settings.Cache.AnalysisCache.RefreshAnalysisCacheOnEnable"),
|
||||||
ANALYSIS_LOG_TO_CONSOLE("Settings.Analysis.LogProgressOnConsole"),
|
ANALYSIS_LOG_TO_CONSOLE("Settings.Analysis.LogProgressOnConsole"),
|
||||||
ANALYSIS_LOG_FINISHED("Settings.Analysis.NotifyWhenFinished"),
|
ANALYSIS_LOG_FINISHED("Settings.Analysis.NotifyWhenFinished"),
|
||||||
|
ANALYSIS_REMOVE_OUTLIERS("Settings.Analysis.RemoveOutliersFromVisualization"),
|
||||||
ANALYSIS_EXPORT("Settings.Analysis.Export.Enabled"),
|
ANALYSIS_EXPORT("Settings.Analysis.Export.Enabled"),
|
||||||
SHOW_ALTERNATIVE_IP("Settings.WebServer.ShowAlternativeServerIP"),
|
SHOW_ALTERNATIVE_IP("Settings.WebServer.ShowAlternativeServerIP"),
|
||||||
USE_ALTERNATIVE_UI("Settings.UseTextUI"),
|
USE_ALTERNATIVE_UI("Settings.UseTextUI"),
|
||||||
@ -78,9 +79,6 @@ public enum Settings {
|
|||||||
HCOLOR_GMP_1("Customization.Colors.HTML.GamemodePie.Creative"),
|
HCOLOR_GMP_1("Customization.Colors.HTML.GamemodePie.Creative"),
|
||||||
HCOLOR_GMP_2("Customization.Colors.HTML.GamemodePie.Adventure"),
|
HCOLOR_GMP_2("Customization.Colors.HTML.GamemodePie.Adventure"),
|
||||||
HCOLOR_GMP_3("Customization.Colors.HTML.GamemodePie.Spectator"),
|
HCOLOR_GMP_3("Customization.Colors.HTML.GamemodePie.Spectator"),
|
||||||
HCOLOR_GENP_M("Customization.Colors.HTML.GenderPie.Male"),
|
|
||||||
HCOLOR_GENP_F("Customization.Colors.HTML.GenderPie.Female"),
|
|
||||||
HCOLOR_GENP_U("Customization.Colors.HTML.GenderPie.Unknown"),
|
|
||||||
// StringList
|
// StringList
|
||||||
HIDE_FACTIONS("Customization.Plugins.Factions.HideFactions"),
|
HIDE_FACTIONS("Customization.Plugins.Factions.HideFactions"),
|
||||||
HIDE_TOWNS("Customization.Plugins.Towny.HideTowns");
|
HIDE_TOWNS("Customization.Plugins.Towny.HideTowns");
|
||||||
|
@ -70,7 +70,14 @@ public class AnalysisData {
|
|||||||
private String geomapZ;
|
private String geomapZ;
|
||||||
private String geomapCodes;
|
private String geomapCodes;
|
||||||
|
|
||||||
private int[] genderData;
|
private int avgUniqJoins;
|
||||||
|
private int avgUniqJoinsDay;
|
||||||
|
private int avgUniqJoinsWeek;
|
||||||
|
private int avgUniqJoinsMonth;
|
||||||
|
|
||||||
|
private int uniqueJoinsDay;
|
||||||
|
private int uniqueJoinsWeek;
|
||||||
|
private int uniqueJoinsMonth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
@ -78,6 +85,13 @@ public class AnalysisData {
|
|||||||
* All data has to be set with setters to avoid NPEs.
|
* All data has to be set with setters to avoid NPEs.
|
||||||
*/
|
*/
|
||||||
public AnalysisData() {
|
public AnalysisData() {
|
||||||
|
avgUniqJoins = 0;
|
||||||
|
avgUniqJoinsDay = 0;
|
||||||
|
avgUniqJoinsWeek = 0;
|
||||||
|
avgUniqJoinsMonth = 0;
|
||||||
|
uniqueJoinsDay = 0;
|
||||||
|
uniqueJoinsWeek = 0;
|
||||||
|
uniqueJoinsMonth = 0;
|
||||||
sortablePlayersTable = Html.ERROR_NOT_SET + "";
|
sortablePlayersTable = Html.ERROR_NOT_SET + "";
|
||||||
commandUseTableHtml = Html.ERROR_NOT_SET + "";
|
commandUseTableHtml = Html.ERROR_NOT_SET + "";
|
||||||
recentPlayers = Html.ERROR_NOT_SET + "";
|
recentPlayers = Html.ERROR_NOT_SET + "";
|
||||||
@ -88,7 +102,6 @@ public class AnalysisData {
|
|||||||
sessionDistributionData = new String[]{"[]", "[]"};
|
sessionDistributionData = new String[]{"[]", "[]"};
|
||||||
playtimeDistributionData = new String[]{"[]", "[]"};
|
playtimeDistributionData = new String[]{"[]", "[]"};
|
||||||
playersDataArray = new String[]{"[0]", "[\"No data\"]", "[0]", "[\"No data\"]", "[0]", "[\"No data\"]"};
|
playersDataArray = new String[]{"[0]", "[\"No data\"]", "[0]", "[\"No data\"]", "[0]", "[\"No data\"]"};
|
||||||
genderData = new int[]{0, 0, 0};
|
|
||||||
additionalDataReplaceMap = new HashMap<>();
|
additionalDataReplaceMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,9 +207,6 @@ public class AnalysisData {
|
|||||||
if (!Arrays.deepEquals(this.playersDataArray, other.playersDataArray)) {
|
if (!Arrays.deepEquals(this.playersDataArray, other.playersDataArray)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Arrays.equals(this.genderData, other.genderData)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,29 +872,6 @@ public class AnalysisData {
|
|||||||
this.sessionAverage = sessionAverage;
|
this.sessionAverage = sessionAverage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the integer array containing 3 numbers.
|
|
||||||
*
|
|
||||||
* 0 Male, 1 Female, 2 Unknown.
|
|
||||||
*
|
|
||||||
* @return for example [0, 4, 5] when 0 male, 4 female and 5 unknown.
|
|
||||||
*/
|
|
||||||
public int[] getGenderData() {
|
|
||||||
return genderData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Set the integer array containing 3 numbers.
|
|
||||||
*
|
|
||||||
* 0 Male, 1 Female, 2 Unknown.
|
|
||||||
*
|
|
||||||
* @param genderData for example [0, 4, 5]
|
|
||||||
*/
|
|
||||||
public void setGenderData(int[] genderData) {
|
|
||||||
this.genderData = genderData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data for the Session Punchcard.
|
* Get the data for the Session Punchcard.
|
||||||
*
|
*
|
||||||
@ -940,4 +927,60 @@ public class AnalysisData {
|
|||||||
public void setPlaytimeDistributionData(String[] playtimeDistributionData) {
|
public void setPlaytimeDistributionData(String[] playtimeDistributionData) {
|
||||||
this.playtimeDistributionData = playtimeDistributionData;
|
this.playtimeDistributionData = playtimeDistributionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getAvgUniqJoins() {
|
||||||
|
return avgUniqJoins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAvgUniqJoinsDay() {
|
||||||
|
return avgUniqJoinsDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAvgUniqJoinsWeek() {
|
||||||
|
return avgUniqJoinsWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAvgUniqJoinsMonth() {
|
||||||
|
return avgUniqJoinsMonth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvgUniqJoins(int avgUniqJoins) {
|
||||||
|
this.avgUniqJoins = avgUniqJoins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvgUniqJoinsDay(int avgUniqJoinsDay) {
|
||||||
|
this.avgUniqJoinsDay = avgUniqJoinsDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvgUniqJoinsWeek(int avgUniqJoinsWeek) {
|
||||||
|
this.avgUniqJoinsWeek = avgUniqJoinsWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvgUniqJoinsMonth(int avgUniqJoinsMonth) {
|
||||||
|
this.avgUniqJoinsMonth = avgUniqJoinsMonth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUniqueJoinsDay() {
|
||||||
|
return uniqueJoinsDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUniqueJoinsDay(int uniqueJoinsDay) {
|
||||||
|
this.uniqueJoinsDay = uniqueJoinsDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUniqueJoinsWeek() {
|
||||||
|
return uniqueJoinsWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUniqueJoinsWeek(int uniqueJoinsWeek) {
|
||||||
|
this.uniqueJoinsWeek = uniqueJoinsWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUniqueJoinsMonth() {
|
||||||
|
return uniqueJoinsMonth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUniqueJoinsMonth(int uniqueJoinsMonth) {
|
||||||
|
this.uniqueJoinsMonth = uniqueJoinsMonth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import main.java.com.djrapitops.plan.utilities.analysis.Analysis;
|
import main.java.com.djrapitops.plan.utilities.analysis.Analysis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,11 +35,11 @@ public class RawAnalysisData {
|
|||||||
private Map<String, Long> latestLogins;
|
private Map<String, Long> latestLogins;
|
||||||
private Map<String, Long> playtimes;
|
private Map<String, Long> playtimes;
|
||||||
private List<SessionData> sessiondata;
|
private List<SessionData> sessiondata;
|
||||||
|
private Map<UUID, List<SessionData>> sortedSessionData;
|
||||||
private Map<String, Integer> commandUse;
|
private Map<String, Integer> commandUse;
|
||||||
private Map<String, Integer> geolocations;
|
private Map<String, Integer> geolocations;
|
||||||
private Map<String, String> geocodes;
|
private Map<String, String> geocodes;
|
||||||
private List<Long> registered;
|
private List<Long> registered;
|
||||||
private int[] genders;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a new empty dataset.
|
* Constructor for a new empty dataset.
|
||||||
@ -56,16 +57,17 @@ public class RawAnalysisData {
|
|||||||
inactive = 0;
|
inactive = 0;
|
||||||
totalKills = 0;
|
totalKills = 0;
|
||||||
totalMobKills = 0;
|
totalMobKills = 0;
|
||||||
|
totalDeaths = 0;
|
||||||
ops = 0;
|
ops = 0;
|
||||||
ages = new ArrayList<>();
|
ages = new ArrayList<>();
|
||||||
latestLogins = new HashMap<>();
|
latestLogins = new HashMap<>();
|
||||||
playtimes = new HashMap<>();
|
playtimes = new HashMap<>();
|
||||||
sessiondata = new ArrayList<>();
|
sessiondata = new ArrayList<>();
|
||||||
|
sortedSessionData = new HashMap<>();
|
||||||
commandUse = new HashMap<>();
|
commandUse = new HashMap<>();
|
||||||
geolocations = new HashMap<>();
|
geolocations = new HashMap<>();
|
||||||
geocodes = new HashMap<>();
|
geocodes = new HashMap<>();
|
||||||
registered = new ArrayList<>();
|
registered = new ArrayList<>();
|
||||||
genders = new int[]{0, 0, 0};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -368,6 +370,15 @@ public class RawAnalysisData {
|
|||||||
return sessiondata;
|
return sessiondata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<UUID, List<SessionData>> getSortedSessionData() {
|
||||||
|
return sortedSessionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSessions(UUID uuid, List<SessionData> sessions) {
|
||||||
|
sessiondata.addAll(sessions);
|
||||||
|
sortedSessionData.put(uuid, sessions);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param commandUse
|
* @param commandUse
|
||||||
@ -391,29 +402,4 @@ public class RawAnalysisData {
|
|||||||
public List<Long> getRegistered() {
|
public List<Long> getRegistered() {
|
||||||
return registered;
|
return registered;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public int[] getGenders() {
|
|
||||||
return genders;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param gender
|
|
||||||
*/
|
|
||||||
public void setGenders(int[] gender) {
|
|
||||||
this.genders = gender;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param i
|
|
||||||
* @param amount
|
|
||||||
*/
|
|
||||||
public void addToGender(int i, int amount) {
|
|
||||||
this.genders[i] = this.genders[i] + amount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ import org.bukkit.scheduler.BukkitRunnable;
|
|||||||
*/
|
*/
|
||||||
public abstract class SQLDB extends Database {
|
public abstract class SQLDB extends Database {
|
||||||
|
|
||||||
final Plan plugin;
|
|
||||||
|
|
||||||
private final boolean supportsModification;
|
private final boolean supportsModification;
|
||||||
|
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
@ -44,7 +42,6 @@ public abstract class SQLDB extends Database {
|
|||||||
*/
|
*/
|
||||||
public SQLDB(Plan plugin, boolean supportsModification) {
|
public SQLDB(Plan plugin, boolean supportsModification) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
this.plugin = plugin;
|
|
||||||
this.supportsModification = supportsModification;
|
this.supportsModification = supportsModification;
|
||||||
boolean usingMySQL = getName().equals("MySQL");
|
boolean usingMySQL = getName().equals("MySQL");
|
||||||
|
|
||||||
@ -158,6 +155,7 @@ public abstract class SQLDB extends Database {
|
|||||||
Set<UUID> uuids = usersTable.getSavedUUIDs();
|
Set<UUID> uuids = usersTable.getSavedUUIDs();
|
||||||
uuids.removeAll(usersTable.getContainsBukkitData(uuids));
|
uuids.removeAll(usersTable.getContainsBukkitData(uuids));
|
||||||
if (uuids.isEmpty()) {
|
if (uuids.isEmpty()) {
|
||||||
|
Log.debug("No conversion necessary.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.info("Beginning Bukkit Data -> DB Conversion for " + uuids.size() + " players");
|
Log.info("Beginning Bukkit Data -> DB Conversion for " + uuids.size() + " players");
|
||||||
@ -313,9 +311,9 @@ public abstract class SQLDB extends Database {
|
|||||||
List<SessionData> sessions = sessionsTable.getSessionData(userId);
|
List<SessionData> sessions = sessionsTable.getSessionData(userId);
|
||||||
data.addSessions(sessions);
|
data.addSessions(sessions);
|
||||||
data.setPlayerKills(killsTable.getPlayerKills(userId));
|
data.setPlayerKills(killsTable.getPlayerKills(userId));
|
||||||
for (DBCallableProcessor processor : processors) {
|
processors.stream().forEach((processor) -> {
|
||||||
processor.process(data);
|
processor.process(data);
|
||||||
}
|
});
|
||||||
Benchmark.stop("DB Give userdata to processors");
|
Benchmark.stop("DB Give userdata to processors");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,12 +331,9 @@ public abstract class SQLDB extends Database {
|
|||||||
|
|
||||||
Benchmark.start("DB get UserData for " + uuidsCol.size());
|
Benchmark.start("DB get UserData for " + uuidsCol.size());
|
||||||
Map<UUID, Integer> userIds = usersTable.getAllUserIds();
|
Map<UUID, Integer> userIds = usersTable.getAllUserIds();
|
||||||
Set<UUID> remove = new HashSet<>();
|
Set<UUID> remove = uuidsCol.stream()
|
||||||
for (UUID uuid : uuidsCol) {
|
.filter((uuid) -> (!userIds.containsKey(uuid)))
|
||||||
if (!userIds.containsKey(uuid)) {
|
.collect(Collectors.toSet());
|
||||||
remove.add(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<UUID> uuids = new ArrayList<>(uuidsCol);
|
List<UUID> uuids = new ArrayList<>(uuidsCol);
|
||||||
Log.debug("Data not found for: " + remove.size());
|
Log.debug("Data not found for: " + remove.size());
|
||||||
uuids.removeAll(remove);
|
uuids.removeAll(remove);
|
||||||
@ -426,23 +421,20 @@ public abstract class SQLDB extends Database {
|
|||||||
gmTimesTable.saveGMTimes(id, gmTimes.get(id));
|
gmTimesTable.saveGMTimes(id, gmTimes.get(id));
|
||||||
}
|
}
|
||||||
Benchmark.stop("Save GMTimes");
|
Benchmark.stop("Save GMTimes");
|
||||||
for (Integer id : locations.keySet()) {
|
userDatas.values().stream()
|
||||||
UUID uuid = uuids.get(id);
|
.filter(u -> u != null)
|
||||||
if (uuid != null) {
|
.filter(uData -> uData.isAccessed())
|
||||||
UserData uData = userDatas.get(uuid);
|
.forEach(uData -> {
|
||||||
if (uData != null) {
|
|
||||||
uData.stopAccessing();
|
uData.stopAccessing();
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
// Save leftovers
|
// Save leftovers
|
||||||
for (UserData userData : saveLast) {
|
saveLast.stream().forEach((userData) -> {
|
||||||
try {
|
try {
|
||||||
saveUserData(userData);
|
saveUserData(userData);
|
||||||
} catch (SQLException | NullPointerException e) {
|
} catch (SQLException | NullPointerException e) {
|
||||||
exceptions.add(e);
|
exceptions.add(e);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
if (!exceptions.isEmpty()) {
|
if (!exceptions.isEmpty()) {
|
||||||
Log.error("SEVERE: MULTIPLE ERRORS OCCURRED: " + exceptions.size());
|
Log.error("SEVERE: MULTIPLE ERRORS OCCURRED: " + exceptions.size());
|
||||||
Log.toLog(this.getClass().getName(), exceptions);
|
Log.toLog(this.getClass().getName(), exceptions);
|
||||||
@ -478,74 +470,6 @@ public abstract class SQLDB extends Database {
|
|||||||
data.stopAccessing();
|
data.stopAccessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param locations
|
|
||||||
* @throws SQLException
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void saveAdditionalLocationsList(int userId, List<Location> locations) throws SQLException {
|
|
||||||
locationsTable.saveAdditionalLocationsList(userId, locations);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param names
|
|
||||||
* @param lastNick
|
|
||||||
* @throws SQLException
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void saveNickList(int userId, Set<String> names, String lastNick) throws SQLException {
|
|
||||||
nicknamesTable.saveNickList(userId, names, lastNick);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param sessions
|
|
||||||
* @throws SQLException
|
|
||||||
* @deprecated Use sessionsTable instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void saveSessionList(int userId, List<SessionData> sessions) throws SQLException {
|
|
||||||
sessionsTable.saveSessionData(userId, sessions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param kills
|
|
||||||
* @throws SQLException
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void savePlayerKills(int userId, List<KillData> kills) throws SQLException {
|
|
||||||
killsTable.savePlayerKills(userId, kills);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param ips
|
|
||||||
* @throws SQLException
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void saveIPList(int userId, Set<InetAddress> ips) throws SQLException {
|
|
||||||
ipsTable.saveIPList(userId, ips);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param gamemodeTimes
|
|
||||||
* @throws SQLException
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void saveGMTimes(int userId, Map<GameMode, Long> gamemodeTimes) throws SQLException {
|
|
||||||
gmTimesTable.saveGMTimes(userId, gamemodeTimes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -4,7 +4,6 @@ import java.sql.PreparedStatement;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -21,10 +20,7 @@ import main.java.com.djrapitops.plan.data.UserData;
|
|||||||
import main.java.com.djrapitops.plan.database.databases.SQLDB;
|
import main.java.com.djrapitops.plan.database.databases.SQLDB;
|
||||||
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
||||||
import main.java.com.djrapitops.plan.utilities.UUIDFetcher;
|
import main.java.com.djrapitops.plan.utilities.UUIDFetcher;
|
||||||
import static org.bukkit.Bukkit.getOfflinePlayer;
|
|
||||||
import static org.bukkit.Bukkit.getOfflinePlayers;
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import static org.bukkit.Bukkit.getOfflinePlayer;
|
import static org.bukkit.Bukkit.getOfflinePlayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package main.java.com.djrapitops.plan.ui.graphs;
|
package main.java.com.djrapitops.plan.ui.graphs;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -10,9 +11,11 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import main.java.com.djrapitops.plan.Settings;
|
||||||
import main.java.com.djrapitops.plan.data.SessionData;
|
import main.java.com.djrapitops.plan.data.SessionData;
|
||||||
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
||||||
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
||||||
|
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -65,13 +68,37 @@ public class PlayerActivityGraphCreator {
|
|||||||
playersOnline.add(lastPValue);
|
playersOnline.add(lastPValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Settings.ANALYSIS_REMOVE_OUTLIERS.isTrue()) {
|
||||||
|
long average = MathUtils.averageLong(playersOnline.stream());
|
||||||
|
double standardDiviation = getStandardDiviation(playersOnline, average);
|
||||||
|
if (standardDiviation > 3) {
|
||||||
|
for (int i = 0; i < playersOnline.size(); i++) {
|
||||||
|
long value = playersOnline.get(i);
|
||||||
|
if (value - average > 3 * standardDiviation) {
|
||||||
|
playersOnline.set(i, (long) maxPlayers + 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Benchmark.stop("Player Activity Graph Amount Calculation");
|
Benchmark.stop("Player Activity Graph Amount Calculation");
|
||||||
playersOnline.add(0L);
|
playersOnline.add(0L);
|
||||||
|
playersOnline.add(0L);
|
||||||
|
playersOnline.add(0L);
|
||||||
|
playersOnline.add(0L);
|
||||||
playersOnline.add((long) maxPlayers);
|
playersOnline.add((long) maxPlayers);
|
||||||
Benchmark.stop("Generate Player Activity Graph " + sessionData.size() + " " + scale + " |");
|
Benchmark.stop("Generate Player Activity Graph " + sessionData.size() + " " + scale + " |");
|
||||||
return new String[]{playersOnline.toString(), labels.toString()};
|
return new String[]{playersOnline.toString(), labels.toString()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static double getStandardDiviation(List<Long> players, long avg) {
|
||||||
|
List<Double> valueMinusAvg = players.stream()
|
||||||
|
.map(p -> Math.pow(Math.abs(p - avg), 2))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
int size = valueMinusAvg.size();
|
||||||
|
double sum = MathUtils.sumDouble(valueMinusAvg.stream().map(p -> (Serializable) p));
|
||||||
|
return Math.sqrt(sum / size);
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<Long, Integer> transformIntoChangeMap(List<Long> sessionStarts, List<Long> sessionEnds) {
|
private static Map<Long, Integer> transformIntoChangeMap(List<Long> sessionStarts, List<Long> sessionEnds) {
|
||||||
Benchmark.start("Player Activity Graph Calc. Change");
|
Benchmark.start("Player Activity Graph Calc. Change");
|
||||||
Map<Long, Integer> starts = sessionStarts.stream().distinct().collect(Collectors.toMap(Function.identity(), start -> Collections.frequency(sessionStarts, start)));
|
Map<Long, Integer> starts = sessionStarts.stream().distinct().collect(Collectors.toMap(Function.identity(), start -> Collections.frequency(sessionStarts, start)));
|
||||||
|
@ -6,12 +6,15 @@
|
|||||||
package main.java.com.djrapitops.plan.ui.graphs;
|
package main.java.com.djrapitops.plan.ui.graphs;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import main.java.com.djrapitops.plan.Log;
|
import main.java.com.djrapitops.plan.Log;
|
||||||
|
import main.java.com.djrapitops.plan.Settings;
|
||||||
import main.java.com.djrapitops.plan.data.SessionData;
|
import main.java.com.djrapitops.plan.data.SessionData;
|
||||||
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -27,7 +30,7 @@ public class PunchCardGraphCreator {
|
|||||||
public static String generateDataArray(Collection<SessionData> data) {
|
public static String generateDataArray(Collection<SessionData> data) {
|
||||||
// Initialize dataset
|
// Initialize dataset
|
||||||
List<Long> sessionStarts = getSessionStarts(data);
|
List<Long> sessionStarts = getSessionStarts(data);
|
||||||
List<int[]> daysAndHours = getDaysAndHours(sessionStarts);
|
List<int[]> daysAndHours = AnalysisUtils.getDaysAndHours(sessionStarts);
|
||||||
int[][] dataArray = createDataArray(daysAndHours);
|
int[][] dataArray = createDataArray(daysAndHours);
|
||||||
int big = findBiggestValue(dataArray);
|
int big = findBiggestValue(dataArray);
|
||||||
int[][] scaled = scale(dataArray, big);
|
int[][] scaled = scale(dataArray, big);
|
||||||
@ -65,36 +68,63 @@ public class PunchCardGraphCreator {
|
|||||||
int h = dAndH[1];
|
int h = dAndH[1];
|
||||||
dataArray[d][h] = dataArray[d][h] + 1;
|
dataArray[d][h] = dataArray[d][h] + 1;
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
Log.debug(" " + Arrays.toString(dataArray[i]));
|
||||||
|
}
|
||||||
|
if (Settings.ANALYSIS_REMOVE_OUTLIERS.isTrue()) {
|
||||||
|
int avg = findAverage(dataArray);
|
||||||
|
double standardDiviation = getStandardDiviation(dataArray, avg);
|
||||||
|
Log.debug("Diviation: " + standardDiviation);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
for (int j = 0; j < 24; j++) {
|
||||||
|
int value = dataArray[i][j];
|
||||||
|
if (value - avg > 3 * standardDiviation) {
|
||||||
|
dataArray[i][j] = (int) (avg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
Log.debug(" " + Arrays.toString(dataArray[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
return dataArray;
|
return dataArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<int[]> getDaysAndHours(List<Long> sessionStarts) {
|
private static double getStandardDiviation(int[][] array, int avg) {
|
||||||
List<int[]> daysAndHours = sessionStarts.stream().map(start -> {
|
int[][] valueMinusAvg = new int[7][24];
|
||||||
Calendar day = Calendar.getInstance();
|
for (int i = 0; i < 7; i++) {
|
||||||
day.setTimeInMillis(start);
|
for (int j = 0; j < 24; j++) {
|
||||||
int hourOfDay = day.get(Calendar.HOUR_OF_DAY);
|
valueMinusAvg[i][j] = (int) Math.pow(Math.abs(array[i][j] - avg), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int size = array.length * array[0].length;
|
||||||
|
int sum = sum(valueMinusAvg);
|
||||||
|
return Math.sqrt(sum / size);
|
||||||
|
}
|
||||||
|
|
||||||
int dayOfWeek = day.get(Calendar.DAY_OF_WEEK) - 2;
|
private static int findAverage(int[][] array) {
|
||||||
if (hourOfDay == 24) {
|
int total = sum(array);
|
||||||
hourOfDay = 0;
|
int size = array.length * array[0].length;
|
||||||
dayOfWeek += 1;
|
return (int) MathUtils.average(total, size);
|
||||||
}
|
}
|
||||||
if (dayOfWeek > 6) {
|
|
||||||
dayOfWeek = 0;
|
private static int sum(int[][] array) {
|
||||||
|
int total = 0;
|
||||||
|
for (int[] is : array) {
|
||||||
|
for (int i : is) {
|
||||||
|
total += i;
|
||||||
}
|
}
|
||||||
if (dayOfWeek < 0) {
|
|
||||||
dayOfWeek = 6;
|
|
||||||
}
|
}
|
||||||
return new int[]{dayOfWeek, hourOfDay};
|
return total;
|
||||||
}).collect(Collectors.toList());
|
|
||||||
return daysAndHours;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Long> getSessionStarts(Collection<SessionData> data) {
|
private static List<Long> getSessionStarts(Collection<SessionData> data) {
|
||||||
|
long now = MiscUtils.getTime();
|
||||||
List<Long> sessionStarts = data.stream()
|
List<Long> sessionStarts = data.stream()
|
||||||
.filter(s -> s != null)
|
.filter(s -> s != null)
|
||||||
.filter(s -> s.isValid())
|
.filter(s -> s.isValid())
|
||||||
.map(s -> s.getSessionStart())
|
.map(s -> s.getSessionStart())
|
||||||
|
.filter(start -> now - start < (long) 2592000 * (long) 1000)
|
||||||
.sorted()
|
.sorted()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
return sessionStarts;
|
return sessionStarts;
|
||||||
@ -135,7 +165,10 @@ public class PunchCardGraphCreator {
|
|||||||
scaled[i][j] = value;
|
scaled[i][j] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.debug("Biggest value: " + big);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
Log.debug(" " + Arrays.toString(scaled[i]));
|
||||||
|
}
|
||||||
return scaled;
|
return scaled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,11 @@ public class Response {
|
|||||||
String playerName = requestArgs[3].trim();
|
String playerName = requestArgs[3].trim();
|
||||||
UUID uuid = UUIDFetcher.getUUIDOf(playerName);
|
UUID uuid = UUIDFetcher.getUUIDOf(playerName);
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
String errorMessage = "HTTP/1.1 404 UUID not Found\r\n"
|
String errorMessage = "HTTP/1.1 500 UUID not Found\r\n"
|
||||||
+ "Content-Type: text/html;\r\n"
|
+ "Content-Type: text/html;\r\n"
|
||||||
+ "Content-Length: 30\r\n"
|
+ "Content-Length: 30\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
+ "<h1>404 - Player doesn't exist</h1>";
|
+ "<h1>500 - Player has no UUID. </h1>";
|
||||||
output.write(errorMessage.getBytes());
|
output.write(errorMessage.getBytes());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,11 +87,11 @@ public class Response {
|
|||||||
output.write((htmlDef + dataHtml).getBytes());
|
output.write((htmlDef + dataHtml).getBytes());
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
Log.toLog(this.getClass().getName(), e);
|
Log.toLog(this.getClass().getName(), e);
|
||||||
String errorMessage = "HTTP/1.1 404 Error\r\n"
|
String errorMessage = "HTTP/1.1 500 Error\r\n"
|
||||||
+ "Content-Type: text/html;\r\n"
|
+ "Content-Type: text/html;\r\n"
|
||||||
+ "Content-Length: 30\r\n"
|
+ "Content-Length: 30\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
+ "<h1>404 - Error has occurred..</h1>";
|
+ "<h1>500 - Error has occurred..</h1>";
|
||||||
output.write(errorMessage.getBytes());
|
output.write(errorMessage.getBytes());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -65,6 +65,13 @@ public class PlaceholderUtils {
|
|||||||
replaceMap.put("%version%", plugin.getDescription().getVersion());
|
replaceMap.put("%version%", plugin.getDescription().getVersion());
|
||||||
replaceMap.put("%planlite%", "");
|
replaceMap.put("%planlite%", "");
|
||||||
replaceMap.put("%sortabletable%", data.getSortablePlayersTable());
|
replaceMap.put("%sortabletable%", data.getSortablePlayersTable());
|
||||||
|
replaceMap.put("%uniquejoinsday%", data.getUniqueJoinsDay()+"");
|
||||||
|
replaceMap.put("%uniquejoinsweek%", data.getUniqueJoinsWeek()+"");
|
||||||
|
replaceMap.put("%uniquejoinsmonth%", data.getUniqueJoinsMonth()+"");
|
||||||
|
replaceMap.put("%avguniquejoins%", data.getAvgUniqJoins()+"");
|
||||||
|
replaceMap.put("%avguniquejoinsday%", data.getAvgUniqJoinsDay()+"");
|
||||||
|
replaceMap.put("%avguniquejoinsweek%", data.getAvgUniqJoinsWeek()+"");
|
||||||
|
replaceMap.put("%avguniquejoinsmonth%", data.getAvgUniqJoinsMonth()+"");
|
||||||
replaceMap.put("%dataday%", data.getPlayersDataArray()[0]);
|
replaceMap.put("%dataday%", data.getPlayersDataArray()[0]);
|
||||||
replaceMap.put("%labelsday%", data.getPlayersDataArray()[1]);
|
replaceMap.put("%labelsday%", data.getPlayersDataArray()[1]);
|
||||||
replaceMap.put("%dataweek%", data.getPlayersDataArray()[2]);
|
replaceMap.put("%dataweek%", data.getPlayersDataArray()[2]);
|
||||||
@ -102,14 +109,6 @@ public class PlaceholderUtils {
|
|||||||
replaceMap.put("%gmlabels%", "[\"Survival\", \"Creative\", \"Adventure\", \"Spectator\"]");
|
replaceMap.put("%gmlabels%", "[\"Survival\", \"Creative\", \"Adventure\", \"Spectator\"]");
|
||||||
replaceMap.put("%gmcolors%", "\"#" + Settings.HCOLOR_GMP_0 + "\",\"#" + Settings.HCOLOR_GMP_1
|
replaceMap.put("%gmcolors%", "\"#" + Settings.HCOLOR_GMP_0 + "\",\"#" + Settings.HCOLOR_GMP_1
|
||||||
+ "\",\"#" + Settings.HCOLOR_GMP_2 + "\",\"#" + Settings.HCOLOR_GMP_3 + "\"");
|
+ "\",\"#" + Settings.HCOLOR_GMP_2 + "\",\"#" + Settings.HCOLOR_GMP_3 + "\"");
|
||||||
replaceMap.put("%genderdata%", Arrays.toString(data.getGenderData()));
|
|
||||||
replaceMap.put("%gendermale%", data.getGenderData()[0] + "");
|
|
||||||
replaceMap.put("%genderfemale%", data.getGenderData()[1] + "");
|
|
||||||
replaceMap.put("%genderlabels%", "[\"Male\", \"Female\", \"Unknown\"]");
|
|
||||||
replaceMap.put("%gendercolors%", "\"#" + Settings.HCOLOR_GENP_M + "\",\"#" + Settings.HCOLOR_GENP_F
|
|
||||||
+ "\",\"#" + Settings.HCOLOR_GENP_U + "\"");
|
|
||||||
replaceMap.put("%genderfcolor%", "#" + Settings.HCOLOR_GENP_F);
|
|
||||||
replaceMap.put("%gendermcolor%", "#" + Settings.HCOLOR_GENP_M);
|
|
||||||
replaceMap.put("%sessionaverage%", FormatUtils.formatTimeAmount(data.getSessionAverage()));
|
replaceMap.put("%sessionaverage%", FormatUtils.formatTimeAmount(data.getSessionAverage()));
|
||||||
replaceMap.put("%geomapcountries%", data.getGeomapCountries());
|
replaceMap.put("%geomapcountries%", data.getGeomapCountries());
|
||||||
replaceMap.put("%geomapz%", data.getGeomapZ());
|
replaceMap.put("%geomapz%", data.getGeomapZ());
|
||||||
|
@ -128,7 +128,7 @@ public class Analysis {
|
|||||||
|
|
||||||
// Analyze & Save RawAnalysisData to AnalysisData
|
// Analyze & Save RawAnalysisData to AnalysisData
|
||||||
createCloroplethMap(analysisData, sorted.getGeolocations(), sorted.getGeocodes());
|
createCloroplethMap(analysisData, sorted.getGeolocations(), sorted.getGeocodes());
|
||||||
createPlayerActivityGraphs(analysisData, sorted.getSessiondata(), sorted.getRegistered());
|
createPlayerActivityGraphs(analysisData, sorted.getSessiondata(), sorted.getRegistered(), sorted.getSortedSessionData());
|
||||||
analysisData.setRecentPlayers(RecentPlayersButtonsCreator.createRecentLoginsButtons(sorted.getLatestLogins(), 20));
|
analysisData.setRecentPlayers(RecentPlayersButtonsCreator.createRecentLoginsButtons(sorted.getLatestLogins(), 20));
|
||||||
long totalPlaytime = sorted.getTotalPlaytime();
|
long totalPlaytime = sorted.getTotalPlaytime();
|
||||||
analysisData.setTotalPlayTime(totalPlaytime);
|
analysisData.setTotalPlayTime(totalPlaytime);
|
||||||
@ -144,7 +144,6 @@ public class Analysis {
|
|||||||
analysisData.setTotalkills(sorted.getTotalKills());
|
analysisData.setTotalkills(sorted.getTotalKills());
|
||||||
analysisData.setTotalmobkills(sorted.getTotalMobKills());
|
analysisData.setTotalmobkills(sorted.getTotalMobKills());
|
||||||
analysisData.setRefreshDate(now);
|
analysisData.setRefreshDate(now);
|
||||||
analysisData.setGenderData(sorted.getGenders());
|
|
||||||
analysisData.setPunchCardData(PunchCardGraphCreator.generateDataArray(sorted.getSessiondata()));
|
analysisData.setPunchCardData(PunchCardGraphCreator.generateDataArray(sorted.getSessiondata()));
|
||||||
analysisData.setSessionDistributionData(SessionLengthDistributionGraphCreator.generateDataArraySessions(sorted.getSessiondata()));
|
analysisData.setSessionDistributionData(SessionLengthDistributionGraphCreator.generateDataArraySessions(sorted.getSessiondata()));
|
||||||
analysisData.setPlaytimeDistributionData(SessionLengthDistributionGraphCreator.generateDataArray(sorted.getPlaytimes().values()));
|
analysisData.setPlaytimeDistributionData(SessionLengthDistributionGraphCreator.generateDataArray(sorted.getPlaytimes().values()));
|
||||||
@ -156,6 +155,7 @@ public class Analysis {
|
|||||||
if (Settings.ANALYSIS_LOG_FINISHED.isTrue()) {
|
if (Settings.ANALYSIS_LOG_FINISHED.isTrue()) {
|
||||||
Log.info(Phrase.ANALYSIS_COMPLETE + "");
|
Log.info(Phrase.ANALYSIS_COMPLETE + "");
|
||||||
}
|
}
|
||||||
|
// LocationAnalysis.performAnalysis(analysisData, plugin.getDB());
|
||||||
if (Settings.ANALYSIS_EXPORT.isTrue()) {
|
if (Settings.ANALYSIS_EXPORT.isTrue()) {
|
||||||
ExportUtility.export(plugin, analysisData, rawData);
|
ExportUtility.export(plugin, analysisData, rawData);
|
||||||
}
|
}
|
||||||
@ -227,25 +227,11 @@ public class Analysis {
|
|||||||
sorted.addTotalDeaths(uData.getDeaths());
|
sorted.addTotalDeaths(uData.getDeaths());
|
||||||
List<SessionData> sessions = uData.getSessions();
|
List<SessionData> sessions = uData.getSessions();
|
||||||
if (!sessions.isEmpty()) {
|
if (!sessions.isEmpty()) {
|
||||||
sorted.getSessiondata().addAll(sessions);
|
sorted.addSessions(uData.getUuid(), sessions);
|
||||||
}
|
}
|
||||||
sorted.getRegistered().add(uData.getRegistered());
|
sorted.getRegistered().add(uData.getRegistered());
|
||||||
sorted.addGeoloc(demData.getGeoLocation());
|
sorted.addGeoloc(demData.getGeoLocation());
|
||||||
uData.stopAccessing();
|
uData.stopAccessing();
|
||||||
Gender gender = demData.getGender();
|
|
||||||
if (null != gender) {
|
|
||||||
switch (gender) {
|
|
||||||
case MALE:
|
|
||||||
sorted.addToGender(0, 1);
|
|
||||||
break;
|
|
||||||
case FEMALE:
|
|
||||||
sorted.addToGender(1, 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sorted.addToGender(2, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
Benchmark.stop("Analysis Fill Dataset");
|
Benchmark.stop("Analysis Fill Dataset");
|
||||||
return sorted;
|
return sorted;
|
||||||
@ -300,7 +286,7 @@ public class Analysis {
|
|||||||
Benchmark.stop("Analysis GMVisualization");
|
Benchmark.stop("Analysis GMVisualization");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPlayerActivityGraphs(AnalysisData data, List<SessionData> sData, List<Long> registered) {
|
private void createPlayerActivityGraphs(AnalysisData data, List<SessionData> sData, List<Long> registered, Map<UUID, List<SessionData>> sortedSData) {
|
||||||
long now = new Date().toInstant().getEpochSecond() * (long) 1000;
|
long now = new Date().toInstant().getEpochSecond() * (long) 1000;
|
||||||
|
|
||||||
long scaleDay = 86400 * 1000;
|
long scaleDay = 86400 * 1000;
|
||||||
@ -312,6 +298,19 @@ public class Analysis {
|
|||||||
data.setNewPlayersWeek(AnalysisUtils.getNewPlayers(registered, scaleWeek, now));
|
data.setNewPlayersWeek(AnalysisUtils.getNewPlayers(registered, scaleWeek, now));
|
||||||
data.setNewPlayersMonth(AnalysisUtils.getNewPlayers(registered, scaleMonth, now));
|
data.setNewPlayersMonth(AnalysisUtils.getNewPlayers(registered, scaleMonth, now));
|
||||||
|
|
||||||
|
Benchmark.start("Analysis Unique/day");
|
||||||
|
data.setAvgUniqJoins(AnalysisUtils.getUniqueJoinsPerDay(sortedSData, -1));
|
||||||
|
data.setAvgUniqJoinsDay(AnalysisUtils.getUniqueJoinsPerDay(sortedSData, scaleDay));
|
||||||
|
data.setAvgUniqJoinsWeek(AnalysisUtils.getUniqueJoinsPerDay(sortedSData, scaleWeek));
|
||||||
|
data.setAvgUniqJoinsMonth(AnalysisUtils.getUniqueJoinsPerDay(sortedSData, scaleMonth));
|
||||||
|
Benchmark.stop("Analysis Unique/day");
|
||||||
|
|
||||||
|
Benchmark.start("Analysis Unique");
|
||||||
|
data.setUniqueJoinsDay(AnalysisUtils.getUniqueJoins(sortedSData, scaleDay));
|
||||||
|
data.setUniqueJoinsWeek(AnalysisUtils.getUniqueJoins(sortedSData, scaleWeek));
|
||||||
|
data.setUniqueJoinsMonth(AnalysisUtils.getUniqueJoins(sortedSData, scaleMonth));
|
||||||
|
Benchmark.stop("Analysis Unique");
|
||||||
|
|
||||||
List<SessionData> sessions = sData.stream()
|
List<SessionData> sessions = sData.stream()
|
||||||
.filter(session -> (session != null))
|
.filter(session -> (session != null))
|
||||||
.filter(session -> session.isValid())
|
.filter(session -> session.isValid())
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
package main.java.com.djrapitops.plan.utilities.analysis;
|
package main.java.com.djrapitops.plan.utilities.analysis;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -11,7 +16,6 @@ import main.java.com.djrapitops.plan.Settings;
|
|||||||
import main.java.com.djrapitops.plan.data.SessionData;
|
import main.java.com.djrapitops.plan.data.SessionData;
|
||||||
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
|
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.additional.PluginData;
|
||||||
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
|
||||||
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
||||||
import main.java.com.djrapitops.plan.utilities.MiscUtils;
|
import main.java.com.djrapitops.plan.utilities.MiscUtils;
|
||||||
|
|
||||||
@ -65,7 +69,6 @@ public class AnalysisUtils {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static int getNewPlayers(List<Long> registered, long scale, long now) {
|
public static int getNewPlayers(List<Long> registered, long scale, long now) {
|
||||||
Benchmark.start("Get new players for "+registered.size()+" "+scale+" | ");
|
|
||||||
int newPlayers = 0;
|
int newPlayers = 0;
|
||||||
if (!registered.isEmpty()) {
|
if (!registered.isEmpty()) {
|
||||||
newPlayers = registered.stream()
|
newPlayers = registered.stream()
|
||||||
@ -74,7 +77,6 @@ public class AnalysisUtils {
|
|||||||
.map((_item) -> 1).reduce(newPlayers, Integer::sum);
|
.map((_item) -> 1).reduce(newPlayers, Integer::sum);
|
||||||
}
|
}
|
||||||
// Filters out register dates before scale
|
// Filters out register dates before scale
|
||||||
Benchmark.stop("Get new players for "+registered.size()+" "+scale+" | ");
|
|
||||||
return newPlayers;
|
return newPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,4 +225,74 @@ public class AnalysisUtils {
|
|||||||
Log.toLog("com.djrapitops.plan.utilities.AnalysisUtils", e);
|
Log.toLog("com.djrapitops.plan.utilities.AnalysisUtils", e);
|
||||||
return source.parseContainer("", "Exception during calculation.");
|
return source.parseContainer("", "Exception during calculation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Integer getUniqueJoins(Map<UUID, List<SessionData>> sessions, long scale) {
|
||||||
|
long now = MiscUtils.getTime();
|
||||||
|
long nowMinusScale = now - scale;
|
||||||
|
Set<UUID> uniqueJoins = new HashSet<>();
|
||||||
|
sessions.keySet().stream().forEach((uuid) -> {
|
||||||
|
List<SessionData> s = sessions.get(uuid);
|
||||||
|
for (SessionData session : s) {
|
||||||
|
if (session.getSessionStart() < nowMinusScale) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uniqueJoins.add(uuid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return uniqueJoins.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getUniqueJoinsPerDay(Map<UUID, List<SessionData>> sessions, long scale) {
|
||||||
|
Map<Integer, Set<UUID>> uniqueJoins = new HashMap<>();
|
||||||
|
long now = MiscUtils.getTime();
|
||||||
|
long nowMinusScale = now - scale;
|
||||||
|
sessions.keySet().stream().forEach((uuid) -> {
|
||||||
|
List<SessionData> s = sessions.get(uuid);
|
||||||
|
for (SessionData session : s) {
|
||||||
|
if (scale != -1) {
|
||||||
|
if (session.getSessionStart() < nowMinusScale) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int day = getDayOfYear(session);
|
||||||
|
if (!uniqueJoins.containsKey(day)) {
|
||||||
|
uniqueJoins.put(day, new HashSet<>());
|
||||||
|
}
|
||||||
|
uniqueJoins.get(day).add(uuid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int total = MathUtils.sumInt(uniqueJoins.values().stream().map(s -> s.size()));
|
||||||
|
int size = uniqueJoins.keySet().size();
|
||||||
|
if (size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return total / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<int[]> getDaysAndHours(List<Long> sessionStarts) {
|
||||||
|
List<int[]> daysAndHours = sessionStarts.stream().map((Long start) -> {
|
||||||
|
Calendar day = Calendar.getInstance();
|
||||||
|
day.setTimeInMillis(start);
|
||||||
|
int hourOfDay = day.get(Calendar.HOUR_OF_DAY);
|
||||||
|
int dayOfWeek = day.get(Calendar.DAY_OF_WEEK) - 2;
|
||||||
|
if (hourOfDay == 24) {
|
||||||
|
hourOfDay = 0;
|
||||||
|
dayOfWeek += 1;
|
||||||
|
}
|
||||||
|
if (dayOfWeek > 6) {
|
||||||
|
dayOfWeek = 0;
|
||||||
|
}
|
||||||
|
if (dayOfWeek < 0) {
|
||||||
|
dayOfWeek = 6;
|
||||||
|
}
|
||||||
|
return new int[]{dayOfWeek, hourOfDay};
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
return daysAndHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getDayOfYear(SessionData session) {
|
||||||
|
Calendar day = Calendar.getInstance();
|
||||||
|
day.setTimeInMillis(session.getSessionStart());
|
||||||
|
return day.get(Calendar.DAY_OF_YEAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
package main.java.com.djrapitops.plan.utilities.analysis.locations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import main.java.com.djrapitops.plan.Log;
|
||||||
|
import main.java.com.djrapitops.plan.data.AnalysisData;
|
||||||
|
import main.java.com.djrapitops.plan.database.Database;
|
||||||
|
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
||||||
|
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
|
||||||
|
import static org.bukkit.Bukkit.getWorlds;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public class LocationAnalysis {
|
||||||
|
|
||||||
|
public static void performAnalysis(AnalysisData data, Database db) {
|
||||||
|
Benchmark.start("Location Analysis");
|
||||||
|
try {
|
||||||
|
Map<Integer, List<Location>> playerLocations = db.getLocationsTable().getAllLocations(getWorlds().stream().collect(Collectors.toMap(w -> w.getName(), Function.identity())));
|
||||||
|
List<Location> locations = new ArrayList<>();
|
||||||
|
for (Integer id : playerLocations.keySet()) {
|
||||||
|
locations.addAll(playerLocations.get(id));
|
||||||
|
}
|
||||||
|
Map<String, Map<Point, Integer>> worldPoints = getWorldPoints(locations);
|
||||||
|
for (String world : worldPoints.keySet()) {
|
||||||
|
Map<Point, Integer> worldLocs = worldPoints.get(world);
|
||||||
|
Set<Point> frequentPoints = getFrequentPoints(worldLocs);
|
||||||
|
Log.debug(frequentPoints.toString());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.toLog("LocationAnalysis.performAnalysis", ex);
|
||||||
|
}
|
||||||
|
Benchmark.stop("Location Analysis");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Point, Object> cluster(Collection<Point> freqPoints, Collection<Point> allPoints) {
|
||||||
|
Benchmark.start("LocAnalysis cluster");
|
||||||
|
allPoints.removeAll(freqPoints);
|
||||||
|
for (Point point : freqPoints) {
|
||||||
|
Set<Point> cluster = allPoints.stream().filter(p -> distance(point, p) < 5).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
Benchmark.stop("LocAnalysis cluster");
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<Point> getFrequentPoints(Map<Point, Integer> points) {
|
||||||
|
Benchmark.start("LocAnalysis getFrequentPoints");
|
||||||
|
if (points.isEmpty()) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
double averageFreq = MathUtils.averageInt(points.values().stream());
|
||||||
|
Set<Point> freqPoints = points.entrySet().stream().filter(e -> e.getValue() > averageFreq).map(e -> e.getKey()).collect(Collectors.toSet());
|
||||||
|
Benchmark.stop("LocAnalysis getFrequentPoints");
|
||||||
|
return freqPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Map<Point, Integer>> getWorldPoints(Collection<Location> locations) {
|
||||||
|
Benchmark.start("LocAnalysis getWorldPoints");
|
||||||
|
Map<String, Map<Point, Integer>> pointMap = new HashMap<>();
|
||||||
|
for (Location location : locations) {
|
||||||
|
World world = location.getWorld();
|
||||||
|
if (world == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String worldName = world.getName();
|
||||||
|
if (!pointMap.containsKey(worldName)) {
|
||||||
|
pointMap.put(worldName, new HashMap<>());
|
||||||
|
}
|
||||||
|
Map<Point, Integer> numOfLocs = pointMap.get(worldName);
|
||||||
|
Point point = new Point(location.getBlockX(), location.getBlockZ());
|
||||||
|
if (!numOfLocs.containsKey(point)) {
|
||||||
|
numOfLocs.put(point, 0);
|
||||||
|
}
|
||||||
|
numOfLocs.replace(point, numOfLocs.get(point) + 1);
|
||||||
|
}
|
||||||
|
Benchmark.stop("LocAnalysis getWorldPoints");
|
||||||
|
return pointMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double distance(Point one, Point two) {
|
||||||
|
return Math.hypot(one.getX() - two.getX(), one.getY() - one.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.utilities.analysis.locations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Risto
|
||||||
|
*/
|
||||||
|
public class Point {
|
||||||
|
|
||||||
|
final private int x;
|
||||||
|
final private int y;
|
||||||
|
|
||||||
|
public Point(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 3;
|
||||||
|
hash = 97 * hash + this.x;
|
||||||
|
hash = 97 * hash + this.y;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Point other = (Point) obj;
|
||||||
|
if (this.x != other.x) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.y != other.y) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "P[x:" + x + "|y:" + y + ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -336,7 +336,8 @@ header p {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="playerChartDay" width="1000" height="350" style="width: 95%;"></canvas><br/>
|
<canvas id="playerChartDay" width="1000" height="350" style="width: 95%;"></canvas>
|
||||||
|
<p><i class="fa fa-user-circle" aria-hidden="true"></i> Unique Players: %uniquejoinsday% | <i class="fa fa-user-circle-o" aria-hidden="true"></i> Unique/Day: %avguniquejoinsday%</p>
|
||||||
</div>
|
</div>
|
||||||
<div class=" box column" style="order: 5;">
|
<div class=" box column" style="order: 5;">
|
||||||
<p class="header-label" style="color: #267F00; "><i class="fa fa-calendar-check-o" aria-hidden="true"></i><span class="header-text"> Recent Logins</span></p>
|
<p class="header-label" style="color: #267F00; "><i class="fa fa-calendar-check-o" aria-hidden="true"></i><span class="header-text"> Recent Logins</span></p>
|
||||||
@ -368,6 +369,7 @@ header p {
|
|||||||
<p><i class="fa fa-clock-o" aria-hidden="true"></i> Total Playtime: %totalplaytime% | <i class="fa fa-clock-o" aria-hidden="true"></i> Player Average: %avgplaytime%<br/>
|
<p><i class="fa fa-clock-o" aria-hidden="true"></i> Total Playtime: %totalplaytime% | <i class="fa fa-clock-o" aria-hidden="true"></i> Player Average: %avgplaytime%<br/>
|
||||||
<i class="fa fa-clock-o" aria-hidden="true"></i> Average Session Length: %sessionaverage%<br/>
|
<i class="fa fa-clock-o" aria-hidden="true"></i> Average Session Length: %sessionaverage%<br/>
|
||||||
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i> Total Login times: %totallogins%<br/>
|
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i> Total Login times: %totallogins%<br/>
|
||||||
|
<i class="fa fa-user-circle-o" aria-hidden="true"></i> Average Unique Players/Day: %avguniquejoins%<br>
|
||||||
<b><i class="fa fa-crosshairs" aria-hidden="true"></i></b> Player kills: %playerkills% | <i class="fa fa-crosshairs" aria-hidden="true"></i> Mob kills: %mobkills% | <i class="fa fa-meh-o" aria-hidden="true"></i> Deaths: %deaths%</p>
|
<b><i class="fa fa-crosshairs" aria-hidden="true"></i></b> Player kills: %playerkills% | <i class="fa fa-crosshairs" aria-hidden="true"></i> Mob kills: %mobkills% | <i class="fa fa-meh-o" aria-hidden="true"></i> Deaths: %deaths%</p>
|
||||||
</div>
|
</div>
|
||||||
<div class=" box column">
|
<div class=" box column">
|
||||||
@ -452,6 +454,7 @@ header p {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="playerChartDay2" width="1000" height="350" style="width: 95%;"></canvas>
|
<canvas id="playerChartDay2" width="1000" height="350" style="width: 95%;"></canvas>
|
||||||
|
<p><i class="fa fa-user-circle" aria-hidden="true"></i> Unique Players: %uniquejoinsday% | <i class="fa fa-user-circle-o" aria-hidden="true"></i> Unique/Day: %avguniquejoinsday%</p>
|
||||||
</div>
|
</div>
|
||||||
<div class=" box column">
|
<div class=" box column">
|
||||||
<div class="headerbox">
|
<div class="headerbox">
|
||||||
@ -473,6 +476,7 @@ header p {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
|
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
|
||||||
|
<p><i class="fa fa-user-circle" aria-hidden="true"></i> Unique Players: %uniquejoinsweek% | <i class="fa fa-user-circle-o" aria-hidden="true"></i> Unique/Day: %avguniquejoinsweek%</p>
|
||||||
</div>
|
</div>
|
||||||
<div class=" box column">
|
<div class=" box column">
|
||||||
<div class="headerbox">
|
<div class="headerbox">
|
||||||
@ -494,6 +498,7 @@ header p {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="playerChartMonth" width="1000" height="350" style="width: 95%;"></canvas>
|
<canvas id="playerChartMonth" width="1000" height="350" style="width: 95%;"></canvas>
|
||||||
|
<p><i class="fa fa-user-circle" aria-hidden="true"></i> Unique Playes: %uniquejoinsmonth% | <i class="fa fa-user-circle-o" aria-hidden="true"></i> Unique/Day: %avguniquejoinsmonth%</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -585,7 +590,7 @@ header p {
|
|||||||
<div class=" box column">
|
<div class=" box column">
|
||||||
<div class="headerbox">
|
<div class="headerbox">
|
||||||
<div class="header-icon" style="width: 50%">
|
<div class="header-icon" style="width: 50%">
|
||||||
<div class="header-label"><i class="fa fa-braille" aria-hidden="true"></i><span class="header-text"> PunchCard</span></div>
|
<div class="header-label"><i class="fa fa-braille" aria-hidden="true"></i><span class="header-text"> PunchCard - Last 30d</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="infobox" >
|
<div class="infobox" >
|
||||||
<div class="info-icon">
|
<div class="info-icon">
|
||||||
@ -730,7 +735,7 @@ header p {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
<div class="row">
|
<div class="row" style="width: 100%;">
|
||||||
<div class=" box column">
|
<div class=" box column">
|
||||||
<div class="headerbox">
|
<div class="headerbox">
|
||||||
<div class="header-icon">
|
<div class="header-icon">
|
||||||
@ -753,42 +758,6 @@ header p {
|
|||||||
<div style="width:100%;"><div id="cloropleth"></div></div>
|
<div style="width:100%;"><div id="cloropleth"></div></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class=" box column">
|
|
||||||
<div class="headerbox">
|
|
||||||
<div class="header-icon">
|
|
||||||
<div class="header-label"><i class="fa fa-male" aria-hidden="true"></i><i class="fa fa-female" aria-hidden="true"></i><span class="header-text"> Gender Distribution</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="infobox" style="width: 22%; background-color: %genderfcolor%">
|
|
||||||
<div class="info-icon">
|
|
||||||
<i class="fa fa-female" aria-hidden="true"></i>
|
|
||||||
</div>
|
|
||||||
<div class="info-text">
|
|
||||||
<div class="info-number">
|
|
||||||
%genderfemale%
|
|
||||||
</div>
|
|
||||||
<div class="info-label">
|
|
||||||
Female
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="infobox" style="width: 22%; background-color: %gendermcolor%">
|
|
||||||
<div class="info-icon">
|
|
||||||
<i class="fa fa-male" aria-hidden="true"></i>
|
|
||||||
</div>
|
|
||||||
<div class="info-text">
|
|
||||||
<div class="info-number">
|
|
||||||
%gendermale%
|
|
||||||
</div>
|
|
||||||
<div class="info-label">
|
|
||||||
Male
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<canvas id="genderPie" width="1000" height="600" style="width: 95%;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tab" style="display: block;">
|
<div class="tab" style="display: block;">
|
||||||
%plugins%
|
%plugins%
|
||||||
@ -932,7 +901,6 @@ function countUpTimer() {
|
|||||||
var ctxmonth = document.getElementById("playerChartMonth");
|
var ctxmonth = document.getElementById("playerChartMonth");
|
||||||
var ctxactivitypie = document.getElementById("activityPie");
|
var ctxactivitypie = document.getElementById("activityPie");
|
||||||
var ctxgmpie = document.getElementById("gmPie");
|
var ctxgmpie = document.getElementById("gmPie");
|
||||||
var ctxgenderpie = document.getElementById("genderPie");
|
|
||||||
var dataday = {
|
var dataday = {
|
||||||
labels: %labelsday%,
|
labels: %labelsday%,
|
||||||
datasets: [
|
datasets: [
|
||||||
@ -1055,28 +1023,6 @@ function countUpTimer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var dataGenderPie = {
|
|
||||||
labels: %genderlabels%,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: %genderdata%,
|
|
||||||
backgroundColor: [%gendercolors%],
|
|
||||||
hoverBackgroundColor: [%gendercolors%]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
var GenderPie = new Chart(ctxgenderpie, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: dataGenderPie,
|
|
||||||
options: {
|
|
||||||
legend: {
|
|
||||||
position: 'right',
|
|
||||||
labels: {
|
|
||||||
padding: 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var playersChartDay = new Chart(ctxday, {
|
var playersChartDay = new Chart(ctxday, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: dataday,
|
data: dataday,
|
||||||
|
@ -8,6 +8,7 @@ Settings:
|
|||||||
LogProgressOnConsole: false
|
LogProgressOnConsole: false
|
||||||
NotifyWhenFinished: true
|
NotifyWhenFinished: true
|
||||||
MinutesPlayedUntilConsidiredActive: 10
|
MinutesPlayedUntilConsidiredActive: 10
|
||||||
|
RemoveOutliersFromVisualization: true
|
||||||
Export:
|
Export:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
DestinationFolder: 'Analysis Results'
|
DestinationFolder: 'Analysis Results'
|
||||||
@ -69,10 +70,6 @@ Customization:
|
|||||||
Banned: '951800'
|
Banned: '951800'
|
||||||
Inactive: 'A9A9A9'
|
Inactive: 'A9A9A9'
|
||||||
JoinedOnce: '808080'
|
JoinedOnce: '808080'
|
||||||
GenderPie:
|
|
||||||
Female: ED97E3
|
|
||||||
Male: 7CB9D6
|
|
||||||
Unknown: A9A9A9
|
|
||||||
DemographicsTriggers:
|
DemographicsTriggers:
|
||||||
Trigger: "i'm, am, im, bin"
|
Trigger: "i'm, am, im, bin"
|
||||||
Female: 'female, girl, gurl, woman, gal, mrs, she, miss, feminin, weiblich, mädchen, frau'
|
Female: 'female, girl, gurl, woman, gal, mrs, she, miss, feminin, weiblich, mädchen, frau'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: Plan
|
name: Plan
|
||||||
author: Rsl1122
|
author: Rsl1122
|
||||||
main: main.java.com.djrapitops.plan.Plan
|
main: main.java.com.djrapitops.plan.Plan
|
||||||
version: 3.3.0
|
version: 3.4.0
|
||||||
|
|
||||||
softdepend:
|
softdepend:
|
||||||
- OnTime
|
- OnTime
|
||||||
|
Loading…
Reference in New Issue
Block a user