/*
*
* 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 .
*
*
*/
package me.clip.placeholderapi;
import me.clip.placeholderapi.commands.CommandHandler;
import me.clip.placeholderapi.commands.CompletionHandler;
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.ApacheListener;
import me.clip.placeholderapi.listeners.PlaceholderListener;
import me.clip.placeholderapi.listeners.ServerLoadEventListener;
import me.clip.placeholderapi.util.TimeUtil;
import me.clip.placeholderapi.util.UpdateChecker;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Yes I have a shit load of work to do...
*
* @author Ryan McCarthy
*/
public class PlaceholderAPIPlugin extends JavaPlugin {
private static final Version serverVersion;
private static PlaceholderAPIPlugin instance;
private static DateTimeFormatter dateFormat;
private static String booleanTrue;
private static String booleanFalse;
static {
// It's not possible to be null or throw an index exception unless it's a bug.
String nmsVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
boolean spigot;
try {
Class.forName("org.spigotmc.SpigotConfig");
spigot = true;
} catch (ExceptionInInitializerError | ClassNotFoundException ignored) {
spigot = false;
}
serverVersion = new Version(nmsVersion, spigot);
}
private PlaceholderAPIConfig config;
private ExpansionManager expansionManager;
private ExpansionCloudManager expansionCloud;
private long startTime;
/**
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API
* class, this is the main class that extends JavaPlugin. For most API methods, use static methods
* available from the class: {@link PlaceholderAPI}
*
* @return PlaceholderAPIPlugin instance
*/
public static PlaceholderAPIPlugin getInstance() {
return instance;
}
/**
* Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for
* generic time based placeholders
*
* @return date format
*/
public static DateTimeFormatter getDateFormat() {
return dateFormat != null ? dateFormat : DateTimeFormatter.ofPattern("MM/dd/yy HH:mm:ss");
}
/**
* Get the configurable {@linkplain String} value that should be returned when a boolean is true
*
* @return string value of true
*/
public static String booleanTrue() {
return booleanTrue != null ? booleanTrue : "true";
}
/**
* Get the configurable {@linkplain String} value that should be returned when a boolean is false
*
* @return string value of false
*/
public static String booleanFalse() {
return booleanFalse != null ? booleanFalse : "false";
}
public static Version getServerVersion() {
return serverVersion;
}
@Override
public void onEnable() {
startTime = System.currentTimeMillis();
instance = this;
config = new PlaceholderAPIConfig(this);
config.loadDefConfig();
setupOptions();
expansionManager = new ExpansionManager(this);
new PlaceholderListener(this);
PluginCommand command = getCommand("placeholderapi");
command.setExecutor(new CommandHandler());
command.setTabCompleter(new CompletionHandler());
new ApacheListener(this);
try {
Class.forName("org.bukkit.event.server.ServerLoadEvent");
new ServerLoadEventListener(this);
} catch (ExceptionInInitializerError | ClassNotFoundException exception) {
Bukkit.getScheduler().runTaskLater(this, () -> {
getLogger().info("Placeholder expansion registration initializing...");
//fetch any hooks that may have registered externally onEnable first otherwise they will be lost
Map alreadyRegistered = PlaceholderAPI.PLACEHOLDERS;
getExpansionManager().registerAllExpansions();
if (alreadyRegistered != null && !alreadyRegistered.isEmpty()) {
alreadyRegistered.forEach(PlaceholderAPI::registerPlaceholderHook);
}
}, 1);
}
if (config.checkUpdates()) new UpdateChecker(this).fetch();
if (config.isCloudEnabled()) enableCloud();
setupMetrics();
getServer().getScheduler().runTaskLater(this, this::checkHook, 40);
}
@Override
public void onDisable() {
disableCloud();
PlaceholderAPI.unregisterAll();
Bukkit.getScheduler().cancelTasks(this);
expansionManager = null;
instance = null;
}
public void reloadConf(CommandSender s) {
PlaceholderAPI.unregisterAllProvidedExpansions();
reloadConfig();
setupOptions();
expansionManager.registerAllExpansions();
if (!config.isCloudEnabled()) {
disableCloud();
} else if (this.expansionCloud != null) {
enableCloud();
}
s.sendMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.PLACEHOLDERS.size() + " &aplaceholder hooks successfully registered!"));
}
@SuppressWarnings("deprecation")
private void checkHook() {
for (PlaceholderHook hook : PlaceholderAPI.PLACEHOLDERS.values()) {
if (hook instanceof EZPlaceholderHook) {
String pluginName = ((EZPlaceholderHook) hook).getPluginName();
String author;
try {
author = Bukkit.getPluginManager().getPlugin(pluginName).getDescription().getAuthors().toString();
} catch (Exception ex) {
author = "the author of the hook's plugin";
}
getLogger().severe(pluginName +
" is currently using a deprecated method to hook into PlaceholderAPI. Placeholders for that plugin no longer work. " +
"Please consult " + author + " and urge them to update it ASAP.");
// disable the hook on startup
PlaceholderAPI.unregisterPlaceholderHook(((EZPlaceholderHook) hook).getPlaceholderName());
}
}
}
private void setupOptions() {
booleanTrue = config.booleanTrue();
if (booleanTrue == null) booleanTrue = "true";
booleanFalse = config.booleanFalse();
if (booleanFalse == null) booleanFalse = "false";
try {
dateFormat = DateTimeFormatter.ofPattern(config.dateFormat());
} catch (Exception ignored) {
dateFormat = DateTimeFormatter.ofPattern("MM/dd/yy HH:mm:ss");
}
}
private void setupMetrics() {
// This is NOT the plugin resource ID. it's the bStats ID.
Metrics metrics = new Metrics(this, 438);
metrics.addCustomChart(new Metrics.SimplePie("using_expansion_cloud",
() -> getExpansionCloud() != null ? "yes" : "no"));
metrics.addCustomChart(new Metrics.SimplePie("using_spigot",
() -> getServerVersion().isSpigot() ? "yes" : "no"));
metrics.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> {
Map map = new HashMap<>();
for (PlaceholderHook hook : PlaceholderAPI.PLACEHOLDERS.values()) {
if (hook.isExpansion()) {
PlaceholderExpansion ex = (PlaceholderExpansion) hook;
map.put(ex.getRequiredPlugin() == null ? ex.getIdentifier()
: ex.getRequiredPlugin(), 1);
}
}
return map;
}));
}
public void enableCloud() {
if (expansionCloud == null) {
expansionCloud = new ExpansionCloudManager(this);
} else {
expansionCloud.clean();
}
expansionCloud.fetch(config.cloudAllowUnverifiedExpansions());
}
public void disableCloud() {
if (expansionCloud != null) expansionCloud = null;
}
/**
* Obtain the configuration class for PlaceholderAPI.
*
* @return PlaceholderAPIConfig instance
*/
public PlaceholderAPIConfig getPlaceholderAPIConfig() {
return config;
}
public ExpansionManager getExpansionManager() {
return expansionManager;
}
public ExpansionCloudManager getExpansionCloud() {
return expansionCloud;
}
public String getUptime() {
return TimeUtil
.getTime((int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime));
}
public long getUptimeMillis() {
return System.currentTimeMillis() - startTime;
}
}