diff --git a/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java b/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java index 57e2f49c..a3dd6786 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java +++ b/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderManager.java @@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import com.willfp.eco.core.Eco; import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.placeholder.AdditionalPlayer; import com.willfp.eco.core.placeholder.InjectablePlaceholder; import com.willfp.eco.core.placeholder.Placeholder; import com.willfp.eco.core.placeholder.PlaceholderInjectable; @@ -11,11 +12,13 @@ import com.willfp.eco.core.placeholder.PlayerPlaceholder; import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder; import com.willfp.eco.core.placeholder.PlayerlessPlaceholder; import com.willfp.eco.core.placeholder.StaticPlaceholder; +import com.willfp.eco.util.StringUtils; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -23,6 +26,8 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Class to handle placeholder integrations. @@ -56,11 +61,17 @@ public final class PlaceholderManager { } @Override - public @NotNull List getPlaceholderInjections() { + public @NotNull + List getPlaceholderInjections() { return Collections.emptyList(); } }; + /** + * The default PlaceholderAPI pattern; brought in for compatibility. + */ + private static final Pattern PATTERN = Pattern.compile("[%]([^%]+)[%]"); + /** * Register a new placeholder integration. * @@ -192,7 +203,45 @@ public final class PlaceholderManager { public static String translatePlaceholders(@NotNull final String text, @Nullable final Player player, @NotNull final PlaceholderInjectable context) { + return translatePlaceholders(text, player, context, new ArrayList<>()); + } + + /** + * Translate all placeholders with respect to a player. + * + * @param text The text that may contain placeholders to translate. + * @param player The player to translate the placeholders with respect to. + * @param context The injectable context. + * @param additionalPlayers Additional players to translate placeholders for. + * @return The text, translated. + */ + public static String translatePlaceholders(@NotNull final String text, + @Nullable final Player player, + @NotNull final PlaceholderInjectable context, + @NotNull final Collection additionalPlayers) { String processed = text; + + // Prevent running 2 scans if there are no additional players. + if (!additionalPlayers.isEmpty()) { + List found = findPlaceholdersIn(text); + + for (AdditionalPlayer additionalPlayer : additionalPlayers) { + for (String placeholder : found) { + String prefix = "%" + additionalPlayer.getIdentifier() + "_"; + + if (placeholder.startsWith(prefix)) { + processed = processed.replace( + placeholder, + translatePlaceholders( + "%" + StringUtils.removePrefix(prefix, placeholder), + additionalPlayer.getPlayer() + ) + ); + } + } + } + } + for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) { processed = integration.translate(processed, player); } @@ -214,12 +263,21 @@ public final class PlaceholderManager { * @return The placeholders. */ public static List findPlaceholdersIn(@NotNull final String text) { - List found = new ArrayList<>(); + Set found = new HashSet<>(); + + // Mock PAPI for those without it installed + if (REGISTERED_INTEGRATIONS.isEmpty()) { + Matcher matcher = PATTERN.matcher(text); + while (matcher.find()) { + found.add(matcher.group()); + } + } + for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) { found.addAll(integration.findPlaceholdersIn(text)); } - return found; + return new ArrayList<>(found); } private record EntryWithPlayer(@NotNull PlayerPlaceholder entry, diff --git a/eco-api/src/main/java/com/willfp/eco/core/placeholder/AdditionalPlayer.java b/eco-api/src/main/java/com/willfp/eco/core/placeholder/AdditionalPlayer.java new file mode 100644 index 00000000..ecd76b55 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/placeholder/AdditionalPlayer.java @@ -0,0 +1,49 @@ +package com.willfp.eco.core.placeholder; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +/** + * An additional player with an identifier to parse placeholders for the player. + */ +public class AdditionalPlayer { + /** + * The player. + */ + private final Player player; + + /** + * The identifier. + */ + private final String identifier; + + /** + * Create a new additional player. + * + * @param player The player. + * @param identifier The identifier. + */ + public AdditionalPlayer(@NotNull final Player player, + @NotNull final String identifier) { + this.player = player; + this.identifier = identifier; + } + + /** + * Get the player. + * + * @return The player. + */ + public Player getPlayer() { + return player; + } + + /** + * Get the identifier. + * + * @return The identifier. + */ + public String getIdentifier() { + return identifier; + } +} diff --git a/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java b/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java index b6f6b80e..1ff026b2 100644 --- a/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java +++ b/eco-api/src/main/java/com/willfp/eco/util/NumberUtils.java @@ -1,5 +1,6 @@ package com.willfp.eco.util; +import com.willfp.eco.core.placeholder.AdditionalPlayer; import com.willfp.eco.core.placeholder.InjectablePlaceholder; import com.willfp.eco.core.placeholder.PlaceholderInjectable; import com.willfp.eco.core.placeholder.StaticPlaceholder; @@ -11,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -263,7 +265,8 @@ public final class NumberUtils { } @Override - public @NotNull List getPlaceholderInjections() { + public @NotNull + List getPlaceholderInjections() { return Collections.emptyList(); } }); @@ -282,7 +285,7 @@ public final class NumberUtils { public static double evaluateExpression(@NotNull final String expression, @Nullable final Player player, @NotNull final Iterable statics) { - return crunch.evaluate(expression, player, new PlaceholderInjectable() { + return evaluateExpression(expression, player, new PlaceholderInjectable() { @Override public void clearInjectedPlaceholders() { // Do nothing. @@ -304,13 +307,29 @@ public final class NumberUtils { * * @param expression The expression. * @param player The player. - * @param context The injectable placeholders. + * @param context The injectable placeholders. * @return The value of the expression, or zero if invalid. */ public static double evaluateExpression(@NotNull final String expression, @Nullable final Player player, @NotNull final PlaceholderInjectable context) { - return crunch.evaluate(expression, player, context); + return evaluateExpression(expression, player, context, new ArrayList<>()); + } + + /** + * Evaluate an expression with respect to a player (for placeholders). + * + * @param expression The expression. + * @param player The player. + * @param context The injectable placeholders. + * @param additionalPlayers Additional players to parse placeholders for. + * @return The value of the expression, or zero if invalid. + */ + public static double evaluateExpression(@NotNull final String expression, + @Nullable final Player player, + @NotNull final PlaceholderInjectable context, + @NotNull final Collection additionalPlayers) { + return crunch.evaluate(expression, player, context, additionalPlayers); } /** @@ -332,14 +351,16 @@ public final class NumberUtils { /** * Evaluate an expression. * - * @param expression The expression. - * @param player The player. - * @param injectable The injectable placeholders. + * @param expression The expression. + * @param player The player. + * @param injectable The injectable placeholders. + * @param additionalPlayers The additional players. * @return The value of the expression, or zero if invalid. */ double evaluate(@NotNull String expression, @Nullable Player player, - @NotNull PlaceholderInjectable injectable); + @NotNull PlaceholderInjectable injectable, + @NotNull Collection additionalPlayers); } private NumberUtils() { diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt index 06f5b16d..a3c670a9 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt @@ -84,6 +84,7 @@ import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogX import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat +import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFabledSkyBlock import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock @@ -93,7 +94,6 @@ import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefRPGHorses import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard -import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFabledSkyBlock import com.willfp.eco.internal.spigot.integrations.customentities.CustomEntitiesMythicMobs import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsCustomCrafting import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsExecutableItems @@ -184,7 +184,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() { val tpsProxy = getProxy(TPSProxy::class.java) ServerUtils.initialize { tpsProxy.getTPS() } - NumberUtils.initCrunch { expression, player, context -> evaluateExpression(expression, player, context) } + NumberUtils.initCrunch(::evaluateExpression) MenuUtils.initialize { it.openInventory.topInventory.getMenu() } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/math/CrunchHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/math/CrunchHandler.kt index 31514a14..fd4b5695 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/math/CrunchHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/math/CrunchHandler.kt @@ -3,6 +3,7 @@ package com.willfp.eco.internal.spigot.math import com.github.benmanes.caffeine.cache.Cache import com.github.benmanes.caffeine.cache.Caffeine import com.willfp.eco.core.integrations.placeholder.PlaceholderManager +import com.willfp.eco.core.placeholder.AdditionalPlayer import com.willfp.eco.core.placeholder.PlaceholderInjectable import org.bukkit.entity.Player import redempt.crunch.CompiledExpression @@ -13,9 +14,9 @@ import redempt.crunch.functional.EvaluationEnvironment private val cache: Cache = Caffeine.newBuilder().build() private val goToZero = Crunch.compileExpression("0") -fun evaluateExpression(expression: String, player: Player?, context: PlaceholderInjectable): Double { +fun evaluateExpression(expression: String, player: Player?, context: PlaceholderInjectable, additional: Collection): Double { val placeholderValues = PlaceholderManager.findPlaceholdersIn(expression) - .map { PlaceholderManager.translatePlaceholders(it, player, context) } + .map { PlaceholderManager.translatePlaceholders(it, player, context, additional) } .map { runCatching { FastNumberParsing.parseDouble(it) }.getOrDefault(0.0) } .toDoubleArray()