Use WE Expressions instead of js evaluation (#2941)

* Implement thread-safe expression evaluation

* Update `{args}` to `plot` automatically

* Stringify more money/balance/price occurrences with EconHandler#format
This commit is contained in:
Hannes Greule 2021-01-02 17:32:07 +01:00 committed by GitHub
parent f47561b580
commit ad99ca1723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 157 additions and 152 deletions

View File

@ -36,6 +36,7 @@ import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
@Singleton public class BukkitEconHandler extends EconHandler { @Singleton public class BukkitEconHandler extends EconHandler {
@ -84,6 +85,11 @@ import org.bukkit.plugin.RegisteredServiceProvider;
return plotArea.useEconomy(); return plotArea.useEconomy();
} }
@Override
public @NonNull String format(double balance) {
return this.econ.format(balance);
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
return true; return true;

View File

@ -46,8 +46,8 @@ import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.services.plots.AutoService; import com.plotsquared.core.services.plots.AutoService;
import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.PlotExpression;
import com.plotsquared.core.util.task.AutoClaimFinishTask; import com.plotsquared.core.util.task.AutoClaimFinishTask;
import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
@ -276,24 +276,24 @@ public class Auto extends SubCommand {
} }
} }
if (this.econHandler != null && plotarea.useEconomy()) { if (this.econHandler != null && plotarea.useEconomy()) {
Expression<Double> costExp = plotarea.getPrices().get("claim"); PlotExpression costExp = plotarea.getPrices().get("claim");
double cost = costExp.evaluate((double) (Settings.Limit.GLOBAL ? double cost = costExp.evaluate(Settings.Limit.GLOBAL ?
player.getPlotCount() : player.getPlotCount() :
player.getPlotCount(plotarea.getWorldName()))); player.getPlotCount(plotarea.getWorldName()));
cost = (size_x * size_z) * cost; cost = (size_x * size_z) * cost;
if (cost > 0d) { if (cost > 0d) {
if (!force && this.econHandler.getMoney(player) < cost) { if (!force && this.econHandler.getMoney(player) < cost) {
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.cannot_afford_plot"), TranslatableCaption.of("economy.cannot_afford_plot"),
Template.of("money", String.valueOf(cost)), Template.of("money", this.econHandler.format(cost)),
Template.of("balance", String.valueOf(this.econHandler.getMoney(player))) Template.of("balance", this.econHandler.format(this.econHandler.getMoney(player)))
); );
return true; return true;
} }
this.econHandler.withdrawMoney(player, cost); this.econHandler.withdrawMoney(player, cost);
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.removed_balance"), TranslatableCaption.of("economy.removed_balance"),
Template.of("money", String.valueOf(cost)) Template.of("money", this.econHandler.format(cost))
); );
} }
} }

View File

@ -92,15 +92,15 @@ public class Buy extends Command {
} }
checkTrue(this.econHandler.getMoney(player) >= price, checkTrue(this.econHandler.getMoney(player) >= price,
TranslatableCaption.of("economy.cannot_afford_plot"), TranslatableCaption.of("economy.cannot_afford_plot"),
Template.of("money", String.valueOf(price)), Template.of("money", this.econHandler.format(price)),
Template.of("balance", String.valueOf(this.econHandler.getMoney(player)))); Template.of("balance", this.econHandler.format(this.econHandler.getMoney(player))));
this.econHandler.withdrawMoney(player, price); this.econHandler.withdrawMoney(player, price);
// Failure // Failure
// Success // Success
confirm.run(this, () -> { confirm.run(this, () -> {
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.removed_balance"), TranslatableCaption.of("economy.removed_balance"),
Template.of("money", String.valueOf(price)) Template.of("money", this.econHandler.format(price))
); );
this.econHandler.depositMoney(PlotSquared.platform().playerManager().getOfflinePlayer(plot.getOwnerAbs()), price); this.econHandler.depositMoney(PlotSquared.platform().playerManager().getOfflinePlayer(plot.getOwnerAbs()), price);
@ -111,7 +111,7 @@ public class Buy extends Command {
TranslatableCaption.of("economy.plot_sold"), TranslatableCaption.of("economy.plot_sold"),
Template.of("plot", plot.getId().toString()), Template.of("plot", plot.getId().toString()),
Template.of("player", player.getName()), Template.of("player", player.getName()),
Template.of("price", String.valueOf(price)) Template.of("price", this.econHandler.format(price))
); );
} }
PlotFlag<?, ?> plotFlag = plot.getFlagContainer().getFlag(PriceFlag.class); PlotFlag<?, ?> plotFlag = plot.getFlagContainer().getFlag(PriceFlag.class);

View File

@ -42,8 +42,8 @@ import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.PlotExpression;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import net.kyori.adventure.text.minimessage.Template; import net.kyori.adventure.text.minimessage.Template;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -136,20 +136,22 @@ public class Claim extends SubCommand {
} }
} }
if (this.econHandler.isEnabled(area) && !force) { if (this.econHandler.isEnabled(area) && !force) {
Expression<Double> costExr = area.getPrices().get("claim"); PlotExpression costExr = area.getPrices().get("claim");
double cost = costExr.evaluate((double) currentPlots); double cost = costExr.evaluate(currentPlots);
if (cost > 0d) { if (cost > 0d) {
if (this.econHandler.getMoney(player) < cost) { if (this.econHandler.getMoney(player) < cost) {
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.cannot_afford_plot"), TranslatableCaption.of("economy.cannot_afford_plot"),
Template.of("money", String.valueOf(cost)) Template.of("money", this.econHandler.format(cost)),
Template.of("balance", this.econHandler.format(this.econHandler.getMoney(player)))
); );
return false;
} }
this.econHandler.withdrawMoney(player, cost); this.econHandler.withdrawMoney(player, cost);
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.removed_balance"), TranslatableCaption.of("economy.removed_balance"),
Template.of("money", String.valueOf(cost)), Template.of("money", this.econHandler.format(cost)),
Template.of("balance", String.valueOf(this.econHandler.getMoney(player))) Template.of("balance", this.econHandler.format(this.econHandler.getMoney(player)))
); );
} }
} }

View File

@ -26,24 +26,23 @@
package com.plotsquared.core.command; package com.plotsquared.core.command;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.events.Result; import com.plotsquared.core.events.Result;
import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.location.Location; import com.plotsquared.core.location.Location;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.PlotExpression;
import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskManager;
import net.kyori.adventure.text.minimessage.Template; import net.kyori.adventure.text.minimessage.Template;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@CommandDeclaration(command = "delete", @CommandDeclaration(command = "delete",
@ -106,13 +105,13 @@ public class Delete extends SubCommand {
boolean result = plot.getPlotModificationManager().deletePlot(player, () -> { boolean result = plot.getPlotModificationManager().deletePlot(player, () -> {
plot.removeRunning(); plot.removeRunning();
if (this.econHandler.isEnabled(plotArea)) { if (this.econHandler.isEnabled(plotArea)) {
Expression<Double> valueExr = plotArea.getPrices().get("sell"); PlotExpression valueExr = plotArea.getPrices().get("sell");
double value = plots.size() * valueExr.evaluate((double) currentPlots); double value = plots.size() * valueExr.evaluate(currentPlots);
if (value > 0d) { if (value > 0d) {
this.econHandler.depositMoney(player, value); this.econHandler.depositMoney(player, value);
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.added_balance"), TranslatableCaption.of("economy.added_balance"),
Template.of("money", String.valueOf(value)) Template.of("money", this.econHandler.format(value))
); );
} }
} }

View File

@ -27,10 +27,10 @@ package com.plotsquared.core.command;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.plotsquared.core.PlotSquared; import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.location.Location; import com.plotsquared.core.location.Location;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.ConsolePlayer;
import com.plotsquared.core.player.MetaDataAccess; import com.plotsquared.core.player.MetaDataAccess;
import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlayerMetaDataKeys;
@ -38,8 +38,8 @@ import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.PlotExpression;
import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal2;
import com.plotsquared.core.util.task.RunnableVal3; import com.plotsquared.core.util.task.RunnableVal3;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -190,11 +190,10 @@ public class MainCommand extends Command {
CmdConfirm.addPending(player, cmd.getUsage(), () -> { CmdConfirm.addPending(player, cmd.getUsage(), () -> {
PlotArea area = player.getApplicablePlotArea(); PlotArea area = player.getApplicablePlotArea();
if (area != null && econHandler.isEnabled(area)) { if (area != null && econHandler.isEnabled(area)) {
Expression<Double> priceEval = PlotExpression priceEval =
area.getPrices().get(cmd.getFullId()); area.getPrices().get(cmd.getFullId());
Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; double price = priceEval != null ? priceEval.evaluate(0d) : 0d;
if (price != null if (econHandler.getMoney(player) < price) {
&& econHandler.getMoney(player) < price) {
if (failure != null) { if (failure != null) {
failure.run(); failure.run();
} }
@ -207,11 +206,10 @@ public class MainCommand extends Command {
}); });
return; return;
} }
if (econHandler != null) {
PlotArea area = player.getApplicablePlotArea(); PlotArea area = player.getApplicablePlotArea();
if (area != null) { if (area != null && econHandler.isEnabled(area)) {
Expression<Double> priceEval = area.getPrices().get(cmd.getFullId()); PlotExpression priceEval = area.getPrices().get(cmd.getFullId());
Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; double price = priceEval != null ? priceEval.evaluate(0d) : 0d;
if (price != 0d && econHandler.getMoney(player) < price) { if (price != 0d && econHandler.getMoney(player) < price) {
if (failure != null) { if (failure != null) {
failure.run(); failure.run();
@ -219,7 +217,6 @@ public class MainCommand extends Command {
return; return;
} }
} }
}
if (success != null) { if (success != null) {
success.run(); success.run();
} }
@ -277,12 +274,10 @@ public class MainCommand extends Command {
if ("f".equals(args[0].substring(1))) { if ("f".equals(args[0].substring(1))) {
confirm = new RunnableVal3<Command, Runnable, Runnable>() { confirm = new RunnableVal3<Command, Runnable, Runnable>() {
@Override public void run(Command cmd, Runnable success, Runnable failure) { @Override public void run(Command cmd, Runnable success, Runnable failure) {
if (PlotSquared.platform().econHandler() != null) { if (area != null && PlotSquared.platform().econHandler().isEnabled(area)) {
PlotArea area = player.getApplicablePlotArea(); PlotExpression priceEval =
if (area != null) {
Expression<Double> priceEval =
area.getPrices().get(cmd.getFullId()); area.getPrices().get(cmd.getFullId());
Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; double price = priceEval != null ? priceEval.evaluate(0d) : 0d;
if (price != 0d if (price != 0d
&& PlotSquared.platform().econHandler().getMoney(player) < price) { && PlotSquared.platform().econHandler().getMoney(player) < price) {
if (failure != null) { if (failure != null) {
@ -291,7 +286,6 @@ public class MainCommand extends Command {
return; return;
} }
} }
}
if (success != null) { if (success != null) {
success.run(); success.run();
} }

View File

@ -39,8 +39,8 @@ import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.PlotExpression;
import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.StringMan;
import net.kyori.adventure.text.minimessage.Template; import net.kyori.adventure.text.minimessage.Template;
@ -162,8 +162,8 @@ public class Merge extends SubCommand {
return false; return false;
} }
final PlotArea plotArea = plot.getArea(); final PlotArea plotArea = plot.getArea();
Expression<Double> priceExr = plotArea.getPrices().getOrDefault("merge", null); PlotExpression priceExr = plotArea.getPrices().getOrDefault("merge", null);
final double price = priceExr == null ? 0d : priceExr.evaluate((double) size); final double price = priceExr == null ? 0d : priceExr.evaluate(size);
UUID uuid = player.getUUID(); UUID uuid = player.getUUID();
if (direction == Direction.ALL) { if (direction == Direction.ALL) {
@ -184,7 +184,8 @@ public class Merge extends SubCommand {
this.econHandler.withdrawMoney(player, price); this.econHandler.withdrawMoney(player, price);
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.removed_balance"), TranslatableCaption.of("economy.removed_balance"),
Template.of("money", String.valueOf(price)) Template.of("money", this.econHandler.format(price)),
Template.of("balance", this.econHandler.format(this.econHandler.getMoney(player)))
); );
} }
player.sendMessage(TranslatableCaption.of("merge.success_merge")); player.sendMessage(TranslatableCaption.of("merge.success_merge"));
@ -205,7 +206,7 @@ public class Merge extends SubCommand {
&& this.econHandler.getMoney(player) < price) { && this.econHandler.getMoney(player) < price) {
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.cannot_afford_merge"), TranslatableCaption.of("economy.cannot_afford_merge"),
Template.of("money", String.valueOf(price)) Template.of("money", this.econHandler.format(price))
); );
return false; return false;
} }
@ -228,7 +229,7 @@ public class Merge extends SubCommand {
this.econHandler.withdrawMoney(player, price); this.econHandler.withdrawMoney(player, price);
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.removed_balance"), TranslatableCaption.of("economy.removed_balance"),
Template.of("money", String.valueOf(price)) Template.of("money", this.econHandler.format(price))
); );
} }
player.sendMessage(TranslatableCaption.of("merge.success_merge")); player.sendMessage(TranslatableCaption.of("merge.success_merge"));
@ -268,14 +269,14 @@ public class Merge extends SubCommand {
if (!force && this.econHandler.getMoney(player) < price) { if (!force && this.econHandler.getMoney(player) < price) {
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.cannot_afford_merge"), TranslatableCaption.of("economy.cannot_afford_merge"),
Template.of("money", String.valueOf(price)) Template.of("money", this.econHandler.format(price))
); );
return; return;
} }
this.econHandler.withdrawMoney(player, price); this.econHandler.withdrawMoney(player, price);
player.sendMessage( player.sendMessage(
TranslatableCaption.of("economy.removed_balance"), TranslatableCaption.of("economy.removed_balance"),
Template.of("money", String.valueOf(price)) Template.of("money", this.econHandler.format(price))
); );
} }
player.sendMessage(TranslatableCaption.of("merge.success_merge")); player.sendMessage(TranslatableCaption.of("merge.success_merge"));

View File

@ -186,7 +186,7 @@ public class ComponentPresetManager {
} else { } else {
econHandler.withdrawMoney(getPlayer(), componentPreset.getCost()); econHandler.withdrawMoney(getPlayer(), componentPreset.getCost());
getPlayer().sendMessage(TranslatableCaption.of("economy.removed_balance"), getPlayer().sendMessage(TranslatableCaption.of("economy.removed_balance"),
Template.of("money", componentPreset.getCost() + "")); Template.of("money", econHandler.format(componentPreset.getCost())));
} }
} }

View File

@ -57,8 +57,8 @@ import com.plotsquared.core.plot.flag.implementations.DoneFlag;
import com.plotsquared.core.plot.flag.types.DoubleFlag; import com.plotsquared.core.plot.flag.types.DoubleFlag;
import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.GlobalBlockQueue;
import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.queue.QueueCoordinator;
import com.plotsquared.core.util.Expression;
import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.MathMan;
import com.plotsquared.core.util.PlotExpression;
import com.plotsquared.core.util.RegionUtil; import com.plotsquared.core.util.RegionUtil;
import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.StringMan;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
@ -134,7 +134,7 @@ public abstract class PlotArea {
private int maxBuildHeight = 256; private int maxBuildHeight = 256;
private int minBuildHeight = 1; private int minBuildHeight = 1;
private GameMode gameMode = GameModes.CREATIVE; private GameMode gameMode = GameModes.CREATIVE;
private Map<String, Expression<Double>> prices = new HashMap<>(); private Map<String, PlotExpression> prices = new HashMap<>();
private List<String> schematics = new ArrayList<>(); private List<String> schematics = new ArrayList<>();
private boolean roadFlags = false; private boolean roadFlags = false;
private boolean worldBorder = false; private boolean worldBorder = false;
@ -306,7 +306,12 @@ public abstract class PlotArea {
if (this.useEconomy) { if (this.useEconomy) {
this.prices = new HashMap<>(); this.prices = new HashMap<>();
for (String key : priceSection.getKeys(false)) { for (String key : priceSection.getKeys(false)) {
this.prices.put(key, Expression.doubleExpression(priceSection.getString(key))); String raw = priceSection.getString(key);
if (raw.contains("{args}")) {
raw = raw.replace("{args}", "plots");
priceSection.set(key, raw); // update if replaced
}
this.prices.put(key, PlotExpression.compile(raw, "plots"));
} }
} }
this.plotChat = config.getBoolean("chat.enabled"); this.plotChat = config.getBoolean("chat.enabled");
@ -1315,7 +1320,7 @@ public abstract class PlotArea {
return this.gameMode; return this.gameMode;
} }
public Map<String, Expression<Double>> getPrices() { public Map<String, PlotExpression> getPrices() {
return this.prices; return this.prices;
} }

View File

@ -29,7 +29,7 @@ import com.plotsquared.core.player.ConsolePlayer;
import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.OfflinePlotPlayer;
import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotArea;
import com.sk89q.worldedit.EditSession; import org.checkerframework.checker.nullness.qual.NonNull;
public abstract class EconHandler { public abstract class EconHandler {
@ -75,6 +75,14 @@ public abstract class EconHandler {
*/ */
public abstract boolean isEnabled(PlotArea plotArea); public abstract boolean isEnabled(PlotArea plotArea);
/**
* Formats the given balance into a human-readable number.
*
* @param balance the balance to format.
* @return the balance as formatted string.
*/
public abstract @NonNull String format(double balance);
/** /**
* Returns whether economy is supported by the server or not. * Returns whether economy is supported by the server or not.
* *
@ -114,6 +122,11 @@ public abstract class EconHandler {
return false; return false;
} }
@Override
public @NonNull String format(double balance) {
return "";
}
@Override @Override
public boolean isSupported() { public boolean isSupported() {
return false; return false;

View File

@ -1,85 +0,0 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* PlotSquared plot management system for Minecraft
* Copyright (C) 2021 IntellectualSites
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util;
import com.plotsquared.core.command.DebugExec;
import com.plotsquared.core.command.MainCommand;
import com.plotsquared.core.configuration.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.ScriptException;
public abstract class Expression<T> {
private static final Logger logger = LoggerFactory.getLogger("P2/" + Expression.class.getSimpleName());
public static <U> Expression<U> constant(final U value) {
return new Expression<U>() {
@Override public U evaluate(U arg) {
return value;
}
};
}
public static Expression<Double> linearDouble(final Double value) {
return new Expression<Double>() {
@Override public Double evaluate(Double arg) {
return (arg * value);
}
};
}
public static Expression<Double> doubleExpression(final String expression) {
try {
return constant(Double.parseDouble(expression));
} catch (NumberFormatException ignore) {
}
if (expression.endsWith("*{arg}")) {
try {
return linearDouble(
Double.parseDouble(expression.substring(0, expression.length() - 6)));
} catch (NumberFormatException ignore) {
}
}
return new Expression<Double>() {
@Override public Double evaluate(Double arg) {
DebugExec exec = (DebugExec) MainCommand.getInstance().getCommand(DebugExec.class);
try {
return (Double) exec.getEngine().eval(expression.replace("{arg}", "" + arg));
} catch (ScriptException e) {
if (Settings.DEBUG) {
logger.info("Invalid expression: {}", expression);
}
e.printStackTrace();
}
return 0d;
}
};
}
public abstract T evaluate(T arg);
}

View File

@ -0,0 +1,70 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* PlotSquared plot management system for Minecraft
* Copyright (C) 2021 IntellectualSites
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util;
import com.sk89q.worldedit.internal.expression.Expression;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* An expression that can be evaluated.
* Evaluation is thread-safe.
* This is a wrapper for {@link Expression}.
*/
public class PlotExpression {
private final Expression expression;
private final Object lock = new Object();
/**
* Compiles an expression from a string.
*
* @param expression the expression to compile.
* @param variableNames the variables that can be set in {@link #evaluate(double...)}.
* @return the compiled expression.
*/
public static @NonNull PlotExpression compile(final @NonNull String expression,
final @NonNull String @NonNull ... variableNames) {
return new PlotExpression(expression, variableNames);
}
private PlotExpression(final @NonNull String rawExpression, final @NonNull String @NonNull [] variableNames) {
this.expression = Expression.compile(rawExpression, variableNames);
}
/**
* Evaluates the expression with the given variable values.
*
* @param values the values to set the variables to.
* @return the result of the evaluation.
*/
public double evaluate(double... values) {
double evaluate;
// synchronization is likely the best option in terms of memory and cpu consumption
synchronized (this.lock) {
evaluate = this.expression.evaluate(values);
}
return evaluate;
}
}