[3.1.0] Removed unnecessary files from git dir, API & doc for API, bugfixes

This commit is contained in:
Rsl1122 2017-05-12 13:03:23 +03:00
parent c1c77b55a8
commit 9b7677e072
56 changed files with 532 additions and 4217 deletions

3
.gitignore vendored
View File

@ -5,5 +5,4 @@
/Plan/target/
/Plan/temporaryTestFolder/
/Debugger/nbproject/private/
/PlanDebugger/
/Plan Lite/
/PlanDebugger/

View File

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="PlanLite" default="default" basedir=".">
<description>Builds, tests, and runs the project PlanLite.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar: JAR building
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="PlanLite-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

View File

@ -1,2 +0,0 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +0,0 @@
build.xml.data.CRC32=f0bf6c4b
build.xml.script.CRC32=42f31611
build.xml.stylesheet.CRC32=8064a381@1.79.1.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=f0bf6c4b
nbproject/build-impl.xml.script.CRC32=ca4555e3
nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48

View File

@ -1,98 +0,0 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=PlanLite
application.vendor=Risto
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# Files in build.classes.dir which should be excluded from distribution jar
dist.archive.excludes=
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/PlanLite.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.AdvancedAchievements-4.0.2.jar=C:\\Users\\Risto\\Documents\\NetBeansProjects\\AdvancedAchievements\\target\\AdvancedAchievements-4.0.2.jar
file.reference.craftbukkit-1.11.2.jar=D:\\Minecraft Servers\\Buildtools\\craftbukkit-1.11.2.jar
file.reference.Factions.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Uusi kansio\\Factions.jar
file.reference.MassiveCore.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Uusi kansio\\MassiveCore.jar
file.reference.mcMMO.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Uusi kansio\\mcMMO.jar
file.reference.PlaceholderAPI.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Uusi kansio\\PlaceholderAPI.jar
file.reference.PlayerLogger_v1.0_.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Uusi kansio\\PlayerLogger[v1.0].jar
file.reference.SuperbVote-0.3.2.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Uusi kansio\\SuperbVote-0.3.2.jar
file.reference.Towny.jar=D:\\Downloads\\Towny.jar
file.reference.Vault.jar=D:\\Minecraft Servers\\TestServer\\plugins\\Vault.jar
includes=**
jar.compress=true
javac.classpath=\
${file.reference.OnTime.jar}:\
${file.reference.EssentialsX-2.0.1.jar}:\
${file.reference.Towny.jar}:\
${file.reference.Vault.jar}:\
${file.reference.Factions.jar}:\
${file.reference.MassiveCore.jar}:\
${file.reference.mcMMO.jar}:\
${file.reference.SuperbVote-0.3.2.jar}:\
${file.reference.PlaceholderAPI.jar}:\
${file.reference.AdvancedAchievements-4.0.2.jar}:\
${file.reference.PlayerLogger_v1.0_.jar}:\
${file.reference.craftbukkit-1.11.2.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.external.vm=true
javac.processorpath=\
${javac.classpath}
javac.source=1.8
javac.target=1.8
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=player.analytics.main.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project.
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
# To set system properties for unit tests define test-sys-prop.name=value:
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>PlanLite</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View File

@ -1,50 +0,0 @@
package com.djrapitops.planlite;
import org.bukkit.ChatColor;
/**
*
* @author Rsl1122
*/
public enum Phrase {
USERNAME_NOT_VALID(ChatColor.RED + "This Player doesn't exist."),
USERNAME_NOT_SEEN(ChatColor.RED + "This Player has not played on this server."),
USERNAME_NOT_KNOWN(ChatColor.RED + "Player not found from the database."),
COLOR_MAIN(ChatColor.DARK_GREEN),
COLOR_SEC(ChatColor.GRAY),
COLOR_TER(ChatColor.WHITE),
ARROWS_RIGHT("»"),
BALL(""),
ERROR_NO_HOOKS(ChatColor.RED + "[PlanLite] No Hooks enabled - Reload plugin!"),
COMMAND_SENDER_NOT_PLAYER(ChatColor.RED + "[PlanLite] This command can be only used as a player."),
COMMAND_REQUIRES_ARGUMENTS(ChatColor.RED + "[PlanLite] Command requires arguments."),
COMMAND_REQUIRES_ARGUMENTS_ONE(ChatColor.RED + "[PlanLite] Command requires one argument."),
COMMAND_NO_PERMISSION(ChatColor.RED + "[PlanLite] You do not have the required permmission.");
private final String text;
private final ChatColor color;
private Phrase(final String text) {
this.text = text;
this.color = null;
}
private Phrase(final ChatColor color) {
this.color = color;
this.text = "";
}
@Override
public String toString() {
return text;
}
/**
* @return Color of the COLOR_ENUM
*/
public ChatColor color() {
return color;
}
}

View File

@ -1,179 +0,0 @@
package com.djrapitops.planlite;
import com.djrapitops.planlite.api.API;
import com.djrapitops.planlite.command.hooks.EssentialsHook;
import com.djrapitops.planlite.command.hooks.FactionsHook;
import com.djrapitops.planlite.command.hooks.OnTimeHook;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.command.hooks.SuperbVoteHook;
import com.djrapitops.planlite.command.hooks.TownyHook;
import com.djrapitops.planlite.command.hooks.VaultHook;
import com.djrapitops.planlite.command.hooks.AdvancedAchievementsHook;
import com.djrapitops.planlite.command.hooks.BukkitDataHook;
import com.djrapitops.planlite.command.hooks.PlayerLoggerHook;
import com.djrapitops.planlite.command.utils.DataUtils;
import com.djrapitops.planlite.command.utils.MiscUtils;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
public class PlanLite extends JavaPlugin {
private final Map<String, Hook> hooks;
private API api;
private final Map<String, Hook> extraHooks;
private PlanLiteCommand planCommand;
public PlanLite() {
this.hooks = new HashMap<>();
this.extraHooks = new HashMap<>();
}
public Map<String, Hook> getHooks() {
return this.hooks;
}
@Override
public void onEnable() {
getDataFolder().mkdirs();
getConfig().options().copyDefaults(true);
getConfig().options().header("PlanLite Config\n"
+ "debug - Errors are saved in errorlog.txt when they occur\n"
+ "visible - Plugin's data is accessable with /plan inspect command"
);
saveConfig();
List<String> hookFail = hookInit();
if (this.hooks.isEmpty()) {
logError("Found no plugins to get data (or config set to false). Disabling plugin..");
logToFile("MAIN\nNo Hooks found. Plugin Disabled.");
getServer().getPluginManager().disablePlugin(this);
return;
}
this.api = new API(this);
log(MiscUtils.checkVersion());
String loadedMsg = "Hooked into: ";
for (String key : this.hooks.keySet()) {
loadedMsg += ChatColor.GREEN + key + " ";
}
String failedMsg = "Not Hooked: ";
for (String string : hookFail) {
failedMsg += ChatColor.RED + string + " ";
}
Bukkit.getServer().getConsoleSender().sendMessage("[PlanLite] " + loadedMsg);
if (!hookFail.isEmpty()) {
Bukkit.getServer().getConsoleSender().sendMessage("[PlanLite] " + failedMsg);
}
planCommand = new PlanLiteCommand(this);
getCommand("planlite").setExecutor(planCommand);
log("Player Analytics Lite Enabled.");
}
public List<String> hookInit() {
this.hooks.clear();
List<String> hookFail = new ArrayList<>();
String[] pluginsArray = {"OnTime", "Essentials", "Towny", "Vault", "Factions", "SuperbVote",
"AdvancedAchievements", "BukkitData", "PlayerLogger"};
List<String> plugins = new ArrayList<>();
plugins.addAll(Arrays.asList(pluginsArray));
StringBuilder errors = new StringBuilder();
errors.append("MAIN-HOOKINIT\n");
plugins.parallelStream().forEach((pluginName) -> {
if (getConfig().getBoolean("visible." + pluginName.toLowerCase())) {
try {
String className = "com.djrapitops.planlite.command.hooks." + pluginName + "Hook";
Class<Hook> clazz = (Class<Hook>) Hook.class.forName(className);
this.hooks.put(pluginName, clazz.getConstructor(PlanLite.class).newInstance(this));
} catch (Exception | NoClassDefFoundError e) {
hookFail.add(pluginName);
errors.append("Failed to hook ").append(pluginName).append("\n").append(e);
errors.append("\n").append(e.getCause());
}
} else {
hookFail.add(ChatColor.YELLOW + pluginName);
}
});
if (!errors.toString().equals("MAIN-HOOKINIT\n")) {
logToFile(errors.toString());
}
for (String extraHook : this.extraHooks.keySet()) {
this.hooks.put(extraHook, this.extraHooks.get(extraHook));
}
return hookFail;
}
@Override
public void onDisable() {
log("Player Analytics Lite Disabled.");
}
public void log(String message) {
getLogger().info(message);
}
public void logError(String message) {
getLogger().severe(message);
}
public void logToFile(String message) {
if (getConfig().getBoolean("debug")) {
File folder = getDataFolder();
if (!folder.exists()) {
folder.mkdir();
}
File log = new File(getDataFolder(), "errorlog.txt");
try {
if (!log.exists()) {
log.createNewFile();
}
FileWriter fw = new FileWriter(log, true);
try (PrintWriter pw = new PrintWriter(fw)) {
pw.println(message + "\n");
pw.flush();
}
} catch (IOException e) {
logError("Failed to create log.txt file");
}
}
}
public API getAPI() {
return api;
}
/**
*
* @param name
* @param hook
*/
public void addExtraHook(String name, Hook hook) {
try {
this.extraHooks.put(name, hook);
this.hooks.put(name, hook);
log("Registered additional hook: " + name);
} catch (Exception | NoClassDefFoundError e) {
logToFile("Failed to hook " + name + "\n" + e);
}
}
public PlanLiteCommand getPlanCommand() {
return planCommand;
}
}

View File

@ -1,103 +0,0 @@
package com.djrapitops.planlite;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import com.djrapitops.planlite.command.commands.AnalyzeCommand;
import com.djrapitops.planlite.command.commands.HelpCommand;
import com.djrapitops.planlite.command.commands.InfoCommand;
import com.djrapitops.planlite.command.commands.InspectCommand;
import com.djrapitops.planlite.command.commands.ReloadCommand;
import com.djrapitops.planlite.command.commands.SearchCommand;
import com.djrapitops.planlite.command.utils.MiscUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import java.util.List;
import java.util.ArrayList;
import org.bukkit.entity.Player;
public class PlanLiteCommand implements CommandExecutor {
private final List<SubCommand> commands;
public PlanLiteCommand(PlanLite plugin) {
commands = new ArrayList<>();
commands.add(new HelpCommand(plugin, this));
commands.add(new InspectCommand(plugin));
commands.add(new AnalyzeCommand(plugin));
commands.add(new SearchCommand(plugin));
commands.add(new InfoCommand(plugin));
commands.add(new ReloadCommand(plugin));
}
public List<SubCommand> getCommands() {
return this.commands;
}
public SubCommand getCommand(String name) {
for (SubCommand command : commands) {
String[] aliases = command.getName().split(",");
for (String alias : aliases) {
if (alias.equalsIgnoreCase(name)) {
return command;
}
}
}
return null;
}
private void sendDefaultCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
String command = "inspect";
if (args.length < 1) {
command = "help";
}
onCommand(sender, cmd, commandLabel, MiscUtils.mergeArrays(new String[]{command}, args));
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (args.length < 1) {
sendDefaultCommand(sender, cmd, commandLabel, args);
return true;
}
SubCommand command = getCommand(args[0]);
if (command == null) {
sendDefaultCommand(sender, cmd, commandLabel, args);
return true;
}
boolean console = !(sender instanceof Player);
if (!sender.hasPermission(command.getPermission())) {
sender.sendMessage(Phrase.COMMAND_NO_PERMISSION.toString());
return true;
}
if (console && args.length < 2 && command.getCommandType() == CommandType.CONSOLE_WITH_ARGUMENTS) {
sender.sendMessage(Phrase.COMMAND_REQUIRES_ARGUMENTS.toString());
return true;
}
if (console && command.getCommandType() == CommandType.PLAYER) {
sender.sendMessage(Phrase.COMMAND_SENDER_NOT_PLAYER.toString());
return true;
}
String[] realArgs = new String[args.length - 1];
for (int i = 1; i < args.length; i++) {
realArgs[i - 1] = args[i];
}
command.onCommand(sender, cmd, commandLabel, realArgs);
return true;
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright (c) 2015 Nate Mortensen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.djrapitops.planlite;
import com.google.common.collect.ImmutableList;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.Callable;
public class UUIDFetcher implements Callable<Map<String, UUID>>
{
private static final double PROFILES_PER_REQUEST = 100;
private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
private final JSONParser jsonParser = new JSONParser();
private final List<String> names;
private final boolean rateLimiting;
public UUIDFetcher( List<String> names, boolean rateLimiting )
{
this.names = ImmutableList.copyOf( names );
this.rateLimiting = rateLimiting;
}
public UUIDFetcher( List<String> names )
{
this( names, true );
}
public Map<String, UUID> call() throws Exception
{
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
int requests = ( int ) Math.ceil( names.size() / PROFILES_PER_REQUEST );
for( int i = 0; i < requests; i++ )
{
HttpURLConnection connection = createConnection();
String body = JSONArray.toJSONString( names.subList( i * 100, Math.min( ( i + 1 ) * 100, names.size() ) ) );
writeBody( connection, body );
JSONArray array = ( JSONArray ) jsonParser.parse( new InputStreamReader( connection.getInputStream() ) );
for( Object profile : array )
{
JSONObject jsonProfile = ( JSONObject ) profile;
String id = ( String ) jsonProfile.get( "id" );
String name = ( String ) jsonProfile.get( "name" );
UUID uuid = UUIDFetcher.getUUID( id );
uuidMap.put( name, uuid );
}
if( rateLimiting && i != requests - 1 )
{
Thread.sleep( 100L );
}
}
return uuidMap;
}
private static void writeBody( HttpURLConnection connection, String body ) throws Exception
{
OutputStream stream = connection.getOutputStream();
stream.write( body.getBytes() );
stream.flush();
stream.close();
}
private static HttpURLConnection createConnection() throws Exception
{
URL url = new URL( PROFILE_URL );
HttpURLConnection connection = ( HttpURLConnection ) url.openConnection();
connection.setRequestMethod( "POST" );
connection.setRequestProperty( "Content-Type", "application/json" );
connection.setUseCaches( false );
connection.setDoInput( true );
connection.setDoOutput( true );
return connection;
}
private static UUID getUUID( String id )
{
return UUID.fromString( id.substring( 0, 8 ) + "-" + id.substring( 8, 12 ) + "-" + id.substring( 12, 16 ) + "-" + id.substring( 16, 20 ) + "-" + id.substring( 20, 32 ) );
}
public static byte[] toBytes( UUID uuid )
{
ByteBuffer byteBuffer = ByteBuffer.wrap( new byte[16] );
byteBuffer.putLong( uuid.getMostSignificantBits() );
byteBuffer.putLong( uuid.getLeastSignificantBits() );
return byteBuffer.array();
}
public static UUID fromBytes( byte[] array )
{
if( array.length != 16 )
{
throw new IllegalArgumentException( "Illegal byte array length: " + array.length );
}
ByteBuffer byteBuffer = ByteBuffer.wrap( array );
long mostSignificant = byteBuffer.getLong();
long leastSignificant = byteBuffer.getLong();
return new UUID( mostSignificant, leastSignificant );
}
public static UUID getUUIDOf( String name ) throws Exception
{
return new UUIDFetcher( Arrays.asList( name ) ).call().get( name );
}
}

View File

@ -1,112 +0,0 @@
package com.djrapitops.planlite.api;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.command.utils.DataFormatUtils;
import com.djrapitops.planlite.command.utils.DataUtils;
import java.util.Date;
import java.util.HashMap;
public class API {
private PlanLite plugin;
public API(PlanLite plugin) {
this.plugin = plugin;
}
public boolean getDebug() {
return plugin.getConfig().getBoolean("debug");
}
public boolean getVisibleEssentials() {
return plugin.getConfig().getBoolean("visible.essentials");
}
public boolean getVisibleOnTime() {
return plugin.getConfig().getBoolean("visible.ontime");
}
public boolean getVisibleFactions() {
return plugin.getConfig().getBoolean("visible.factions");
}
public boolean getVisibleSuperbVote() {
return plugin.getConfig().getBoolean("visible.superbvote");
}
public boolean getVisibleTowny() {
return plugin.getConfig().getBoolean("visible.towny");
}
public boolean getVisibleVault() {
return plugin.getConfig().getBoolean("visible.vault");
}
public boolean getVisibleAdvancedAchievements() {
return plugin.getConfig().getBoolean("visible.advancedachievements");
}
public boolean getVisiblePlaceholderAPI() {
return plugin.getConfig().getBoolean("visible.placeholderapi");
}
public HashMap<String, DataPoint> getData(String playerName, boolean dataPoint) {
return DataFormatUtils.removeExtraDataPoints(DataUtils.getData(false, playerName));
}
// Please move to DataPoint system as soon as possible
@Deprecated
public HashMap<String, String> getData(String playerName) {
HashMap<String, String> data = new HashMap<>();
HashMap<String, DataPoint> dataWPoints = getData(playerName, true);
dataWPoints.keySet().parallelStream().forEach((key) -> {
data.put(key, dataWPoints.get(key).data());
});
return data;
}
public HashMap<String, DataPoint> getAllData(String playerName, boolean dataPoint) {
return DataFormatUtils.removeExtraDataPoints(DataUtils.getData(true, playerName));
}
// Please move to DataPoint system as soon as possible
@Deprecated
public HashMap<String, String> getAllData(String playerName) {
HashMap<String, String> data = new HashMap<>();
HashMap<String, DataPoint> dataWPoints = getAllData(playerName, true);
dataWPoints.keySet().parallelStream().forEach((key) -> {
data.put(key, dataWPoints.get(key).data());
});
return data;
}
public HashMap<String, DataPoint> transformOldDataFormat(HashMap<String, String> oldData) {
HashMap<String, DataPoint> data = new HashMap<>();
for (String key : oldData.keySet()) {
data.put(key, new DataPoint(oldData.get(key), DataType.OTHER));
}
return data;
}
// use (new Date) on after parameter for time since moment to now
public static String formatTimeSinceDate(Date before, Date after) {
return DataFormatUtils.formatTimeAmountSinceDate(before, after);
}
// use (new Date) on after parameter for time since moment to now
public static String formatTimeSinceString(String before, Date after) {
return DataFormatUtils.formatTimeAmountSinceString(before, after);
}
public static String formatTimeAmount(String timeInMs) {
return DataFormatUtils.formatTimeAmount(timeInMs);
}
public static String formatTimeStamp(String timeInMs) {
return DataFormatUtils.formatTimeStamp(timeInMs);
}
public void addExtraHook(String name, Hook hook) {
plugin.addExtraHook(name, hook);
}
}

View File

@ -1,26 +0,0 @@
package com.djrapitops.planlite.api;
public class DataPoint {
private String data;
private final DataType type;
public DataPoint(String data, DataType type) {
this.data = data;
this.type = type;
}
public String data() {
return data;
}
public void setData(String data) {
this.data = data;
}
public DataType type() {
return type;
}
}

View File

@ -1,20 +0,0 @@
package com.djrapitops.planlite.api;
public enum DataType {
STRING, // Any preformatted data & words
TIME, // Long in milliseconds
TIME_TIMESTAMP, // Long in milliseconds since Epoch Date 1970, will be subtracted from current time.
DATE, // Long in milliseconds since Epoch Date 1970
LOCATION, // X:# Y:# Z:#
AMOUNT, // Number
AMOUNT_WITH_MAX, // Example: 41 / 44
AMOUNT_WITH_LETTERS, // Example $50
BOOLEAN, // true/false
PERCENT, // Example 50%
OTHER, // Any data not listed here - will not be analyzed
MAP, // An image presentation of array in string format, no format yet
LINK, // Link to a webpage
HEATMAP, // An image presentation of array in string format, no format yet
DEPRECATED // Old data that has been rendered useless
}

View File

@ -1,16 +0,0 @@
package com.djrapitops.planlite.api;
import com.djrapitops.planlite.PlanLite;
import java.util.HashMap;
public interface Hook {
public HashMap<String, DataPoint> getData(String player) throws Exception;
public HashMap<String, DataPoint> getAllData(String player) throws Exception;
public default void setPlan(PlanLite plan) throws Exception {
}
}

View File

@ -1,8 +0,0 @@
package com.djrapitops.planlite.command;
public enum CommandType
{
CONSOLE,
PLAYER,
CONSOLE_WITH_ARGUMENTS
}

View File

@ -1,62 +0,0 @@
package com.djrapitops.planlite.command;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public abstract class SubCommand
{
private final String name;
private final String permission;
private final String usage;
// private final Phrase description;
private final CommandType commandType;
public SubCommand( String name, String permission, String usage, CommandType commandType )
{
this.name = name;
this.permission = permission;
this.usage = usage;
// this.description = description;
this.commandType = commandType;
}
public String getFirstName()
{
return name.split( "," )[0];
}
public String getName()
{
return name;
}
public String getPermission()
{
return permission;
}
public String getUsage()
{
return usage;
}
// public Phrase getDescription()
// {
// return description;
// }
public CommandType getCommandType()
{
return commandType;
}
public abstract boolean onCommand( CommandSender sender, Command cmd, String commandLabel, String[] args );
}

View File

@ -1,76 +0,0 @@
package com.djrapitops.planlite.command.commands;
import com.djrapitops.planlite.Phrase;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.command.utils.DataFormatUtils;
import com.djrapitops.planlite.command.utils.DataUtils;
import com.djrapitops.planlite.command.utils.Analysis;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class AnalyzeCommand extends SubCommand {
private PlanLite plugin;
private HashMap<UUID, HashMap<String, DataPoint>> playerData;
private HashMap<String, DataPoint> analyzedPlayerdata;
private Date refreshDate;
public AnalyzeCommand(PlanLite plugin) {
super("analyze", "planlite.analyze", "Analyze data of players, /planlite analyze [-refresh]", CommandType.CONSOLE);
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
for (String arg : args) {
if (arg.toLowerCase().equals("-refresh")) {
if (sender.hasPermission("planlite.analyze.refresh") || !(sender instanceof Player)) {
refreshAnalysisData(sender);
} else {
sender.sendMessage(Phrase.COMMAND_NO_PERMISSION.toString());
}
}
}
if (this.playerData == null || this.refreshDate == null || this.analyzedPlayerdata == null || DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()).contains("m")) {
refreshAnalysisData(sender);
}
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite | Analysis results - refreshed "
+ DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()) + " ago");
List<String[]> dataList = DataFormatUtils.turnDataHashMapToSortedListOfArrays(analyzedPlayerdata);
sender.sendMessage(hColor + Phrase.BALL.toString() + tColor + " Averages for " + hColor + this.playerData.size() + tColor + " player(s)");
for (String[] dataString : dataList) {
sender.sendMessage(" " + tColor + Phrase.BALL + oColor+" "
+ dataString[0].charAt(4) + dataString[0].toLowerCase().substring(5) + ": " + tColor + dataString[1]);
}
sender.sendMessage(hColor + Phrase.BALL.toString());
return true;
}
private void refreshAnalysisData(CommandSender sender) {
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite " + tColor + "| "
+ "Refreshing playerData, this might take a while..");
this.playerData = DataUtils.getTotalData(DataUtils.getMatchingDisplaynames(true));
this.refreshDate = new Date();
this.analyzedPlayerdata = Analysis.analyze(this.playerData);
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite " + tColor + "| "
+ "Refreshed, took " + DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()));
}
}

View File

@ -1,55 +0,0 @@
package com.djrapitops.planlite.command.commands;
import com.djrapitops.planlite.Phrase;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.PlanLiteCommand;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class HelpCommand extends SubCommand {
private final PlanLite plugin;
private final PlanLiteCommand command;
public HelpCommand(PlanLite plugin, PlanLiteCommand command) {
super("help,?", "planlite.?", "Show command list.", CommandType.CONSOLE);
this.plugin = plugin;
this.command = command;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite");
for (SubCommand command : this.command.getCommands()) {
if (command.getName().equalsIgnoreCase(getName())) {
continue;
}
if (!sender.hasPermission(command.getPermission())) {
continue;
}
if (!(sender instanceof Player) && command.getCommandType() == CommandType.PLAYER) {
continue;
}
sender.sendMessage(" "+Phrase.BALL+oColor + " /planlite " + command.getFirstName() + tColor + " " + command.getUsage());
}
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
return true;
}
}

View File

@ -1,37 +0,0 @@
package com.djrapitops.planlite.command.commands;
import com.djrapitops.planlite.Phrase;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import com.djrapitops.planlite.command.utils.MiscUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class InfoCommand extends SubCommand {
private PlanLite plugin;
public InfoCommand(PlanLite plugin) {
super("info", "planlite.info", "View version and enabled hooks", CommandType.CONSOLE);
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
plugin.reloadConfig();
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite | Info");
sender.sendMessage(oColor+"Version: "+tColor+plugin.getDescription().getVersion());
sender.sendMessage(tColor+MiscUtils.checkVersion());
sender.sendMessage(oColor+"Enabled Hooks: "+tColor+plugin.getHooks().keySet());
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
return true;
}
}

View File

@ -1,93 +0,0 @@
package com.djrapitops.planlite.command.commands;
import com.djrapitops.planlite.Phrase;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import com.djrapitops.planlite.command.utils.DataFormatUtils;
import com.djrapitops.planlite.command.utils.DataUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.UUID;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class InspectCommand extends SubCommand {
private PlanLite plugin;
public InspectCommand(PlanLite plugin) {
super("inspect", "planlite.inspect", "Inspect data /planlite <player> [-a, -r].", CommandType.CONSOLE_WITH_ARGUMENTS);
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
String playerName = DataUtils.getPlayerDisplayname(args, sender);
UUID uuid;
try {
uuid = UUIDFetcher.getUUIDOf(playerName);
if (uuid == null) {
throw new Exception("Username doesn't exist.");
}
} catch (Exception e) {
sender.sendMessage(Phrase.USERNAME_NOT_VALID.toString());
return true;
}
OfflinePlayer p = getOfflinePlayer(uuid);
if (!p.hasPlayedBefore()) {
sender.sendMessage(Phrase.USERNAME_NOT_SEEN.toString());
return true;
}
if (this.plugin.getHooks().isEmpty()) {
sender.sendMessage(Phrase.ERROR_NO_HOOKS.toString());
return true;
}
boolean allData = false;
boolean format = true;
for (String arg : args) {
if (arg.toLowerCase().equals("-a")) {
allData = true;
}
if (arg.toLowerCase().equals("-r")) {
format = false;
}
}
Date refreshDate = new Date();
HashMap<String, DataPoint> data = DataUtils.getData(allData, playerName);
if (format && !data.isEmpty()) {
data = DataFormatUtils.removeExtraDataPoints(data);
}
if (data.isEmpty()) {
data.put("ERR-NO RESULTS", new DataPoint("No results were found.", DataType.OTHER));
plugin.logToFile("INSPECT-Results\nNo results were found for: " + playerName);
}
List<String[]> dataList = DataFormatUtils.turnDataHashMapToSortedListOfArrays(data);
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite | Inspect results: " + playerName);
for (String[] dataString : dataList) {
sender.sendMessage(" " + tColor + Phrase.BALL + oColor+" "+ dataString[0].charAt(4) + dataString[0].toLowerCase().substring(5) + ": " + tColor + dataString[1]);
}
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
return true;
}
}

View File

@ -1,47 +0,0 @@
package com.djrapitops.planlite.command.commands;
import com.djrapitops.planlite.Phrase;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import com.djrapitops.planlite.command.utils.DataUtils;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class ReloadCommand extends SubCommand {
private PlanLite plugin;
public ReloadCommand(PlanLite plugin) {
super("reload", "planlite.reload", "Reload plugin config & Hooks", CommandType.CONSOLE);
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
plugin.reloadConfig();
List<String> hookFail = plugin.hookInit();
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite | Config & Hooks reloaded.");
String loadedMsg = " Hooked into: ";
for (String key : plugin.getHooks().keySet()) {
loadedMsg += ChatColor.GREEN + key + " ";
}
String failedMsg = " Not Hooked: ";
for (String string : hookFail) {
failedMsg += ChatColor.RED + string + " ";
}
sender.sendMessage(tColor + loadedMsg);
if (!hookFail.isEmpty()) {
sender.sendMessage(tColor + failedMsg);
}
return true;
}
}

View File

@ -1,89 +0,0 @@
package com.djrapitops.planlite.command.commands;
import com.djrapitops.planlite.Phrase;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.command.CommandType;
import com.djrapitops.planlite.command.SubCommand;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import com.djrapitops.planlite.command.utils.DataFormatUtils;
import com.djrapitops.planlite.command.utils.DataUtils;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class SearchCommand extends SubCommand {
private final PlanLite plugin;
public SearchCommand(PlanLite plugin) {
super("search", "planlite.search", "Inspect specific data /planlite <search terms> [-p]", CommandType.CONSOLE_WITH_ARGUMENTS);
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
boolean playerFirst = false;
for (String arg : args) {
if (arg.equals("-p")) {
playerFirst = true;
}
}
Set<OfflinePlayer> matchingPlayers;
if (playerFirst) {
String[] playername = new String[1];
playername[0] = args[0];
matchingPlayers = DataUtils.getMatchingDisplaynames(playername, sender, false);
} else {
matchingPlayers = DataUtils.getMatchingDisplaynames(args, sender, false);
}
args = DataFormatUtils.parseSearchArgs(args);
if (this.plugin.getHooks().isEmpty()) {
sender.sendMessage(Phrase.ERROR_NO_HOOKS.toString());
return true;
}
HashMap<UUID, HashMap<String, DataPoint>> data = DataUtils.getTotalData(matchingPlayers);
Date refreshDate = new Date();
HashMap<String, List<String[]>> dataLists = new HashMap<>();
for (UUID key : data.keySet()) {
OfflinePlayer p = getOfflinePlayer(key);
HashMap<String, DataPoint> dataMap = data.get(key);
if (!dataMap.isEmpty()) {
dataMap = DataFormatUtils.removeExtraDataPointsSearch(dataMap, args);
}
if (dataMap.isEmpty()) {
dataMap.put("ERR-NO RESULTS", new DataPoint("No results were found.", DataType.OTHER));
plugin.logToFile("SEARCH-Results\nNo results were found for: " + p.getName() + Arrays.toString(args));
}
dataLists.put(p.getName(), DataFormatUtils.turnDataHashMapToSortedListOfArrays(dataMap));
}
ChatColor oColor = Phrase.COLOR_MAIN.color();
ChatColor tColor = Phrase.COLOR_SEC.color();
ChatColor hColor = Phrase.COLOR_TER.color();
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString() + oColor + " Player Analytics Lite | Search results: " + Arrays.toString(args));
if (dataLists.isEmpty()) {
sender.sendMessage(" " + tColor + Phrase.BALL + oColor + " No results.");
} else {
for (String playerName : dataLists.keySet()) {
sender.sendMessage(tColor + "Matching player: " + hColor + playerName);
for (String[] dataString : dataLists.get(playerName)) {
sender.sendMessage(" " + tColor + Phrase.BALL + oColor + " "
+ dataString[0].charAt(4) + dataString[0].toLowerCase().substring(5) + ": " + tColor + dataString[1]);
}
}
}
sender.sendMessage(hColor + Phrase.ARROWS_RIGHT.toString());
return true;
}
}

View File

@ -1,107 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import com.hm.achievement.AdvancedAchievements;
import com.hm.achievement.category.MultipleAchievements;
import com.hm.achievement.category.NormalAchievements;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Optional;
import java.util.UUID;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.OfflinePlayer;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class AdvancedAchievementsHook implements Hook {
private PlanLite plugin;
private AdvancedAchievements aAPlugin;
private int totalAchievements;
private boolean usingUUID;
public AdvancedAchievementsHook(PlanLite plugin) throws Exception, NoClassDefFoundError {
this.plugin = plugin;
this.aAPlugin = getPlugin(AdvancedAchievements.class);
// Version was important because 4.0.3 added required method for Offline players
String[] aAVersion = aAPlugin.getDescription().getVersion().split("\\.");
try {
double versionNumber = Double.parseDouble(aAVersion[0] + "." + aAVersion[1] + aAVersion[2]);
if (versionNumber >= 4.03) {
this.usingUUID = true;
} else {
this.usingUUID = false;
plugin.logError("Advanced Achievements 4.0.3 or above required for Offline players");
}
} catch (Exception e) {
// Some versions were formatted with two numbers
try {
double versionNumber = Double.parseDouble(aAVersion[0] + "." + aAVersion[1]);
if (versionNumber >= 4.03) {
this.usingUUID = true;
} else {
this.usingUUID = false;
plugin.logError("Advanced Achievements 4.0.3 or above required for Offline players");
}
} catch (Exception e2) {
plugin.logToFile("AAHOOK\nError getting version number.\n" + e2 + "\n" + e + "\n"
+ aAPlugin.getDescription().getVersion() + "\n" + Arrays.toString(aAVersion));
}
}
// Get total number of Achievements
for (NormalAchievements category : NormalAchievements.values()) {
String categoryName = category.toString();
if (aAPlugin.getDisabledCategorySet().contains(categoryName)) {
continue;
}
totalAchievements += aAPlugin.getPluginConfig().getConfigurationSection(categoryName).getKeys(false).size();
}
for (MultipleAchievements category : MultipleAchievements.values()) {
String categoryName = category.toString();
if (aAPlugin.getDisabledCategorySet().contains(categoryName)) {
continue;
}
for (String item : aAPlugin.getPluginConfig().getConfigurationSection(categoryName).getKeys(false)) {
totalAchievements += aAPlugin.getPluginConfig().getConfigurationSection(categoryName + '.' + item)
.getKeys(false).size();
}
}
if (!aAPlugin.getDisabledCategorySet().contains("Commands")) {
totalAchievements += aAPlugin.getPluginConfig().getConfigurationSection("Commands").getKeys(false).size();
}
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
UUID uuid = UUIDFetcher.getUUIDOf(player);
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
if (totalAchievements > 0) {
if (this.usingUUID) {
data.put("AAC-ACHIEVEMENTS", new DataPoint(aAPlugin.getDb().getPlayerAchievementsAmount(uuid.toString()) + " / " + totalAchievements, DataType.AMOUNT_WITH_MAX));
} else {
plugin.log("You're using outdated version of AdvancedAchievements!");
}
}
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
return getData(player);
}
public boolean isUsingUUID() {
return usingUUID;
}
}

View File

@ -1,59 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import com.google.common.base.Optional;
import java.util.HashMap;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class BukkitDataHook implements Hook {
private final PlanLite plugin;
public BukkitDataHook(PlanLite p) throws Exception {
plugin = p;
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
data.put("BUK-REGISTERED", new DataPoint("" + p.getFirstPlayed(), DataType.DATE));
data.put("BUK-LAST LOGIN", new DataPoint("" + p.getLastPlayed(), DataType.DATE));
if (p.isBanned()) {
data.put("BUK-BANNED", new DataPoint("" + p.isBanned(), DataType.BOOLEAN));
}
data.put("BUK-ONLINE", new DataPoint("" + p.isOnline(), DataType.BOOLEAN));
}
} catch (IllegalArgumentException | NullPointerException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
data.putAll(getData(player));
try {
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
Location loc = p.getBedSpawnLocation();
if (Optional.of(loc).isPresent()) {
data.put("BUK-BED LOCATION WORLD", new DataPoint(loc.getWorld().getName(), DataType.STRING));
data.put("BUK-BED LOCATION", new DataPoint(" X:" + loc.getBlockX() + " Y:" + loc.getBlockY() + " Z:" + loc.getBlockZ(), DataType.LOCATION));
}
data.put("BUK-UUID", new DataPoint("" + p.getUniqueId(), DataType.OTHER));
}
} catch (IllegalArgumentException | NullPointerException e) {
}
return data;
}
}

View File

@ -1,103 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.HashMap;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import net.ess3.api.IEssentials;
import com.earth2me.essentials.craftbukkit.BanLookup;
import java.util.Optional;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
import org.bukkit.BanList;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class EssentialsHook implements Hook {
private IEssentials ess;
private final PlanLite plugin;
public EssentialsHook(PlanLite p) throws Exception {
this.ess = getPlugin(Essentials.class);
this.plugin = p;
}
// Gets data with Essentials own User methods
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
User user = this.ess.getOfflineUser(player);
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
if (Optional.of(user).isPresent()) {
if (this.ess.getServer().getBanList(BanList.Type.IP).isBanned(player)
|| BanLookup.isBanned(this.ess, player)) {
data.put("ESS-BANNED", new DataPoint("" + true, DataType.BOOLEAN));
data.put("ESS-BAN REASON", new DataPoint("" + BanLookup.getBanEntry(this.ess, player).getReason(), DataType.STRING));
}
if (user.isJailed()) {
data.put("ESS-JAILED", new DataPoint("" + true, DataType.BOOLEAN));
data.put("ESS-JAIL TIME", new DataPoint("" + user.getJailTimeout(), DataType.TIME_TIMESTAMP));
}
if (user.isMuted()) {
data.put("ESS-MUTED", new DataPoint("" + true, DataType.BOOLEAN));
data.put("ESS-MUTE TIME", new DataPoint("" + user.getMuteTimeout(), DataType.TIME_TIMESTAMP));
}
try {
if (user.isReachable()) {
Location loc = user.getLocation();
data.put("ESS-LOCATION WORLD", new DataPoint(loc.getWorld().getName(), DataType.STRING));
data.put("ESS-LOCATION", new DataPoint(" X:" + loc.getBlockX() + " Y:" + loc.getBlockY() + " Z:" + loc.getBlockZ(), DataType.LOCATION));
} else {
Location loc = user.getLogoutLocation();
data.put("ESS-LOCATION WORLD", new DataPoint(loc.getWorld().getName(), DataType.STRING));
data.put("ESS-LOCATION", new DataPoint("X:" + loc.getBlockX() + " Y:" + loc.getBlockY() + " Z:" + loc.getBlockZ(), DataType.LOCATION));
}
} catch (Exception e) {
this.plugin.logToFile("ESSENTIALSHOOK\n" + e + "\n" + e.getMessage());
}
data.put("ESS-NICKNAME", new DataPoint("" + user.getDisplayName(), DataType.STRING));
if (user.isReachable()) {
data.put("ESS-ONLINE SINCE", new DataPoint("" + user.getLastLogin(), DataType.TIME_TIMESTAMP));
} else {
data.put("ESS-OFFLINE SINCE", new DataPoint("" + user.getLastLogout(), DataType.TIME_TIMESTAMP));
}
}
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
data.putAll(getData(player));
try {
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
User user = this.ess.getOfflineUser(player);
if (Optional.of(user).isPresent()) {
data.put("ESS-UUID", new DataPoint("" + user.getBase().getUniqueId().toString(), DataType.OTHER));
data.put("ESS-HEALTH", new DataPoint("" + user.getBase().getHealth(), DataType.AMOUNT));
data.put("ESS-HUNGER", new DataPoint("" + user.getBase().getFoodLevel(), DataType.AMOUNT));
data.put("ESS-XP LEVEL", new DataPoint("" + user.getBase().getLevel(), DataType.AMOUNT));
data.put("ESS-OPPED", new DataPoint("" + user.getBase().isOp(), DataType.BOOLEAN));
data.put("ESS-FLYING", new DataPoint("" + user.getBase().isFlying(), DataType.BOOLEAN));
}
}
} catch (IllegalArgumentException e) {
}
return data;
}
}

View File

@ -1,56 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import com.massivecraft.factions.Factions;
import java.util.HashMap;
import com.massivecraft.factions.entity.MPlayer;
import java.util.UUID;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.OfflinePlayer;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class FactionsHook implements Hook {
private PlanLite plugin;
private Factions factions;
public FactionsHook(PlanLite plugin) throws Exception {
this.plugin = plugin;
this.factions = getPlugin(Factions.class);
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
MPlayer mplayer;
UUID uuid = UUIDFetcher.getUUIDOf(player);
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
mplayer = MPlayer.get(uuid);
if (mplayer.hasFaction()) {
data.put("FAC-FACTION", new DataPoint(mplayer.getFactionName(), DataType.STRING));
if (mplayer.hasTitle()) {
data.put("FAC-TITLE", new DataPoint(mplayer.getTitle(), DataType.STRING));
}
}
data.put("FAC-POWER", new DataPoint(mplayer.getPowerRounded() + " / " + mplayer.getPowerMax(), DataType.AMOUNT_WITH_MAX));
data.put("FAC-POWER PER HOUR", new DataPoint("" + mplayer.getPowerPerHour(), DataType.AMOUNT));
data.put("FAC-POWER PER DEATH", new DataPoint("" + mplayer.getPowerPerDeath(), DataType.AMOUNT));
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
return getData(player);
}
}

View File

@ -1,53 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.HashMap;
import me.edge209.OnTime.OnTimeAPI;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.OfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class OnTimeHook implements Hook {
private PlanLite plugin;
public OnTimeHook(PlanLite plugin) throws Exception {
this.plugin = plugin;
if (OnTimeAPI.data.LASTLOGIN == null) {
throw new Exception("Ontime not installed.");
}
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
try {
data.put("ONT-LAST LOGIN", new DataPoint("" + OnTimeAPI.getPlayerTimeData(player, OnTimeAPI.data.LASTLOGIN), DataType.DEPRECATED));
data.put("ONT-TOTAL PLAY", new DataPoint("" + OnTimeAPI.getPlayerTimeData(player, OnTimeAPI.data.TOTALPLAY), DataType.TIME));
data.put("ONT-TOTAL VOTES", new DataPoint("" + OnTimeAPI.getPlayerTimeData(player, OnTimeAPI.data.TOTALVOTE), DataType.AMOUNT));
data.put("ONT-TOTAL REFERRED", new DataPoint("" + OnTimeAPI.getPlayerTimeData(player, OnTimeAPI.data.TOTALREFER), DataType.AMOUNT));
} catch (NoClassDefFoundError e) {
plugin.logToFile("ONTIME HOOK ERROR"
+ "\nOntimeHook enabled but failing, could not get data."
+ "\n" + e
+ "\n" + e.getMessage());
}
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
return getData(player);
}
}

View File

@ -1,64 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.HashMap;
import java.util.UUID;
import me.BadBones69.Logger.SettingsManager;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.file.FileConfiguration;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class PlayerLoggerHook implements Hook {
private PlanLite plugin;
public PlayerLoggerHook(PlanLite plugin) throws Exception, NoClassDefFoundError {
this.plugin = plugin;
SettingsManager.getInstance();
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
FileConfiguration file = SettingsManager.getInstance().getData();
try {
UUID uuid = UUIDFetcher.getUUIDOf(player);
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
data.put("PLG-REGISTERED", new DataPoint(file.getString("Players." + uuid + ".DateJoined"), DataType.DEPRECATED));
data.put("PLG-LAST LOGIN", new DataPoint(file.getString("Players." + uuid + ".LastSeen"), DataType.DEPRECATED));
data.put("PLG-TIMES JOINED", new DataPoint(file.getString("Players." + uuid + ".TimePlayed"), DataType.AMOUNT));
data.put("PLG-KILLS", new DataPoint(file.getString("Players." + uuid + ".Kills"), DataType.AMOUNT));
data.put("PLG-DEATHS", new DataPoint(file.getString("Players." + uuid + ".Deaths"), DataType.AMOUNT));
data.put("PLG-TIMES KICKED", new DataPoint(file.getString("Players." + uuid + ".Kicks"), DataType.AMOUNT));
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
data.putAll(getData(player));
try {
UUID uuid = UUIDFetcher.getUUIDOf(player);
OfflinePlayer p = getOfflinePlayer(uuid);
FileConfiguration file = SettingsManager.getInstance().getData();
if (p.hasPlayedBefore()) {
data.put("PLG-STICKS MADE", new DataPoint(file.getString("Players." + uuid + ".Sticks"), DataType.AMOUNT));
data.put("PLG-STEPS", new DataPoint(file.getString("Players." + uuid + ".Steps"), DataType.AMOUNT));
data.put("PLG-CROUCHES", new DataPoint(file.getString("Players." + uuid + ".Twerks"), DataType.AMOUNT));
}
} catch (IllegalArgumentException e) {
}
return data;
}
}

View File

@ -1,43 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import io.minimum.minecraft.superbvote.SuperbVote;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.OfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class SuperbVoteHook implements Hook {
private PlanLite plugin;
private SuperbVote hookP;
public SuperbVoteHook(PlanLite plugin) throws Exception {
this.plugin = plugin;
this.hookP = SuperbVote.getPlugin();
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
UUID uuid = UUIDFetcher.getUUIDOf(player);
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
data.put("SVO-VOTES", new DataPoint("" + hookP.getVoteStorage().getVotes(uuid), DataType.AMOUNT));
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
return getData(player);
}
}

View File

@ -1,94 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import com.palmergames.bukkit.towny.Towny;
import static com.palmergames.bukkit.towny.TownyFormatter.getFormattedName;
import static com.palmergames.bukkit.towny.TownyFormatter.lastOnlineFormat;
import static com.palmergames.bukkit.towny.TownyFormatter.registeredFormat;
import com.palmergames.bukkit.towny.exceptions.TownyException;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.TownyUniverse;
import com.palmergames.bukkit.util.BukkitTools;
import java.util.HashMap;
import java.util.List;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
import org.bukkit.OfflinePlayer;
import static com.palmergames.bukkit.towny.TownyFormatter.getFormattedResidents;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class TownyHook implements Hook {
private final Towny towny;
private final PlanLite plugin;
public TownyHook(PlanLite p) throws Exception {
this.towny = getPlugin(Towny.class);
this.plugin = p;
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
try {
Resident resident = TownyUniverse.getDataSource().getResident(player);
if (resident != null) {
data.put("TOW-ONLINE", new DataPoint("" + BukkitTools.isOnline(player), DataType.BOOLEAN));
data.put("TOW-REGISTERED", new DataPoint(registeredFormat.format(resident.getRegistered()), DataType.DEPRECATED));
data.put("TOW-LAST LOGIN", new DataPoint(lastOnlineFormat.format(resident.getLastOnline()), DataType.DEPRECATED));
data.put("TOW-OWNER OF", new DataPoint(resident.getTownBlocks().size() + " plots", DataType.STRING));
try {
if (resident.hasTown()) {
data.put("TOW-TOWN", new DataPoint(getFormattedName(resident.getTown()), DataType.STRING));
}
if (resident.hasNation()) {
if (!resident.getNationRanks().isEmpty()) {
data.put("TOW-NATION", new DataPoint(resident.getTown().getNation().getName(), DataType.STRING));
}
}
} catch (TownyException e) {
plugin.logToFile("TOWNYHOOK\n" + e + "\n" + e.getMessage());
}
}
} catch (TownyException e) {
plugin.logToFile("TOWNYHOOK\n" + e + "\nError resident: " + player);
}
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
data.putAll(getData(player));
try {
OfflinePlayer p = getOfflinePlayer(UUIDFetcher.getUUIDOf(player));
if (p.hasPlayedBefore()) {
try {
Resident resident = TownyUniverse.getDataSource().getResident(player);
data.put("TOW-PLOT PERMS", new DataPoint(resident.getPermissions().getColourString(), DataType.STRING));
data.put("TOW-PLOT OPTIONS", new DataPoint("PVP: " + ((resident.getPermissions().pvp) ? "ON" : "OFF") + " Explosions: " + ((resident.getPermissions().explosion) ? "ON" : "OFF") + " Firespread: " + ((resident.getPermissions().fire) ? "ON" : "OFF") + " Mob Spawns: " + ((resident.getPermissions().mobs) ? "ON" : "OFF"), DataType.STRING));
List<Resident> friends = resident.getFriends();
data.put("TOW-FRIENDS", new DataPoint(getFormattedResidents("Friends", friends).toString(), DataType.STRING));
} catch (TownyException e) {
plugin.logToFile("TOWNYHOOK-All\n" + e + "\nError resident: " + player);
}
}
} catch (IllegalArgumentException e) {
}
return data;
}
}

View File

@ -1,44 +0,0 @@
package com.djrapitops.planlite.command.hooks;
import com.djrapitops.planlite.api.Hook;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.OfflinePlayer;
import net.milkbowl.vault.economy.Economy;
import static org.bukkit.Bukkit.getServer;
import static org.bukkit.Bukkit.getOfflinePlayer;
public class VaultHook implements Hook {
private PlanLite plugin;
private Economy econ;
public VaultHook(PlanLite plugin) throws Exception {
this.plugin = plugin;
this.econ = getServer().getServicesManager().getRegistration(Economy.class).getProvider();
}
@Override
public HashMap<String, DataPoint> getData(String player) throws Exception {
HashMap<String, DataPoint> data = new HashMap<>();
try {
UUID uuid = UUIDFetcher.getUUIDOf(player);
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
data.put("ECO-BALANCE", new DataPoint(this.econ.format(this.econ.getBalance(p)), DataType.AMOUNT_WITH_LETTERS));
}
} catch (IllegalArgumentException e) {
}
return data;
}
@Override
public HashMap<String, DataPoint> getAllData(String player) throws Exception {
return getData(player);
}
}

View File

@ -1,105 +0,0 @@
package com.djrapitops.planlite.command.utils;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.command.hooks.AdvancedAchievementsHook;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
public class Analysis {
public static HashMap<String, DataPoint> analyze(HashMap<UUID, HashMap<String, DataPoint>> playerData) {
PlanLite plugin = getPlugin(PlanLite.class);
HashMap<String, List<String>> playerDataLists = new HashMap<>();
HashMap<String, DataType> dataTypes = new HashMap<>();
// Ignore following keys (Strings, unprocessable or irrelevant data)
DataType[] ignoreType = {DataType.DEPRECATED, DataType.STRING, DataType.LOCATION, DataType.LINK, DataType.HEATMAP,
DataType.MAP, DataType.OTHER, DataType.DATE, DataType.TIME_TIMESTAMP};
String[] ignore = {"ESS-HEALTH", "ESS-HUNGER", "ESS-XP LEVEL", "ESS-OPPED"};
List<String> ignoreKeys = new ArrayList<>();
List<DataType> ignoreTypes = new ArrayList<>();
try {
AdvancedAchievementsHook aaHook = (AdvancedAchievementsHook) plugin.getHooks().get("AdvancedAchievements");
if (!aaHook.isUsingUUID()) {
ignoreKeys.add("AAC-ACHIEVEMENTS");
}
} catch (Exception e) {
ignoreKeys.add("AAC-ACHIEVEMENTS");
}
ignoreKeys.addAll(Arrays.asList(ignore));
ignoreTypes.addAll(Arrays.asList(ignoreType));
// Turn playerData into Hashmap of Lists sorted by keys.
playerData.keySet().parallelStream().forEach((key) -> {
playerData.get(key).keySet().parallelStream()
.filter((dataKey) -> !(ignoreKeys.contains(dataKey)))
.map((dataKey) -> {
if (dataTypes.get(dataKey) == null) {
dataTypes.put(dataKey, playerData.get(key).get(dataKey).type());
}
return dataKey;
})
.filter((dataKey) -> !(ignoreTypes.contains(dataTypes.get(dataKey))))
.map((dataKey) -> {
if (playerDataLists.get(dataKey) == null) {
playerDataLists.put(dataKey, new ArrayList<>());
}
return dataKey;
})
.forEach((dataKey) -> {
playerDataLists.get(dataKey).add(playerData.get(key).get(dataKey).data());
});
});
HashMap<String, DataPoint> analyzedData = new HashMap<>();
// Analyze
playerDataLists.keySet().parallelStream().forEach((dataKey) -> {
DataType type = dataTypes.get(dataKey);
if (type == DataType.AMOUNT
|| type == DataType.AMOUNT_WITH_LETTERS
|| type == DataType.AMOUNT_WITH_MAX
|| type == DataType.PERCENT) {
// Get a clean list of dataPoints with only numbers
List<String> dataPoints = playerDataLists.get(dataKey);
if (null != type) {
switch (type) {
case AMOUNT_WITH_LETTERS:
dataPoints = AnalysisUtils.parseWLetters(playerDataLists.get(dataKey));
break;
case PERCENT:
dataPoints = AnalysisUtils.parseWLetters(playerDataLists.get(dataKey));
break;
case AMOUNT_WITH_MAX:
dataPoints = AnalysisUtils.parseWMax(playerDataLists.get(dataKey));
break;
default:
break;
}
}
if (type == DataType.PERCENT) {
String averageAmount = AnalysisUtils.AmountAverage(dataPoints);
analyzedData.put(dataKey, new DataPoint(averageAmount + "%", DataType.PERCENT));
} else {
String averageAmount = AnalysisUtils.AmountAverage(dataPoints);
analyzedData.put(dataKey, new DataPoint(averageAmount, DataType.AMOUNT));
// String highestAmount = AnalysisUtils.AmountHighest(dataPoints);
// analyzedData.put(dataKey + " (HIGHEST)", new DataPoint(highestAmount, DataType.AMOUNT));
}
} else if (type == DataType.TIME) {
String averageTime = AnalysisUtils.TimeAverage(playerDataLists.get(dataKey));
analyzedData.put(dataKey, new DataPoint(averageTime, DataType.TIME));
} else if (type == DataType.BOOLEAN) {
String percent = AnalysisUtils.BooleanPercent(playerDataLists.get(dataKey));
analyzedData.put(dataKey, new DataPoint(percent, DataType.PERCENT));
}
});
return DataFormatUtils.formatAnalyzed(analyzedData);
}
}

View File

@ -1,76 +0,0 @@
package com.djrapitops.planlite.command.utils;
import java.util.ArrayList;
import java.util.List;
class AnalysisUtils {
static String AmountAverage(List<String> dataPoints) {
double sum = 0;
for (String dataPoint : dataPoints) {
try {
sum += Double.parseDouble(dataPoint);
} catch (Exception e) {
}
}
return "" + (sum * 1.0 / dataPoints.size());
}
static List<String> parseWLetters(List<String> dataPoints) {
List<String> parsed = new ArrayList<>();
dataPoints.parallelStream().forEach((dataPoint) -> {
parsed.add(DataFormatUtils.removeLetters(dataPoint));
});
return parsed;
}
static List<String> parseWMax(List<String> dataPoints) {
List<String> parsed = new ArrayList<>();
dataPoints.parallelStream().forEach((dataPoint) -> {
parsed.add(dataPoint.split(" ")[0]);
});
return parsed;
}
static String TimeAverage(List<String> dataPoints) {
Long time = Long.parseLong("0");
for (String dataPoint : dataPoints) {
try {
time += Long.parseLong(dataPoint);
} catch (Exception e) {
}
}
return "" + (time / dataPoints.size());
}
static String BooleanPercent(List<String> dataPoints) {
int amount = 0;
for (String dataPoint : dataPoints) {
try {
if (Boolean.parseBoolean(dataPoint)) {
amount++;
}
} catch (Exception e) {
}
}
return "" + ((amount * 1.0 / dataPoints.size())*100)+"%";
}
static String AmountHighest(List<String> dataPoints) {
int highest = 0;
for (String dataPoint : dataPoints) {
try {
int value = Integer.parseInt(dataPoint);
if (value > highest) {
highest = value;
}
} catch (Exception e) {
}
}
return ""+highest;
}
}

View File

@ -1,298 +0,0 @@
package com.djrapitops.planlite.command.utils;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.api.DataPoint;
import com.djrapitops.planlite.api.DataType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
public class DataFormatUtils {
public static HashMap<String, DataPoint> removeExtraDataPoints(HashMap<String, DataPoint> data) throws NumberFormatException {
Date dateNow = new Date();
List<String> remove = new ArrayList<>();
PlanLite plugin = getPlugin(PlanLite.class);
data.keySet().parallelStream().forEach((key) -> {
try {
// Process OnTime empty data (returns -1 if empty)
if (key.subSequence(0, 3).equals("ONT")) {
if ((data.get(key)).data().equals("-1") || (data.get(key)).data().equals("-1.0")) {
remove.add(key);
}
}
// Process failed PlaceholderAPI requests (%string%)
if (key.subSequence(0, 3).equals("PHA")) {
if ((data.get(key)).data().contains("%")) {
remove.add(key);
}
}
} catch (Exception e) {
plugin.logToFile("FORMAT-Remove\n" + e + "\n" + key);
}
});
// Remove faulty data to prevent TOW-LAST LOGIN from being removed with empty data
remove.parallelStream().forEach((removedKey) -> {
data.remove(removedKey);
});
remove.clear();
// Process Towny data (Empty returns date with 1970 for REGISTERED)
if (data.get("TOW-REGISTERED") != null) {
if (data.get("TOW-REGISTERED").data().contains("1970")) {
remove.add("TOW-REGISTERED");
remove.add("TOW-ONLINE");
remove.add("TOW-LAST LOGIN");
remove.add("TOW-OWNER OF");
if (data.get("TOW-FRIENDS") != null) {
remove.add("TOW-FRIENDS");
remove.add("TOW-PLOT PERMS");
remove.add("TOW-PLOT OPTIONS");
}
}
}
// If both OnTime and Towny data found, OnTime priority.
if (data.get("ONT-LAST LOGIN") != null) {
remove.add("TOW-LAST LOGIN");
remove.add("PLG-LAST LOGIN");
}
// Remove faulty Towny data
remove.parallelStream().forEach((removeKey) -> {
data.remove(removeKey);
});
// Remove faulty Essentials SINCE data, reload turns data to 0
String[] keysRemoveIfZero = {"ESS-ONLINE SINCE", "ESS-OFFLINE SINCE"};
for (String key : keysRemoveIfZero) {
if (data.get(key) != null) {
if (data.get(key).data().equals("0")) {
data.remove(key);
}
}
}
// Remove OnTime Total Votes if SuperbVote is present
if (data.get("SVO-VOTES") != null) {
if (data.get("ONT-TOTAL VOTES") != null) {
data.remove("ONT-TOTAL VOTES");
}
}
// Remove Bukkit uuid points if essentials present
if (data.get("ESS-UUID") != null) {
data.remove("BUK-UUID");
}
// Remove colliding Player Logger Data
if (data.get("TOW-LAST LOGIN") != null) {
data.remove("PLG-LAST LOGIN");
}
data.keySet().parallelStream()
.filter((key) -> (data.get(key).type() == DataType.DEPRECATED))
.forEach((key) -> {
remove.add(key);
});
remove.parallelStream().forEach((key) -> {
data.remove(key);
});
// Format TimeStamps and Time Amounts
for (String key : data.keySet()) {
DataPoint dataPoint = data.get(key);
if (null != dataPoint.type()) switch (dataPoint.type()) {
case DATE:{
String formatted = formatTimeStamp(dataPoint.data());
dataPoint.setData(formatted);
break;
}
case TIME:{
String formatted = formatTimeAmount(dataPoint.data());
dataPoint.setData(formatted);
break;
}
case TIME_TIMESTAMP:{
String formatted = formatTimeAmountSinceString(dataPoint.data(), dateNow);
dataPoint.setData(formatted);
break;
}
default:
break;
}
}
return data;
}
// Analysis data Formatting, will be updated after more analysis is added
public static HashMap<String, DataPoint> formatAnalyzed(HashMap<String, DataPoint> analyzedData) {
return removeExtraDataPoints(analyzedData);
}
// Format Search Results
public static HashMap<String, DataPoint> removeExtraDataPointsSearch(HashMap<String, DataPoint> dataMap, String[] args) {
if (args.length <= 1) {
return removeExtraDataPoints(dataMap);
}
HashMap<String, DataPoint> returnMap = new HashMap<>();
String errors = "FORMAT-SEARCH\n";
for (String key : dataMap.keySet()) {
for (String arg : args) {
try {
if (key.toLowerCase().contains(arg.toLowerCase())) {
returnMap.put(key, dataMap.get(key));
}
} catch (Exception e) {
if (!errors.contains(Arrays.toString(args))) {
errors += Arrays.toString(args) + "\n";
}
errors += (e + "\n" + key + " " + arg + "\n");
}
}
}
if (!errors.equals("FORMAT-SEARCH\n")) {
PlanLite plugin = getPlugin(PlanLite.class);
plugin.logToFile(errors);
}
return removeExtraDataPoints(returnMap);
}
// Replace certain items of search terms with plugin tags and remove playername if -p
public static String[] parseSearchArgs(String[] args) {
String[] aacTerms = {"aac", "advanced", "achiev"};
String[] svoTerms = {"svo", "superb", "vote"};
String[] ontTerms = {"ont", "onoime", "time"};
String[] ecoTerms = {"eco", "money", "bal"};
String[] towTerms = {"tow", "town", "nation", "res", "plot", "perm"};
List<String> aac = new ArrayList<>();
List<String> svo = new ArrayList<>();
List<String> ont = new ArrayList<>();
List<String> eco = new ArrayList<>();
List<String> tow = new ArrayList<>();
aac.addAll(Arrays.asList(aacTerms));
svo.addAll(Arrays.asList(svoTerms));
ont.addAll(Arrays.asList(ontTerms));
eco.addAll(Arrays.asList(ecoTerms));
tow.addAll(Arrays.asList(towTerms));
String[] returnArray = new String[args.length];
argloop:
for (int i = 0; i < args.length; i++) {
for (String s : aac) {
if (args[i].toLowerCase().contains(s)) {
returnArray[i] = "AAC";
continue argloop;
}
}
for (String s : svo) {
if (args[i].toLowerCase().contains(s)) {
returnArray[i] = "SVO";
continue argloop;
}
}
for (String s : ont) {
if (args[i].toLowerCase().contains(s)) {
returnArray[i] = "ONT";
continue argloop;
}
}
for (String s : eco) {
if (args[i].toLowerCase().contains(s)) {
returnArray[i] = "ECO";
continue argloop;
}
}
for (String s : tow) {
if (args[i].toLowerCase().contains(s)) {
returnArray[i] = "TOW";
continue argloop;
}
}
returnArray[i] = args[i];
if (args[i].equals("-p")) {
returnArray[0] = args[0] + "_(Playername)";
returnArray[i] = "---";
}
}
return returnArray;
}
// Creates a new Date with Epoch second and returns Date and Time String
public static String formatTimeStamp(String string) throws NumberFormatException {
long ms = Long.parseLong(string);
Date sfd = new Date(ms);
return ("" + sfd).substring(4, 19);
}
// Formats Time Since (0 -> string)
public static String formatTimeAmount(String string) throws NumberFormatException {
long ms = Long.parseLong(string);
return turnMsLongToString(ms);
}
// Formats Time Difference String before -> Date now
public static String formatTimeAmountSinceString(String string, Date now) throws NumberFormatException {
long ms = Math.abs((now.toInstant().getEpochSecond() * 1000) - Long.parseLong(string));
return turnMsLongToString(ms);
}
// Formats Time Difference Date before -> Date now
public static String formatTimeAmountSinceDate(Date before, Date now) throws NumberFormatException {
long ms = Math.abs((now.toInstant().getEpochSecond() * 1000) - (before.toInstant().getEpochSecond() * 1000));
return turnMsLongToString(ms);
}
// Formats long in milliseconds into d:h:m:s string
private static String turnMsLongToString(long ms) {
String returnValue = "";
long x = ms / 1000;
long seconds = x % 60;
x /= 60;
long minutes = x % 60;
x /= 60;
long hours = x % 24;
x /= 24;
long days = x;
if (days != 0) {
returnValue += days + "d ";
}
if (hours != 0) {
returnValue += hours + "h ";
}
if (minutes != 0) {
returnValue += minutes + "m ";
}
if (seconds != 0) {
returnValue += seconds + "s";
}
if (returnValue.isEmpty()) {
returnValue += "< 1s";
}
return returnValue;
}
// Removes letters from a string leaving only numbers and dots.
public static String removeLetters(String dataPoint) {
String numbers = "0123456789.";
List<Character> numList = new ArrayList<>();
char[] numberArray = numbers.toCharArray();
for (char c : numberArray) {
numList.add(c);
}
String returnString = "";
for (int i = 0; i < dataPoint.length(); i++) {
if (numList.contains(dataPoint.charAt(i))) {
returnString += dataPoint.charAt(i);
}
}
return returnString;
}
// Sorts HashMap into Sorted List of Arrays
public static List<String[]> turnDataHashMapToSortedListOfArrays(HashMap<String, DataPoint> data) {
List<String[]> dataList = new ArrayList<>();
data.keySet().stream().forEach((key) -> {
dataList.add(new String[]{key, data.get(key).data()});
});
Collections.sort(dataList, (String[] strings, String[] otherStrings) -> strings[0].compareTo(otherStrings[0]));
return dataList;
}
}

View File

@ -1,114 +0,0 @@
package com.djrapitops.planlite.command.utils;
import com.djrapitops.planlite.PlanLite;
import com.djrapitops.planlite.UUIDFetcher;
import com.djrapitops.planlite.api.DataPoint;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
public class DataUtils {
// allData defined by -a argument in InspectCommand
// returns data given by each Hook
public static HashMap<String, DataPoint> getData(boolean allData, String playerName) {
HashMap<String, DataPoint> data = new HashMap<>();
PlanLite plugin = getPlugin(PlanLite.class);
plugin.getHooks().keySet().parallelStream().forEach((hook) -> {
try {
if (allData) {
data.putAll(plugin.getHooks().get(hook).getAllData(playerName));
} else {
data.putAll(plugin.getHooks().get(hook).getData(playerName));
}
} catch (Exception e) {
String toLog = "UTILS-GetData"
+ "\nFailed to getData from " + hook
+ "\n" + e
+ "\ncausing argument: " + playerName;
for (StackTraceElement element : e.getStackTrace()) {
toLog += "\n " + element;
}
plugin.logToFile(toLog);
}
});
return data;
}
// Returns data HashMaps for all pplayers in a HashMap.
public static HashMap<UUID, HashMap<String, DataPoint>> getTotalData(Set<OfflinePlayer> ofPlayers) {
HashMap<UUID, HashMap<String, DataPoint>> playerData = new HashMap<>();
List<OfflinePlayer> players = new ArrayList<>();
players.addAll(ofPlayers);
players.parallelStream()
.filter((player) -> (playerData.get(player.getUniqueId()) == null))
.forEach((player) -> {
playerData.put(player.getUniqueId(), getData(true, player.getName()));
});
return playerData;
}
@Deprecated
public static HashMap<String, DataPoint> analyze(HashMap<UUID, HashMap<String, DataPoint>> playerData) {
return Analysis.analyze(playerData);
}
public static String getPlayerDisplayname(String[] args, CommandSender sender) {
String playerName = "";
PlanLite plugin = getPlugin(PlanLite.class);
if (args.length > 0) {
if ((args[0].equals("-a")) || (args[0].equals("-r"))) {
playerName = "ArgumentGivenError";
plugin.log("No username given, returned empty username.");
plugin.logToFile("INSPECT-GETNAME\nNo username given, returned empty username.\n" + args[0]);
} else if (sender.hasPermission("planlite.inspect.other") || !(sender instanceof Player)) {
playerName = args[0];
}
} else {
try {
Player player = plugin.getServer().getPlayer(UUIDFetcher.getUUIDOf(sender.getName()));
playerName = player.getName();
} catch (Exception e) {
playerName = "ConsoleNotPlayerErr";
}
}
return playerName;
}
public static Set<OfflinePlayer> getMatchingDisplaynames(String[] args, CommandSender sender, boolean all) {
List<OfflinePlayer> players = new ArrayList<>();
players.addAll(Arrays.asList(Bukkit.getOfflinePlayers()));
Set<OfflinePlayer> matches = new HashSet<>();
if (all) {
matches.addAll(players);
} else {
List<String> searchTerms = new ArrayList<>();
searchTerms.addAll(Arrays.asList(args));
players.parallelStream().forEach((p) -> {
searchTerms.stream().filter((searchTerm) -> (p.getName().toLowerCase().contains(searchTerm.toLowerCase()))).forEach((_item) -> {
matches.add(p);
});
});
}
return matches;
}
public static Set<OfflinePlayer> getMatchingDisplaynames(boolean b) {
return getMatchingDisplaynames(new String[0], null, true);
}
}

View File

@ -1,57 +0,0 @@
package com.djrapitops.planlite.command.utils;
import com.djrapitops.planlite.PlanLite;
import java.net.URL;
import java.util.Scanner;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
public class MiscUtils {
// <h1>Plan - Player Analytics <span class="muted">
public static String checkVersion() {
PlanLite plugin = getPlugin(PlanLite.class);
String[] nVersion;
String[] cVersion;
String lineWithVersion;
try {
URL githubUrl = new URL("https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/Plan%20Lite/src/plugin.yml");
lineWithVersion = "";
Scanner websiteScanner = new Scanner(githubUrl.openStream());
while (websiteScanner.hasNextLine()) {
String line = websiteScanner.nextLine();
if (line.toLowerCase().contains("version")) {
lineWithVersion = line;
break;
}
}
String versionString = lineWithVersion.split(": ")[1];
nVersion = versionString.split("\\.");
double newestVersionNumber = Double.parseDouble(nVersion[0] + "." + nVersion[1] + nVersion[2]);
cVersion = plugin.getDescription().getVersion().split("\\.");
double currentVersionNumber = Double.parseDouble(cVersion[0] + "." + cVersion[1] + cVersion[2]);
if (newestVersionNumber > currentVersionNumber) {
return "New Version (" + versionString + ") is availible at https://www.spigotmc.org/resources/plan-player-analytics.32536/";
} else {
return "You're running the latest version";
}
} catch (Exception e) {
plugin.logToFile("Failed to compare versions.\n"+e);
}
return "Failed to get newest version number.";
}
public static String[] mergeArrays(String[]... arrays) {
int arraySize = 0;
for (String[] array : arrays) {
arraySize += array.length;
}
String[] result = new String[arraySize];
int j = 0;
for (String[] array : arrays) {
for (String string : array) {
result[j++] = string;
}
}
return result;
}
}

View File

@ -1,13 +0,0 @@
debug: true
visible:
bukkitdata: true
ontime: true
essentials: true
factions: true
towny: true
vault: true
superbvote: true
placeholderapi: true
advancedachievements: true
playerlogger: true

View File

@ -1,83 +0,0 @@
name: PlanLite
main: com.djrapitops.planlite.PlanLite
version: 1.6.3
commands:
planlite:
usage: /<command> <name>
description: base command
inspect:
usage: /planlite inspect <name>
description: inspect player data
analyze:
usage: /planlite analyze
description: analyze all players' data, add -refresh to refresh analysis.
reload:
usage: /planlite reload
description: reload plugin config
search:
usage: /planlite <search terms> -p add -p to make not search playername
description: search data of multiple players with search terms
debug:
usage: /planlite debug
description: run commands to debug the plugin.
softdepend:
- OnTime
- EssentialsX
- Towny
- Vault
- Factions
- SuperbVote
- PlaceholderAPI
- AdvancedAchievements
- PlayerLogger
permissions:
planlite.?:
description: Help command
default: true
planlite.inspect:
description: Allows you to check your player data.
default: true
planlite.inspect.other:
description: Allows you to check other players' player data.
default: true
planlite.analyze:
description: Allows you to check analysed data about all players.
default: true
planlite.analyze.refresh:
description: Allows you to refresh the analyse result with -r argument
default: op
planlite.reload:
description: Allows to reload plugin config
default: true
planlite.search:
description: Allows search
default: true
planlite.info:
description: Allows to view info
default: true
planlite.debug:
description: Allows debug command
default: op
planlite.basic:
children:
planlite.?: true
planlite.inspect: true
planlite.info: true
planlite.search: true
planlite.advanced:
childer:
planlite.basic: true
planlite.analyze: true
planlite.staff:
children:
planlite.debug: true
planlite.advanced: true
planlite.inspect.other: true
planlite.analyze.refresh: true
planlite.reload: true
planlite.*:
children:
planlite.staff: true

View File

@ -5,11 +5,22 @@
<artifactId>Plan</artifactId>
<version>2.0.0</version>
<packaging>jar</packaging>
<repositories>
<!-- <repository>
<id>bukkit-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>-->
<repository>
<id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.10.2-R0.1-SNAPSHOT</version>
<version>1.11.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- SoftDepended Plugins-->
<dependency>
@ -30,12 +41,6 @@
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.minimum</groupId>
<artifactId>superbvote</artifactId>
<version>0.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.massivecraft</groupId>
<artifactId>factions</artifactId>
@ -54,6 +59,12 @@
<version>0.91.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.6</version>
<scope>provided</scope>
</dependency>
<!-- -->
<dependency>
<groupId>org.powermock</groupId>
@ -111,6 +122,7 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>clean package install</defaultGoal>
<finalName>${project.name}</finalName>
@ -126,7 +138,6 @@
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
@ -135,22 +146,6 @@
<target>1.8</target>
</configuration>
</plugin>
<!-- <plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
@ -177,19 +172,6 @@
<configLocation>checkstyle.xml</configLocation>
</configuration>
</plugin>
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>-->
</plugins>
</build>
<properties>

View File

@ -45,11 +45,11 @@ public enum Settings {
COLOR_SEC("Customization.Colors.Commands.Secondary"),
COLOR_TER("Customization.Colors.Commands.Highlight"),
//
HCOLOR_MAIN("Customization.HTML.UI.Main"),
HCOLOR_MAIN_DARK("Customization.HTML.UI.MainDark"),
HCOLOR_SEC("Customization.HTML.UI.Secondary"),
HCOLOR_TER("Customization.HTML.UI.Tertiary"),
HCOLOR_TER_DARK("Customization.HTML.UI.TertiaryDark"),
HCOLOR_MAIN("Customization.Colors.HTML.UI.Main"),
HCOLOR_MAIN_DARK("Customization.Colors.HTML.UI.MainDark"),
HCOLOR_SEC("Customization.Colors.HTML.UI.Secondary"),
HCOLOR_TER("Customization.Colors.HTML.UI.Tertiary"),
HCOLOR_TER_DARK("Customization.Colors.HTML.UI.TertiaryDark"),
HCOLOR_ACT_ONL("Customization.Colors.HTML.ActivityGraph.OnlinePlayers"),
HCOLOR_ACT_ONL_FILL("Customization.Colors.HTML.ActivityGraph.OnlinePlayersFill"),
HCOLOR_ACTP_ACT("Customization.Colors.HTML.ActivityPie.Active"),

View File

@ -6,6 +6,8 @@ import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor;
import main.java.com.djrapitops.plan.data.handling.info.HandlingInfo;
import main.java.com.djrapitops.plan.ui.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.WebSocketServer;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
@ -78,6 +80,139 @@ public class API {
return HtmlUtils.getInspectUrl(name);
}
/**
* Schedule a UserData object to be fetched from the database or cache if
* the player is online.
*
* The data will not be cached if it is not already cached.
*
* @param uuid UUID of the player.
* @param processor Object implementing DBCallableProcessor, which
* process(UserData data) method will be called.
*/
public void scheduleForGet(UUID uuid, DBCallableProcessor processor) {
plugin.getHandler().getUserDataForProcessing(processor, uuid, false);
}
/**
* Schedule a HandlingInfo object to be processed.
*
* UserData associated with the UUID of the HandlingInfo object will be
* cached.
*
* @param info object that extends HandlingInfo.
*/
public void scheduleEventHandlingInfo(HandlingInfo info) {
plugin.getHandler().addToPool(info);
}
/**
* Used to cache a UserData object.
*
* If data is already cached it will be overridden.
*
* @param data UserData object. Will be placed to the data.getUuid() key in
* the cache.
*/
public void placeDataToCache(UserData data) {
plugin.getHandler().cache(data);
}
/**
* Used to save the cached data to the database.
*
* Should be only called from an Asyncronous thread.
*/
public void saveCachedData() {
plugin.getHandler().saveCachedUserData();
}
/**
* Check if the UserData is cached to the InspectCache.
*
* @param uuid UUID of the player.
* @return true/false
*/
public boolean isPlayersDataInspectCached(UUID uuid) {
return plugin.getInspectCache().isCached(uuid);
}
/**
* Cache the UserData to InspectCache.
*
* Uses cache if data is cached or database if not. Call from an Asyncronous
* thread.
*
* @param uuid
*/
public void cacheUserDataToInspectCache(UUID uuid) {
plugin.getInspectCache().cache(uuid);
}
/**
* Used to get the full Html of the Inspect page as a string.
*
* Check if the data is cached to InspectCache before calling this.
*
* @param uuid UUID of the player.
* @return player.html with all placeholders replaced.
*/
public String getPlayerHtmlAsString(UUID uuid) {
WebSocketServer server = plugin.getUiServer();
if (server != null) {
return server.getDataReqHandler().getInspectHtml(uuid);
}
DataRequestHandler reqH = new DataRequestHandler(plugin);
return reqH.getInspectHtml(uuid);
}
/**
* Check if the Analysis has been run & is cached to the AnalysisCache.
*
* @return true/false
*/
public boolean isAnalysisCached() {
return plugin.getAnalysisCache().isCached();
}
/**
* Run's the analysis with the current data in the cache & fetches rest from
* the database.
*
* Starts a new Asyncronous task to run the analysis.
*/
public void updateAnalysisCache() {
plugin.getAnalysisCache().updateCache();
}
/**
* Used to get the full Html of the Analysis page as a string.
*
* Check if the data is cached to AnalysisCache before calling this.
*
* @return analysis.html with all placeholders replaced.
*/
public String getAnalysisHtmlAsString() {
WebSocketServer server = plugin.getUiServer();
if (server != null) {
return server.getDataReqHandler().getAnalysisHtml();
}
DataRequestHandler reqH = new DataRequestHandler(plugin);
return reqH.getAnalysisHtml();
}
/**
* Used to get the AnalysisData object.
*
* Check if the data is cached to AnalysisCache before calling this.
*
* @return AnalysisData object.
* @see AnalysisData
*/
public AnalysisData getAnalysisDataFromCache() {
return plugin.getAnalysisCache().getData();
}
/**
* Used to get the playerName of a player who has played on the server.
*
@ -125,44 +260,4 @@ public class API {
public static String formatTimeStamp(String timeInMs) {
return FormatUtils.formatTimeStamp(timeInMs);
}
@Deprecated
public void cacheUserDataToInspectCache(UUID uuid) {
plugin.getInspectCache().cache(uuid);
}
@Deprecated
public String getPlayerHtmlAsString(UUID uuid) {
WebSocketServer server = plugin.getUiServer();
if (server != null) {
return server.getDataReqHandler().getInspectHtml(uuid);
}
DataRequestHandler reqH = new DataRequestHandler(plugin);
return reqH.getInspectHtml(uuid);
}
@Deprecated
public void updateAnalysisCache() {
plugin.getAnalysisCache().updateCache();
}
@Deprecated
public String getAnalysisHtmlAsString() {
WebSocketServer server = plugin.getUiServer();
if (server != null) {
return server.getDataReqHandler().getAnalysisHtml();
}
DataRequestHandler reqH = new DataRequestHandler(plugin);
return reqH.getAnalysisHtml();
}
@Deprecated
public UserData getUserDataFromInspectCache(UUID uuid) {
return plugin.getInspectCache().getFromCache(uuid);
}
@Deprecated
public AnalysisData getAnalysisDataFromCache() {
return plugin.getAnalysisCache().getData();
}
}

View File

@ -10,10 +10,10 @@ 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.data.additional.vault.VaultHook;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
/**
@ -25,16 +25,9 @@ import main.java.com.djrapitops.plan.utilities.HtmlUtils;
public class HookHandler {
private List<PluginData> additionalDataSources;
private AdvancedAchievementsHook advancedAchievementsHook;
private EssentialsHook essentialsHook;
private FactionsHook factionsHook;
private OnTimeHook onTimeHook;
private TownyHook townyHook;
/**
* Class constructor, hooks to plugins.
*
* @param plan Current instance of Plan.
*/
public HookHandler() {
additionalDataSources = new ArrayList<>();
@ -57,7 +50,7 @@ public class HookHandler {
}
/**
* Used to get all PluginData objects in a list.
* Used to get all PluginData objects currently registered.
*
* @return List of PluginData objects.
*/
@ -65,43 +58,53 @@ public class HookHandler {
return additionalDataSources;
}
/**
*
*/
public void reloadHooks() {
additionalDataSources.clear();
hook();
}
private void hook() {
try {
advancedAchievementsHook = new AdvancedAchievementsHook(this);
AdvancedAchievementsHook advancedAchievementsHook = new AdvancedAchievementsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
essentialsHook = new EssentialsHook(this);
EssentialsHook essentialsHook = new EssentialsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
factionsHook = new FactionsHook(this);
FactionsHook factionsHook = new FactionsHook(this);
} catch (NoClassDefFoundError e) {
}
try {
onTimeHook = new OnTimeHook(this);
OnTimeHook onTimeHook = new OnTimeHook(this);
} catch (NoClassDefFoundError e) {
}
try {
townyHook = new TownyHook(this);
TownyHook townyHook = new TownyHook(this);
} catch (NoClassDefFoundError e) {
}
try {
VaultHook vaultHook = new VaultHook(this);
} catch (NoClassDefFoundError e) {
}
}
/**
* Used to get the Layout with PluginData placeholders to replace %plugins%
* placeholder on analysis.hmtl.
*
* @return html, getPluginsTabLayout-method
* @see HtmlUtils
*/
public String getPluginsTabLayoutForAnalysis() {
List<String> pluginNames = getPluginNamesAnalysis();
Map<String, List<String>> placeholders = getPlaceholdersAnalysis();
return HtmlUtils.getPluginsTabLayout(pluginNames, placeholders);
}
/**
* Used to get the Layout with PluginData placeholders to replace %plugins%
* placeholder on player.hmtl.
*
* @return html, getPluginsTabLayout-method
* @see HtmlUtils
*/
public String getPluginsTabLayoutForInspect() {
List<String> pluginNames = getPluginNamesInspect();
Map<String, List<String>> placeholders = getPlaceholdersInspect();

View File

@ -9,19 +9,82 @@ import java.util.UUID;
import main.java.com.djrapitops.plan.ui.Html;
/**
* This is an abstract class that can be used to add data from a plugin to the
* "Plugins"-tab of Analysis & Inspect pages.
*
* API-section of documentation has examples on the usage of this class & how to
* register objects extending this class.
*
* @author Rsl1122
*/
public abstract class PluginData {
/**
* Placeholder string, for example "stepsTaken". This will be used when
* building the structure of the Plugins tab.
*
* The complete placeholder also includes the plugin name & if analysis is
* run, a modifier.
*
* Second parameter of any super constructor.
*/
protected String placeholder;
/**
* Name of the plugin the data is coming from.
*
* All datasources with the same sourcePlugin will be placed in the same
* "box" in the "Plugins" tab.
*
* A box has a max height of 600px, and higher than that will add a
* scrollbar.
*
* First parameter of any super constructor.
*/
protected String sourcePlugin;
/**
* Determines if the datapoint should only be used for the analysis page.
*
* If set to false, the datapoint will be added to the inspect page as well.
*/
protected boolean analysisOnly;
/**
* Font Awesome icon name.
*
* http://fontawesome.io/icons/
*/
protected String icon;
/**
* Prefix shown before the data, for example "Steps taken: ".
*/
protected String prefix;
/**
* Suffix shown after the data, for example " steps".
*/
protected String suffix;
/**
* A list containing the AnalysisType enums that determine what should be
* done with the data on the analysis page.
*/
protected List<AnalysisType> analysisTypes;
/**
* Main constructor.
*
* Defaults analysisOnly to true.
*
* Defaults icon, prefix & suffix to "".
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
* @param analysisTypes A list containing the AnalysisType enums that
* determine what should be done with the data on the analysis page
*/
public PluginData(String sourcePlugin, String placeholder, List<AnalysisType> analysisTypes) {
this.placeholder = placeholder;
this.sourcePlugin = sourcePlugin;
@ -32,58 +95,182 @@ public abstract class PluginData {
this.suffix = "";
}
/**
* Constructor for accepting single, multiple & arrays of AnalysisType.
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
* @param analysisTypes AnalysisType enums that determine what should be
* done with the data on the analysis page
*/
public PluginData(String sourcePlugin, String placeholder, AnalysisType... analysisTypes) {
this(sourcePlugin, placeholder, Arrays.asList(analysisTypes));
}
/**
* Constructor for Inspect-page only data point.
*
* analysisOnly will be set to false.
*
* @param sourcePlugin Name of the plugin the data is coming from
* @param placeholder Placeholder string, for example "stepsTaken"
*/
public PluginData(String sourcePlugin, String placeholder) {
this(sourcePlugin, placeholder, new ArrayList<>());
analysisOnly = false;
}
/**
* Returns the list of AnalysisTypes.
*
* Used by Analysis
*
* @return a list.
*/
public final List<AnalysisType> getAnalysisTypes() {
return analysisTypes;
}
/**
* This method should be used with the return values of
* getHtmlReplaceValue(String, UUID).
*
* It will add the div, icon, modifier, prefix & suffix to the value.
* Modifier is for example, if calculating AnalysisType.INT_AVG "Average ",
* it is a text that helps user understand that a calculation has been made.
*
* @param modifier For example "Average " - Determined by value of
* AnalysisType's modifier-variable.
* @param contents The data, number/string/html that should be placed on the
* page.
* @return a proper format for the html.
* @see AnalysisType
*/
public final String parseContainer(String modifier, String contents) {
return "<div class=\"plugin-data\">" + icon + modifier + prefix + contents + suffix + "</div>";
}
/**
* Used to get the full placeholder.
*
* Used to avoid conflicts with existing placeholders & placeholders of
* other plugins.
*
* @param modifier Modifier determined by AnalysisType's
* placeholderModifier-variable.
* @return for example "%StepCounter_stepsTaken_total%"
* @see AnalysisType
*/
public final String getPlaceholder(String modifier) {
return "%" + sourcePlugin + "_" + placeholder + modifier + "%";
}
/**
* Used to get the source plugin's name.
*
* @return for example "StepCounter"
*/
public final String getSourcePlugin() {
return sourcePlugin;
}
/**
* Used to get the string for the html page.
*
* parseContainer(modifierPrefix, value); should be used for all return
* values so that div, icon, prefix & suffix are added.
*
* This method is used when AnalysisType.HTML is set, or while getting the
* value for the inspect page.
*
* When using AnalysisType.HTML a random UUID is given, so it should be
* disregarded. modifierPrefix is empty in that case.
*
* @param modifierPrefix Modifier determined by AnalysisType's
* modifier-variable.
* @param uuid UUID of the player or random UUID if AnalysisType.HTML is
* used.
* @return html for the page.
*/
public abstract String getHtmlReplaceValue(String modifierPrefix, UUID uuid);
/**
* Used to get the value for analysis. The return value is determined by
* AnalysisType you have specified. If the AnalysisType's name has a BOOLEAN
* in it, Analysis will expect boolean values etc.
*
* If the Type & return value mismatch, exception is thrown and the result
* on the analysis page will say that error occurred as the value.
*
* If a player has no value a -1 should be returned in the case of a Number.
* -1 is excluded from the Average calculation's size & total.
*
* @param uuid UUID of the player the value belongs to.
* @return Long, Integer, Double, Boolean or String, return -1 if the player
* has no value.
*/
public abstract Serializable getValue(UUID uuid);
/**
* Used to set the prefix.
*
* @param prefix for example "Steps Taken: " or a Html start tag.
*/
public final void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Used to set the suffix.
*
* @param suffix for example " steps" or a html end tag.
*/
public final void setSuffix(String suffix) {
this.suffix = suffix;
}
/**
* Used to set the Font Awesome icon.
*
* @param iconName Icon's name http://fontawesome.io/icons/
*/
public final void setIcon(String iconName) {
this.icon = Html.FONT_AWESOME_ICON.parse(iconName) + " ";
}
/**
* Used to set the analysisOnly parameter.
*
* true: only used for Analysis page false: used for both if AnalysisTypes
* specified, if no AnalysisTypes are specified only used for Inspect page.
*
* @param analysisOnly true/false
*/
public final void setAnalysisOnly(boolean analysisOnly) {
this.analysisOnly = analysisOnly;
}
/**
* Used to get the analysisOnly parameter.
*
* @return true/false
*/
public final boolean analysisOnly() {
return analysisOnly;
}
/**
* Used to get the prefix.
* @return example: "Steps Taken "
*/
public final String getPrefix() {
return prefix;
}
/**
* Used to get the suffix.
* @return example: " steps"
*/
public final String getSuffix() {
return suffix;
}

View File

@ -13,7 +13,6 @@ public class FactionsFaction extends PluginData {
public FactionsFaction() {
super("Factions", "faction");
super.setAnalysisOnly(false);
super.setIcon("flag");
super.setPrefix("Faction: ");
}
@ -21,7 +20,11 @@ public class FactionsFaction extends PluginData {
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
MPlayer mPlayer = MPlayer.get(uuid);
return parseContainer("", mPlayer.getFactionName());
String faction = mPlayer.getFactionName();
if (faction.isEmpty()) {
return parseContainer("", "No Faction.");
}
return parseContainer("", faction);
}
@Override

View File

@ -15,7 +15,6 @@ public class FactionsMaxPower extends PluginData {
public FactionsMaxPower() {
super("Factions", "maxpower");
super.setAnalysisOnly(false);
super.setPrefix("Max Power: ");
}

View File

@ -0,0 +1,47 @@
package main.java.com.djrapitops.plan.data.additional.vault;
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;
import main.java.com.djrapitops.plan.utilities.FormatUtils;
import net.milkbowl.vault.economy.Economy;
import static org.bukkit.Bukkit.getOfflinePlayer;
import org.bukkit.OfflinePlayer;
/**
*
* @author Rsl1122
*/
public class EconomyBalance extends PluginData {
private Economy econ;
public EconomyBalance(Economy econ) {
super("Vault", "balance", AnalysisType.DOUBLE_TOTAL, AnalysisType.DOUBLE_AVG);
this.econ = econ;
super.setAnalysisOnly(false);
super.setIcon("money");
super.setPrefix("Balance: ");
super.setSuffix(" "+FormatUtils.removeNumbers(econ.format(0)));
}
@Override
public String getHtmlReplaceValue(String modifierPrefix, UUID uuid) {
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
parseContainer(modifierPrefix, this.econ.getBalance(p)+"");
}
return "";
}
@Override
public Serializable getValue(UUID uuid) {
OfflinePlayer p = getOfflinePlayer(uuid);
if (p.hasPlayedBefore()) {
return this.econ.getBalance(p);
}
return -1;
}
}

View File

@ -0,0 +1,39 @@
package main.java.com.djrapitops.plan.data.additional.vault;
import main.java.com.djrapitops.plan.data.additional.Hook;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import net.milkbowl.vault.economy.Economy;
import static org.bukkit.Bukkit.getServer;
/**
*
* @author Rsl1122
*/
public class VaultHook extends Hook {
private Economy econ;
/**
* Hooks to Vault plugin
*
*/
public VaultHook(HookHandler hookH) throws NoClassDefFoundError {
super("net.milkbowl.vault.Vault");
if (!enabled) {
return;
}
try {
this.econ = getServer().getServicesManager().getRegistration(Economy.class).getProvider();
enabled = true;
} catch (Throwable e) {
enabled = false;
}
if (!enabled) {
return;
}
hookH.addPluginDataSource(new EconomyBalance(econ));
}
}

View File

@ -12,7 +12,6 @@ import main.java.com.djrapitops.plan.Plan;
*/
public class SQLiteDB extends SQLDB {
private final Plan plugin;
private final String dbName;
/**
@ -31,8 +30,6 @@ public class SQLiteDB extends SQLDB {
*/
public SQLiteDB(Plan plugin, String dbName) {
super(plugin, false);
this.plugin = plugin;
this.dbName = dbName;
}

View File

@ -72,6 +72,14 @@ public class FormatUtils {
public static String removeLetters(String dataPoint) {
return dataPoint.replaceAll("[^\\d.]", "");
}
public static String removeNumbers(String dataPoint) {
for (char c : removeLetters(dataPoint).toCharArray()) {
dataPoint = dataPoint.replace(c+"", "");
}
dataPoint = dataPoint.replace(" ", "");
return dataPoint;
}
// Formats long in milliseconds into d:h:m:s string
private static String turnMsLongToString(long ms) {

View File

@ -522,11 +522,6 @@ table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sor
</div>
</div>
</div>
<div class="columns">
<div class="about box column">
</div>
</div>
</div>
<div class="tab">
<div class="columns">

View File

@ -1,7 +1,7 @@
name: Plan
author: Rsl1122
main: main.java.com.djrapitops.plan.Plan
version: 3.0.2
version: 3.1.0
softdepend:
- OnTime
@ -9,7 +9,6 @@ softdepend:
- Towny
- Vault
- Factions
- SuperbVote
- AdvancedAchievements
commands:
@ -19,9 +18,15 @@ commands:
inspect:
usage: /plan inspect <name>
description: inspect player data
qinspect:
usage: /plan qinspect <name>
description: inspect player data & view in chatbox
analyze:
usage: /plan analyze
description: analyze all players' data, add -refresh to refresh analysis.
description: analyze all players' data
qanalyze:
usage: /plan qanalyze
description: analyze all players' data & view in chatbox
reload:
usage: /plan reload
description: reload plugin config
@ -42,9 +47,17 @@ permissions:
plan.inspect.other:
description: Allows you to check other players' player data.
default: op
plan.qinspect:
description: Allows you to check your player data.
default: op
plan.qinspect.other:
description: Allows you to check other players' player data.
plan.analyze:
description: Allows you to check analysed data about all players.
default: op
plan.qanalyze:
description: Allows you to check analysed data about all players.
default: op
plan.reload:
description: Allows to reload plugin config
default: op
@ -64,17 +77,20 @@ permissions:
plan.basic:
children:
plan.?: true
plan.inspect: true
plan.inspect: true
plan.qinspect: true
plan.advanced:
childer:
plan.basic: true
plan.info: true
plan.analyze: true
plan.info: true
plan.qanalyze: true
plan.staff:
children:
plan.search: true
plan.advanced: true
plan.analyze: true
plan.inspect.other: true
plan.qinspect.other: true
plan.reload: true
plan.*:
children:

View File

@ -82,6 +82,22 @@ public class FormatUtilsTest {
assertEquals(expResult, result);
}
@Test
public void testRemoveNumbers() {
String dataPoint = "34532453.5 $";
String expResult = "$";
String result = FormatUtils.removeNumbers(dataPoint);
assertEquals(expResult, result);
}
@Test
public void testRemoveNumbers2() {
String dataPoint = "l43r4545tl43 4.5";
String expResult = "lrtl";
String result = FormatUtils.removeNumbers(dataPoint);
assertEquals(expResult, result);
}
/**
*
*/

View File

@ -55,12 +55,12 @@ public class StepCounterSteps extends PluginData {
}
```
**At the moment registering this data source will have no effect.** It is disregarded because of two variables inside PluginData:
**At the moment registering this data source will have Only show up on Inspect page.** It is disregarded on analysis page. Two variables inside PluginData determine what should be done with the datapoint:
- List<AnalysisType> analysisTypes
- boolean analysisOnly
analysisOnly is 'true' by default. - Thus Inspect page will ignore the data.
analysisOnly is 'true' by default. - Thus Inspect page will ignore the data. (Except when using a super constructor without AnalysisType parameters. - then 'false'.)
analysisTypes is empty. - Thus Analysis page will ignore the data.
## Registering the data point

View File

@ -0,0 +1,21 @@
![Player Analytics](https://puu.sh/t8vin.png)
# Links to Dependencies
In order to fork the project, some dependencies need to be installed locally.
- [CraftBukkit-1.11.2](https://www.spigotmc.org/wiki/buildtools/)
- [Advanced Achievements v5.1](https://www.spigotmc.org/resources/advanced-achievements.6239/)
- [Download](https://www.spigotmc.org/resources/advanced-achievements.6239/download?version=157933)
- [EssentialsX](https://www.spigotmc.org/resources/essentialsx.9089/)
- [Download (Jenkins)](https://ci.drtshock.net/job/essentialsx/)
- [Factions & MCore](https://www.spigotmc.org/resources/factions.1900/)
- [Download](https://www.spigotmc.org/resources/factions.1900/download?version=140245)
- [OnTime](https://dev.bukkit.org/projects/ontime)
- [Download](https://dev.bukkit.org/projects/ontime/files/latest)
- [Towny Advanced](http://towny.palmergames.com/)
- [Download](http://towny.palmergames.com/file-repo/Towny%20Advanced/Latest/)

View File

@ -1 +0,0 @@
version: 1.6.3