Revert "Performance Improvements (#340)"

This reverts commit 54d5757d
This commit is contained in:
extendedclip 2020-07-20 16:57:16 -04:00
parent 8972f7cff4
commit 4ce0b03852
52 changed files with 873 additions and 874 deletions

34
pom.xml
View File

@ -5,8 +5,8 @@
<groupId>me.clip</groupId> <groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId> <artifactId>placeholderapi</artifactId>
<version>2.10.7-DEV-${BUILD_NUMBER}</version>
<version>2.10.7-DEV-${BUILD_NUMBER}</version>
<name>PlaceholderAPI</name> <name>PlaceholderAPI</name>
<description>An awesome placeholder provider!</description> <description>An awesome placeholder provider!</description>
<url>http://extendedclip.com</url> <url>http://extendedclip.com</url>
@ -53,7 +53,7 @@
<dependency> <dependency>
<groupId>org.bstats</groupId> <groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId> <artifactId>bstats-bukkit</artifactId>
<version>1.7</version> <version>1.5</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>me.rayzr522</groupId> <groupId>me.rayzr522</groupId>
@ -83,27 +83,27 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version> <version>3.1.0</version>
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.clip.placeholderapi.util</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.code.gson</pattern>
<shadedPattern>me.clip.placeholderapi.libs.gson</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>me.clip.placeholderapi.metrics</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.code.gson</pattern>
<shadedPattern>me.clip.placeholderapi.libs.gson</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>

View File

@ -20,13 +20,14 @@
*/ */
package me.clip.placeholderapi; package me.clip.placeholderapi;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import me.clip.placeholderapi.events.ExpansionRegisterEvent; import me.clip.placeholderapi.events.ExpansionRegisterEvent;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent; import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.expansion.Cacheable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational; import me.clip.placeholderapi.expansion.Relational;
import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
@ -34,17 +35,18 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static me.clip.placeholderapi.util.Msg.color; import static me.clip.placeholderapi.util.Msg.color;
public class PlaceholderAPI { public class PlaceholderAPI {
protected static final Map<String, PlaceholderHook> PLACEHOLDERS = new ConcurrentHashMap<>();
private static final Pattern PERCENT_PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]"); private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
private static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]"); private static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
private static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern.compile("[%](rel_)([^%]+)[%]"); private static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern.compile("[%](rel_)([^%]+)[%]");
private static final Map<String, PlaceholderHook> placeholders = new HashMap<>();
private PlaceholderAPI() { private PlaceholderAPI() {
} }
@ -56,7 +58,9 @@ public class PlaceholderAPI {
* @return true if identifier is already registered * @return true if identifier is already registered
*/ */
public static boolean isRegistered(String identifier) { public static boolean isRegistered(String identifier) {
return PLACEHOLDERS.containsKey(identifier.toLowerCase(Locale.ENGLISH)); return getRegisteredIdentifiers().stream()
.filter(id -> id.equalsIgnoreCase(identifier))
.findFirst().orElse(null) != null;
} }
/** /**
@ -69,11 +73,15 @@ public class PlaceholderAPI {
* registered for the specified identifier * registered for the specified identifier
*/ */
public static boolean registerPlaceholderHook(String identifier, PlaceholderHook placeholderHook) { public static boolean registerPlaceholderHook(String identifier, PlaceholderHook placeholderHook) {
Validate.notEmpty(identifier, "Placeholder identifier cannot be null or empty"); Validate.notNull(identifier, "Identifier can not be null");
Objects.requireNonNull(placeholderHook, "Placeholder hook cannot be null"); Validate.notNull(placeholderHook, "Placeholderhook can not be null");
if (isRegistered(identifier)) {
return false;
}
placeholders.put(identifier.toLowerCase(), placeholderHook);
if (isRegistered(identifier)) return false;
PLACEHOLDERS.put(identifier.toLowerCase(Locale.ENGLISH), placeholderHook);
return true; return true;
} }
@ -85,8 +93,8 @@ public class PlaceholderAPI {
* placeholder hook registered for the identifier specified * placeholder hook registered for the identifier specified
*/ */
public static boolean unregisterPlaceholderHook(String identifier) { public static boolean unregisterPlaceholderHook(String identifier) {
Validate.notEmpty(identifier, "Identifier cannot be null"); Validate.notNull(identifier, "Identifier can not be null");
return PLACEHOLDERS.remove(identifier.toLowerCase(Locale.ENGLISH)) != null; return placeholders.remove(identifier.toLowerCase()) != null;
} }
/** /**
@ -95,7 +103,7 @@ public class PlaceholderAPI {
* @return All registered placeholder identifiers * @return All registered placeholder identifiers
*/ */
public static Set<String> getRegisteredIdentifiers() { public static Set<String> getRegisteredIdentifiers() {
return ImmutableSet.copyOf(PLACEHOLDERS.keySet()); return ImmutableSet.copyOf(placeholders.keySet());
} }
/** /**
@ -104,16 +112,15 @@ public class PlaceholderAPI {
* @return Copy of the internal placeholder map * @return Copy of the internal placeholder map
*/ */
public static Map<String, PlaceholderHook> getPlaceholders() { public static Map<String, PlaceholderHook> getPlaceholders() {
return ImmutableMap.copyOf(PLACEHOLDERS); return ImmutableMap.copyOf(placeholders);
} }
public static Set<PlaceholderExpansion> getExpansions() { public static Set<PlaceholderExpansion> getExpansions() {
Set<PlaceholderExpansion> expansions = new HashSet<>(); Set<PlaceholderExpansion> set = getPlaceholders().values().stream()
for (PlaceholderHook expansion : PLACEHOLDERS.values()) { .filter(PlaceholderExpansion.class::isInstance).map(PlaceholderExpansion.class::cast)
if (expansion.isExpansion()) expansions.add((PlaceholderExpansion) expansion); .collect(Collectors.toCollection(HashSet::new));
}
return ImmutableSet.copyOf(expansions); return ImmutableSet.copyOf(set);
} }
/** /**
@ -123,7 +130,7 @@ public class PlaceholderAPI {
* @return true if String contains any registered placeholder identifiers, false otherwise * @return true if String contains any registered placeholder identifiers, false otherwise
*/ */
public static boolean containsPlaceholders(String text) { public static boolean containsPlaceholders(String text) {
return !Strings.isNullOrEmpty(text) && PERCENT_PLACEHOLDER_PATTERN.matcher(text).find(); return text != null && PLACEHOLDER_PATTERN.matcher(text).find();
} }
/** /**
@ -133,7 +140,7 @@ public class PlaceholderAPI {
* @return true if String contains any registered placeholder identifiers, false otherwise * @return true if String contains any registered placeholder identifiers, false otherwise
*/ */
public static boolean containsBracketPlaceholders(String text) { public static boolean containsBracketPlaceholders(String text) {
return !Strings.isNullOrEmpty(text) && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find(); return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find();
} }
/** /**
@ -170,7 +177,7 @@ public class PlaceholderAPI {
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text) { public static List<String> setPlaceholders(OfflinePlayer player, List<String> text) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, true); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true);
} }
/** /**
@ -183,7 +190,7 @@ public class PlaceholderAPI {
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, boolean colorize) { public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, boolean colorize) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, colorize); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize);
} }
/** /**
@ -212,13 +219,13 @@ public class PlaceholderAPI {
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, Pattern pattern, boolean colorize) { public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, Pattern pattern, boolean colorize) {
if (text == null) return null; if (text == null) {
List<String> lines = new ArrayList<>(); return null;
for (String line : text) {
lines.add(setPlaceholders(player, line, pattern, colorize));
} }
return lines;
return text.stream()
.map(line -> setPlaceholders(player, line, pattern, colorize))
.collect(Collectors.toList());
} }
/** /**
@ -255,7 +262,7 @@ public class PlaceholderAPI {
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
public static String setPlaceholders(OfflinePlayer player, String text) { public static String setPlaceholders(OfflinePlayer player, String text) {
return PlaceholderReplacer.evaluatePlaceholders(player, text, PlaceholderReplacer.Closure.PERCENT, false); return setPlaceholders(player, text, PLACEHOLDER_PATTERN);
} }
/** /**
@ -268,7 +275,7 @@ public class PlaceholderAPI {
* @return The text containing the parsed placeholders * @return The text containing the parsed placeholders
*/ */
public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) { public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, colorize); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize);
} }
/** /**
@ -297,51 +304,43 @@ public class PlaceholderAPI {
* @return The text containing the parsed placeholders * @return The text containing the parsed placeholders
*/ */
public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern, boolean colorize) { public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern, boolean colorize) {
if (text == null) return null; if (text == null) {
if (PLACEHOLDERS.isEmpty()) return colorize ? color(text) : text; return null;
}
if (placeholders.isEmpty()) {
return colorize ? color(text) : text;
}
final Matcher matcher = pattern.matcher(text);
final Map<String, PlaceholderHook> hooks = getPlaceholders();
Matcher matcher = pattern.matcher(text);
while (matcher.find()) { while (matcher.find()) {
String format = matcher.group(1); final String format = matcher.group(1);
int index = format.indexOf('_'); final int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) continue;
// We don't need to use getPlaceholders() because we know what we're doing and we won't modify the map. if (index <= 0 || index >= format.length()) {
// And instead of looking for the element twice using contains() and get() we only get it and check if it's null. continue;
String identifier = format.substring(0, index).toLowerCase(Locale.ENGLISH); }
PlaceholderHook handler = PLACEHOLDERS.get(identifier);
if (handler != null) { final String identifier = format.substring(0, index).toLowerCase();
String params = format.substring(index + 1); final String params = format.substring(index + 1);
String value = handler.onRequest(player, params); final PlaceholderHook hook = hooks.get(identifier);
if (value != null) { if (hook == null) {
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); continue;
} }
final String value = hook.onRequest(player, params);
if (value != null) {
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
} }
} }
return colorize ? color(text) : text; return colorize ? color(text) : text;
} }
/**
* Optimized version of {@link #setPlaceholders(OfflinePlayer, String, Pattern, boolean)}
*
* @param player player to parse the placeholders against.
* @param text the text to translate.
* @param closure the closing points of a placeholder. %, {, [ etc...
* @param colorize if we should colorize this text using the common & symbol.
* @return the translated text.
*/
public static String setPlaceholders(OfflinePlayer player, String text, PlaceholderReplacer.Closure closure, boolean colorize) {
if (text == null) return null;
if (text.isEmpty()) return "";
if (PLACEHOLDERS.isEmpty()) return colorize ? color(text) : text;
// We don't want to dirty our class.
return PlaceholderReplacer.evaluatePlaceholders(player, text, closure, colorize);
}
/** /**
* Translate placeholders in the provided List based on the relation of the two provided players. * Translate placeholders in the provided List based on the relation of the two provided players.
* <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}. * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}.
@ -366,12 +365,13 @@ public class PlaceholderAPI {
* @return The text containing the parsed relational placeholders * @return The text containing the parsed relational placeholders
*/ */
public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text, boolean colorize) { public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text, boolean colorize) {
if (text == null) return null; if (text == null) {
List<String> lines = new ArrayList<>(); return null;
for (String line : text) {
lines.add(setRelationalPlaceholders(one, two, line, colorize));
} }
return lines;
return text.stream()
.map(line -> setRelationalPlaceholders(one, two, line, colorize))
.collect(Collectors.toList());
} }
/** /**
@ -397,31 +397,43 @@ public class PlaceholderAPI {
* @param colorize If color codes (&[0-1a-fk-o]) should be translated * @param colorize If color codes (&[0-1a-fk-o]) should be translated
* @return The text containing the parsed relational placeholders * @return The text containing the parsed relational placeholders
*/ */
@SuppressWarnings("DuplicatedCode")
public static String setRelationalPlaceholders(Player one, Player two, String text, boolean colorize) { public static String setRelationalPlaceholders(Player one, Player two, String text, boolean colorize) {
if (text == null) return null; if (text == null) {
if (PLACEHOLDERS.isEmpty()) return colorize ? color(text) : text; return null;
}
if (placeholders.isEmpty()) {
return colorize ? Msg.color(text) : text;
}
final Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
final Map<String, PlaceholderHook> hooks = getPlaceholders();
Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
while (matcher.find()) { while (matcher.find()) {
String format = matcher.group(2); final String format = matcher.group(2);
int index = format.indexOf('_'); final int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) continue;
String identifier = format.substring(0, index).toLowerCase(Locale.ENGLISH); if (index <= 0 || index >= format.length()) {
PlaceholderHook handler = PLACEHOLDERS.get(identifier); continue;
}
if (handler.isRelational()) { String identifier = format.substring(0, index).toLowerCase();
Relational relational = (Relational) handler; String params = format.substring(index + 1);
String params = format.substring(index + 1); final PlaceholderHook hook = hooks.get(identifier);
String value = relational.onPlaceholderRequest(one, two, params);
if (value != null) { if (!(hook instanceof Relational)) {
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); continue;
} }
final String value = ((Relational) hook).onPlaceholderRequest(one, two, params);
if (value != null) {
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
} }
} }
return colorize ? color(text) : text; return colorize ? Msg.color(text) : text;
} }
/** /**
@ -429,34 +441,43 @@ public class PlaceholderAPI {
*/ */
protected static void unregisterAll() { protected static void unregisterAll() {
unregisterAllProvidedExpansions(); unregisterAllProvidedExpansions();
PLACEHOLDERS.clear(); placeholders.clear();
} }
/** /**
* Unregister all expansions provided by PlaceholderAPI * Unregister all expansions provided by PlaceholderAPI
*/ */
public static void unregisterAllProvidedExpansions() { public static void unregisterAllProvidedExpansions() {
if (PLACEHOLDERS.isEmpty()) return; final Set<PlaceholderHook> set = new HashSet<>(placeholders.values());
for (PlaceholderHook handler : PLACEHOLDERS.values()) { for (PlaceholderHook hook : set) {
if (handler.isExpansion()) { if (hook instanceof PlaceholderExpansion) {
PlaceholderExpansion expansion = (PlaceholderExpansion) handler; final PlaceholderExpansion expansion = (PlaceholderExpansion) hook;
if (!expansion.persist()) unregisterExpansion(expansion);
if (!expansion.persist()) {
unregisterExpansion(expansion);
}
}
if (hook instanceof Cacheable) {
((Cacheable) hook).clear();
} }
} }
} }
public static boolean registerExpansion(PlaceholderExpansion expansion) { public static boolean registerExpansion(PlaceholderExpansion ex) {
ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); ExpansionRegisterEvent ev = new ExpansionRegisterEvent(ex);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(ev);
if (event.isCancelled()) return false; if (ev.isCancelled()) {
return false;
}
return registerPlaceholderHook(expansion.getIdentifier(), expansion); return registerPlaceholderHook(ex.getIdentifier(), ex);
} }
public static boolean unregisterExpansion(PlaceholderExpansion expansion) { public static boolean unregisterExpansion(PlaceholderExpansion ex) {
if (unregisterPlaceholderHook(expansion.getIdentifier())) { if (unregisterPlaceholderHook(ex.getIdentifier())) {
Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(ex));
return true; return true;
} }
@ -469,7 +490,7 @@ public class PlaceholderAPI {
* @return The pattern for {@literal %<identifier>_<params>%} * @return The pattern for {@literal %<identifier>_<params>%}
*/ */
public static Pattern getPlaceholderPattern() { public static Pattern getPlaceholderPattern() {
return PERCENT_PLACEHOLDER_PATTERN; return PLACEHOLDER_PATTERN;
} }
/** /**
@ -511,19 +532,19 @@ public class PlaceholderAPI {
} }
public static String setPlaceholders(Player player, String text) { public static String setPlaceholders(Player player, String text) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, true); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true);
} }
public static String setPlaceholders(Player player, String text, boolean colorize) { public static String setPlaceholders(Player player, String text, boolean colorize) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, colorize); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize);
} }
public static List<String> setPlaceholders(Player player, List<String> text) { public static List<String> setPlaceholders(Player player, List<String> text) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, true); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true);
} }
public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) { public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) {
return setPlaceholders(player, text, PERCENT_PLACEHOLDER_PATTERN, colorize); return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize);
} }
public static String setBracketPlaceholders(Player player, String text) { public static String setBracketPlaceholders(Player player, String text) {

View File

@ -21,63 +21,66 @@
package me.clip.placeholderapi; package me.clip.placeholderapi;
import me.clip.placeholderapi.commands.CommandHandler; import me.clip.placeholderapi.commands.CommandHandler;
import me.clip.placeholderapi.commands.CompletionHandler;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import me.clip.placeholderapi.expansion.ExpansionManager; import me.clip.placeholderapi.expansion.ExpansionManager;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Version; import me.clip.placeholderapi.expansion.Version;
import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager; import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
import me.clip.placeholderapi.external.EZPlaceholderHook; import me.clip.placeholderapi.external.EZPlaceholderHook;
import me.clip.placeholderapi.listeners.ApacheListener;
import me.clip.placeholderapi.listeners.PlaceholderListener; import me.clip.placeholderapi.listeners.PlaceholderListener;
import me.clip.placeholderapi.listeners.ServerLoadEventListener; import me.clip.placeholderapi.listeners.ServerLoadEventListener;
import me.clip.placeholderapi.updatechecker.UpdateChecker;
import me.clip.placeholderapi.util.TimeUtil; import me.clip.placeholderapi.util.TimeUtil;
import me.clip.placeholderapi.util.UpdateChecker;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Yes I have a shit load of work to do... * Yes I have a shit load of work to do...
* *
* @author Ryan McCarthy * @author Ryan McCarthy
*/ */
public class PlaceholderAPIPlugin extends JavaPlugin { public class PlaceholderAPIPlugin extends JavaPlugin {
private static final Version serverVersion;
private static PlaceholderAPIPlugin instance; private static PlaceholderAPIPlugin instance;
private static DateTimeFormatter dateFormat; private static SimpleDateFormat dateFormat;
private static String booleanTrue; private static String booleanTrue;
private static String booleanFalse; private static String booleanFalse;
private static Version serverVersion;
static {
// It's not possible to be null or throw an index exception unless it's a bug.
String nmsVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
boolean spigot;
try {
Class.forName("org.spigotmc.SpigotConfig");
spigot = true;
} catch (ExceptionInInitializerError | ClassNotFoundException ignored) {
spigot = false;
}
serverVersion = new Version(nmsVersion, spigot);
}
private PlaceholderAPIConfig config; private PlaceholderAPIConfig config;
private ExpansionManager expansionManager; private ExpansionManager expansionManager;
private ExpansionCloudManager expansionCloud; private ExpansionCloudManager expansionCloud;
private long startTime; private long startTime;
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 ignored) {
}
return new Version(v, spigot);
}
/** /**
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API * 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 * class, this is the main class that extends JavaPlugin. For most API methods, use static methods
@ -95,8 +98,9 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
* *
* @return date format * @return date format
*/ */
public static DateTimeFormatter getDateFormat() { public static SimpleDateFormat getDateFormat() {
return dateFormat != null ? dateFormat : DateTimeFormatter.ofPattern("MM/dd/yy HH:mm:ss"); return dateFormat != null ? dateFormat : new SimpleDateFormat(
"MM/dd/yy HH:mm:ss");
} }
/** /**
@ -118,26 +122,26 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
} }
public static Version getServerVersion() { public static Version getServerVersion() {
return serverVersion; return serverVersion != null ? serverVersion : getVersion();
}
@Override
public void onLoad() {
startTime = System.currentTimeMillis();
instance = this;
serverVersion = getVersion();
config = new PlaceholderAPIConfig(this);
expansionManager = new ExpansionManager(this);
} }
@Override @Override
public void onEnable() { public void onEnable() {
startTime = System.currentTimeMillis();
instance = this;
config = new PlaceholderAPIConfig(this);
config.loadDefConfig(); config.loadDefConfig();
setupOptions(); setupOptions();
expansionManager = new ExpansionManager(this); Objects.requireNonNull(getCommand("placeholderapi")).setExecutor(new CommandHandler());
new PlaceholderListener(this); new PlaceholderListener(this);
PluginCommand command = getCommand("placeholderapi");
command.setExecutor(new CommandHandler());
command.setTabCompleter(new CompletionHandler());
new ApacheListener(this);
try { try {
Class.forName("org.bukkit.event.server.ServerLoadEvent"); Class.forName("org.bukkit.event.server.ServerLoadEvent");
new ServerLoadEventListener(this); new ServerLoadEventListener(this);
@ -146,7 +150,7 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
getLogger().info("Placeholder expansion registration initializing..."); getLogger().info("Placeholder expansion registration initializing...");
//fetch any hooks that may have registered externally onEnable first otherwise they will be lost //fetch any hooks that may have registered externally onEnable first otherwise they will be lost
Map<String, PlaceholderHook> alreadyRegistered = PlaceholderAPI.PLACEHOLDERS; final Map<String, PlaceholderHook> alreadyRegistered = PlaceholderAPI.getPlaceholders();
getExpansionManager().registerAllExpansions(); getExpansionManager().registerAllExpansions();
if (alreadyRegistered != null && !alreadyRegistered.isEmpty()) { if (alreadyRegistered != null && !alreadyRegistered.isEmpty()) {
@ -155,8 +159,13 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
}, 1); }, 1);
} }
if (config.checkUpdates()) new UpdateChecker(this).fetch(); if (config.checkUpdates()) {
if (config.isCloudEnabled()) enableCloud(); new UpdateChecker(this).fetch();
}
if (config.isCloudEnabled()) {
enableCloud();
}
setupMetrics(); setupMetrics();
getServer().getScheduler().runTaskLater(this, this::checkHook, 40); getServer().getScheduler().runTaskLater(this, this::checkHook, 40);
@ -166,13 +175,14 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
public void onDisable() { public void onDisable() {
disableCloud(); disableCloud();
PlaceholderAPI.unregisterAll(); PlaceholderAPI.unregisterAll();
Bukkit.getScheduler().cancelTasks(this);
expansionManager = null; expansionManager = null;
Bukkit.getScheduler().cancelTasks(this);
serverVersion = null;
instance = null; instance = null;
} }
public void reloadConf(CommandSender s) { public void reloadConf(CommandSender s) {
boolean cloudEnabled = this.expansionCloud != null;
PlaceholderAPI.unregisterAllProvidedExpansions(); PlaceholderAPI.unregisterAllProvidedExpansions();
reloadConfig(); reloadConfig();
setupOptions(); setupOptions();
@ -180,70 +190,79 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
if (!config.isCloudEnabled()) { if (!config.isCloudEnabled()) {
disableCloud(); disableCloud();
} else if (this.expansionCloud != null) { } else if (!cloudEnabled) {
enableCloud(); enableCloud();
} }
s.sendMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.PLACEHOLDERS.size() + " &aplaceholder hooks successfully registered!")); s.sendMessage(ChatColor.translateAlternateColorCodes('&',
PlaceholderAPI.getRegisteredIdentifiers().size()
+ " &aplaceholder hooks successfully registered!"));
} }
@SuppressWarnings("deprecation")
private void checkHook() { private void checkHook() {
for (PlaceholderHook hook : PlaceholderAPI.PLACEHOLDERS.values()) { Map<String, PlaceholderHook> loaded = PlaceholderAPI.getPlaceholders();
if (hook instanceof EZPlaceholderHook) {
String pluginName = ((EZPlaceholderHook) hook).getPluginName(); loaded.values().forEach(h -> {
if (h instanceof EZPlaceholderHook) {
String author; String author;
try { try {
author = Bukkit.getPluginManager().getPlugin(pluginName).getDescription().getAuthors().toString(); author = Bukkit.getPluginManager().getPlugin(((EZPlaceholderHook) h).getPluginName()).getDescription().getAuthors().toString();
} catch (Exception ex) { } catch (Exception ex) {
author = "the author of the hook's plugin"; author = "the author of the hook's plugin";
} }
getLogger().severe(pluginName + getLogger().severe(((EZPlaceholderHook) h).getPluginName() +
" is currently using a deprecated method to hook into PlaceholderAPI. Placeholders for that plugin no longer work. " + " is currently using a deprecated method to hook into PlaceholderAPI. Placeholders for that plugin no longer work. " +
"Please consult " + author + " and urge them to update it ASAP."); "Please consult {author} and urge them to update it ASAP.".replace("{author}", author));
// disable the hook on startup // disable the hook on startup
PlaceholderAPI.unregisterPlaceholderHook(((EZPlaceholderHook) hook).getPlaceholderName()); PlaceholderAPI.unregisterPlaceholderHook(((EZPlaceholderHook) h).getPlaceholderName());
} }
} });
} }
private void setupOptions() { private void setupOptions() {
booleanTrue = config.booleanTrue(); booleanTrue = config.booleanTrue();
if (booleanTrue == null) booleanTrue = "true";
if (booleanTrue == null) {
booleanTrue = "true";
}
booleanFalse = config.booleanFalse(); booleanFalse = config.booleanFalse();
if (booleanFalse == null) booleanFalse = "false";
if (booleanFalse == null) {
booleanFalse = "false";
}
try { try {
dateFormat = DateTimeFormatter.ofPattern(config.dateFormat()); dateFormat = new SimpleDateFormat(config.dateFormat());
} catch (Exception ignored) { } catch (Exception e) {
dateFormat = DateTimeFormatter.ofPattern("MM/dd/yy HH:mm:ss"); dateFormat = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
} }
} }
private void setupMetrics() { private void setupMetrics() {
// This is NOT the plugin resource ID. it's the bStats ID. Metrics m = new Metrics(this);
Metrics metrics = new Metrics(this, 438); m.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", () -> getExpansionCloud() != null ? "yes" : "no"));
metrics.addCustomChart(new Metrics.SimplePie("using_expansion_cloud",
() -> getExpansionCloud() != null ? "yes" : "no"));
metrics.addCustomChart(new Metrics.SimplePie("using_spigot", m.addCustomChart(new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
() -> getServerVersion().isSpigot() ? "yes" : "no"));
metrics.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> { m.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> {
Map<String, Integer> map = new HashMap<>(); Map<String, Integer> map = new HashMap<>();
for (PlaceholderHook hook : PlaceholderAPI.PLACEHOLDERS.values()) { Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
if (hook.isExpansion()) {
PlaceholderExpansion ex = (PlaceholderExpansion) hook; if (!hooks.isEmpty()) {
map.put(ex.getRequiredPlugin() == null ? ex.getIdentifier()
: ex.getRequiredPlugin(), 1); for (PlaceholderHook hook : hooks.values()) {
if (hook instanceof PlaceholderExpansion) {
PlaceholderExpansion expansion = (PlaceholderExpansion) hook;
map.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() : expansion.getRequiredPlugin(), 1);
}
} }
} }
return map; return map;
})); }));
} }
@ -257,7 +276,10 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
} }
public void disableCloud() { public void disableCloud() {
if (expansionCloud != null) expansionCloud = null; if (expansionCloud != null) {
expansionCloud.clean();
expansionCloud = null;
}
} }
/** /**
@ -283,6 +305,6 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
} }
public long getUptimeMillis() { public long getUptimeMillis() {
return System.currentTimeMillis() - startTime; return (System.currentTimeMillis() - startTime);
} }
} }

View File

@ -20,14 +20,13 @@
*/ */
package me.clip.placeholderapi; package me.clip.placeholderapi;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public abstract class PlaceholderHook { public abstract class PlaceholderHook {
/** /**
* Called when a placeholder value is requested from this hook. * called when a placeholder value is requested from this hook
* *
* @param player {@link OfflinePlayer} to request the placeholder value for, null if not needed for a * @param player {@link OfflinePlayer} to request the placeholder value for, null if not needed for a
* player * player
@ -42,12 +41,8 @@ public abstract class PlaceholderHook {
return onPlaceholderRequest(null, params); return onPlaceholderRequest(null, params);
} }
public PlaceholderAPIPlugin getPlaceholderAPI() {
return PlaceholderAPIPlugin.getInstance();
}
/** /**
* Called when a placeholder is requested from this hook. * called when a placeholder is requested from this hook
* *
* @param player {@link Player} to request the placeholder value for, null if not needed for a player * @param player {@link Player} to request the placeholder value for, null if not needed for a player
* @param params String passed to the hook to determine what value to return * @param params String passed to the hook to determine what value to return
@ -56,12 +51,4 @@ public abstract class PlaceholderHook {
public String onPlaceholderRequest(Player player, String params) { public String onPlaceholderRequest(Player player, String params) {
return null; return null;
} }
public boolean isExpansion() {
return this instanceof PlaceholderExpansion;
}
public boolean isRelational() {
return this instanceof Relational;
}
} }

View File

@ -1,150 +0,0 @@
/*
* PlaceholderAPI
* Copyright (C) 2019 Ryan McCarthy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package me.clip.placeholderapi;
import com.google.common.collect.ImmutableSet;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import java.util.Set;
/**
* This is certainly hard to understand and maintain, but it's fully optimized.
* It's almost x5 times faster than the RegEx method for normal sized strings. This performance gap gets smaller
* for smaller strings.
*
* @author Crypto Morin
*/
public class PlaceholderReplacer {
/**
* Cached available color codes. Technically the uppercase of each letter can be used too, but no one really uses the uppercase ones.
*/
private static final Set<Character> COLOR_CODES = ImmutableSet.of('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'k', 'l', 'm', 'o', 'r', 'x');
/**
* Translates placeholders for a string using pure character loops.
* Might cause problems in really rare conditions.
*
* @param player the player to translate the string for.
* @param str the string to translate.
* @param closure the type of the placeholder closing points.
* @param colorize if this message should be colorized as well.
* @return a translated string.
*/
public static String evaluatePlaceholders(OfflinePlayer player, String str, Closure closure, boolean colorize) {
char[] chars = str.toCharArray();
StringBuilder builder = new StringBuilder(chars.length);
// This won't cause memory leaks. It's inside a method. And we want to use setLength instead of
// creating a new string builder to use the maximum capacity and avoid initializing new objects.
StringBuilder identifier = new StringBuilder(50);
PlaceholderHook handler = null;
// Stages:
// Stage -1: Look for the color code in the next character.
// Stage 0: No closures detected, or the detected identifier is invalid. We're going forward while appending the characters normally.
// Stage 1: The closure has been detected, looking for the placeholder identifier...
// Stage 2: Detected the identifier and the parameter. Translating the placeholder...
int stage = 0;
for (char ch : chars) {
if (stage == -1 && COLOR_CODES.contains(ch)) {
builder.append(ChatColor.COLOR_CHAR).append(ch);
stage = 0;
continue;
}
// Check if the placeholder starts or ends.
if (ch == closure.start || ch == closure.end) {
// If the placeholder ends.
if (stage == 2) {
String parameter = identifier.toString();
String translated = handler.onRequest(player, parameter);
if (translated == null) {
String name = handler.isExpansion() ? ((PlaceholderExpansion) handler).getIdentifier() : "";
builder.append(closure.start).append(name).append('_').append(parameter).append(closure.end);
} else builder.append(translated);
identifier.setLength(0);
stage = 0;
continue;
} else if (stage == 1) { // If it just started | Double closures | If it's still hasn't detected the indentifier, reset.
builder.append(closure.start).append(identifier);
}
identifier.setLength(0);
stage = 1;
continue;
}
// Placeholder identifier started.
if (stage == 1) {
// Compare the current character with the idenfitier's.
// We reached the end of our identifier.
if (ch == '_') {
handler = PlaceholderAPI.PLACEHOLDERS.get(identifier.toString());
if (handler == null) {
builder.append(closure.start).append(identifier).append('_');
stage = 0;
} else {
identifier.setLength(0);
stage = 2;
}
continue;
}
// Keep building the identifier name.
identifier.append(ch);
continue;
}
// Building the placeholder parameter.
if (stage == 2) {
identifier.append(ch);
continue;
}
// Nothing placeholder related was found.
if (colorize && ch == '&') {
stage = -1;
continue;
}
builder.append(ch);
}
if (identifier != null) {
if (stage > 0) builder.append(closure.end);
builder.append(identifier);
}
return builder.toString();
}
public enum Closure {
PERCENT('%', '%'), BRACKETS('[', ']'), BRACES('{', '}');
public char start, end;
Closure(char start, char end) {
this.start = start;
this.end = end;
}
}
}

View File

@ -1,42 +1,52 @@
package me.clip.placeholderapi.commands; package me.clip.placeholderapi.commands;
import com.google.common.collect.ImmutableSet;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
public abstract class Command { public abstract class Command {
private static final Options EMPTY_OPTIONS = new Options(null, 0); private static final Options EMPTY_OPTIONS = new Options(null, 0, null);
private final String match; private final String match;
private final String usage; private final String usage;
private final int minimumArguments; private final int minimumArguments;
/** private final Set<String> permissions;
* Commands should not have multiple permissions. This can lead to a lot of confusions.
* This is also a lot more appropriate for maintainability, I saw a lot of commands regitered with wrong permissions.
* We will use the main command name to parse our permission.
*/
private final String permission;
protected Command(String match) { protected Command(@NotNull final String match) {
this(match, EMPTY_OPTIONS); this(match, EMPTY_OPTIONS);
} }
protected Command(String match, Options options) { protected Command(@NotNull final String match, @NotNull final Options options) {
this.match = match; this.match = match;
this.usage = options.usage == null ? "/papi " + match + " <required args> [optional args]" : options.usage; this.usage = options.usage == null ? "/papi " + match + " <required args> [optional args]" : options.usage;
this.permission = "placeholderapi." + match.replace(' ', '.'); this.permissions = options.permissions == null ? Collections.emptySet() : ImmutableSet.copyOf(options.permissions);
this.minimumArguments = options.minimumArguments; this.minimumArguments = options.minimumArguments;
} }
protected static Options options(String usage, int minimumArguments) { protected static Options usage(@NotNull final String usage, final int minimumArguments) {
return new Options(usage, minimumArguments); return new Options(usage, minimumArguments, null);
} }
protected static Options permissions(@NotNull final String... permissions) {
return new Options(null, 0, permissions);
}
protected static Options options(@NotNull final String usage, final int minimumArguments,
@NotNull final String... permissions) {
return new Options(usage, minimumArguments, permissions);
}
@NotNull
public String getMatch() { public String getMatch() {
return match; return match;
} }
@NotNull
public String getUsage() { public String getUsage() {
return usage; return usage;
} }
@ -45,23 +55,28 @@ public abstract class Command {
return minimumArguments; return minimumArguments;
} }
public String getPermission() { @NotNull
return permission; public Set<String> getPermissions() {
return permissions;
} }
public abstract void execute(CommandSender sender, String[] args); public abstract void execute(@NotNull final CommandSender sender, @NotNull final String[] args);
public List<String> handleCompletion(CommandSender sender, String[] args) { @NotNull
public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
return Collections.emptyList(); return Collections.emptyList();
} }
private static class Options { private static class Options {
private final String usage; private final String usage;
private final int minimumArguments; private final int minimumArguments;
private final String[] permissions;
private Options(String usage, int minimumArguments) { private Options(@Nullable final String usage, final int minimumArguments,
@Nullable final String[] permissions) {
this.usage = usage; this.usage = usage;
this.minimumArguments = minimumArguments; this.minimumArguments = minimumArguments;
this.permissions = permissions;
} }
} }
} }

View File

@ -1,33 +1,25 @@
package me.clip.placeholderapi.commands; package me.clip.placeholderapi.commands;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.command.*; import me.clip.placeholderapi.commands.command.*;
import me.clip.placeholderapi.commands.command.ecloud.EcloudInfoCommand;
import me.clip.placeholderapi.commands.command.ecloud.EcloudListCommand;
import me.clip.placeholderapi.commands.command.ecloud.*; import me.clip.placeholderapi.commands.command.ecloud.*;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.regex.Pattern;
public final class CommandHandler implements CommandExecutor { public final class CommandHandler implements CommandExecutor {
private static final Command DEFAULT = new VersionCommand(); private static final Command DEFAULT = new VersionCommand();
protected static final List<Command> COMMANDS = Lists.newArrayList( private static final List<Command> COMMANDS = Lists.newArrayList(
DEFAULT,
new HelpCommand(),
new InfoCommand(),
new ListCommand(),
new RegisterCommand(),
new UnregisterCommand(),
new ReloadCommand(),
new BcParseCommand(),
new ParseCommand(),
new ParseRelCommand(),
new EcloudCommand(),
new EcloudClearCommand(), new EcloudClearCommand(),
new EcloudDownloadCommand(), new EcloudDownloadCommand(),
new EcloudInfoCommand(), new EcloudInfoCommand(),
@ -36,57 +28,74 @@ public final class CommandHandler implements CommandExecutor {
new EcloudRefreshCommand(), new EcloudRefreshCommand(),
new EcloudStatusCommand(), new EcloudStatusCommand(),
new EcloudVersionInfoCommand(), new EcloudVersionInfoCommand(),
new EcloudDisableCommand(), new EcloudCommand(),
new EcloudEnableCommand() new BcParseCommand(),
new ParseCommand(),
new ParseRelCommand(),
new DisableEcloudCommand(),
new EnableCloudCommand(),
new HelpCommand(),
new InfoCommand(),
new ListCommand(),
new RegisterCommand(),
new ReloadCommand(),
DEFAULT,
new UnregisterCommand()
); );
static { static {
COMMANDS.sort((command1, command2) -> { COMMANDS.sort((command1, command2) -> {
int comparison = Integer.compare(command1.getMatch().length(), command2.getMatch().length()); final int comparison = Integer.compare(command1.getMatch().length(), command2.getMatch().length());
if (comparison == 1) return -1; if (comparison == 1) return -1;
if (comparison == -1) return 1; if (comparison == -1) return 1;
return 0; return 0;
}); });
Objects.requireNonNull(PlaceholderAPIPlugin.getInstance().getCommand("placeholderapi"))
.setTabCompleter(new CompletionHandler(COMMANDS));
} }
private static String[] splitArguments(String joinedArguments, String command) { private static final Pattern SPACE_PATTERN = Pattern.compile(" ");
joinedArguments = StringUtils.remove(joinedArguments, command).trim();
String[] args = StringUtils.split(joinedArguments);
return args.length == 1 && args[0].isEmpty() ? new String[0] : args;
}
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull org.bukkit.command.Command bukkitCommand, @NotNull String name, String[] args) { public boolean onCommand(@NotNull final CommandSender sender, @NotNull final org.bukkit.command.Command bukkitCommand,
@NotNull final String name, @NotNull String[] args) {
if (args.length == 0) { if (args.length == 0) {
DEFAULT.execute(sender, args); DEFAULT.execute(sender, args);
return true; return true;
} }
String joined = String.join(" ", args).toLowerCase(); final String joined = String.join(" ", args).toLowerCase();
Optional<Command> optional = COMMANDS.stream() final Optional<Command> optional = COMMANDS.stream()
.filter(command -> joined.startsWith(command.getMatch())) .filter(command -> joined.startsWith(command.getMatch()))
.findFirst(); .findFirst();
if (!optional.isPresent()) { if (!optional.isPresent()) {
Msg.msg(sender, "&cUnknown command."); sender.sendMessage("Specified command is not valid.");
return true; return true;
} }
Command command = optional.get(); final Command command = optional.get();
String permission = command.getPermission();
if (!sender.hasPermission(permission)) { if (!command.getPermissions().isEmpty() && command.getPermissions().stream().noneMatch(sender::hasPermission)) {
Msg.msg(sender, "&cYou do not have the permission to use this command."); sender.sendMessage("You do not have the permission to execute specified command.");
return true; return true;
} }
args = splitArguments(joined, command.getMatch()); args = splitArguments(joined, command.getMatch());
if (args.length < command.getMinimumArguments()) { if (args.length < command.getMinimumArguments()) {
Msg.msg(sender, command.getUsage()); Msg.msg(sender, command.getUsage());
return true; return true;
} }
command.execute(sender, args); command.execute(sender, args);
return true; return true;
} }
static String[] splitArguments(@NotNull final String joinedArguments, @NotNull final String command) {
final String[] args = SPACE_PATTERN.split(joinedArguments.replace(command, "").trim());
return args.length == 1 && args[0].isEmpty() ? new String[]{} : args;
}
} }

View File

@ -1,37 +1,32 @@
package me.clip.placeholderapi.commands; package me.clip.placeholderapi.commands;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Optional;
import java.util.stream.Collectors;
public final class CompletionHandler implements TabCompleter { public final class CompletionHandler implements TabCompleter {
private static String[] splitArguments(String[] args, String command) { private final List<Command> commands;
int skip = StringUtils.split(command).length;
return Arrays.stream(args).skip(skip).toArray(String[]::new); CompletionHandler(@NotNull final List<Command> commands) {
this.commands = commands;
} }
// it makes me physically cringe trying to understand why bukkit uses a list instead of a set for this // it makes me physically cringe trying to understand why bukkit uses a list instead of a set for this
// It's because of the list order. Even if they wanted to change that, they couldn't for the sake of backward compatibility. ~Crypto @NotNull
@Override @Override
public List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command bukkitCommand, @NotNull String name, String[] args) { public List<String> onTabComplete(@NotNull final CommandSender sender, @NotNull final org.bukkit.command.Command bukkitCommand,
String joined = String.join(" ", args).toLowerCase(Locale.ENGLISH); @NotNull final String name, @NotNull final String[] args) {
final String joined = String.join(" ", args).toLowerCase();
final Optional<Command> optional = commands.stream()
.filter(command -> joined.startsWith(command.getMatch()))
.findAny();
if (args.length > 1) { return optional
return CommandHandler.COMMANDS.stream() .map(command -> command.handleCompletion(sender, CommandHandler.splitArguments(joined, command.getMatch())))
.filter(command -> sender.hasPermission(command.getPermission()) && joined.startsWith(command.getMatch())) .orElse(Collections.emptyList());
.findFirst()
.map(command -> command.handleCompletion(sender, splitArguments(args, command.getMatch())))
.orElse(Collections.emptyList());
}
return CommandHandler.COMMANDS.stream()
.filter(command -> sender.hasPermission(command.getPermission()) && (args[0].isEmpty() || command.getMatch().startsWith(joined)))
.map(Command::getMatch).collect(Collectors.toList());
} }
} }

View File

@ -8,34 +8,40 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BcParseCommand extends Command { public final class BcParseCommand extends Command {
public BcParseCommand() { public BcParseCommand() {
super("bcparse", options("&cYou must specify a player.", 1)); super("bcparse", options("&cYou must specify a player.", 1, "placeholderapi.parse"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
OfflinePlayer player; final OfflinePlayer player;
String input = args[0]; final String input = args[0];
if (input.equalsIgnoreCase("me")) { if (input.equalsIgnoreCase("me")) {
if (sender instanceof Player) { if (sender instanceof Player) {
player = (Player) sender; player = (Player) sender;
} else { } else {
Msg.msg(sender, "&cThis command must target a player when used by console"); Msg.msg(sender, "&cThis command must target a player when used by console");
return; return;
} }
} else { } else {
player = Bukkit.getPlayer(input); if (Bukkit.getPlayer(input) != null) {
if (player == null) player = Bukkit.getOfflinePlayer(input); player = Bukkit.getPlayer(input);
if (player == null || !player.hasPlayedBefore()) { } else {
Msg.msg(sender, "&cCould not find player&8: &f" + input); player = Bukkit.getOfflinePlayer(input);
return;
} }
} }
String parse = StringUtils.join(args, " ", 2, args.length); if (player == null || !player.hasPlayedBefore()) {
Msg.msg(sender, "&cFailed to find player: &f" + input);
return;
}
final String parse = StringUtils.join(args, " ", 2, args.length);
Msg.broadcast("&r" + PlaceholderAPI.setPlaceholders(player, parse)); Msg.broadcast("&r" + PlaceholderAPI.setPlaceholders(player, parse));
} }
} }

View File

@ -1,25 +1,29 @@
package me.clip.placeholderapi.commands.command.ecloud; package me.clip.placeholderapi.commands.command;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class EcloudDisableCommand extends Command { public final class DisableEcloudCommand extends Command {
public EcloudDisableCommand() { public DisableEcloudCommand() {
super("ecloud disable"); super("disablecloud", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
if (plugin.getExpansionCloud() == null) { if (plugin.getExpansionCloud() == null) {
Msg.msg(sender, "&7The cloud is already disabled!"); Msg.msg(sender, "&7The cloud is already disabled!");
return; return;
} }
plugin.disableCloud(); plugin.disableCloud();
plugin.getPlaceholderAPIConfig().setCloudEnabled(false); plugin.getPlaceholderAPIConfig().setCloudEnabled(false);
Msg.msg(sender, "&aThe cloud has been disabled!"); Msg.msg(sender, "&aThe cloud has been disabled!");
return;
} }
} }

View File

@ -6,6 +6,7 @@ import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -21,18 +22,16 @@ public final class EcloudCommand extends Command {
"placeholders", "placeholders",
"refresh", "refresh",
"status", "status",
"versioninfo", "versioninfo"
"enable",
"disable"
); );
public EcloudCommand() { public EcloudCommand() {
super("ecloud"); super("ecloud", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
if (args.length == 0) { if (args.length == 0) {
Msg.msg(sender, "&bExpansion cloud commands", Msg.msg(sender, "&bExpansion cloud commands",
@ -58,6 +57,7 @@ public final class EcloudCommand extends Command {
if (plugin.getExpansionCloud() == null) { if (plugin.getExpansionCloud() == null) {
Msg.msg(sender, "&7The expansion cloud is not enabled!"); Msg.msg(sender, "&7The expansion cloud is not enabled!");
return; return;
} }
@ -69,9 +69,9 @@ public final class EcloudCommand extends Command {
sender.sendMessage("Specified command is not valid."); sender.sendMessage("Specified command is not valid.");
} }
@NotNull
@Override @Override
public List<String> handleCompletion(CommandSender sender, String[] args) { public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MAXIMUM_ARGUMENTS) { if (args.length == MAXIMUM_ARGUMENTS) {
return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size())); return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size()));
} }

View File

@ -1,20 +1,22 @@
package me.clip.placeholderapi.commands.command.ecloud; package me.clip.placeholderapi.commands.command;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class EcloudEnableCommand extends Command { public final class EnableCloudCommand extends Command {
public EcloudEnableCommand() { public EnableCloudCommand() {
super("ecloud enable"); super("enablecloud", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
if (plugin.getExpansionCloud() != null) { if (plugin.getExpansionCloud() != null) {
Msg.msg(sender, "&7The cloud is already enabled!"); Msg.msg(sender, "&7The cloud is already enabled!");
return; return;
} }

View File

@ -4,14 +4,15 @@ import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class HelpCommand extends Command { public final class HelpCommand extends Command {
public HelpCommand() { public HelpCommand() {
super("help"); super("help", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
Msg.msg(sender, "PlaceholderAPI &aHelp &e(&f" + PlaceholderAPIPlugin.getInstance().getDescription().getVersion() + "&e)", Msg.msg(sender, "PlaceholderAPI &aHelp &e(&f" + PlaceholderAPIPlugin.getInstance().getDescription().getVersion() + "&e)",
"&b/papi", "&b/papi",
"&fView plugin info/version info", "&fView plugin info/version info",

View File

@ -7,6 +7,7 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -16,13 +17,13 @@ public final class InfoCommand extends Command {
private static final int MINIMUM_ARGUMENTS = 1; private static final int MINIMUM_ARGUMENTS = 1;
public InfoCommand() { public InfoCommand() {
super("info", options("&cIncorrect usage! &7/papi info <expansion>", MINIMUM_ARGUMENTS)); super("info", options("&cIncorrect usage! &7/papi info <expansion>", MINIMUM_ARGUMENTS, "placeholderapi.info"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
String requestedExpansion = args[0]; final String requestedExpansion = args[0];
PlaceholderExpansion ex = PlaceholderAPIPlugin.getInstance().getExpansionManager().getRegisteredExpansion(requestedExpansion); final PlaceholderExpansion ex = PlaceholderAPIPlugin.getInstance().getExpansionManager().getRegisteredExpansion(requestedExpansion);
if (ex == null) { if (ex == null) {
Msg.msg(sender, "&cThere is no expansion loaded with the identifier: &f" + requestedExpansion); Msg.msg(sender, "&cThere is no expansion loaded with the identifier: &f" + requestedExpansion);
@ -53,11 +54,11 @@ public final class InfoCommand extends Command {
} }
} }
@NotNull
@Override @Override
public List<String> handleCompletion(CommandSender sender, String[] args) { public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MINIMUM_ARGUMENTS) { if (args.length == MINIMUM_ARGUMENTS) {
Set<String> completions = PlaceholderAPI.getRegisteredIdentifiers(); final Set<String> completions = PlaceholderAPI.getRegisteredIdentifiers();
return StringUtil.copyPartialMatches(args[0], completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(args[0], completions, new ArrayList<>(completions.size()));
} }

View File

@ -4,18 +4,19 @@ import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public final class ListCommand extends Command { public final class ListCommand extends Command {
public ListCommand() { public ListCommand() {
super("list"); super("list", permissions("placeholderapi.list"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
Set<String> registered = PlaceholderAPI.getRegisteredIdentifiers(); final Set<String> registered = PlaceholderAPI.getRegisteredIdentifiers();
if (registered.isEmpty()) { if (registered.isEmpty()) {
Msg.msg(sender, "&7There are no placeholder hooks currently registered!"); Msg.msg(sender, "&7There are no placeholder hooks currently registered!");
return; return;

View File

@ -7,53 +7,41 @@ import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public final class ParseCommand extends Command { public final class ParseCommand extends Command {
public ParseCommand() { public ParseCommand() {
super("parse", options("&cYou must specify a player.", 1)); super("parse", options("&cYou must specify a player.", 1, "placeholderapi.parse"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
OfflinePlayer player; final OfflinePlayer player;
String input = args[0]; final String input = args[0];
if (input.equalsIgnoreCase("me")) { if (input.equalsIgnoreCase("me")) {
if (sender instanceof Player) { if (sender instanceof Player) {
player = (Player) sender; player = (Player) sender;
} else { } else {
Msg.msg(sender, "&cThis command must target a player when used by console"); Msg.msg(sender, "&cThis command must target a player when used by console");
return; return;
} }
} else { } else {
player = Bukkit.getPlayer(input); if (Bukkit.getPlayer(input) != null) {
if (player == null) player = Bukkit.getOfflinePlayer(input); player = Bukkit.getPlayer(input);
if (player == null || !player.hasPlayedBefore()) { } else {
Msg.msg(sender, "&cCould not find player&8: &f" + input); player = Bukkit.getOfflinePlayer(input);
return;
} }
} }
String parse = StringUtils.join(args, " ", 1, args.length); if (player == null || !player.hasPlayedBefore()) {
Msg.msg(sender, "&cFailed to find player: &f" + input);
return;
}
final String parse = StringUtils.join(args, " ", 1, args.length);
Msg.msg(sender, "&r" + PlaceholderAPI.setPlaceholders(player, parse)); Msg.msg(sender, "&r" + PlaceholderAPI.setPlaceholders(player, parse));
} }
@Override
public List<String> handleCompletion(CommandSender sender, String[] args) {
if (args.length == 1) {
List<String> players = Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName).collect(Collectors.toList());
players.add("me");
if (args[0].isEmpty()) return players;
else return players.stream().filter(name -> name.startsWith(args[0])).collect(Collectors.toList());
}
if (args.length == 2) return Collections.singletonList("<message>");
return new ArrayList<>();
}
} }

View File

@ -7,27 +7,30 @@ import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class ParseRelCommand extends Command { public final class ParseRelCommand extends Command {
public ParseRelCommand() { public ParseRelCommand() {
super("parserel", options("&cYou must specify at least two players.", 2)); super("parserel", options("&cYou must specify at least two players.", 2, "placeholderapi.parse"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
Player one = Bukkit.getPlayer(args[0]); final Player one = Bukkit.getPlayer(args[0]);
if (one == null) { if (one == null) {
Msg.msg(sender, args[0] + " &cis not online!"); Msg.msg(sender, args[0] + " &cis not online!");
return; return;
} }
Player two = Bukkit.getPlayer(args[1]); final Player two = Bukkit.getPlayer(args[1]);
if (two == null) { if (two == null) {
Msg.msg(sender, args[1] + " &cis not online!"); Msg.msg(sender, args[1] + " &cis not online!");
return; return;
} }
String parse = StringUtils.join(args, " ", 1, args.length); final String parse = StringUtils.join(args, " ", 1, args.length);
Msg.msg(sender, "&r" + PlaceholderAPI.setRelationalPlaceholders(one, two, parse)); Msg.msg(sender, "&r" + PlaceholderAPI.setRelationalPlaceholders(one, two, parse));
} }
} }

View File

@ -4,21 +4,22 @@ import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class RegisterCommand extends Command { public final class RegisterCommand extends Command {
public RegisterCommand() { public RegisterCommand() {
super("register", options("&cAn expansion file name must be specified!", 1)); super("register", options("&cAn expansion file name must be specified!", 1,"placeholderapi.register"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
String fileName = StringUtils.remove(args[0], ".jar"); final String fileName = args[0].replace(".jar", "");
PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionManager().registerExpansion(fileName); final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionManager().registerExpansion(fileName);
if (expansion == null) { if (expansion == null) {
Msg.msg(sender, "&cFailed to register expansion from " + fileName); Msg.msg(sender, "&cFailed to register expansion from " + fileName);
return; return;
} }

View File

@ -4,14 +4,15 @@ import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class ReloadCommand extends Command { public final class ReloadCommand extends Command {
public ReloadCommand() { public ReloadCommand() {
super("reload"); super("reload", permissions("placeholderapi.reload"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
Msg.msg(sender, "&fPlaceholder&7API &bconfiguration reloaded!"); Msg.msg(sender, "&fPlaceholder&7API &bconfiguration reloaded!");
PlaceholderAPIPlugin.getInstance().reloadConf(sender); PlaceholderAPIPlugin.getInstance().reloadConf(sender);
} }

View File

@ -7,6 +7,7 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -16,17 +17,18 @@ public final class UnregisterCommand extends Command {
private static final int MINIMUM_ARGUMENTS = 1; private static final int MINIMUM_ARGUMENTS = 1;
public UnregisterCommand() { public UnregisterCommand() {
super("unregister", options("&cAn expansion name must be specified!", MINIMUM_ARGUMENTS)); super("unregister", options("&cAn expansion name must be specified!", MINIMUM_ARGUMENTS, "placeholderapi.register"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
String requestedExpansion = args[0]; final String requestedExpansion = args[0];
PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionManager() final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionManager()
.getRegisteredExpansion(requestedExpansion); .getRegisteredExpansion(requestedExpansion);
if (expansion == null) { if (expansion == null) {
Msg.msg(sender, "&cFailed to find expansion: &f" + requestedExpansion); Msg.msg(sender, "&cFailed to find expansion: &f" + requestedExpansion);
return; return;
} }
@ -37,11 +39,12 @@ public final class UnregisterCommand extends Command {
} }
} }
@NotNull
@Override @Override
public List<String> handleCompletion(CommandSender sender, String[] args) { public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MINIMUM_ARGUMENTS) { if (args.length == MINIMUM_ARGUMENTS) {
Set<String> completions = PlaceholderAPI.getRegisteredIdentifiers(); final Set<String> completions = PlaceholderAPI.getRegisteredIdentifiers();
return StringUtil.copyPartialMatches(args[0], completions, new ArrayList<>(completions.size())); return StringUtil.copyPartialMatches(args[0], completions, new ArrayList<>(completions.size()));
} }

View File

@ -7,6 +7,7 @@ import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -33,8 +34,8 @@ public final class VersionCommand extends Command {
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PluginDescriptionFile description = PlaceholderAPIPlugin.getInstance().getDescription(); final PluginDescriptionFile description = PlaceholderAPIPlugin.getInstance().getDescription();
Msg.msg(sender, "PlaceholderAPI &7version &b&o" + description.getVersion(), Msg.msg(sender, "PlaceholderAPI &7version &b&o" + description.getVersion(),
"&fCreated by&7: &b" + description.getAuthors(), "&fCreated by&7: &b" + description.getAuthors(),
@ -42,9 +43,9 @@ public final class VersionCommand extends Command {
"&fEcloud commands: &b/papi ecloud"); "&fEcloud commands: &b/papi ecloud");
} }
@NotNull
@Override @Override
public List<String> handleCompletion(CommandSender sender, String[] args) { public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == 1) { if (args.length == 1) {
return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size())); return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size()));
} }

View File

@ -4,14 +4,15 @@ import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class EcloudClearCommand extends Command { public final class EcloudClearCommand extends Command {
public EcloudClearCommand() { public EcloudClearCommand() {
super("ecloud clear"); super("ecloud clear", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin.getInstance().getExpansionCloud().clean(); PlaceholderAPIPlugin.getInstance().getExpansionCloud().clean();
Msg.msg(sender, "&aThe cache has been cleared!!"); Msg.msg(sender, "&aThe cache has been cleared!!");
} }

View File

@ -9,24 +9,25 @@ import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class EcloudDownloadCommand extends Command { public final class EcloudDownloadCommand extends Command {
public EcloudDownloadCommand() { public EcloudDownloadCommand() {
super("ecloud download", options("&cAn expansion name must be specified!", 1)); super("ecloud download", options("&cAn expansion name must be specified!", 1, "placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
String input = args[0]; final String input = args[0];
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(input); final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(input);
if (expansion == null) { if (expansion == null) {
Msg.msg(sender, "&cNo expansion found with the name: &f" + input); Msg.msg(sender, "&cNo expansion found with the name: &f" + input);
return; return;
} }
PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(input); final PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(input);
if (loaded != null && loaded.isRegistered()) { if (loaded != null && loaded.isRegistered()) {
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier()); PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
} }
@ -45,23 +46,10 @@ public final class EcloudDownloadCommand extends Command {
} }
Msg.msg(sender, "&aDownload starting for expansion: &f" + expansion.getName() + " &aversion: &f" + version); Msg.msg(sender, "&aDownload starting for expansion: &f" + expansion.getName() + " &aversion: &f" + version);
String player = ((sender instanceof Player) ? sender.getName() : null); final String player = ((sender instanceof Player) ? sender.getName() : null);
ExpansionCloudManager cloud = plugin.getExpansionCloud(); final ExpansionCloudManager cloud = plugin.getExpansionCloud();
cloud.downloadExpansion(player, expansion, version); cloud.downloadExpansion(player, expansion, version);
cloud.clean(); cloud.clean();
cloud.fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); cloud.fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions());
} }
// @Override
// public List<String> handleCompletion(CommandSender sender, String[] args) {
// List<String> downloads = new ArrayList<>();
// if (!PlaceholderAPI.isRegistered("player")) downloads.add("player");
//
// for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
// String identifier = plugin.getName();
// if (!PlaceholderAPI.isRegistered(identifier)) downloads.add(identifier);
// }
//
// return downloads;
// }
} }

View File

@ -7,18 +7,19 @@ import me.clip.placeholderapi.util.Msg;
import me.rayzr522.jsonmessage.JSONMessage; import me.rayzr522.jsonmessage.JSONMessage;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static me.clip.placeholderapi.util.Msg.color; import static me.clip.placeholderapi.util.Msg.color;
public final class EcloudInfoCommand extends Command { public final class EcloudInfoCommand extends Command {
public EcloudInfoCommand() { public EcloudInfoCommand() {
super("ecloud info", options("&cAn expansion name must be specified!", 1)); super("ecloud info", options("&cAn expansion name must be specified!", 1, "placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
String input = args[0]; final String input = args[0];
CloudExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionCloud().getCloudExpansion(input); final CloudExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionCloud().getCloudExpansion(input);
if (expansion == null) { if (expansion == null) {
Msg.msg(sender, "&cNo expansion found by the name: &f" + input); Msg.msg(sender, "&cNo expansion found by the name: &f" + input);
@ -34,7 +35,7 @@ public final class EcloudInfoCommand extends Command {
return; return;
} }
Player p = (Player) sender; final Player p = (Player) sender;
Msg.msg(sender, "&bExpansion&7: &f" + expansion.getName(), Msg.msg(sender, "&bExpansion&7: &f" + expansion.getName(),
"&bAuthor: &f" + expansion.getAuthor(), "&bAuthor: &f" + expansion.getAuthor(),
@ -42,7 +43,7 @@ public final class EcloudInfoCommand extends Command {
); );
// latest version // latest version
JSONMessage latestVersion = JSONMessage final JSONMessage latestVersion = JSONMessage
.create(color("&bLatest version: &f" + expansion.getLatestVersion())); .create(color("&bLatest version: &f" + expansion.getLatestVersion()));
latestVersion.tooltip(color("&bReleased: &f" + expansion.getTimeSinceLastUpdate() latestVersion.tooltip(color("&bReleased: &f" + expansion.getTimeSinceLastUpdate()
+ "\n&bUpdate information: &f" + expansion.getVersion().getReleaseNotes() + "\n&bUpdate information: &f" + expansion.getVersion().getReleaseNotes()
@ -50,7 +51,7 @@ public final class EcloudInfoCommand extends Command {
latestVersion.send(p); latestVersion.send(p);
// versions // versions
JSONMessage versions = JSONMessage final JSONMessage versions = JSONMessage
.create(color("&bVersions available: &f" + expansion.getVersions().size())); .create(color("&bVersions available: &f" + expansion.getVersions().size()));
versions.tooltip(color(String.join("&b, &f", expansion.getAvailableVersions()))); versions.tooltip(color(String.join("&b, &f", expansion.getAvailableVersions())));
versions.suggestCommand( versions.suggestCommand(
@ -59,7 +60,7 @@ public final class EcloudInfoCommand extends Command {
// placeholders // placeholders
if (expansion.getPlaceholders() != null) { if (expansion.getPlaceholders() != null) {
JSONMessage placeholders = JSONMessage final JSONMessage placeholders = JSONMessage
.create(color("&bPlaceholders: &f" + expansion.getPlaceholders().size())); .create(color("&bPlaceholders: &f" + expansion.getPlaceholders().size()));
placeholders.tooltip(color(String.join("&b, &f", expansion.getPlaceholders()))); placeholders.tooltip(color(String.join("&b, &f", expansion.getPlaceholders())));
placeholders.suggestCommand("/papi ecloud placeholders " + expansion.getName()); placeholders.suggestCommand("/papi ecloud placeholders " + expansion.getName());

View File

@ -9,6 +9,7 @@ import me.rayzr522.jsonmessage.JSONMessage;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -24,12 +25,13 @@ public final class EcloudListCommand extends Command {
); );
public EcloudListCommand() { public EcloudListCommand() {
super("ecloud list", options("&cIncorrect usage! &7/papi ecloud list <all/author/installed> (page)", MINIMUM_ARGUMENTS)); super("ecloud list", options("&cIncorrect usage! &7/papi ecloud list <all/author/installed> (page)",
MINIMUM_ARGUMENTS, "placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
int page = 1; int page = 1;
String author; String author;
@ -101,7 +103,7 @@ public final class EcloudListCommand extends Command {
Msg.msg(sender, "&6Gold = Expansions which need updated"); Msg.msg(sender, "&6Gold = Expansions which need updated");
if (!(sender instanceof Player)) { if (!(sender instanceof Player)) {
Map<String, CloudExpansion> expansions = new HashMap<>(); final Map<String, CloudExpansion> expansions = new HashMap<>();
for (CloudExpansion exp : ex.values()) { for (CloudExpansion exp : ex.values()) {
if (exp == null || exp.getName() == null) { if (exp == null || exp.getName() == null) {
@ -111,7 +113,7 @@ public final class EcloudListCommand extends Command {
expansions.put(exp.getName(), exp); expansions.put(exp.getName(), exp);
} }
List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList()); final List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList());
int i = (int) ex.keySet().toArray()[0]; int i = (int) ex.keySet().toArray()[0];
@ -120,7 +122,7 @@ public final class EcloudListCommand extends Command {
continue; continue;
} }
CloudExpansion expansion = expansions.get(name); final CloudExpansion expansion = expansions.get(name);
Msg.msg(sender, Msg.msg(sender,
"&b" + i + "&7: " + (expansion.shouldUpdate() ? "&6" "&b" + i + "&7: " + (expansion.shouldUpdate() ? "&6"
@ -132,11 +134,11 @@ public final class EcloudListCommand extends Command {
return; return;
} }
Player p = (Player) sender; final Player p = (Player) sender;
Map<String, CloudExpansion> expansions = new HashMap<>(); final Map<String, CloudExpansion> expansions = new HashMap<>();
for (CloudExpansion exp : ex.values()) { for (final CloudExpansion exp : ex.values()) {
if (exp == null || exp.getName() == null) { if (exp == null || exp.getName() == null) {
continue; continue;
} }
@ -144,7 +146,7 @@ public final class EcloudListCommand extends Command {
expansions.put(exp.getName(), exp); expansions.put(exp.getName(), exp);
} }
List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList()); final List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList());
int i = page > 1 ? page * 10 : 0; int i = page > 1 ? page * 10 : 0;
@ -153,8 +155,8 @@ public final class EcloudListCommand extends Command {
continue; continue;
} }
CloudExpansion expansion = expansions.get(name); final CloudExpansion expansion = expansions.get(name);
StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
if (expansion.shouldUpdate()) { if (expansion.shouldUpdate()) {
sb.append("&6Click to update to the latest version of this expansion\n\n"); sb.append("&6Click to update to the latest version of this expansion\n\n");
@ -170,13 +172,13 @@ public final class EcloudListCommand extends Command {
sb.append("&bLast updated&7: &f").append(expansion.getTimeSinceLastUpdate()).append(" ago\n"); sb.append("&bLast updated&7: &f").append(expansion.getTimeSinceLastUpdate()).append(" ago\n");
sb.append("\n").append(expansion.getDescription()); sb.append("\n").append(expansion.getDescription());
String msg = color( final String msg = color(
"&b" + (i + 1) + "&7: " + (expansion.shouldUpdate() ? "&6" "&b" + (i + 1) + "&7: " + (expansion.shouldUpdate() ? "&6"
: (expansion.hasExpansion() ? "&a" : "")) + expansion.getName()); : (expansion.hasExpansion() ? "&a" : "")) + expansion.getName());
String hover = color(sb.toString()); final String hover = color(sb.toString());
JSONMessage line = JSONMessage.create(msg); final JSONMessage line = JSONMessage.create(msg);
line.tooltip(hover); line.tooltip(hover);
if (expansion.shouldUpdate() || !expansion.hasExpansion()) { if (expansion.shouldUpdate() || !expansion.hasExpansion()) {
@ -190,9 +192,9 @@ public final class EcloudListCommand extends Command {
} }
} }
@NotNull
@Override @Override
public List<String> handleCompletion(CommandSender sender, String[] args) { public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MINIMUM_ARGUMENTS) { if (args.length == MINIMUM_ARGUMENTS) {
return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size())); return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size()));
} }

View File

@ -8,26 +8,27 @@ import me.clip.placeholderapi.util.Msg;
import me.rayzr522.jsonmessage.JSONMessage; import me.rayzr522.jsonmessage.JSONMessage;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
public final class EcloudPlaceholdersCommand extends Command { public final class EcloudPlaceholdersCommand extends Command {
public EcloudPlaceholdersCommand() { public EcloudPlaceholdersCommand() {
super("ecloud placeholders", options("&cAn expansion name must be specified!", 1)); super("ecloud placeholders", options("&cAn expansion name must be specified!", 1, "placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
String input = args[0]; final String input = args[0];
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(input); final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(input);
if (expansion == null) { if (expansion == null) {
Msg.msg(sender, "&cNo expansion found by the name: &f" + input); Msg.msg(sender, "&cNo expansion found by the name: &f" + input);
return; return;
} }
List<String> placeholders = expansion.getPlaceholders(); final List<String> placeholders = expansion.getPlaceholders();
if (placeholders == null) { if (placeholders == null) {
Msg.msg(sender, "&cThe expansion: &f" + expansion.getName() Msg.msg(sender, "&cThe expansion: &f" + expansion.getName()
+ " &cdoes not have any placeholders listed.", + " &cdoes not have any placeholders listed.",
@ -44,15 +45,15 @@ public final class EcloudPlaceholdersCommand extends Command {
return; return;
} }
Player p = (Player) sender; final Player p = (Player) sender;
JSONMessage message = JSONMessage.create(Msg.color("&bPlaceholders: &f" + placeholders.size())); final JSONMessage message = JSONMessage.create(Msg.color("&bPlaceholders: &f" + placeholders.size()));
message.then("\n"); message.then("\n");
for (int i = 0; i < placeholders.size(); i++) { for (int i = 0; i < placeholders.size(); i++) {
message.then(i == placeholders.size() - 1 ? placeholders.get(i) : Msg.color(placeholders.get(i) + "&b, &f")); message.then(i == placeholders.size() - 1 ? placeholders.get(i) : Msg.color(placeholders.get(i) + "&b, &f"));
try { try {
message.tooltip(PlaceholderAPI.setPlaceholders(p, placeholders.get(i))); message.tooltip(PlaceholderAPI.setPlaceholders(p, placeholders.get(i)));
} catch (Exception ignored) { } catch (final Exception ignored) {
// Ignored exception // Ignored exception
} }
} }

View File

@ -5,16 +5,17 @@ import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager; import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class EcloudRefreshCommand extends Command { public final class EcloudRefreshCommand extends Command {
public EcloudRefreshCommand() { public EcloudRefreshCommand() {
super("ecloud refresh"); super("ecloud refresh", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
ExpansionCloudManager cloud = plugin.getExpansionCloud(); final ExpansionCloudManager cloud = plugin.getExpansionCloud();
Msg.msg(sender, "&aRefresh task started. Use &f/papi ecloud list all &ain a few!!"); Msg.msg(sender, "&aRefresh task started. Use &f/papi ecloud list all &ain a few!!");
cloud.clean(); cloud.clean();
cloud.fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); cloud.fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions());

View File

@ -4,15 +4,16 @@ import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command; import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class EcloudStatusCommand extends Command { public final class EcloudStatusCommand extends Command {
public EcloudStatusCommand() { public EcloudStatusCommand() {
super("ecloud status"); super("ecloud status", permissions("placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance(); final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
Msg.msg(sender, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size() Msg.msg(sender, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size()
+ " &bexpansions available on the cloud.", + " &bexpansions available on the cloud.",
"&7A total of &f" + plugin.getExpansionCloud().getCloudAuthorCount() "&7A total of &f" + plugin.getExpansionCloud().getCloudAuthorCount()

View File

@ -7,22 +7,24 @@ import me.clip.placeholderapi.util.Msg;
import me.rayzr522.jsonmessage.JSONMessage; import me.rayzr522.jsonmessage.JSONMessage;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class EcloudVersionInfoCommand extends Command { public final class EcloudVersionInfoCommand extends Command {
public EcloudVersionInfoCommand() { public EcloudVersionInfoCommand() {
super("ecloud versioninfo", options("&cIncorrect usage! &7/papi ecloud versioninfo <name> <version>", 2)); super("ecloud versioninfo", options("&cIncorrect usage! &7/papi ecloud versioninfo <name> <version>",
2, "placeholderapi.ecloud"));
} }
@Override @Override
public void execute(CommandSender sender, String[] args) { public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
String input = args[0]; final String input = args[0];
CloudExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionCloud().getCloudExpansion(input); final CloudExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionCloud().getCloudExpansion(input);
if (expansion == null) { if (expansion == null) {
Msg.msg(sender, "&cNo expansion found by the name: &f" + input); Msg.msg(sender, "&cNo expansion found by the name: &f" + input);
return; return;
} }
CloudExpansion.Version version = expansion.getVersion(args[1]); final CloudExpansion.Version version = expansion.getVersion(args[1]);
if (version == null) { if (version == null) {
Msg.msg(sender, "&cThe version specified does not exist for expansion: &f" + expansion.getName()); Msg.msg(sender, "&cThe version specified does not exist for expansion: &f" + expansion.getName());
return; return;
@ -37,10 +39,10 @@ public final class EcloudVersionInfoCommand extends Command {
return; return;
} }
Player p = (Player) sender; final Player p = (Player) sender;
JSONMessage download = JSONMessage.create(Msg.color("&7Click to download this version")); final JSONMessage download = JSONMessage.create(Msg.color("&7Click to download this version"));
download.suggestCommand( download.suggestCommand(
"/papi ecloud download " + expansion.getName() + ' ' + version.getVersion()); "/papi ecloud download " + expansion.getName() + " " + version.getVersion());
download.send(p); download.send(p);
} }
} }

View File

@ -0,0 +1,8 @@
package me.clip.placeholderapi.exceptions;
public final class NoDefaultCommandException extends RuntimeException {
public NoDefaultCommandException(final String message) {
super(message);
}
}

View File

@ -28,6 +28,7 @@ package me.clip.placeholderapi.expansion;
* @author Ryan McCarthy * @author Ryan McCarthy
*/ */
public interface Cacheable { public interface Cacheable {
/** /**
* Called when the implementing class is unregistered from PlaceholderAPI * Called when the implementing class is unregistered from PlaceholderAPI
*/ */

View File

@ -30,10 +30,11 @@ import org.bukkit.entity.Player;
* @author Ryan McCarthy * @author Ryan McCarthy
*/ */
public interface Cleanable { public interface Cleanable {
/** /**
* Called when a player leaves the server * Called when a player leaves the server
* *
* @param player (@link Player} who left the server * @param p (@link Player} who left the server
*/ */
void cleanup(Player player); void cleanup(Player p);
} }

View File

@ -20,7 +20,6 @@
*/ */
package me.clip.placeholderapi.expansion; package me.clip.placeholderapi.expansion;
import com.google.common.base.Strings;
import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook; import me.clip.placeholderapi.PlaceholderHook;
@ -42,13 +41,15 @@ public final class ExpansionManager {
public ExpansionManager(PlaceholderAPIPlugin instance) { public ExpansionManager(PlaceholderAPIPlugin instance) {
plugin = instance; plugin = instance;
File f = new File(plugin.getDataFolder(), "expansions"); File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), "expansions");
if (!f.exists()) f.mkdirs(); if (!f.exists()) {
f.mkdirs();
}
} }
public PlaceholderExpansion getRegisteredExpansion(String name) { public PlaceholderExpansion getRegisteredExpansion(String name) {
for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) { for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) {
if (hook.getValue().isExpansion()) { if (hook.getValue() instanceof PlaceholderExpansion) {
if (name.equalsIgnoreCase(hook.getKey())) { if (name.equalsIgnoreCase(hook.getKey())) {
return (PlaceholderExpansion) hook.getValue(); return (PlaceholderExpansion) hook.getValue();
} }
@ -59,28 +60,31 @@ public final class ExpansionManager {
} }
public boolean registerExpansion(PlaceholderExpansion expansion) { public boolean registerExpansion(PlaceholderExpansion expansion) {
if (expansion == null || expansion.getIdentifier() == null) return false; if (expansion == null || expansion.getIdentifier() == null) {
return false;
}
if (expansion instanceof Configurable) { if (expansion instanceof Configurable) {
Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); Map<String, Object> defaults = ((Configurable) expansion).getDefaults();
String pre = expansion.getPathStarter(); String pre = "expansions." + expansion.getIdentifier() + ".";
FileConfiguration cfg = plugin.getConfig(); FileConfiguration cfg = plugin.getConfig();
boolean save = false; boolean save = false;
if (defaults != null) { if (defaults != null) {
for (Entry<String, Object> entry : defaults.entrySet()) { for (Entry<String, Object> entries : defaults.entrySet()) {
String key = entry.getKey(); if (entries.getKey() == null || entries.getKey().isEmpty()) {
if (Strings.isNullOrEmpty(key)) continue; continue;
}
if (entry.getValue() == null) { if (entries.getValue() == null) {
if (cfg.contains(pre + key)) { if (cfg.contains(pre + entries.getKey())) {
save = true; save = true;
cfg.set(pre + key, null); cfg.set(pre + entries.getKey(), null);
} }
} else { } else {
if (!cfg.contains(pre + key)) { if (!cfg.contains(pre + entries.getKey())) {
save = true; save = true;
cfg.set(pre + key, entry.getValue()); cfg.set(pre + entries.getKey(), entries.getValue());
} }
} }
} }
@ -103,11 +107,17 @@ public final class ExpansionManager {
} }
} }
if (!expansion.canRegister()) return false; if (!expansion.canRegister()) {
if (!expansion.register()) return false; return false;
}
if (!expansion.register()) {
return false;
}
if (expansion instanceof Listener) { if (expansion instanceof Listener) {
Bukkit.getPluginManager().registerEvents((Listener) expansion, plugin); Listener l = (Listener) expansion;
Bukkit.getPluginManager().registerEvents(l, plugin);
} }
plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier());
@ -133,18 +143,29 @@ public final class ExpansionManager {
public PlaceholderExpansion registerExpansion(String fileName) { public PlaceholderExpansion registerExpansion(String fileName) {
List<Class<?>> subs = FileUtil.getClasses("expansions", fileName, PlaceholderExpansion.class); List<Class<?>> subs = FileUtil.getClasses("expansions", fileName, PlaceholderExpansion.class);
if (subs == null || subs.isEmpty()) return null; if (subs == null || subs.isEmpty()) {
return null;
}
// Only register the first instance found as an expansion JAR should only have 1 class // only register the first instance found as an expansion jar should only have 1 class
// extending PlaceholderExpansion // extending PlaceholderExpansion
PlaceholderExpansion ex = createInstance(subs.get(0)); PlaceholderExpansion ex = createInstance(subs.get(0));
if (registerExpansion(ex)) return ex; if (registerExpansion(ex)) {
return ex;
}
return null; return null;
} }
public void registerAllExpansions() { public void registerAllExpansions() {
if (plugin == null) {
return;
}
List<Class<?>> subs = FileUtil.getClasses("expansions", null, PlaceholderExpansion.class); List<Class<?>> subs = FileUtil.getClasses("expansions", null, PlaceholderExpansion.class);
if (subs == null || subs.isEmpty()) return; if (subs == null || subs.isEmpty()) {
return;
}
for (Class<?> klass : subs) { for (Class<?> klass : subs) {
PlaceholderExpansion ex = createInstance(klass); PlaceholderExpansion ex = createInstance(klass);
@ -159,29 +180,34 @@ public final class ExpansionManager {
} }
} }
private PlaceholderExpansion createInstance(Class<?> clazz) { private PlaceholderExpansion createInstance(Class<?> klass) {
if (clazz == null) return null; if (klass == null) {
if (!PlaceholderExpansion.class.isAssignableFrom(clazz)) return null; return null;
}
PlaceholderExpansion ex = null;
if (!PlaceholderExpansion.class.isAssignableFrom(klass)) {
return null;
}
PlaceholderExpansion expansion = null;
try { try {
Constructor<?>[] constructors = clazz.getConstructors(); Constructor<?>[] c = klass.getConstructors();
if (constructors.length == 0) { if (c.length == 0) {
expansion = (PlaceholderExpansion) clazz.newInstance(); ex = (PlaceholderExpansion) klass.newInstance();
} else { } else {
for (Constructor<?> ctor : constructors) { for (Constructor<?> con : c) {
if (ctor.getParameterTypes().length == 0) { if (con.getParameterTypes().length == 0) {
expansion = (PlaceholderExpansion) ctor.newInstance(); ex = (PlaceholderExpansion) klass.newInstance();
break; break;
} }
} }
} }
} catch (Throwable t) { } catch (Throwable t) {
plugin.getLogger() plugin.getLogger()
.severe("Failed to init placeholder expansion from class: " + clazz.getName()); .severe("Failed to init placeholder expansion from class: " + klass.getName());
plugin.getLogger().severe(t.getMessage()); plugin.getLogger().severe(t.getMessage());
} }
return expansion; return ex;
} }
} }

View File

@ -20,28 +20,26 @@
*/ */
package me.clip.placeholderapi.expansion; package me.clip.placeholderapi.expansion;
import com.google.common.base.Enums;
import java.util.Optional;
public enum NMSVersion { public enum NMSVersion {
UNKNOWN("unknown"),
SPIGOT_1_7_R1("v1_7_R1"), UNKNOWN("unknown"),
SPIGOT_1_7_R2("v1_7_R2"), SPIGOT_1_7_R1("v1_7_R1"),
SPIGOT_1_7_R3("v1_7_R3"), SPIGOT_1_7_R2("v1_7_R2"),
SPIGOT_1_7_R4("v1_7_R4"), SPIGOT_1_7_R3("v1_7_R3"),
SPIGOT_1_8_R1("v1_8_R1"), SPIGOT_1_7_R4("v1_7_R4"),
SPIGOT_1_8_R2("v1_8_R2"), SPIGOT_1_8_R1("v1_8_R1"),
SPIGOT_1_8_R3("v1_8_R3"), SPIGOT_1_8_R2("v1_8_R2"),
SPIGOT_1_9_R1("v1_9_R1"), SPIGOT_1_8_R3("v1_8_R3"),
SPIGOT_1_9_R2("v1_9_R2"), SPIGOT_1_9_R1("v1_9_R1"),
SPIGOT_1_10_R1("v1_10_R1"), SPIGOT_1_9_R2("v1_9_R2"),
SPIGOT_1_11_R1("v1_11_R1"), SPIGOT_1_10_R1("v1_10_R1"),
SPIGOT_1_12_R1("v1_12_R1"), SPIGOT_1_11_R1("v1_11_R1"),
SPIGOT_1_13_R1("v1_13_R1"), SPIGOT_1_12_R1("v1_12_R1"),
SPIGOT_1_13_R2("v1_13_R2"), SPIGOT_1_13_R1("v1_13_R1"),
SPIGOT_1_14_R1("v1_14_R1"), SPIGOT_1_13_R2("v1_13_R2"),
SPIGOT_1_15_R1("v1_15_R1"); SPIGOT_1_14_R1("v1_14_R1"),
SPIGOT_1_15_R1("v1_15_R1"),
SPIGOT_1_16_R1("v1_16_R1");
private final String version; private final String version;
@ -50,12 +48,17 @@ public enum NMSVersion {
} }
public static NMSVersion getVersion(String version) { public static NMSVersion getVersion(String version) {
// Guava caches values() as well. for (NMSVersion v : values()) {
Optional<NMSVersion> opt = Enums.getIfPresent(NMSVersion.class, version).toJavaUtil(); if (v.getVersion().equalsIgnoreCase(version)) {
return opt.orElse(NMSVersion.UNKNOWN); return v;
}
}
return NMSVersion.UNKNOWN;
} }
public String getVersion() { public String getVersion() {
return version; return version;
} }
} }

View File

@ -26,11 +26,11 @@ import me.clip.placeholderapi.PlaceholderHook;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.List; import java.util.List;
public abstract class PlaceholderExpansion extends PlaceholderHook { public abstract class PlaceholderExpansion extends PlaceholderHook {
/** /**
* The name of this expansion * The name of this expansion
* *
@ -123,58 +123,60 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
} }
/** /**
* Quick getter for the {@link PlaceholderAPIPlugin} config. * Quick getter for the {@link PlaceholderAPIPlugin} instance
* *
* @return {@link PlaceholderAPIPlugin} config instance. * @return {@link PlaceholderAPIPlugin} instance
*/ */
public FileConfiguration getConfig() { public PlaceholderAPIPlugin getPlaceholderAPI() {
return PlaceholderAPIPlugin.getInstance().getConfig(); return PlaceholderAPIPlugin.getInstance();
} }
public String getString(String path, String def) { public String getString(String path, String def) {
return getConfig().getString(getPathStarter() + path, def); return getPlaceholderAPI().getConfig()
.getString("expansions." + getIdentifier() + "." + path, def);
} }
public int getInt(String path, int def) { public int getInt(String path, int def) {
return getConfig().getInt(getPathStarter() + path, def); return getPlaceholderAPI().getConfig()
.getInt("expansions." + getIdentifier() + "." + path, def);
} }
public long getLong(String path, long def) { public long getLong(String path, long def) {
return getConfig().getLong(getPathStarter() + path, def); return getPlaceholderAPI().getConfig()
.getLong("expansions." + getIdentifier() + "." + path, def);
} }
public double getDouble(String path, double def) { public double getDouble(String path, double def) {
return getConfig().getDouble(getPathStarter() + path, def); return getPlaceholderAPI().getConfig()
.getDouble("expansions." + getIdentifier() + "." + path, def);
} }
public List<String> getStringList(String path) { public List<String> getStringList(String path) {
return getConfig().getStringList(getPathStarter() + path); return getPlaceholderAPI().getConfig()
.getStringList("expansions." + getIdentifier() + "." + path);
} }
public Object get(String path, Object def) { public Object get(String path, Object def) {
return getConfig().get(getPathStarter() + path, def); return getPlaceholderAPI().getConfig().get("expansions." + getIdentifier() + "." + path, def);
} }
public ConfigurationSection getConfigSection(String path) { public ConfigurationSection getConfigSection(String path) {
return getConfig().getConfigurationSection(getPathStarter() + path); return getPlaceholderAPI().getConfig()
.getConfigurationSection("expansions." + getIdentifier() + "." + path);
} }
public ConfigurationSection getConfigSection() { public ConfigurationSection getConfigSection() {
return getConfig().getConfigurationSection("expansions." + getIdentifier()); return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier());
} }
public boolean configurationContains(String path) { public boolean configurationContains(String path) {
return getConfig().contains(getPathStarter() + path); return getPlaceholderAPI().getConfig().contains("expansions." + getIdentifier() + "." + path);
} }
protected String getPathStarter() {
return "expansions." + getIdentifier() + '.';
}
/** /**
* @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()} * @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()}
*/ */
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated @Deprecated
public String getPlugin() { public String getPlugin() {
return null; return null;

View File

@ -23,5 +23,6 @@ package me.clip.placeholderapi.expansion;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public interface Relational { public interface Relational {
String onPlaceholderRequest(Player one, Player two, String identifier); String onPlaceholderRequest(Player one, Player two, String identifier);
} }

View File

@ -20,7 +20,9 @@
*/ */
package me.clip.placeholderapi.expansion; package me.clip.placeholderapi.expansion;
public interface Taskable { public interface Taskable {
/** /**
* Called when the implementing class has successfully been registered to the placeholder map * 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 * Tasks that need to be performed when this expansion is registered should go here

View File

@ -21,6 +21,7 @@
package me.clip.placeholderapi.expansion; package me.clip.placeholderapi.expansion;
public final class Version { public final class Version {
private final boolean isSpigot; private final boolean isSpigot;
private final String version; private final String version;
@ -40,4 +41,5 @@ public final class Version {
public boolean compareTo(String version) { public boolean compareTo(String version) {
return getVersion().equalsIgnoreCase(version); return getVersion().equalsIgnoreCase(version);
} }
} }

View File

@ -36,5 +36,5 @@ public interface VersionSpecific {
* *
* @return true if your expansion is compatible with the version the server is running. * @return true if your expansion is compatible with the version the server is running.
*/ */
boolean isCompatibleWith(Version version); boolean isCompatibleWith(Version v);
} }

View File

@ -26,8 +26,11 @@ import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class CloudExpansion { public class CloudExpansion {
private String name, author,
private String name,
author,
latest_version, latest_version,
description, description,
source_url, source_url,
@ -71,12 +74,14 @@ public class CloudExpansion {
} }
public Version getVersion() { public Version getVersion() {
return latest_version == null ? null : getVersion(latest_version); return getLatestVersion() == null ? null : getVersion(getLatestVersion());
} }
public Version getVersion(String version) { public Version getVersion(String version) {
return versions == null ? null : versions.stream() return versions == null ? null : versions.stream()
.filter(v -> v.getVersion().equals(version)).findFirst().orElse(null); .filter(v -> v.getVersion().equals(version))
.findFirst()
.orElse(null);
} }
public List<String> getAvailableVersions() { public List<String> getAvailableVersions() {
@ -135,10 +140,6 @@ public class CloudExpansion {
return verified; return verified;
} }
public void setVerified(boolean verified) {
this.verified = verified;
}
public long getLastUpdate() { public long getLastUpdate() {
return last_update; return last_update;
} }
@ -155,10 +156,6 @@ public class CloudExpansion {
return average_rating; return average_rating;
} }
public void setAverage_rating(double average_rating) {
this.average_rating = average_rating;
}
public List<String> getPlaceholders() { public List<String> getPlaceholders() {
return placeholders; return placeholders;
} }
@ -175,11 +172,7 @@ public class CloudExpansion {
this.versions = versions; this.versions = versions;
} }
public void setRatings_count(long ratings_count) { public class Version {
this.ratings_count = ratings_count;
}
public static class Version {
private String url, version, release_notes; private String url, version, release_notes;
public String getUrl() { public String getUrl() {

View File

@ -37,29 +37,37 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
public class ExpansionCloudManager { public class ExpansionCloudManager {
private static final String API_URL = "http://api.extendedclip.com/v2/"; private static final String API_URL = "http://api.extendedclip.com/v2/";
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
private final PlaceholderAPIPlugin plugin; private final PlaceholderAPIPlugin plugin;
private final File expansionsDir; private final File expansionsDir;
private final Set<String> downloading = new HashSet<>(); private final List<String> downloading = new ArrayList<>();
private final Map<Integer, CloudExpansion> remote = new TreeMap<>(); private final Map<Integer, CloudExpansion> remote = new TreeMap<>();
public ExpansionCloudManager(PlaceholderAPIPlugin plugin) { public ExpansionCloudManager(PlaceholderAPIPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
expansionsDir = new File(plugin.getDataFolder(), "expansions"); expansionsDir = new File(plugin.getDataFolder(), "expansions");
if (expansionsDir.mkdirs()) { final boolean result = expansionsDir.mkdirs();
if (result) {
plugin.getLogger().info("Created Expansions Directory"); plugin.getLogger().info("Created Expansions Directory");
} }
} }
public void clean() { public void clean() {
remote.clear(); remote.clear();
downloading.clear(); downloading.clear();
} }
public Map<Integer, CloudExpansion> getCloudExpansions() { public Map<Integer, CloudExpansion> getCloudExpansions() {
return remote; return remote;
} }
@ -72,6 +80,7 @@ public class ExpansionCloudManager {
.orElse(null); .orElse(null);
} }
public int getCloudAuthorCount() { public int getCloudAuthorCount() {
return remote.values() return remote.values()
.stream() .stream()
@ -117,10 +126,14 @@ public class ExpansionCloudManager {
public int getPagesAvailable(Map<Integer, CloudExpansion> map, int amount) { public int getPagesAvailable(Map<Integer, CloudExpansion> map, int amount) {
if (map == null) return 0; if (map == null) {
return 0;
}
int pages = map.size() > 0 ? 1 : 0; int pages = map.size() > 0 ? 1 : 0;
if (pages == 0) return 0; if (pages == 0) {
return pages;
}
if (map.size() > amount) { if (map.size() > amount) {
pages = map.size() / amount; pages = map.size() / amount;
@ -146,11 +159,12 @@ public class ExpansionCloudManager {
return ex; return ex;
} }
public void fetch(boolean allowUnverified) { public void fetch(boolean allowUnverified) {
plugin.getLogger().info("Fetching available expansion information..."); plugin.getLogger().info("Fetching available expansion information...");
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
Map<String, CloudExpansion> data = new HashMap<>(); final Map<String, CloudExpansion> data = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(API_URL).openStream()))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(API_URL).openStream()))) {
data.putAll(GSON.fromJson(reader, new TypeToken<Map<String, CloudExpansion>>() { data.putAll(GSON.fromJson(reader, new TypeToken<Map<String, CloudExpansion>>() {
@ -159,12 +173,11 @@ public class ExpansionCloudManager {
if (plugin.getPlaceholderAPIConfig().isDebugMode()) { if (plugin.getPlaceholderAPIConfig().isDebugMode()) {
ex.printStackTrace(); ex.printStackTrace();
} else { } else {
plugin.getLogger().warning("Unable to fetch expansions!\nThere was an error with the server host connecting to the PlaceholderAPI eCloud (https://api" + plugin.getLogger().warning("Unable to fetch expansions!\nThere was an error with the server host connecting to the PlaceholderAPI eCloud (https://api.extendedclip.com/v2/)");
".extendedclip.com/v2/)");
} }
} }
List<CloudExpansion> unsorted = new ArrayList<>(); final List<CloudExpansion> unsorted = new ArrayList<>();
data.forEach((name, cexp) -> { data.forEach((name, cexp) -> {
if ((allowUnverified || cexp.isVerified()) && cexp.getLatestVersion() != null && cexp.getVersion(cexp.getLatestVersion()) != null) { if ((allowUnverified || cexp.isVerified()) && cexp.getLatestVersion() != null && cexp.getVersion(cexp.getLatestVersion()) != null) {
@ -191,6 +204,7 @@ public class ExpansionCloudManager {
} }
plugin.getLogger().info(count + " placeholder expansions are available on the cloud."); plugin.getLogger().info(count + " placeholder expansions are available on the cloud.");
long updates = getToUpdateCount(); long updates = getToUpdateCount();
if (updates > 0) { if (updates > 0) {
@ -206,15 +220,19 @@ public class ExpansionCloudManager {
private void download(URL url, String name) throws IOException { private void download(URL url, String name) throws IOException {
InputStream is = null; InputStream is = null;
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
URLConnection urlConn = url.openConnection(); URLConnection urlConn = url.openConnection();
is = urlConn.getInputStream(); is = urlConn.getInputStream();
fos = new FileOutputStream( fos = new FileOutputStream(
expansionsDir.getAbsolutePath() + File.separator + "Expansion-" + name + ".jar"); expansionsDir.getAbsolutePath() + File.separator + "Expansion-" + name + ".jar");
byte[] buffer = new byte[is.available()]; byte[] buffer = new byte[is.available()];
int l; int l;
while ((l = is.read(buffer)) > 0) { while ((l = is.read(buffer)) > 0) {
@ -234,35 +252,42 @@ public class ExpansionCloudManager {
} }
public void downloadExpansion(String player, CloudExpansion ex) { public void downloadExpansion(final String player, final CloudExpansion ex) {
downloadExpansion(player, ex, ex.getLatestVersion()); downloadExpansion(player, ex, ex.getLatestVersion());
} }
public void downloadExpansion(String player, CloudExpansion ex, String version) { public void downloadExpansion(final String player, final CloudExpansion ex, final String version) {
if (downloading.contains(ex.getName())) { if (downloading.contains(ex.getName())) {
return; return;
} }
CloudExpansion.Version ver = ex.getVersions() final CloudExpansion.Version ver = ex.getVersions()
.stream() .stream()
.filter(v -> v.getVersion().equals(version)) .filter(v -> v.getVersion().equals(version))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
if (ver == null) return; if (ver == null) {
return;
}
downloading.add(ex.getName()); downloading.add(ex.getName());
plugin.getLogger().info("Attempting download of expansion: " + ex.getName() + (player != null ? " by user: " + player : "") + " from url: " + ver.getUrl()); plugin.getLogger().info("Attempting download of expansion: " + ex.getName() + (player != null ? " by user: " + player : "") + " from url: " + ver.getUrl());
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try { try {
download(new URL(ver.getUrl()), ex.getName()); download(new URL(ver.getUrl()), ex.getName());
plugin.getLogger().info("Download of expansion: " + ex.getName() + " complete!"); plugin.getLogger().info("Download of expansion: " + ex.getName() + " complete!");
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger() plugin.getLogger()
.warning("Failed to download expansion: " + ex.getName() + " from: " + ver.getUrl()); .warning("Failed to download expansion: " + ex.getName() + " from: " + ver.getUrl());
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(plugin, () -> {
downloading.remove(ex.getName()); downloading.remove(ex.getName());
if (player != null) { if (player != null) {
@ -289,6 +314,7 @@ public class ExpansionCloudManager {
} }
} }
}); });
}); });
} }
} }

View File

@ -25,7 +25,9 @@ import me.clip.placeholderapi.PlaceholderHook;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@SuppressWarnings("DeprecatedIsStillUsed") /**
* Use {@link me.clip.placeholderapi.expansion.PlaceholderExpansion} instead
*/
@Deprecated @Deprecated
public abstract class EZPlaceholderHook extends PlaceholderHook { public abstract class EZPlaceholderHook extends PlaceholderHook {
@ -33,8 +35,8 @@ public abstract class EZPlaceholderHook extends PlaceholderHook {
private final String plugin; private final String plugin;
public EZPlaceholderHook(Plugin plugin, String identifier) { public EZPlaceholderHook(Plugin plugin, String identifier) {
Validate.notNull(plugin, "Plugin cannot be null"); Validate.notNull(plugin, "Plugin can not be null!");
Validate.notNull(identifier, "Placeholder name cannot be null"); Validate.notNull(identifier, "Placeholder name can not be null!");
this.identifier = identifier; this.identifier = identifier;
this.plugin = plugin.getName(); this.plugin = plugin.getName();
} }

View File

@ -1,39 +0,0 @@
package me.clip.placeholderapi.listeners;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.bukkit.Bukkit;
/**
* The purpose of this class is to filter the console warning messages when the plugin
* tries to load placeholder expansions from other jars in the plugins folder.
*/
public class ApacheListener extends AbstractFilter {
private boolean cancelled = false;
public ApacheListener(PlaceholderAPIPlugin plugin) {
org.apache.logging.log4j.core.Logger logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
logger.addFilter(this);
// 3 second should be more than enough. I have no idea how to unregister a filter.
Bukkit.getScheduler().runTaskLater(plugin, () -> cancelled = true, 3 * 20L);
}
@Override
public Result filter(LogEvent event) {
if (cancelled) return Result.NEUTRAL;
if (event.getLevel() != Level.WARN) return Result.NEUTRAL;
if (!event.getLoggerName().equals("PlaceholderAPI")) return Result.NEUTRAL;
// Format:
// Loaded class {CLASS} from {PLUGIN} {VERSION} which is not a depend, softdepend or loadbefore of this plugin.
// E.g.
// Loaded class com.earth2me.essentials.Essentials from PlaceholderAPI v2.10.5-DEV-84 which is not a depend, softdepend or loadbefore of this plugin.
String message = event.getMessage().getFormattedMessage();
if (message.startsWith("Loaded class") && message.endsWith("which is not a depend, softdepend or loadbefore of this plugin.")) return Result.DENY;
return Result.NEUTRAL;
}
}

View File

@ -37,8 +37,13 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginDisableEvent;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class PlaceholderListener implements Listener { public class PlaceholderListener implements Listener {
private final PlaceholderAPIPlugin plugin; private final PlaceholderAPIPlugin plugin;
public PlaceholderListener(PlaceholderAPIPlugin instance) { public PlaceholderListener(PlaceholderAPIPlugin instance) {
@ -48,23 +53,22 @@ public class PlaceholderListener implements Listener {
@EventHandler @EventHandler
public void onExpansionUnregister(ExpansionUnregisterEvent event) { public void onExpansionUnregister(ExpansionUnregisterEvent event) {
PlaceholderExpansion expansion = event.getExpansion(); if (event.getExpansion() instanceof Listener) {
if (expansion instanceof Listener) { HandlerList.unregisterAll((Listener) event.getExpansion());
HandlerList.unregisterAll((Listener) expansion);
} }
if (expansion instanceof Taskable) { if (event.getExpansion() instanceof Taskable) {
((Taskable) expansion).stop(); ((Taskable) event.getExpansion()).stop();
} }
if (expansion instanceof Cacheable) { if (event.getExpansion() instanceof Cacheable) {
((Cacheable) expansion).clear(); ((Cacheable) event.getExpansion()).clear();
} }
if (plugin.getExpansionCloud() != null) { if (plugin.getExpansionCloud() != null) {
CloudExpansion ex = plugin.getExpansionCloud() CloudExpansion ex = plugin.getExpansionCloud()
.getCloudExpansion(expansion.getName()); .getCloudExpansion(event.getExpansion().getName());
if (ex != null) { if (ex != null) {
ex.setHasExpansion(false); ex.setHasExpansion(false);
@ -74,20 +78,28 @@ public class PlaceholderListener implements Listener {
} }
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
public void onPluginUnload(PluginDisableEvent event) { public void onPluginUnload(PluginDisableEvent e) {
// A plugin name cannot be null. String n = e.getPlugin().getName();
String name = event.getPlugin().getName();
if (name.equals(plugin.getName())) return;
for (PlaceholderHook hook : PlaceholderAPI.getPlaceholders().values()) { if (n.equals(plugin.getName())) {
if (hook.isExpansion()) { return;
PlaceholderExpansion ex = (PlaceholderExpansion) hook; }
if (ex.getRequiredPlugin() == null) continue; Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
if (ex.getRequiredPlugin().equalsIgnoreCase(name)) { for (Entry<String, PlaceholderHook> entry : hooks.entrySet()) {
if (PlaceholderAPI.unregisterExpansion(ex)) { PlaceholderHook hook = entry.getValue();
plugin.getLogger().info("Unregistered placeholder expansion: " + ex.getIdentifier());
if (hook instanceof PlaceholderExpansion) {
PlaceholderExpansion expansion = (PlaceholderExpansion) hook;
if (expansion.getRequiredPlugin() == null) {
continue;
}
if (expansion.getRequiredPlugin().equalsIgnoreCase(n)) {
if (PlaceholderAPI.unregisterExpansion(expansion)) {
plugin.getLogger().info("Unregistered placeholder expansion: " + expansion.getIdentifier());
} }
} }
} }
@ -95,10 +107,16 @@ public class PlaceholderListener implements Listener {
} }
@EventHandler @EventHandler
public void onQuit(PlayerQuitEvent event) { public void onQuit(PlayerQuitEvent e) {
for (PlaceholderHook hook : PlaceholderAPI.getPlaceholders().values()) { Set<PlaceholderExpansion> expansions = PlaceholderAPI.getExpansions();
if (hook instanceof Cleanable) {
((Cleanable) hook).cleanup(event.getPlayer()); if (expansions.isEmpty()) {
return;
}
for (PlaceholderExpansion ex : expansions) {
if (ex instanceof Cleanable) {
((Cleanable) ex).cleanup(e.getPlayer());
} }
} }
} }

View File

@ -31,6 +31,7 @@ import org.bukkit.event.server.ServerLoadEvent;
import java.util.Map; import java.util.Map;
public class ServerLoadEventListener implements Listener { public class ServerLoadEventListener implements Listener {
private final PlaceholderAPIPlugin plugin; private final PlaceholderAPIPlugin plugin;
public ServerLoadEventListener(PlaceholderAPIPlugin instance) { public ServerLoadEventListener(PlaceholderAPIPlugin instance) {
@ -39,19 +40,19 @@ public class ServerLoadEventListener implements Listener {
} }
/** /**
* This method will be called when the server is first loaded. * This method will be called when the server is first loaded
* <p> * <p>
* The goal of the method is to register all the expansions as soon as possible * The goal of the method is to register all the expansions as soon as possible
* especially before players can join. * especially before players can join
* <p> * <p>
* This will ensure no issues with expanions and hooks. * This will ensure no issues with expanions and hooks.
* *
* @param event the server load event. * @param e the server load event
*/ */
@EventHandler @EventHandler
public void onServerLoad(ServerLoadEvent event) { public void onServerLoad(ServerLoadEvent e) {
plugin.getLogger().info("Placeholder expansion registration initializing..."); plugin.getLogger().info("Placeholder expansion registration initializing...");
Map<String, PlaceholderHook> alreadyRegistered = PlaceholderAPI.getPlaceholders(); final Map<String, PlaceholderHook> alreadyRegistered = PlaceholderAPI.getPlaceholders();
plugin.getExpansionManager().registerAllExpansions(); plugin.getExpansionManager().registerAllExpansions();
if (alreadyRegistered != null && !alreadyRegistered.isEmpty()) { if (alreadyRegistered != null && !alreadyRegistered.isEmpty()) {

View File

@ -18,13 +18,13 @@
* *
* *
*/ */
package me.clip.placeholderapi.util; package me.clip.placeholderapi.updatechecker;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.apache.commons.lang.StringUtils; import me.clip.placeholderapi.util.Msg;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
@ -32,11 +32,10 @@ import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
public class UpdateChecker implements Listener { public class UpdateChecker implements Listener {
private static final int RESOURCE_ID = 6245;
private static final String SPIGOT_API = "https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID; private final int RESOURCE_ID = 6245;
private final PlaceholderAPIPlugin plugin; private final PlaceholderAPIPlugin plugin;
private final String pluginVersion; private final String pluginVersion;
private String spigotVersion; private String spigotVersion;
@ -58,35 +57,39 @@ public class UpdateChecker implements Listener {
public void fetch() { public void fetch() {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try { try {
HttpsURLConnection con = (HttpsURLConnection) new URL(SPIGOT_API).openConnection(); HttpsURLConnection con = (HttpsURLConnection) new URL(
"https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection();
// Prevents the server from freezing with bad internet connection.
con.setRequestMethod("GET"); con.setRequestMethod("GET");
con.setConnectTimeout(2000); spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
con.setReadTimeout(2000);
spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)).readLine();
} catch (Exception ex) { } catch (Exception ex) {
plugin.getLogger().warning("Failed to check for updates on spigot."); plugin.getLogger().info("Failed to check for updates on spigot.");
return;
}
if (spigotVersion == null || spigotVersion.isEmpty()) {
return; return;
} }
if (spigotVersion == null || spigotVersion.isEmpty()) return;
updateAvailable = spigotIsNewer(); updateAvailable = spigotIsNewer();
if (!updateAvailable) return;
if (!updateAvailable) {
return;
}
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(plugin, () -> {
plugin.getLogger() plugin.getLogger()
.info("An update for PlaceholderAPI (v" + spigotVersion + ") is available at:"); .info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:");
plugin.getLogger() plugin.getLogger()
.info("https://www.spigotmc.org/resources/" + RESOURCE_ID + '/'); .info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/");
Bukkit.getPluginManager().registerEvents(this, plugin); Bukkit.getPluginManager().registerEvents(this, plugin);
}); });
}); });
} }
private boolean spigotIsNewer() { private boolean spigotIsNewer() {
if (spigotVersion == null || spigotVersion.isEmpty()) return false; if (spigotVersion == null || spigotVersion.isEmpty()) {
return false;
}
String plV = toReadable(pluginVersion); String plV = toReadable(pluginVersion);
String spV = toReadable(spigotVersion); String spV = toReadable(spigotVersion);
@ -94,17 +97,21 @@ public class UpdateChecker implements Listener {
} }
private String toReadable(String version) { private String toReadable(String version) {
if (version.contains("-DEV-")) version = StringUtils.split(version, "-DEV-")[0]; if (version.contains("-DEV-")) {
return StringUtils.remove(version, '.'); version = version.split("-DEV-")[0];
}
return version.replaceAll("\\.", "");
} }
@EventHandler @EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent event) { public void onJoin(PlayerJoinEvent e) {
Player player = event.getPlayer(); if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) {
if (player.hasPermission("placeholderapi.updatenotify")) { Msg.msg(e.getPlayer(),
Msg.msg(player, "&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion()
"&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion() + "&e)", + "&e)"
"&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + '/'); , "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID
+ "/");
} }
} }
} }

View File

@ -0,0 +1,9 @@
package me.clip.placeholderapi.util;
public class Constants {
public static final String ADMIN_PERMISSION = "placeholderapi.admin";
public static final String ECLOUD_PERMISSION = "placeholderapi.ecloud";
public static final String INFO_PERMISSION = "placeholderapi.info";
public static final String LIST_PERMISSION = "placeholderapi.list";
public static final String RELOAD_PERMISSION = "placeholderapi.reload";
}

View File

@ -42,50 +42,65 @@ public class FileUtil {
try { try {
File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder); File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder);
if (!f.exists()) return list; if (!f.exists()) {
return list;
}
FilenameFilter fileNameFilter = (dir, name) -> { FilenameFilter fileNameFilter = (dir, name) -> {
boolean isJar = name.endsWith(".jar");
if (fileName != null) { if (fileName != null) {
return isJar && name.substring(0, name.length() - 4) return name.endsWith(".jar") && name.replace(".jar", "")
.equalsIgnoreCase(fileName.substring(0, fileName.length() - 4)); .equalsIgnoreCase(fileName.replace(".jar", ""));
} }
return isJar; return name.endsWith(".jar");
}; };
File[] jars = f.listFiles(fileNameFilter); File[] jars = f.listFiles(fileNameFilter);
if (jars == null) return list; if (jars == null) {
return list;
}
for (File file : jars) { for (File file : jars) {
list = gather(file.toURI().toURL(), list, type); list = gather(file.toURI().toURL(), list, type);
} }
return list; return list;
} catch (Throwable ignored) { } catch (Throwable t) {
} }
return null; return null;
} }
private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) { private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) {
// list cannot be null. if (list == null) {
list = new ArrayList<>();
}
try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader()); try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
JarInputStream jis = new JarInputStream(jar.openStream())) { JarInputStream jis = new JarInputStream(jar.openStream())) {
JarEntry entry; while (true) {
while ((entry = jis.getNextJarEntry()) != null) { JarEntry j = jis.getNextJarEntry();
String name = entry.getName(); if (j == null) {
if (name == null || name.isEmpty()) continue; break;
}
String name = j.getName();
if (name == null || name.isEmpty()) {
continue;
}
if (name.endsWith(".class")) { if (name.endsWith(".class")) {
name = name.substring(0, name.length() - 6).replace('/', '.'); name = name.replace("/", ".");
String cname = name.substring(0, name.lastIndexOf(".class"));
Class<?> loaded = cl.loadClass(name); Class<?> c = cl.loadClass(cname);
if (clazz.isAssignableFrom(loaded)) list.add(loaded); if (clazz.isAssignableFrom(c)) {
list.add(c);
}
} }
} }
} catch (Throwable ignored) { } catch (Throwable t) {
} }
return list; return list;

View File

@ -24,20 +24,17 @@ import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
public class Msg { import java.util.Arrays;
public static void msg(CommandSender sender, String... messages) { import java.util.Objects;
for (String message : messages) { import java.util.stream.Collectors;
String msg = color(message);
sender.sendMessage(msg); public final class Msg {
} public static void msg(CommandSender s, String... msg) {
s.sendMessage(Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).collect(Collectors.joining("\n")));
} }
public static void broadcast(String... messages) { public static void broadcast(String... msg) {
CommandSender sender = Bukkit.getConsoleSender(); Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).forEach(Bukkit::broadcastMessage);
for (String message : messages) {
String msg = color(message);
sender.sendMessage(msg);
}
} }
public static String color(String text) { public static String color(String text) {

View File

@ -0,0 +1,28 @@
/*
*
* PlaceholderAPI
* Copyright (C) 2019 Ryan McCarthy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
package me.clip.placeholderapi.util;
public enum TimeFormat {
DAYS,
HOURS,
MINUTES,
SECONDS
}

View File

@ -22,10 +22,10 @@ package me.clip.placeholderapi.util;
import java.time.Duration; import java.time.Duration;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
public class TimeUtil { public class TimeUtil {
public static String getRemaining(int seconds, TimeUnit type) {
public static String getRemaining(int seconds, TimeFormat type) {
if (seconds < 60) { if (seconds < 60) {
switch (type) { switch (type) {
case DAYS: case DAYS:
@ -124,8 +124,8 @@ public class TimeUtil {
* @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 seconds) * @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 seconds)
* @return formatted time * @return formatted time
*/ */
public static String getTime(Duration duration) { public static String getTime(final Duration duration) {
StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
long seconds = duration.getSeconds(); long seconds = duration.getSeconds();
long minutes = seconds / 60; long minutes = seconds / 60;

View File

@ -4,51 +4,39 @@ version: ${project.version}
api-version: '1.13' api-version: '1.13'
authors: [extended_clip, Glare] authors: [extended_clip, Glare]
description: ${project.description} description: ${project.description}
commands:
placeholderapi:
description: PlaceholderAPI command
aliases: [papi]
permissions: permissions:
placeholderapi.*: placeholderapi.*:
description: ability to use all commands description: ability to use all commands
children: children:
placeholderapi.admin: true placeholderapi.admin: true
placeholderapi.admin: placeholderapi.admin:
description: ability to use all commands description: ability to use all commands
children: children:
placeholderapi.list: true placeholderapi.list: true
placeholderapi.reload: true placeholderapi.reload: true
placeholderapi.ecloud: true placeholderapi.ecloud: true
placeholderapi.parse: true placeholderapi.parse: true
placeholderapi.register: true placeholderapi.register: true
placeholderapi.updatenotify: true placeholderapi.updatenotify: true
placeholderapi.list: placeholderapi.list:
description: ability to use the list command description: ability to use the list command
default: op default: op
placeholderapi.reload: placeholderapi.reload:
description: ability to use the reload command description: ability to use the reload command
default: op default: op
placeholderapi.parse: placeholderapi.parse:
description: ability to use parse command description: ability to use parse command
default: op default: op
placeholderapi.register: placeholderapi.register:
description: ability to register or unregister placeholder expansions description: ability to register or unregister placeholder expansions
default: op default: op
placeholderapi.ecloud: placeholderapi.ecloud:
description: allows the usage of ecloud commands description: allows the usage of ecloud commands
default: op default: op
children: placeholderapi.updatenotify:
placeholderapi.ecloud.enable: true description: notifies you when there is a PAPI update
placeholderapi.ecloud.disable: true default: op
placeholderapi.ecloud.list: true commands:
placeholderapi.ecloud.info: true placeholderapi:
placeholderapi.ecloud.clear: true description: PlaceholderAPI command
placeholderapi.ecloud.status: true aliases: [papi]
placeholderapi.ecloud.refresh: true
placeholderapi.ecloud.download: true
placeholderapi.ecloud.versioninfo: true
placeholderapi.updatenotify:
description: notifies you when there is a PAPI update
default: op