mirror of
https://github.com/PlaceholderAPI/PlaceholderAPI.git
synced 2024-11-22 18:46:20 +01:00
2.8.5
This commit is contained in:
commit
fbe0a03a8f
71
pom.xml
Normal file
71
pom.xml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>me.clip</groupId>
|
||||||
|
<artifactId>placeholderapi</artifactId>
|
||||||
|
|
||||||
|
<version>2.8.5</version>
|
||||||
|
<name>PlaceholderAPI</name>
|
||||||
|
<description>An awesome placeholder plugin</description>
|
||||||
|
<url>http://extendedclip.com</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>sonatype</id>
|
||||||
|
<url> https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.12.2-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<defaultGoal>clean package</defaultGoal>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.7.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<minimizeJar>true</minimizeJar>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
</project>
|
297
src/main/java/me/clip/placeholderapi/PlaceholderAPI.java
Normal file
297
src/main/java/me/clip/placeholderapi/PlaceholderAPI.java
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
package me.clip.placeholderapi;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.events.PlaceholderHookUnloadEvent;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.expansion.Relational;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class PlaceholderAPI {
|
||||||
|
|
||||||
|
private PlaceholderAPI() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
|
||||||
|
private final static Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
|
||||||
|
private final static Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern.compile("[%](rel_)([^%]+)[%]");
|
||||||
|
private final static Map<String, PlaceholderHook> placeholders = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unregister ALL placeholder hooks that are currently registered
|
||||||
|
*/
|
||||||
|
protected static void unregisterAll() {
|
||||||
|
unregisterAllExpansions();
|
||||||
|
placeholders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unregister all expansions
|
||||||
|
*/
|
||||||
|
public static void unregisterAllExpansions() {
|
||||||
|
if (placeholders.isEmpty()) return;
|
||||||
|
getPlaceholders().forEach((key, value) -> {
|
||||||
|
if (value instanceof PlaceholderExpansion) {
|
||||||
|
Bukkit.getPluginManager().callEvent(new PlaceholderHookUnloadEvent(key, value));
|
||||||
|
unregisterPlaceholderHook(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if a specific placeholder identifier is currently registered
|
||||||
|
* @param identifier to check
|
||||||
|
* @return true if identifier is already registered
|
||||||
|
*/
|
||||||
|
public static boolean isRegistered(String identifier) {
|
||||||
|
return !placeholders.isEmpty() && getRegisteredIdentifiers().stream().filter(id -> id.equalsIgnoreCase(identifier)).findFirst().orElse(null) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new placeholder hook
|
||||||
|
* @param identifier Identifier of the placeholder -> "%(identifier)_(args...)%
|
||||||
|
*
|
||||||
|
* @param placeholderHook implementing class that contains the onPlaceholderRequest method which is called when a value is needed for the specific placeholder
|
||||||
|
* @return true if the hook was successfully registered, false if there is already a hook registered for the specified identifier
|
||||||
|
*/
|
||||||
|
public static boolean registerPlaceholderHook(String identifier, PlaceholderHook placeholderHook) {
|
||||||
|
Validate.notNull(identifier, "Identifier can not be null");
|
||||||
|
Validate.notNull(placeholderHook, "Placeholderhook can not be null");
|
||||||
|
if (isRegistered(identifier)) return false;
|
||||||
|
//test
|
||||||
|
placeholders.put(identifier.toLowerCase(), placeholderHook);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unregister a placeholder hook by identifier
|
||||||
|
* @param identifier the identifier for the placeholder hook to unregister
|
||||||
|
* @return true if the placeholder hook was successfully unregistered, false if there was no placeholder hook registered for the identifier specified
|
||||||
|
*/
|
||||||
|
public static boolean unregisterPlaceholderHook(String identifier) {
|
||||||
|
Validate.notNull(identifier, "Identifier can not be null");
|
||||||
|
return placeholders.remove(identifier.toLowerCase()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all registered placeholder identifiers
|
||||||
|
* @return all registered placeholder identifiers
|
||||||
|
*/
|
||||||
|
public static Set<String> getRegisteredIdentifiers() {
|
||||||
|
if (placeholders.isEmpty()) return new HashSet<>();
|
||||||
|
return new HashSet<>(placeholders.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get map of registered placeholders
|
||||||
|
* @return copy of the internal placeholder map
|
||||||
|
*/
|
||||||
|
public static Map<String, PlaceholderHook> getPlaceholders() {
|
||||||
|
return new HashMap<>(placeholders);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if a String contains any PlaceholderAPI placeholders
|
||||||
|
* @param text String to check
|
||||||
|
* @return true if String contains any registered placeholder identifiers, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean containsPlaceholders(String text) {
|
||||||
|
return text != null && PLACEHOLDER_PATTERN.matcher(text).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if a String contains any PlaceholderAPI bracket placeholders
|
||||||
|
* @param text String to check
|
||||||
|
* @return true if String contains any registered placeholder identifiers, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean containsBracketPlaceholders(String text) {
|
||||||
|
return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set placeholders in the list<String> text provided
|
||||||
|
* placeholders are matched with the pattern {<placeholder>} when set with this method
|
||||||
|
* @param p Player to parse the placeholders for
|
||||||
|
* @param text text to set the placeholder values in
|
||||||
|
* @return modified list with all placeholders set to the corresponding values
|
||||||
|
*/
|
||||||
|
public static List<String> setBracketPlaceholders(Player p, List<String> text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
List<String> temp = new ArrayList<>();
|
||||||
|
text.forEach(line -> {
|
||||||
|
temp.add(setBracketPlaceholders(p, line));
|
||||||
|
});
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set placeholders in the text specified
|
||||||
|
* placeholders are matched with the pattern {<placeholder>} when set with this method
|
||||||
|
* @param player Player to parse the placeholders for
|
||||||
|
* @param text text to parse the placeholder values to
|
||||||
|
* @return modified text with all placeholders set to the corresponding values
|
||||||
|
*/
|
||||||
|
public static String setBracketPlaceholders(Player player, String text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
if (placeholders.isEmpty()) return colorize(text);
|
||||||
|
Matcher placeholderMatcher = BRACKET_PLACEHOLDER_PATTERN.matcher(text);
|
||||||
|
Map<String, PlaceholderHook> hooks = getPlaceholders();
|
||||||
|
while (placeholderMatcher.find()) {
|
||||||
|
String format = placeholderMatcher.group(1);
|
||||||
|
int index = format.indexOf("_");
|
||||||
|
if (index == -1 || index >= format.length()) continue;
|
||||||
|
String identifier = format.substring(0, index).toLowerCase();
|
||||||
|
String params = format.substring(index+1);
|
||||||
|
if (hooks.containsKey(identifier)) {
|
||||||
|
String value = hooks.get(identifier).onPlaceholderRequest(player, params);
|
||||||
|
if (value != null) {
|
||||||
|
text = text.replaceAll("\\{"+format+"\\}", Matcher.quoteReplacement(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return colorize(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set placeholders in the list<String> text provided
|
||||||
|
* placeholders are matched with the pattern %(identifier)_(params)>% when set with this method
|
||||||
|
* @param p Player to parse the placeholders for
|
||||||
|
* @param text text to parse the placeholder values in
|
||||||
|
* @return modified list with all placeholders set to the corresponding values
|
||||||
|
*/
|
||||||
|
public static List<String> setPlaceholders(Player p, List<String> text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
List<String> temp = new ArrayList<>();
|
||||||
|
text.forEach(line -> {
|
||||||
|
temp.add(setPlaceholders(p, line));
|
||||||
|
});
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set placeholders in the text specified
|
||||||
|
* placeholders are matched with the pattern %<(identifier)_(params)>% when set with this method
|
||||||
|
* @param player Player to parse the placeholders for
|
||||||
|
* @param text text to parse the placeholder values to
|
||||||
|
* @return text with all placeholders set to the corresponding values
|
||||||
|
*/
|
||||||
|
public static String setPlaceholders(Player player, String text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
if (placeholders.isEmpty()) return colorize(text);
|
||||||
|
Matcher m = PLACEHOLDER_PATTERN.matcher(text);
|
||||||
|
Map<String, PlaceholderHook> hooks = getPlaceholders();
|
||||||
|
while (m.find()) {
|
||||||
|
String format = m.group(1);
|
||||||
|
int index = format.indexOf("_");
|
||||||
|
if (index <= 0 || index >= format.length()) continue;
|
||||||
|
String identifier = format.substring(0, index).toLowerCase();
|
||||||
|
String params = format.substring(index+1);
|
||||||
|
if (hooks.containsKey(identifier)) {
|
||||||
|
String value = hooks.get(identifier).onPlaceholderRequest(player, params);
|
||||||
|
if (value != null) {
|
||||||
|
text = text.replace("%"+format+"%", Matcher.quoteReplacement(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set relational placeholders in the text specified
|
||||||
|
* placeholders are matched with the pattern %<rel_(identifier)_(params)>% when set with this method
|
||||||
|
* @param one Player to compare
|
||||||
|
* @param two Player to compare
|
||||||
|
* @param text text to parse the placeholder values to
|
||||||
|
* @return text with all relational placeholders set to the corresponding values
|
||||||
|
*/
|
||||||
|
public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
List<String> temp = new ArrayList<>();
|
||||||
|
text.forEach(line -> {
|
||||||
|
temp.add(setRelationalPlaceholders(one, two, line));
|
||||||
|
});
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set relational placeholders in the text specified
|
||||||
|
* placeholders are matched with the pattern %<rel_(identifier)_(params)>% when set with this method
|
||||||
|
* @param one Player to compare
|
||||||
|
* @param two Player to compare
|
||||||
|
* @param text text to parse the placeholder values to
|
||||||
|
* @return text with all relational placeholders set to the corresponding values
|
||||||
|
*/
|
||||||
|
public static String setRelationalPlaceholders(Player one, Player two, String text) {
|
||||||
|
if (text == null) return null;
|
||||||
|
if (placeholders.isEmpty()) return colorize(text);
|
||||||
|
Matcher m = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
|
||||||
|
Map<String, PlaceholderHook> hooks = getPlaceholders();
|
||||||
|
while (m.find()) {
|
||||||
|
String format = m.group(2);
|
||||||
|
int index = format.indexOf("_");
|
||||||
|
if (index <= 0 || index >= format.length()) continue;
|
||||||
|
String identifier = format.substring(0, index).toLowerCase();
|
||||||
|
String params = format.substring(index+1);
|
||||||
|
|
||||||
|
if (hooks.containsKey(identifier)) {
|
||||||
|
|
||||||
|
if (!(hooks.get(identifier) instanceof Relational)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Relational rel = (Relational) hooks.get(identifier);
|
||||||
|
String value = rel.onPlaceholderRequest(one, two, params);
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
text = text.replace("%rel_"+format+"%", Matcher.quoteReplacement(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pattern getPlaceholderPattern() {
|
||||||
|
return PLACEHOLDER_PATTERN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pattern getBracketPlaceholderPattern() {
|
||||||
|
return BRACKET_PLACEHOLDER_PATTERN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pattern getRelationalPlaceholderPattern() {
|
||||||
|
return RELATIONAL_PLACEHOLDER_PATTERN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String colorize(String text) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static Set<String> getRegisteredPlaceholderPlugins() {
|
||||||
|
return getRegisteredIdentifiers();
|
||||||
|
}
|
||||||
|
@Deprecated
|
||||||
|
public static Set<String> getExternalPlaceholderPlugins() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Deprecated
|
||||||
|
public static boolean registerPlaceholderHook(Plugin plugin, PlaceholderHook placeholderHook) {
|
||||||
|
return plugin != null && registerPlaceholderHook(plugin.getName(), placeholderHook);
|
||||||
|
}
|
||||||
|
@Deprecated
|
||||||
|
public static boolean unregisterPlaceholderHook(Plugin plugin) {
|
||||||
|
return plugin != null && unregisterPlaceholderHook(plugin.getName());
|
||||||
|
}
|
||||||
|
}
|
258
src/main/java/me/clip/placeholderapi/PlaceholderAPIPlugin.java
Normal file
258
src/main/java/me/clip/placeholderapi/PlaceholderAPIPlugin.java
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
package me.clip.placeholderapi;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
|
||||||
|
import me.clip.placeholderapi.expansion.ExpansionManager;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.expansion.Version;
|
||||||
|
import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
|
||||||
|
import me.clip.placeholderapi.updatechecker.UpdateChecker;
|
||||||
|
import me.clip.placeholderapi.util.TimeUtil;
|
||||||
|
import me.clip.placeholderapi.metrics.Metrics;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yes I have a shit load of work to do...
|
||||||
|
*
|
||||||
|
* @author Ryan McCarthy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PlaceholderAPIPlugin extends JavaPlugin {
|
||||||
|
|
||||||
|
private static PlaceholderAPIPlugin instance;
|
||||||
|
|
||||||
|
private PlaceholderAPIConfig config;
|
||||||
|
|
||||||
|
private ExpansionManager expansionManager;
|
||||||
|
|
||||||
|
private ExpansionCloudManager expansionCloud;
|
||||||
|
|
||||||
|
private static SimpleDateFormat dateFormat;
|
||||||
|
|
||||||
|
private static String booleanTrue;
|
||||||
|
|
||||||
|
private static String booleanFalse;
|
||||||
|
|
||||||
|
private static Version serverVersion;
|
||||||
|
|
||||||
|
private long startTime;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
instance = this;
|
||||||
|
serverVersion = getVersion();
|
||||||
|
config = new PlaceholderAPIConfig(this);
|
||||||
|
expansionManager = new ExpansionManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
config.loadDefConfig();
|
||||||
|
setupOptions();
|
||||||
|
setupCommands();
|
||||||
|
new PlaceholderListener(this);
|
||||||
|
getLogger().info("Placeholder expansion registration initializing...");
|
||||||
|
expansionManager.registerAllExpansions();
|
||||||
|
if (config.checkUpdates()) {
|
||||||
|
new UpdateChecker(this);
|
||||||
|
}
|
||||||
|
if (config.isCloudEnabled()) {
|
||||||
|
enableCloud();
|
||||||
|
}
|
||||||
|
setupMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
disableCloud();
|
||||||
|
PlaceholderAPI.unregisterAll();
|
||||||
|
expansionManager.clean();
|
||||||
|
expansionManager = null;
|
||||||
|
Bukkit.getScheduler().cancelTasks(this);
|
||||||
|
serverVersion = null;
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reloadConf(CommandSender s) {
|
||||||
|
boolean cloudEnabled = this.expansionCloud != null;
|
||||||
|
expansionManager.clean();
|
||||||
|
PlaceholderAPI.unregisterAllExpansions();
|
||||||
|
reloadConfig();
|
||||||
|
saveConfig();
|
||||||
|
setupOptions();
|
||||||
|
expansionManager.registerAllExpansions();
|
||||||
|
if (!config.isCloudEnabled()) {
|
||||||
|
disableCloud();
|
||||||
|
} else if (!cloudEnabled) {
|
||||||
|
enableCloud();
|
||||||
|
}
|
||||||
|
s.sendMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.getRegisteredIdentifiers().size() + " &aplaceholder hooks successfully registered!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupCommands() {
|
||||||
|
if (serverVersion != null && serverVersion.isSpigot()) {
|
||||||
|
getCommand("placeholderapi").setExecutor(new me.clip.placeholderapi.commands.spigot.PlaceholderAPICommands(this));
|
||||||
|
} else {
|
||||||
|
getCommand("placeholderapi").setExecutor(new me.clip.placeholderapi.commands.bukkit.PlaceholderAPICommands(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupOptions() {
|
||||||
|
booleanTrue = config.booleanTrue();
|
||||||
|
if (booleanTrue == null) {
|
||||||
|
booleanTrue = "true";
|
||||||
|
}
|
||||||
|
booleanFalse = config.booleanFalse();
|
||||||
|
if (booleanFalse == null) {
|
||||||
|
booleanFalse = "false";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dateFormat = new SimpleDateFormat(config.dateFormat());
|
||||||
|
} catch (Exception e) {
|
||||||
|
dateFormat = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMetrics() {
|
||||||
|
Metrics m = new Metrics(this);
|
||||||
|
m.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", () -> getExpansionCloud() != null ? "yes" : "no"));
|
||||||
|
|
||||||
|
m.addCustomChart(new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
|
||||||
|
|
||||||
|
m.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> {
|
||||||
|
Map<String, Integer> map = new HashMap<>();
|
||||||
|
Map<String, PlaceholderHook> p = PlaceholderAPI.getPlaceholders();
|
||||||
|
|
||||||
|
if (!p.isEmpty()) {
|
||||||
|
|
||||||
|
for (PlaceholderHook hook : p.values()) {
|
||||||
|
if (hook instanceof PlaceholderExpansion) {
|
||||||
|
PlaceholderExpansion ex = (PlaceholderExpansion) hook;
|
||||||
|
map.put(ex.getPlugin() == null ? ex.getIdentifier()
|
||||||
|
: ex.getPlugin(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Version getVersion() {
|
||||||
|
String v = "unknown";
|
||||||
|
boolean spigot = false;
|
||||||
|
try {
|
||||||
|
v = Bukkit.getServer().getClass().getPackage().getName()
|
||||||
|
.split("\\.")[3];
|
||||||
|
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Class.forName("org.spigotmc.SpigotConfig");
|
||||||
|
Class.forName("net.md_5.bungee.api.chat.BaseComponent");
|
||||||
|
spigot = true;
|
||||||
|
} catch (ExceptionInInitializerError | ClassNotFoundException exception) {
|
||||||
|
}
|
||||||
|
return new Version(v, spigot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enableCloud() {
|
||||||
|
if (expansionCloud == null) {
|
||||||
|
expansionCloud = new ExpansionCloudManager(this);
|
||||||
|
expansionCloud.fetch();
|
||||||
|
} else {
|
||||||
|
expansionCloud.clean();
|
||||||
|
expansionCloud.fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableCloud() {
|
||||||
|
if (expansionCloud != null) {
|
||||||
|
expansionCloud.clean();
|
||||||
|
expansionCloud = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the static instance of the main class for PlaceholderAPI. This class
|
||||||
|
* is not the actual API class, this is the main class that extends
|
||||||
|
* JavaPlugin. For most API methods, use static methods available from the
|
||||||
|
* class: {@link PlaceholderAPI}
|
||||||
|
*
|
||||||
|
* @return PlaceholderAPIPlugin instance
|
||||||
|
*/
|
||||||
|
public static PlaceholderAPIPlugin getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configurable {@linkplain SimpleDateFormat} object that is used to
|
||||||
|
* parse time for generic time based placeholders
|
||||||
|
*
|
||||||
|
* @return date format
|
||||||
|
*/
|
||||||
|
public static SimpleDateFormat getDateFormat() {
|
||||||
|
return dateFormat != null ? dateFormat : new SimpleDateFormat(
|
||||||
|
"MM/dd/yy HH:mm:ss");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configurable {@linkplain String} value that should be returned
|
||||||
|
* when a boolean is true
|
||||||
|
*
|
||||||
|
* @return string value of true
|
||||||
|
*/
|
||||||
|
public static String booleanTrue() {
|
||||||
|
return booleanTrue != null ? booleanTrue : "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configurable {@linkplain String} value that should be returned
|
||||||
|
* when a boolean is false
|
||||||
|
*
|
||||||
|
* @return string value of false
|
||||||
|
*/
|
||||||
|
public static String booleanFalse() {
|
||||||
|
return booleanFalse != null ? booleanFalse : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Version getServerVersion() {
|
||||||
|
return serverVersion != null ? serverVersion : getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the configuration class for PlaceholderAPI.
|
||||||
|
*
|
||||||
|
* @return PlaceholderAPIConfig instance
|
||||||
|
*/
|
||||||
|
public PlaceholderAPIConfig getPlaceholderAPIConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpansionManager getExpansionManager() {
|
||||||
|
return expansionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpansionCloudManager getExpansionCloud() {
|
||||||
|
return expansionCloud;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUptime() {
|
||||||
|
return TimeUtil.getTime((int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getUptimeMillis() {
|
||||||
|
return (System.currentTimeMillis() - startTime);
|
||||||
|
}
|
||||||
|
}
|
14
src/main/java/me/clip/placeholderapi/PlaceholderHook.java
Normal file
14
src/main/java/me/clip/placeholderapi/PlaceholderHook.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package me.clip.placeholderapi;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public abstract class PlaceholderHook {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called when a placeholder is requested from this PlaceholderHook
|
||||||
|
* @param p Player requesting the placeholder value for, null if not needed for a player
|
||||||
|
* @param params String passed for the placeholder hook to determine what value to return
|
||||||
|
* @return value for the requested player and params
|
||||||
|
*/
|
||||||
|
public abstract String onPlaceholderRequest(Player p, String params);
|
||||||
|
}
|
138
src/main/java/me/clip/placeholderapi/PlaceholderListener.java
Normal file
138
src/main/java/me/clip/placeholderapi/PlaceholderListener.java
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package me.clip.placeholderapi;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.events.PlaceholderHookUnloadEvent;
|
||||||
|
import me.clip.placeholderapi.expansion.Cacheable;
|
||||||
|
import me.clip.placeholderapi.expansion.Cleanable;
|
||||||
|
import me.clip.placeholderapi.expansion.ExpansionManager;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.expansion.Taskable;
|
||||||
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
|
import me.clip.placeholderapi.external.EZPlaceholderHook;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.event.server.PluginDisableEvent;
|
||||||
|
import org.bukkit.event.server.PluginEnableEvent;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public class PlaceholderListener implements Listener {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
public PlaceholderListener(PlaceholderAPIPlugin instance) {
|
||||||
|
plugin = instance;
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInternalUnload(PlaceholderHookUnloadEvent event) {
|
||||||
|
|
||||||
|
if (event.getHook() instanceof Listener) {
|
||||||
|
HandlerList.unregisterAll((Listener)event.getHook());
|
||||||
|
plugin.getLogger().info("Unregistered event listener for placeholder expansion: " + event.getHookName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getHook() instanceof Taskable) {
|
||||||
|
plugin.getLogger().info("Cancelling scheduled task for placeholder expansion: " + event.getHookName());
|
||||||
|
((Taskable) event.getHook()).stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getHook() instanceof Cacheable) {
|
||||||
|
((Cacheable) event.getHook()).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() != null) {
|
||||||
|
|
||||||
|
CloudExpansion ex = plugin.getExpansionCloud().getCloudExpansion(event.getHookName());
|
||||||
|
|
||||||
|
if (ex != null) {
|
||||||
|
ex.setHasExpansion(false);
|
||||||
|
ex.setShouldUpdate(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onEnable(PluginEnableEvent event) {
|
||||||
|
ExpansionManager m = plugin.getExpansionManager();
|
||||||
|
PlaceholderExpansion e = m.getCachedExpansion(event.getPlugin().getName().toLowerCase());
|
||||||
|
if (e != null && e.canRegister()) {
|
||||||
|
if (e.isRegistered() || m.registerExpansion(e)) {
|
||||||
|
m.removeCachedExpansion(e.getPlugin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH)
|
||||||
|
public void onPluginUnload(PluginDisableEvent e) {
|
||||||
|
|
||||||
|
String n = e.getPlugin().getName();
|
||||||
|
|
||||||
|
if (n == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.equals(plugin.getName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
|
||||||
|
|
||||||
|
for (Entry<String, PlaceholderHook> hook : hooks.entrySet()) {
|
||||||
|
|
||||||
|
PlaceholderHook i = hook.getValue();
|
||||||
|
|
||||||
|
if (i instanceof EZPlaceholderHook) {
|
||||||
|
|
||||||
|
EZPlaceholderHook h = (EZPlaceholderHook) i;
|
||||||
|
|
||||||
|
if (h.getPluginName() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h.getPluginName().equalsIgnoreCase(n)) {
|
||||||
|
if (PlaceholderAPI.unregisterPlaceholderHook(hook.getKey())) {
|
||||||
|
plugin.getLogger().info("Unregistered placeholder hook for placeholder: " + h.getPlaceholderName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (i instanceof PlaceholderExpansion) {
|
||||||
|
|
||||||
|
PlaceholderExpansion ex = (PlaceholderExpansion) i;
|
||||||
|
|
||||||
|
if (ex.getPlugin() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getPlugin().equalsIgnoreCase(n)) {
|
||||||
|
if (PlaceholderAPI.unregisterPlaceholderHook(hook.getKey())) {
|
||||||
|
plugin.getLogger().info("Unregistered placeholder expansion: " + ex.getIdentifier());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onQuit(PlayerQuitEvent e) {
|
||||||
|
|
||||||
|
Map<String, PlaceholderHook> placeholders = PlaceholderAPI.getPlaceholders();
|
||||||
|
|
||||||
|
if (placeholders.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PlaceholderHook hooks : placeholders.values()) {
|
||||||
|
if (hooks instanceof Cleanable) {
|
||||||
|
((Cleanable) hooks).cleanup(e.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,215 @@
|
|||||||
|
package me.clip.placeholderapi.commands.bukkit;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class ExpansionCloudCommands implements CommandExecutor {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
public ExpansionCloudCommands(PlaceholderAPIPlugin instance) {
|
||||||
|
plugin = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
Msg.msg(s, "&bExpansion cloud commands");
|
||||||
|
Msg.msg(s, " ");
|
||||||
|
Msg.msg(s, "&b/papi ecloud status");
|
||||||
|
Msg.msg(s, "&fView status of the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud list <all/author> (page)");
|
||||||
|
Msg.msg(s, "&fList all/author specific available expansions");
|
||||||
|
Msg.msg(s, "&b/papi ecloud info <expansion name>");
|
||||||
|
Msg.msg(s, "&fView information about a specific expansion available on the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud download <expansion name>");
|
||||||
|
Msg.msg(s, "&fDownload a specific expansion from the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud refresh");
|
||||||
|
Msg.msg(s, "&fFetch the most up to date list of expansions available.");
|
||||||
|
Msg.msg(s, "&b/papi ecloud clear");
|
||||||
|
Msg.msg(s, "&fClear the expansion cloud cache.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("refresh")) {
|
||||||
|
Msg.msg(s, "&aRefresh task started. Use &7/papi ecloud list all &fin a few!!");
|
||||||
|
plugin.getExpansionCloud().clean();
|
||||||
|
plugin.getExpansionCloud().fetch();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud().getCloudExpansions().isEmpty()) {
|
||||||
|
Msg.msg(s, "&7No cloud expansions are available at this time.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("clear")) {
|
||||||
|
plugin.getExpansionCloud().clean();
|
||||||
|
Msg.msg(s, "&aThe cloud cache has been cleared!!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("download")) {
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
Msg.msg(s, "&cAn expansion name must be specified!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
|
||||||
|
|
||||||
|
if (expansion == null) {
|
||||||
|
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
|
||||||
|
|
||||||
|
if (loaded != null && loaded.isRegistered()) {
|
||||||
|
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&aAttempting download of expansion &f" + expansion.getName());
|
||||||
|
|
||||||
|
String player = ((s instanceof Player) ? s.getName() : null);
|
||||||
|
|
||||||
|
plugin.getExpansionCloud().downloadExpansion(player, expansion);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("status")) {
|
||||||
|
|
||||||
|
Msg.msg(s, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size()
|
||||||
|
+ " &bcloud expansions available to download on demand.");
|
||||||
|
Msg.msg(s, "&bA total of &f" + plugin.getExpansionCloud().getCloudAuthorCount()
|
||||||
|
+ " &bauthors have contributed to the expansion cloud.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (args[1].equalsIgnoreCase("info")) {
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
Msg.msg(s, "&cAn expansion name must be specified!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
|
||||||
|
|
||||||
|
if (expansion == null) {
|
||||||
|
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceholderExpansion exp = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
|
||||||
|
|
||||||
|
boolean enabled = false;
|
||||||
|
String version = null;
|
||||||
|
|
||||||
|
if (exp != null) {
|
||||||
|
enabled = exp.isRegistered();
|
||||||
|
version = exp.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&aExpansion: &f" + expansion.getName());
|
||||||
|
if (enabled) {
|
||||||
|
Msg.msg(s, "&aThis expansion is currently enabled!");
|
||||||
|
Msg.msg(s, "&bYour version&7: &f" + version);
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&bCloud version&7: &f" + expansion.getVersion());
|
||||||
|
Msg.msg(s, "&bAuthor&7: &f" + expansion.getAuthor());
|
||||||
|
|
||||||
|
String desc = expansion.getVersion();
|
||||||
|
|
||||||
|
if (desc.indexOf("\n") > 0) {
|
||||||
|
for (String line : desc.split("\n")) {
|
||||||
|
Msg.msg(s, line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&bDownload with &7/papi ecloud download " + expansion.getName());
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args[1].equalsIgnoreCase("list")) {
|
||||||
|
|
||||||
|
int page = 1;
|
||||||
|
|
||||||
|
String author;
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
Msg.msg(s, "&cIncorrect usage! &7/papi ecloud list <all/author> (page)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
author = args[2];
|
||||||
|
|
||||||
|
if (author.equalsIgnoreCase("all")) {
|
||||||
|
author = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length >= 4) {
|
||||||
|
try {
|
||||||
|
page = Integer.parseInt(args[3]);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
Msg.msg(s, "&cPage number must be an integer!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page < 1) {
|
||||||
|
Msg.msg(s, "&cPage must be greater than or equal to 1!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avail;
|
||||||
|
|
||||||
|
Map<Integer, CloudExpansion> ex;
|
||||||
|
|
||||||
|
if (author == null) {
|
||||||
|
ex = plugin.getExpansionCloud().getCloudExpansions();
|
||||||
|
} else {
|
||||||
|
ex = plugin.getExpansionCloud().getAllByAuthor(author);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex == null) {
|
||||||
|
Msg.msg(s, "&cNo expansions available" + (author != null ? " for author &f" + author : ""));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
avail = plugin.getExpansionCloud().getPagesAvailable(ex, 10);
|
||||||
|
|
||||||
|
if (page > avail) {
|
||||||
|
Msg.msg(s, "&cThere " + ((avail == 1) ? " is only &f" + avail + " &cpage available!" : "are only &f" + avail + " &cpages available!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&bExpansion cloud for &f" + (author != null ? author : "all available")+ " &8&m-- &r&bamount&7: &f" + ex.size() + " &bpage&7: &f" + page + "&7/&f" + avail);
|
||||||
|
|
||||||
|
ex = plugin.getExpansionCloud().getPage(ex, page);
|
||||||
|
|
||||||
|
for (Entry<Integer, CloudExpansion> expansion : ex.entrySet()) {
|
||||||
|
Msg.msg(s, "&b" + (expansion.getKey()+1) + "&7: &f" + expansion.getValue().getName() + " &8&m-- &r" + expansion.getValue().getLink());
|
||||||
|
}
|
||||||
|
Msg.msg(s, "&bDownload an expansion with &7/papi ecloud download <name>");
|
||||||
|
Msg.msg(s, "&bView more info on an expansion with &7/papi ecloud info <expansion>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,226 @@
|
|||||||
|
package me.clip.placeholderapi.commands.bukkit;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlaceholderAPICommands implements CommandExecutor {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
private ExpansionCloudCommands eCloud;
|
||||||
|
|
||||||
|
|
||||||
|
public PlaceholderAPICommands(PlaceholderAPIPlugin i) {
|
||||||
|
plugin = i;
|
||||||
|
eCloud = new ExpansionCloudCommands(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
Msg.msg(s, "PlaceholderAPI &7version &b&o"+plugin.getDescription().getVersion());
|
||||||
|
Msg.msg(s, "&fCreated by&7: &bextended_clip");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("help")) {
|
||||||
|
Msg.msg(s, "PlaceholderAPI &aHelp &e(&f" + plugin.getDescription().getVersion() + "&e)");
|
||||||
|
Msg.msg(s, "&b/papi");
|
||||||
|
Msg.msg(s, "&fView plugin info/version info");
|
||||||
|
Msg.msg(s, "&b/papi list");
|
||||||
|
Msg.msg(s, "&fList all placeholder expansions that are currently active");
|
||||||
|
Msg.msg(s, "&b/papi info <placeholder name>");
|
||||||
|
Msg.msg(s, "&fView information for a specific expansion");
|
||||||
|
Msg.msg(s, "&b/papi parse <...args>");
|
||||||
|
Msg.msg(s, "&fParse a String with placeholders");
|
||||||
|
Msg.msg(s, "&b/papi reload");
|
||||||
|
Msg.msg(s, "&fReload the config settings");
|
||||||
|
|
||||||
|
boolean enabled = plugin.getExpansionCloud() != null;
|
||||||
|
|
||||||
|
|
||||||
|
if (s.isOp()) {
|
||||||
|
if (!enabled) {
|
||||||
|
Msg.msg(s, "&b/papi enablecloud");
|
||||||
|
Msg.msg(s, "&fEnable the expansion cloud");
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, "&b/papi disablecloud");
|
||||||
|
Msg.msg(s, "&fDisable the expansion cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud");
|
||||||
|
Msg.msg(s, "&fView information about the PlaceholderAPI expansion cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud status");
|
||||||
|
Msg.msg(s, "&fView status of the PlaceholderAPI expansion cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud list <all/author> <page>");
|
||||||
|
Msg.msg(s, "&fList all available expansions");
|
||||||
|
Msg.msg(s, "&b/papi ecloud info <expansion name>");
|
||||||
|
Msg.msg(s, "&fView information about a specific expansion on the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud download <expansion name>");
|
||||||
|
Msg.msg(s, "&fDownload a specific expansion from the cloud");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("ecloud")) {
|
||||||
|
if (!s.isOp()) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() == null) {
|
||||||
|
Msg.msg(s, "&7The expansion cloud is not enabled!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eCloud.onCommand(s, c, label, args);
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("enablecloud")) {
|
||||||
|
|
||||||
|
if (!s.isOp()) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() != null) {
|
||||||
|
Msg.msg(s, "&7The cloud is already enabled!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.enableCloud();
|
||||||
|
plugin.getPlaceholderAPIConfig().setCloudEnabled(true);
|
||||||
|
Msg.msg(s, "&aThe cloud has been enabled!");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("disablecloud")) {
|
||||||
|
|
||||||
|
if (!s.isOp()) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() == null) {
|
||||||
|
Msg.msg(s, "&7The cloud is already disabled!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.disableCloud();
|
||||||
|
plugin.getPlaceholderAPIConfig().setCloudEnabled(false);
|
||||||
|
Msg.msg(s, "&aThe cloud has been disabled!");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("info")) {
|
||||||
|
|
||||||
|
if (!s.hasPermission("placeholderapi.info")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(args[1]);
|
||||||
|
|
||||||
|
if (ex == null) {
|
||||||
|
Msg.msg(s, "&cThere is no expansion loaded with the identifier: &f" + args[1]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&7Placeholder expansion info for: &f%" + ex.getIdentifier() + "_<identifier>%");
|
||||||
|
|
||||||
|
Msg.msg(s, "&7Status: " + (ex.isRegistered() ? "&aRegistered" : "&cNot registered"));
|
||||||
|
|
||||||
|
if (ex.getAuthor() != null) {
|
||||||
|
Msg.msg(s, "&7Created by: &f" + ex.getAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getVersion() != null) {
|
||||||
|
Msg.msg(s, "&7Version: &f" + ex.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getDescription() != null) {
|
||||||
|
Msg.msg(s, ex.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getLink() != null) {
|
||||||
|
Msg.msg(s, "&7Link: &f" + ex.getLink());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getPlugin() != null) {
|
||||||
|
Msg.msg(s, "&7Requires plugin: &f" + ex.getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getPlaceholders() != null) {
|
||||||
|
Msg.msg(s, "&8&m-- &r&7Placeholders &8&m--");
|
||||||
|
for (String placeholder : ex.getPlaceholders()) {
|
||||||
|
Msg.msg(s, placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (args[0].equalsIgnoreCase("parse")) {
|
||||||
|
|
||||||
|
if (!(s instanceof Player)) {
|
||||||
|
Msg.msg(s, "&cThis command can only be used in game!");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (!s.hasPermission("placeholderapi.parse")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Player p = (Player) s;
|
||||||
|
|
||||||
|
String parse = StringUtils.join(args, " ", 1, args.length);
|
||||||
|
|
||||||
|
Msg.msg(s, "&r" + PlaceholderAPI.setPlaceholders(p, parse));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (args[0].equalsIgnoreCase("reload")) {
|
||||||
|
|
||||||
|
if (s instanceof Player) {
|
||||||
|
if (!s.hasPermission("placeholderapi.reload")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&cClips &fPlaceholder&7API &bconfiguration reloaded!");
|
||||||
|
|
||||||
|
plugin.reloadConf(s);
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("list")) {
|
||||||
|
|
||||||
|
if (s instanceof Player) {
|
||||||
|
if (!s.hasPermission("placeholderapi.list")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> registered = PlaceholderAPI.getRegisteredIdentifiers();
|
||||||
|
|
||||||
|
if (registered.isEmpty()) {
|
||||||
|
Msg.msg(s, "&7There are no placeholder hooks currently registered!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Msg.msg(s, registered.size()+" &7Placeholder hooks registered:");
|
||||||
|
Msg.msg(s, registered.toString());
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, "&cIncorrect usage! &7/papi help");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,301 @@
|
|||||||
|
package me.clip.placeholderapi.commands.spigot;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class ExpansionCloudCommands implements CommandExecutor {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
public ExpansionCloudCommands(PlaceholderAPIPlugin instance) {
|
||||||
|
plugin = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
Msg.msg(s, "&bExpansion cloud commands");
|
||||||
|
Msg.msg(s, " ");
|
||||||
|
Msg.msg(s, "&b/papi ecloud status");
|
||||||
|
Msg.msg(s, "&fView status of the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud list <all/author> (page)");
|
||||||
|
Msg.msg(s, "&fList all/author specific available expansions");
|
||||||
|
Msg.msg(s, "&b/papi ecloud info <expansion name>");
|
||||||
|
Msg.msg(s, "&fView information about a specific expansion available on the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud download <expansion name>");
|
||||||
|
Msg.msg(s, "&fDownload a specific expansion from the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud refresh");
|
||||||
|
Msg.msg(s, "&fFetch the most up to date list of expansions available.");
|
||||||
|
Msg.msg(s, "&b/papi ecloud clear");
|
||||||
|
Msg.msg(s, "&fClear the expansion cloud cache.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("refresh") || args[1].equalsIgnoreCase("update") || args[1].equalsIgnoreCase("fetch")) {
|
||||||
|
Msg.msg(s, "&aRefresh task started. Use &f/papi ecloud list all &ain a few!!");
|
||||||
|
plugin.getExpansionCloud().clean();
|
||||||
|
plugin.getExpansionCloud().fetch();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud().getCloudExpansions().isEmpty()) {
|
||||||
|
Msg.msg(s, "&7No cloud expansions are available at this time.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("clear")) {
|
||||||
|
plugin.getExpansionCloud().clean();
|
||||||
|
Msg.msg(s, "&aThe cloud cache has been cleared!!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("status")) {
|
||||||
|
|
||||||
|
Msg.msg(s, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size() + " &bexpansions available on the cloud.");
|
||||||
|
Msg.msg(s, "&7A total of &f" + plugin.getExpansionCloud().getCloudAuthorCount()
|
||||||
|
+ " &7authors have contributed to the expansion cloud.");
|
||||||
|
if (plugin.getExpansionCloud().getToUpdateCount() > 0) {
|
||||||
|
Msg.msg(s, "&eYou have &f" + plugin.getExpansionCloud().getToUpdateCount()
|
||||||
|
+ " &eexpansions installed that have updates available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("info")) {
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
Msg.msg(s, "&cAn expansion name must be specified!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
|
||||||
|
|
||||||
|
if (expansion == null) {
|
||||||
|
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(s instanceof Player)) {
|
||||||
|
Msg.msg(s, (expansion.shouldUpdate() ? "&e" : "") + expansion.getName() + " &8&m-- &r" + expansion.getLink());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player p = (Player) s;
|
||||||
|
|
||||||
|
Msg.msg(s, "&bCloud expansion info for&7:" + (expansion.shouldUpdate() ? "&6" : (expansion.hasExpansion() ? "&e" : "")) + expansion.getName());
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append(expansion.getDescription());
|
||||||
|
|
||||||
|
if (expansion.getReleaseNotes() != null) {
|
||||||
|
sb.append("\n\n" + expansion.getReleaseNotes());
|
||||||
|
}
|
||||||
|
|
||||||
|
String hover = ChatColor.translateAlternateColorCodes('&', sb.toString());
|
||||||
|
|
||||||
|
if (expansion.hasExpansion()) {
|
||||||
|
if (expansion.shouldUpdate()) {
|
||||||
|
Msg.msg(s, "&6You have this expansion but there is a newer version available.");
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, "&aYou have the latest version of this expansion!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, "&7You do not have this expansion installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
sms(p, "&bAuthor&7: &f" + expansion.getAuthor(), hover, null);
|
||||||
|
sms(p, "&bVersion&7: &f" + expansion.getVersion(), hover, null);
|
||||||
|
if (expansion.getLastUpdate() > 1) {
|
||||||
|
sb.append("&bLast updated&7: &f" + expansion.getTimeSinceLastUpdate() + " ago");
|
||||||
|
}
|
||||||
|
sms(p, "&aClick here to download!", hover, expansion.getName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("list")) {
|
||||||
|
|
||||||
|
int page = 1;
|
||||||
|
|
||||||
|
String author;
|
||||||
|
boolean installed = false;
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
Msg.msg(s, "&cIncorrect usage! &7/papi ecloud list <all/author/installed> (page)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
author = args[2];
|
||||||
|
|
||||||
|
if (author.equalsIgnoreCase("all")) {
|
||||||
|
author = null;
|
||||||
|
} else if (author.equalsIgnoreCase("installed")) {
|
||||||
|
author = null;
|
||||||
|
installed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length >= 4) {
|
||||||
|
try {
|
||||||
|
page = Integer.parseInt(args[3]);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
Msg.msg(s, "&cPage number must be an integer!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page < 1) {
|
||||||
|
Msg.msg(s, "&cPage must be greater than or equal to 1!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avail;
|
||||||
|
|
||||||
|
Map<Integer, CloudExpansion> ex;
|
||||||
|
|
||||||
|
if (installed) {
|
||||||
|
ex = plugin.getExpansionCloud().getAllInstalled();
|
||||||
|
} else if (author == null) {
|
||||||
|
ex = plugin.getExpansionCloud().getCloudExpansions();
|
||||||
|
} else {
|
||||||
|
ex = plugin.getExpansionCloud().getAllByAuthor(author);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex == null || ex.isEmpty()) {
|
||||||
|
Msg.msg(s, "&cNo expansions available" + (author != null ? " for author &f" + author : ""));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
avail = plugin.getExpansionCloud().getPagesAvailable(ex, 10);
|
||||||
|
|
||||||
|
if (page > avail) {
|
||||||
|
Msg.msg(s, "&cThere " + ((avail == 1) ? " is only &f" + avail + " &cpage available!" : "are only &f" + avail + " &cpages available!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&bShowing expansions for&7: &f" + (author != null ? author : (installed ? "all installed" : "all available"))+ " &8&m--&r &bamount&7: &f" + ex.size() + " &bpage&7: &f" + page + "&7/&f" + avail);
|
||||||
|
|
||||||
|
ex = plugin.getExpansionCloud().getPage(ex, page);
|
||||||
|
|
||||||
|
if (ex == null) {
|
||||||
|
Msg.msg(s, "&cThere was a problem getting the requested page...");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&aGreen = Expansions you have");
|
||||||
|
Msg.msg(s, "&6Gold = Expansions which need updated");
|
||||||
|
|
||||||
|
if (!(s instanceof Player)) {
|
||||||
|
|
||||||
|
for (Entry<Integer, CloudExpansion> expansion : ex.entrySet()) {
|
||||||
|
if (expansion == null || expansion.getKey() == null || expansion.getValue() == null) continue;
|
||||||
|
Msg.msg(s, "&b" + (expansion.getKey()+1) + "&7: " + (expansion.getValue().shouldUpdate() ? "&6" : (expansion.getValue().hasExpansion() ? "&a" : "&7")) + expansion.getValue().getName() + " &8&m-- &r" + expansion.getValue().getLink());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player p = (Player) s;
|
||||||
|
|
||||||
|
for (Entry<Integer, CloudExpansion> expansion : ex.entrySet()) {
|
||||||
|
|
||||||
|
if (expansion == null || expansion.getValue() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (expansion.getValue().shouldUpdate()) {
|
||||||
|
sb.append("&6Click to update to the latest version of this expansion\n\n");
|
||||||
|
} else if (!expansion.getValue().hasExpansion()) {
|
||||||
|
sb.append("&bClick to download this expansion\n\n");
|
||||||
|
} else {
|
||||||
|
sb.append("&aYou have the latest version of this expansion\n\n");
|
||||||
|
}
|
||||||
|
sb.append("&bAuthor&7: &f" + expansion.getValue().getAuthor() + "\n");
|
||||||
|
sb.append("&bVersion&7: &f" + expansion.getValue().getVersion() + "\n");
|
||||||
|
if (expansion.getValue().getLastUpdate() > 1) {
|
||||||
|
sb.append("&bLast updated&7: &f" + expansion.getValue().getTimeSinceLastUpdate() + " ago\n");
|
||||||
|
}
|
||||||
|
if (expansion.getValue().getReleaseNotes() != null) {
|
||||||
|
sb.append("&bRelease Notes&7: &f" + expansion.getValue().getReleaseNotes() + "\n");
|
||||||
|
}
|
||||||
|
sb.append("\n" + expansion.getValue().getDescription());
|
||||||
|
|
||||||
|
String msg = ChatColor.translateAlternateColorCodes('&', "&b" + (expansion.getKey()+1) + "&7: " + (expansion.getValue().shouldUpdate() ? "&6" : (expansion.getValue().hasExpansion() ? "&a" : "")) + expansion.getValue().getName());
|
||||||
|
|
||||||
|
String hover = ChatColor.translateAlternateColorCodes('&', sb.toString());
|
||||||
|
|
||||||
|
sms(p, msg, hover, expansion.getValue().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (args[1].equalsIgnoreCase("download")) {
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
Msg.msg(s, "&cAn expansion name must be specified!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
|
||||||
|
|
||||||
|
if (expansion == null) {
|
||||||
|
Msg.msg(s, "&cNo expansion found with the name: &f" + args[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expansion.hasExpansion() && !expansion.shouldUpdate()) {
|
||||||
|
Msg.msg(s, "&aYou already have this expansion installed and your version is up to date!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
|
||||||
|
|
||||||
|
if (loaded != null && loaded.isRegistered()) {
|
||||||
|
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&aAttempting download of expansion &f" + expansion.getName());
|
||||||
|
|
||||||
|
String player = ((s instanceof Player) ? s.getName() : null);
|
||||||
|
|
||||||
|
plugin.getExpansionCloud().downloadExpansion(player, expansion);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&cIncorrect usage! &b/papi ecloud");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sms(Player p, String text, String hover, String link) {
|
||||||
|
TextComponent message = new TextComponent( ChatColor.translateAlternateColorCodes('&', text) );
|
||||||
|
if (hover != null) {
|
||||||
|
message.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(ChatColor.translateAlternateColorCodes('&', hover)).create() ) );
|
||||||
|
}
|
||||||
|
if (link != null) {
|
||||||
|
message.setClickEvent( new ClickEvent( ClickEvent.Action.SUGGEST_COMMAND, "/papi ecloud download " + link) );
|
||||||
|
}
|
||||||
|
p.spigot().sendMessage( message );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,258 @@
|
|||||||
|
package me.clip.placeholderapi.commands.spigot;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class PlaceholderAPICommands implements CommandExecutor {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
private ExpansionCloudCommands eCloud;
|
||||||
|
|
||||||
|
public PlaceholderAPICommands(PlaceholderAPIPlugin i) {
|
||||||
|
plugin = i;
|
||||||
|
eCloud = new ExpansionCloudCommands(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
Msg.msg(s, "PlaceholderAPI &7version &b&o"+plugin.getDescription().getVersion());
|
||||||
|
Msg.msg(s, "&fCreated by&7: &bextended_clip");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("help")) {
|
||||||
|
Msg.msg(s, "PlaceholderAPI &aHelp &e(&f" + plugin.getDescription().getVersion() + "&e)");
|
||||||
|
Msg.msg(s, "&b/papi");
|
||||||
|
Msg.msg(s, "&fView plugin info/version info");
|
||||||
|
Msg.msg(s, "&b/papi list");
|
||||||
|
Msg.msg(s, "&fList all placeholder expansions that are currently active");
|
||||||
|
Msg.msg(s, "&b/papi info <placeholder name>");
|
||||||
|
Msg.msg(s, "&fView information for a specific expansion");
|
||||||
|
Msg.msg(s, "&b/papi parse <...args>");
|
||||||
|
Msg.msg(s, "&fParse a String with placeholders");
|
||||||
|
Msg.msg(s, "&b/papi parserel <player one> <player two> <...args>");
|
||||||
|
Msg.msg(s, "&fParse a String with relational placeholders");
|
||||||
|
Msg.msg(s, "&b/papi reload");
|
||||||
|
Msg.msg(s, "&fReload the config settings");
|
||||||
|
|
||||||
|
boolean enabled = plugin.getExpansionCloud() != null;
|
||||||
|
|
||||||
|
|
||||||
|
if (s.isOp()) {
|
||||||
|
if (!enabled) {
|
||||||
|
Msg.msg(s, "&b/papi enablecloud");
|
||||||
|
Msg.msg(s, "&fEnable the expansion cloud");
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, "&b/papi disablecloud");
|
||||||
|
Msg.msg(s, "&fDisable the expansion cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud");
|
||||||
|
Msg.msg(s, "&fView information about the PlaceholderAPI expansion cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud status");
|
||||||
|
Msg.msg(s, "&fView status of the PlaceholderAPI expansion cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud list <all/author> <page>");
|
||||||
|
Msg.msg(s, "&fList all available expansions");
|
||||||
|
Msg.msg(s, "&b/papi ecloud info <expansion name>");
|
||||||
|
Msg.msg(s, "&fView information about a specific expansion on the cloud");
|
||||||
|
Msg.msg(s, "&b/papi ecloud download <expansion name>");
|
||||||
|
Msg.msg(s, "&fDownload a specific expansion from the cloud");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("ecloud")) {
|
||||||
|
if (!s.isOp()) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() == null) {
|
||||||
|
Msg.msg(s, "&7The expansion cloud is not enabled!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eCloud.onCommand(s, c, label, args);
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("enablecloud")) {
|
||||||
|
|
||||||
|
if (!s.isOp()) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() != null) {
|
||||||
|
Msg.msg(s, "&7The cloud is already enabled!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.enableCloud();
|
||||||
|
plugin.getPlaceholderAPIConfig().setCloudEnabled(true);
|
||||||
|
Msg.msg(s, "&aThe cloud has been enabled!");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("disablecloud")) {
|
||||||
|
|
||||||
|
if (!s.isOp()) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getExpansionCloud() == null) {
|
||||||
|
Msg.msg(s, "&7The cloud is already disabled!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.disableCloud();
|
||||||
|
plugin.getPlaceholderAPIConfig().setCloudEnabled(false);
|
||||||
|
Msg.msg(s, "&aThe cloud has been disabled!");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (args.length > 1 && args[0].equalsIgnoreCase("info")) {
|
||||||
|
|
||||||
|
if (!s.hasPermission("placeholderapi.info")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(args[1]);
|
||||||
|
|
||||||
|
if (ex == null) {
|
||||||
|
Msg.msg(s, "&cThere is no expansion loaded with the identifier: &f" + args[1]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&7Placeholder expansion info for: &f%" + ex.getIdentifier() + "_<identifier>%");
|
||||||
|
|
||||||
|
Msg.msg(s, "&7Status: " + (ex.isRegistered() ? "&aRegistered" : "&cNot registered"));
|
||||||
|
|
||||||
|
if (ex.getAuthor() != null) {
|
||||||
|
Msg.msg(s, "&7Created by: &f" + ex.getAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getVersion() != null) {
|
||||||
|
Msg.msg(s, "&7Version: &f" + ex.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getDescription() != null) {
|
||||||
|
Msg.msg(s, ex.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getLink() != null) {
|
||||||
|
Msg.msg(s, "&7Link: &f" + ex.getLink());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getPlugin() != null) {
|
||||||
|
Msg.msg(s, "&7Requires plugin: &f" + ex.getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getPlaceholders() != null) {
|
||||||
|
Msg.msg(s, "&8&m-- &r&7Placeholders &8&m--");
|
||||||
|
for (String placeholder : ex.getPlaceholders()) {
|
||||||
|
Msg.msg(s, placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (args.length > 1 && args[0].equalsIgnoreCase("parse")) {
|
||||||
|
|
||||||
|
if (!(s instanceof Player)) {
|
||||||
|
Msg.msg(s, "&cThis command can only be used in game!");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (!s.hasPermission("placeholderapi.parse")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Player p = (Player) s;
|
||||||
|
|
||||||
|
String parse = StringUtils.join(args, " ", 1, args.length);
|
||||||
|
|
||||||
|
Msg.msg(s, "&r" + PlaceholderAPI.setPlaceholders(p, parse));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (args.length > 3 && args[0].equalsIgnoreCase("parserel")) {
|
||||||
|
|
||||||
|
if (!(s instanceof Player)) {
|
||||||
|
Msg.msg(s, "&cThis command can only be used in game!");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (!s.hasPermission("placeholderapi.parse")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Player one = Bukkit.getPlayer(args[1]);
|
||||||
|
if (one == null) {
|
||||||
|
Msg.msg(s, args[1] + " &cis not online!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player two = Bukkit.getPlayer(args[2]);
|
||||||
|
|
||||||
|
if (two == null) {
|
||||||
|
Msg.msg(s, args[2] + " &cis not online!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String parse = StringUtils.join(args, " ", 3, args.length);
|
||||||
|
|
||||||
|
Msg.msg(s, "&r" + PlaceholderAPI.setRelationalPlaceholders(one, two, parse));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (args[0].equalsIgnoreCase("reload")) {
|
||||||
|
|
||||||
|
if (s instanceof Player) {
|
||||||
|
if (!s.hasPermission("placeholderapi.reload")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg.msg(s, "&fPlaceholder&7API &bconfiguration reloaded!");
|
||||||
|
|
||||||
|
plugin.reloadConf(s);
|
||||||
|
|
||||||
|
} else if (args[0].equalsIgnoreCase("list")) {
|
||||||
|
|
||||||
|
if (s instanceof Player) {
|
||||||
|
if (!s.hasPermission("placeholderapi.list")) {
|
||||||
|
Msg.msg(s, "&cYou don't have permission to do that!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> registered = PlaceholderAPI.getRegisteredIdentifiers();
|
||||||
|
|
||||||
|
if (registered.isEmpty()) {
|
||||||
|
Msg.msg(s, "&7There are no placeholder hooks currently registered!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Msg.msg(s, registered.size()+" &7Placeholder hooks registered:");
|
||||||
|
Msg.msg(s, registered.toString());
|
||||||
|
} else {
|
||||||
|
Msg.msg(s, "&cIncorrect usage! &7/papi help");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package me.clip.placeholderapi.configuration;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
public class PlaceholderAPIConfig {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
public PlaceholderAPIConfig(PlaceholderAPIPlugin i) {
|
||||||
|
plugin = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadDefConfig() {
|
||||||
|
|
||||||
|
FileConfiguration c = plugin.getConfig();
|
||||||
|
|
||||||
|
c.options().header("PlaceholderAPI version "+plugin.getDescription().getVersion()+""
|
||||||
|
+ "\nCreated by extended_clip"
|
||||||
|
+ "\n"
|
||||||
|
+ "\nNo placeholders are provided with this plugin."
|
||||||
|
+ "\nDownload placeholders with /papi ecloud"
|
||||||
|
+ "\nExample:"
|
||||||
|
+ "\n/papi ecloud refresh"
|
||||||
|
+ "\n/papi ecloud list all"
|
||||||
|
+ "\n/papi ecloud list all 2"
|
||||||
|
+ "\n/papi ecloud download Player"
|
||||||
|
+ "\n/papi ecloud download Vault"
|
||||||
|
+ "\n/papi reload");
|
||||||
|
|
||||||
|
c.set("auto_install_expansions", null);
|
||||||
|
c.set("cloud_enable_unverified_expansions", null);
|
||||||
|
c.addDefault("check_updates", true);
|
||||||
|
c.addDefault("cloud_enabled", true);
|
||||||
|
c.addDefault("cloud_allow_unverified_expansions", false);
|
||||||
|
c.addDefault("boolean.true", "yes");
|
||||||
|
c.addDefault("boolean.false", "no");
|
||||||
|
c.addDefault("date_format", "MM/dd/yy HH:mm:ss");
|
||||||
|
c.options().copyDefaults(true);
|
||||||
|
plugin.saveConfig();
|
||||||
|
plugin.reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkUpdates() {
|
||||||
|
return plugin.getConfig().getBoolean("check_updates");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean cloudAllowUnverifiedExpansions() {
|
||||||
|
return plugin.getConfig().getBoolean("cloud_allow_unverified_expansions");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCloudEnabled() {
|
||||||
|
return plugin.getConfig().getBoolean("cloud_enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCloudEnabled(boolean b) {
|
||||||
|
plugin.getConfig().set("cloud_enabled", b);
|
||||||
|
plugin.saveConfig();
|
||||||
|
plugin.reloadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String booleanTrue() {
|
||||||
|
return plugin.getConfig().getString("boolean.true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String booleanFalse() {
|
||||||
|
return plugin.getConfig().getString("boolean.false");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dateFormat() {
|
||||||
|
return plugin.getConfig().getString("date_format");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package me.clip.placeholderapi.events;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderHook;
|
||||||
|
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class PlaceholderHookUnloadEvent extends Event {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private String plugin;
|
||||||
|
private PlaceholderHook hook;
|
||||||
|
|
||||||
|
public PlaceholderHookUnloadEvent(String plugin, PlaceholderHook placeholderHook) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.hook = placeholderHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHookName() {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceholderHook getHook() {
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface allows a class which extends a {@link PlaceholderExpansion}
|
||||||
|
* to have the clear method called when the implementing expansion is unregistered
|
||||||
|
* from PlaceholderAPI.
|
||||||
|
* This is useful if we want to do things when the implementing hook is unregistered
|
||||||
|
* @author Ryan McCarthy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Cacheable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the implementing class is unregistered from PlaceholderAPI
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface allows a class which extends a {@link PlaceholderExpansion}
|
||||||
|
* to have the cleanup method called every time a player leaves the server.
|
||||||
|
* This is useful if we want to clean up after the player
|
||||||
|
* @author Ryan McCarthy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Cleanable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player leaves the server
|
||||||
|
* @param p (@link Player} who left the server
|
||||||
|
*/
|
||||||
|
void cleanup(Player p);
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any {@link PlaceholderExpansion} class which implements configurable will
|
||||||
|
* have any options listed in the getDefaults map automatically added to the PlaceholderAPI config.yml file
|
||||||
|
* @author Ryan McCarthy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Configurable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will be called before the implementing class is registered
|
||||||
|
* to obtain a map of configuration options that the implementing class needs
|
||||||
|
* These paths and values will be added to the PlaceholderAPI config.yml in the configuration section
|
||||||
|
* expansions.(placeholder identifier).(your key): (your value)
|
||||||
|
* @return Map of config path / values which need to be added / removed from the PlaceholderAPI config.yml file
|
||||||
|
*/
|
||||||
|
Map<String, Object> getDefaults();
|
||||||
|
}
|
@ -0,0 +1,191 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderHook;
|
||||||
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
|
import me.clip.placeholderapi.util.FileUtil;
|
||||||
|
|
||||||
|
public final class ExpansionManager {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
private final Map<String, PlaceholderExpansion> cache = new HashMap<>();
|
||||||
|
|
||||||
|
public ExpansionManager(PlaceholderAPIPlugin instance) {
|
||||||
|
plugin = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clean() {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceholderExpansion getCachedExpansion(String plugin) {
|
||||||
|
return cache.getOrDefault(plugin, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeCachedExpansion(String identifier) {
|
||||||
|
return cache.remove(identifier) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceholderExpansion getRegisteredExpansion(String name) {
|
||||||
|
for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) {
|
||||||
|
if (hook.getValue() instanceof PlaceholderExpansion) {
|
||||||
|
if (name.equalsIgnoreCase(hook.getKey())) {
|
||||||
|
return (PlaceholderExpansion) hook.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean registerExpansion(PlaceholderExpansion c) {
|
||||||
|
|
||||||
|
if (c == null || c.getIdentifier() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c instanceof Configurable) {
|
||||||
|
|
||||||
|
Map<String, Object> defaults = ((Configurable) c).getDefaults();
|
||||||
|
|
||||||
|
String pre = "expansions." + c.getIdentifier() + ".";
|
||||||
|
|
||||||
|
if (defaults != null && !defaults.isEmpty()) {
|
||||||
|
|
||||||
|
FileConfiguration cfg = plugin.getConfig();
|
||||||
|
|
||||||
|
boolean save = false;
|
||||||
|
|
||||||
|
for (Entry<String, Object> entries : defaults.entrySet()) {
|
||||||
|
if (entries.getKey() == null || entries.getKey().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.getValue() == null) {
|
||||||
|
if (cfg.contains(pre + entries.getKey())) {
|
||||||
|
save = true;
|
||||||
|
cfg.set(pre + entries.getKey(), null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!cfg.contains(pre + entries.getKey())) {
|
||||||
|
save = true;
|
||||||
|
cfg.set(pre + entries.getKey(), entries.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save) {
|
||||||
|
plugin.saveConfig();
|
||||||
|
plugin.reloadConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c instanceof VersionSpecific) {
|
||||||
|
VersionSpecific nms = (VersionSpecific) c;
|
||||||
|
if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) {
|
||||||
|
plugin.getLogger().info("Your server version is not compatible with expansion: " + c.getIdentifier()
|
||||||
|
+ " version: " + c.getVersion());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c.canRegister()) {
|
||||||
|
if (c.getPlugin() != null) {
|
||||||
|
cache.put(c.getPlugin().toLowerCase(), c);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c.register()) {
|
||||||
|
if (c.getPlugin() != null) {
|
||||||
|
cache.put(c.getPlugin().toLowerCase(), c);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c instanceof Listener) {
|
||||||
|
Listener l = (Listener) c;
|
||||||
|
Bukkit.getPluginManager().registerEvents(l, plugin);
|
||||||
|
plugin.getLogger().info("Registered event listener for expansion: " + c.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getLogger().info("Successfully registered expansion: " + c.getIdentifier());
|
||||||
|
|
||||||
|
if (c instanceof Taskable) {
|
||||||
|
((Taskable) c).start();
|
||||||
|
plugin.getLogger().info("Started scheduled task for expansion: " + c.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerAllExpansions() {
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Class<?>> subs = FileUtil.getClasses("expansions", PlaceholderExpansion.class);
|
||||||
|
|
||||||
|
if (subs == null || subs.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Class<?> klass : subs) {
|
||||||
|
|
||||||
|
if (klass == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
PlaceholderExpansion ex = null;
|
||||||
|
|
||||||
|
Constructor<?>[] c = klass.getConstructors();
|
||||||
|
|
||||||
|
if (c.length == 0) {
|
||||||
|
ex = (PlaceholderExpansion) klass.newInstance();
|
||||||
|
} else {
|
||||||
|
for (Constructor<?> con : c) {
|
||||||
|
if (con.getParameterTypes().length == 0) {
|
||||||
|
ex = (PlaceholderExpansion) klass.newInstance();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registerExpansion(ex)) {
|
||||||
|
if (plugin.getExpansionCloud() != null) {
|
||||||
|
CloudExpansion ce = plugin.getExpansionCloud().getCloudExpansion(ex.getIdentifier());
|
||||||
|
if (ce != null) {
|
||||||
|
ce.setHasExpansion(true);
|
||||||
|
if (!ce.getVersion().equals(ex.getVersion())) {
|
||||||
|
ce.setShouldUpdate(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Throwable t) {
|
||||||
|
plugin.getLogger().severe("Failed to load placeholder expansion from class: " + klass.getName());
|
||||||
|
plugin.getLogger().severe(t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
public enum NMSVersion {
|
||||||
|
|
||||||
|
UNKNOWN("unknown"),
|
||||||
|
SPIGOT_1_7_R1("v1_7_R1"),
|
||||||
|
SPIGOT_1_7_R2("v1_7_R2"),
|
||||||
|
SPIGOT_1_7_R3("v1_7_R3"),
|
||||||
|
SPIGOT_1_7_R4("v1_7_R4"),
|
||||||
|
SPIGOT_1_8_R1("v1_8_R1"),
|
||||||
|
SPIGOT_1_8_R2("v1_8_R2"),
|
||||||
|
SPIGOT_1_8_R3("v1_8_R3"),
|
||||||
|
SPIGOT_1_9_R1("v1_9_R1"),
|
||||||
|
SPIGOT_1_9_R2("v1_9_R2"),
|
||||||
|
SPIGOT_1_10_R1("v1_10_R1"),
|
||||||
|
SPIGOT_1_11_R1("v1_11_R1"),
|
||||||
|
SPIGOT_1_12_R1("v1_12_R1");
|
||||||
|
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
NMSVersion(String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NMSVersion getVersion(String version) {
|
||||||
|
for (NMSVersion v : values()) {
|
||||||
|
if (v.getVersion().equalsIgnoreCase(version)) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NMSVersion.UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import me.clip.placeholderapi.PlaceholderHook;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
|
public abstract class PlaceholderExpansion extends PlaceholderHook {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of this expansion
|
||||||
|
* @return identifier used for expansion if no name present
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return getIdentifier();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the identifier that this placeholder expansion uses to be passed placeholder requests
|
||||||
|
* @return placeholder identifier that is associated with this class
|
||||||
|
*/
|
||||||
|
public abstract String getIdentifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the plugin that this expansion hooks into.
|
||||||
|
* This will ensure the expansion is added to a cache if canRegister() returns false
|
||||||
|
* get.
|
||||||
|
* The expansion will be removed from the cache
|
||||||
|
* once a plugin loads with the name that is here and the expansion is registered
|
||||||
|
* @return placeholder identifier that is associated with this class
|
||||||
|
*/
|
||||||
|
public abstract String getPlugin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the author of this PlaceholderExpansion
|
||||||
|
* @return name of the author for this expansion
|
||||||
|
*/
|
||||||
|
public abstract String getAuthor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version of this PlaceholderExpansion
|
||||||
|
* @return current version of this expansion
|
||||||
|
*/
|
||||||
|
public abstract String getVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a placeholder has already been registered with this identifier
|
||||||
|
* @return true if the identifier for this expansion has already been registered
|
||||||
|
*/
|
||||||
|
public boolean isRegistered() {
|
||||||
|
Validate.notNull(getIdentifier(), "Placeholder identifier can not be null!");
|
||||||
|
return PlaceholderAPI.getRegisteredIdentifiers().contains(getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If any requirements are required to be checked before this hook can register, add them here
|
||||||
|
* @return true if this hook meets all the requirements to register
|
||||||
|
*/
|
||||||
|
public boolean canRegister() {
|
||||||
|
return getPlugin() == null || Bukkit.getPluginManager().getPlugin(getPlugin()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to register this PlaceholderExpansion with PlaceholderAPI
|
||||||
|
* @return true if this class and identifier have been successfully registered with PlaceholderAPI
|
||||||
|
*/
|
||||||
|
public boolean register() {
|
||||||
|
Validate.notNull(getIdentifier(), "Placeholder identifier can not be null!");
|
||||||
|
return PlaceholderAPI.registerPlaceholderHook(getIdentifier(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quick getter for the {@link PlaceholderAPIPlugin} instance
|
||||||
|
* @return {@link PlaceholderAPIPlugin} instance
|
||||||
|
*/
|
||||||
|
public PlaceholderAPIPlugin getPlaceholderAPI() {
|
||||||
|
return PlaceholderAPIPlugin.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short description of this expansion
|
||||||
|
* @return null if no description
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The url link to this expansion page
|
||||||
|
* @return null if no link
|
||||||
|
*/
|
||||||
|
public String getLink() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all valid placeholders
|
||||||
|
* @return null if you dont care
|
||||||
|
*/
|
||||||
|
public List<String> getPlaceholders() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(String path, String def) {
|
||||||
|
return getPlaceholderAPI().getConfig().getString("expansions." + getIdentifier() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(String path, int def) {
|
||||||
|
return getPlaceholderAPI().getConfig().getInt("expansions." + getIdentifier() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLong(String path, long def) {
|
||||||
|
return getPlaceholderAPI().getConfig().getLong("expansions." + getIdentifier() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble(String path, double def) {
|
||||||
|
return getPlaceholderAPI().getConfig().getDouble("expansions." + getIdentifier() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getStringList(String path) {
|
||||||
|
return getPlaceholderAPI().getConfig().getStringList("expansions." + getIdentifier() + "." + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(String path, Object def) {
|
||||||
|
return getPlaceholderAPI().getConfig().get("expansions." + getIdentifier() + "." + path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationSection getConfigSection(String path) {
|
||||||
|
return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier() + "." + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationSection getConfigSection() {
|
||||||
|
return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean configurationContains(String path) {
|
||||||
|
return getPlaceholderAPI().getConfig().contains("expansions." + getIdentifier() + "." + path);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public interface Relational {
|
||||||
|
String onPlaceholderRequest(Player one, Player two, String identifier);
|
||||||
|
}
|
17
src/main/java/me/clip/placeholderapi/expansion/Taskable.java
Normal file
17
src/main/java/me/clip/placeholderapi/expansion/Taskable.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
|
||||||
|
public interface Taskable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the implementing class has successfully been registered to the placeholder map
|
||||||
|
* Tasks that need to be performed when this expansion is registered should go here
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the implementing class has been unregistered from PlaceholderAPI
|
||||||
|
* Tasks that need to be performed when this expansion has unregistered should go here
|
||||||
|
*/
|
||||||
|
void stop();
|
||||||
|
}
|
21
src/main/java/me/clip/placeholderapi/expansion/Version.java
Normal file
21
src/main/java/me/clip/placeholderapi/expansion/Version.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
public class Version {
|
||||||
|
|
||||||
|
private boolean isSpigot;
|
||||||
|
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
public Version(String version, boolean isSpigot) {
|
||||||
|
this.version = version;
|
||||||
|
this.isSpigot = isSpigot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version == null ? "unknown" : version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSpigot() {
|
||||||
|
return isSpigot;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package me.clip.placeholderapi.expansion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder expansions which use NMS code should be version specific.
|
||||||
|
* Implementing this class allows you to perform checks based on the version the server is running.
|
||||||
|
* The isCompatibleWith method will be passed the server version and allow you to return if your expansion is compatible with that version.
|
||||||
|
* @author Ryan McCarthy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface VersionSpecific {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called before the expansion is attempted to be registered
|
||||||
|
* The server version will be passed to this method so you know what version the server is currently running.
|
||||||
|
*
|
||||||
|
* @return true if your expansion is compatible with the version the server is running.
|
||||||
|
*/
|
||||||
|
boolean isCompatibleWith(Version v);
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package me.clip.placeholderapi.expansion.cloud;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.util.TimeUtil;
|
||||||
|
|
||||||
|
|
||||||
|
public class CloudExpansion {
|
||||||
|
|
||||||
|
private String name, author, version, description, link, releaseNotes;
|
||||||
|
|
||||||
|
private boolean hasExpansion, shouldUpdate;
|
||||||
|
|
||||||
|
private long lastUpdate;
|
||||||
|
|
||||||
|
public CloudExpansion(String name, String author, String version, String description, String link) {
|
||||||
|
this.name = name;
|
||||||
|
this.author = author;
|
||||||
|
this.version = version;
|
||||||
|
this.description = description;
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLink() {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasExpansion() {
|
||||||
|
return hasExpansion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasExpansion(boolean hasExpansion) {
|
||||||
|
this.hasExpansion = hasExpansion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldUpdate() {
|
||||||
|
return shouldUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShouldUpdate(boolean shouldUpdate) {
|
||||||
|
this.shouldUpdate = shouldUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastUpdate() {
|
||||||
|
return lastUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUpdate(long lastUpdate) {
|
||||||
|
this.lastUpdate = lastUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReleaseNotes() {
|
||||||
|
return releaseNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReleaseNotes(String releaseNotes) {
|
||||||
|
this.releaseNotes = releaseNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimeSinceLastUpdate() {
|
||||||
|
int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate());
|
||||||
|
return TimeUtil.getTime(time);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,422 @@
|
|||||||
|
package me.clip.placeholderapi.expansion.cloud;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|
||||||
|
public class ExpansionCloudManager {
|
||||||
|
|
||||||
|
private final File dir;
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
private final TreeMap<Integer, CloudExpansion> remote = new TreeMap<>();
|
||||||
|
|
||||||
|
private final List<String> downloading = new ArrayList<>();
|
||||||
|
|
||||||
|
private int toUpdate = 0;
|
||||||
|
|
||||||
|
public ExpansionCloudManager(PlaceholderAPIPlugin instance) {
|
||||||
|
|
||||||
|
plugin = instance;
|
||||||
|
dir = new File(instance.getDataFolder() + File.separator + "expansions");
|
||||||
|
|
||||||
|
if (!dir.exists()) {
|
||||||
|
try {
|
||||||
|
dir.mkdirs();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clean() {
|
||||||
|
remote.clear();
|
||||||
|
toUpdate = 0;
|
||||||
|
downloading.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDownloading(String expansion) {
|
||||||
|
return downloading.contains(expansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, CloudExpansion> getCloudExpansions() {
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CloudExpansion getCloudExpansion(String name) {
|
||||||
|
|
||||||
|
for (CloudExpansion ex : remote.values()) {
|
||||||
|
if (ex.getName().equalsIgnoreCase(name)) {
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCloudAuthorCount() {
|
||||||
|
|
||||||
|
if (remote == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> temp = new ArrayList<>();
|
||||||
|
|
||||||
|
for (CloudExpansion ex : remote.values()) {
|
||||||
|
if (!temp.contains(ex.getAuthor())) {
|
||||||
|
temp.add(ex.getAuthor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getToUpdateCount() {
|
||||||
|
return toUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decrementToUpdateCount() {
|
||||||
|
if (toUpdate > 0) {
|
||||||
|
toUpdate--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, CloudExpansion> getAllByAuthor(String author) {
|
||||||
|
|
||||||
|
if (remote.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeMap<Integer, CloudExpansion> byAuthor = new TreeMap<>();
|
||||||
|
boolean first = true;
|
||||||
|
|
||||||
|
for (CloudExpansion ex : remote.values()) {
|
||||||
|
if (ex.getAuthor().equalsIgnoreCase(author)) {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
byAuthor.put(0, ex);
|
||||||
|
} else {
|
||||||
|
byAuthor.put(byAuthor.lastKey()+1, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byAuthor.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return byAuthor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, CloudExpansion> getAllInstalled() {
|
||||||
|
|
||||||
|
if (remote.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeMap<Integer, CloudExpansion> has = new TreeMap<>();
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
|
||||||
|
for (CloudExpansion ex : remote.values()) {
|
||||||
|
if (ex.hasExpansion()) {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
has.put(0, ex);
|
||||||
|
} else {
|
||||||
|
has.put(has.lastKey()+1, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return has;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPagesAvailable(Map<Integer, CloudExpansion> map, int amount) {
|
||||||
|
|
||||||
|
if (map == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pages = map.size() > 0 ? 1 : 0;
|
||||||
|
|
||||||
|
if (pages == 0) {
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.size() > amount) {
|
||||||
|
|
||||||
|
pages = map.size()/amount;
|
||||||
|
|
||||||
|
if (map.size() % amount > 0) {
|
||||||
|
pages = pages+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, CloudExpansion> getPage(Map<Integer, CloudExpansion> map, int page) {
|
||||||
|
|
||||||
|
if (map == null || map.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page > getPagesAvailable(map, 10)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int end = 10*page;
|
||||||
|
|
||||||
|
int start = end-10;
|
||||||
|
|
||||||
|
end = end-1;
|
||||||
|
|
||||||
|
int size = map.size();
|
||||||
|
|
||||||
|
if (end > size) {
|
||||||
|
end = size-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeMap<Integer, CloudExpansion> ex = new TreeMap<>();
|
||||||
|
|
||||||
|
for (int i = start ; i <= end ; i++) {
|
||||||
|
ex.put(i, map.get(i));
|
||||||
|
}
|
||||||
|
return ex.isEmpty() ? null : ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fetch() {
|
||||||
|
|
||||||
|
plugin.getLogger().info("Fetching available expansion list...");
|
||||||
|
|
||||||
|
toUpdate = 0;
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
StringBuilder sb;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
URL api = new URL("http://api.extendedclip.com/");
|
||||||
|
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) api.openConnection();
|
||||||
|
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
|
||||||
|
sb = new StringBuilder();
|
||||||
|
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
br.close();
|
||||||
|
connection.disconnect();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String json = sb.toString();
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
Object obj = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
obj = parser.parse(json);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CloudExpansion> unsorted = new ArrayList<>();
|
||||||
|
|
||||||
|
if (obj instanceof JSONObject) {
|
||||||
|
|
||||||
|
JSONObject jo = (JSONObject) obj;
|
||||||
|
|
||||||
|
for (Object o : jo.keySet()) {
|
||||||
|
|
||||||
|
JSONObject sub = (JSONObject) jo.get(o);
|
||||||
|
String name = o.toString();
|
||||||
|
String author = (String) sub.get("author");
|
||||||
|
String version = (String) sub.get("version");
|
||||||
|
String link = (String) sub.get("link");
|
||||||
|
String description = (String) sub.get("description");
|
||||||
|
String notes = "";
|
||||||
|
long update = -1;
|
||||||
|
|
||||||
|
if (sub.get("release_notes") != null) {
|
||||||
|
notes = (String) sub.get("release_notes");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sub.get("last_update") != null) {
|
||||||
|
|
||||||
|
Object u = sub.get("last_update");
|
||||||
|
|
||||||
|
if (u instanceof Long) {
|
||||||
|
update = (long) sub.get("last_update");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudExpansion ce = new CloudExpansion(name, author, version, description, link);
|
||||||
|
|
||||||
|
ce.setReleaseNotes(notes);
|
||||||
|
|
||||||
|
ce.setLastUpdate(update);
|
||||||
|
|
||||||
|
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(name);
|
||||||
|
|
||||||
|
if (ex != null && ex.isRegistered()) {
|
||||||
|
ce.setHasExpansion(true);
|
||||||
|
if (!ex.getVersion().equals(version)) {
|
||||||
|
ce.setShouldUpdate(true);
|
||||||
|
toUpdate++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsorted.add(ce);
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
unsorted.sort(Comparator.comparing(CloudExpansion::getLastUpdate).reversed());
|
||||||
|
|
||||||
|
for (CloudExpansion e : unsorted) {
|
||||||
|
remote.put(count, e);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getLogger().info(count + " placeholder expansions are available on the cloud.");
|
||||||
|
plugin.getLogger().info(toUpdate + " expansions you use have updates.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void download(URL url, String name) throws IOException {
|
||||||
|
|
||||||
|
InputStream is = null;
|
||||||
|
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
URLConnection urlConn = url.openConnection();
|
||||||
|
|
||||||
|
is = urlConn.getInputStream();
|
||||||
|
|
||||||
|
fos = new FileOutputStream(dir.getAbsolutePath() + File.separator + "Expansion-" + name + ".jar");
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
|
||||||
|
int l;
|
||||||
|
|
||||||
|
while ((l = is.read(buffer)) > 0) {
|
||||||
|
fos.write(buffer, 0, l);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (is != null) {
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (fos != null) {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void downloadExpansion(final String player, final CloudExpansion ex) {
|
||||||
|
|
||||||
|
if (downloading.contains(ex.getName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.getLink() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloading.add(ex.getName());
|
||||||
|
|
||||||
|
plugin.getLogger().info("Attempting download of expansion: " + ex.getName() + (player != null ? " by user: " + player : "") + " from url: " + ex.getLink());
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
download(new URL(ex.getLink()), ex.getName());
|
||||||
|
|
||||||
|
plugin.getLogger().info("Download of expansion: " + ex.getName() + " complete!");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
plugin.getLogger().warning("Failed to download expansion: " + ex.getName() + " from: " + ex.getLink());
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
|
||||||
|
downloading.remove(ex.getName());
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
Player p = Bukkit.getPlayer(player);
|
||||||
|
|
||||||
|
if (p != null) {
|
||||||
|
Msg.msg(p, "&cThere was a problem downloading expansion: &f" + ex.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
|
||||||
|
downloading.remove(ex.getName());
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
|
||||||
|
Player p = Bukkit.getPlayer(player);
|
||||||
|
|
||||||
|
if (p != null) {
|
||||||
|
Msg.msg(p, "&aExpansion &f" + ex.getName() + " &adownload complete!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package me.clip.placeholderapi.expansion.cloud;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public class ExpansionComparator implements Comparator<CloudExpansion> {
|
||||||
|
|
||||||
|
private static final int AUTHOR = 0;
|
||||||
|
private static final int LAST = 1;
|
||||||
|
private static final int RATING = 2;
|
||||||
|
private static final int TO_UPDATE = 3;
|
||||||
|
private int compare_mode = LAST;
|
||||||
|
|
||||||
|
public ExpansionComparator() { }
|
||||||
|
|
||||||
|
public ExpansionComparator(int compare_mode) {
|
||||||
|
this.compare_mode = compare_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(CloudExpansion o1, CloudExpansion o2) {
|
||||||
|
switch (compare_mode) {
|
||||||
|
case LAST:
|
||||||
|
return (int) (o2.getLastUpdate() - o1.getLastUpdate());
|
||||||
|
default:
|
||||||
|
return o1.getAuthor().compareTo(o2.getAuthor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
src/main/java/me/clip/placeholderapi/external/EZPlaceholderHook.java
vendored
Normal file
38
src/main/java/me/clip/placeholderapi/external/EZPlaceholderHook.java
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package me.clip.placeholderapi.external;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderHook;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public abstract class EZPlaceholderHook extends PlaceholderHook {
|
||||||
|
|
||||||
|
private String identifier;
|
||||||
|
|
||||||
|
private String plugin;
|
||||||
|
|
||||||
|
public EZPlaceholderHook(Plugin plugin, String identifier) {
|
||||||
|
Validate.notNull(plugin, "Plugin can not be null!");
|
||||||
|
Validate.notNull(identifier, "Placeholder name can not be null!");
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.plugin = plugin.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHooked() {
|
||||||
|
return PlaceholderAPI.getRegisteredPlaceholderPlugins().contains(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hook() {
|
||||||
|
return PlaceholderAPI.registerPlaceholderHook(identifier, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlaceholderName() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPluginName() {
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
}
|
666
src/main/java/me/clip/placeholderapi/metrics/Metrics.java
Normal file
666
src/main/java/me/clip/placeholderapi/metrics/Metrics.java
Normal file
@ -0,0 +1,666 @@
|
|||||||
|
package me.clip.placeholderapi.metrics;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
import org.bukkit.plugin.ServicePriority;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bStats collects some data for plugin authors.
|
||||||
|
* Check out https://bStats.org/ to learn more about bStats!
|
||||||
|
*/
|
||||||
|
public class Metrics {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// You can use the property to disable the check in your test environment
|
||||||
|
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||||
|
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
|
||||||
|
final String defaultPackage = new String(
|
||||||
|
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
|
||||||
|
final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||||
|
// We want to make sure nobody just copy & pastes the example and use the wrong package names
|
||||||
|
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
|
||||||
|
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The version of this bStats class
|
||||||
|
public static final int B_STATS_VERSION = 1;
|
||||||
|
|
||||||
|
// The url to which the data is sent
|
||||||
|
private static final String URL = "https://bStats.org/submitData/bukkit";
|
||||||
|
|
||||||
|
// Should failed requests be logged?
|
||||||
|
private static boolean logFailedRequests;
|
||||||
|
|
||||||
|
// The uuid of the server
|
||||||
|
private static String serverUUID;
|
||||||
|
|
||||||
|
// The plugin
|
||||||
|
private final JavaPlugin plugin;
|
||||||
|
|
||||||
|
// A list with all custom charts
|
||||||
|
private final List<CustomChart> charts = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param plugin The plugin which stats should be submitted.
|
||||||
|
*/
|
||||||
|
public Metrics(JavaPlugin plugin) {
|
||||||
|
if (plugin == null) {
|
||||||
|
throw new IllegalArgumentException("Plugin cannot be null!");
|
||||||
|
}
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
// Get the config file
|
||||||
|
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||||
|
File configFile = new File(bStatsFolder, "config.yml");
|
||||||
|
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||||
|
|
||||||
|
// Check if the config file exists
|
||||||
|
if (!config.isSet("serverUuid")) {
|
||||||
|
|
||||||
|
// Add default values
|
||||||
|
config.addDefault("enabled", true);
|
||||||
|
// Every server gets it's unique random id.
|
||||||
|
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||||
|
// Should failed request be logged?
|
||||||
|
config.addDefault("logFailedRequests", false);
|
||||||
|
|
||||||
|
// Inform the server owners about bStats
|
||||||
|
config.options().header(
|
||||||
|
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
|
||||||
|
"To honor their work, you should not disable it.\n" +
|
||||||
|
"This has nearly no effect on the server performance!\n" +
|
||||||
|
"Check out https://bStats.org/ to learn more :)"
|
||||||
|
).copyDefaults(true);
|
||||||
|
try {
|
||||||
|
config.save(configFile);
|
||||||
|
} catch (IOException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the data
|
||||||
|
serverUUID = config.getString("serverUuid");
|
||||||
|
logFailedRequests = config.getBoolean("logFailedRequests", false);
|
||||||
|
if (config.getBoolean("enabled", true)) {
|
||||||
|
boolean found = false;
|
||||||
|
// Search for all other bStats Metrics classes to see if we are the first one
|
||||||
|
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||||
|
try {
|
||||||
|
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||||
|
found = true; // We aren't the first
|
||||||
|
break;
|
||||||
|
} catch (NoSuchFieldException ignored) { }
|
||||||
|
}
|
||||||
|
// Register our service
|
||||||
|
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
|
||||||
|
if (!found) {
|
||||||
|
// We are the first!
|
||||||
|
startSubmitting();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a custom chart.
|
||||||
|
*
|
||||||
|
* @param chart The chart to add.
|
||||||
|
*/
|
||||||
|
public void addCustomChart(CustomChart chart) {
|
||||||
|
if (chart == null) {
|
||||||
|
throw new IllegalArgumentException("Chart cannot be null!");
|
||||||
|
}
|
||||||
|
charts.add(chart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the Scheduler which submits our data every 30 minutes.
|
||||||
|
*/
|
||||||
|
private void startSubmitting() {
|
||||||
|
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
|
||||||
|
timer.scheduleAtFixedRate(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!plugin.isEnabled()) { // Plugin was disabled
|
||||||
|
timer.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
|
||||||
|
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
|
||||||
|
Bukkit.getScheduler().runTask(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
submitData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000*60*5, 1000*60*30);
|
||||||
|
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
|
||||||
|
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
|
||||||
|
// WARNING: Just don't do it!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the plugin specific data.
|
||||||
|
* This method is called using Reflection.
|
||||||
|
*
|
||||||
|
* @return The plugin specific data.
|
||||||
|
*/
|
||||||
|
public JSONObject getPluginData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
|
||||||
|
String pluginName = plugin.getDescription().getName();
|
||||||
|
String pluginVersion = plugin.getDescription().getVersion();
|
||||||
|
|
||||||
|
data.put("pluginName", pluginName); // Append the name of the plugin
|
||||||
|
data.put("pluginVersion", pluginVersion); // Append the version of the plugin
|
||||||
|
JSONArray customCharts = new JSONArray();
|
||||||
|
for (CustomChart customChart : charts) {
|
||||||
|
// Add the data of the custom charts
|
||||||
|
JSONObject chart = customChart.getRequestJsonObject();
|
||||||
|
if (chart == null) { // If the chart is null, we skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
customCharts.add(chart);
|
||||||
|
}
|
||||||
|
data.put("customCharts", customCharts);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server specific data.
|
||||||
|
*
|
||||||
|
* @return The server specific data.
|
||||||
|
*/
|
||||||
|
private JSONObject getServerData() {
|
||||||
|
// Minecraft specific data
|
||||||
|
int playerAmount;
|
||||||
|
try {
|
||||||
|
// Around MC 1.8 the return type was changed to a collection from an array,
|
||||||
|
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||||
|
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||||
|
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||||
|
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||||
|
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||||
|
} catch (Exception e) {
|
||||||
|
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
|
||||||
|
}
|
||||||
|
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
|
||||||
|
String bukkitVersion = org.bukkit.Bukkit.getVersion();
|
||||||
|
bukkitVersion = bukkitVersion.substring(bukkitVersion.indexOf("MC: ") + 4, bukkitVersion.length() - 1);
|
||||||
|
|
||||||
|
// OS/Java specific data
|
||||||
|
String javaVersion = System.getProperty("java.version");
|
||||||
|
String osName = System.getProperty("os.name");
|
||||||
|
String osArch = System.getProperty("os.arch");
|
||||||
|
String osVersion = System.getProperty("os.version");
|
||||||
|
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||||
|
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
|
||||||
|
data.put("serverUUID", serverUUID);
|
||||||
|
|
||||||
|
data.put("playerAmount", playerAmount);
|
||||||
|
data.put("onlineMode", onlineMode);
|
||||||
|
data.put("bukkitVersion", bukkitVersion);
|
||||||
|
|
||||||
|
data.put("javaVersion", javaVersion);
|
||||||
|
data.put("osName", osName);
|
||||||
|
data.put("osArch", osArch);
|
||||||
|
data.put("osVersion", osVersion);
|
||||||
|
data.put("coreCount", coreCount);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the data and sends it afterwards.
|
||||||
|
*/
|
||||||
|
private void submitData() {
|
||||||
|
final JSONObject data = getServerData();
|
||||||
|
|
||||||
|
JSONArray pluginData = new JSONArray();
|
||||||
|
// Search for all other bStats Metrics classes to get their plugin data
|
||||||
|
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||||
|
try {
|
||||||
|
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||||
|
|
||||||
|
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
|
||||||
|
try {
|
||||||
|
pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider()));
|
||||||
|
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException ignored) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
data.put("plugins", pluginData);
|
||||||
|
|
||||||
|
// Create a new thread for the connection to the bStats server
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// Send the data
|
||||||
|
sendData(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Something went wrong! :(
|
||||||
|
if (logFailedRequests) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the data to the bStats server.
|
||||||
|
*
|
||||||
|
* @param data The data to send.
|
||||||
|
* @throws Exception If the request failed.
|
||||||
|
*/
|
||||||
|
private static void sendData(JSONObject data) throws Exception {
|
||||||
|
if (data == null) {
|
||||||
|
throw new IllegalArgumentException("Data cannot be null!");
|
||||||
|
}
|
||||||
|
if (Bukkit.isPrimaryThread()) {
|
||||||
|
throw new IllegalAccessException("This method must not be called from the main thread!");
|
||||||
|
}
|
||||||
|
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||||
|
|
||||||
|
// Compress the data to save bandwidth
|
||||||
|
byte[] compressedData = compress(data.toString());
|
||||||
|
|
||||||
|
// Add headers
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.addRequestProperty("Accept", "application/json");
|
||||||
|
connection.addRequestProperty("Connection", "close");
|
||||||
|
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||||
|
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||||
|
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||||
|
|
||||||
|
// Send data
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
|
||||||
|
outputStream.write(compressedData);
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
connection.getInputStream().close(); // We don't care about the response - Just send our data :)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gzips the given String.
|
||||||
|
*
|
||||||
|
* @param str The string to gzip.
|
||||||
|
* @return The gzipped String.
|
||||||
|
* @throws IOException If the compression failed.
|
||||||
|
*/
|
||||||
|
private static byte[] compress(final String str) throws IOException {
|
||||||
|
if (str == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
|
||||||
|
gzip.write(str.getBytes("UTF-8"));
|
||||||
|
gzip.close();
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom chart.
|
||||||
|
*/
|
||||||
|
public static abstract class CustomChart {
|
||||||
|
|
||||||
|
// The id of the chart
|
||||||
|
final String chartId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
CustomChart(String chartId) {
|
||||||
|
if (chartId == null || chartId.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||||
|
}
|
||||||
|
this.chartId = chartId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject getRequestJsonObject() {
|
||||||
|
JSONObject chart = new JSONObject();
|
||||||
|
chart.put("chartId", chartId);
|
||||||
|
try {
|
||||||
|
JSONObject data = getChartData();
|
||||||
|
if (data == null) {
|
||||||
|
// If the data is null we don't send the chart.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
chart.put("data", data);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
if (logFailedRequests) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract JSONObject getChartData() throws Exception;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom simple pie.
|
||||||
|
*/
|
||||||
|
public static class SimplePie extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<String> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public SimplePie(String chartId, Callable<String> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
String value = callable.call();
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("value", value);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom advanced pie.
|
||||||
|
*/
|
||||||
|
public static class AdvancedPie extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<Map<String, Integer>> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
Map<String, Integer> map = callable.call();
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
values.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom drilldown pie.
|
||||||
|
*/
|
||||||
|
public static class DrilldownPie extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
Map<String, Map<String, Integer>> map = callable.call();
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean reallyAllSkipped = true;
|
||||||
|
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||||
|
JSONObject value = new JSONObject();
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||||
|
value.put(valueEntry.getKey(), valueEntry.getValue());
|
||||||
|
allSkipped = false;
|
||||||
|
}
|
||||||
|
if (!allSkipped) {
|
||||||
|
reallyAllSkipped = false;
|
||||||
|
values.put(entryValues.getKey(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reallyAllSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom single line chart.
|
||||||
|
*/
|
||||||
|
public static class SingleLineChart extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<Integer> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
int value = callable.call();
|
||||||
|
if (value == 0) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("value", value);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom multi line chart.
|
||||||
|
*/
|
||||||
|
public static class MultiLineChart extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<Map<String, Integer>> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
Map<String, Integer> map = callable.call();
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
values.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom simple bar chart.
|
||||||
|
*/
|
||||||
|
public static class SimpleBarChart extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<Map<String, Integer>> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
Map<String, Integer> map = callable.call();
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
JSONArray categoryValues = new JSONArray();
|
||||||
|
categoryValues.add(entry.getValue());
|
||||||
|
values.put(entry.getKey(), categoryValues);
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom advanced bar chart.
|
||||||
|
*/
|
||||||
|
public static class AdvancedBarChart extends CustomChart {
|
||||||
|
|
||||||
|
private final Callable<Map<String, int[]>> callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
* @param callable The callable which is used to request the chart data.
|
||||||
|
*/
|
||||||
|
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
|
||||||
|
super(chartId);
|
||||||
|
this.callable = callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() throws Exception {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
Map<String, int[]> map = callable.call();
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue().length == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
JSONArray categoryValues = new JSONArray();
|
||||||
|
for (int categoryValue : entry.getValue()) {
|
||||||
|
categoryValues.add(categoryValue);
|
||||||
|
}
|
||||||
|
values.put(entry.getKey(), categoryValues);
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
package me.clip.placeholderapi.updatechecker;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* thanks maxim
|
||||||
|
*/
|
||||||
|
public class UpdateChecker implements Listener {
|
||||||
|
|
||||||
|
private PlaceholderAPIPlugin plugin;
|
||||||
|
|
||||||
|
private final int resourceId = 6245;
|
||||||
|
|
||||||
|
private static String latestVersion = "";
|
||||||
|
|
||||||
|
private static boolean updateAvailable = false;
|
||||||
|
|
||||||
|
public UpdateChecker(PlaceholderAPIPlugin i) {
|
||||||
|
plugin = i;
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
if (checkForUpdate()) {
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
plugin.getLogger().info("An update for PlaceholderAPI (v" + getLatestVersion() + ") is available at:");
|
||||||
|
plugin.getLogger().info("https://www.spigotmc.org/resources/placeholderapi." + resourceId + "/");
|
||||||
|
register();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register() {
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onJoin(PlayerJoinEvent e) {
|
||||||
|
if (e.getPlayer().isOp()) {
|
||||||
|
e.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', "&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getLatestVersion() + "&e)"));
|
||||||
|
e.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + resourceId + "/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSpigotVersion() {
|
||||||
|
try {
|
||||||
|
HttpsURLConnection con = (HttpsURLConnection) new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceId).openConnection();
|
||||||
|
con.setRequestMethod("GET");
|
||||||
|
String version = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
|
||||||
|
if (version.length() <= 7) {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
plugin.getLogger().info("Failed to check for a update on spigot.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkHigher(String currentVersion, String newVersion) {
|
||||||
|
String current = toReadable(currentVersion);
|
||||||
|
String newVers = toReadable(newVersion);
|
||||||
|
return current.compareTo(newVers) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkForUpdate() {
|
||||||
|
String version = getSpigotVersion();
|
||||||
|
if (version != null) {
|
||||||
|
if (checkHigher(plugin.getDescription().getVersion(), version)) {
|
||||||
|
latestVersion = version;
|
||||||
|
updateAvailable = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean updateAvailable() {
|
||||||
|
return updateAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLatestVersion() {
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toReadable(String version) {
|
||||||
|
String[] split = Pattern.compile(".", Pattern.LITERAL).split(version.replace("v", ""));
|
||||||
|
version = "";
|
||||||
|
for (String s : split) {
|
||||||
|
version += String.format("%4s", s);
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
73
src/main/java/me/clip/placeholderapi/util/FileUtil.java
Normal file
73
src/main/java/me/clip/placeholderapi/util/FileUtil.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package me.clip.placeholderapi.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarInputStream;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
|
||||||
|
public static List<Class<?>> getClasses(String folder, Class<?> type) {
|
||||||
|
List<Class<?>> list = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder);
|
||||||
|
if (!f.exists()) {
|
||||||
|
if (!f.mkdir()) {
|
||||||
|
PlaceholderAPIPlugin.getInstance().getLogger().severe("Failed to create " + folder + " folder!");
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
FilenameFilter fileNameFilter = (dir, name) -> {
|
||||||
|
int i = name.lastIndexOf('.');
|
||||||
|
return i > 0 && name.substring(i).equals(".jar");
|
||||||
|
};
|
||||||
|
File[] jars = f.listFiles(fileNameFilter);
|
||||||
|
if (jars == null) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
for (File file : jars) {
|
||||||
|
list = gather(file.toURI().toURL(), list, type);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
} catch (Throwable t) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) {
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<>();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
|
||||||
|
JarInputStream jis = new JarInputStream(jar.openStream());
|
||||||
|
while (true) {
|
||||||
|
JarEntry j = jis.getNextJarEntry();
|
||||||
|
if (j == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String name = j.getName();
|
||||||
|
if (name == null || name.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (name.endsWith(".class")) {
|
||||||
|
name = name.replace("/", ".");
|
||||||
|
String cname = name.substring(0, name.lastIndexOf(".class"));
|
||||||
|
Class<?> c = cl.loadClass(cname);
|
||||||
|
if (clazz.isAssignableFrom(c)) {
|
||||||
|
list.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cl.close();
|
||||||
|
jis.close();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
12
src/main/java/me/clip/placeholderapi/util/Msg.java
Normal file
12
src/main/java/me/clip/placeholderapi/util/Msg.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package me.clip.placeholderapi.util;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public class Msg {
|
||||||
|
|
||||||
|
public static void msg(CommandSender s, String msg) {
|
||||||
|
s.sendMessage(ChatColor.translateAlternateColorCodes('&', msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package me.clip.placeholderapi.util;
|
||||||
|
|
||||||
|
public enum TimeFormat {
|
||||||
|
|
||||||
|
DAYS,
|
||||||
|
HOURS,
|
||||||
|
MINUTES,
|
||||||
|
SECONDS
|
||||||
|
}
|
183
src/main/java/me/clip/placeholderapi/util/TimeUtil.java
Normal file
183
src/main/java/me/clip/placeholderapi/util/TimeUtil.java
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
package me.clip.placeholderapi.util;
|
||||||
|
|
||||||
|
public class TimeUtil {
|
||||||
|
|
||||||
|
public static String getRemaining(int seconds, TimeFormat type) {
|
||||||
|
|
||||||
|
if (seconds < 60) {
|
||||||
|
switch(type) {
|
||||||
|
case DAYS:
|
||||||
|
return "0";
|
||||||
|
case HOURS:
|
||||||
|
return "0";
|
||||||
|
case MINUTES:
|
||||||
|
return "0";
|
||||||
|
case SECONDS:
|
||||||
|
return String.valueOf(seconds);
|
||||||
|
}
|
||||||
|
return String.valueOf(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int minutes = seconds / 60;
|
||||||
|
|
||||||
|
int s = 60 * minutes;
|
||||||
|
|
||||||
|
int secondsLeft = seconds - s;
|
||||||
|
|
||||||
|
if (minutes < 60) {
|
||||||
|
switch(type) {
|
||||||
|
case DAYS:
|
||||||
|
return "0";
|
||||||
|
case HOURS:
|
||||||
|
return "0";
|
||||||
|
case MINUTES:
|
||||||
|
return String.valueOf(minutes);
|
||||||
|
case SECONDS:
|
||||||
|
return String.valueOf(secondsLeft);
|
||||||
|
}
|
||||||
|
return String.valueOf(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minutes < 1440) {
|
||||||
|
|
||||||
|
int hours = minutes / 60;
|
||||||
|
|
||||||
|
int inMins = 60 * hours;
|
||||||
|
|
||||||
|
int leftOver = minutes - inMins;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case DAYS:
|
||||||
|
return "0";
|
||||||
|
case HOURS:
|
||||||
|
return String.valueOf(hours);
|
||||||
|
case MINUTES:
|
||||||
|
return String.valueOf(leftOver);
|
||||||
|
case SECONDS:
|
||||||
|
return String.valueOf(secondsLeft);
|
||||||
|
}
|
||||||
|
return String.valueOf(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int days = minutes / 1440;
|
||||||
|
|
||||||
|
int inMins = 1440 * days;
|
||||||
|
|
||||||
|
int leftOver = minutes - inMins;
|
||||||
|
|
||||||
|
|
||||||
|
if (leftOver < 60) {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DAYS:
|
||||||
|
return String.valueOf(days);
|
||||||
|
case HOURS:
|
||||||
|
return String.valueOf(0);
|
||||||
|
case MINUTES:
|
||||||
|
return String.valueOf(leftOver);
|
||||||
|
case SECONDS:
|
||||||
|
return String.valueOf(secondsLeft);
|
||||||
|
}
|
||||||
|
return String.valueOf(seconds);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
int hours = leftOver / 60;
|
||||||
|
|
||||||
|
int hoursInMins = 60 * hours;
|
||||||
|
|
||||||
|
int minsLeft = leftOver - hoursInMins;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DAYS:
|
||||||
|
return String.valueOf(days);
|
||||||
|
case HOURS:
|
||||||
|
return String.valueOf(hours);
|
||||||
|
case MINUTES:
|
||||||
|
return String.valueOf(minsLeft);
|
||||||
|
case SECONDS:
|
||||||
|
return String.valueOf(secondsLeft);
|
||||||
|
}
|
||||||
|
return String.valueOf(seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTime(int seconds) {
|
||||||
|
|
||||||
|
if (seconds < 60) {
|
||||||
|
return seconds+"s";
|
||||||
|
}
|
||||||
|
|
||||||
|
int minutes = seconds / 60;
|
||||||
|
|
||||||
|
int s = 60 * minutes;
|
||||||
|
|
||||||
|
int secondsLeft = seconds - s;
|
||||||
|
|
||||||
|
if (minutes < 60) {
|
||||||
|
if (secondsLeft > 0) {
|
||||||
|
return String.valueOf(minutes+"m "+secondsLeft+"s");
|
||||||
|
} else {
|
||||||
|
return String.valueOf(minutes+"m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minutes < 1440) {
|
||||||
|
|
||||||
|
String time;
|
||||||
|
|
||||||
|
int hours = minutes / 60;
|
||||||
|
|
||||||
|
time = hours+"h";
|
||||||
|
|
||||||
|
int inMins = 60 * hours;
|
||||||
|
|
||||||
|
int leftOver = minutes - inMins;
|
||||||
|
|
||||||
|
if (leftOver >= 1) {
|
||||||
|
time = time+" "+leftOver+"m";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondsLeft > 0) {
|
||||||
|
time = time+" "+secondsLeft+"s";
|
||||||
|
}
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
String time;
|
||||||
|
|
||||||
|
int days = minutes / 1440;
|
||||||
|
|
||||||
|
time = days+"d";
|
||||||
|
|
||||||
|
int inMins = 1440 * days;
|
||||||
|
|
||||||
|
int leftOver = minutes - inMins;
|
||||||
|
|
||||||
|
if (leftOver >= 1) {
|
||||||
|
|
||||||
|
if (leftOver < 60) {
|
||||||
|
|
||||||
|
time = time+" "+leftOver+"m";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
int hours = leftOver / 60;
|
||||||
|
|
||||||
|
time = time+" "+hours+"h";
|
||||||
|
|
||||||
|
int hoursInMins = 60 * hours;
|
||||||
|
|
||||||
|
int minsLeft = leftOver - hoursInMins;
|
||||||
|
|
||||||
|
time = time+" "+minsLeft+"m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondsLeft > 0) {
|
||||||
|
time = time+" "+secondsLeft+"s";
|
||||||
|
}
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
32
src/main/resources/plugin.yml
Normal file
32
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: PlaceholderAPI
|
||||||
|
main: me.clip.placeholderapi.PlaceholderAPIPlugin
|
||||||
|
version: ${pom.version}
|
||||||
|
author: [extended_clip]
|
||||||
|
description: A placeholder provider
|
||||||
|
permissions:
|
||||||
|
placeholderapi.*:
|
||||||
|
description: ability to use all commands
|
||||||
|
children:
|
||||||
|
placeholderapi.admin: true
|
||||||
|
placeholderapi.admin:
|
||||||
|
description: ability to use all commands
|
||||||
|
children:
|
||||||
|
placeholderapi.list: true
|
||||||
|
placeholderapi.reload: true
|
||||||
|
placeholderapi.parse: true
|
||||||
|
placeholderapi.injector.chat.bypass: true
|
||||||
|
placeholderapi.injector.signs.bypass: true
|
||||||
|
placeholderapi.injector.anvil.bypass: true
|
||||||
|
placeholderapi.list:
|
||||||
|
description: ability to use the list command
|
||||||
|
default: op
|
||||||
|
placeholderapi.reload:
|
||||||
|
description: ability to use the reload command
|
||||||
|
default: op
|
||||||
|
placeholderapi.parse:
|
||||||
|
description: ability to use parse command
|
||||||
|
default: op
|
||||||
|
commands:
|
||||||
|
placeholderapi:
|
||||||
|
description: PlaceholderAPI command
|
||||||
|
aliases: [clipsplaceholderapi, papi]
|
Loading…
Reference in New Issue
Block a user