Add better control over expression timeouts. (#451)

Add better control over expression timeouts.
* //timeout command can be used to change player's current timeout.
* Config now also has a max timeout, can be bypassed with permission
* Timeout of < 0 will let expressions run indefinitely.
* Said expressions won't run on a separate thread, slightly reducing the
  overhead from context switching. For large //gen commands, for example,
  this can actually increase speed.
This commit is contained in:
wizjany
2019-03-06 19:58:32 -05:00
committed by GitHub
parent f84f3c6f85
commit de08c8b8c7
21 changed files with 301 additions and 76 deletions

View File

@ -57,9 +57,9 @@ public class GeneralCommands {
@Command(
aliases = { "/limit" },
usage = "<limit>",
usage = "[limit]",
desc = "Modify block change limit",
min = 1,
min = 0,
max = 1
)
@CommandPermissions("worldedit.limit")
@ -68,7 +68,7 @@ public class GeneralCommands {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted");
int limit = Math.max(-1, args.getInteger(0));
int limit = args.argsLength() == 0 ? config.defaultChangeLimit : Math.max(-1, args.getInteger(0));
if (!mayDisable && config.maxChangeLimit > -1) {
if (limit > config.maxChangeLimit) {
player.printError("Your maximum allowable limit is " + config.maxChangeLimit + ".");
@ -78,13 +78,43 @@ public class GeneralCommands {
session.setBlockChangeLimit(limit);
if (limit != -1) {
player.print("Block change limit set to " + limit + ". (Use //limit -1 to go back to the default.)");
if (limit != config.defaultChangeLimit) {
player.print("Block change limit set to " + limit + ". (Use //limit to go back to the default.)");
} else {
player.print("Block change limit set to " + limit + ".");
}
}
@Command(
aliases = { "/timeout" },
usage = "[time]",
desc = "Modify evaluation timeout time.",
min = 0,
max = 1
)
@CommandPermissions("worldedit.timeout")
public void timeout(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted");
int limit = args.argsLength() == 0 ? config.calculationTimeout : Math.max(-1, args.getInteger(0));
if (!mayDisable && config.maxCalculationTimeout > -1) {
if (limit > config.maxCalculationTimeout) {
player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms.");
return;
}
}
session.setTimeout(limit);
if (limit != config.calculationTimeout) {
player.print("Timeout time set to " + limit + " ms. (Use //timeout to go back to the default.)");
} else {
player.print("Timeout time set to " + limit + " ms.");
}
}
@Command(
aliases = { "/fast" },
usage = "[on|off]",

View File

@ -306,7 +306,7 @@ public class GenerationCommands {
}
try {
final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow);
final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow, session.getTimeout());
player.findFreePosition();
player.print(affected + " block(s) have been created.");
} catch (ExpressionException e) {
@ -333,7 +333,7 @@ public class GenerationCommands {
min = 2,
max = -1
)
@CommandPermissions({"worldedit.generation.shape", "worldedit.biome.set"})
@CommandPermissions("worldedit.generation.shape.biome")
@Logging(ALL)
public void generateBiome(Player player, LocalSession session, EditSession editSession,
@Selection Region region,
@ -371,7 +371,7 @@ public class GenerationCommands {
}
try {
final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow);
final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow, session.getTimeout());
player.findFreePosition();
player.print("" + affected + " columns affected.");
} catch (ExpressionException e) {

View File

@ -404,7 +404,7 @@ public class RegionCommands {
}
try {
final int affected = editSession.deformRegion(region, zero, unit, expression);
final int affected = editSession.deformRegion(region, zero, unit, expression, session.getTimeout());
player.findFreePosition();
player.print(affected + " block(s) have been deformed.");
} catch (ExpressionException e) {

View File

@ -52,6 +52,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.SessionOwner;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Dispatcher;
@ -541,13 +542,18 @@ public class UtilityCommands {
public void calc(Actor actor, @Text String input) throws CommandException {
try {
Expression expression = Expression.compile(input);
actor.print("= " + expression.evaluate());
if (actor instanceof SessionOwner) {
actor.print("= " + expression.evaluate(
new double[]{}, WorldEdit.getInstance().getSessionManager().get((SessionOwner) actor).getTimeout()));
} else {
actor.print("= " + expression.evaluate());
}
} catch (EvaluationException e) {
actor.printError(String.format(
"'%s' could not be parsed as a valid expression", input));
"'%s' could not be evaluated (error: %s)", input, e.getMessage()));
} catch (ExpressionException e) {
actor.printError(String.format(
"'%s' could not be evaluated (error: %s)", input, e.getMessage()));
"'%s' could not be parsed as a valid expression", input));
}
}

View File

@ -79,6 +79,7 @@ public class SelectionCommand extends SimpleCommand<Operation> {
EditContext editContext = new EditContext();
editContext.setDestination(locals.get(EditSession.class));
editContext.setRegion(selection);
editContext.setSession(session);
Operation operation = operationFactory.createFromContext(editContext);
Operations.completeBlindly(operation);

View File

@ -75,7 +75,7 @@ public class ShapedBrushCommand extends SimpleCommand<Object> {
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
tool.setSize(radius);
tool.setFill(null);
tool.setBrush(new OperationFactoryBrush(factory, regionFactory), permission);
tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission);
} catch (MaxBrushRadiusException | InvalidToolBindException e) {
WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e);
}

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.command.tool.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
@ -33,10 +34,16 @@ public class OperationFactoryBrush implements Brush {
private final Contextual<? extends Operation> operationFactory;
private final RegionFactory regionFactory;
private final LocalSession session;
public OperationFactoryBrush(Contextual<? extends Operation> operationFactory, RegionFactory regionFactory) {
this(operationFactory, regionFactory, null);
}
public OperationFactoryBrush(Contextual<? extends Operation> operationFactory, RegionFactory regionFactory, LocalSession session) {
this.operationFactory = operationFactory;
this.regionFactory = regionFactory;
this.session = session;
}
@Override
@ -45,6 +52,7 @@ public class OperationFactoryBrush implements Brush {
context.setDestination(editSession);
context.setRegion(regionFactory.createCenteredAt(position, size));
context.setFill(pattern);
context.setSession(session);
Operation operation = operationFactory.createFromContext(context);
Operations.completeLegacy(operation);
}