[3.2.1] Merge pull request #97 from Rsl1122/3.2.1

Pull Request for 3.2.1
This commit is contained in:
Rsl1122 2017-05-28 13:46:41 +03:00 committed by GitHub
commit 1cfb86c293
14 changed files with 635 additions and 176 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.djrapitops</groupId>
<artifactId>Plan</artifactId>
<version>3.2.0</version>
<version>3.2.1</version>
<packaging>jar</packaging>
<repositories>
<!-- <repository>
@ -47,12 +47,24 @@
<version>2.10.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.gamingmesh</groupId>
<artifactId>jobs</artifactId>
<version>3.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.massivecraft</groupId>
<artifactId>mcore</artifactId>
<version>2.10.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.gmail.nossr50</groupId>
<artifactId>mcmmo</artifactId>
<version>1.5.07</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.palmergames</groupId>
<artifactId>towny</artifactId>

View File

@ -11,6 +11,8 @@ import java.util.UUID;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.data.additional.factions.FactionsHook;
import main.java.com.djrapitops.plan.data.additional.jobs.JobsHook;
import main.java.com.djrapitops.plan.data.additional.mcmmo.McmmoHook;
import main.java.com.djrapitops.plan.data.additional.ontime.OnTimeHook;
import main.java.com.djrapitops.plan.data.additional.towny.TownyHook;
import main.java.com.djrapitops.plan.data.additional.vault.VaultHook;
@ -72,6 +74,14 @@ public class HookHandler {
FactionsHook factionsHook = new FactionsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
McmmoHook mcMmoHook = new McmmoHook(this);
} catch (NoClassDefFoundError e) {
}
try {
JobsHook jobsHook = new JobsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
OnTimeHook onTimeHook = new OnTimeHook(this);
} catch (NoClassDefFoundError e) {
@ -177,7 +187,14 @@ public class HookHandler {
if (source.analysisOnly()) {
continue;
}
addReplace.put(source.getPlaceholder(""), source.getHtmlReplaceValue("", uuid));
try {
addReplace.put(source.getPlaceholder(""), source.getHtmlReplaceValue("", uuid));
} catch (Exception e) {
addReplace.put(source.getPlaceholder(""), "Error occurred: " + e);
Log.error("PluginDataSource caused an exception: " + source.getSourcePlugin());
Log.toLog("PluginDataSource caused an exception: " + source.getSourcePlugin());
Log.toLog(this.getClass().getName(), e);
}
}
return addReplace;
}

View File

@ -0,0 +1,90 @@
package main.java.com.djrapitops.plan.data.additional.jobs;
import com.gamingmesh.jobs.Jobs;
import com.gamingmesh.jobs.PlayerManager;
import com.gamingmesh.jobs.container.Job;
import com.gamingmesh.jobs.container.JobProgression;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.ui.Html;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MathUtils;
import static org.bukkit.Bukkit.getOfflinePlayers;
/**
* PluginData class for Jobs-plugin.
*
* Registered to the plugin by JobsHook
*
* @author Rsl1122
* @since 3.2.1
* @see JobsHook
*/
public class JobsAnalysisJobTable extends PluginData {
public JobsAnalysisJobTable() {
super("Jobs", "analysistable", AnalysisType.HTML);
final String job = Html.FONT_AWESOME_ICON.parse("suitcase") + " Job";
final String workers = Html.FONT_AWESOME_ICON.parse("users") + " Workers";
final String tLevel = Html.FONT_AWESOME_ICON.parse("plus") + " Total Level";
final String aLevel = Html.FONT_AWESOME_ICON.parse("plus") + " Avg Level";
super.setPrefix(Html.TABLE_START_4.parse(job, workers, aLevel, tLevel));
super.setSuffix(Html.TABLE_END.parse());
}
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
PlayerManager pm = Jobs.getPlayerManager();
List<List<JobProgression>> players = Arrays.stream(getOfflinePlayers())
.filter(p -> p != null)
.map(p -> pm.getPlayerInfo(p.getUniqueId()))
.filter(i -> i != null)
.map(i -> pm.getJobsPlayerOffline(i))
.map(p -> p.getJobProgression())
.filter(list -> !list.isEmpty())
.collect(Collectors.toList());
if (players.isEmpty()) {
return parseContainer("", Html.TABLELINE_4.parse("No Players with Jobs", "", "", ""));
}
Map<String, Integer> workers = new HashMap<>();
Map<String, Long> totals = new HashMap<>();
for (List<JobProgression> jobs : players) {
for (JobProgression job : jobs) {
String name = job.getJob().getName();
int level = job.getLevel();
if (!workers.containsKey(name)) {
workers.put(name, 0);
}
workers.put(name, workers.get(name) + 1);
if (!totals.containsKey(name)) {
totals.put(name, 0L);
}
totals.put(name, totals.get(name) + level);
}
}
StringBuilder html = new StringBuilder();
for (String job : workers.keySet()) {
Integer amountOfWorkers = workers.get(job);
Long totalLevel = totals.get(job);
html.append(Html.TABLELINE_4.parse(
job,
"" + amountOfWorkers,
FormatUtils.cutDecimals(MathUtils.average((int) (long) totalLevel, amountOfWorkers)),
"" + totalLevel)
);
}
return parseContainer("", html.toString());
}
@Override
public Serializable getValue(UUID uuid) {
return -1;
}
}

View File

@ -0,0 +1,31 @@
package main.java.com.djrapitops.plan.data.additional.jobs;
import main.java.com.djrapitops.plan.data.additional.Hook;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.mcmmo.McmmoAnalysisSkillTable;
/**
* A Class responsible for hooking to Jobs and registering data sources.
*
* @author Rsl1122
* @since 3.2.1
*/
public class JobsHook extends Hook {
/**
* Hooks the plugin and registers it's PluginData objects.
*
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @see API
*/
public JobsHook(HookHandler hookH) {
super("com.gamingmesh.jobs.Jobs");
if (enabled) {
hookH.addPluginDataSource(new JobsInspectJobTable());
hookH.addPluginDataSource(new JobsAnalysisJobTable());
}
}
}

View File

@ -0,0 +1,54 @@
package main.java.com.djrapitops.plan.data.additional.jobs;
import com.gamingmesh.jobs.Jobs;
import com.gamingmesh.jobs.PlayerManager;
import com.gamingmesh.jobs.container.JobProgression;
import com.gamingmesh.jobs.container.JobsPlayer;
import com.gamingmesh.jobs.container.PlayerInfo;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.ui.Html;
/**
* PluginData class for Jobs-plugin.
*
* Registered to the plugin by JobsHook
*
* @author Rsl1122
* @since 3.2.1
* @see JobsHook
*/
public class JobsInspectJobTable extends PluginData {
public JobsInspectJobTable() {
super("Jobs", "inspecttable");
super.setAnalysisOnly(false);
final String job = Html.FONT_AWESOME_ICON.parse("suitcase") + " Job";
final String level = Html.FONT_AWESOME_ICON.parse("plus") + " Level";
super.setPrefix(Html.TABLE_START_2.parse(job, level));
super.setSuffix(Html.TABLE_END.parse());
}
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
PlayerManager pm = Jobs.getPlayerManager();
PlayerInfo info = pm.getPlayerInfo(uuid);
JobsPlayer player = pm.getJobsPlayerOffline(info);
List<JobProgression> progression = player.getJobProgression();
if (progression.isEmpty()) {
return parseContainer("", Html.TABLELINE_2.parse("No Jobs.", ""));
}
StringBuilder html = new StringBuilder();
for (JobProgression job : progression) {
html.append(Html.TABLELINE_2.parse(job.getJob().getName(), "" + job.getLevel()));
}
return parseContainer("", html.toString());
}
@Override
public Serializable getValue(UUID uuid) {
return -1;
}
}

View File

@ -0,0 +1,68 @@
package main.java.com.djrapitops.plan.data.additional.mcmmo;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.util.player.UserManager;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.ui.Html;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.MathUtils;
import org.apache.commons.lang.StringUtils;
import static org.bukkit.Bukkit.getOfflinePlayers;
/**
* PluginData class for McMMO-plugin.
*
* Registered to the plugin by McmmoHook
*
* @author Rsl1122
* @since 3.2.1
* @see McmmoHook
*/
public class McmmoAnalysisSkillTable extends PluginData {
public McmmoAnalysisSkillTable() {
super("McMMO", "analysistable", AnalysisType.HTML);
final String skill = Html.FONT_AWESOME_ICON.parse("star") + " Skill";
final String tLevel = Html.FONT_AWESOME_ICON.parse("plus") + " Total Level";
final String aLevel = Html.FONT_AWESOME_ICON.parse("plus") + " Average Level";
final String notice = "Only online players shown. " + Html.LINK_EXTERNAL.parse("https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/java/com/gmail/nossr50/util/player/UserManager.java#L105", "More info") + "<br>";
super.setPrefix(notice + Html.TABLE_START_3.parse(skill, tLevel, aLevel));
super.setSuffix(Html.TABLE_END.parse());
}
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
List<PlayerProfile> profiles = Arrays.stream(getOfflinePlayers())
.filter(p -> p != null)
.map(p -> UserManager.getOfflinePlayer(p))
.filter(u -> u != null)
.map(u -> u.getProfile())
.collect(Collectors.toList());
if (profiles.isEmpty()) {
return parseContainer("", Html.TABLELINE_3.parse("No players online", "", ""));
}
final List<SkillType> skills = new ArrayList<>();
skills.addAll(Arrays.stream(SkillType.values()).distinct().collect(Collectors.toList()));
final StringBuilder html = new StringBuilder();
for (SkillType skill : skills) {
long total = MathUtils.sumInt(profiles.stream().map(p -> (Serializable) p.getSkillLevel(skill)));
html.append(Html.TABLELINE_3.parse(StringUtils.capitalize(skill.getName().toLowerCase()), "" + total, FormatUtils.cutDecimals(MathUtils.average((int) total, profiles.size()))));
}
return parseContainer("", html.toString());
}
@Override
public Serializable getValue(UUID uuid) {
return -1;
}
}

View File

@ -0,0 +1,30 @@
package main.java.com.djrapitops.plan.data.additional.mcmmo;
import main.java.com.djrapitops.plan.data.additional.Hook;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
/**
* A Class responsible for hooking to MCMMO and registering data sources.
*
* @author Rsl1122
* @since 3.2.1
*/
public class McmmoHook extends Hook {
/**
* Hooks the plugin and registers it's PluginData objects.
*
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @see API
*/
public McmmoHook(HookHandler hookH) {
super("com.gmail.nossr50.mcMMO");
if (enabled) {
hookH.addPluginDataSource(new McmmoInspectSkillTable());
hookH.addPluginDataSource(new McmmoAnalysisSkillTable());
}
}
}

View File

@ -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.data.additional.mcmmo;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.util.player.UserManager;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.ui.Html;
import org.apache.commons.lang.StringUtils;
import static org.bukkit.Bukkit.getOfflinePlayer;
/**
* PluginData class for McMMO-plugin.
*
* Registered to the plugin by McmmoHook
*
* @author Rsl1122
* @since 3.2.1
* @see McmmoHook
*/
public class McmmoInspectSkillTable extends PluginData {
public McmmoInspectSkillTable() {
super("McMMO", "inspectskilltable");
super.setAnalysisOnly(false);
final String skill = Html.FONT_AWESOME_ICON.parse("star") + " Skill";
final String level = Html.FONT_AWESOME_ICON.parse("plus") + " Level";
final String notice = "Only online players shown. " + Html.LINK_EXTERNAL.parse("https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/java/com/gmail/nossr50/util/player/UserManager.java#L105", "More info") + "<br>";
super.setPrefix(notice + Html.TABLE_START_2.parse(skill, level));
super.setSuffix(Html.TABLE_END.parse());
}
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
McMMOPlayer user = UserManager.getOfflinePlayer(getOfflinePlayer(uuid));
if (user == null) {
return parseContainer("", Html.TABLELINE_2.parse("User not known/online", ""));
}
final PlayerProfile skillProfile = user.getProfile();
final List<SkillType> skills = new ArrayList<>();
skills.addAll(Arrays.stream(SkillType.values()).distinct().collect(Collectors.toList()));
final StringBuilder html = new StringBuilder();
for (SkillType skill : skills) {
html.append(Html.TABLELINE_2.parse(StringUtils.capitalize(skill.getName().toLowerCase()), "" + skillProfile.getSkillLevel(skill)));
}
return parseContainer("", html.toString());
}
@Override
public Serializable getValue(UUID uuid) {
return -1;
}
}

View File

@ -39,6 +39,7 @@ public enum Html {
BUTTON("<a class=\"button\" href=\"" + REPLACE0 + "\">" + REPLACE1 + "</a>"),
BUTTON_CLASS("class=\"button\""),
LINK("<a class=\"link\" href=\"" + REPLACE0 + "\">" + REPLACE1 + "</a>"),
LINK_EXTERNAL("<a class=\"link\" target=\"_blank\" href=\"" + REPLACE0 + "\">" + REPLACE1 + "</a>"),
LINK_CLASS("class=\"link\""),
IMG("<img src=\"" + REPLACE0 + "\">"),
COLUMNS_DIV_WRAPPER("<div class=\"columns\">" + REPLACE0 + "</div>"),

View File

@ -122,7 +122,6 @@ public class PunchCardGraphCreator {
int[][] scaled = new int[7][24];
for (int i = 0; i < 7; i++) {
Log.debug("Scaling: " + Arrays.toString(dataArray[i]) + " | " + big);
for (int j = 0; j < 24; j++) {
int value = (int) ((dataArray[i][j] * 10.0) / big);
if (value != 0) {
@ -130,7 +129,6 @@ public class PunchCardGraphCreator {
}
scaled[i][j] = value;
}
Log.debug(" Scaled: " + Arrays.toString(scaled[i]));
}
return scaled;

View File

@ -4,6 +4,7 @@
<title>Plan | Server Analysis</title>
<meta name="description" content="Player Analysis window">
<meta name="author" content="Rsl1122">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="https://puu.sh/tK0KL/6aa2ba141b.ico" type="image/x-icon" />
<script src="https://use.fontawesome.com/df48eb908b.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
@ -13,7 +14,7 @@ header {
top: 0;
left: 0;
width: 100%;
height: 10%;
height: 88px;
padding: 0px;
background-color: #348e0f;
z-index: 1;
@ -35,7 +36,7 @@ body {
background-color: #5cb239;
overflow-x: hidden;
transition: 0.5s;
padding-top: 5.4%;
padding-top: 88px;
text-align: left;
}
.sidenav p {
@ -76,7 +77,7 @@ body {
}
.main-wrapper {
margin-top: 5.5%;
margin-top: 88px;
transform: translate3d(0, 0, 0);
opacity: 0;
transition: 1.5s;
@ -87,22 +88,31 @@ body {
padding: 5px;
text-decoration: none;!important;
color: #000
width: 100%;
text-align: left;
margin: 5px;
padding: 5px;
}
.box p {
color: #000;
}
.tab {
width: 20%;
height: 100%;
float: left;
display: flex;
text-align: left;
align-content: flex-start;
}
.content {
text-align: center;
padding: 5px;
margin: 0px;
text-align: center;
padding: 5px;
margin: 0px;
}
.row {
width: 50%;
display: flex;
flex-direction: column;
}
.columns {
display: flex;
@ -110,22 +120,9 @@ body {
.column {
flex: 1;
}
.column-one {
order: 1;
}
.column-two {
order: 2;
}
.column-three {
order: 3;
}
.about {
text-align: left;
margin: 5px;
padding: 5px;
}
.box-area {
width: 100%;
display: flex;
}
.infobox {
margin-left: 3px;
@ -225,19 +222,74 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
.plugin-data {
color: #000;
}
header img {
float: right;
padding: 5px;
display: inline;
}
header p {
float: right;
text-align: right;
}
#navbutton {
display: none;
font-size: 40px;
cursor:pointer;
}
@media only screen and (max-width: 850px) {
#navbutton {
display: inline;
}
.sidenav p {
display: none;
}
header {
margin: 0px;
padding 0px;
}
header h1 {
margin: 0px;
}
header img {
margin: 0px;
padding: 0px;
margin-right: 0px;
}
header p {
margin: 0px;
margin-top: 5px;
}
.tab {
flex-direction: column;
}
.columns {
flex-direction: column;
}
.row {
width: 100%;
}
.sidenav {
width: 0%;
transition: 0s;
}
.main-limiter {
margin-left: 0%;
width: 100%;
}
}
</style>
</head>
<body>
<header>
<div class="header-content">
<img style="float: right; padding: 5px" src="http://puu.sh/tJZUb/c2e0ab220f.png" alt="Player Analytics | Analysis">
<p style="float: right; text-align: right;">Player Analytics v.%version%</p>
<h1>Plan | Server Analysis</h1>
<img src="http://puu.sh/tJZUb/c2e0ab220f.png" alt="Player Analytics | Analysis">
<p>Player Analytics v.%version%</p>
<h1><span id="navbutton" onclick="openNav()">&#9776; </span>Plan | Server Analysis</h1>
</div>
</header>
<div id="content" class="content">
<div class="sidenav">
<div id="sidenav" class="sidenav">
<p>Last Refresh: <br>%refresh% ago</p>
<a href="javascript:void(0)" class="nav-button">
<i class="fa fa-info-circle" aria-hidden="true"></i> Information
@ -261,11 +313,11 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
<i class="fa fa-cubes" aria-hidden="true"></i> Plugins
</a>
</div>
<div class="main-limiter">
<div id="limiter" class="main-limiter">
<div id="main" class="main-wrapper">
<div class="tab">
<div class="columns">
<div class="about box column">
<div class="row">
<div class="box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity - Last 24h</span></div>
@ -284,8 +336,17 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
<canvas id="playerChartDay" width="1000" height="350" style="width: 95%;"></canvas><br/>
</div>
<div class="about box column">
<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>
<div class="buttons">
%recentlogins%
</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-info-circle" aria-hidden="true"></i><span class="header-text"> Information</span></div>
@ -304,17 +365,12 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<canvas id="playerChartDay" width="1000" height="350" style="width: 95%;"></canvas><br/>
</div>
<div class="about box column">
<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-calendar-plus-o" aria-hidden="true"></i> Total Login times: %totallogins%<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>
</div>
<div class=" box column">
<p class="header-label" style="color: #267F00; "><i class="fa fa-pie-chart" aria-hidden="true"></i><span class="header-text"> Gamemode Usage</span></p><br/>
<div class="box-area">
<div class="infobox" style="background-color: #%gm0col%; width: 20%;">
@ -370,23 +426,13 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<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>
<div class="buttons">
%recentlogins%
</div>
</div>
<div class="about box column">
<canvas id="gmPie" width="1000" height="600" style="width: 95%;"></canvas>
</div>
</div>
</div>
<div class="tab">
<div class="columns">
<div class="about box column">
<div class="row">
<div class=" box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity - Last 24h</span></div>
@ -406,6 +452,8 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
<canvas id="playerChartDay2" width="1000" height="350" style="width: 95%;"></canvas>
</div>
<div class=" box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity - Last 7d</span></div>
@ -425,6 +473,8 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
</div>
<div class=" box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity - Last 30d</span></div>
@ -445,7 +495,9 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
<canvas id="playerChartMonth" width="1000" height="350" style="width: 95%;"></canvas>
</div>
<div class="about box column">
</div>
<div class="row">
<div class="box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-pie-chart" aria-hidden="true"></i><span class="header-text"> Playerbase Composition</span></div>
@ -519,6 +571,8 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div><br><br>
<canvas id="activityPie" width="1000" height="600" style="width: 95%;"></canvas><br>
</div>
<div class=" box column">
<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>
<div class="buttons">
%recentlogins%
@ -526,9 +580,9 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
<div class="tab">
<div class="columns">
<div class="about box column">
<div class="tab">
<div class="row">
<div class=" box column">
<div class="headerbox">
<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>
@ -547,8 +601,11 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
<canvas id="punchcard" width="1000" height="600" style="width: 95%;"></canvas>
</div>
<div class="about box column">
</div>
<div class="row">
<div class=" box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Length Distribution</span></div>
@ -567,18 +624,11 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<canvas id="punchcard" width="1000" height="600" style="width: 95%;"></canvas>
</div>
<div class="about box column">
<canvas id="sessiondistribution" width="1000" height="600" style="width: 95%;"></canvas>
</div>
</div>
<!--<div class="columns">
<div class="about box column">
<div class=" box column">
<div class="headerbox">
<div class="header-icon" style="width: 50%">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Playtime Distribution</span></div>
@ -599,14 +649,14 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
<canvas id="playdistribution" width="1000" height="600" style="width: 95%;"></canvas>
</div>
<div class="about box column">
<div class=" box column">
</div>
</div>-->
</div>
<div class="tab">
<div class="columns">
<div class="about box column">
<div class="row" style="width: 100%;">
<div class="box column">
<div class="headerbox" style="width: 97%;">
<div class="header-icon">
<div class="header-label"><i class="fa fa-list-alt" aria-hidden="true"></i><span class="header-text"> Playerlist</span></div>
@ -625,10 +675,6 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<table class="sortable table">
<thead>
<tr>
@ -649,8 +695,8 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
<div class="tab">
<div class="columns">
<div class="about box column">
<div class="row" style="width: 100%;">
<div class=" box column">
<div class="headerbox" style="width: 97%;">
<div class="header-icon">
<div class="header-label"><i class="fa fa-terminal" aria-hidden="true"></i><span class="header-text"> Command usage</span></div>
@ -669,10 +715,6 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<table class="sortable table">
<thead>
<tr>
@ -688,8 +730,8 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
<div class="tab">
<div class="columns">
<div class="about box column">
<div class="row">
<div class=" box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-globe" aria-hidden="true"></i><span class="header-text"> Geolocations</span></div>
@ -708,8 +750,11 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
<div class="about box column">
<div style="width:100%;"><div id="cloropleth"></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>
@ -741,23 +786,26 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<div style="width:100%;"><div id="cloropleth"></div></div>
</div>
<div class="about box column">
<canvas id="genderPie" width="1000" height="600" style="width: 95%;"></canvas>
</div>
</div>
</div>
<div class="tab">
<div class="tab" style="display: block;">
%plugins%
</div>
</div>
</div>
<script>
function openNav() {
document.getElementById("sidenav").style.width = "100%";
document.getElementById("limiter").style.display = "none";
document.getElementById("navbutton").onclick = function () { closeNav(); };
}
function closeNav() {
document.getElementById("sidenav").style.width = "0%";
document.getElementById("limiter").style.display = "block";
document.getElementById("navbutton").onclick = function () { openNav(); };
}
var navButtons = document.getElementsByClassName("nav-button");
var tabs = document.getElementsByClassName("tab");
var slideIndex = 0;
@ -775,6 +823,9 @@ openFunc(0);
function openFunc(i) {
return function() {
if (window.getComputedStyle(document.getElementById("navbutton")).getPropertyValue('display') == "inline") {
closeNav();
}
var max = navButtons.length;
var perc = -100 / navButtons.length;
slideIndex = i;

View File

@ -12,7 +12,7 @@ header {
top: 0;
left: 0;
width: 100%;
height: 10%;
height: 88px;
padding: 0px;
background-color: #348e0f;
z-index: 1;
@ -34,7 +34,7 @@ body {
background-color: #5cb239;
overflow-x: hidden;
transition: 0.5s;
padding-top: 5.4%;
padding-top: 88px;
text-align: left;
}
.sidenav p {
@ -75,7 +75,7 @@ body {
}
.main-wrapper {
margin-top: 5.5%;
padding-top: 88px;
transform: translate3d(0, 0, 0);
opacity: 0;
transition: 1.5s;
@ -86,7 +86,9 @@ body {
padding: 5px;
text-decoration: none;
color: #000;
width: 100%;
text-align: left;
margin: 5px;
padding: 5px;
}
.box p {
@ -97,6 +99,14 @@ body {
width: 20%;
height: 100%;
float: left;
display: flex;
text-align: left;
align-content: flex-start;
}
.row {
width: 50%;
display: flex;
flex-direction: column;
}
.content {
text-align: center;
@ -109,20 +119,6 @@ body {
.column {
flex: 1;
}
.column-one {
order: 1;
}
.column-two {
order: 2;
}
.column-three {
order: 3;
}
.about {
text-align: left;
margin: 5px;
padding: 5px;
}
.box-area {
width: 100%;
}
@ -272,6 +268,52 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
.white {
color: #FFFFFF;
}
#navbutton {
display: none;
font-size: 40px;
cursor:pointer;
}
@media only screen and (max-width: 850px) {
#navbutton {
display: inline;
}
.sidenav p {
display: none;
}
header {
margin: 0px;
padding 0px;
}
header h1 {
margin: 0px;
}
header img {
margin: 0px;
padding: 0px;
margin-right: 0px;
}
header p {
margin: 0px;
margin-top: 5px;
}
.tab {
flex-direction: column;
}
.columns {
flex-direction: column;
}
.row {
width: 100%;
}
.sidenav {
width: 0%;
transition: 0s;
}
.main-limiter {
margin-left: 0%;
width: 100%;
}
}
</style>
</head>
<body>
@ -279,11 +321,11 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
<div class="header-content">
<img style="float: right; padding: 5px" src="http://puu.sh/tJZUb/c2e0ab220f.png" alt="Player Analytics | Analysis">
<p style="float: right; text-align: right;">Player Analytics v.%version%</p>
<h1>Plan | Inspect Player %name%%op%</h1>
<h1><span id="navbutton" onclick="openNav()">&#9776; </span>Plan | Inspect Player %name%%op%</h1>
</div>
</header>
<div id="content" class="content">
<div class="sidenav">
<div id="sidenav" class="sidenav">
<p>Has Connected from ips:<br>%ips%</p>
<a href="javascript:void(0)" class="nav-button">
<i class="fa fa-info-circle" aria-hidden="true"></i> Information
@ -295,10 +337,10 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
<i class="fa fa-cubes" aria-hidden="true"></i> Plugins
</a>
</div>
<div class="main-limiter">
<div id="limiter" class="main-limiter">
<div id="main" class="main-wrapper">
<div class="tab">
<div class="columns">
<div class="row">
<div class="about box column">
<div class="headerbox">
<div class="header-icon">
@ -318,30 +360,6 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
<div class="about box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity: 7d</span></div>
</div>
<div class="infobox" style="float: right;">
<div class="info-icon">
<i class="fa fa-calendar-check-o" aria-hidden="true"></i>
</div>
<div class="info-text" style="width: 70%;">
<div class="info-number">
%lastseen%
</div>
<div class="info-label">
Last seen
</div>
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<img style="float: right; padding: 5px" alt="%name%" src="http://cravatar.eu/head/%name%/128.png">
<p><i class="fa fa-user" aria-hidden="true"></i> %active% %isonline%%banned%<br/>
<i class="fa fa-address-card-o" aria-hidden="true"></i> Nicknames: %nicknames%<br/>
@ -354,11 +372,6 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
<i class="fa fa-play" aria-hidden="true"></i> Age: %age% | <i class="fa fa-male" aria-hidden="true"></i><i class="fa fa-female" aria-hidden="true"></i> Gender: %gender%<br/>
<i class="fa fa-tag" aria-hidden="true"></i> UUID: %uuid%</p>
</div>
<div class="about box column">
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
</div>
</div>
<div class="columns">
<div class="about box column">
<div class="headerbox">
<div class="header-icon" style="width: 50%">
@ -378,30 +391,6 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
<div class="about box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-crosshairs" aria-hidden="true"></i><span class="header-text"> Last 10 Kills</span></div>
</div>
<div class="infobox" style="float: right;">
<div class="info-icon">
<i class="fa fa-crosshairs" aria-hidden="true"></i>
</div>
<div class="info-text" style="width: 70%;">
<div class="info-number">
%playerkills%
</div>
<div class="info-label">
Player Kills
</div>
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<div class="box-area">
<div class="infobox" style="float: left; background-color: #%gm0col%; width: 45%;">
<div class="info-icon">
@ -458,13 +447,54 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
<canvas id="gmPie" width="1000" height="600" style="width: 95%;"></canvas>
</div>
</div>
<div class="row">
<div class="about box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity: 7d</span></div>
</div>
<div class="infobox" style="float: right;">
<div class="info-icon">
<i class="fa fa-calendar-check-o" aria-hidden="true"></i>
</div>
<div class="info-text" style="width: 70%;">
<div class="info-number">
%lastseen%
</div>
<div class="info-label">
Last seen
</div>
</div>
</div>
</div>
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
</div>
<div class="about box column">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-crosshairs" aria-hidden="true"></i><span class="header-text"> Last 10 Kills</span></div>
</div>
<div class="infobox" style="float: right;">
<div class="info-icon">
<i class="fa fa-crosshairs" aria-hidden="true"></i>
</div>
<div class="info-text" style="width: 70%;">
<div class="info-number">
%playerkills%
</div>
<div class="info-label">
Player Kills
</div>
</div>
</div>
</div>
%killstable%
</div>
</div>
</div>
<div class="tab">
<div class="columns">
<div class="row">
<div class="about box column">
<div class="headerbox">
<div class="header-icon" style="width: 50%">
@ -484,7 +514,10 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
<canvas id="punchcard" width="1000" height="600" style="width: 95%;"></canvas>
</div>
</div>
<div class="row">
<div class="about box column">
<div class="headerbox">
<div class="header-icon">
@ -504,23 +537,26 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
<canvas id="punchcard" width="1000" height="600" style="width: 95%;"></canvas>
</div>
<div class="about box column">
<canvas id="sessiondistribution" width="1000" height="600" style="width: 95%;"></canvas>
</div>
</div>
</div>
<div class="tab">
<div class="tab" style="display: block;">
%plugins%
</div>
</div>
</div>
<script>
function openNav() {
document.getElementById("sidenav").style.width = "100%";
document.getElementById("limiter").style.display = "none";
document.getElementById("navbutton").onclick = function () { closeNav(); };
}
function closeNav() {
document.getElementById("sidenav").style.width = "0%";
document.getElementById("limiter").style.display = "block";
document.getElementById("navbutton").onclick = function () { openNav(); };
}
var navButtons = document.getElementsByClassName("nav-button");
var tabs = document.getElementsByClassName("tab");
var slideIndex = 0;
@ -538,6 +574,9 @@ openFunc(0);
function openFunc(i) {
return function() {
if (window.getComputedStyle(document.getElementById("navbutton")).getPropertyValue('display') == "inline") {
closeNav();
}
var max = navButtons.length;
var perc = -100 / navButtons.length;
slideIndex = i;

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.Plan
version: 3.2.0
version: 3.2.1
softdepend:
- OnTime
@ -10,6 +10,8 @@ softdepend:
- Vault
- Factions
- AdvancedAchievements
- McMMO
- Jobs
commands:
plan:

View File

@ -15,6 +15,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.easymock.EasyMock;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
@ -168,6 +169,7 @@ public class MiscUtilsTest {
/**
*
*/
@Ignore("Inconsistant")
@Test
public void testGetMatchingDisplaynames() {
String search = "testname";