Remove AsyncCommandHelper for new AsyncCommandBuilder.

Helper suffers from race conditions for short-lived tasks, leading to
some poor UX conditions such as errors not propagating to the user
(because the exception handler wasn't attached to the future yet), or
lack of success messages.

This commit replaces that system by a Builder which takes a callable to
begin, and then takes supervisor, delay message, and the success and
failure messages and handlers as parts of the builder. The success and
failure handlers wrap the callable itself before submitting to the
executor so they will always be run. The supervisor and delay are added
as listeners to the future since they aren't required if the task is
sufficiently short-lived (and to maintain compatibility with the classes
which are now in WorldEdit).

The builder also supports Components for success and failure messages,
as well as consumers of the callable's result or exception for better
customization of output, instead of having to rely on adding a callback
to the future.

The future is still returned for certain special usages.
This commit is contained in:
wizjany 2019-05-11 19:22:33 -04:00
parent e7ef6af012
commit d542ba78ff
8 changed files with 185 additions and 191 deletions

View File

@ -29,7 +29,6 @@
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.NestedCommand;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.AsyncCommandHelper;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.auth.AuthorizationException;
@ -41,6 +40,7 @@
import com.sk89q.worldedit.util.paste.ActorCallbackPaste;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.util.report.SystemInfoReport;
import com.sk89q.worldedit.util.task.FutureForwardingTask;
import com.sk89q.worldedit.util.task.Task;
import com.sk89q.worldedit.util.task.TaskStateComparator;
import com.sk89q.worldedit.world.World;
@ -142,7 +142,7 @@ public void report(CommandContext args, final Actor sender) throws CommandExcept
if (args.hasFlag('p')) {
sender.checkPermission("worldguard.report.pastebin");
ActorCallbackPaste.pastebin(worldGuard.getSupervisor(), sender, result, "WorldGuard report: %s.report", worldGuard.getExceptionConverter());
ActorCallbackPaste.pastebin(worldGuard.getSupervisor(), sender, result, "WorldGuard report: %s.report");
}
}
@ -196,14 +196,12 @@ public void profile(final CommandContext args, final Actor sender) throws Comman
}
sender.print(TextComponent.of("Starting CPU profiling. Use ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/wg stopprofle", TextColor.AQUA)
.append(TextComponent.of("/wg stopprofile", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/wg stopprofile")))
.append(TextComponent.of(" to stop profling.", TextColor.LIGHT_PURPLE)));
AsyncCommandHelper.wrap(sampler.getFuture(), worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.formatUsing(minutes)
.registerWithSupervisor("Running CPU profiler for %d minute(s)...")
.sendMessageAfterDelay("(Please wait... profiling for %d minute(s)...)")
.thenTellErrorsOnly("CPU profiling failed");
.append(TextComponent.of(" to stop profiling.", TextColor.LIGHT_PURPLE)));
worldGuard.getSupervisor().monitor(FutureForwardingTask.create(
sampler.getFuture(), "CPU profiling for " + minutes + " minutes", sender));
sampler.getFuture().addListener(() -> {
synchronized (WorldGuardCommands.this) {
@ -225,7 +223,7 @@ public void onSuccess(Sampler result) {
}
if (pastebin) {
ActorCallbackPaste.pastebin(worldGuard.getSupervisor(), sender, output, "Profile result: %s.profile", worldGuard.getExceptionConverter());
ActorCallbackPaste.pastebin(worldGuard.getSupervisor(), sender, output, "Profile result: %s.profile");
}
}

View File

@ -82,7 +82,7 @@ class FlagHelperBox extends PaginationBox {
private final RegionPermissionModel perms;
FlagHelperBox(World world, ProtectedRegion region, RegionPermissionModel perms) {
super("Flags for " + region.getId(), "/rg flags -w " + world.getName() + " " + region.getId() + " %page%");
super("Flags for " + region.getId(), "/rg flags -w " + world.getName() + " -p %page% " + region.getId());
this.world = world;
this.region = region;
this.perms = perms;

View File

@ -19,13 +19,11 @@
package com.sk89q.worldguard.commands.region;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.command.util.AsyncCommandHelper;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.world.World;
@ -37,6 +35,8 @@
import com.sk89q.worldguard.protection.util.DomainInputResolver;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
import java.util.concurrent.Callable;
public class MemberCommands extends RegionCommandsBase {
private final WorldGuard worldGuard;
@ -68,16 +68,13 @@ public void addMember(CommandContext args, Actor sender) throws CommandException
WorldGuard.getInstance().getProfileService(), args.getParsedPaddedSlice(1, 0));
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
// Then add it to the members
ListenableFuture<DefaultDomain> future = Futures.transform(
WorldGuard.getInstance().getExecutorService().submit(resolver),
resolver.createAddAllFunction(region.getMembers()));
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.formatUsing(region.getId(), world.getName())
.registerWithSupervisor("Adding members to the region '%s' on '%s'")
.sendMessageAfterDelay("(Please wait... querying player names...)")
.thenRespondWith("Region '%s' updated with new members.", "Failed to add new members");
final String description = String.format("Adding members to the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(resolver, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new members.", region.getId()), region.getMembers()::addAll)
.onFailure("Failed to add new members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@Command(aliases = {"addowner", "addowner", "ao"},
@ -127,16 +124,13 @@ public void addOwner(CommandContext args, Actor sender) throws CommandException,
WorldGuard.getInstance().getProfileService(), args.getParsedPaddedSlice(1, 0));
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
// Then add it to the owners
ListenableFuture<DefaultDomain> future = Futures.transform(
WorldGuard.getInstance().getExecutorService().submit(resolver),
resolver.createAddAllFunction(region.getOwners()));
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.formatUsing(region.getId(), world.getName())
.registerWithSupervisor("Adding owners to the region '%s' on '%s'")
.sendMessageAfterDelay("(Please wait... querying player names...)")
.thenRespondWith("Region '%s' updated with new owners.", "Failed to add new owners");
final String description = String.format("Adding owners to the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(resolver, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new owners.", region.getId()), region.getOwners()::addAll)
.onFailure("Failed to add new owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@Command(aliases = {"removemember", "remmember", "removemem", "remmem", "rm"},
@ -157,12 +151,9 @@ public void removeMember(CommandContext args, Actor sender) throws CommandExcept
throw new CommandPermissionsException();
}
ListenableFuture<?> future;
Callable<DefaultDomain> callable;
if (args.hasFlag('a')) {
region.getMembers().removeAll();
future = Futures.immediateFuture(null);
callable = region::getMembers;
} else {
if (args.argsLength() < 2) {
throw new CommandException("List some names to remove, or use -a to remove all.");
@ -173,17 +164,16 @@ public void removeMember(CommandContext args, Actor sender) throws CommandExcept
WorldGuard.getInstance().getProfileService(), args.getParsedPaddedSlice(1, 0));
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_AND_NAME);
// Then remove it from the members
future = Futures.transform(
WorldGuard.getInstance().getExecutorService().submit(resolver),
resolver.createRemoveAllFunction(region.getMembers()));
callable = resolver;
}
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.formatUsing(region.getId(), world.getName())
.registerWithSupervisor("Removing members from the region '%s' on '%s'")
final String description = String.format("Removing members from the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)")
.thenRespondWith("Region '%s' updated with members removed.", "Failed to remove members");
.onSuccess(String.format("Region '%s' updated with members removed.", region.getId()), region.getMembers()::removeAll)
.onFailure("Failed to remove members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@Command(aliases = {"removeowner", "remowner", "ro"},
@ -204,12 +194,9 @@ public void removeOwner(CommandContext args, Actor sender) throws CommandExcepti
throw new CommandPermissionsException();
}
ListenableFuture<?> future;
Callable<DefaultDomain> callable;
if (args.hasFlag('a')) {
region.getOwners().removeAll();
future = Futures.immediateFuture(null);
callable = region::getOwners;
} else {
if (args.argsLength() < 2) {
throw new CommandException("List some names to remove, or use -a to remove all.");
@ -220,16 +207,15 @@ public void removeOwner(CommandContext args, Actor sender) throws CommandExcepti
WorldGuard.getInstance().getProfileService(), args.getParsedPaddedSlice(1, 0));
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_AND_NAME);
// Then remove it from the owners
future = Futures.transform(
WorldGuard.getInstance().getExecutorService().submit(resolver),
resolver.createRemoveAllFunction(region.getOwners()));
callable = resolver;
}
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.formatUsing(region.getId(), world.getName())
.registerWithSupervisor("Removing owners from the region '%s' on '%s'")
final String description = String.format("Removing owners from the region '%s' on '%s'", region.getId(), world.getName());
AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)")
.thenRespondWith("Region '%s' updated with owners removed.", "Failed to remove owners");
.onSuccess(String.format("Region '%s' updated with owners removed.", region.getId()), region.getOwners()::removeAll)
.onFailure("Failed to remove owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
}

View File

@ -22,22 +22,19 @@
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.AsyncCommandHelper;
import com.sk89q.worldedit.command.util.FutureProgressListener;
import com.sk89q.worldedit.command.util.MessageFutureCallback.Builder;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.LabelFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
@ -49,7 +46,7 @@
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.commands.task.RegionAdder;
import com.sk89q.worldguard.commands.task.RegionLister;
import com.sk89q.worldguard.commands.task.RegionManagerReloader;
import com.sk89q.worldguard.commands.task.RegionManagerLoader;
import com.sk89q.worldguard.commands.task.RegionManagerSaver;
import com.sk89q.worldguard.commands.task.RegionRemover;
import com.sk89q.worldguard.config.ConfigurationManager;
@ -84,6 +81,7 @@
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* Implements the /region commands for WorldGuard.
@ -137,20 +135,18 @@ public void define(CommandContext args, Actor sender) throws CommandException {
RegionAdder task = new RegionAdder(manager, region);
task.addOwnersFromCommand(args, 2);
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(task);
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), player, worldGuard.getExceptionConverter())
.formatUsing(id)
.registerWithSupervisor("Adding the region '%s'...")
.sendMessageAfterDelay("(Please wait... adding '%s'...)")
.thenRespondWith(
"A new region has been made named '%s'.",
"Failed to add the region '%s'");
final String description = String.format("Adding region '%s'", region.getId());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("A new region has been made named '%s'.", region.getId()), null)
.onFailure("Failed to add the region '%s'", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
/**
* Re-defines a region with a new selection.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -189,23 +185,22 @@ public void redefine(CommandContext args, Actor sender) throws CommandException
region.copyFrom(existing);
RegionAdder task = new RegionAdder(manager, region);
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(task);
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), player, worldGuard.getExceptionConverter())
.formatUsing(id)
.registerWithSupervisor("Updating the region '%s'...")
.sendMessageAfterDelay("(Please wait... updating '%s'...)")
.thenRespondWith(
"Region '%s' has been updated with a new area.",
"Failed to update the region '%s'");
final String description = String.format("Updating region '%s'", region.getId());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(String.format("Region '%s' has been updated with a new area.", region.getId()), null)
.onFailure(String.format("Failed to update the region '%s'", region.getId()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
/**
* Claiming command for users.
*
*
* <p>This command is a joke and it needs to be rewritten. It was contributed
* code :(</p>
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -219,7 +214,7 @@ public void claim(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionPermissionModel permModel = getPermissionModel(player);
// Check permissions
if (!permModel.mayClaim()) {
throw new CommandPermissionsException();
@ -290,20 +285,18 @@ public void claim(CommandContext args, Actor sender) throws CommandException {
RegionAdder task = new RegionAdder(manager, region);
task.setLocatorPolicy(UserLocatorPolicy.UUID_ONLY);
task.setOwnersInput(new String[]{player.getName()});
ListenableFuture<?> future = worldGuard.getExecutorService().submit(task);
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), player, worldGuard.getExceptionConverter())
.formatUsing(id)
.registerWithSupervisor("Claiming the region '%s'...")
.sendMessageAfterDelay("(Please wait... claiming '%s'...)")
.thenRespondWith(
"A new region has been claimed named '%s'.",
"Failed to claim the region '%s'");
final String description = String.format("Claiming region '%s'", id);
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", id)), null)
.onFailure("Failed to claim region", WorldGuard.getInstance().getExceptionConverter());
}
/**
* Get a WorldEdit selection from a region.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -316,7 +309,7 @@ public void select(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionManager manager = checkRegionManager(player.getWorld());
ProtectedRegion existing;
// If no arguments were given, get the region that the player is inside
if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player, "/rg select %id%");
@ -335,7 +328,7 @@ public void select(CommandContext args, Actor sender) throws CommandException {
/**
* Get information about a region.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -359,7 +352,7 @@ public void info(CommandContext args, Actor sender) throws CommandException {
if (!(sender instanceof LocalPlayer)) {
throw new CommandException("Please specify the region with /region info -w world_name region_name.");
}
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w " + world.getName() + " %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID
@ -384,19 +377,18 @@ public void info(CommandContext args, Actor sender) throws CommandException {
// Print region information
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), existing,
args.hasFlag('u') ? null : WorldGuard.getInstance().getProfileCache(), sender);
ListenableFuture<?> future = Futures.transform(
WorldGuard.getInstance().getExecutorService().submit(printout),
CommandUtils.messageComponentFunction(sender)::apply);
AsyncCommandHelper.wrap(future, WorldGuard.getInstance().getSupervisor(), sender, WorldGuard.getInstance().getExceptionConverter())
.registerWithSupervisor("Fetching region info")
AsyncCommandBuilder.wrap(printout, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Fetching region info")
.sendMessageAfterDelay("(Please wait... fetching region information...)")
.thenTellErrorsOnly("Failed to fetch region information");
.onSuccess((Component) null, sender::print)
.onFailure("Failed to fetch region information", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
/**
* List regions.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -441,17 +433,16 @@ public void list(CommandContext args, Actor sender) throws CommandException {
task.filterOwnedByName(ownedBy, args.hasFlag('n'));
}
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(task);
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.registerWithSupervisor("Getting list of regions...")
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Getting region list")
.sendMessageAfterDelay("(Please wait... fetching region list...)")
.thenTellErrorsOnly("Failed to fetch region list");
.onFailure("Failed to fetch region list", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
/**
* Set a flag.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -512,8 +503,6 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
Collections.sort(flagList);
// TODO paginationbox + descs etc
final TextComponent.Builder builder = TextComponent.builder("Available flags: ");
final HoverEvent clickToSet = HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set"));
@ -530,7 +519,13 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
sender.printError("Unknown flag specified: " + flagName);
sender.print(builder.build());
if (sender.isPlayer()) {
sender.print(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + existing.getId(), TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w " + world.getName() + " " + existing.getId()))));
}
return;
} else if (value != null) {
if (foundFlag == Flags.BUILD || foundFlag == Flags.BLOCK_BREAK || foundFlag == Flags.BLOCK_PLACE) {
@ -562,7 +557,7 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
}
}
}
// Also make sure that we can use this flag
// This permission is confusing and probably should be replaced, but
// but not here -- in the model
@ -574,7 +569,7 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
if (args.hasFlag('g')) {
String group = args.getFlag('g');
RegionGroupFlag groupFlag = foundFlag.getRegionGroupFlag();
if (groupFlag == null) {
throw new CommandException("Region flag '" + foundFlag.getName()
+ "' does not have a group flag!");
@ -602,7 +597,7 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " set on '" + existing.getId() + "' to '" + value + "'.");
}
// No value? Clear the flag, if -g isn't specified
} else if (!args.hasFlag('g')) {
// Clear the flag only if neither [value] nor [-g group] was given
@ -636,17 +631,7 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
// Print region information
if (args.hasFlag('h')) {
int page = args.getFlagInteger('h');
final FlagHelperBox flagHelperBox = new FlagHelperBox(world, existing, permModel);
flagHelperBox.setComponentsPerPage(18);
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(() -> {
sender.print(flagHelperBox.create(page));
return null;
});
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.registerWithSupervisor("Getting region flags.")
.sendMessageAfterDelay("(Please wait... fetching region info...)")
.thenTellErrorsOnly("Failed to fetch region info");
sendFlagHelper(sender, world, existing, permModel, page);
} else {
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), existing, null, sender);
printout.append(SubtleFormat.wrap("(Current flags: "));
@ -657,39 +642,48 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
}
@Command(aliases = "flags",
usage = "<id> [page]",
flags = "w:",
usage = "[-p <page>] [id]",
flags = "p:w:",
desc = "View region flags",
min = 1, max = 2)
min = 0, max = 2)
public void flagHelper(CommandContext args, Actor sender) throws CommandException {
World world = checkWorld(args, sender, 'w'); // Get the world
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, args.getString(0), true);
ProtectedRegion region;
if (args.argsLength() == 0) { // Get region from where the player is
if (!(sender instanceof LocalPlayer)) {
throw new CommandException("Please specify the region with /region info -w world_name region_name.");
}
region = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg flags -w " + world.getName() + " %id%");
} else { // Get region from the ID
region = checkExistingRegion(manager, args.getString(0), true);
}
final RegionPermissionModel perms = getPermissionModel(sender);
if (!perms.mayLookup(region)) {
throw new CommandPermissionsException();
}
int page = args.getInteger(1, 1);
int page = args.hasFlag('p') ? args.getFlagInteger('p') : 1;
sendFlagHelper(sender, world, region, perms, page);
}
private static void sendFlagHelper(Actor sender, World world, ProtectedRegion region, RegionPermissionModel perms, int page) {
final FlagHelperBox flagHelperBox = new FlagHelperBox(world, region, perms);
flagHelperBox.setComponentsPerPage(18);
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(() -> {
sender.print(flagHelperBox.create(page));
return null;
});
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.registerWithSupervisor("Getting region flags.")
.sendMessageAfterDelay("(Please wait... fetching region info...)")
.thenTellErrorsOnly("Failed to fetch region info");
AsyncCommandBuilder.wrap(() -> flagHelperBox.create(page), sender)
.onSuccess((Component) null, sender::print)
.onFailure("Failed to get region flags", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
/**
* Set the priority of a region.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -721,7 +715,7 @@ public void setPriority(CommandContext args, Actor sender) throws CommandExcepti
/**
* Set the parent of a region.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -740,7 +734,7 @@ public void setParent(CommandContext args, Actor sender) throws CommandException
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
// Get parent and child
child = checkExistingRegion(manager, args.getString(0), false);
if (args.argsLength() == 2) {
@ -768,7 +762,7 @@ public void setParent(CommandContext args, Actor sender) throws CommandException
printout.send(sender);
return;
}
// Tell the user the current inheritance
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender);
printout.append(LabelFormat.wrap("Inheritance set for region '", child.getId(), "'."));
@ -785,7 +779,7 @@ public void setParent(CommandContext args, Actor sender) throws CommandException
/**
* Remove a region.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -821,18 +815,20 @@ public void remove(CommandContext args, Actor sender) throws CommandException {
task.setRemovalStrategy(RemovalStrategy.UNSET_PARENT_IN_CHILDREN);
}
AsyncCommandHelper.wrap(WorldGuard.getInstance().getExecutorService().submit(task), worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.formatUsing(existing.getId())
.registerWithSupervisor("Removing the region '%s'...")
.sendMessageAfterDelay("(Please wait... removing '%s'...)")
.thenRespondWith(
"The region named '%s' has been removed.",
"Failed to remove the region '%s'");
final String description = String.format("Removing region '%s' in '%s'", existing.getId(), world.getName());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("Please wait... removing region.")
.onSuccess((Component) null, removed -> sender.print(TextComponent.of(
"Successfully removed " + removed.stream().map(ProtectedRegion::getId).collect(Collectors.joining(", ")) + ".",
TextColor.LIGHT_PURPLE)))
.onFailure("Failed to remove region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
/**
* Reload the region database.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -847,7 +843,7 @@ public void load(CommandContext args, final Actor sender) throws CommandExceptio
World world = null;
try {
world = checkWorld(args, sender, 'w'); // Get the world
} catch (CommandException e) {
} catch (CommandException ignored) {
// assume the user wants to reload all worlds
}
@ -863,10 +859,13 @@ public void load(CommandContext args, final Actor sender) throws CommandExceptio
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(new RegionManagerReloader(manager));
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.forRegionDataLoad(world, false);
final String description = String.format("Loading region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerLoader(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("Please wait... " + description)
.onSuccess(String.format("Loaded region data for '%s'", world.getName()), null)
.onFailure(String.format("Failed to load region data for '%s'", world.getName()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
} else {
// Load regions for all worlds
List<RegionManager> managers = new ArrayList<>();
@ -878,20 +877,18 @@ public void load(CommandContext args, final Actor sender) throws CommandExceptio
}
}
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(new RegionManagerReloader(managers));
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.registerWithSupervisor("Loading regions for all worlds")
AsyncCommandBuilder.wrap(new RegionManagerLoader(managers), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), "Loading regions for all worlds")
.sendMessageAfterDelay("(Please wait... loading region data for all worlds...)")
.thenRespondWith(
"Successfully load the region data for all worlds.",
"Failed to load regions for all worlds");
.onSuccess("Successfully load the region data for all worlds.", null)
.onFailure("Failed to load regions for all worlds", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
}
/**
* Re-save the region database.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -906,7 +903,7 @@ public void save(CommandContext args, final Actor sender) throws CommandExceptio
World world = null;
try {
world = checkWorld(args, sender, 'w'); // Get the world
} catch (CommandException e) {
} catch (CommandException ignored) {
// assume user wants to save all worlds
}
@ -922,35 +919,37 @@ public void save(CommandContext args, final Actor sender) throws CommandExceptio
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(new RegionManagerSaver(manager));
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.forRegionDataSave(world, false);
final String description = String.format("Saving region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerSaver(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("Please wait... " + description)
.onSuccess(String.format("Saving region data for '%s'", world.getName()), null)
.onFailure(String.format("Failed to save region data for '%s'", world.getName()), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
} else {
// Save for all worlds
List<RegionManager> managers = new ArrayList<>();
final RegionContainer regionContainer = worldGuard.getPlatform().getRegionContainer();
for (World w : WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getWorlds()) {
RegionManager manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(w);
RegionManager manager = regionContainer.get(w);
if (manager != null) {
managers.add(manager);
}
}
ListenableFuture<?> future = WorldGuard.getInstance().getExecutorService().submit(new RegionManagerSaver(managers));
AsyncCommandHelper.wrap(future, worldGuard.getSupervisor(), sender, worldGuard.getExceptionConverter())
.registerWithSupervisor("Saving regions for all worlds")
AsyncCommandBuilder.wrap(new RegionManagerSaver(managers), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), "Saving regions for all worlds")
.sendMessageAfterDelay("(Please wait... saving region data for all worlds...)")
.thenRespondWith(
"Successfully saved the region data for all worlds.",
"Failed to save regions for all worlds");
.onSuccess("Successfully saved the region data for all worlds.", null)
.onFailure("Failed to save regions for all worlds", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
}
/**
* Migrate the region database.
*
*
* @param args the arguments
* @param sender the sender
* @throws CommandException any error
@ -975,7 +974,7 @@ public void migrateDB(CommandContext args, Actor sender) throws CommandException
throw new CommandException("The value of 'to' is not a recognized type of region region data database.");
}
if (from.equals(to)) {
if (from == to) {
throw new CommandException("It is not possible to migrate between the same types of region data databases.");
}

View File

@ -28,16 +28,16 @@
import static com.google.common.base.Preconditions.checkNotNull;
public class RegionManagerReloader implements Callable<Collection<RegionManager>> {
public class RegionManagerLoader implements Callable<Collection<RegionManager>> {
private final Collection<RegionManager> managers;
public RegionManagerReloader(Collection<RegionManager> managers) {
public RegionManagerLoader(Collection<RegionManager> managers) {
checkNotNull(managers);
this.managers = managers;
}
public RegionManagerReloader(RegionManager... manager) {
public RegionManagerLoader(RegionManager... manager) {
this(Arrays.asList(manager));
}

View File

@ -139,6 +139,10 @@ public DefaultDomain call() throws UnresolvedNamesException {
return domain;
}
/**
* @deprecated was only used for Future transformation. Can be replaced with {@code region.getOwners()::addAll} (or getMembers).
*/
@Deprecated
public Function<DefaultDomain, DefaultDomain> createAddAllFunction(final DefaultDomain target) {
return domain -> {
target.addAll(domain);
@ -146,6 +150,10 @@ public Function<DefaultDomain, DefaultDomain> createAddAllFunction(final Default
};
}
/**
* @deprecated was only used for Future transformation. Can be replaced with {@code region.getOwners()::removeAll} (or getMembers).
*/
@Deprecated
public Function<DefaultDomain, DefaultDomain> createRemoveAllFunction(final DefaultDomain target) {
return domain -> {
target.removeAll(domain);

View File

@ -19,16 +19,15 @@
package com.sk89q.worldguard.util;
import com.google.common.collect.ImmutableList;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.internal.command.exception.ExceptionConverterHelper;
import com.sk89q.worldedit.internal.command.exception.ExceptionMatch;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.util.UnresolvedNamesException;
import org.enginehub.piston.exception.CommandException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.RejectedExecutionException;
@ -41,7 +40,7 @@ public class WorldGuardExceptionConverter extends ExceptionConverterHelper {
private static final Pattern numberFormat = Pattern.compile("^For input string: \"(.*)\"$");
private CommandException newCommandException(String message, Throwable cause) {
return new CommandException(TextComponent.of(String.valueOf(message)), cause, ImmutableList.of());
return new CommandException(message, cause);
}
@ExceptionMatch
@ -56,6 +55,11 @@ public void convert(NumberFormatException e) throws CommandException {
}
}
@ExceptionMatch
public void convert(InvalidComponentException e) throws CommandException {
throw newCommandException(e.getMessage(), e);
}
@ExceptionMatch
public void convert(StorageException e) throws CommandException {
WorldGuard.logger.log(Level.WARNING, "Error loading/saving regions", e);

View File

@ -95,9 +95,8 @@ private <T extends Event & CancelLogging> void testEvent(CommandSender receiver,
log.info("Event report for " + receiver.getName() + ":\n\n" + result);
plugin.checkPermission(receiver, "worldguard.debug.pastebin");
ActorCallbackPaste
.pastebin(WorldGuard.getInstance().getSupervisor(), plugin.wrapCommandSender(receiver), result,
"Event debugging report: %s.txt", WorldGuard.getInstance().getExceptionConverter());
ActorCallbackPaste.pastebin(WorldGuard.getInstance().getSupervisor(), plugin.wrapCommandSender(receiver),
result, "Event debugging report: %s.txt");
} else {
receiver.sendMessage(result.replaceAll("(?m)^", ChatColor.AQUA.toString()));