From d542ba78ffa91b0d6e7202ed595582b0104656ae Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 11 May 2019 19:22:33 -0400 Subject: [PATCH] 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. --- .../commands/WorldGuardCommands.java | 18 +- .../commands/region/FlagHelperBox.java | 2 +- .../commands/region/MemberCommands.java | 80 +++--- .../commands/region/RegionCommands.java | 251 +++++++++--------- ...Reloader.java => RegionManagerLoader.java} | 6 +- .../protection/util/DomainInputResolver.java | 8 + .../util/WorldGuardExceptionConverter.java | 12 +- .../worldguard/bukkit/BukkitDebugHandler.java | 5 +- 8 files changed, 188 insertions(+), 194 deletions(-) rename worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/{RegionManagerReloader.java => RegionManagerLoader.java} (87%) diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/WorldGuardCommands.java b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/WorldGuardCommands.java index 9837563b7..e7cb9c060 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/WorldGuardCommands.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/WorldGuardCommands.java @@ -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"); } } diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/FlagHelperBox.java b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/FlagHelperBox.java index 212fee7e7..8c03991c2 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/FlagHelperBox.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/FlagHelperBox.java @@ -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; diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/MemberCommands.java b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/MemberCommands.java index dd05dc3b2..14a1b1398 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/MemberCommands.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/MemberCommands.java @@ -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 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 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 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 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()); } } diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java index b7896852e..8c23f5045 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/region/RegionCommands.java @@ -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. - * + * *

This command is a joke and it needs to be rewritten. It was contributed * code :(

- * + * * @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 = " [page]", - flags = "w:", + usage = "[-p ] [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 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 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."); } diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/RegionManagerReloader.java b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/RegionManagerLoader.java similarity index 87% rename from worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/RegionManagerReloader.java rename to worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/RegionManagerLoader.java index ca42a17fc..0343cdcd1 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/RegionManagerReloader.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/commands/task/RegionManagerLoader.java @@ -28,16 +28,16 @@ import static com.google.common.base.Preconditions.checkNotNull; -public class RegionManagerReloader implements Callable> { +public class RegionManagerLoader implements Callable> { private final Collection managers; - public RegionManagerReloader(Collection managers) { + public RegionManagerLoader(Collection managers) { checkNotNull(managers); this.managers = managers; } - public RegionManagerReloader(RegionManager... manager) { + public RegionManagerLoader(RegionManager... manager) { this(Arrays.asList(manager)); } diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/util/DomainInputResolver.java b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/util/DomainInputResolver.java index bd721ea07..17f7f0b5f 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/protection/util/DomainInputResolver.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/protection/util/DomainInputResolver.java @@ -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 createAddAllFunction(final DefaultDomain target) { return domain -> { target.addAll(domain); @@ -146,6 +150,10 @@ public Function createAddAllFunction(final Default }; } + /** + * @deprecated was only used for Future transformation. Can be replaced with {@code region.getOwners()::removeAll} (or getMembers). + */ + @Deprecated public Function createRemoveAllFunction(final DefaultDomain target) { return domain -> { target.removeAll(domain); diff --git a/worldguard-core/src/main/java/com/sk89q/worldguard/util/WorldGuardExceptionConverter.java b/worldguard-core/src/main/java/com/sk89q/worldguard/util/WorldGuardExceptionConverter.java index 92c5a062f..89492df2d 100644 --- a/worldguard-core/src/main/java/com/sk89q/worldguard/util/WorldGuardExceptionConverter.java +++ b/worldguard-core/src/main/java/com/sk89q/worldguard/util/WorldGuardExceptionConverter.java @@ -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); diff --git a/worldguard-legacy/src/main/java/com/sk89q/worldguard/bukkit/BukkitDebugHandler.java b/worldguard-legacy/src/main/java/com/sk89q/worldguard/bukkit/BukkitDebugHandler.java index 74e6ae9b6..67dd8ba7e 100644 --- a/worldguard-legacy/src/main/java/com/sk89q/worldguard/bukkit/BukkitDebugHandler.java +++ b/worldguard-legacy/src/main/java/com/sk89q/worldguard/bukkit/BukkitDebugHandler.java @@ -95,9 +95,8 @@ private 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()));