Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8515ff2b7b | ||
|
|
74aeaec257 | ||
|
|
0ce3d294d1 | ||
|
|
7c7052f5b9 | ||
|
|
a6b7dda82d |
@@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user