Compare commits

..

5 Commits

Author SHA1 Message Date
Auxilor
8515ff2b7b Updated to 6.63.0 2023-06-03 15:13:51 +01:00
Auxilor
74aeaec257 Added NumberUtils.evaluateExpressionOrNull 2023-06-03 15:13:42 +01:00
Auxilor
0ce3d294d1 Updated to 6.62.2 2023-06-03 14:23:33 +01:00
Auxilor
7c7052f5b9 Placeholders with identical patterns will now override previous registrations 2023-06-03 14:23:15 +01:00
Auxilor
a6b7dda82d Added check to prevent !!float in configs 2023-06-03 14:20:59 +01:00
9 changed files with 56 additions and 29 deletions

View File

@@ -527,9 +527,10 @@ public interface Eco {
* *
* @param expression The expression. * @param expression The expression.
* @param context The context. * @param context The context.
* @return The value of the expression, or zero if invalid. * @return The value of the expression, or null if invalid.
*/ */
double evaluate(@NotNull String expression, @Nullable
Double evaluate(@NotNull String expression,
@NotNull PlaceholderContext context); @NotNull PlaceholderContext context);
/** /**

View File

@@ -98,6 +98,7 @@ public final class PlaceholderManager {
// Storing as immutable set leads to slower times to register placeholders, but much // Storing as immutable set leads to slower times to register placeholders, but much
// faster times to access registrations. // faster times to access registrations.
Set<Placeholder> pluginPlaceholders = new HashSet<>(REGISTERED_PLACEHOLDERS.get(placeholder.getPlugin())); Set<Placeholder> pluginPlaceholders = new HashSet<>(REGISTERED_PLACEHOLDERS.get(placeholder.getPlugin()));
pluginPlaceholders.removeIf(p -> p.getPattern().equals(placeholder.getPattern()));
pluginPlaceholders.add(placeholder); pluginPlaceholders.add(placeholder);
REGISTERED_PLACEHOLDERS.put(placeholder.getPlugin(), ImmutableSet.copyOf(pluginPlaceholders)); REGISTERED_PLACEHOLDERS.put(placeholder.getPlugin(), ImmutableSet.copyOf(pluginPlaceholders));
} }

View File

@@ -12,6 +12,7 @@ import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -251,12 +252,15 @@ public final class NumberUtils {
@Nullable final Player player, @Nullable final Player player,
@Nullable final PlaceholderInjectable context, @Nullable final PlaceholderInjectable context,
@NotNull final Collection<AdditionalPlayer> additionalPlayers) { @NotNull final Collection<AdditionalPlayer> additionalPlayers) {
return Eco.get().evaluate(expression, new PlaceholderContext( return evaluateExpression(
player, expression,
null, new PlaceholderContext(
context, player,
additionalPlayers null,
)); context,
additionalPlayers
)
);
} }
/** /**
@@ -283,6 +287,22 @@ public final class NumberUtils {
*/ */
public static double evaluateExpression(@NotNull final String expression, public static double evaluateExpression(@NotNull final String expression,
@NotNull final PlaceholderContext context) { @NotNull final PlaceholderContext context) {
return Objects.requireNonNullElse(
evaluateExpressionOrNull(expression, context),
0.0
);
}
/**
* Evaluate an expression in a context.
*
* @param expression The expression.
* @param context The context.
* @return The value of the expression, or zero if invalid.
*/
@Nullable
public static Double evaluateExpressionOrNull(@NotNull final String expression,
@NotNull final PlaceholderContext context) {
return Eco.get().evaluate(expression, context); return Eco.get().evaluate(expression, context);
} }

View File

@@ -31,3 +31,7 @@ fun evaluateExpression(expression: String) =
/** @see NumberUtils.evaluateExpression */ /** @see NumberUtils.evaluateExpression */
fun evaluateExpression(expression: String, context: PlaceholderContext) = fun evaluateExpression(expression: String, context: PlaceholderContext) =
NumberUtils.evaluateExpression(expression, context) NumberUtils.evaluateExpression(expression, context)
/** @see NumberUtils.evaluateExpressionOrNull */
fun evaluateExpressionOrNull(expression: String, context: PlaceholderContext) =
NumberUtils.evaluateExpressionOrNull(expression, context)

View File

@@ -30,6 +30,8 @@ internal fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
this.toMutableList() this.toMutableList()
} }
} }
is Float -> this.toDouble() // Should prevent !!float from being written
else -> this else -> this
} }

View File

@@ -7,7 +7,6 @@ import com.willfp.eco.core.placeholder.InjectablePlaceholder
import com.willfp.eco.core.placeholder.Placeholder import com.willfp.eco.core.placeholder.Placeholder
import com.willfp.eco.core.placeholder.context.PlaceholderContext import com.willfp.eco.core.placeholder.context.PlaceholderContext
import com.willfp.eco.util.StringUtils import com.willfp.eco.util.StringUtils
import java.util.Optional
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/* /*
@@ -23,7 +22,7 @@ class PlaceholderParser {
private val placeholderLookupCache = Caffeine.newBuilder() private val placeholderLookupCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.SECONDS) .expireAfterWrite(1, TimeUnit.SECONDS)
.build<PlaceholderLookup, Optional<Placeholder>>() .build<PlaceholderLookup, Placeholder?>()
fun translatePlacholders(text: String, context: PlaceholderContext): String { fun translatePlacholders(text: String, context: PlaceholderContext): String {
return translatePlacholders(text, context, context.injectableContext.placeholderInjections) return translatePlacholders(text, context, context.injectableContext.placeholderInjections)
@@ -122,10 +121,10 @@ class PlaceholderParser {
val lookup = PlaceholderLookup(args, plugin, injections) val lookup = PlaceholderLookup(args, plugin, injections)
val placeholder = placeholderLookupCache.get(lookup) { val placeholder = placeholderLookupCache.get(lookup) {
Optional.ofNullable(it.findMatchingPlaceholder()) it.findMatchingPlaceholder()
}.orElse(null) ?: return null }
return placeholder.getValue(args, context) return placeholder?.getValue(args, context)
} }
private fun translateEcoPlaceholdersIn( private fun translateEcoPlaceholdersIn(

View File

@@ -10,11 +10,11 @@ class DelegatedExpressionHandler(
plugin: EcoPlugin, plugin: EcoPlugin,
private val handler: ExpressionHandler private val handler: ExpressionHandler
) : ExpressionHandler { ) : ExpressionHandler {
private val evaluationCache: Cache<Int, Double> = Caffeine.newBuilder() private val evaluationCache: Cache<Int, Double?> = Caffeine.newBuilder()
.expireAfterWrite(plugin.configYml.getInt("math-cache-ttl").toLong(), TimeUnit.MILLISECONDS) .expireAfterWrite(plugin.configYml.getInt("math-cache-ttl").toLong(), TimeUnit.MILLISECONDS)
.build() .build()
override fun evaluate(expression: String, context: PlaceholderContext): Double { override fun evaluate(expression: String, context: PlaceholderContext): Double? {
// Peak performance (totally not having fun with bitwise operators) // Peak performance (totally not having fun with bitwise operators)
val hash = (((expression.hashCode() shl 5) - expression.hashCode()) xor val hash = (((expression.hashCode() shl 5) - expression.hashCode()) xor
(context.player?.uniqueId?.hashCode() ?: 0) (context.player?.uniqueId?.hashCode() ?: 0)
@@ -22,7 +22,7 @@ class DelegatedExpressionHandler(
return evaluationCache.get(hash) { return evaluationCache.get(hash) {
handler.evaluate(expression, context) handler.evaluate(expression, context)
.let { if (!it.isFinite()) 0.0 else it } // Fixes NaN bug. .let { if (it?.isFinite() != true) null else it } // Fixes NaN bug.
} }
} }
} }

View File

@@ -14,8 +14,6 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.math.pow import kotlin.math.pow
private val goToZero = Crunch.compileExpression("0")
private val min = Function("min", 2) { private val min = Function("min", 2) {
min(it[0], it[1]) min(it[0], it[1])
} }
@@ -25,8 +23,9 @@ private val max = Function("max", 2) {
} }
interface ExpressionHandler { interface ExpressionHandler {
fun evaluate(expression: String, context: PlaceholderContext): Double fun evaluate(expression: String, context: PlaceholderContext): Double?
} }
private fun String.fastToDoubleOrNull(): Double? { private fun String.fastToDoubleOrNull(): Double? {
if (isEmpty()) { if (isEmpty()) {
return null return null
@@ -47,6 +46,7 @@ private fun String.fastToDoubleOrNull(): Double? {
if (decimalIdx != -1) return null if (decimalIdx != -1) return null
decimalIdx = idx decimalIdx = idx
} }
in '0'..'9' -> { in '0'..'9' -> {
val number = (char.code - '0'.code).toDouble() val number = (char.code - '0'.code).toDouble()
if (decimalIdx != -1) { if (decimalIdx != -1) {
@@ -55,6 +55,7 @@ private fun String.fastToDoubleOrNull(): Double? {
integerPart = integerPart * 10 + number integerPart = integerPart * 10 + number
} }
} }
else -> return null else -> return null
} }
@@ -70,7 +71,7 @@ private fun String.fastToDoubleOrNull(): Double? {
class ImmediatePlaceholderTranslationExpressionHandler( class ImmediatePlaceholderTranslationExpressionHandler(
private val placeholderParser: PlaceholderParser private val placeholderParser: PlaceholderParser
) : ExpressionHandler { ) : ExpressionHandler {
private val cache: Cache<String, CompiledExpression> = Caffeine.newBuilder() private val cache: Cache<String, CompiledExpression?> = Caffeine.newBuilder()
.expireAfterAccess(500, TimeUnit.MILLISECONDS) .expireAfterAccess(500, TimeUnit.MILLISECONDS)
.build() .build()
@@ -78,25 +79,24 @@ class ImmediatePlaceholderTranslationExpressionHandler(
addFunctions(min, max) addFunctions(min, max)
} }
override fun evaluate(expression: String, context: PlaceholderContext): Double { override fun evaluate(expression: String, context: PlaceholderContext): Double? {
val translatedExpression = placeholderParser.translatePlacholders(expression, context) val translatedExpression = placeholderParser.translatePlacholders(expression, context)
val compiled = cache.get(translatedExpression) { val compiled = cache.get(translatedExpression) {
runCatching { Crunch.compileExpression(translatedExpression, env) } runCatching { Crunch.compileExpression(translatedExpression, env) }.getOrNull()
.getOrDefault(goToZero)
} }
return runCatching { compiled.evaluate() }.getOrDefault(0.0) return runCatching { compiled?.evaluate() }.getOrNull()
} }
} }
class LazyPlaceholderTranslationExpressionHandler( class LazyPlaceholderTranslationExpressionHandler(
private val placeholderParser: PlaceholderParser private val placeholderParser: PlaceholderParser
) : ExpressionHandler { ) : ExpressionHandler {
private val cache: Cache<String, CompiledExpression> = Caffeine.newBuilder() private val cache: Cache<String, CompiledExpression?> = Caffeine.newBuilder()
.build() .build()
override fun evaluate(expression: String, context: PlaceholderContext): Double { override fun evaluate(expression: String, context: PlaceholderContext): Double? {
val placeholders = PlaceholderManager.findPlaceholdersIn(expression) val placeholders = PlaceholderManager.findPlaceholdersIn(expression)
val placeholderValues = placeholderParser.parseIndividualPlaceholders(placeholders, context) val placeholderValues = placeholderParser.parseIndividualPlaceholders(placeholders, context)
@@ -107,9 +107,9 @@ class LazyPlaceholderTranslationExpressionHandler(
val env = EvaluationEnvironment() val env = EvaluationEnvironment()
env.setVariableNames(*placeholders.toTypedArray()) env.setVariableNames(*placeholders.toTypedArray())
env.addFunctions(min, max) env.addFunctions(min, max)
runCatching { Crunch.compileExpression(expression, env) }.getOrDefault(goToZero) runCatching { Crunch.compileExpression(expression, env) }.getOrNull()
} }
return runCatching { compiled.evaluate(*placeholderValues) }.getOrDefault(0.0) return runCatching { compiled?.evaluate(*placeholderValues) }.getOrNull()
} }
} }

View File

@@ -1,3 +1,3 @@
version = 6.62.1 version = 6.63.0
plugin-name = eco plugin-name = eco
kotlin.code.style = official kotlin.code.style = official