diff --git a/pom.xml b/pom.xml
index bcf424033..c2bc4dc8b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,10 @@
vault-repo
http://nexus.hc.to/content/repositories/pub_releases
+
+ placeholderapi
+ http://repo.extendedclip.com/content/repositories/placeholderapi/
+
@@ -108,6 +112,13 @@
1.7
provided
+
+
+ me.clip
+ placeholderapi
+ 2.9.2
+ provided
+
diff --git a/src/main/java/world/bentobox/bentobox/BentoBox.java b/src/main/java/world/bentobox/bentobox/BentoBox.java
index 5584f4757..d45315966 100644
--- a/src/main/java/world/bentobox/bentobox/BentoBox.java
+++ b/src/main/java/world/bentobox/bentobox/BentoBox.java
@@ -12,6 +12,7 @@ import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
import world.bentobox.bentobox.api.user.Notifier;
import world.bentobox.bentobox.commands.BentoBoxCommand;
+import world.bentobox.bentobox.hooks.PlaceholderAPIHook;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.listeners.BannedVisitorCommands;
import world.bentobox.bentobox.listeners.BlockEndDragon;
@@ -27,6 +28,7 @@ import world.bentobox.bentobox.managers.HooksManager;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
+import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.managers.SchemsManager;
@@ -52,6 +54,7 @@ public class BentoBox extends JavaPlugin {
private RanksManager ranksManager;
private SchemsManager schemsManager;
private HooksManager hooksManager;
+ private PlaceholdersManager placeholdersManager;
// Settings
private Settings settings;
@@ -143,6 +146,10 @@ public class BentoBox extends JavaPlugin {
// Load hooks
hooksManager = new HooksManager(this);
hooksManager.registerHook(new VaultHook());
+ hooksManager.registerHook(new PlaceholderAPIHook());
+
+ // Setup the Placeholders manager
+ placeholdersManager = new PlaceholdersManager(this);
// Fire plugin ready event
isLoaded = true;
diff --git a/src/main/java/world/bentobox/bentobox/api/placeholders/PlaceholderReplacer.java b/src/main/java/world/bentobox/bentobox/api/placeholders/PlaceholderReplacer.java
new file mode 100644
index 000000000..54bdfb59d
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/api/placeholders/PlaceholderReplacer.java
@@ -0,0 +1,8 @@
+package world.bentobox.bentobox.api.placeholders;
+
+import world.bentobox.bentobox.api.user.User;
+
+public interface PlaceholderReplacer {
+
+ String onReplace(User user);
+}
diff --git a/src/main/java/world/bentobox/bentobox/hooks/PlaceholderAPIHook.java b/src/main/java/world/bentobox/bentobox/hooks/PlaceholderAPIHook.java
new file mode 100644
index 000000000..f8e425f35
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/hooks/PlaceholderAPIHook.java
@@ -0,0 +1,128 @@
+package world.bentobox.bentobox.hooks;
+
+import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import org.bukkit.entity.Player;
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.Addon;
+import world.bentobox.bentobox.api.hooks.Hook;
+import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
+import world.bentobox.bentobox.api.user.User;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Provides implementations and interfacing needed to register and get placeholders from PlaceholderAPI.
+ *
+ * @author Poslovitch
+ */
+public class PlaceholderAPIHook extends Hook {
+
+ private BentoBoxPlaceholderExpansion bentoboxExpansion;
+ private Map addonsExpansions;
+
+ public PlaceholderAPIHook() {
+ super("PlaceholderAPI");
+ this.bentoboxExpansion = new BentoBoxPlaceholderExpansion(BentoBox.getInstance());
+ this.addonsExpansions = new HashMap<>();
+ }
+
+ @Override
+ public boolean hook() {
+ return bentoboxExpansion.canRegister() && bentoboxExpansion.register();
+ }
+
+ @Override
+ public String getFailureCause() {
+ return "could not register BentoBox's expansion";
+ }
+
+ public void registerBentoBoxPlaceholder(String placeholder, PlaceholderReplacer replacer) {
+ bentoboxExpansion.registerPlaceholder(placeholder, replacer);
+ }
+
+ public void registerAddonPlaceholder(Addon addon, String placeholder, PlaceholderReplacer replacer) {
+ // Check if the addon expansion does not exist
+ if (!addonsExpansions.containsKey(addon)) {
+ AddonPlaceholderExpansion addonPlaceholderExpansion = new AddonPlaceholderExpansion(addon);
+ addonPlaceholderExpansion.register();
+ addonsExpansions.put(addon, addonPlaceholderExpansion);
+ }
+
+ addonsExpansions.get(addon).registerPlaceholder(placeholder, replacer);
+ }
+
+ abstract class BasicPlaceholderExpansion extends PlaceholderExpansion {
+ private Map placeholders;
+
+ BasicPlaceholderExpansion() {
+ this.placeholders = new HashMap<>();
+ }
+
+ @Override
+ public String getIdentifier() {
+ return getName().toLowerCase(Locale.ENGLISH);
+ }
+
+ void registerPlaceholder(String placeholder, PlaceholderReplacer replacer) {
+ placeholders.putIfAbsent(placeholder, replacer);
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player p, String placeholder) {
+ User user = User.getInstance(p);
+
+ if (placeholders.containsKey(placeholder)) {
+ return placeholders.get(placeholder).onReplace(user);
+ }
+ return null;
+ }
+ }
+
+ class BentoBoxPlaceholderExpansion extends BasicPlaceholderExpansion {
+ private BentoBox plugin;
+
+ BentoBoxPlaceholderExpansion(BentoBox plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public String getName() {
+ return plugin.getName();
+ }
+
+ @Override
+ public String getAuthor() {
+ return "Tastybento and Poslovitch";
+ }
+
+ @Override
+ public String getVersion() {
+ return plugin.getDescription().getVersion();
+ }
+ }
+
+ class AddonPlaceholderExpansion extends BasicPlaceholderExpansion {
+ private Addon addon;
+
+ AddonPlaceholderExpansion(Addon addon) {
+ this.addon = addon;
+ }
+
+ @Override
+ public String getName() {
+ return addon.getDescription().getName();
+ }
+
+ @Override
+ public String getAuthor() {
+ return addon.getDescription().getAuthors().get(0);
+ }
+
+ @Override
+ public String getVersion() {
+ return addon.getDescription().getVersion();
+ }
+ }
+}
diff --git a/src/main/java/world/bentobox/bentobox/managers/PlaceholdersManager.java b/src/main/java/world/bentobox/bentobox/managers/PlaceholdersManager.java
new file mode 100644
index 000000000..341dbee1c
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/managers/PlaceholdersManager.java
@@ -0,0 +1,35 @@
+package world.bentobox.bentobox.managers;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.addons.Addon;
+import world.bentobox.bentobox.api.placeholders.PlaceholderReplacer;
+import world.bentobox.bentobox.hooks.PlaceholderAPIHook;
+
+public class PlaceholdersManager {
+
+ private BentoBox plugin;
+
+ public PlaceholdersManager(BentoBox plugin) {
+ this.plugin = plugin;
+ }
+
+ public void registerPlaceholder(String placeholder, PlaceholderReplacer replacer) {
+ // Register it in PlaceholderAPI
+ plugin.getHooks().getHook("PlaceholderAPI").ifPresent(hook -> {
+ PlaceholderAPIHook placeholderAPIHook = (PlaceholderAPIHook) hook;
+ placeholderAPIHook.registerBentoBoxPlaceholder(placeholder, replacer);
+ });
+ }
+
+ public void registerPlaceholder(Addon addon, String placeholder, PlaceholderReplacer replacer) {
+ if (addon == null) {
+ registerPlaceholder(placeholder, replacer);
+ return;
+ }
+ // Register it in PlaceholderAPI
+ plugin.getHooks().getHook("PlaceholderAPI").ifPresent(hook -> {
+ PlaceholderAPIHook placeholderAPIHook = (PlaceholderAPIHook) hook;
+ placeholderAPIHook.registerAddonPlaceholder(addon, placeholder, replacer);
+ });
+ }
+}