diff --git a/src/main/java/me/clip/placeholderapi/PlaceholderAPI.java b/src/main/java/me/clip/placeholderapi/PlaceholderAPI.java
index 53c0ffc..36b9b56 100644
--- a/src/main/java/me/clip/placeholderapi/PlaceholderAPI.java
+++ b/src/main/java/me/clip/placeholderapi/PlaceholderAPI.java
@@ -32,6 +32,7 @@ import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
import me.clip.placeholderapi.replacer.CharsReplacer;
+import me.clip.placeholderapi.replacer.DelegatorReplacer;
import me.clip.placeholderapi.replacer.Replacer;
import me.clip.placeholderapi.replacer.Replacer.Closure;
import me.clip.placeholderapi.util.Msg;
@@ -43,8 +44,8 @@ import org.jetbrains.annotations.NotNull;
public final class PlaceholderAPI {
- private static Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
- private static Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
+ private static final Replacer REPLACER_PERCENT = new DelegatorReplacer(new CharsReplacer(Closure.PERCENT));
+ private static final Replacer REPLACER_BRACKET = new DelegatorReplacer(new CharsReplacer(Closure.BRACKET));
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
private static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
diff --git a/src/main/java/me/clip/placeholderapi/events/PlaceholderRequestEvent.java b/src/main/java/me/clip/placeholderapi/events/PlaceholderRequestEvent.java
new file mode 100644
index 0000000..5bc8852
--- /dev/null
+++ b/src/main/java/me/clip/placeholderapi/events/PlaceholderRequestEvent.java
@@ -0,0 +1,78 @@
+package me.clip.placeholderapi.events;
+
+import org.bukkit.OfflinePlayer;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import me.clip.placeholderapi.replacer.Replacer;
+
+
+/**
+ * Fired when user requests for placeholder replacement via {@link Replacer}
+ * */
+public class PlaceholderRequestEvent extends Event
+{
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final String input;
+ private final OfflinePlayer player;
+ private final Replacer defaultReplacer;
+ private String output;
+
+ public PlaceholderRequestEvent(String input, OfflinePlayer player, Replacer defaultReplacer) {
+ this.input = input;
+ this.player = player;
+ this.defaultReplacer = defaultReplacer;
+ }
+
+ /**
+ * @return Input string of the request with no replacements
+ * */
+ public @NotNull String getInput() {
+ return input;
+ }
+
+ /**
+ * @return Player that was used for replacement
+ */
+ public @Nullable OfflinePlayer getPlayer() {
+ return player;
+ }
+
+ /**
+ * Returns output that will be provided for this request.
+ *
If the output is equal to null, replacer will be used to provide final result
+ * @return Output that will be provided for this request
+ */
+ public @Nullable String getOutput() {
+ return output;
+ }
+
+ /**
+ * Sets output that will be provided for this request
+ *
If the output is equal to null, replacer will be used to provide final result
+ * @param output Output that will be provided for this request
+ */
+ public void setOutput(@Nullable String output) {
+ this.output = output;
+ }
+
+ /**
+ * @return {@link Replacer} that will be used to provide final result if {@link PlaceholderRequestEvent#getOutput()} is null
+ */
+ public Replacer getDefaultReplacer() {
+ return defaultReplacer;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+}
diff --git a/src/main/java/me/clip/placeholderapi/replacer/DelegatorReplacer.java b/src/main/java/me/clip/placeholderapi/replacer/DelegatorReplacer.java
new file mode 100644
index 0000000..9e3cee8
--- /dev/null
+++ b/src/main/java/me/clip/placeholderapi/replacer/DelegatorReplacer.java
@@ -0,0 +1,28 @@
+package me.clip.placeholderapi.replacer;
+
+import me.clip.placeholderapi.events.PlaceholderRequestEvent;
+import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.Function;
+
+public class DelegatorReplacer implements Replacer {
+
+ private final Replacer defaultReplacer;
+
+ public DelegatorReplacer(Replacer defaultReplacer) {
+ this.defaultReplacer = defaultReplacer;
+ }
+
+
+ @Override
+ public @NotNull String apply(@NotNull String text, @Nullable OfflinePlayer player, @NotNull Function lookup) {
+ PlaceholderRequestEvent placeholderRequestEvent = new PlaceholderRequestEvent(text, player, defaultReplacer);
+ Bukkit.getPluginManager().callEvent(placeholderRequestEvent);
+ return placeholderRequestEvent.getOutput() == null ? defaultReplacer.apply(text, player, lookup)
+ : placeholderRequestEvent.getOutput();
+ }
+}