New Html, Fixed the new data addition system for other plugins.

This commit is contained in:
Rsl1122 2017-05-11 20:27:01 +03:00
parent 7892d695f9
commit a75447a77b
37 changed files with 2356 additions and 1443 deletions

View File

@ -231,7 +231,7 @@ public enum Phrase {
while (localeScanner.hasNextLine()) {
String line = localeScanner.nextLine();
if (!line.isEmpty()) {
if (line.equals("<<<<<<HTML>>>>>>")) {
if ("<<<<<<HTML>>>>>>".equals(line)) {
break;
}
localeRows.add(line);

View File

@ -131,7 +131,7 @@ public class Plan extends JavaPlugin {
consoleSender.sendMessage(Phrase.NOTIFY_EMPTY_IP + "");
}
hookHandler = new HookHandler(this);
hookHandler = new HookHandler();
Log.debug("Verboose debug messages are enabled.");
Log.info(Phrase.ENABLED + "");
}
@ -302,10 +302,17 @@ public class Plan extends JavaPlugin {
return bootAnalysisTaskID;
}
/**
* Old method for getting the API.
*
* @deprecated Use Plan.getAPI() (static method) instead.
* @return the Plan API.
*/
@Deprecated
public API getAPI() {
return api;
}
private void initLocale() {
String locale = Settings.LOCALE.toString().toUpperCase();
/*// Used to write a new Locale file
@ -362,6 +369,15 @@ public class Plan extends JavaPlugin {
Log.info("Using locale: " + usingLocale);
}
/**
* Used to get the current instance of Plan.
*
* Instance is set on the first line of onEnable method.
*
* @return current instance of Plan, Singleton.
* @throws IllegalStateException If onEnable method has not been called &
* the instance is null.
*/
public static Plan getInstance() {
Plan INSTANCE = PlanHolder.INSTANCE;
if (INSTANCE == null) {
@ -370,10 +386,22 @@ public class Plan extends JavaPlugin {
return INSTANCE;
}
/**
* Used to set the current instance of Plan.
*
* @param plan The newly enabled Plan instance.
*/
public static void setInstance(Plan plan) {
PlanHolder.INSTANCE = plan;
}
/**
* Used to get the PlanAPI. @see API
*
* @return API of the current instance of Plan.
* @throws IllegalStateException If onEnable method has not been called on
* Plan & the instance is null.
*/
public static API getPlanAPI() throws IllegalStateException {
Plan INSTANCE = PlanHolder.INSTANCE;
if (INSTANCE == null) {
@ -383,7 +411,6 @@ public class Plan extends JavaPlugin {
}
private static class PlanHolder {
private static Plan INSTANCE = null;
}
}

View File

@ -11,13 +11,14 @@ import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.UUIDFetcher;
import org.bukkit.OfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.OfflinePlayer;
/**
* This class contains the API methods.
* <p>
* Revamp incoming in 3.1.0
* Methods can be called from Asyncronous task & are thread safe unless
* otherwise stated.
*
* @author Rsl1122
* @since 2.0.0
@ -35,18 +36,64 @@ public class API {
this.plugin = plugin;
}
public void addPluginDataSource(PluginData dataSource) {
plugin.getHookHandler().addPluginDataSource(dataSource);
/**
* Check whether or not the plugin enabled successfully.
*
* @return true if plugin is enabled correctly.
*/
public boolean isEnabled() {
return plugin.isEnabled();
}
public String getPlayerInspectPageLinkHtml(UUID uuid) throws IllegalStateException {
/**
* Add a source of plugin data to the Plugins tab on Analysis and/or Inspect
* page.
*
* Refer to documentation on github or Javadoc of PluginData to set-up a
* data source that extends PluginData correctly.
*
* @param dataSource an object that extends PluginData-object, thus allowing
* Analysis & Inspect to manage the data of a plugin correctly.
* @see PluginData
*/
public void addPluginDataSource(PluginData dataSource) {
if (isEnabled()) {
plugin.getHookHandler().addPluginDataSource(dataSource);
}
}
/**
* Used to get the link to InspectPage of a player.
*
* This method is useful if you have a table and want to link to the inspect
* page.
*
* Html.LINK.parse("Link", "Playername") can be used to get a link
* {@code <a href="Link">Playername</a>}
*
* @param name Playername of the player
* @return ip:port/security/player/Playername
*/
public String getPlayerInspectPageLink(String name) {
return HtmlUtils.getInspectUrl(name);
}
/**
* Used to get the playerName of a player who has played on the server.
*
* @param uuid UUID of the player.
* @return Playername, eg "Rsl1122"
* @throws IllegalStateException If the player has not played on the server
* before.
*/
public String getPlayerName(UUID uuid) throws IllegalStateException {
OfflinePlayer offlinePlayer = getOfflinePlayer(uuid);
if (offlinePlayer.hasPlayedBefore()) {
return HtmlUtils.getInspectUrl(offlinePlayer.getName());
return offlinePlayer.getName();
}
throw new IllegalStateException("Player has not played on this server before.");
}
/**
* Uses UUIDFetcher to turn PlayerName to UUID
*
@ -57,8 +104,7 @@ public class API {
public UUID playerNameToUUID(String playerName) throws Exception {
return UUIDFetcher.getUUIDOf(playerName);
}
// DEPRECATED METHODS WILL BE REMOVED IN 3.2.0
@Deprecated
public static String formatTimeSinceDate(Date before, Date after) {
@ -114,7 +160,7 @@ public class API {
public UserData getUserDataFromInspectCache(UUID uuid) {
return plugin.getInspectCache().getFromCache(uuid);
}
@Deprecated
public AnalysisData getAnalysisDataFromCache() {
return plugin.getAnalysisCache().getData();

View File

@ -1,27 +1,146 @@
package main.java.com.djrapitops.plan.data.additional;
import main.java.com.djrapitops.plan.data.additional.advancedachievements.AdvancedAchievementsTable;
import main.java.com.djrapitops.plan.data.additional.factions.FactionsMaxPower;
import main.java.com.djrapitops.plan.data.additional.factions.FactionsPower;
import main.java.com.djrapitops.plan.data.additional.factions.FactionsTable;
import main.java.com.djrapitops.plan.data.additional.towny.TownyTable;
/**
* This class contains Enum values for different types of Analysis that can be
* performed on values of PluginData.
*
* The enum determines what should be done to the return value of
* PluginData.getValue() method when the analysis is run.
*
* Refer to the documentation on github for additional information.
*
* @author Rsl1122
*/
public enum AnalysisType {
INT_AVG("Average "), LONG_AVG("Average "), DOUBLE_AVG("Average "),
INT_TOTAL, LONG_TOTAL, DOUBLE_TOTAL,
LONG_TIME_MS_AVG, LONG_TIME_MS_TOTAL, LONG_EPOCH_MS_MINUS_NOW_TOTAL,
BOOLEAN_PERCENTAGE, BOOLEAN_TOTAL,
HTML, TOTAL_VALUE;
/**
* Used when the getValue() method returns an integer & average should be
* calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
INT_AVG("avgInt_","Average "),
/**
* Used when the getValue() method returns a long & average should be
* calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_AVG("avgLong_","Average "),
/**
* Used when the getValue() method returns double & average should be
* calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
DOUBLE_AVG("avgDouble_", "Average "),
/**
* Used when the getValue() method returns an integer & total should be
* calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
INT_TOTAL("totalInt_"),
/**
* Used when the getValue() method returns a long & total should be
* calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TOTAL("totalLong_"),
/**
* Used when the getValue() method returns a double & total should be
* calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
DOUBLE_TOTAL("totalDouble_"),
/**
* Used when the getValue() method returns an amount of milliseconds as long
* & average should be calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TIME_MS_AVG("avgTimeMs_", "Average "),
/**
* Used when the getValue() method returns an amount of milliseconds as long
* & total should be calculated.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_TIME_MS_TOTAL("totalTimeMs_"),
/**
* Used when the getValue() method returns an Epoch Millisecond as long &
* average of differences between the millisecond & current millisecond
* should be calculated.
*
* For example if a player has dropped a Foo on epoch ms 1494486504000 &
* that was 5s (5000ms) ago. Now you want to calculate the average
* time-since for all players. Then you use this one.
*
* -1 values will be disregarded from the calculation (size will not grow).
*/
LONG_EPOCH_MS_MINUS_NOW_AVG("avgEpochMsMinusNow_", "Average "),
/**
* Used to calculate %-true for the returned boolean values of getValue().
*/
BOOLEAN_PERCENTAGE("perchBool_","Percentage "),
/**
* Used to calculate number of true values for the returned boolean values
* of getValue().
*
* Will be presented as "n / total".
*/
BOOLEAN_TOTAL("totalBool_"),
/**
* Used to add html tags to the plugins tab.
*
* Can be used to add Tables, Images (for example maps) & other html
* elements.
*
* @see AdvancedAchievementsTable
* @see FactionsTable
* @see TownyTable
*/
HTML;
private final String modifier;
private final String placeholderModifier;
private AnalysisType(String modifier) {
private AnalysisType(String placeholderModifier, String modifier) {
this.placeholderModifier = placeholderModifier;
this.modifier = modifier;
}
private AnalysisType() {
private AnalysisType(String placeholderModifier) {
this.placeholderModifier = placeholderModifier;
this.modifier = "";
}
private AnalysisType() {
this.placeholderModifier = "";
this.modifier = "";
}
/**
* Used to get the modifier for the Prefix of the value.
*
* For example: "Average Votes" when INT_AVG is used and Prefix is set as
* "Votes".
*
* @return Modifier, can be empty.
*/
public String getModifier() {
return modifier;
}
public String getPlaceholderModifier() {
return placeholderModifier;
}
}

View File

@ -4,6 +4,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/**
* Abstract class for easy hooking of plugins.
*
* @author Rsl1122
*/
@ -12,8 +13,11 @@ public abstract class Hook {
protected boolean enabled;
/**
* Class constructor.
*
* @param plugin
* Checks if the given plugin (class path) is enabled.
*
* @param plugin Class path string of the plugin's main JavaPlugin class.
*/
public Hook(String plugin) {
try {
@ -24,26 +28,11 @@ public abstract class Hook {
enabled = false;
}
}
/**
*
* Consturctor to set enabled to false.
*/
public Hook() {
enabled = false;
}
/**
* @return Whether or not the plugin was successfully hooked.
*/
public boolean isEnabled() {
return enabled;
}
/**
*
* @param enabled
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@ -3,22 +3,27 @@ package main.java.com.djrapitops.plan.data.additional;
import main.java.com.djrapitops.plan.data.additional.essentials.EssentialsHook;
import main.java.com.djrapitops.plan.data.additional.advancedachievements.AdvancedAchievementsHook;
import java.util.ArrayList;
import java.util.Collections;
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.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.additional.factions.FactionsHook;
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.utilities.HtmlUtils;
/**
* Class responsible for hooking to other plugins & managing the %plugins%
* placeholder on Analysis & Inspect pages.
*
* @author Rsl1122
*/
public class HookHandler {
private Plan plan;
private List<PluginData> additionalDataSources;
private AdvancedAchievementsHook advancedAchievementsHook;
private EssentialsHook essentialsHook;
@ -27,23 +32,39 @@ public class HookHandler {
private TownyHook townyHook;
/**
* Class constructor, hooks to plugins.
*
* @param plan
* @param plan Current instance of Plan.
*/
public HookHandler(Plan plan) {
this.plan = plan;
public HookHandler() {
additionalDataSources = new ArrayList<>();
hook();
}
/**
* Adds a new PluginData source to the list.
*
* The plugin data will appear on Analysis and/or Inspect pages depending on
* how the extending object is set up.
*
* Refer to documentation on github for more information.
*
* @param dataSource an object extending the PluginData class.
*/
public void addPluginDataSource(PluginData dataSource) {
Log.debug("Registered a new datasource: " + dataSource.getPlaceholder("").replace("%", ""));
additionalDataSources.add(dataSource);
}
/**
* Used to get all PluginData objects in a list.
*
* @return List of PluginData objects.
*/
public List<PluginData> getAdditionalDataSources() {
return additionalDataSources;
}
/**
*
*/
@ -54,31 +75,97 @@ public class HookHandler {
private void hook() {
try {
advancedAchievementsHook = new AdvancedAchievementsHook();
advancedAchievementsHook = new AdvancedAchievementsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
essentialsHook = new EssentialsHook();
essentialsHook = new EssentialsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
factionsHook = new FactionsHook();
factionsHook = new FactionsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
onTimeHook = new OnTimeHook();
onTimeHook = new OnTimeHook(this);
} catch (NoClassDefFoundError e) {
}
try {
townyHook = new TownyHook();
townyHook = new TownyHook(this);
} catch (NoClassDefFoundError e) {
}
}
public String getPluginsTabLayoutForAnalysis() {
List<String> pluginNames = getPluginNamesAnalysis();
Map<String, List<String>> placeholders = getPlaceholdersAnalysis();
return HtmlUtils.getPluginsTabLayout(pluginNames, placeholders);
}
public String getPluginsTabLayoutForInspect() {
List<String> pluginNames = getPluginNamesInspect();
Map<String, List<String>> placeholders = getPlaceholdersInspect();
return HtmlUtils.getPluginsTabLayout(pluginNames, placeholders);
}
private List<String> getPluginNamesAnalysis() {
List<String> pluginNames = additionalDataSources.stream()
.filter(source -> !source.getAnalysisTypes().isEmpty())
.map(source -> source.getSourcePlugin())
.distinct()
.collect(Collectors.toList());
Collections.sort(pluginNames);
return pluginNames;
}
private List<String> getPluginNamesInspect() {
List<String> pluginNames = additionalDataSources.stream()
.filter(source -> !source.analysisOnly())
.map(source -> source.getSourcePlugin())
.distinct()
.collect(Collectors.toList());
Collections.sort(pluginNames);
return pluginNames;
}
private Map<String, List<String>> getPlaceholdersAnalysis() {
Map<String, List<String>> placeholders = new HashMap<>();
for (PluginData source : additionalDataSources) {
List<AnalysisType> analysisTypes = source.getAnalysisTypes();
if (analysisTypes.isEmpty()) {
continue;
}
String pluginName = source.getSourcePlugin();
if (!placeholders.containsKey(pluginName)) {
placeholders.put(pluginName, new ArrayList<>());
}
for (AnalysisType t : analysisTypes) {
placeholders.get(pluginName).add(source.getPlaceholder(t.getPlaceholderModifier()));
}
}
return placeholders;
}
private Map<String, List<String>> getPlaceholdersInspect() {
Map<String, List<String>> placeholders = new HashMap<>();
for (PluginData source : additionalDataSources) {
if (source.analysisOnly()) {
continue;
}
String pluginName = source.getSourcePlugin();
if (!placeholders.containsKey(pluginName)) {
placeholders.put(pluginName, new ArrayList<>());
}
placeholders.get(pluginName).add(source.getPlaceholder(""));
}
return placeholders;
}
/**
* Used to get the replaceMap for inspect page.
*
* @param uuid
* @return
* @param uuid UUID of the player whose page is being inspected.
* @return Map: key|value - %placeholder%|value
*/
public Map<String, String> getAdditionalInspectReplaceRules(UUID uuid) {
Map<String, String> addReplace = new HashMap<>();

View File

@ -40,19 +40,19 @@ public abstract class PluginData {
this(sourcePlugin, placeholder, new ArrayList<>());
}
public List<AnalysisType> getAnalysisTypes() {
public final List<AnalysisType> getAnalysisTypes() {
return analysisTypes;
}
public String parseContainer(String modifier, String contents) {
public final String parseContainer(String modifier, String contents) {
return "<div class=\"plugin-data\">" + icon + modifier + prefix + contents + suffix + "</div>";
}
public String getPlaceholder(String modifier) {
return "%" + placeholder + modifier + "%";
public final String getPlaceholder(String modifier) {
return "%" + sourcePlugin + "_" + placeholder + modifier + "%";
}
public String getSourcePlugin() {
public final String getSourcePlugin() {
return sourcePlugin;
}
@ -60,26 +60,34 @@ public abstract class PluginData {
public abstract Serializable getValue(UUID uuid);
public void setPrefix(String prefix) {
public final void setPrefix(String prefix) {
this.prefix = prefix;
}
public void setSuffix(String suffix) {
public final void setSuffix(String suffix) {
this.suffix = suffix;
}
public void setIcon(String iconName) {
this.icon = Html.FONT_AWESOME_ICON.parse(iconName)+" ";
public final void setIcon(String iconName) {
this.icon = Html.FONT_AWESOME_ICON.parse(iconName) + " ";
}
public void setAnalysisOnly(boolean analysisOnly) {
public final void setAnalysisOnly(boolean analysisOnly) {
this.analysisOnly = analysisOnly;
}
public boolean analysisOnly() {
public final boolean analysisOnly() {
return analysisOnly;
}
public final String getPrefix() {
return prefix;
}
public final String getSuffix() {
return suffix;
}
/**
* If a PluginData object has same placeholder, sourcePlugin &
* analysisTypes, it is considired equal.
@ -88,7 +96,7 @@ public abstract class PluginData {
* @return Is current object equal to given object.
*/
@Override
public boolean equals(Object obj) {
public final boolean equals(Object obj) {
if (this == obj) {
return true;
}
@ -115,7 +123,7 @@ public abstract class PluginData {
}
@Override
public int hashCode() {
public final int hashCode() {
int hash = 5;
hash = 47 * hash + Objects.hashCode(this.placeholder);
hash = 47 * hash + Objects.hashCode(this.sourcePlugin);

View File

@ -16,9 +16,10 @@ public class AdvancedAchievementsAchievements extends PluginData {
public AdvancedAchievementsAchievements(AdvancedAchievementsAPI aaAPI) {
super("AdvancedAchievements", "achievements", new AnalysisType[]{AnalysisType.INT_TOTAL, AnalysisType.INT_AVG});
this.aaAPI = aaAPI;
super.setAnalysisOnly(false);
super.setIcon("check-circle-o");
super.setPrefix("Achivements: ");
super.setSuffix(" / %totalachievements%");
}
@Override

View File

@ -4,10 +4,8 @@ import main.java.com.djrapitops.plan.data.additional.Hook;
import com.hm.achievement.AdvancedAchievements;
import com.hm.achievement.api.AdvancedAchievementsAPI;
import com.hm.achievement.api.AdvancedAchievementsBukkitAPI;
import com.hm.achievement.category.MultipleAchievements;
import com.hm.achievement.category.NormalAchievements;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/**
*
@ -15,51 +13,22 @@ import main.java.com.djrapitops.plan.api.API;
*/
public class AdvancedAchievementsHook extends Hook {
private AdvancedAchievements hookedPlugin;
private AdvancedAchievementsAPI aaAPI;
private AdvancedAchievements aa;
/**
* Hooks the plugin and calculates Total Achievements.
*/
public AdvancedAchievementsHook() throws NoClassDefFoundError {
public AdvancedAchievementsHook(HookHandler hookH) throws NoClassDefFoundError {
super("com.hm.achievement.AdvancedAchievements");
if (enabled) {
if (Integer.parseInt(Character.toString(hookedPlugin.getDescription().getVersion().charAt(0))) >= 5) {
aaAPI = AdvancedAchievementsBukkitAPI.linkAdvancedAchievements();
API planAPI = Plan.getPlanAPI();
planAPI.addPluginDataSource(new AdvancedAchievementsTable(aaAPI));
planAPI.addPluginDataSource(new AdvancedAchievementsTotalAchievements(calcTotalAchievements()));
planAPI.addPluginDataSource(new AdvancedAchievementsAchievements(aaAPI));
aa = getPlugin(AdvancedAchievements.class);
if (Integer.parseInt(Character.toString(aa.getDescription().getVersion().charAt(0))) >= 5) {
AdvancedAchievementsAPI aaAPI = AdvancedAchievementsBukkitAPI.linkAdvancedAchievements();
hookH.addPluginDataSource(new AdvancedAchievementsAchievements(aaAPI));
hookH.addPluginDataSource(new AdvancedAchievementsTable(aaAPI));
} else {
enabled = false;
}
}
}
private int calcTotalAchievements() {
int total = 0;
for (NormalAchievements category : NormalAchievements.values()) {
String categoryName = category.toString();
if (hookedPlugin.getDisabledCategorySet().contains(categoryName)) {
// Ignore this type.
continue;
}
total += hookedPlugin.getPluginConfig().getConfigurationSection(categoryName).getKeys(false).size();
}
for (MultipleAchievements category : MultipleAchievements.values()) {
String categoryName = category.toString();
if (hookedPlugin.getDisabledCategorySet().contains(categoryName)) {
// Ignore this type.
continue;
}
for (String item : hookedPlugin.getPluginConfig().getConfigurationSection(categoryName).getKeys(false)) {
total += hookedPlugin.getPluginConfig().getConfigurationSection(categoryName + '.' + item)
.getKeys(false).size();
}
}
if (!hookedPlugin.getDisabledCategorySet().contains("Commands")) {
total += hookedPlugin.getPluginConfig().getConfigurationSection("Commands").getKeys(false).size();
}
return total;
}
}

View File

@ -23,8 +23,9 @@ public class AdvancedAchievementsTable extends PluginData {
public AdvancedAchievementsTable(AdvancedAchievementsAPI aaAPI) {
super("AdvancedAchievements", "achievementstable", AnalysisType.HTML);
String player = Html.FONT_AWESOME_ICON.parse("user") + "Player";
String achievements = Html.FONT_AWESOME_ICON.parse("check-circle-o") + "Achievements";
this.aaAPI = aaAPI;
String player = Html.FONT_AWESOME_ICON.parse("user") + " Player";
String achievements = Html.FONT_AWESOME_ICON.parse("check-circle-o") + " Achievements";
// analysisOnly true by default.
super.setPrefix(Html.TABLE_START_2.parse(player, achievements));
super.setSuffix(Html.TABLE_END.parse());
@ -40,10 +41,10 @@ public class AdvancedAchievementsTable extends PluginData {
for (OfflinePlayer p : offlinePlayers) {
String inspectUrl = HtmlUtils.getInspectUrl(p.getName());
String achievements = aaAPI.getPlayerTotalAchievements(p.getUniqueId()) + "";
html.append(Html.TABLELINE_2.parse(inspectUrl, achievements));
html.append(Html.TABLELINE_2.parse(Html.LINK.parse(inspectUrl, p.getName()), achievements));
}
}
return parseContainer(modifierPrefix, html.toString());
return parseContainer("", html.toString());
}
@Override

View File

@ -1,32 +0,0 @@
package main.java.com.djrapitops.plan.data.additional.advancedachievements;
import java.io.Serializable;
import java.util.UUID;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
/**
*
* @author Rsl1122
*/
public class AdvancedAchievementsTotalAchievements extends PluginData {
private int totalAchievements;
public AdvancedAchievementsTotalAchievements(int totalAchievements) {
super("AdvancedAchievements", "totalachievements", AnalysisType.TOTAL_VALUE);
super.setAnalysisOnly(false);
super.setPrefix("Total Achivements: ");
}
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
return totalAchievements + "";
}
@Override
public Serializable getValue(UUID uuid) {
return totalAchievements;
}
}

View File

@ -2,12 +2,7 @@ package main.java.com.djrapitops.plan.data.additional.essentials;
import main.java.com.djrapitops.plan.data.additional.Hook;
import com.earth2me.essentials.Essentials;
import java.util.List;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.essentials.EssentialsJailed;
import main.java.com.djrapitops.plan.data.additional.essentials.EssentialsMuted;
import main.java.com.djrapitops.plan.data.additional.essentials.EssentialsWarps;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/**
@ -16,21 +11,17 @@ import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
*/
public class EssentialsHook extends Hook {
private Essentials ess;
private List<String> warps;
/**
* Hooks to Essentials plugin
*
*/
public EssentialsHook() throws NoClassDefFoundError{
public EssentialsHook(HookHandler hookH) throws NoClassDefFoundError{
super("com.earth2me.essentials.Essentials");
if (super.isEnabled()) {
ess = getPlugin(Essentials.class);
API planAPI = Plan.getPlanAPI();
planAPI.addPluginDataSource(new EssentialsJailed(ess));
planAPI.addPluginDataSource(new EssentialsMuted(ess));
planAPI.addPluginDataSource(new EssentialsWarps(ess));
if (enabled) {
Essentials ess = getPlugin(Essentials.class);
hookH.addPluginDataSource(new EssentialsJailed(ess));
hookH.addPluginDataSource(new EssentialsMuted(ess));
hookH.addPluginDataSource(new EssentialsWarps(ess));
}
}
}

View File

@ -18,6 +18,7 @@ public class EssentialsJailed extends PluginData {
public EssentialsJailed(Essentials essentials) {
super("Essentials", "jailed", AnalysisType.BOOLEAN_PERCENTAGE, AnalysisType.BOOLEAN_TOTAL);
this.essentials = essentials;
super.setIcon("ban");
super.setAnalysisOnly(false);
super.setPrefix("Jailed: ");
}

View File

@ -18,6 +18,7 @@ public class EssentialsMuted extends PluginData {
public EssentialsMuted(Essentials essentials) {
super("Essentials", "muted", AnalysisType.BOOLEAN_PERCENTAGE, AnalysisType.BOOLEAN_TOTAL);
this.essentials = essentials;
super.setIcon("bell-slash-o");
super.setAnalysisOnly(false);
super.setPrefix("Muted: ");
}

View File

@ -4,6 +4,7 @@ import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.Warps;
import java.io.Serializable;
import java.util.UUID;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.PluginData;
/**
@ -15,9 +16,9 @@ public class EssentialsWarps extends PluginData {
private Essentials essentials;
public EssentialsWarps(Essentials essentials) {
super("Essentials", "warps");
super("Essentials", "warps", AnalysisType.HTML);
this.essentials = essentials;
super.setAnalysisOnly(false);
super.setIcon("map-marker");
super.setPrefix("Warps: ");
}

View File

@ -14,6 +14,7 @@ public class FactionsFaction extends PluginData {
public FactionsFaction() {
super("Factions", "faction");
super.setAnalysisOnly(false);
super.setIcon("flag");
super.setPrefix("Faction: ");
}

View File

@ -7,9 +7,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
/**
*
@ -21,14 +20,13 @@ public class FactionsHook extends Hook {
* Hooks to Factions plugin
*
*/
public FactionsHook() {
public FactionsHook(HookHandler hookH) {
super("com.massivecraft.factions.Factions");
if (enabled) {
API planAPI = Plan.getPlanAPI();
planAPI.addPluginDataSource(new FactionsTable(this.getTopFactions()));
planAPI.addPluginDataSource(new FactionsFaction());
planAPI.addPluginDataSource(new FactionsPower());
planAPI.addPluginDataSource(new FactionsMaxPower());
if (enabled) {
hookH.addPluginDataSource(new FactionsFaction());
hookH.addPluginDataSource(new FactionsPower());
hookH.addPluginDataSource(new FactionsMaxPower());
hookH.addPluginDataSource(new FactionsTable(this.getTopFactions()));
}
}

View File

@ -14,7 +14,7 @@ import main.java.com.djrapitops.plan.utilities.FormatUtils;
public class FactionsMaxPower extends PluginData {
public FactionsMaxPower() {
super("Factions", "maxpower", AnalysisType.TOTAL_VALUE);
super("Factions", "maxpower");
super.setAnalysisOnly(false);
super.setPrefix("Max Power: ");
}

View File

@ -16,8 +16,8 @@ public class FactionsPower extends PluginData {
public FactionsPower() {
super("Factions", "power", AnalysisType.DOUBLE_AVG);
super.setAnalysisOnly(false);
super.setIcon("bolt");
super.setPrefix("Power: ");
super.setSuffix(" / %maxpower%");
}
@Override

View File

@ -1,8 +1,7 @@
package main.java.com.djrapitops.plan.data.additional.ontime;
import main.java.com.djrapitops.plan.data.additional.Hook;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
/**
*
@ -14,17 +13,15 @@ public class OnTimeHook extends Hook {
/**
* Hooks to OnTime plugin
*/
public OnTimeHook() throws NoClassDefFoundError {
public OnTimeHook(HookHandler hookH) throws NoClassDefFoundError {
super("me.edge209.OnTime.OnTime");
if (enabled) {
API planAPI = Plan.getPlanAPI();
planAPI.addPluginDataSource(new OntimeVotes());
planAPI.addPluginDataSource(new OntimeVotesWeek());
planAPI.addPluginDataSource(new OntimeVotesMonth());
planAPI.addPluginDataSource(new OntimeRefer());
planAPI.addPluginDataSource(new OntimeReferWeek());
planAPI.addPluginDataSource(new OntimeReferMonth());
hookH.addPluginDataSource(new OntimeVotes());
hookH.addPluginDataSource(new OntimeVotesWeek());
hookH.addPluginDataSource(new OntimeVotesMonth());
hookH.addPluginDataSource(new OntimeRefer());
hookH.addPluginDataSource(new OntimeReferWeek());
hookH.addPluginDataSource(new OntimeReferMonth());
}
}
}

View File

@ -15,8 +15,9 @@ import org.bukkit.OfflinePlayer;
public class OntimeRefer extends PluginData {
public OntimeRefer() {
super("OnTime", "refer", AnalysisType.LONG_TOTAL);
super("OnTime", "refer", AnalysisType.INT_TOTAL, AnalysisType.INT_AVG);
super.setAnalysisOnly(false);
super.setIcon("commenting-o");
super.setPrefix("Referrals All Time: ");
}

View File

@ -15,8 +15,9 @@ import org.bukkit.OfflinePlayer;
public class OntimeReferMonth extends PluginData {
public OntimeReferMonth() {
super("OnTime", "refer_30d", AnalysisType.LONG_TOTAL);
super("OnTime", "refer_30d", AnalysisType.INT_TOTAL);
super.setAnalysisOnly(false);
super.setIcon("commenting-o");
super.setPrefix("Referrals Last 30d: ");
}

View File

@ -15,8 +15,9 @@ import org.bukkit.OfflinePlayer;
public class OntimeReferWeek extends PluginData {
public OntimeReferWeek() {
super("OnTime", "refer_7d", AnalysisType.LONG_TOTAL);
super("OnTime", "refer_7d", AnalysisType.INT_TOTAL);
super.setAnalysisOnly(false);
super.setIcon("commenting-o");
super.setPrefix("Referrals Last 7d: ");
}

View File

@ -15,8 +15,9 @@ import org.bukkit.OfflinePlayer;
public class OntimeVotes extends PluginData {
public OntimeVotes() {
super("OnTime", "votes", AnalysisType.LONG_TOTAL);
super("OnTime", "votes", AnalysisType.INT_TOTAL, AnalysisType.INT_AVG);
super.setAnalysisOnly(false);
super.setIcon("check");
super.setPrefix("Votes All Time: ");
}

View File

@ -15,8 +15,9 @@ import org.bukkit.OfflinePlayer;
public class OntimeVotesMonth extends PluginData {
public OntimeVotesMonth() {
super("OnTime", "votes_30d", AnalysisType.LONG_TOTAL);
super("OnTime", "votes_30d", AnalysisType.INT_TOTAL);
super.setAnalysisOnly(false);
super.setIcon("check");
super.setPrefix("Votes Last 30d: ");
}

View File

@ -15,8 +15,9 @@ import org.bukkit.OfflinePlayer;
public class OntimeVotesWeek extends PluginData {
public OntimeVotesWeek() {
super("OnTime", "votes_7d", AnalysisType.LONG_TOTAL);
super("OnTime", "votes_7d", AnalysisType.INT_TOTAL);
super.setAnalysisOnly(false);
super.setIcon("check");
super.setPrefix("Votes Last 7d: ");
}

View File

@ -9,8 +9,15 @@ import java.util.Comparator;
*/
public class TownComparator implements Comparator<Town> {
// This method should only be used if FactionsHook.isEnabled() returns true.
// Note: this comparator imposes orderings that are inconsistent with equals.
/**
* Used to compare two Town objects.
*
* This method should only be used if TownyHook.isEnabled() returns true.
*
* Note: this comparator imposes orderings that are inconsistent with
* equals.
*
*/
@Override
public int compare(Town tow1, Town tow2) {
if (tow1.equals(tow2)) {

View File

@ -6,9 +6,8 @@ import com.palmergames.bukkit.towny.object.TownyUniverse;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
/**
*
@ -20,17 +19,16 @@ public class TownyHook extends Hook {
* Hooks to Factions plugin
*
*/
public TownyHook() throws NoClassDefFoundError {
public TownyHook(HookHandler hookH) throws NoClassDefFoundError {
super("com.palmergames.bukkit.towny.Towny");
if (enabled) {
API planAPI = Plan.getPlanAPI();
planAPI.addPluginDataSource(new TownyTable(getTopTowns()));
planAPI.addPluginDataSource(new TownyTown());
hookH.addPluginDataSource(new TownyTable(getTopTowns()));
hookH.addPluginDataSource(new TownyTown());
}
}
/**
* @return List of Faction names sorted by power
* @return List of Towns sorted by residents
*/
public List<Town> getTopTowns() {
List<Town> topTowns = TownyUniverse.getDataSource().getTowns();

View File

@ -19,6 +19,7 @@ public class TownyTown extends PluginData {
public TownyTown() {
super("Towny", "town");
super.setAnalysisOnly(false);
super.setIcon("bank");
super.setPrefix("Town: ");
}

View File

@ -40,6 +40,12 @@ public enum Html {
LINK("<a class=\"link\" href=\"" + REPLACE0 + "\">" + REPLACE1 + "</a>"),
LINK_CLASS("class=\"link\""),
IMG("<img src=\"" + REPLACE0 + "\">"),
COLUMNS_DIV_WRAPPER("<div class=\"columns\">" + REPLACE0 + "</div>"),
COLUMN_DIV_WRAPPER("<div class=\"about box column\">" + REPLACE0 + "</div>"),
HEADER("<div class=\"headerbox\" style=\"width: 95%;\"><div class=\"header-icon\"><div class=\"header-label\"><i class=\"fa fa-cube\" aria-hidden=\"true\"></i><span class=\"header-text\"> " + REPLACE0 + "</span></div></div></div>"),
PLUGIN_DATA_WRAPPER("<div class=\"plugin-data\">" + REPLACE0 + "</div>"),
PLUGIN_CONTAINER_START("<div class=\"plugin-container\">"),
NO_PLUGINS("<p>No extra plugins registered.</p>"),
//
TOP_TOWNS("<p><b>Top 20 Towns</b></p>"),
TOP_FACTIONS("<p><b>Top 20 Factions</b></p>"),
@ -83,8 +89,8 @@ public enum Html {
TABLE_START_4("<table class=\"sortable table\"><thead><tr><th>REPLACE0</th><th>REPLACE1</th><th>REPLACE2</th><th>REPLACE3</th></tr></thead><tbody>"),
TABLE_SESSIONS_START(TABLE_START_3.parse("Session Started", "Session Ended", "Session Length")),
TABLE_KILLS_START(TABLE_START_3.parse("Date", "Killed", "With")),
TABLE_FACTIONS_START(TABLE_START_4.parse("Faction", "Power", "Land", "Leader")),
TABLE_TOWNS_START(TABLE_START_4.parse("Town", "Residents", "Land", "Mayor")),
TABLE_FACTIONS_START(TABLE_START_4.parse(FONT_AWESOME_ICON.parse("flag")+" Faction", FONT_AWESOME_ICON.parse("bolt")+" Power", FONT_AWESOME_ICON.parse("map-o")+" Land", FONT_AWESOME_ICON.parse("user")+" Leader")),
TABLE_TOWNS_START(TABLE_START_4.parse(FONT_AWESOME_ICON.parse("bank")+" Town", FONT_AWESOME_ICON.parse("users")+" Residents", FONT_AWESOME_ICON.parse("map-o")+" Land", FONT_AWESOME_ICON.parse("user")+" Mayor")),
TABLELINE_2("<tr><td><b>" + REPLACE0 + "</b></td><td>" + REPLACE1 + "</td></tr>"),
TABLELINE_3("<tr><td><b>" + REPLACE0 + "</b></td><td>" + REPLACE1 + "</td><td>REPLACE2</td></tr>"),
TABLELINE_4("<tr><td><b>" + REPLACE0 + "</b></td><td>" + REPLACE1 + "</td><td>REPLACE2</td><td>REPLACE3</td></tr>"),

View File

@ -19,6 +19,9 @@ import main.java.com.djrapitops.plan.data.KillData;
import main.java.com.djrapitops.plan.data.RawAnalysisData;
import main.java.com.djrapitops.plan.data.SessionData;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.additional.AnalysisType;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.cache.AnalysisCacheHandler;
import main.java.com.djrapitops.plan.data.cache.InspectCacheHandler;
import main.java.com.djrapitops.plan.database.Database;
@ -255,6 +258,7 @@ public class Analysis {
analysisData.setTotalmobkills(sorted.getTotalMobKills());
analysisData.setRefreshDate(new Date().getTime());
analysisData.setGenderData(sorted.getGenders());
analysisData.setAdditionalDataReplaceMap(analyzeAdditionalPluginData(uuids));
analysisCache.cache(analysisData);
if (Settings.ANALYSIS_LOG_FINISHED.isTrue()) {
Log.info(Phrase.ANALYSIS_COMPLETE + "");
@ -357,4 +361,51 @@ public class Analysis {
aData.setGeomapZ(z.replace(",]", "]"));
aData.setGeomapCodes(text.replace(",]", "]"));
}
private Map<String, String> analyzeAdditionalPluginData(List<UUID> uuids) {
Map<String, String> replaceMap = new HashMap<>();
HookHandler hookHandler = Plan.getInstance().getHookHandler();
List<PluginData> sources = hookHandler.getAdditionalDataSources();
for (PluginData source : sources) {
Log.debug("Analyzing source: " + source.getPlaceholder("").replace("%", ""));
try {
List<AnalysisType> analysisTypes = source.getAnalysisTypes();
if (analysisTypes.isEmpty()) {
continue;
}
if (analysisTypes.contains(AnalysisType.HTML)) {
replaceMap.put(source.getPlaceholder(AnalysisType.HTML.getPlaceholderModifier()), source.getHtmlReplaceValue(AnalysisType.HTML.getModifier(), uuids.get(0)));
continue;
}
AnalysisType[] totalTypes = new AnalysisType[]{
AnalysisType.INT_TOTAL, AnalysisType.LONG_TOTAL, AnalysisType.LONG_TIME_MS_TOTAL, AnalysisType.DOUBLE_TOTAL
};
for (AnalysisType type : totalTypes) {
if (analysisTypes.contains(type)) {
replaceMap.put(source.getPlaceholder(type.getPlaceholderModifier()), AnalysisUtils.getTotal(type, source, uuids));
}
}
AnalysisType[] avgTypes = new AnalysisType[]{
AnalysisType.INT_AVG, AnalysisType.LONG_AVG, AnalysisType.LONG_TIME_MS_AVG, AnalysisType.LONG_EPOCH_MS_MINUS_NOW_AVG, AnalysisType.DOUBLE_AVG
};
for (AnalysisType type : avgTypes) {
if (analysisTypes.contains(type)) {
replaceMap.put(source.getPlaceholder(type.getPlaceholderModifier()), AnalysisUtils.getAverage(type, source, uuids));
}
}
AnalysisType t = AnalysisType.BOOLEAN_PERCENTAGE;
if (analysisTypes.contains(t)) {
replaceMap.put(source.getPlaceholder(t.getPlaceholderModifier()), AnalysisUtils.getBooleanPercentage(t, source, uuids));
}
t = AnalysisType.BOOLEAN_TOTAL;
if (analysisTypes.contains(t)) {
replaceMap.put(source.getPlaceholder(t.getPlaceholderModifier()), AnalysisUtils.getBooleanTotal(t, source, uuids));
}
} catch (Throwable e) {
Log.error("A PluginData-source caused an exception: " + source.getPlaceholder("").replace("%", ""));
Log.toLog(this.getClass().getName(), e);
}
}
return replaceMap;
}
}

View File

@ -1,13 +1,20 @@
package main.java.com.djrapitops.plan.utilities;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.OptionalDouble;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
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.UserData;
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.tables.SortableCommandUseTableCreator;
import main.java.com.djrapitops.plan.ui.tables.SortablePlayersTableCreator;
@ -97,4 +104,137 @@ public class AnalysisUtils {
}
return total / list.size();
}
// Refactor to MathUtils class
public static String getTotal(AnalysisType analysisType, PluginData source, List<UUID> uuids) {
try {
if (null != analysisType) {
Number total;
switch (analysisType) {
case INT_TOTAL:
total = getCorrectValues(uuids, source)
.mapToInt(value -> (Integer) value)
.sum();
break;
case LONG_TOTAL:
total = getCorrectValues(uuids, source)
.mapToLong(value -> (Long) value)
.sum();
break;
case LONG_TIME_MS_TOTAL:
total = getCorrectValues(uuids, source)
.mapToLong(value -> (Long) value)
.sum();
return source.parseContainer(analysisType.getModifier(), FormatUtils.formatTimeAmount(total + ""));
case DOUBLE_TOTAL:
total = getCorrectValues(uuids, source)
.mapToDouble(value -> (Double) value)
.sum();
break;
default:
return source.parseContainer("ERROR ", "Wrong Analysistype specified: " + analysisType.name());
}
return source.parseContainer(analysisType.getModifier(), total + "");
}
} catch (Throwable e) {
Log.toLog("com.djrapitops.plan.utilities.AnalysisUtils", e);
}
return source.parseContainer("ERROR ", "Exception during total calculation.");
}
private static Stream<Serializable> getCorrectValues(List<UUID> uuids, PluginData source) {
return uuids.stream()
.map(uuid -> source.getValue(uuid))
.filter(value -> !value.equals(-1));
}
// Refactor to MathUtils class
public static String getAverage(AnalysisType analysisType, PluginData source, List<UUID> uuids) {
try {
if (null != analysisType) {
Number total;
switch (analysisType) {
case LONG_EPOCH_MS_MINUS_NOW_AVG:
final long now = new Date().getTime();
List<Long> longValues = getCorrectValues(uuids, source)
.map(value -> ((long) value) - now)
.collect(Collectors.toList());
return source.parseContainer(analysisType.getModifier(), FormatUtils.formatTimeAmount(average(longValues) + ""));
case INT_AVG:
OptionalDouble avg = getCorrectValues(uuids, source)
.map(value -> (Integer) value)
.mapToInt(i -> i)
.average();
if (!avg.isPresent()) {
total = 0;
} else {
total = avg.getAsDouble();
}
break;
case LONG_AVG:
List<Long> longVal = getCorrectValues(uuids, source)
.map(value -> (Long) value)
.collect(Collectors.toList());
total = average(longVal);
break;
case LONG_TIME_MS_AVG:
List<Long> longVal2 = getCorrectValues(uuids, source)
.map(value -> (Long) value)
.collect(Collectors.toList());
return source.parseContainer(analysisType.getModifier(), FormatUtils.formatTimeAmount(average(longVal2) + ""));
case DOUBLE_AVG:
OptionalDouble average = getCorrectValues(uuids, source)
.mapToDouble(value -> (Double) value)
.average();
if (!average.isPresent()) {
total = 0;
} else {
total = average.getAsDouble();
}
break;
default:
return source.parseContainer("", "Wrong Analysistype specified: " + analysisType.name());
}
return source.parseContainer(analysisType.getModifier(), total + "");
}
} catch (Throwable e) {
Log.error("A PluginData-source caused an exception: "+source.getPlaceholder("").replace("%", ""));
Log.toLog("com.djrapitops.plan.utilities.AnalysisUtils", e);
}
return source.parseContainer("", "Exception during average calculation.");
}
static String getBooleanPercentage(AnalysisType analysisType, PluginData source, List<UUID> uuids) {
if (analysisType == AnalysisType.BOOLEAN_PERCENTAGE) {
try {
List<Boolean> tempList = getCorrectValues(uuids, source)
.map(value -> (boolean) value)
.collect(Collectors.toList());
long count = tempList.stream().filter(value -> value).count();
return source.parseContainer(analysisType.getModifier(), ((double) (count / tempList.size()) * 100) + "%");
} catch (Throwable e) {
Log.error("A PluginData-source caused an exception: "+source.getPlaceholder("").replace("%", ""));
Log.toLog("com.djrapitops.plan.utilities.AnalysisUtils", e);
return source.parseContainer("", "Exception during calculation.");
}
}
return source.parseContainer("", "Wrong Analysistype specified: " + analysisType.name());
}
static String getBooleanTotal(AnalysisType analysisType, PluginData source, List<UUID> uuids) {
if (analysisType == AnalysisType.BOOLEAN_TOTAL) {
try {
List<Boolean> tempList = getCorrectValues(uuids, source)
.map(value -> (boolean) value)
.collect(Collectors.toList());
long count = tempList.stream().filter(value -> value).count();
return source.parseContainer(analysisType.getModifier(), count + " / " + tempList.size());
} catch (Throwable e) {
Log.error("A PluginData-source caused an exception: "+source.getPlaceholder("").replace("%", ""));
Log.toLog("com.djrapitops.plan.utilities.AnalysisUtils", e);
return source.parseContainer("", "Exception during calculation.");
}
}
return source.parseContainer("", "Wrong Analysistype specified: " + analysisType.name());
}
}

View File

@ -2,10 +2,13 @@ package main.java.com.djrapitops.plan.utilities;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.ui.Html;
/**
*
@ -40,7 +43,7 @@ public class HtmlUtils {
* @param replaceMap
* @return
*/
public static String replacePlaceholders(String html, HashMap<String, String> replaceMap) {
public static String replacePlaceholders(String html, Map<String, String> replaceMap) {
for (String key : replaceMap.keySet()) {
html = html.replace(key, replaceMap.get(key));
}
@ -91,4 +94,49 @@ public class HtmlUtils {
.replace("<script>", "")
.replace("</script>", "");
}
public static String getPluginsTabLayout(List<String> pluginNames, Map<String, List<String>> placeholders) {
boolean sizeIsEvenNumber = pluginNames.size() % 2 == 0;
StringBuilder html = new StringBuilder();
String temp = "";
int evenSize = pluginNames.size() - (pluginNames.size() % 2);
Log.debug("Html parsing for:" + pluginNames + ", " + (evenSize));
for (int i = 0; i < evenSize; i++) {
String name = pluginNames.get(i);
Log.debug("Html parsing: " + name);
if (i % 2 == 0) {
temp = Html.COLUMN_DIV_WRAPPER.parse(getContent(name, placeholders.get(name)));
} else {
html.append(Html.COLUMNS_DIV_WRAPPER.parse(temp + Html.COLUMN_DIV_WRAPPER.parse(getContent(name, placeholders.get(name)))));
}
}
if (!sizeIsEvenNumber) {
int lastIndex = pluginNames.size() - 1;
String name = pluginNames.get(lastIndex);
html.append(Html.COLUMNS_DIV_WRAPPER.parse(Html.COLUMN_DIV_WRAPPER.parse(getContent(name, placeholders.get(name)))+Html.COLUMN_DIV_WRAPPER.parse("")));
}
String returnValue = html.toString();
if (returnValue.isEmpty()) {
return Html.COLUMNS_DIV_WRAPPER.parse(
Html.COLUMN_DIV_WRAPPER.parse(
Html.PLUGIN_DATA_WRAPPER.parse(
Html.NO_PLUGINS.parse()
)
)
);
}
return returnValue;
}
private static String getContent(String name, List<String> placeholders) {
Log.debug("Getting content for: "+name);
StringBuilder html = new StringBuilder();
html.append(Html.HEADER.parse(name));
html.append(Html.PLUGIN_CONTAINER_START.parse());
for (String placeholder : placeholders) {
html.append(placeholder);
}
html.append("</div>");
return html.toString();
}
}

View File

@ -29,7 +29,7 @@ public class PlaceholderUtils {
* @param data AnalysisData used to replace the placeholders with
* @return HashMap that contains string for each placeholder.
*/
public static HashMap<String, String> getAnalysisReplaceRules(AnalysisData data) {
public static Map<String, String> getAnalysisReplaceRules(AnalysisData data) {
HashMap<String, String> replaceMap = new HashMap<>();
replaceMap.put("%gm0%", (int) (data.getGm0Perc() * 100) + "%");
replaceMap.put("%gm1%", (int) (data.getGm1Perc() * 100) + "%");
@ -105,11 +105,13 @@ public class PlaceholderUtils {
+ "\",\"#" + Settings.HCOLOR_GENP_U + "\"");
replaceMap.put("%genderfcolor%", "#" + Settings.HCOLOR_GENP_F);
replaceMap.put("%gendermcolor%", "#" + Settings.HCOLOR_GENP_M);
replaceMap.putAll(data.getAdditionalDataReplaceMap());
replaceMap.put("%sessionaverage%", FormatUtils.formatTimeAmount(data.getSessionAverage() + ""));
replaceMap.put("%geomapcountries%", data.getGeomapCountries());
replaceMap.put("%geomapz%", data.getGeomapZ());
replaceMap.put("%geomapcodes%", data.getGeomapCodes());
String pluginsTabHtml = plugin.getHookHandler().getPluginsTabLayoutForAnalysis();
String replacedOnce = HtmlUtils.replacePlaceholders(pluginsTabHtml, data.getAdditionalDataReplaceMap());
replaceMap.put("%plugins%", HtmlUtils.replacePlaceholders(replacedOnce, data.getAdditionalDataReplaceMap()));
return replaceMap;
}
@ -120,7 +122,7 @@ public class PlaceholderUtils {
* @return HashMap that contains string for each placeholder.
* @throws java.io.FileNotFoundException if planliteplayer.html is not found
*/
public static HashMap<String, String> getInspectReplaceRules(UserData data) throws FileNotFoundException {
public static Map<String, String> getInspectReplaceRules(UserData data) throws FileNotFoundException {
HashMap<String, String> replaceMap = new HashMap<>();
boolean showIPandUUID = Settings.SECURITY_IP_UUID.isTrue();
UUID uuid = data.getUuid();
@ -189,7 +191,10 @@ public class PlaceholderUtils {
replaceMap.put("%gm2col%", Settings.HCOLOR_GMP_2 + "");
replaceMap.put("%gm3col%", Settings.HCOLOR_GMP_3 + "");
replaceMap.put("%inaccuratedatawarning%", (new Date().getTime() - data.getRegistered() < 180000) ? Html.WARN_INACCURATE.parse() : "");
replaceMap.putAll(plugin.getHookHandler().getAdditionalInspectReplaceRules(uuid));
String pluginsTabHtml = plugin.getHookHandler().getPluginsTabLayoutForInspect();
Map<String, String> additionalReplaceRules = plugin.getHookHandler().getAdditionalInspectReplaceRules(uuid);
String replacedOnce = HtmlUtils.replacePlaceholders(pluginsTabHtml, additionalReplaceRules);
replaceMap.put("%plugins%", HtmlUtils.replacePlaceholders(replacedOnce, additionalReplaceRules));
return replaceMap;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

209
documentation/API.md Normal file
View File

@ -0,0 +1,209 @@
![Player Analytics](https://puu.sh/t8vin.png)
# API
- [API class](/Plan/src/main/java/com/djrapitops/plan/api/API.java)
- API Javadocs (Coming soon)
Accessing the API Methods:
```
API planAPI = Plan.getPlanAPI(); // Throws IllegalStateException if onEnable() method for Plan has not yet been called.
```
## Adding plugin's data to the 'plugins'-tab on Analysis and/or Inspect pages
Plan has a flexible data addition system since 3.1.0. With it you can add Averages, Totals, Percentages, Tables & Other Html elements to the Plugins tab on the Analysis and/or Inspect pages.
## Basics
- [PluginData](/Plan/src/main/java/com/djrapitops/plan/data/additional/PluginData.java))
- [AnalysisType Enum](/Plan/src/main/java/com/djrapitops/plan/data/additional/AnalysisType.java)
- [Example classes](/Plan/src/main/java/com/djrapitops/plan/data/additional)
To add data a class that extends PluginData class is needed. One PluginData object should only contain data for one user, but tables & other elements are an exception.
### Basic Example
```
public class StepCounterSteps extends PluginData {
private StepCounterPlugin stepCounter; // This is the example plugin where the data is taken from.
// Constructor with the plugin as parameter.
public StepCounterSteps(StepCounterPlugin stepCounter) {
// A call to super constructor: PluginName, PlaceholderName
super("StepCounter", "stepsTaken");
this.stepCounter = stepCounter; // Setting the plugin
}
// Required method.
// This method is used with AnalysisType.HTML and for Inspect page's values.
// All return values should use parseContainer(String modifier, String value)-method, more on that down below.
@Override
public String getHtmlReplaceValue(String modifier, UUID uuid) {
return parseContainer(modifier, stepCounter.getSteps(uuid)+"");
}
// Required method.
// This method is used to calculate values for the Analysis page.
@Override
public Serializable getValue(UUID uuid) {
return stepCounter.getSteps(uuid);
}
}
```
**At the moment registering this data source will have no effect.** It is disregarded because of two variables inside PluginData:
- List<AnalysisType> analysisTypes
- boolean analysisOnly
analysisOnly is 'true' by default. - Thus Inspect page will ignore the data.
analysisTypes is empty. - Thus Analysis page will ignore the data.
## Registering the data point
This might be the easiest step.
get the API and call a single method - all done!
```
Plan.getPlanAPI().addPluginDataSource(new StepCounterSteps(stepCounter));
```
**If you register multiple data sources, they will appear in the order they were registered.**
### Inspect Example
We can add the data to the Inspect page with `super.setAnalysisOnly(false);`-call inside the constructor:
```
public StepCounterSteps(StepCounterPlugin stepCounter) {
super("StepCounter", "stepsTaken");
super.setAnalysisOnly(false); //
this.stepCounter = stepCounter;
}
```
Now on the inspect page, there will be a "StepCounter" plugin box. Inside the box, however **is only a single number**
This is because no prefix has been set.
Let's do that:
```
public StepCounterSteps(StepCounterPlugin stepCounter) {
super("StepCounter", "stepsTaken");
super.setPrefix("Steps taken: ")
//super.setSuffix(" steps"); // You can also define the suffix
super.setAnalysisOnly(false);
this.stepCounter = stepCounter;
}
```
Why should parseContainer(String modifier, String value)-method be used with getHtmlReplaceValue-method?
- Automatically add <div class="plugin-data"></div> wrap around the text.
- Automatically add the prefix, suffix & icon to the value.
Wait, icons?
[Font Awesome Icons](http://fontawesome.io/icons/) can be used. They are added before the prefix when parseContainer method is called.
To set the icon call `super.setIcon(iconName)` in the constructor. Icon-names are visible on the linked page.
```
super.setIcon("wheelchair");
```
### Analysis Example
Adding data to the Analysis page is straightforward as well. Please note that one class can add a data to both Analysis & Inspect pages.
To add data to the Analysis page, analysisTypes need to be set.
This is done in the super constructor. There are three ways to set them:
```
List:
List<AnalysisType> types = new ArrayList<>();
types.add(AnalysisType.LONG_AVG);
types.add(AnalysisType.LONG_TOTAL);
super("StepCounter", "stepsTaken", types);
```
```
Array:
AnalysisType[] types = new AnalysisType{AnalysisType.LONG_AVG, AnalysisType.LONG_TOTAL};
super("StepCounter", "stepsTaken", types);
```
```
Values (1):
super("StepCounter", "stepsTaken", AnalysisType.LONG_AVG);
Values (many):
super("StepCounter", "stepsTaken", AnalysisType.LONG_AVG, AnalysisType.LONG_TOTAL);
```
Refer to AnalysisType for what types you should add. The type depends on the return of the getValue(UUID uuid)-method you have written.
- [AnalysisType](/Plan/src/main/java/com/djrapitops/plan/data/additional/AnalysisType.java)
- AnalysisType Javadoc (Coming soon)
AnalysisType.HTML is for all other elements you might want to add.
### Table Example
A good example is the [AdvancedAchievementsTable](/Plan/src/main/java/com/djrapitops/plan/data/additional/advancedachievements/AdvanceAchievementsTable.java).
You can use the [Html Enum] to quickly create table html.
The Html Enum has easy lines for 2, 3 & 4 line columns - More than that will most likely not fit in the box.
the parse(String... p)-method takes as many strings as parameters as needed to replace all the REPLACE# placeholders on the line.
Let's deconstruct the constructor.
```
public AdvancedAchievementsTable(AdvancedAchievementsAPI aaAPI) {
super("AdvancedAchievements", "achievementstable", AnalysisType.HTML);
this.aaAPI = aaAPI;
String player = Html.FONT_AWESOME_ICON.parse("user") + " Player";
String achievements = Html.FONT_AWESOME_ICON.parse("check-circle-o") + " Achievements";
// analysisOnly true by default.
super.setPrefix(Html.TABLE_START_2.parse(player, achievements));
super.setSuffix(Html.TABLE_END.parse());
}
```
- analysisTypes is set as AnalysisType.HTML.
- prefix is set as a sortable table's start with "<icon> Player" and "<icon> Achievements" columns.
- suffix is set as the end tags for the whole table.
Now let's see how the table gets the values:
```
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
StringBuilder html = new StringBuilder();
List<OfflinePlayer> offlinePlayers = Arrays.stream(getOfflinePlayers()).filter(p -> p.hasPlayedBefore()).collect(Collectors.toList());
if (offlinePlayers.isEmpty()) {
html.append(Html.TABLELINE_2.parse("No Players.",""));
} else {
for (OfflinePlayer p : offlinePlayers) {
String inspectUrl = HtmlUtils.getInspectUrl(p.getName());
String achievements = aaAPI.getPlayerTotalAchievements(p.getUniqueId()) + "";
html.append(Html.TABLELINE_2.parse(Html.LINK.parse(inspectUrl, p.getName()), achievements));
}
}
return parseContainer("", html.toString());
}
```
It simply gets the Players that have played on the server. If the list is empty, a row with "No Players" is added to the value (html, StringBuilder).
Otherwise it get's the Url for the Inspect page of each player, and the amount of achievements a player has.
The link is parsed inside a html a-tag (with the text of the players name).
Then that is parsed into a table line with the a-tag & achievements.
The parseContainer uses an empty string as modifierPrefix, because we don't want any extra text added in-front of the table.
Inspect doesn't use getValue(UUID uuid) &
AnalysisType.HTML disregards it's return values, so that simply returns an empty string.
```
@Override
public Serializable getValue(UUID uuid) {
return "";
}
```