Changed command system (#304)

* Save Cacheable expansions data on shutdown

* Prepare for 1.16

* 1.16.1 is out apparently

* Further fixes, still not done

* Inline JSONMessages & fix for 1.16

* Done :O

* Done for real now, (hopefully)

* Changed to static instead of DI for plugin instance

* Cleanup

* Modified tab completions. Removed extra command.

* Apparently this is needed

* Started cleaning stuff up

basically just pushing so I can continue on laptop

* did more cleaning, probs like half way done

* more cleaning. reverted back to a min arg system somewhat similar to what frosty had, but less boilerplate.

* Started debugging and fixing runtime/compile errors

* Fixed bugs, still needs thorough testing

* Re-enable metrics

* relocated stuff again

* - Remove json message relocation
- uncomment other relocations
- reformat pom
- remove useless scope declaration
- Fix metrics constructor
- Switch commands to use inline json message

Co-authored-by: iGabyTM <contactgabytm@gmail.com>
Co-authored-by: darbyjack <admin@glaremasters.me>
Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>
This commit is contained in:
Frcsty 2020-07-13 21:27:59 +02:00 committed by GitHub
parent 82fa8d7393
commit 3e396a97b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 4253 additions and 2750 deletions

3
.gitignore vendored

@ -146,3 +146,6 @@ dist/
nbdist/
.nb-gradle/
nbactions.xml
### Piggy's Debugging Shit ###
server/

19
pom.xml

@ -24,17 +24,13 @@
<id>CodeMC</id>
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
<repository>
<id>rayzr-repo</id>
<url>https://cdn.rawgit.com/Rayzr522/maven-repo/master/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<version>1.16.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -46,13 +42,12 @@
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.rayzr522</groupId>
<artifactId>jsonmessage</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>19.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
@ -95,10 +90,6 @@
<pattern>org.bstats</pattern>
<shadedPattern>me.clip.placeholderapi.metrics</shadedPattern>
</relocation>
<relocation>
<pattern>me.rayzr522</pattern>
<shadedPattern>me.clip.placeholderapi.util</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.code.gson</pattern>
<shadedPattern>me.clip.placeholderapi.libs.gson</shadedPattern>

@ -24,8 +24,10 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import me.clip.placeholderapi.events.ExpansionRegisterEvent;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.expansion.Cacheable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
@ -56,7 +58,8 @@ public class PlaceholderAPI {
* @return true if identifier is already registered
*/
public static boolean isRegistered(String identifier) {
return getRegisteredIdentifiers().stream().filter(id -> id.equalsIgnoreCase(identifier))
return getRegisteredIdentifiers().stream()
.filter(id -> id.equalsIgnoreCase(identifier))
.findFirst().orElse(null) != null;
}
@ -220,7 +223,8 @@ public class PlaceholderAPI {
return null;
}
return text.stream().map(line -> setPlaceholders(player, line, pattern, colorize))
return text.stream()
.map(line -> setPlaceholders(player, line, pattern, colorize))
.collect(Collectors.toList());
}
@ -308,25 +312,29 @@ public class PlaceholderAPI {
return colorize ? color(text) : text;
}
Matcher m = pattern.matcher(text);
Map<String, PlaceholderHook> hooks = getPlaceholders();
final Matcher matcher = pattern.matcher(text);
final Map<String, PlaceholderHook> hooks = getPlaceholders();
while (m.find()) {
String format = m.group(1);
int index = format.indexOf("_");
while (matcher.find()) {
final String format = matcher.group(1);
final int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) {
continue;
}
String identifier = format.substring(0, index).toLowerCase();
String params = format.substring(index + 1);
final String identifier = format.substring(0, index).toLowerCase();
final String params = format.substring(index + 1);
final PlaceholderHook hook = hooks.get(identifier);
if (hooks.containsKey(identifier)) {
String value = hooks.get(identifier).onRequest(player, params);
if (value != null) {
text = text.replaceAll(Pattern.quote(m.group()), Matcher.quoteReplacement(value));
if (hook == null) {
continue;
}
final String value = hook.onRequest(player, params);
if (value != null) {
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
}
}
@ -361,7 +369,8 @@ public class PlaceholderAPI {
return null;
}
return text.stream().map(line -> setRelationalPlaceholders(one, two, line, colorize))
return text.stream()
.map(line -> setRelationalPlaceholders(one, two, line, colorize))
.collect(Collectors.toList());
}
@ -388,21 +397,22 @@ public class PlaceholderAPI {
* @param colorize If color codes (&[0-1a-fk-o]) should be translated
* @return The text containing the parsed relational placeholders
*/
@SuppressWarnings("DuplicatedCode")
public static String setRelationalPlaceholders(Player one, Player two, String text, boolean colorize) {
if (text == null) {
return null;
}
if (placeholders.isEmpty()) {
return colorize ? color(text) : text;
return colorize ? Msg.color(text) : text;
}
Matcher m = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
Map<String, PlaceholderHook> hooks = getPlaceholders();
final Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
final Map<String, PlaceholderHook> hooks = getPlaceholders();
while (m.find()) {
String format = m.group(2);
int index = format.indexOf("_");
while (matcher.find()) {
final String format = matcher.group(2);
final int index = format.indexOf("_");
if (index <= 0 || index >= format.length()) {
continue;
@ -410,22 +420,20 @@ public class PlaceholderAPI {
String identifier = format.substring(0, index).toLowerCase();
String params = format.substring(index + 1);
final PlaceholderHook hook = hooks.get(identifier);
if (hooks.containsKey(identifier)) {
if (!(hooks.get(identifier) instanceof Relational)) {
if (!(hook instanceof Relational)) {
continue;
}
Relational rel = (Relational) hooks.get(identifier);
String value = rel.onPlaceholderRequest(one, two, params);
final String value = ((Relational) hook).onPlaceholderRequest(one, two, params);
if (value != null) {
text = text.replaceAll(Pattern.quote(m.group()), Matcher.quoteReplacement(value));
}
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
}
}
return colorize ? color(text) : text;
return colorize ? Msg.color(text) : text;
}
/**
@ -440,19 +448,21 @@ public class PlaceholderAPI {
* Unregister all expansions provided by PlaceholderAPI
*/
public static void unregisterAllProvidedExpansions() {
if (placeholders.isEmpty()) {
return;
final Set<PlaceholderHook> set = new HashSet<>(placeholders.values());
for (PlaceholderHook hook : set) {
if (hook instanceof PlaceholderExpansion) {
final PlaceholderExpansion expansion = (PlaceholderExpansion) hook;
if (!expansion.persist()) {
unregisterExpansion(expansion);
}
}
getPlaceholders().forEach((key, value) -> {
if (value instanceof PlaceholderExpansion) {
PlaceholderExpansion ex = (PlaceholderExpansion) value;
if (!ex.persist()) {
unregisterExpansion(ex);
if (hook instanceof Cacheable) {
((Cacheable) hook).clear();
}
}
});
}
public static boolean registerExpansion(PlaceholderExpansion ex) {

@ -20,13 +20,15 @@
*/
package me.clip.placeholderapi;
import me.clip.placeholderapi.commands.PlaceholderAPICommands;
import me.clip.placeholderapi.commands.CommandHandler;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import me.clip.placeholderapi.expansion.ExpansionManager;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Version;
import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
import me.clip.placeholderapi.external.EZPlaceholderHook;
import me.clip.placeholderapi.listeners.PlaceholderListener;
import me.clip.placeholderapi.listeners.ServerLoadEventListener;
import me.clip.placeholderapi.updatechecker.UpdateChecker;
import me.clip.placeholderapi.util.TimeUtil;
import org.bstats.bukkit.Metrics;
@ -38,6 +40,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@ -136,7 +139,7 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
config.loadDefConfig();
setupOptions();
getCommand("placeholderapi").setExecutor(new PlaceholderAPICommands(this));
Objects.requireNonNull(getCommand("placeholderapi")).setExecutor(new CommandHandler());
new PlaceholderListener(this);
try {
@ -241,30 +244,26 @@ public class PlaceholderAPIPlugin extends JavaPlugin {
private void setupMetrics() {
Metrics m = new Metrics(this);
m.addCustomChart(new Metrics.SimplePie("using_expansion_cloud",
() -> getExpansionCloud() != null ? "yes" : "no"));
m.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", () -> getExpansionCloud() != null ? "yes" : "no"));
m.addCustomChart(
new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
m.addCustomChart(new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
m.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> {
Map<String, Integer> map = new HashMap<>();
Map<String, PlaceholderHook> p = PlaceholderAPI.getPlaceholders();
Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
if (!p.isEmpty()) {
if (!hooks.isEmpty()) {
for (PlaceholderHook hook : p.values()) {
for (PlaceholderHook hook : hooks.values()) {
if (hook instanceof PlaceholderExpansion) {
PlaceholderExpansion ex = (PlaceholderExpansion) hook;
map.put(ex.getRequiredPlugin() == null ? ex.getIdentifier()
: ex.getRequiredPlugin(), 1);
PlaceholderExpansion expansion = (PlaceholderExpansion) hook;
map.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() : expansion.getRequiredPlugin(), 1);
}
}
}
return map;
}));
}
public void enableCloud() {

@ -28,14 +28,14 @@ public abstract class PlaceholderHook {
/**
* called when a placeholder value is requested from this hook
*
* @param p {@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
* @param params String passed to the hook to determine what value to return
* @return value for the requested player and params
*/
public String onRequest(OfflinePlayer p, String params) {
if (p != null && p.isOnline()) {
return onPlaceholderRequest((Player) p, params);
public String onRequest(OfflinePlayer player, String params) {
if (player != null && player.isOnline()) {
return onPlaceholderRequest((Player) player, params);
}
return onPlaceholderRequest(null, params);
@ -44,11 +44,11 @@ public abstract class PlaceholderHook {
/**
* called when a placeholder is requested from this hook
*
* @param p {@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
* @return value for the requested player and params
*/
public String onPlaceholderRequest(Player p, String params) {
public String onPlaceholderRequest(Player player, String params) {
return null;
}
}

@ -1,124 +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 me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.expansion.Cacheable;
import me.clip.placeholderapi.expansion.Cleanable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Taskable;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class PlaceholderListener implements Listener {
private final PlaceholderAPIPlugin plugin;
public PlaceholderListener(PlaceholderAPIPlugin instance) {
plugin = instance;
Bukkit.getPluginManager().registerEvents(this, instance);
}
@EventHandler
public void onExpansionUnregister(ExpansionUnregisterEvent event) {
if (event.getExpansion() instanceof Listener) {
HandlerList.unregisterAll((Listener) event.getExpansion());
}
if (event.getExpansion() instanceof Taskable) {
((Taskable) event.getExpansion()).stop();
}
if (event.getExpansion() instanceof Cacheable) {
((Cacheable) event.getExpansion()).clear();
}
if (plugin.getExpansionCloud() != null) {
CloudExpansion ex = plugin.getExpansionCloud()
.getCloudExpansion(event.getExpansion().getName());
if (ex != null) {
ex.setHasExpansion(false);
ex.setShouldUpdate(false);
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPluginUnload(PluginDisableEvent e) {
String n = e.getPlugin().getName();
if (n == null) {
return;
}
if (n.equals(plugin.getName())) {
return;
}
Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
for (Entry<String, PlaceholderHook> hook : hooks.entrySet()) {
PlaceholderHook i = hook.getValue();
if (i instanceof PlaceholderExpansion) {
PlaceholderExpansion ex = (PlaceholderExpansion) i;
if (ex.getRequiredPlugin() == null) {
continue;
}
if (ex.getRequiredPlugin().equalsIgnoreCase(n)) {
if (PlaceholderAPI.unregisterExpansion(ex)) {
plugin.getLogger().info("Unregistered placeholder expansion: " + ex.getIdentifier());
}
}
}
}
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
Set<PlaceholderExpansion> expansions = PlaceholderAPI.getExpansions();
if (expansions.isEmpty()) {
return;
}
for (PlaceholderExpansion ex : expansions) {
if (ex instanceof Cleanable) {
((Cleanable) ex).cleanup(e.getPlayer());
}
}
}
}

@ -0,0 +1,82 @@
package me.clip.placeholderapi.commands;
import com.google.common.collect.ImmutableSet;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public abstract class Command {
private static final Options EMPTY_OPTIONS = new Options(null, 0, null);
private final String match;
private final String usage;
private final int minimumArguments;
private final Set<String> permissions;
protected Command(@NotNull final String match) {
this(match, EMPTY_OPTIONS);
}
protected Command(@NotNull final String match, @NotNull final Options options) {
this.match = match;
this.usage = options.usage == null ? "/papi " + match + " <required args> [optional args]" : options.usage;
this.permissions = options.permissions == null ? Collections.emptySet() : ImmutableSet.copyOf(options.permissions);
this.minimumArguments = options.minimumArguments;
}
protected static Options usage(@NotNull final String usage, final int 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() {
return match;
}
@NotNull
public String getUsage() {
return usage;
}
public int getMinimumArguments() {
return minimumArguments;
}
@NotNull
public Set<String> getPermissions() {
return permissions;
}
public abstract void execute(@NotNull final CommandSender sender, @NotNull final String[] args);
@NotNull
public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
return Collections.emptyList();
}
private static class Options {
private final String usage;
private final int minimumArguments;
private final String[] permissions;
private Options(@Nullable final String usage, final int minimumArguments,
@Nullable final String[] permissions) {
this.usage = usage;
this.minimumArguments = minimumArguments;
this.permissions = permissions;
}
}
}

@ -0,0 +1,104 @@
package me.clip.placeholderapi.commands;
import com.google.common.collect.Lists;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.command.*;
import me.clip.placeholderapi.commands.command.ecloud.InfoCommand;
import me.clip.placeholderapi.commands.command.ecloud.ListCommand;
import me.clip.placeholderapi.commands.command.ecloud.*;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
public final class CommandHandler implements CommandExecutor {
private static final Command DEFAULT = new VersionCommand();
private static final List<Command> COMMANDS = Lists.newArrayList(
new ClearCommand(),
new DownloadCommand(),
new InfoCommand(),
new ListCommand(),
new PlaceholdersCommand(),
new RefreshCommand(),
new StatusCommand(),
new VersionInfoCommand(),
new EcloudCommand(),
new BcParseCommand(),
new ParseCommand(),
new ParseRelCommand(),
new DisableEcloudCommand(),
new EnableCloudCommand(),
new HelpCommand(),
new me.clip.placeholderapi.commands.command.InfoCommand(),
new me.clip.placeholderapi.commands.command.ListCommand(),
new RegisterCommand(),
new ReloadCommand(),
DEFAULT,
new UnregisterCommand()
);
static {
COMMANDS.sort((command1, command2) -> {
final int comparison = Integer.compare(command1.getMatch().length(), command2.getMatch().length());
if (comparison == 1) return -1;
if (comparison == -1) return 1;
return 0;
});
}
private static final Pattern SPACE_PATTERN = Pattern.compile(" ");
static {
Objects.requireNonNull(PlaceholderAPIPlugin.getInstance().getCommand("placeholderapi"))
.setTabCompleter(new CompletionHandler(COMMANDS));
}
@Override
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) {
DEFAULT.execute(sender, args);
return true;
}
final String joined = String.join(" ", args).toLowerCase();
final Optional<Command> optional = COMMANDS.stream()
.filter(command -> joined.startsWith(command.getMatch()))
.findFirst();
if (!optional.isPresent()) {
sender.sendMessage("Specified command is not valid.");
return true;
}
final Command command = optional.get();
if (!command.getPermissions().isEmpty() && command.getPermissions().stream().noneMatch(sender::hasPermission)) {
sender.sendMessage("You do not have the permission to execute specified command.");
return true;
}
args = splitArguments(joined, command.getMatch());
if (args.length < command.getMinimumArguments()) {
Msg.msg(sender, command.getUsage());
return true;
}
command.execute(sender, args);
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;
}
}

@ -0,0 +1,32 @@
package me.clip.placeholderapi.commands;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public final class CompletionHandler implements TabCompleter {
private final List<Command> commands;
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
@NotNull
@Override
public List<String> onTabComplete(@NotNull final CommandSender sender, @NotNull final org.bukkit.command.Command bukkitCommand,
@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();
return optional
.map(command -> command.handleCompletion(sender, CommandHandler.splitArguments(joined, command.getMatch())))
.orElse(Collections.emptyList());
}
}

@ -1,469 +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.commands;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.rayzr522.jsonmessage.JSONMessage;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static me.clip.placeholderapi.util.Msg.color;
import static me.clip.placeholderapi.util.Msg.msg;
public class ExpansionCloudCommands implements CommandExecutor {
private final PlaceholderAPIPlugin plugin;
public ExpansionCloudCommands(PlaceholderAPIPlugin instance) {
plugin = instance;
}
@Override
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
if (args.length == 1) {
msg(s, "&bExpansion cloud commands",
" ",
"&b/papi ecloud status",
"&fView status of the ecloud",
"&b/papi ecloud list <all/author> (page)",
"&fList all/author specific available expansions",
"&b/papi ecloud info <expansion name>",
"&fView information about a specific expansion available on the cloud",
"&b/papi ecloud versioninfo <expansion name> <version>",
"&fView information about a specific version of an expansion",
"&b/papi ecloud placeholders <expansion name>",
"&fView placeholders for an expansion",
"&b/papi ecloud download <expansion name> (version)",
"&fDownload an expansion from the ecloud",
"&b/papi ecloud refresh",
"&fFetch the most up to date list of expansions available.",
"&b/papi ecloud clear",
"&fClear the expansion cloud cache.");
return true;
}
if (args[1].equalsIgnoreCase("refresh") || args[1].equalsIgnoreCase("update") || args[1]
.equalsIgnoreCase("fetch")) {
msg(s, "&aRefresh task started. Use &f/papi ecloud list all &ain a few!!");
plugin.getExpansionCloud().clean();
plugin.getExpansionCloud().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions());
return true;
}
if (plugin.getExpansionCloud().getCloudExpansions().isEmpty()) {
msg(s, "&7No cloud expansions are available at this time.");
return true;
}
if (args[1].equalsIgnoreCase("clear")) {
msg(s, "&aThe cache has been cleared!!");
plugin.getExpansionCloud().clean();
return true;
}
if (args[1].equalsIgnoreCase("status")) {
msg(s, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size()
+ " &bexpansions available on the cloud.",
"&7A total of &f" + plugin.getExpansionCloud().getCloudAuthorCount()
+ " &7authors have contributed to the expansion cloud.");
if (plugin.getExpansionCloud().getToUpdateCount() > 0) {
msg(s, "&eYou have &f" + plugin.getExpansionCloud().getToUpdateCount()
+ " &eexpansions installed that have updates available.");
}
return true;
}
if (args[1].equalsIgnoreCase("info")) {
if (args.length < 3) {
msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
msg(s, "&cNo expansion found by the name: &f" + args[2]);
return true;
}
if (!(s instanceof Player)) {
msg(s,
(expansion.shouldUpdate() ? "&e" : "") + expansion.getName() + " &8&m-- &r" + expansion
.getVersion().getUrl());
return true;
}
Player p = (Player) s;
msg(s, "&bExpansion&7: &f" + expansion.getName(),
"&bAuthor: &f" + expansion.getAuthor(),
"&bVerified: &f" + expansion.isVerified()
);
// latest version
JSONMessage latestVersion = JSONMessage
.create(color("&bLatest version: &f" + expansion.getLatestVersion()));
latestVersion.tooltip(color("&bReleased: &f" + expansion.getTimeSinceLastUpdate()
+ "\n&bUpdate information: &f" + expansion.getVersion().getReleaseNotes()
));
latestVersion.send(p);
// versions
JSONMessage versions = JSONMessage
.create(color("&bVersions available: &f" + expansion.getVersions().size()));
versions.tooltip(color(String.join("&b, &f", expansion.getAvailableVersions())));
versions.suggestCommand(
"/papi ecloud versioninfo " + expansion.getName() + " " + expansion.getLatestVersion());
versions.send(p);
// placeholders
if (expansion.getPlaceholders() != null) {
JSONMessage placeholders = JSONMessage
.create(color("&bPlaceholders: &f" + expansion.getPlaceholders().size()));
placeholders.tooltip(color(String.join("&b, &f", expansion.getPlaceholders())));
placeholders.suggestCommand("/papi ecloud placeholders " + expansion.getName());
placeholders.send(p);
}
return true;
}
if (args[1].equalsIgnoreCase("versioninfo")) {
if (args.length < 4) {
msg(s, "&cAn expansion name and version must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
msg(s, "&cNo expansion found by the name: &f" + args[2]);
return true;
}
CloudExpansion.Version version = expansion.getVersion(args[3]);
if (version == null) {
msg(s, "&cThe version specified does not exist for expansion: &f" + expansion.getName());
return true;
}
msg(s, "&bExpansion: " + (expansion.shouldUpdate() ? "&e" : "&f") + expansion.getName(),
"&bVersion: &f" + version.getVersion(),
"&bVersion info: &f" + version.getReleaseNotes());
if (!(s instanceof Player)) {
msg(s, "&bDownload url: " + version.getUrl());
return true;
}
Player p = (Player) s;
JSONMessage download = JSONMessage.create(color("&7Click to download this version"));
download.suggestCommand(
"/papi ecloud download " + expansion.getName() + " " + version.getVersion());
download.send(p);
return true;
}
if (args[1].equalsIgnoreCase("placeholders")) {
if (args.length < 3) {
msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
msg(s, "&cNo expansion found by the name: &f" + args[2]);
return true;
}
List<String> placeholders = expansion.getPlaceholders();
if (placeholders == null) {
msg(s, "&cThe expansion: &f" + expansion.getName()
+ " &cdoes not have any placeholders listed.",
"&7You should contact &f" + expansion.getAuthor() + " &7and ask for them to be added.");
return true;
}
if (!(s instanceof Player)
|| plugin.getExpansionManager().getRegisteredExpansion(expansion.getName()) == null) {
msg(s, "&bPlaceholders: &f" + placeholders.size(),
String.join("&a, &f", placeholders));
return true;
}
Player p = (Player) s;
JSONMessage message = JSONMessage.create(color("&bPlaceholders: &f" + placeholders.size()));
message.then("\n");
for (int i = 0; i < placeholders.size(); i++) {
if (i == placeholders.size() - 1) {
message.then(placeholders.get(i));
} else {
message.then(color(placeholders.get(i) + "&b, &f"));
}
try {
message.tooltip(PlaceholderAPI.setPlaceholders(p, placeholders.get(i)));
} catch (Exception e) {
}
}
message.send(p);
return true;
}
if (args[1].equalsIgnoreCase("list")) {
int page = 1;
String author;
boolean installed = false;
if (args.length < 3) {
msg(s, "&cIncorrect usage! &7/papi ecloud list <all/author/installed> (page)");
return true;
}
author = args[2];
if (author.equalsIgnoreCase("all")) {
author = null;
} else if (author.equalsIgnoreCase("installed")) {
author = null;
installed = true;
}
if (args.length >= 4) {
try {
page = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
msg(s, "&cPage number must be an integer!");
return true;
}
}
if (page < 1) {
msg(s, "&cPage must be greater than or equal to 1!");
return true;
}
int avail;
Map<Integer, CloudExpansion> ex;
if (installed) {
ex = plugin.getExpansionCloud().getAllInstalled();
} else if (author == null) {
ex = plugin.getExpansionCloud().getCloudExpansions();
} else {
ex = plugin.getExpansionCloud().getAllByAuthor(author);
}
if (ex == null || ex.isEmpty()) {
msg(s, "&cNo expansions available" + (author != null ? " for author &f" + author : ""));
return true;
}
avail = plugin.getExpansionCloud().getPagesAvailable(ex, 10);
if (page > avail) {
msg(s, "&cThere " + ((avail == 1) ? " is only &f" + avail + " &cpage available!"
: "are only &f" + avail + " &cpages available!"));
return true;
}
msg(s, "&bShowing expansions for&7: &f" + (author != null ? author
: (installed ? "all installed" : "all available")) + " &8&m--&r &bamount&7: &f" + ex
.size() + " &bpage&7: &f" + page + "&7/&f" + avail);
ex = plugin.getExpansionCloud().getPage(ex, page, 10);
if (ex == null) {
msg(s, "&cThere was a problem getting the requested page...");
return true;
}
msg(s, "&aGreen = Expansions you have");
msg(s, "&6Gold = Expansions which need updated");
if (!(s instanceof Player)) {
Map<String, CloudExpansion> expansions = new HashMap<>();
for (CloudExpansion exp : ex.values()) {
if (exp == null || exp.getName() == null) {
continue;
}
expansions.put(exp.getName(), exp);
}
List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList());
int i = (int) ex.keySet().toArray()[0];
for (String name : ce) {
if (expansions.get(name) == null) {
continue;
}
CloudExpansion expansion = expansions.get(name);
msg(s,
"&b" + i + "&7: " + (expansion.shouldUpdate() ? "&6"
: (expansion.hasExpansion() ? "&a" : "&7")) + expansion
.getName() + " &8&m-- &r" + expansion.getVersion().getUrl());
i++;
}
return true;
}
Player p = (Player) s;
Map<String, CloudExpansion> expansions = new HashMap<>();
for (CloudExpansion exp : ex.values()) {
if (exp == null || exp.getName() == null) {
continue;
}
expansions.put(exp.getName(), exp);
}
List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList());
int i = page > 1 ? page * 10 : 0;
for (String name : ce) {
if (expansions.get(name) == null) {
continue;
}
CloudExpansion expansion = expansions.get(name);
StringBuilder sb = new StringBuilder();
if (expansion.shouldUpdate()) {
sb.append("&6Click to update to the latest version of this expansion\n\n");
} else if (!expansion.hasExpansion()) {
sb.append("&bClick to download this expansion\n\n");
} else {
sb.append("&aYou have the latest version of this expansion\n\n");
}
sb.append("&bAuthor&7: &f").append(expansion.getAuthor()).append("\n");
sb.append("&bVerified&7: &f").append(expansion.isVerified()).append("\n");
sb.append("&bLatest version&7: &f").append(expansion.getVersion().getVersion()).append("\n");
sb.append("&bLast updated&7: &f").append(expansion.getTimeSinceLastUpdate()).append(" ago\n");
sb.append("\n").append(expansion.getDescription());
String msg = color(
"&b" + (i + 1) + "&7: " + (expansion.shouldUpdate() ? "&6"
: (expansion.hasExpansion() ? "&a" : "")) + expansion.getName());
String hover = color(sb.toString());
JSONMessage line = JSONMessage.create(msg);
line.tooltip(hover);
if (expansion.shouldUpdate() || !expansion.hasExpansion()) {
line.suggestCommand("/papi ecloud download " + expansion.getName());
} else {
line.suggestCommand("/papi ecloud info " + expansion.getName());
}
line.send(p);
i++;
}
return true;
}
if (args[1].equalsIgnoreCase("download")) {
if (args.length < 3) {
msg(s, "&cAn expansion name must be specified!");
return true;
}
CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(args[2]);
if (expansion == null) {
msg(s, "&cNo expansion found with the name: &f" + args[2]);
return true;
}
PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(args[2]);
if (loaded != null && loaded.isRegistered()) {
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
}
String version = expansion.getLatestVersion();
if (args.length == 4) {
version = args[3];
if (expansion.getVersion(version) == null) {
msg(s, "&cThe version you specified does not exist for &f" + expansion.getName());
msg(s, "&7Available versions: &f" + expansion.getVersions().size());
msg(s, String.join("&a, &f", expansion.getAvailableVersions()));
return true;
}
}
msg(s, "&aDownload starting for expansion: &f" + expansion.getName() + " &aversion: &f" + version);
String player = ((s instanceof Player) ? s.getName() : null);
plugin.getExpansionCloud().downloadExpansion(player, expansion, version);
plugin.getExpansionCloud().clean();
plugin.getExpansionCloud().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions());
return true;
}
msg(s, "&cIncorrect usage! &b/papi ecloud");
return true;
}
}

@ -1,330 +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.commands;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Set;
import java.util.stream.Collectors;
public class PlaceholderAPICommands implements CommandExecutor {
private final PlaceholderAPIPlugin plugin;
private final CommandExecutor eCloud;
public PlaceholderAPICommands(PlaceholderAPIPlugin i) {
plugin = i;
eCloud = new ExpansionCloudCommands(i);
}
@Override
public boolean onCommand(CommandSender s, Command c, String label, String[] args) {
if (args.length == 0) {
Msg.msg(s, "PlaceholderAPI &7version &b&o" + plugin.getDescription().getVersion(),
"&fCreated by&7: &b" + plugin.getDescription().getAuthors(),
"&fPapi commands: &b/papi help",
"&fEcloud commands: &b/papi ecloud");
return true;
} else {
if (args[0].equalsIgnoreCase("help")) {
Msg.msg(s, "PlaceholderAPI &aHelp &e(&f" + plugin.getDescription().getVersion() + "&e)",
"&b/papi",
"&fView plugin info/version info",
"&b/papi list",
"&fList all placeholder expansions that are currently active",
"&b/papi info <placeholder name>",
"&fView information for a specific expansion",
"&b/papi parse <(playername)/me> <...args>",
"&fParse a String with placeholders",
"&b/papi bcparse <(playername)/me> <...args>",
"&fParse a String with placeholders and broadcast the message",
"&b/papi parserel <player one> <player two> <...args>",
"&fParse a String with relational placeholders",
"&b/papi register <fileName>",
"&fRegister an expansion by the name of the file",
"&b/papi unregister <Expansion name>",
"&fUnregister an expansion by name",
"&b/papi reload",
"&fReload the config settings");
if (s.hasPermission("placeholderapi.ecloud")) {
Msg.msg(s, "&b/papi disablecloud",
"&fDisable the expansion cloud",
"&b/papi ecloud",
"&fView ecloud command usage");
Msg.msg(s, "&b/papi enablecloud",
"&fEnable the expansion cloud");
}
return true;
} else if (args[0].equalsIgnoreCase("ecloud")) {
if (!s.hasPermission("placeholderapi.ecloud")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
if (plugin.getExpansionCloud() == null) {
Msg.msg(s, "&7The expansion cloud is not enabled!");
return true;
}
return eCloud.onCommand(s, c, label, args);
} else if (args[0].equalsIgnoreCase("enablecloud")) {
if (!s.hasPermission("placeholderapi.ecloud")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
if (plugin.getExpansionCloud() != null) {
Msg.msg(s, "&7The cloud is already enabled!");
return true;
}
plugin.enableCloud();
plugin.getPlaceholderAPIConfig().setCloudEnabled(true);
Msg.msg(s, "&aThe cloud has been enabled!");
return true;
} else if (args[0].equalsIgnoreCase("disablecloud")) {
if (!s.hasPermission("placeholderapi.ecloud")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
if (plugin.getExpansionCloud() == null) {
Msg.msg(s, "&7The cloud is already disabled!");
return true;
}
plugin.disableCloud();
plugin.getPlaceholderAPIConfig().setCloudEnabled(false);
Msg.msg(s, "&aThe cloud has been disabled!");
return true;
} else if (args.length > 1 && args[0].equalsIgnoreCase("info")) {
if (!s.hasPermission("placeholderapi.info")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(args[1]);
if (ex == null) {
Msg.msg(s, "&cThere is no expansion loaded with the identifier: &f" + args[1]);
return true;
}
Msg.msg(s, "&7Placeholder expansion info for: &f" + ex.getName());
Msg.msg(s, "&7Status: " + (ex.isRegistered() ? "&aRegistered" : "&cNot registered"));
if (ex.getAuthor() != null) {
Msg.msg(s, "&7Created by: &f" + ex.getAuthor());
}
if (ex.getVersion() != null) {
Msg.msg(s, "&7Version: &f" + ex.getVersion());
}
if (ex.getRequiredPlugin() != null) {
Msg.msg(s, "&7Requires plugin: &f" + ex.getRequiredPlugin());
}
if (ex.getPlaceholders() != null) {
Msg.msg(s, "&8&m-- &r&7Placeholders &8&m--");
for (String placeholder : ex.getPlaceholders()) {
Msg.msg(s, placeholder);
}
}
return true;
} else if (args.length > 2 && args[0].equalsIgnoreCase("parse")
|| args.length > 2 && args[0].equalsIgnoreCase("bcparse")) {
if (!s.hasPermission("placeholderapi.parse")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
OfflinePlayer pl;
if (args[1].equalsIgnoreCase("me")) {
if (s instanceof Player) {
pl = (Player) s;
} else {
Msg.msg(s, "&cThis command must target a player when used by console");
return true;
}
} else {
if (Bukkit.getPlayer(args[1]) != null) {
pl = Bukkit.getPlayer(args[1]);
} else {
pl = Bukkit.getOfflinePlayer(args[1]);
}
}
if (pl == null || (!pl.hasPlayedBefore() && !pl.isOnline())) {
Msg.msg(s, "&cFailed to find player: &f" + args[1]);
return true;
}
String parse = StringUtils.join(args, " ", 2, args.length);
if (args[0].equalsIgnoreCase("bcparse")) {
Msg.broadcast("&r" + PlaceholderAPI.setPlaceholders(pl, parse));
} else {
Msg.msg(s, "&r" + PlaceholderAPI.setPlaceholders(pl, parse));
}
return true;
} else if (args.length > 3 && args[0].equalsIgnoreCase("parserel")) {
if (!(s instanceof Player)) {
Msg.msg(s, "&cThis command can only be used in game!");
return true;
} else {
if (!s.hasPermission("placeholderapi.parse")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Player one = Bukkit.getPlayer(args[1]);
if (one == null) {
Msg.msg(s, args[1] + " &cis not online!");
return true;
}
Player two = Bukkit.getPlayer(args[2]);
if (two == null) {
Msg.msg(s, args[2] + " &cis not online!");
return true;
}
String parse = StringUtils.join(args, " ", 3, args.length);
Msg.msg(s, "&r" + PlaceholderAPI.setRelationalPlaceholders(one, two, parse));
return true;
} else if (args[0].equalsIgnoreCase("reload")) {
if (s instanceof Player) {
if (!s.hasPermission("placeholderapi.reload")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Msg.msg(s, "&fPlaceholder&7API &bconfiguration reloaded!");
plugin.reloadConf(s);
} else if (args[0].equalsIgnoreCase("list")) {
if (s instanceof Player) {
if (!s.hasPermission("placeholderapi.list")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
Set<String> registered = PlaceholderAPI.getRegisteredIdentifiers();
if (registered.isEmpty()) {
Msg.msg(s, "&7There are no placeholder hooks currently registered!");
return true;
}
Msg.msg(s, registered.size() + " &7Placeholder hooks registered:");
Msg.msg(s, registered.stream().sorted().collect(Collectors.joining(", ")));
} else if (args.length > 1 && args[0].equalsIgnoreCase("register")) {
if (s instanceof Player) {
if (!s.hasPermission("placeholderapi.register")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
String fileName = args[1].replace(".jar", "");
PlaceholderExpansion ex = plugin.getExpansionManager().registerExpansion(fileName);
if (ex == null) {
Msg.msg(s, "&cFailed to register expansion from " + fileName);
return true;
}
Msg.msg(s, "&aSuccessfully registered expansion: &f" + ex.getName());
} else if (args.length > 1 && args[0].equalsIgnoreCase("unregister")) {
if (s instanceof Player) {
if (!s.hasPermission("placeholderapi.register")) {
Msg.msg(s, "&cYou don't have permission to do that!");
return true;
}
}
PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(args[1]);
if (ex == null) {
Msg.msg(s, "&cFailed to find expansion: &f" + args[1]);
return true;
}
if (PlaceholderAPI.unregisterExpansion(ex)) {
Msg.msg(s, "&aSuccessfully unregistered expansion: &f" + ex.getName());
} else {
Msg.msg(s, "&cFailed to unregister expansion: &f" + ex.getName());
}
} else {
Msg.msg(s, "&cIncorrect usage! &7/papi help");
}
}
return true;
}
}

@ -0,0 +1,47 @@
package me.clip.placeholderapi.commands.command;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BcParseCommand extends Command {
public BcParseCommand() {
super("bcparse", options("&cYou must specify a player.", 1, "placeholderapi.parse"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final OfflinePlayer player;
final String input = args[0];
if (input.equalsIgnoreCase("me")) {
if (sender instanceof Player) {
player = (Player) sender;
} else {
Msg.msg(sender, "&cThis command must target a player when used by console");
return;
}
} else {
if (Bukkit.getPlayer(input) != null) {
player = Bukkit.getPlayer(input);
} else {
player = Bukkit.getOfflinePlayer(input);
}
}
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));
}
}

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

@ -0,0 +1,81 @@
package me.clip.placeholderapi.commands.command;
import com.google.common.collect.Sets;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public final class EcloudCommand extends Command {
private static final int MAXIMUM_ARGUMENTS = 1;
private static final Set<String> COMPLETIONS = Sets.newHashSet(
"clear",
"download",
"info",
"list",
"placeholders",
"refresh",
"status",
"versioninfo"
);
public EcloudCommand() {
super("ecloud", permissions("placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
if (args.length == 0) {
Msg.msg(sender, "&bExpansion cloud commands",
" ",
"&b/papi ecloud status",
"&fView status of the ecloud",
"&b/papi ecloud list <all/author> (page)",
"&fList all/author specific available expansions",
"&b/papi ecloud info <expansion name>",
"&fView information about a specific expansion available on the cloud",
"&b/papi ecloud versioninfo <expansion name> <version>",
"&fView information about a specific version of an expansion",
"&b/papi ecloud placeholders <expansion name>",
"&fView placeholders for an expansion",
"&b/papi ecloud download <expansion name> (version)",
"&fDownload an expansion from the ecloud",
"&b/papi ecloud refresh",
"&fFetch the most up to date list of expansions available.",
"&b/papi ecloud clear",
"&fClear the expansion cloud cache.");
return;
}
if (plugin.getExpansionCloud() == null) {
Msg.msg(sender, "&7The expansion cloud is not enabled!");
return;
}
if (plugin.getExpansionCloud().getCloudExpansions().isEmpty()) {
Msg.msg(sender, "&7No cloud expansions are available at this time.");
return;
}
sender.sendMessage("Specified command is not valid.");
}
@NotNull
@Override
public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MAXIMUM_ARGUMENTS) {
return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size()));
}
return super.handleCompletion(sender, args);
}
}

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

@ -0,0 +1,46 @@
package me.clip.placeholderapi.commands.command;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class HelpCommand extends Command {
public HelpCommand() {
super("help", permissions("placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
Msg.msg(sender, "PlaceholderAPI &aHelp &e(&f" + PlaceholderAPIPlugin.getInstance().getDescription().getVersion() + "&e)",
"&b/papi",
"&fView plugin info/version info",
"&b/papi list",
"&fList all placeholder expansions that are currently active",
"&b/papi info <placeholder name>",
"&fView information for a specific expansion",
"&b/papi parse <(playername)/me> <...args>",
"&fParse a String with placeholders",
"&b/papi bcparse <(playername)/me> <...args>",
"&fParse a String with placeholders and broadcast the message",
"&b/papi parserel <player one> <player two> <...args>",
"&fParse a String with relational placeholders",
"&b/papi register <fileName>",
"&fRegister an expansion by the name of the file",
"&b/papi unregister <Expansion name>",
"&fUnregister an expansion by name",
"&b/papi reload",
"&fReload the config settings");
if (sender.hasPermission("placeholderapi.ecloud")) {
Msg.msg(sender, "&b/papi disablecloud",
"&fDisable the expansion cloud",
"&b/papi ecloud",
"&fView ecloud command usage",
"&b/papi enablecloud",
"&fEnable the expansion cloud");
}
}
}

@ -0,0 +1,68 @@
package me.clip.placeholderapi.commands.command;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public final class InfoCommand extends Command {
private static final int MINIMUM_ARGUMENTS = 1;
public InfoCommand() {
super("info", options("&cIncorrect usage! &7/papi info <expansion>", MINIMUM_ARGUMENTS, "placeholderapi.info"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final String requestedExpansion = args[0];
final PlaceholderExpansion ex = PlaceholderAPIPlugin.getInstance().getExpansionManager().getRegisteredExpansion(requestedExpansion);
if (ex == null) {
Msg.msg(sender, "&cThere is no expansion loaded with the identifier: &f" + requestedExpansion);
return;
}
Msg.msg(sender, "&7Placeholder expansion info for: &f" + ex.getName());
Msg.msg(sender, "&7Status: " + (ex.isRegistered() ? "&aRegistered" : "&cNot registered"));
if (ex.getAuthor() != null) {
Msg.msg(sender, "&7Created by: &f" + ex.getAuthor());
}
if (ex.getVersion() != null) {
Msg.msg(sender, "&7Version: &f" + ex.getVersion());
}
if (ex.getRequiredPlugin() != null) {
Msg.msg(sender, "&7Requires plugin: &f" + ex.getRequiredPlugin());
}
if (ex.getPlaceholders() != null) {
Msg.msg(sender, "&8&m-- &r&7Placeholders &8&m--");
for (String placeholder : ex.getPlaceholders()) {
Msg.msg(sender, placeholder);
}
}
}
@NotNull
@Override
public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MINIMUM_ARGUMENTS) {
final Set<String> completions = PlaceholderAPI.getRegisteredIdentifiers();
return StringUtil.copyPartialMatches(args[0], completions, new ArrayList<>(completions.size()));
}
return super.handleCompletion(sender, args);
}
}

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

@ -0,0 +1,47 @@
package me.clip.placeholderapi.commands.command;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class ParseCommand extends Command {
public ParseCommand() {
super("parse", options("&cYou must specify a player.", 1, "placeholderapi.parse"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final OfflinePlayer player;
final String input = args[0];
if (input.equalsIgnoreCase("me")) {
if (sender instanceof Player) {
player = (Player) sender;
} else {
Msg.msg(sender, "&cThis command must target a player when used by console");
return;
}
} else {
if (Bukkit.getPlayer(input) != null) {
player = Bukkit.getPlayer(input);
} else {
player = Bukkit.getOfflinePlayer(input);
}
}
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));
}
}

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

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

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

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

@ -0,0 +1,55 @@
package me.clip.placeholderapi.commands.command;
import com.google.common.collect.Sets;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public final class VersionCommand extends Command {
private static final Set<String> COMPLETIONS = Sets.newHashSet(
"unregister",
"reload",
"register",
"parserel",
"parse",
"list",
"info",
"help",
"ecloud",
"enablecloud",
"disablecloud",
"bcparse"
);
public VersionCommand() {
super("version");
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final PluginDescriptionFile description = PlaceholderAPIPlugin.getInstance().getDescription();
Msg.msg(sender, "PlaceholderAPI &7version &b&o" + description.getVersion(),
"&fCreated by&7: &b" + description.getAuthors(),
"&fPapi commands: &b/papi help",
"&fEcloud commands: &b/papi ecloud");
}
@NotNull
@Override
public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == 1) {
return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size()));
}
return super.handleCompletion(sender, args);
}
}

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

@ -0,0 +1,55 @@
package me.clip.placeholderapi.commands.command.ecloud;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class DownloadCommand extends Command {
public DownloadCommand() {
super("ecloud download", options("&cAn expansion name must be specified!", 1, "placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
final String input = args[0];
final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(input);
if (expansion == null) {
Msg.msg(sender, "&cNo expansion found with the name: &f" + input);
return;
}
final PlaceholderExpansion loaded = plugin.getExpansionManager().getRegisteredExpansion(input);
if (loaded != null && loaded.isRegistered()) {
PlaceholderAPI.unregisterPlaceholderHook(loaded.getIdentifier());
}
String version = expansion.getLatestVersion();
if (args.length == 2) {
version = args[1];
if (expansion.getVersion(version) == null) {
Msg.msg(sender, "&cThe version you specified does not exist for &f" + expansion.getName());
Msg.msg(sender, "&7Available versions: &f" + expansion.getVersions().size());
Msg.msg(sender, String.join("&a, &f", expansion.getAvailableVersions()));
return;
}
}
Msg.msg(sender, "&aDownload starting for expansion: &f" + expansion.getName() + " &aversion: &f" + version);
final String player = ((sender instanceof Player) ? sender.getName() : null);
final ExpansionCloudManager cloud = plugin.getExpansionCloud();
cloud.downloadExpansion(player, expansion, version);
cloud.clean();
cloud.fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions());
}
}

@ -0,0 +1,70 @@
package me.clip.placeholderapi.commands.command.ecloud;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.JSONMessage;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static me.clip.placeholderapi.util.Msg.color;
public final class InfoCommand extends Command {
public InfoCommand() {
super("ecloud info", options("&cAn expansion name must be specified!", 1, "placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final String input = args[0];
final CloudExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionCloud().getCloudExpansion(input);
if (expansion == null) {
Msg.msg(sender, "&cNo expansion found by the name: &f" + input);
return;
}
if (!(sender instanceof Player)) {
Msg.msg(sender,
(expansion.shouldUpdate() ? "&e" : "") + expansion.getName() + " &8&m-- &r" + expansion
.getVersion().getUrl());
return;
}
final Player p = (Player) sender;
Msg.msg(sender, "&bExpansion&7: &f" + expansion.getName(),
"&bAuthor: &f" + expansion.getAuthor(),
"&bVerified: &f" + expansion.isVerified()
);
// latest version
final JSONMessage latestVersion = JSONMessage
.create(color("&bLatest version: &f" + expansion.getLatestVersion()));
latestVersion.tooltip(color("&bReleased: &f" + expansion.getTimeSinceLastUpdate()
+ "\n&bUpdate information: &f" + expansion.getVersion().getReleaseNotes()
));
latestVersion.send(p);
// versions
final JSONMessage versions = JSONMessage
.create(color("&bVersions available: &f" + expansion.getVersions().size()));
versions.tooltip(color(String.join("&b, &f", expansion.getAvailableVersions())));
versions.suggestCommand(
"/papi ecloud versioninfo " + expansion.getName() + " " + expansion.getLatestVersion());
versions.send(p);
// placeholders
if (expansion.getPlaceholders() != null) {
final JSONMessage placeholders = JSONMessage
.create(color("&bPlaceholders: &f" + expansion.getPlaceholders().size()));
placeholders.tooltip(color(String.join("&b, &f", expansion.getPlaceholders())));
placeholders.suggestCommand("/papi ecloud placeholders " + expansion.getName());
placeholders.send(p);
}
}
}

@ -0,0 +1,208 @@
package me.clip.placeholderapi.commands.command.ecloud;
import com.google.common.collect.Sets;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.JSONMessage;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
import static me.clip.placeholderapi.util.Msg.color;
public final class ListCommand extends Command {
private static final int MINIMUM_ARGUMENTS = 1;
private static final Set<String> COMPLETIONS = Sets.newHashSet(
"all",
"author",
"installed"
);
public ListCommand() {
super("ecloud list", options("&cIncorrect usage! &7/papi ecloud list <all/author/installed> (page)",
MINIMUM_ARGUMENTS, "placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
int page = 1;
String author;
boolean installed = false;
author = args[0];
if (author.equalsIgnoreCase("all")) {
author = null;
} else if (author.equalsIgnoreCase("installed")) {
author = null;
installed = true;
}
if (args.length >= 2) {
try {
page = Integer.parseInt(args[1]);
} catch (NumberFormatException ex) {
Msg.msg(sender, "&cPage number must be an integer!");
return;
}
}
if (page < 1) {
Msg.msg(sender, "&cPage must be greater than or equal to 1!");
return;
}
int avail;
Map<Integer, CloudExpansion> ex;
if (installed) {
ex = plugin.getExpansionCloud().getAllInstalled();
} else if (author == null) {
ex = plugin.getExpansionCloud().getCloudExpansions();
} else {
ex = plugin.getExpansionCloud().getAllByAuthor(author);
}
if (ex == null || ex.isEmpty()) {
Msg.msg(sender, "&cNo expansions available" + (author != null ? " for author &f" + author : ""));
return;
}
avail = plugin.getExpansionCloud().getPagesAvailable(ex, 10);
if (page > avail) {
Msg.msg(sender, "&cThere " + ((avail == 1) ? " is only &f" + avail + " &cpage available!"
: "are only &f" + avail + " &cpages available!"));
return;
}
Msg.msg(sender, "&bShowing expansions for&7: &f" + (author != null ? author
: (installed ? "all installed" : "all available")) + " &8&m--&r &bamount&7: &f" + ex
.size() + " &bpage&7: &f" + page + "&7/&f" + avail);
ex = plugin.getExpansionCloud().getPage(ex, page, 10);
if (ex == null) {
Msg.msg(sender, "&cThere was a problem getting the requested page...");
return;
}
Msg.msg(sender, "&aGreen = Expansions you have");
Msg.msg(sender, "&6Gold = Expansions which need updated");
if (!(sender instanceof Player)) {
final Map<String, CloudExpansion> expansions = new HashMap<>();
for (CloudExpansion exp : ex.values()) {
if (exp == null || exp.getName() == null) {
continue;
}
expansions.put(exp.getName(), exp);
}
final List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList());
int i = (int) ex.keySet().toArray()[0];
for (String name : ce) {
if (expansions.get(name) == null) {
continue;
}
final CloudExpansion expansion = expansions.get(name);
Msg.msg(sender,
"&b" + i + "&7: " + (expansion.shouldUpdate() ? "&6"
: (expansion.hasExpansion() ? "&a" : "&7")) + expansion
.getName() + " &8&m-- &r" + expansion.getVersion().getUrl());
i++;
}
return;
}
final Player p = (Player) sender;
final Map<String, CloudExpansion> expansions = new HashMap<>();
for (final CloudExpansion exp : ex.values()) {
if (exp == null || exp.getName() == null) {
continue;
}
expansions.put(exp.getName(), exp);
}
final List<String> ce = expansions.keySet().stream().sorted().collect(Collectors.toList());
int i = page > 1 ? page * 10 : 0;
for (String name : ce) {
if (expansions.get(name) == null) {
continue;
}
final CloudExpansion expansion = expansions.get(name);
final StringBuilder sb = new StringBuilder();
if (expansion.shouldUpdate()) {
sb.append("&6Click to update to the latest version of this expansion\n\n");
} else if (!expansion.hasExpansion()) {
sb.append("&bClick to download this expansion\n\n");
} else {
sb.append("&aYou have the latest version of this expansion\n\n");
}
sb.append("&bAuthor&7: &f").append(expansion.getAuthor()).append("\n");
sb.append("&bVerified&7: &f").append(expansion.isVerified()).append("\n");
sb.append("&bLatest version&7: &f").append(expansion.getVersion().getVersion()).append("\n");
sb.append("&bLast updated&7: &f").append(expansion.getTimeSinceLastUpdate()).append(" ago\n");
sb.append("\n").append(expansion.getDescription());
final String msg = color(
"&b" + (i + 1) + "&7: " + (expansion.shouldUpdate() ? "&6"
: (expansion.hasExpansion() ? "&a" : "")) + expansion.getName());
final String hover = color(sb.toString());
final JSONMessage line = JSONMessage.create(msg);
line.tooltip(hover);
if (expansion.shouldUpdate() || !expansion.hasExpansion()) {
line.suggestCommand("/papi ecloud download " + expansion.getName());
} else {
line.suggestCommand("/papi ecloud info " + expansion.getName());
}
line.send(p);
i++;
}
}
@NotNull
@Override
public List<String> handleCompletion(@NotNull final CommandSender sender, @NotNull final String[] args) {
if (args.length == MINIMUM_ARGUMENTS) {
return StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(COMPLETIONS.size()));
}
if (args.length == MINIMUM_ARGUMENTS + 1) {
return Collections.singletonList("Pages");
}
return super.handleCompletion(sender, args);
}
}

@ -0,0 +1,63 @@
package me.clip.placeholderapi.commands.command.ecloud;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.JSONMessage;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class PlaceholdersCommand extends Command {
public PlaceholdersCommand() {
super("ecloud placeholders", options("&cAn expansion name must be specified!", 1, "placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
final String input = args[0];
final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(input);
if (expansion == null) {
Msg.msg(sender, "&cNo expansion found by the name: &f" + input);
return;
}
final List<String> placeholders = expansion.getPlaceholders();
if (placeholders == null) {
Msg.msg(sender, "&cThe expansion: &f" + expansion.getName()
+ " &cdoes not have any placeholders listed.",
"&7You should contact &f" + expansion.getAuthor() + " &7and ask for them to be added.");
return;
}
if (!(sender instanceof Player)
|| plugin.getExpansionManager().getRegisteredExpansion(expansion.getName()) == null) {
Msg.msg(sender, "&bPlaceholders: &f" + placeholders.size(),
String.join("&a, &f", placeholders));
return;
}
final Player p = (Player) sender;
final JSONMessage message = JSONMessage.create(Msg.color("&bPlaceholders: &f" + placeholders.size()));
message.then("\n");
for (int i = 0; i < placeholders.size(); i++) {
message.then(i == placeholders.size() - 1 ? placeholders.get(i) : Msg.color(placeholders.get(i) + "&b, &f"));
try {
message.tooltip(PlaceholderAPI.setPlaceholders(p, placeholders.get(i)));
} catch (final Exception ignored) {
// Ignored exception
}
}
message.send(p);
}
}

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

@ -0,0 +1,26 @@
package me.clip.placeholderapi.commands.command.ecloud;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public final class StatusCommand extends Command {
public StatusCommand() {
super("ecloud status", permissions("placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final PlaceholderAPIPlugin plugin = PlaceholderAPIPlugin.getInstance();
Msg.msg(sender, "&bThere are &f" + plugin.getExpansionCloud().getCloudExpansions().size()
+ " &bexpansions available on the cloud.",
"&7A total of &f" + plugin.getExpansionCloud().getCloudAuthorCount()
+ " &7authors have contributed to the expansion cloud.");
if (plugin.getExpansionCloud().getToUpdateCount() > 0) {
Msg.msg(sender, "&eYou have &f" + plugin.getExpansionCloud().getToUpdateCount()
+ " &eexpansions installed that have updates available.");
}
}
}

@ -0,0 +1,48 @@
package me.clip.placeholderapi.commands.command.ecloud;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.Command;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import me.clip.placeholderapi.util.JSONMessage;
import me.clip.placeholderapi.util.Msg;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class VersionInfoCommand extends Command {
public VersionInfoCommand() {
super("ecloud versioninfo", options("&cIncorrect usage! &7/papi ecloud versioninfo <name> <version>",
2, "placeholderapi.ecloud"));
}
@Override
public void execute(@NotNull final CommandSender sender, @NotNull final String[] args) {
final String input = args[0];
final CloudExpansion expansion = PlaceholderAPIPlugin.getInstance().getExpansionCloud().getCloudExpansion(input);
if (expansion == null) {
Msg.msg(sender, "&cNo expansion found by the name: &f" + input);
return;
}
final CloudExpansion.Version version = expansion.getVersion(args[1]);
if (version == null) {
Msg.msg(sender, "&cThe version specified does not exist for expansion: &f" + expansion.getName());
return;
}
Msg.msg(sender, "&bExpansion: " + (expansion.shouldUpdate() ? "&e" : "&f") + expansion.getName(),
"&bVersion: &f" + version.getVersion(),
"&bVersion info: &f" + version.getReleaseNotes());
if (!(sender instanceof Player)) {
Msg.msg(sender, "&bDownload url: " + version.getUrl());
return;
}
final Player p = (Player) sender;
final JSONMessage download = JSONMessage.create(Msg.color("&7Click to download this version"));
download.suggestCommand(
"/papi ecloud download " + expansion.getName() + " " + version.getVersion());
download.send(p);
}
}

@ -47,15 +47,15 @@ public class PlaceholderAPIConfig {
return plugin.getConfig().getBoolean("cloud_enabled");
}
public boolean isDebugMode() {
return plugin.getConfig().getBoolean("debug", false);
}
public void setCloudEnabled(boolean b) {
plugin.getConfig().set("cloud_enabled", b);
plugin.reloadConfig();
}
public boolean isDebugMode() {
return plugin.getConfig().getBoolean("debug", false);
}
public String booleanTrue() {
return plugin.getConfig().getString("boolean.true");
}

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

@ -38,7 +38,8 @@ public enum NMSVersion {
SPIGOT_1_13_R1("v1_13_R1"),
SPIGOT_1_13_R2("v1_13_R2"),
SPIGOT_1_14_R1("v1_14_R1"),
SPIGOT_1_15_R1("v1_15_R1");
SPIGOT_1_15_R1("v1_15_R1"),
SPIGOT_1_16_R1("v1_16_R1");
private final String version;

@ -167,12 +167,12 @@ public class ExpansionCloudManager {
final Map<String, CloudExpansion> data = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(API_URL).openStream()))) {
data.putAll(GSON.fromJson(reader, new TypeToken<Map<String, CloudExpansion>>() {}.getType()));
data.putAll(GSON.fromJson(reader, new TypeToken<Map<String, CloudExpansion>>() {
}.getType()));
} catch (Exception ex) {
if (plugin.getPlaceholderAPIConfig().isDebugMode()) {
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.extendedclip.com/v2/)");
}
}

@ -25,6 +25,9 @@ import me.clip.placeholderapi.PlaceholderHook;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.Plugin;
/**
* Use {@link me.clip.placeholderapi.expansion.PlaceholderExpansion} instead
*/
@Deprecated
public abstract class EZPlaceholderHook extends PlaceholderHook {

@ -0,0 +1,123 @@
/*
*
* 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.listeners;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
import me.clip.placeholderapi.expansion.Cacheable;
import me.clip.placeholderapi.expansion.Cleanable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Taskable;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class PlaceholderListener implements Listener {
private final PlaceholderAPIPlugin plugin;
public PlaceholderListener(PlaceholderAPIPlugin instance) {
plugin = instance;
Bukkit.getPluginManager().registerEvents(this, instance);
}
@EventHandler
public void onExpansionUnregister(ExpansionUnregisterEvent event) {
if (event.getExpansion() instanceof Listener) {
HandlerList.unregisterAll((Listener) event.getExpansion());
}
if (event.getExpansion() instanceof Taskable) {
((Taskable) event.getExpansion()).stop();
}
if (event.getExpansion() instanceof Cacheable) {
((Cacheable) event.getExpansion()).clear();
}
if (plugin.getExpansionCloud() != null) {
CloudExpansion ex = plugin.getExpansionCloud()
.getCloudExpansion(event.getExpansion().getName());
if (ex != null) {
ex.setHasExpansion(false);
ex.setShouldUpdate(false);
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPluginUnload(PluginDisableEvent e) {
String n = e.getPlugin().getName();
if (n.equals(plugin.getName())) {
return;
}
Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders();
for (Entry<String, PlaceholderHook> entry : hooks.entrySet()) {
PlaceholderHook hook = entry.getValue();
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());
}
}
}
}
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
Set<PlaceholderExpansion> expansions = PlaceholderAPI.getExpansions();
if (expansions.isEmpty()) {
return;
}
for (PlaceholderExpansion ex : expansions) {
if (ex instanceof Cleanable) {
((Cleanable) ex).cleanup(e.getPlayer());
}
}
}
}

@ -18,8 +18,11 @@
*
*
*/
package me.clip.placeholderapi;
package me.clip.placeholderapi.listeners;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -38,11 +41,12 @@ public class ServerLoadEventListener implements Listener {
/**
* This method will be called when the server is first loaded
*
* <p>
* The goal of the method is to register all the expansions as soon as possible
* especially before players can join
*
* <p>
* This will ensure no issues with expanions and hooks.
*
* @param e the server load event
*/
@EventHandler

@ -37,8 +37,8 @@ public class UpdateChecker implements Listener {
private final int RESOURCE_ID = 6245;
private final PlaceholderAPIPlugin plugin;
private String spigotVersion;
private final String pluginVersion;
private String spigotVersion;
private boolean updateAvailable;
public UpdateChecker(PlaceholderAPIPlugin i) {

@ -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";
}

@ -0,0 +1,985 @@
package me.clip.placeholderapi.util;
import com.google.common.base.Strings;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.Vector;
/**
* This is a complete JSON message builder class. To create a new JSONMessage do
* {@link #create(String)}
*
* @author Rayzr
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class JSONMessage {
private static final BiMap<ChatColor, String> stylesToNames;
static {
ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder();
for (final ChatColor style : ChatColor.values()) {
if (!style.isFormat()) {
continue;
}
String styleName;
switch (style) {
case MAGIC:
styleName = "obfuscated";
break;
case UNDERLINE:
styleName = "underlined";
break;
default:
styleName = style.name().toLowerCase();
break;
}
builder.put(style, styleName);
}
stylesToNames = builder.build();
}
private final List<MessagePart> parts = new ArrayList<>();
private int centeringStartIndex = -1;
/**
* Creates a new {@link JSONMessage} object
*
* @param text The text to start with
*/
private JSONMessage(String text) {
parts.add(new MessagePart(text));
}
/**
* Creates a new {@link JSONMessage} object
*
* @param text The text to start with
* @return A new {@link JSONMessage} object
*/
public static JSONMessage create(String text) {
return new JSONMessage(text);
}
/**
* Creates a new {@link JSONMessage} object
*
* @return A new {@link JSONMessage} object
*/
public static JSONMessage create() {
return create("");
}
/**
* Sends an action bar message
*
* @param message The message to send
* @param players The players you want to send it to
*/
public static void actionbar(String message, Player... players) {
ReflectionHelper.sendPacket(ReflectionHelper.createActionbarPacket(ChatColor.translateAlternateColorCodes('&', message)), players);
}
/**
* @return The latest {@link MessagePart}
* @throws ArrayIndexOutOfBoundsException If {@code parts.size() <= 0}.
*/
public MessagePart last() {
if (parts.size() <= 0) {
throw new ArrayIndexOutOfBoundsException("No MessageParts exist!");
}
return parts.get(parts.size() - 1);
}
/**
* Converts this {@link JSONMessage} instance to actual JSON
*
* @return The JSON representation of this {@link JSONMessage}
*/
public JsonObject toJSON() {
JsonObject obj = new JsonObject();
obj.addProperty("text", "");
JsonArray array = new JsonArray();
parts.stream()
.map(MessagePart::toJSON)
.forEach(array::add);
obj.add("extra", array);
return obj;
}
/**
* Converts this {@link JSONMessage} object to a String representation of the JSON.
* This is an alias of {@code toJSON().toString()}.
*/
@Override
public String toString() {
return toJSON().toString();
}
/**
* Converts this {@link JSONMessage} object to the legacy formatting system, which
* uses formatting codes (like &amp;6, &amp;l, &amp;4, etc.)
*
* @return This {@link JSONMessage} instance {@link JSONMessage} in legacy format
*/
public String toLegacy() {
StringBuilder output = new StringBuilder();
parts.stream()
.map(MessagePart::toLegacy)
.forEach(output::append);
return output.toString();
}
/**
* Sends this {@link JSONMessage} to all the players specified
*
* @param players The players you want to send this to
*/
public void send(Player... players) {
if (ReflectionHelper.getStringVersion().equalsIgnoreCase("v1_16_R1")) {
ReflectionHelper.sendTextPacket(toString(), players);
return;
}
ReflectionHelper.sendPacket(ReflectionHelper.createTextPacket(toString()), players);
}
/**
* Sends this as a title to all the players specified
*
* @param fadeIn How many ticks to fade in
* @param stay How many ticks to stay
* @param fadeOut How many ticks to fade out
* @param players The players to send this to
*/
public void title(int fadeIn, int stay, int fadeOut, Player... players) {
ReflectionHelper.sendPacket(ReflectionHelper.createTitleTimesPacket(fadeIn, stay, fadeOut), players);
ReflectionHelper.sendPacket(ReflectionHelper.createTitlePacket(toString()), players);
}
/**
* Sends this as a subtitle to all the players specified. Must be used after sending a {@link #title(int, int, int, Player...) title}.
*
* @param players The players to send this to
*/
public void subtitle(Player... players) {
ReflectionHelper.sendPacket(ReflectionHelper.createSubtitlePacket(toString()), players);
}
/**
* Sends an action bar message
*
* @param players The players you want to send this to
*/
public void actionbar(Player... players) {
actionbar(toLegacy(), players);
}
/**
* Sets the color of the current message part.
*
* @param color The color to set
* @return This {@link JSONMessage} instance
*/
public JSONMessage color(ChatColor color) {
last().setColor(color);
return this;
}
/**
* Adds a style to the current message part.
*
* @param style The style to add
* @return This {@link JSONMessage} instance
*/
public JSONMessage style(ChatColor style) {
last().addStyle(style);
return this;
}
/**
* Makes the text run a command.
*
* @param command The command to run
* @return This {@link JSONMessage} instance
*/
public JSONMessage runCommand(String command) {
last().setOnClick(ClickEvent.runCommand(command));
return this;
}
/**
* Makes the text suggest a command.
*
* @param command The command to suggest
* @return This {@link JSONMessage} instance
*/
public JSONMessage suggestCommand(String command) {
last().setOnClick(ClickEvent.suggestCommand(command));
return this;
}
/**
* Opens a URL.
*
* @param url The url to open
* @return This {@link JSONMessage} instance
*/
public JSONMessage openURL(String url) {
last().setOnClick(ClickEvent.openURL(url));
return this;
}
/**
* Changes the page of a book. Using this in a non-book context is useless
* and will probably error.
*
* @param page The page to change to
* @return This {@link JSONMessage} instance
*/
public JSONMessage changePage(int page) {
last().setOnClick(ClickEvent.changePage(page));
return this;
}
/**
* Shows text when you hover over it
*
* @param text The text to show
* @return This {@link JSONMessage} instance
*/
public JSONMessage tooltip(String text) {
last().setOnHover(HoverEvent.showText(text));
return this;
}
/**
* Shows text when you hover over it
*
* @param message The text to show
* @return This {@link JSONMessage} instance
*/
public JSONMessage tooltip(JSONMessage message) {
last().setOnHover(HoverEvent.showText(message));
return this;
}
/**
* Shows an achievement when you hover over it
*
* @param id The id of the achievement
* @return This {@link JSONMessage} instance
*/
public JSONMessage achievement(String id) {
last().setOnHover(HoverEvent.showAchievement(id));
return this;
}
/**
* Adds another part to this {@link JSONMessage}
*
* @param text The text to start the next {@link MessagePart} with
* @return This {@link JSONMessage} instance
*/
public JSONMessage then(String text) {
return then(new MessagePart(text));
}
/**
* Adds another part to this {@link JSONMessage}
*
* @param nextPart The next {@link MessagePart}
* @return This {@link JSONMessage} instance
*/
public JSONMessage then(MessagePart nextPart) {
parts.add(nextPart);
return this;
}
/**
* Adds a horizontal bar to the message of the given length
*
* @param length The length of the horizontal bar
* @return This {@link JSONMessage} instance
*/
public JSONMessage bar(int length) {
return then(Strings.repeat("-", length)).color(ChatColor.DARK_GRAY).style(ChatColor.STRIKETHROUGH);
}
/**
* Adds a horizontal bar to the message that's 53 characters long. This is
* the default width of the player's chat window.
*
* @return This {@link JSONMessage} instance
*/
public JSONMessage bar() {
return bar(53);
}
/**
* Adds a blank line to the message
*
* @return This {@link JSONMessage} instance
*/
public JSONMessage newline() {
return then("\n");
}
/**
* Sets the starting point to begin centering JSONMessages.
*
* @return This {@link JSONMessage} instance
*/
public JSONMessage beginCenter() {
// Start with the NEXT message part.
centeringStartIndex = parts.size();
return this;
}
/**
* Ends the centering of the JSONMessage text.
*
* @return This {@link JSONMessage} instance
*/
public JSONMessage endCenter() {
int current = centeringStartIndex;
while (current < parts.size()) {
Vector<MessagePart> currentLine = new Vector<>();
int totalLineLength = 0;
for (; ; current++) {
MessagePart part = current < parts.size() ? parts.get(current) : null;
String raw = part == null ? null : ChatColor.stripColor(part.toLegacy());
if (current >= parts.size() || totalLineLength + raw.length() >= 53) {
int padding = Math.max(0, (53 - totalLineLength) / 2);
currentLine.firstElement().setText(Strings.repeat(" ", padding) + currentLine.firstElement().getText());
currentLine.lastElement().setText(currentLine.lastElement().getText() + "\n");
currentLine.clear();
break;
}
totalLineLength += raw.length();
currentLine.add(part);
}
}
MessagePart last = parts.get(parts.size() - 1);
last.setText(last.getText().substring(0, last.getText().length() - 1));
centeringStartIndex = -1;
return this;
}
///////////////////////////
// BEGIN UTILITY CLASSES //
///////////////////////////
/**
* Represents the JSON format that all click/hover events in JSON messages must follow.
* <br>
* <br>
* <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a>
*
* @author Rayzr
*/
public static class MessageEvent {
private String action;
private Object value;
public MessageEvent(String action, Object value) {
this.action = action;
this.value = value;
}
/**
* @return A {@link JsonObject} representing the properties of this {@link MessageEvent}
*/
public JsonObject toJSON() {
JsonObject obj = new JsonObject();
obj.addProperty("action", action);
if (value instanceof JsonElement) {
obj.add("value", (JsonElement) value);
} else {
obj.addProperty("value", value.toString());
}
return obj;
}
/**
* @return The action
*/
public String getAction() {
return action;
}
/**
* @param action The action to set
*/
public void setAction(String action) {
this.action = action;
}
/**
* @return The value
*/
public Object getValue() {
return value;
}
/**
* @param value The value to set
*/
public void setValue(Object value) {
this.value = value;
}
}
public static class ClickEvent {
/**
* Runs a command.
*
* @param command The command to run
* @return The {@link MessageEvent}
*/
public static MessageEvent runCommand(String command) {
return new MessageEvent("run_command", command);
}
/**
* Suggests a command by putting inserting it in chat.
*
* @param command The command to suggest
* @return The {@link MessageEvent}
*/
public static MessageEvent suggestCommand(String command) {
return new MessageEvent("suggest_command", command);
}
/**
* Requires web links to be enabled on the client.
*
* @param url The url to open
* @return The {@link MessageEvent}
*/
public static MessageEvent openURL(String url) {
return new MessageEvent("open_url", url);
}
/**
* Only used with written books.
*
* @param page The page to switch to
* @return The {@link MessageEvent}
*/
public static MessageEvent changePage(int page) {
return new MessageEvent("change_page", page);
}
}
public static class HoverEvent {
/**
* Shows text when you hover over it
*
* @param text The text to show
* @return The {@link MessageEvent}
*/
public static MessageEvent showText(String text) {
return new MessageEvent("show_text", text);
}
/**
* Shows text when you hover over it
*
* @param message The {@link JSONMessage} to show
* @return The {@link MessageEvent}
*/
public static MessageEvent showText(JSONMessage message) {
JsonArray arr = new JsonArray();
arr.add(new JsonPrimitive(""));
arr.add(message.toJSON());
return new MessageEvent("show_text", arr);
}
/**
* Shows an achievement when you hover over it
*
* @param id The id of the achievement
* @return The {@link MessageEvent}
*/
public static MessageEvent showAchievement(String id) {
return new MessageEvent("show_achievement", id);
}
}
private static class ReflectionHelper {
private static final String version;
private static Class<?> craftPlayer;
private static Constructor<?> chatComponentText;
private static Class<?> packetPlayOutChat;
private static Class<?> packetPlayOutTitle;
private static Class<?> iChatBaseComponent;
private static Class<?> titleAction;
private static Field connection;
private static MethodHandle GET_HANDLE;
private static MethodHandle SEND_PACKET;
private static MethodHandle STRING_TO_CHAT;
private static Object enumActionTitle;
private static Object enumActionSubtitle;
private static Object enumChatMessage;
private static Object enumActionbarMessage;
private static boolean SETUP;
private static int MAJOR_VER = -1;
static {
String[] split = Bukkit.getServer().getClass().getPackage().getName().split("\\.");
version = split[split.length - 1];
try {
SETUP = true;
MAJOR_VER = getVersion();
craftPlayer = getClass("{obc}.entity.CraftPlayer");
Method getHandle = craftPlayer.getMethod("getHandle");
connection = getHandle.getReturnType().getField("playerConnection");
Method sendPacket = connection.getType().getMethod("sendPacket", getClass("{nms}.Packet"));
chatComponentText = getClass("{nms}.ChatComponentText").getConstructor(String.class);
iChatBaseComponent = getClass("{nms}.IChatBaseComponent");
Method stringToChat;
if (MAJOR_VER < 8) {
stringToChat = getClass("{nms}.ChatSerializer").getMethod("a", String.class);
} else {
stringToChat = getClass("{nms}.IChatBaseComponent$ChatSerializer").getMethod("a", String.class);
}
GET_HANDLE = MethodHandles.lookup().unreflect(getHandle);
SEND_PACKET = MethodHandles.lookup().unreflect(sendPacket);
STRING_TO_CHAT = MethodHandles.lookup().unreflect(stringToChat);
packetPlayOutChat = getClass("{nms}.PacketPlayOutChat");
packetPlayOutTitle = getClass("{nms}.PacketPlayOutTitle");
titleAction = getClass("{nms}.PacketPlayOutTitle$EnumTitleAction");
enumActionTitle = titleAction.getField("TITLE").get(null);
enumActionSubtitle = titleAction.getField("SUBTITLE").get(null);
if (MAJOR_VER >= 12) {
Method getChatMessageType = getClass("{nms}.ChatMessageType").getMethod("a", byte.class);
enumChatMessage = getChatMessageType.invoke(null, (byte) 1);
enumActionbarMessage = getChatMessageType.invoke(null, (byte) 2);
}
} catch (Exception e) {
e.printStackTrace();
SETUP = false;
}
}
static void sendPacket(Object packet, Player... players) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
if (packet == null) {
return;
}
for (Player player : players) {
try {
SEND_PACKET.bindTo(connection.get(GET_HANDLE.bindTo(player).invoke())).invoke(packet);
} catch (Throwable e) {
System.err.println("Failed to send packet");
e.printStackTrace();
}
}
}
private static void setType(Object object, byte type) {
if (MAJOR_VER < 12) {
set("b", object, type);
return;
}
switch (type) {
case 1:
set("b", object, enumChatMessage);
break;
case 2:
set("b", object, enumActionbarMessage);
break;
default:
throw new IllegalArgumentException("type must be 1 or 2");
}
}
static Object createActionbarPacket(String message) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
Object packet = createTextPacket(message);
setType(packet, (byte) 2);
return packet;
}
static Object createTextPacket(String message) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
try {
Object packet = packetPlayOutChat.newInstance();
set("a", packet, fromJson(message));
setType(packet, (byte) 1);
return packet;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
static void sendTextPacket(String message, Player... players) {
try {
for (Player player : players) {
Class chatTypeClass = getClass("{nms}.ChatMessageType");
Constructor<?> constructor = packetPlayOutChat.getConstructor(getClass("{nms}.IChatBaseComponent"), chatTypeClass, UUID.class);
Object packet = constructor.newInstance(fromJson(message), Enum.valueOf(chatTypeClass, "CHAT"), player.getUniqueId());
Object handler = player.getClass().getMethod("getHandle").invoke(player);
Object playerConnection = handler.getClass().getField("playerConnection").get(handler);
playerConnection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(playerConnection, packet);
}
} catch (IllegalArgumentException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException | ClassNotFoundException e) {
e.printStackTrace();
}
}
static Object createTitlePacket(String message) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
try {
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionTitle, fromJson(message));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
static Object createSubtitlePacket(String message) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
try {
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionSubtitle, fromJson(message));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
static Object createTitleTimesPacket(int fadeIn, int stay, int fadeOut) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
try {
return packetPlayOutTitle.getConstructor(int.class, int.class, int.class).newInstance(fadeIn, stay, fadeOut);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Creates a ChatComponentText from plain text
*
* @param message The text to convert to a chat component
* @return The chat component
*/
static Object componentText(String message) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
try {
return chatComponentText.newInstance(message);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Attempts to convert a String representing a JSON message into a usable object
*
* @param json The JSON to attempt to parse
* @return The object representing the text in JSON form, or <code>null</code> if something went wrong converting the String to JSON data
*/
static Object fromJson(String json) {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
if (!json.trim().startsWith("{")) {
return componentText(json);
}
try {
return STRING_TO_CHAT.invoke(json);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/**
* Returns a class with the given package and name. This method replaces <code>{nms}</code> with <code>net.minecraft.server.[version]</code> and <code>{obc}</code> with <code>org.bukkit.craft.[version]</code>
* <br>
* <br>
* Example:
*
* <pre>
* Class<?> entityPlayer = ReflectionHelper.getClass("{nms}.EntityPlayer");
* </pre>
*
* @param path The path to the {@link Class}
* @return The class
* @throws ClassNotFoundException If the class was not found
*/
static Class<?> getClass(String path) throws ClassNotFoundException {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
return Class.forName(path.replace("{nms}", "net.minecraft.server." + version).replace("{obc}", "org.bukkit.craftbukkit." + version));
}
/**
* Sets a field with the given name on an object to the value specified
*
* @param field The name of the field to change
* @param obj The object to change the field of
* @param value The new value to set
*/
static void set(String field, Object obj, Object value) {
try {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getStringVersion() {
return version;
}
static int getVersion() {
if (!SETUP) {
throw new IllegalStateException("ReflectionHelper is not set up!");
}
try {
return Integer.parseInt(version.split("_")[1]);
} catch (NumberFormatException e) {
e.printStackTrace();
return 10;
}
}
}
/**
* Defines a section of the message, and represents the format that all JSON messages must follow in Minecraft.
* <br>
* <br>
* <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a>
*
* @author Rayzr
*/
public static class MessagePart {
private final List<ChatColor> styles = new ArrayList<>();
private MessageEvent onClick;
private MessageEvent onHover;
private ChatColor color;
private String text;
public MessagePart(String text) {
this.text = text == null ? "null" : text;
}
/**
* Converts this {@link MessagePart} into a {@link JsonObject}
*
* @return The Minecraft-compatible {@link JsonObject}
*/
public JsonObject toJSON() {
Objects.requireNonNull(text);
JsonObject obj = new JsonObject();
obj.addProperty("text", text);
if (color != null) {
obj.addProperty("color", color.name().toLowerCase());
}
for (ChatColor style : styles) {
obj.addProperty(stylesToNames.get(style), true);
}
if (onClick != null) {
obj.add("clickEvent", onClick.toJSON());
}
if (onHover != null) {
obj.add("hoverEvent", onHover.toJSON());
}
return obj;
}
/**
* @return This {@link MessagePart} in legacy-style color/formatting codes
*/
public String toLegacy() {
StringBuilder output = new StringBuilder();
if (color != null) {
output.append(color.toString());
}
styles.stream()
.map(ChatColor::toString)
.forEach(output::append);
return output.append(text).toString();
}
/**
* @return The click event bound
*/
public MessageEvent getOnClick() {
return onClick;
}
/**
* @param onClick The new click event to bind
*/
public void setOnClick(MessageEvent onClick) {
this.onClick = onClick;
}
/**
* @return The hover event bound
*/
public MessageEvent getOnHover() {
return onHover;
}
/**
* @param onHover The new hover event to bind
*/
public void setOnHover(MessageEvent onHover) {
this.onHover = onHover;
}
/**
* @return The color
*/
public ChatColor getColor() {
return color;
}
/**
* @param color The color to set
*/
public void setColor(ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color!");
}
this.color = color;
}
/**
* @return The list of styles
*/
public List<ChatColor> getStyles() {
return styles;
}
/**
* @param style The new style to add
*/
public void addStyle(ChatColor style) {
if (style == null) {
throw new IllegalArgumentException("Style cannot be null!");
}
if (!style.isFormat()) {
throw new IllegalArgumentException(color.name() + " is not a style!");
}
styles.add(style);
}
/**
* @return The raw text
*/
public String getText() {
return text;
}
/**
* @param text The raw text to set
*/
public void setText(String text) {
this.text = text;
}
}
}

@ -25,15 +25,16 @@ import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
public class Msg {
public final class Msg {
public static void msg(CommandSender s, String... msg) {
Arrays.stream(msg).map(Msg::color).forEach(s::sendMessage);
s.sendMessage(Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).collect(Collectors.joining("\n")));
}
public static void broadcast(String... msg) {
Arrays.stream(msg).map(Msg::color).forEach(Bukkit::broadcastMessage);
Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).forEach(Bukkit::broadcastMessage);
}
public static String color(String text) {

@ -20,6 +20,9 @@
*/
package me.clip.placeholderapi.util;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
public class TimeUtil {
public static String getRemaining(int seconds, TimeFormat type) {
@ -112,64 +115,56 @@ public class TimeUtil {
}
public static String getTime(int seconds) {
if (seconds < 60) {
return seconds + "s";
return getTime(Duration.ofSeconds(seconds));
}
int minutes = seconds / 60;
int s = 60 * minutes;
int secondsLeft = seconds - s;
/**
* Format the given value with s, m, h and d (seconds, minutes, hours and days)
*
* @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 seconds)
* @return formatted time
*/
public static String getTime(final Duration duration) {
final StringBuilder builder = new StringBuilder();
if (minutes < 60) {
if (secondsLeft > 0) {
return minutes + "m " + secondsLeft + "s";
} else {
return minutes + "m";
}
long seconds = duration.getSeconds();
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
seconds %= 60;
minutes %= 60;
hours %= 60;
days %= 24;
if (seconds > 0) {
builder.insert(0, seconds + "s");
}
if (minutes < 1440) {
String time;
int hours = minutes / 60;
time = hours + "h";
int inMins = 60 * hours;
int leftOver = minutes - inMins;
if (leftOver >= 1) {
time = time + " " + leftOver + "m";
if (minutes > 0) {
if (builder.length() > 0) {
builder.insert(0, ' ');
}
if (secondsLeft > 0) {
time = time + " " + secondsLeft + "s";
builder.insert(0, minutes + "m");
}
return time;
if (hours > 0) {
if (builder.length() > 0) {
builder.insert(0, ' ');
}
String time;
int days = minutes / 1440;
time = days + "d";
int inMins = 1440 * days;
int leftOver = minutes - inMins;
if (leftOver >= 1) {
if (leftOver < 60) {
time = time + " " + leftOver + "m";
} else {
int hours = leftOver / 60;
time = time + " " + hours + "h";
int hoursInMins = 60 * hours;
int minsLeft = leftOver - hoursInMins;
time = time + " " + minsLeft + "m";
}
builder.insert(0, hours + "h");
}
if (secondsLeft > 0) {
time = time + " " + secondsLeft + "s";
if (days > 0) {
if (builder.length() > 0) {
builder.insert(0, ' ');
}
return time;
builder.insert(0, days + "d");
}
return builder.toString();
}
}

@ -1,7 +1,7 @@
name: ${project.name}
main: me.clip.placeholderapi.PlaceholderAPIPlugin
version: ${project.version}
api-version: 1.13
api-version: '1.13'
authors: [extended_clip, Glare]
description: ${project.description}
permissions: