diff --git a/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/Config.java b/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/Config.java index e03caa87..93429946 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/Config.java +++ b/eco-api/src/main/java/com/willfp/eco/core/config/interfaces/Config.java @@ -2,6 +2,8 @@ package com.willfp.eco.core.config.interfaces; import com.willfp.eco.core.config.ConfigType; import com.willfp.eco.core.config.TransientConfig; +import com.willfp.eco.core.placeholder.PlaceholderInjectable; +import com.willfp.eco.core.placeholder.StaticPlaceholder; import com.willfp.eco.util.NumberUtils; import com.willfp.eco.util.StringUtils; import org.bukkit.entity.Player; @@ -9,6 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -18,7 +21,7 @@ import java.util.Objects; * Contains all methods that must exist in yaml and json configurations. */ @SuppressWarnings("unused") -public interface Config extends Cloneable { +public interface Config extends Cloneable, PlaceholderInjectable { /** * Clears cache. */ @@ -563,7 +566,7 @@ public interface Config extends Cloneable { */ default double getDoubleFromExpression(@NotNull String path, @Nullable Player player) { - return NumberUtils.evaluateExpression(this.getString(path), player); + return NumberUtils.evaluateExpression(this.getString(path), player, this.getInjectedPlaceholders()); } /** @@ -629,4 +632,14 @@ public interface Config extends Cloneable { * @return The clone. */ Config clone(); + + @Override + default void injectPlaceholders(@NotNull StaticPlaceholder... placeholders) { + // Do nothing. + } + + @Override + default List getInjectedPlaceholders() { + return Collections.emptyList(); + } } diff --git a/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderEntry.java b/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderEntry.java index c92f2098..a7f7c850 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderEntry.java +++ b/eco-api/src/main/java/com/willfp/eco/core/integrations/placeholder/PlaceholderEntry.java @@ -1,6 +1,10 @@ package com.willfp.eco.core.integrations.placeholder; +import com.willfp.eco.core.Eco; import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.placeholder.Placeholder; +import com.willfp.eco.core.placeholder.PlayerPlaceholder; +import com.willfp.eco.core.placeholder.PlayerlessPlaceholder; import org.apache.commons.lang.Validate; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -10,10 +14,13 @@ import java.util.Objects; import java.util.function.Function; /** - * A {@link PlaceholderEntry} is a placeholder in and of itself. + * A placeholder entry is a placeholder in and of itself. *

* It should be fairly straightforward. + * + * @deprecated Confusing functionality with inconsistent nullability and poor naming. */ +@Deprecated(since = "6.28.0", forRemoval = true) public class PlaceholderEntry { /** * The name of the placeholder, used in lookups. @@ -140,7 +147,28 @@ public class PlaceholderEntry { * Register the placeholder. */ public void register() { - PlaceholderManager.registerPlaceholder(this); + PlaceholderManager.registerPlaceholder(this.toModernPlaceholder()); + } + + /** + * Convert the placeholder to a modern placeholder. + * + * @return The placeholder. + */ + Placeholder toModernPlaceholder() { + if (this.requiresPlayer) { + return new PlayerPlaceholder( + Objects.requireNonNullElse(plugin, Eco.getHandler().getEcoPlugin()), + identifier, + function + ); + } else { + return new PlayerlessPlaceholder( + Objects.requireNonNullElse(plugin, Eco.getHandler().getEcoPlugin()), + identifier, + () -> function.apply(null) + ); + } } @Override 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 a590a7b5..cd3913fd 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,11 +4,16 @@ 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.Placeholder; +import com.willfp.eco.core.placeholder.PlayerPlaceholder; +import com.willfp.eco.core.placeholder.PlayerlessPlaceholder; +import com.willfp.eco.core.placeholder.StaticPlaceholder; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -19,11 +24,12 @@ import java.util.concurrent.TimeUnit; /** * Class to handle placeholder integrations. */ +@SuppressWarnings("removal") public final class PlaceholderManager { /** * All registered placeholders. */ - private static final Map> REGISTERED_PLACEHOLDERS = new HashMap<>(); + private static final Map> REGISTERED_PLACEHOLDERS = new HashMap<>(); /** * All registered placeholder integrations. @@ -35,7 +41,7 @@ public final class PlaceholderManager { */ private static final LoadingCache PLACEHOLDER_CACHE = Caffeine.newBuilder() .expireAfterWrite(50, TimeUnit.MILLISECONDS) - .build(key -> key.entry.getResult(key.player)); + .build(key -> key.entry.getValue(key.player)); /** * Register a new placeholder integration. @@ -50,16 +56,31 @@ public final class PlaceholderManager { /** * Register a placeholder. * - * @param expansion The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderEntry} to register. + * @param placeholder The placeholder to register. */ - public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) { - EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin(); - Map pluginPlaceholders = REGISTERED_PLACEHOLDERS + public static void registerPlaceholder(@NotNull final Placeholder placeholder) { + if (placeholder instanceof StaticPlaceholder) { + throw new IllegalArgumentException("Static placeholders cannot be registered!"); + } + + EcoPlugin plugin = placeholder.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : placeholder.getPlugin(); + Map pluginPlaceholders = REGISTERED_PLACEHOLDERS .getOrDefault(plugin, new HashMap<>()); - pluginPlaceholders.put(expansion.getIdentifier(), expansion); + pluginPlaceholders.put(placeholder.getIdentifier(), placeholder); REGISTERED_PLACEHOLDERS.put(plugin, pluginPlaceholders); } + /** + * Register a placeholder. + * + * @param placeholder The placeholder to register. + * @deprecated Uses old placeholder system. + */ + @Deprecated(since = "6.28.0", forRemoval = true) + public static void registerPlaceholder(@NotNull final PlaceholderEntry placeholder) { + registerPlaceholder(placeholder.toModernPlaceholder()); + } + /** * Get the result of a placeholder with respect to a player. * @@ -82,29 +103,36 @@ public final class PlaceholderManager { * @param plugin The plugin for the placeholder. * @return The value of the placeholder. */ + @NotNull public static String getResult(@Nullable final Player player, @NotNull final String identifier, @Nullable final EcoPlugin plugin) { EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin; - PlaceholderEntry entry = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase()); + Placeholder placeholder = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase()); - if (entry == null && plugin != null) { - PlaceholderEntry alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>()) + if (placeholder == null && plugin != null) { + Placeholder alternate = REGISTERED_PLACEHOLDERS.getOrDefault(Eco.getHandler().getEcoPlugin(), new HashMap<>()) .get(identifier.toLowerCase()); if (alternate != null) { - entry = alternate; + placeholder = alternate; } } - if (entry == null) { + if (placeholder == null) { return ""; } - if (player == null && entry.requiresPlayer()) { + if (placeholder instanceof PlayerPlaceholder playerPlaceholder) { + if (player == null) { + return ""; + } else { + return PLACEHOLDER_CACHE.get(new EntryWithPlayer(playerPlaceholder, player)); + } + } else if (placeholder instanceof PlayerlessPlaceholder playerlessPlaceholder) { + return playerlessPlaceholder.getValue(); + } else { return ""; } - - return PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player)); } /** @@ -116,10 +144,28 @@ public final class PlaceholderManager { */ public static String translatePlaceholders(@NotNull final String text, @Nullable final Player player) { + return translatePlaceholders(text, player, Collections.emptyList()); + } + + /** + * 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 statics Extra static placeholders. + * @return The text, translated. + */ + public static String translatePlaceholders(@NotNull final String text, + @Nullable final Player player, + @NotNull final List statics) { String processed = text; for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) { processed = integration.translate(processed, player); } + for (StaticPlaceholder placeholder : statics) { + // Do I know this is a bad way of doing this? Yes. + processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue()); + } return processed; } @@ -138,8 +184,8 @@ public final class PlaceholderManager { return found; } - private static record EntryWithPlayer(@NotNull PlaceholderEntry entry, - @Nullable Player player) { + private record EntryWithPlayer(@NotNull PlayerPlaceholder entry, + @NotNull Player player) { } diff --git a/eco-api/src/main/java/com/willfp/eco/core/placeholder/Placeholder.java b/eco-api/src/main/java/com/willfp/eco/core/placeholder/Placeholder.java new file mode 100644 index 00000000..66ff163b --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/placeholder/Placeholder.java @@ -0,0 +1,22 @@ +package com.willfp.eco.core.placeholder; + +import com.willfp.eco.core.EcoPlugin; + +/** + * A placeholder represents a string that can hold a value. + */ +public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceholder, StaticPlaceholder { + /** + * Get the plugin that holds the placeholder. + * + * @return The plugin. + */ + EcoPlugin getPlugin(); + + /** + * Get the identifier for the placeholder. + * + * @return The identifier. + */ + String getIdentifier(); +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlaceholderInjectable.java b/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlaceholderInjectable.java new file mode 100644 index 00000000..f26b6063 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlaceholderInjectable.java @@ -0,0 +1,24 @@ +package com.willfp.eco.core.placeholder; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Represents a class that can have placeholders injected into it. + */ +public interface PlaceholderInjectable { + /** + * Inject placeholder. + * + * @param placeholders The placeholders. + */ + void injectPlaceholders(@NotNull StaticPlaceholder... placeholders); + + /** + * Get injected placeholders. + * + * @return Injected placeholders. + */ + List getInjectedPlaceholders(); +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlayerPlaceholder.java b/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlayerPlaceholder.java new file mode 100644 index 00000000..252a3938 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlayerPlaceholder.java @@ -0,0 +1,73 @@ +package com.willfp.eco.core.placeholder; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; + +/** + * A placeholder that requires a player. + */ +public final class PlayerPlaceholder implements Placeholder { + /** + * The name of the placeholder. + */ + private final String identifier; + + /** + * The function to retrieve the output of the placeholder given a player. + */ + private final Function function; + + /** + * The plugin for the placeholder. + */ + private final EcoPlugin plugin; + + /** + * Create a new player placeholder. + * + * @param plugin The plugin. + * @param identifier The identifier. + * @param function The function to retrieve the value. + */ + public PlayerPlaceholder(@NotNull final EcoPlugin plugin, + @NotNull final String identifier, + @NotNull final Function function) { + this.plugin = plugin; + this.identifier = identifier; + this.function = function; + } + + /** + * Get the value of the placeholder for a given player. + * + * @param player The player. + * @return The value. + */ + public String getValue(@NotNull final Player player) { + return function.apply(player); + } + + /** + * Register the placeholder. + * + * @return The placeholder. + */ + public PlayerPlaceholder register() { + PlaceholderManager.registerPlaceholder(this); + return this; + } + + @Override + public EcoPlugin getPlugin() { + return this.plugin; + } + + @Override + public String getIdentifier() { + return this.identifier; + } +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlayerlessPlaceholder.java b/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlayerlessPlaceholder.java new file mode 100644 index 00000000..f5179a58 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/placeholder/PlayerlessPlaceholder.java @@ -0,0 +1,71 @@ +package com.willfp.eco.core.placeholder; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Supplier; + +/** + * A placeholder that does not require a player. + */ +public final class PlayerlessPlaceholder implements Placeholder { + /** + * The name of the placeholder. + */ + private final String identifier; + + /** + * The function to retrieve the output of the placeholder. + */ + private final Supplier function; + + /** + * The plugin for the placeholder. + */ + private final EcoPlugin plugin; + + /** + * Create a new player placeholder. + * + * @param plugin The plugin. + * @param identifier The identifier. + * @param function The function to retrieve the value. + */ + public PlayerlessPlaceholder(@NotNull final EcoPlugin plugin, + @NotNull final String identifier, + @NotNull final Supplier function) { + this.plugin = plugin; + this.identifier = identifier; + this.function = function; + } + + /** + * Get the value of the placeholder. + * + * @return The value. + */ + public String getValue() { + return function.get(); + } + + /** + * Register the placeholder. + * + * @return The placeholder. + */ + public PlayerlessPlaceholder register() { + PlaceholderManager.registerPlaceholder(this); + return this; + } + + @Override + public EcoPlugin getPlugin() { + return this.plugin; + } + + @Override + public String getIdentifier() { + return this.identifier; + } +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/placeholder/StaticPlaceholder.java b/eco-api/src/main/java/com/willfp/eco/core/placeholder/StaticPlaceholder.java new file mode 100644 index 00000000..65fce9c2 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/placeholder/StaticPlaceholder.java @@ -0,0 +1,53 @@ +package com.willfp.eco.core.placeholder; + +import com.willfp.eco.core.Eco; +import com.willfp.eco.core.EcoPlugin; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Supplier; + +/** + * A placeholder that cannot be registered, and exists purely in injection. + */ +public final class StaticPlaceholder implements Placeholder { + /** + * The name of the placeholder. + */ + private final String identifier; + + /** + * The function to retrieve the output of the placeholder. + */ + private final Supplier function; + + /** + * Create a new player placeholder. + * + * @param identifier The identifier. + * @param function The function to retrieve the value. + */ + public StaticPlaceholder(@NotNull final String identifier, + @NotNull final Supplier function) { + this.identifier = identifier; + this.function = function; + } + + /** + * Get the value of the placeholder. + * + * @return The value. + */ + public String getValue() { + return function.get(); + } + + @Override + public EcoPlugin getPlugin() { + return Eco.getHandler().getEcoPlugin(); + } + + @Override + public String getIdentifier() { + return this.identifier; + } +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/recipe/recipes/ShapelessCraftingRecipe.java b/eco-api/src/main/java/com/willfp/eco/core/recipe/recipes/ShapelessCraftingRecipe.java index 22450a22..73c4b57a 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/recipe/recipes/ShapelessCraftingRecipe.java +++ b/eco-api/src/main/java/com/willfp/eco/core/recipe/recipes/ShapelessCraftingRecipe.java @@ -1,5 +1,6 @@ package com.willfp.eco.core.recipe.recipes; +import com.google.common.annotations.Beta; import com.willfp.eco.core.Eco; import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.PluginDependent; @@ -24,6 +25,7 @@ import java.util.Optional; /** * Shapeless crafting recipe. */ +@Beta public final class ShapelessCraftingRecipe extends PluginDependent implements CraftingRecipe { /** * Recipe parts. 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 e3c260a7..5bd4814a 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.StaticPlaceholder; import org.apache.commons.lang.Validate; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; @@ -7,10 +8,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.text.DecimalFormat; +import java.util.Collections; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ThreadLocalRandom; -import java.util.function.BiFunction; /** * Utilities / API methods for numbers. @@ -24,7 +25,7 @@ public final class NumberUtils { /** * Crunch handler. */ - private static BiFunction crunch = null; + private static CrunchHandler crunch = null; /** * Set of roman numerals to look up. @@ -251,7 +252,21 @@ public final class NumberUtils { */ public static double evaluateExpression(@NotNull final String expression, @Nullable final Player player) { - return crunch.apply(expression, player); + return evaluateExpression(expression, player, Collections.emptyList()); + } + + /** + * Evaluate an expression with respect to a player (for placeholders). + * + * @param expression The expression. + * @param player The player. + * @param statics The static 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 Iterable statics) { + return crunch.evaluate(expression, player, statics); } /** @@ -260,11 +275,29 @@ public final class NumberUtils { * @param handler The handler. */ @ApiStatus.Internal - public static void initCrunch(@NotNull final BiFunction handler) { + public static void initCrunch(@NotNull final CrunchHandler handler) { Validate.isTrue(crunch == null, "Already initialized!"); crunch = handler; } + /** + * Bridge component for crunch. + */ + @ApiStatus.Internal + public interface CrunchHandler { + /** + * Evaluate an expression. + * + * @param expression The expression. + * @param player The player. + * @param statics The statics. + * @return The value of the expression, or zero if invalid. + */ + double evaluate(@NotNull String expression, + @Nullable Player player, + @NotNull Iterable statics); + } + private NumberUtils() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); } diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigSection.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigSection.kt index 3e4608e0..71c62498 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigSection.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigSection.kt @@ -1,8 +1,11 @@ package com.willfp.eco.internal.config.json +import com.willfp.eco.core.placeholder.StaticPlaceholder + @Suppress("UNCHECKED_CAST") -class EcoJSONConfigSection(values: Map) : EcoJSONConfigWrapper() { +class EcoJSONConfigSection(values: Map, injections: Collection = emptyList()) : EcoJSONConfigWrapper() { init { init(values) + this.injections = injections.toMutableList() } } \ No newline at end of file diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigWrapper.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigWrapper.kt index f7b571f5..0b38de36 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigWrapper.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/json/EcoJSONConfigWrapper.kt @@ -6,6 +6,7 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.willfp.eco.core.config.ConfigType import com.willfp.eco.core.config.interfaces.JSONConfig +import com.willfp.eco.core.placeholder.StaticPlaceholder import com.willfp.eco.util.StringUtils import java.util.Objects import java.util.concurrent.ConcurrentHashMap @@ -22,6 +23,7 @@ open class EcoJSONConfigWrapper : JSONConfig { val values = ConcurrentHashMap() private val cache = ConcurrentHashMap() + var injections = mutableListOf() fun init(values: Map) { this.values.clear() @@ -62,7 +64,7 @@ open class EcoJSONConfigWrapper : JSONConfig { } return if (values[closestPath] is Map<*, *> && path != closestPath) { val section = - EcoJSONConfigSection((values[closestPath] as Map?)!!) + EcoJSONConfigSection((values[closestPath] as Map?)!!, injections) section.getOfKnownType(path.substring(closestPath.length + 1), clazz, false) } else { if (values.containsKey(closestPath)) { @@ -88,7 +90,7 @@ open class EcoJSONConfigWrapper : JSONConfig { for (key in values.keys) { list.add(root + key) if (values[key] is Map<*, *>) { - val section = EcoJSONConfigSection((values[key] as Map?)!!) + val section = EcoJSONConfigSection((values[key] as Map?)!!, injections) list.addAll(section.getDeepKeys(list, "$root$key.")) } } @@ -117,7 +119,7 @@ open class EcoJSONConfigWrapper : JSONConfig { closestPath = split[0] } if (values[closestPath] is Map<*, *> && path != closestPath) { - val section = EcoJSONConfigSection((values[closestPath] as Map?)!!) + val section = EcoJSONConfigSection((values[closestPath] as Map?)!!, injections) section.setRecursively(path.substring(closestPath.length + 1), obj) values[closestPath] = section.values } else { @@ -130,13 +132,13 @@ open class EcoJSONConfigWrapper : JSONConfig { } override fun getSubsection(path: String): JSONConfig { - return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf()) + return getSubsectionOrNull(path) ?: EcoJSONConfigSection(mutableMapOf(), injections) } override fun getSubsectionOrNull(path: String): JSONConfig? { return if (values.containsKey(path)) { val subsection = values[path] as Map - EcoJSONConfigSection(subsection) + EcoJSONConfigSection(subsection, injections) } else { null } @@ -147,7 +149,7 @@ open class EcoJSONConfigWrapper : JSONConfig { ?: return null val configs = mutableListOf() for (map in maps) { - configs.add(EcoJSONConfigSection(map)) + configs.add(EcoJSONConfigSection(map, injections)) } return configs.toMutableList() } @@ -206,11 +208,19 @@ open class EcoJSONConfigWrapper : JSONConfig { return (getOfKnownType(path, Any::class.java) as Collection?)?.toMutableList() } + override fun injectPlaceholders(vararg placeholders: StaticPlaceholder) { + injections.addAll(placeholders) + } + + override fun getInjectedPlaceholders(): List { + return injections.toList() + } + override fun getType(): ConfigType { return ConfigType.JSON } override fun clone(): JSONConfig { - return EcoJSONConfigSection(this.values.toMutableMap()) + return EcoJSONConfigSection(this.values.toMutableMap(), injections) } } \ No newline at end of file diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigSection.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigSection.kt index 8ceea7d9..3efeec7e 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigSection.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigSection.kt @@ -1,9 +1,11 @@ package com.willfp.eco.internal.config.yaml +import com.willfp.eco.core.placeholder.StaticPlaceholder import org.bukkit.configuration.ConfigurationSection -class EcoYamlConfigSection(section: ConfigurationSection) : EcoYamlConfigWrapper() { +class EcoYamlConfigSection(section: ConfigurationSection, injections: Collection = emptyList()) : EcoYamlConfigWrapper() { init { init(section) + this.injections = injections.toMutableList() } } \ No newline at end of file diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigWrapper.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigWrapper.kt index efd610f7..b2c60fff 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigWrapper.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/config/yaml/EcoYamlConfigWrapper.kt @@ -2,6 +2,7 @@ package com.willfp.eco.internal.config.yaml import com.willfp.eco.core.config.ConfigType import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.placeholder.StaticPlaceholder import com.willfp.eco.util.StringUtils import org.bukkit.configuration.ConfigurationSection import org.bukkit.configuration.file.YamlConfiguration @@ -11,6 +12,7 @@ import java.io.StringReader open class EcoYamlConfigWrapper : Config { lateinit var handle: T private val cache = mutableMapOf() + var injections = mutableListOf() protected fun init(config: T): Config { handle = config @@ -57,7 +59,7 @@ open class EcoYamlConfigWrapper : Config { if (raw == null) { cache[path] = null } else { - cache[path] = EcoYamlConfigSection(raw) + cache[path] = EcoYamlConfigSection(raw, injections) } getSubsectionOrNull(path) } @@ -214,7 +216,7 @@ open class EcoYamlConfigWrapper : Config { for (map in mapList) { val temp = YamlConfiguration.loadConfiguration(StringReader("")) temp.createSection("a", map) - configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!)) + configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!, injections)) } cache[path] = if (has(path)) configList else emptyList() @@ -225,6 +227,14 @@ open class EcoYamlConfigWrapper : Config { } } + override fun injectPlaceholders(vararg placeholders: StaticPlaceholder) { + injections.addAll(placeholders) + } + + override fun getInjectedPlaceholders(): List { + return injections.toList() + } + override fun getType(): ConfigType { return ConfigType.JSON } @@ -235,7 +245,8 @@ open class EcoYamlConfigWrapper : Config { StringReader( toPlaintext() ) - ) + ), + injections ) } } \ No newline at end of file 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 4a79684d..fee12b24 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 @@ -176,7 +176,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() { val tpsProxy = getProxy(TPSProxy::class.java) ServerUtils.initialize { tpsProxy.getTPS() } - NumberUtils.initCrunch { exp, player -> evaluateExpression(exp, player) } + NumberUtils.initCrunch { expression, player, statics -> evaluateExpression(expression, player, statics) } postInit() } 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 d7fc0b45..2ff3fbdd 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.StaticPlaceholder import org.bukkit.entity.Player import redempt.crunch.CompiledExpression import redempt.crunch.Crunch @@ -12,14 +13,16 @@ import redempt.crunch.functional.EvaluationEnvironment private val cache: Cache = Caffeine.newBuilder().build() private val goToZero = Crunch.compileExpression("0") -fun evaluateExpression(expression: String, player: Player?): Double { +fun evaluateExpression(expression: String, player: Player?, statics: Iterable): Double { val placeholderValues = PlaceholderManager.findPlaceholdersIn(expression) .map { PlaceholderManager.translatePlaceholders(it, player) } + .union(statics.map { it.value }) + .toList() .map { runCatching { FastNumberParsing.parseDouble(it) }.getOrDefault(0.0) } .toDoubleArray() val compiled = cache.get(expression) { - val placeholders = PlaceholderManager.findPlaceholdersIn(it) + val placeholders = PlaceholderManager.findPlaceholdersIn(it) union statics.map { static -> "%${static.identifier}%" } val env = EvaluationEnvironment() env.setVariableNames(*placeholders.toTypedArray()) runCatching { Crunch.compileExpression(expression, env) }.getOrDefault(goToZero)