mirror of
https://github.com/PlaceholderAPI/PlaceholderAPI
synced 2026-02-07 12:37:14 +01:00
Compare commits
14 Commits
hytale-cur
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9022daf07f | ||
|
|
675b305cac | ||
|
|
d49c76c560 | ||
|
|
13e492cf44 | ||
|
|
d561afbb63 | ||
|
|
2a3f4482a0 | ||
|
|
4ee2840a0a | ||
|
|
c52d117f12 | ||
|
|
e307aba414 | ||
|
|
5ea5a18fe8 | ||
|
|
9c1db4b48a | ||
|
|
b233c92ca1 | ||
|
|
1b1d2e61b9 | ||
|
|
2dc5b93133 |
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 240+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.
|
Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 240+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.
|
||||||
|
|
||||||
PlaceholderAPI has been downloaded over 1,700,000 times on Spigot and has been used concurrently on over 45,000 servers, which makes it a must-have for a server of any type or scale.
|
PlaceholderAPI has been downloaded over 2,000,000 times on Spigot and has been used concurrently on over 50,000 servers, which makes it a must-have for a server of any type or scale.
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
If you would like to contribute towards PlaceholderAPI should you take a look at our [Contributing file][contributing] for the ins and outs on how you can do that and what you need to keep in mind.
|
If you would like to contribute towards PlaceholderAPI should you take a look at our [Contributing file][contributing] for the ins and outs on how you can do that and what you need to keep in mind.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "me.clip"
|
group = "me.clip"
|
||||||
version = "2.12.0-DEV-${System.getProperty("BUILD_NUMBER")}"
|
version = "2.12.2-DEV-${System.getProperty("BUILD_NUMBER")}"
|
||||||
|
|
||||||
description = "An awesome placeholder provider!"
|
description = "An awesome placeholder provider!"
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.impl.cloud.CommandECloud;
|
import me.clip.placeholderapi.commands.impl.cloud.CommandECloud;
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandDump;
|
import me.clip.placeholderapi.commands.impl.local.CommandDump;
|
||||||
@@ -119,14 +120,18 @@ public final class PlaceholderCommandRouter implements CommandExecutor, TabCompl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(@NotNull final CommandSender sender,
|
public List<String> onTabComplete(@NotNull final CommandSender sender, @NotNull final Command command,
|
||||||
@NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) {
|
@NotNull final String alias, @NotNull final String[] args) {
|
||||||
final List<String> suggestions = new ArrayList<>();
|
final List<String> suggestions = new ArrayList<>();
|
||||||
|
|
||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
final PlaceholderCommand target = this.commands.get(args[0].toLowerCase(Locale.ROOT));
|
final PlaceholderCommand target = this.commands.get(args[0].toLowerCase(Locale.ROOT));
|
||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
|
if (target.getPermission() != null && !target.getPermission().isEmpty() && !sender.hasPermission(target.getPermission())) {
|
||||||
|
return suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
target.complete(plugin, sender, args[0].toLowerCase(Locale.ROOT),
|
target.complete(plugin, sender, args[0].toLowerCase(Locale.ROOT),
|
||||||
Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions);
|
Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ public final class CommandECloud extends PlaceholderCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!target.getLabel().equalsIgnoreCase("refresh") && plugin.getCloudExpansionManager().isEmpty()) {
|
||||||
|
Msg.msg(sender, "&cThere is no available data from the eCloud. Please try running &f/papi ecloud refresh&c. If this does not resolve the issue, the eCloud may be blocked by your firewall, server host, or service provider.\n&r\n&cMore information: &fhttps://placeholderapi.com/ecloud-blocked");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
target.evaluate(plugin, sender, search, params.subList(1, params.size()));
|
target.evaluate(plugin, sender, search, params.subList(1, params.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,8 @@ public final class CommandECloudExpansionList extends PlaceholderCommand {
|
|||||||
.append(newline()).append(newline())
|
.append(newline()).append(newline())
|
||||||
.append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
|
.append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
|
||||||
.append(newline())
|
.append(newline())
|
||||||
|
.append(text("Version: ", AQUA)).append(text(expansion.getVersion().getVersion(), WHITE))
|
||||||
|
.append(newline())
|
||||||
.append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD))
|
.append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD))
|
||||||
.append(newline())
|
.append(newline())
|
||||||
.append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
|
.append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ public final class PlaceholderAPIConfig {
|
|||||||
return plugin.getConfig().getBoolean("debug", false);
|
return plugin.getConfig().getBoolean("debug", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean useAdventureReplacer() {
|
||||||
|
return plugin.getConfig().getBoolean("use_adventure_provided_replacer", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Optional<ExpansionSort> getExpansionSort() {
|
public Optional<ExpansionSort> getExpansionSort() {
|
||||||
final String option = plugin.getConfig()
|
final String option = plugin.getConfig()
|
||||||
@@ -87,8 +91,11 @@ public final class PlaceholderAPIConfig {
|
|||||||
return plugin.getConfig().getString("boolean.false", "false");
|
return plugin.getConfig().getString("boolean.false", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean useAdventureProvidedReplacer() {
|
||||||
|
return plugin.getConfig().getBoolean("use_adventure_provided_replacer", false);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean detectMaliciousExpansions() {
|
public boolean detectMaliciousExpansions() {
|
||||||
return plugin.getConfig().getBoolean("detect_malicious_expansions", true);
|
return plugin.getConfig().getBoolean("detect_malicious_expansions", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -62,7 +63,7 @@ import org.jetbrains.annotations.Unmodifiable;
|
|||||||
public final class CloudExpansionManager {
|
public final class CloudExpansionManager {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static final String API_URL = "https://ecloud.placeholderapi.com/api/v3/";
|
private static final String API_URL = "https://ecloud.placeholderapi.com/api/v3/?platform=bukkit";
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static final Gson GSON = new Gson();
|
private static final Gson GSON = new Gson();
|
||||||
@@ -115,6 +116,10 @@ public final class CloudExpansionManager {
|
|||||||
return ImmutableMap.copyOf(cache);
|
return ImmutableMap.copyOf(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return cache.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Unmodifiable
|
@Unmodifiable
|
||||||
public Map<String, CloudExpansion> getCloudExpansionsInstalled() {
|
public Map<String, CloudExpansion> getCloudExpansionsInstalled() {
|
||||||
@@ -197,6 +202,8 @@ public final class CloudExpansionManager {
|
|||||||
for (String name : toRemove) {
|
for (String name : toRemove) {
|
||||||
values.remove(name);
|
values.remove(name);
|
||||||
}
|
}
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "There is no data available from the eCloud. Please try running /papi refresh. If this does not resolve the issue, the eCloud may be blocked by your firewall, server host, or service provider.\n\nMore information: https://placeholderapi.com/ecloud-blocked", e);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// ugly swallowing of every throwable, but we have to be defensive
|
// ugly swallowing of every throwable, but we have to be defensive
|
||||||
plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e);
|
plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e);
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import java.net.URL;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
@@ -36,12 +38,13 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
public class UpdateChecker implements Listener {
|
public class UpdateChecker implements Listener {
|
||||||
|
private static final String MODRINTH_URL = "https://api.modrinth.com/v2/project/lKEzGugV/version";
|
||||||
|
|
||||||
private static final int RESOURCE_ID = 6245;
|
private static final int RESOURCE_ID = 6245;
|
||||||
private final PlaceholderAPIPlugin plugin;
|
private final PlaceholderAPIPlugin plugin;
|
||||||
private final TaskScheduler scheduler;
|
private final TaskScheduler scheduler;
|
||||||
private final String pluginVersion;
|
private final String pluginVersion;
|
||||||
private String spigotVersion;
|
private String modrinthVersion;
|
||||||
private boolean updateAvailable;
|
private boolean updateAvailable;
|
||||||
|
|
||||||
public UpdateChecker(PlaceholderAPIPlugin plugin) {
|
public UpdateChecker(PlaceholderAPIPlugin plugin) {
|
||||||
@@ -54,27 +57,27 @@ public class UpdateChecker implements Listener {
|
|||||||
return updateAvailable;
|
return updateAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSpigotVersion() {
|
public String getModrinthVersion() {
|
||||||
return spigotVersion;
|
return modrinthVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetch() {
|
public void fetch() {
|
||||||
scheduler.runTaskAsynchronously(() -> {
|
scheduler.runTaskAsynchronously(() -> {
|
||||||
try {
|
try {
|
||||||
HttpsURLConnection con = (HttpsURLConnection) new URL(
|
HttpsURLConnection con = (HttpsURLConnection) new URL(MODRINTH_URL).openConnection();
|
||||||
"https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection();
|
|
||||||
con.setRequestMethod("GET");
|
con.setRequestMethod("GET");
|
||||||
spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
|
final JsonElement json = JsonParser.parseReader(new BufferedReader(new InputStreamReader(con.getInputStream())));
|
||||||
|
modrinthVersion = json.getAsJsonArray().get(0).getAsJsonObject().get("version_number").getAsString();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
plugin.getLogger().info("Failed to check for updates on spigot.");
|
plugin.getLogger().info("Failed to check for updates on modrinth.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spigotVersion == null || spigotVersion.isEmpty()) {
|
if (modrinthVersion == null || modrinthVersion.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAvailable = spigotIsNewer();
|
updateAvailable = modrinthIsNewer();
|
||||||
|
|
||||||
if (!updateAvailable) {
|
if (!updateAvailable) {
|
||||||
return;
|
return;
|
||||||
@@ -82,21 +85,21 @@ public class UpdateChecker implements Listener {
|
|||||||
|
|
||||||
scheduler.runTask(() -> {
|
scheduler.runTask(() -> {
|
||||||
plugin.getLogger()
|
plugin.getLogger()
|
||||||
.info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:");
|
.info("An update for PlaceholderAPI (v" + getModrinthVersion() + ") is available at:");
|
||||||
plugin.getLogger()
|
plugin.getLogger()
|
||||||
.info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/");
|
.info("https://modrinth.com/plugin/placeholderapi");
|
||||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean spigotIsNewer() {
|
private boolean modrinthIsNewer() {
|
||||||
if (spigotVersion == null || spigotVersion.isEmpty()) {
|
if (modrinthVersion == null || modrinthVersion.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] plV = toReadable(pluginVersion);
|
int[] plV = toReadable(pluginVersion);
|
||||||
int[] spV = toReadable(spigotVersion);
|
int[] spV = toReadable(modrinthVersion);
|
||||||
|
|
||||||
if (plV[0] < spV[0]) {
|
if (plV[0] < spV[0]) {
|
||||||
return true;
|
return true;
|
||||||
@@ -119,10 +122,9 @@ public class UpdateChecker implements Listener {
|
|||||||
public void onJoin(PlayerJoinEvent e) {
|
public void onJoin(PlayerJoinEvent e) {
|
||||||
if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) {
|
if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) {
|
||||||
Msg.msg(e.getPlayer(),
|
Msg.msg(e.getPlayer(),
|
||||||
"&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion()
|
"&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getModrinthVersion()
|
||||||
+ "&e)"
|
+ "&e)"
|
||||||
, "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID
|
, "&bis available at &ehttps://modrinth.com/plugin/placeholderapi");
|
||||||
+ "/");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
# Expansions: https://placeholderapi.com/ecloud
|
# Expansions: https://placeholderapi.com/ecloud
|
||||||
# Wiki: https://wiki.placeholderapi.com/
|
# Wiki: https://wiki.placeholderapi.com/
|
||||||
# Discord: https://helpch.at/discord
|
# Discord: https://helpch.at/discord
|
||||||
|
# If you're seeing performance issues with plugins that use component replacement, or things don't look quite right,
|
||||||
|
# switch to the replacer provided by adventure itself by changing use_adventure_provided_replacer to true
|
||||||
# No placeholders are provided with this plugin by default.
|
# No placeholders are provided with this plugin by default.
|
||||||
# Download placeholders: /papi ecloud
|
# Download placeholders: /papi ecloud
|
||||||
check_updates: true
|
check_updates: true
|
||||||
@@ -16,4 +18,5 @@ boolean:
|
|||||||
'false': 'no'
|
'false': 'no'
|
||||||
date_format: MM/dd/yy HH:mm:ss
|
date_format: MM/dd/yy HH:mm:ss
|
||||||
detect_malicious_expansions: true
|
detect_malicious_expansions: true
|
||||||
|
use_adventure_provided_replacer: false
|
||||||
debug: false
|
debug: false
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
package me.clip.placeholderapi;
|
package me.clip.placeholderapi;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.replacer.ComponentReplacer;
|
||||||
import me.clip.placeholderapi.replacer.ExactReplacer;
|
import me.clip.placeholderapi.replacer.ExactReplacer;
|
||||||
import me.clip.placeholderapi.replacer.RelationalExactReplacer;
|
import me.clip.placeholderapi.replacer.RelationalExactReplacer;
|
||||||
import me.clip.placeholderapi.replacer.Replacer;
|
import me.clip.placeholderapi.replacer.Replacer;
|
||||||
@@ -48,9 +49,12 @@ public final class PAPIComponents {
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Component setPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
|
public static Component setPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
|
||||||
// TODO: explore a custom TextReplacementRenderer which doesn't use regex for performance benefits i.e. merge CharsReplacer with kyori TextReplacementRenderer
|
if (PlaceholderAPIPlugin.getInstance().getPlaceholderAPIConfig().useAdventureProvidedReplacer()) {
|
||||||
return component.replaceText(config -> config.match(PlaceholderAPI.PLACEHOLDER_PATTERN).replacement((result, builder) ->
|
return component.replaceText(config -> config.match(PlaceholderAPI.PLACEHOLDER_PATTERN).replacement((result, builder) ->
|
||||||
builder.content(PERCENT_EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
|
builder.content(PERCENT_EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ComponentReplacer.replace(component, str -> PlaceholderAPI.setPlaceholders(player, str));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,8 +106,12 @@ public final class PAPIComponents {
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Component setBracketPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
|
public static Component setBracketPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
|
||||||
return component.replaceText(config -> config.match(PlaceholderAPI.BRACKET_PLACEHOLDER_PATTERN).replacement((result, builder) ->
|
if (PlaceholderAPIPlugin.getInstance().getPlaceholderAPIConfig().useAdventureReplacer()) {
|
||||||
builder.content(BRACKET_EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
|
return component.replaceText(config -> config.match(PlaceholderAPI.BRACKET_PLACEHOLDER_PATTERN).replacement((result, builder) ->
|
||||||
|
builder.content(BRACKET_EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ComponentReplacer.replace(component, str -> PlaceholderAPI.setBracketPlaceholders(player, str));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,6 +163,7 @@ public final class PAPIComponents {
|
|||||||
* @return The Component containing the parsed relational placeholders
|
* @return The Component containing the parsed relational placeholders
|
||||||
*/
|
*/
|
||||||
public static Component setRelationalPlaceholders(Player one, Player two, Component component) {
|
public static Component setRelationalPlaceholders(Player one, Player two, Component component) {
|
||||||
|
//todo: custom replacer
|
||||||
return component.replaceText(config -> config.match(RELATIONAL_PLACEHOLDER_PATTERN).replacement((result, builder) ->
|
return component.replaceText(config -> config.match(RELATIONAL_PLACEHOLDER_PATTERN).replacement((result, builder) ->
|
||||||
builder.content(RELATIONAL_EXACT_REPLACER.apply(result.group(2), one, two, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
|
builder.content(RELATIONAL_EXACT_REPLACER.apply(result.group(2), one, two, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
|
||||||
}
|
}
|
||||||
@@ -172,9 +181,4 @@ public final class PAPIComponents {
|
|||||||
return components.stream().map(line -> setRelationalPlaceholders(one, two, line))
|
return components.stream().map(line -> setRelationalPlaceholders(one, two, line))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
// kyori doesn't seem to have a method that can do a contains with regex, we don't want to do a more expensive replace
|
|
||||||
// public static boolean containsPlaceholders(@Nullable final Component text) {
|
|
||||||
// return text != null && text.replaceText()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package me.clip.placeholderapi.replacer;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||||
|
import net.kyori.adventure.text.*;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.event.DataComponentValue;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.Style;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ComponentReplacer {
|
||||||
|
@NotNull
|
||||||
|
public static Component replace(@NotNull final Component component, @NotNull final Function<String, String> replacer) {
|
||||||
|
return rebuild(component, replacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static Component rebuild(@NotNull final Component component, @NotNull final Function<String, String> replacer) {
|
||||||
|
Component rebuilt;
|
||||||
|
|
||||||
|
if (component instanceof TextComponent) {
|
||||||
|
final TextComponent text = (TextComponent) component;
|
||||||
|
final String replaced = replacer.apply(text.content());
|
||||||
|
|
||||||
|
rebuilt = Component.text(replaced);
|
||||||
|
} else if (component instanceof TranslatableComponent) {
|
||||||
|
final TranslatableComponent translatable = (TranslatableComponent) component;
|
||||||
|
final List<Component> arguments = new ArrayList<>();
|
||||||
|
|
||||||
|
for (final ComponentLike arg : translatable.arguments()) {
|
||||||
|
arguments.add(rebuild(arg.asComponent(), replacer));
|
||||||
|
}
|
||||||
|
|
||||||
|
rebuilt = Component.translatable(translatable.key(), arguments);
|
||||||
|
} else if (component instanceof KeybindComponent) {
|
||||||
|
final KeybindComponent keybind = (KeybindComponent) component;
|
||||||
|
rebuilt = Component.keybind(keybind.keybind());
|
||||||
|
} else if (component instanceof ScoreComponent) {
|
||||||
|
final ScoreComponent score = (ScoreComponent) component;
|
||||||
|
rebuilt = Component.score(score.name(), score.objective());
|
||||||
|
} else if (component instanceof SelectorComponent) {
|
||||||
|
final SelectorComponent selector = (SelectorComponent) component;
|
||||||
|
rebuilt = Component.selector(selector.pattern());
|
||||||
|
} else {
|
||||||
|
rebuilt = Component.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
rebuilt = rebuilt.style(rebuildStyle(component.style(), replacer));
|
||||||
|
|
||||||
|
if (!component.children().isEmpty()) {
|
||||||
|
final List<Component> children = new ArrayList<>();
|
||||||
|
for (Component child : component.children()) {
|
||||||
|
children.add(rebuild(child, replacer));
|
||||||
|
}
|
||||||
|
rebuilt = rebuilt.children(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rebuilt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static Style rebuildStyle(@NotNull final Style style, @NotNull final Function<String, String> replacer) {
|
||||||
|
final Style.Builder builder = style.toBuilder();
|
||||||
|
final ClickEvent click = style.clickEvent();
|
||||||
|
|
||||||
|
if (click != null) {
|
||||||
|
builder.clickEvent(rebuildClickEvent(click, replacer));
|
||||||
|
}
|
||||||
|
|
||||||
|
final HoverEvent<?> hover = style.hoverEvent();
|
||||||
|
|
||||||
|
if (hover != null) {
|
||||||
|
builder.hoverEvent(rebuildHoverEvent(hover, replacer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static ClickEvent rebuildClickEvent(@NotNull final ClickEvent click, @NotNull final Function<String, String> replacer) {
|
||||||
|
final ClickEvent.Payload payload = click.payload();
|
||||||
|
|
||||||
|
if (!(payload instanceof ClickEvent.Payload.Text)) {
|
||||||
|
return click;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String original = ((ClickEvent.Payload.Text) payload).value();
|
||||||
|
final String replaced = replacer.apply(original);
|
||||||
|
|
||||||
|
final ClickEvent.Action action = click.action();
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case OPEN_URL:
|
||||||
|
return ClickEvent.openUrl(replaced);
|
||||||
|
case OPEN_FILE:
|
||||||
|
return ClickEvent.openFile(replaced);
|
||||||
|
case RUN_COMMAND:
|
||||||
|
return ClickEvent.runCommand(replaced);
|
||||||
|
case SUGGEST_COMMAND:
|
||||||
|
return ClickEvent.suggestCommand(replaced);
|
||||||
|
case COPY_TO_CLIPBOARD:
|
||||||
|
return ClickEvent.copyToClipboard(replaced);
|
||||||
|
default:
|
||||||
|
return click;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static HoverEvent<?> rebuildHoverEvent(@NotNull final HoverEvent<?> hover, @NotNull final Function<String, String> replacer) {
|
||||||
|
final Object value = hover.value();
|
||||||
|
|
||||||
|
if (value instanceof Component) {
|
||||||
|
final Component rebuilt = rebuild((Component) value, replacer);
|
||||||
|
return HoverEvent.showText(rebuilt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof HoverEvent.ShowItem) {
|
||||||
|
return rebuildShowItem((HoverEvent.ShowItem) value, replacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof HoverEvent.ShowEntity) {
|
||||||
|
final HoverEvent.ShowEntity entity = (HoverEvent.ShowEntity) value;
|
||||||
|
|
||||||
|
Component rebuiltName = null;
|
||||||
|
if (entity.name() != null) {
|
||||||
|
rebuiltName = rebuild(entity.name(), replacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return HoverEvent.showEntity(entity.type(), entity.id(), rebuiltName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static HoverEvent<?> rebuildShowItem(@NotNull final HoverEvent.ShowItem item, @NotNull final Function<String, String> replacer) {
|
||||||
|
final BinaryTagHolder nbt = item.nbt();
|
||||||
|
|
||||||
|
if (nbt != null && !nbt.string().isEmpty()) {
|
||||||
|
final String replaced = replacer.apply(nbt.string());
|
||||||
|
|
||||||
|
return HoverEvent.showItem(item.item(), item.count(), BinaryTagHolder.binaryTagHolder(replaced));
|
||||||
|
}
|
||||||
|
|
||||||
|
//I'm not 100% sure this is how we're meant to support data components but let's give it a go and see if it causes any issues :)
|
||||||
|
final Map<Key, DataComponentValue> components = item.dataComponents();
|
||||||
|
|
||||||
|
if (!components.isEmpty()) {
|
||||||
|
final Map<Key, DataComponentValue> rebuilt = new HashMap<>();
|
||||||
|
|
||||||
|
for (final Map.Entry<Key, DataComponentValue> entry : components.entrySet()) {
|
||||||
|
final DataComponentValue value = entry.getValue();
|
||||||
|
|
||||||
|
if (!(value instanceof BinaryTagHolder)) {
|
||||||
|
rebuilt.put(entry.getKey(), value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rebuilt.put(entry.getKey(), BinaryTagHolder.binaryTagHolder(replacer.apply(((BinaryTagHolder) value).string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return HoverEvent.showItem(item.item(), item.count(), rebuilt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return HoverEvent.showItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user