diff --git a/docs/acf-core/co/aikar/commands/RegisteredCommand.html b/docs/acf-core/co/aikar/commands/RegisteredCommand.html
index dd952ed5..c5751a7e 100644
--- a/docs/acf-core/co/aikar/commands/RegisteredCommand.html
+++ b/docs/acf-core/co/aikar/commands/RegisteredCommand.html
@@ -246,7 +246,7 @@ extends
preCommand
-public void preCommand()
+public void preCommand()
@@ -255,7 +255,7 @@ extends
postCommand
-public void postCommand()
+public void postCommand()
@@ -265,7 +265,7 @@ extends
getPermission
@Deprecated
-public String getPermission()
+public String getPermission()
Deprecated.
- See Also:
@@ -279,7 +279,7 @@ public
-
getRequiredPermissions
-public Set<String> getRequiredPermissions()
+public Set<String> getRequiredPermissions()
@@ -288,7 +288,7 @@ public
-
requiresPermission
-public boolean requiresPermission(String permission)
+public boolean requiresPermission(String permission)
@@ -297,7 +297,7 @@ public
-
getPrefSubCommand
-public String getPrefSubCommand()
+public String getPrefSubCommand()
@@ -306,7 +306,7 @@ public
-
getSyntaxText
-public String getSyntaxText()
+public String getSyntaxText()
@@ -315,7 +315,7 @@ public
-
getHelpText
-public String getHelpText()
+public String getHelpText()
@@ -324,7 +324,7 @@ public
-
isPrivate
-public boolean isPrivate()
+public boolean isPrivate()
@@ -333,7 +333,7 @@ public
-
getCommand
-public String getCommand()
+public String getCommand()
@@ -342,7 +342,7 @@ public
-
addSubcommand
-public void addSubcommand(String cmd)
+public void addSubcommand(String cmd)
@@ -351,7 +351,7 @@ public
-
addSubcommands
-public void addSubcommands(Collection<String> cmd)
+public void addSubcommands(Collection<String> cmd)
@@ -360,7 +360,7 @@ public
-
getAnnotation
-public <T extends Annotation> T getAnnotation(Class<T> annotation)
+public <T extends Annotation> T getAnnotation(Class<T> annotation)
diff --git a/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html b/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html
index 0439ef71..b79d871b 100644
--- a/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html
+++ b/docs/acf-core/src-html/co/aikar/commands/RegisteredCommand.html
@@ -158,208 +158,210 @@
150 method.invoke(scope, passedArgs.values().toArray());
151 } catch (Exception e) {
152 handleException(sender, args, e);
-153 }
-154 postCommand();
-155 }
-156
-157 public void preCommand() {
-158 }
-159
-160 public void postCommand() {
-161 }
-162
-163 void handleException(CommandIssuer sender, List<String> args, Exception e) {
-164 if (e instanceof InvocationTargetException && e.getCause() instanceof InvalidCommandArgument) {
-165 e = (Exception) e.getCause();
-166 }
-167 if (e instanceof ShowCommandHelp) {
-168 ShowCommandHelp showHelp = (ShowCommandHelp) e;
-169 CommandHelp commandHelp = manager.generateCommandHelp();
-170 if (showHelp.search) {
-171 commandHelp.setSearch(showHelp.searchArgs == null ? args : showHelp.searchArgs);
-172 }
-173 commandHelp.showHelp(sender);
-174 } else if (e instanceof InvalidCommandArgument) {
-175 InvalidCommandArgument invalidCommandArg = (InvalidCommandArgument) e;
-176 if (invalidCommandArg.key != null) {
-177 sender.sendMessage(MessageType.ERROR, invalidCommandArg.key, invalidCommandArg.replacements);
-178 } else if (e.getMessage() != null && !e.getMessage().isEmpty()) {
-179 sender.sendMessage(MessageType.ERROR, MessageKeys.ERROR_PREFIX, "{message}", e.getMessage());
-180 }
-181 if (invalidCommandArg.showSyntax) {
-182 scope.showSyntax(sender, this);
-183 }
-184 } else {
-185 try {
-186 if (!this.manager.handleUncaughtException(scope, this, sender, args, e)) {
-187 sender.sendMessage(MessageType.ERROR, MessageKeys.ERROR_PERFORMING_COMMAND);
-188 }
-189 boolean hasExceptionHandler = this.manager.defaultExceptionHandler != null || this.scope.getExceptionHandler() != null;
-190 if (!hasExceptionHandler || this.manager.logUnhandledExceptions) {
-191 this.manager.log(LogLevel.ERROR, "Exception in command: " + command + " " + ACFUtil.join(args), e);
-192 }
-193 } catch (Exception e2) {
-194 this.manager.log(LogLevel.ERROR, "Exception in handleException for command: " + command + " " + ACFUtil.join(args), e);
-195 this.manager.log(LogLevel.ERROR, "Exception triggered by exception handler:", e2);
-196 }
-197 }
-198 }
-199
-200 @Nullable
-201 Map<String, Object> resolveContexts(CommandIssuer sender, List<String> args) throws InvalidCommandArgument {
-202 return resolveContexts(sender, args, parameters.length);
-203 }
-204
-205 @Nullable
-206 Map<String, Object> resolveContexts(CommandIssuer sender, List<String> args, int argLimit) throws InvalidCommandArgument {
-207 args = new ArrayList<>(args);
-208 String[] origArgs = args.toArray(new String[args.size()]);
-209 Map<String, Object> passedArgs = new LinkedHashMap<>();
-210 int remainingRequired = requiredResolvers;
-211 CommandOperationContext opContext = CommandManager.getCurrentCommandOperationContext();
-212 for (int i = 0; i < parameters.length && i < argLimit; i++) {
-213 boolean isLast = i == parameters.length - 1;
-214 boolean allowOptional = remainingRequired == 0;
-215 final CommandParameter<CEC> parameter = parameters[i];
-216 if (!parameter.canConsumeInput()) {
-217 argLimit++;
-218 }
-219 final String parameterName = parameter.getName();
-220 final Class<?> type = parameter.getType();
-221 //noinspection unchecked
-222 final ContextResolver<?, CEC> resolver = parameter.getResolver();
-223 //noinspection unchecked
-224 CEC context = (CEC) this.manager.createCommandContext(this, parameter, sender, args, i, passedArgs);
-225 boolean requiresInput = parameter.requiresInput();
-226 if (requiresInput && remainingRequired > 0) {
-227 remainingRequired--;
-228 }
-229
-230 Set<String> parameterPermissions = parameter.getRequiredPermissions();
-231 if (args.isEmpty() && !(isLast && type == String[].class)) {
-232 if (allowOptional && parameter.getDefaultValue() != null) {
-233 args.add(parameter.getDefaultValue());
-234 } else if (allowOptional && parameter.isOptional()) {
-235 if (!this.manager.hasPermission(sender, parameterPermissions)) {
-236 sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED_PARAMETER, "{param}", parameterName);
-237 throw new InvalidCommandArgument(false);
-238 }
-239 Object value = parameter.isOptionalResolver() ? resolver.getContext(context) : null;
-240
-241 if (value == null && parameter.getClass().isPrimitive()) {
-242 throw new IllegalStateException("Parameter " + parameter.getName() + " is primitive and does not support Optional.");
-243 }
-244 //noinspection unchecked
-245 this.manager.conditions.validateConditions(context, value);
-246 passedArgs.put(parameterName, value);
-247 continue;
-248 } else if (requiresInput) {
-249 scope.showSyntax(sender, this);
-250 return null;
-251 }
-252 } else {
-253 if (!this.manager.hasPermission(sender, parameterPermissions)) {
-254 sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED_PARAMETER, "{param}", parameterName);
-255 throw new InvalidCommandArgument(false);
-256 }
-257 }
-258
-259 if (parameter.getValues() != null) {
-260 String arg = !args.isEmpty() ? args.get(0) : "";
-261
-262 Set<String> possible = new HashSet<>();
-263 CommandCompletions commandCompletions = this.manager.getCommandCompletions();
-264 for (String s : parameter.getValues()) {
-265 if ("*".equals(s) || "@completions".equals(s)) {
-266 s = commandCompletions.findDefaultCompletion(this, origArgs);
-267 }
-268 //noinspection unchecked
-269 List<String> check = commandCompletions.getCompletionValues(this, sender, s, origArgs, opContext.isAsync());
-270 if (!check.isEmpty()) {
-271 possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList()));
-272 } else {
-273 possible.add(s.toLowerCase());
-274 }
-275 }
-276 if (!possible.contains(arg.toLowerCase())) {
-277 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF,
-278 "{valid}", ACFUtil.join(possible, ", "));
-279 }
-280 }
-281
-282 Object paramValue = resolver.getContext(context);
+153 } finally {
+154 postCommand();
+155 }
+156 }
+157
+158 public void preCommand() {
+159 }
+160
+161 public void postCommand() {
+162 }
+163
+164 void handleException(CommandIssuer sender, List<String> args, Exception e) {
+165 if (e instanceof InvocationTargetException && e.getCause() instanceof InvalidCommandArgument) {
+166 e = (Exception) e.getCause();
+167 }
+168 if (e instanceof ShowCommandHelp) {
+169 ShowCommandHelp showHelp = (ShowCommandHelp) e;
+170 CommandHelp commandHelp = manager.generateCommandHelp();
+171 if (showHelp.search) {
+172 commandHelp.setSearch(showHelp.searchArgs == null ? args : showHelp.searchArgs);
+173 }
+174 commandHelp.showHelp(sender);
+175 } else if (e instanceof InvalidCommandArgument) {
+176 InvalidCommandArgument invalidCommandArg = (InvalidCommandArgument) e;
+177 if (invalidCommandArg.key != null) {
+178 sender.sendMessage(MessageType.ERROR, invalidCommandArg.key, invalidCommandArg.replacements);
+179 } else if (e.getMessage() != null && !e.getMessage().isEmpty()) {
+180 sender.sendMessage(MessageType.ERROR, MessageKeys.ERROR_PREFIX, "{message}", e.getMessage());
+181 }
+182 if (invalidCommandArg.showSyntax) {
+183 scope.showSyntax(sender, this);
+184 }
+185 } else {
+186 try {
+187 if (!this.manager.handleUncaughtException(scope, this, sender, args, e)) {
+188 sender.sendMessage(MessageType.ERROR, MessageKeys.ERROR_PERFORMING_COMMAND);
+189 }
+190 boolean hasExceptionHandler = this.manager.defaultExceptionHandler != null || this.scope.getExceptionHandler() != null;
+191 if (!hasExceptionHandler || this.manager.logUnhandledExceptions) {
+192 this.manager.log(LogLevel.ERROR, "Exception in command: " + command + " " + ACFUtil.join(args), e);
+193 }
+194 } catch (Exception e2) {
+195 this.manager.log(LogLevel.ERROR, "Exception in handleException for command: " + command + " " + ACFUtil.join(args), e);
+196 this.manager.log(LogLevel.ERROR, "Exception triggered by exception handler:", e2);
+197 }
+198 }
+199 }
+200
+201 @Nullable
+202 Map<String, Object> resolveContexts(CommandIssuer sender, List<String> args) throws InvalidCommandArgument {
+203 return resolveContexts(sender, args, parameters.length);
+204 }
+205
+206 @Nullable
+207 Map<String, Object> resolveContexts(CommandIssuer sender, List<String> args, int argLimit) throws InvalidCommandArgument {
+208 args = new ArrayList<>(args);
+209 String[] origArgs = args.toArray(new String[args.size()]);
+210 Map<String, Object> passedArgs = new LinkedHashMap<>();
+211 int remainingRequired = requiredResolvers;
+212 CommandOperationContext opContext = CommandManager.getCurrentCommandOperationContext();
+213 for (int i = 0; i < parameters.length && i < argLimit; i++) {
+214 boolean isLast = i == parameters.length - 1;
+215 boolean allowOptional = remainingRequired == 0;
+216 final CommandParameter<CEC> parameter = parameters[i];
+217 if (!parameter.canConsumeInput()) {
+218 argLimit++;
+219 }
+220 final String parameterName = parameter.getName();
+221 final Class<?> type = parameter.getType();
+222 //noinspection unchecked
+223 final ContextResolver<?, CEC> resolver = parameter.getResolver();
+224 //noinspection unchecked
+225 CEC context = (CEC) this.manager.createCommandContext(this, parameter, sender, args, i, passedArgs);
+226 boolean requiresInput = parameter.requiresInput();
+227 if (requiresInput && remainingRequired > 0) {
+228 remainingRequired--;
+229 }
+230
+231 Set<String> parameterPermissions = parameter.getRequiredPermissions();
+232 if (args.isEmpty() && !(isLast && type == String[].class)) {
+233 if (allowOptional && parameter.getDefaultValue() != null) {
+234 args.add(parameter.getDefaultValue());
+235 } else if (allowOptional && parameter.isOptional()) {
+236 Object value;
+237 if (!parameter.isOptionalResolver() || !this.manager.hasPermission(sender, parameterPermissions)) {
+238 value = null;
+239 } else {
+240 value = resolver.getContext(context);
+241 }
+242
+243 if (value == null && parameter.getClass().isPrimitive()) {
+244 throw new IllegalStateException("Parameter " + parameter.getName() + " is primitive and does not support Optional.");
+245 }
+246 //noinspection unchecked
+247 this.manager.conditions.validateConditions(context, value);
+248 passedArgs.put(parameterName, value);
+249 continue;
+250 } else if (requiresInput) {
+251 scope.showSyntax(sender, this);
+252 return null;
+253 }
+254 } else {
+255 if (!this.manager.hasPermission(sender, parameterPermissions)) {
+256 sender.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED_PARAMETER, "{param}", parameterName);
+257 throw new InvalidCommandArgument(false);
+258 }
+259 }
+260
+261 if (parameter.getValues() != null) {
+262 String arg = !args.isEmpty() ? args.get(0) : "";
+263
+264 Set<String> possible = new HashSet<>();
+265 CommandCompletions commandCompletions = this.manager.getCommandCompletions();
+266 for (String s : parameter.getValues()) {
+267 if ("*".equals(s) || "@completions".equals(s)) {
+268 s = commandCompletions.findDefaultCompletion(this, origArgs);
+269 }
+270 //noinspection unchecked
+271 List<String> check = commandCompletions.getCompletionValues(this, sender, s, origArgs, opContext.isAsync());
+272 if (!check.isEmpty()) {
+273 possible.addAll(check.stream().map(String::toLowerCase).collect(Collectors.toList()));
+274 } else {
+275 possible.add(s.toLowerCase());
+276 }
+277 }
+278 if (!possible.contains(arg.toLowerCase())) {
+279 throw new InvalidCommandArgument(MessageKeys.PLEASE_SPECIFY_ONE_OF,
+280 "{valid}", ACFUtil.join(possible, ", "));
+281 }
+282 }
283
-284 //noinspection unchecked
-285 this.manager.conditions.validateConditions(context, paramValue);
-286 passedArgs.put(parameterName, paramValue);
-287 }
-288 return passedArgs;
-289 }
-290
-291 boolean hasPermission(CommandIssuer issuer) {
-292 return this.manager.hasPermission(issuer, getRequiredPermissions());
-293 }
-294
-295 /**
-296 * @see #getRequiredPermissions()
-297 * @deprecated
-298 */
-299 @Deprecated
-300 public String getPermission() {
-301 if (this.permission == null || this.permission.isEmpty()) {
-302 return null;
-303 }
-304 return ACFPatterns.COMMA.split(this.permission)[0];
-305 }
-306
-307 void computePermissions() {
-308 this.permissions.clear();
-309 this.permissions.addAll(this.scope.getRequiredPermissions());
-310 if (this.permission != null && !this.permission.isEmpty()) {
-311 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission)));
-312 }
-313 }
-314
-315 public Set<String> getRequiredPermissions() {
-316 return this.permissions;
-317 }
-318
-319 public boolean requiresPermission(String permission) {
-320 return getRequiredPermissions().contains(permission);
-321 }
-322
-323 public String getPrefSubCommand() {
-324 return prefSubCommand;
-325 }
-326
-327 public String getSyntaxText() {
-328 return syntaxText;
-329 }
-330
-331 public String getHelpText() {
-332 return helpText != null ? helpText : "";
-333 }
-334
-335 public boolean isPrivate() {
-336 return isPrivate;
-337 }
-338
-339 public String getCommand() {
-340 return command;
-341 }
-342
-343 public void addSubcommand(String cmd) {
-344 this.registeredSubcommands.add(cmd);
-345 }
-346
-347 public void addSubcommands(Collection<String> cmd) {
-348 this.registeredSubcommands.addAll(cmd);
-349 }
-350
-351 public <T extends Annotation> T getAnnotation(Class<T> annotation) {
-352 return method.getAnnotation(annotation);
-353 }
-354}
+284 Object paramValue = resolver.getContext(context);
+285
+286 //noinspection unchecked
+287 this.manager.conditions.validateConditions(context, paramValue);
+288 passedArgs.put(parameterName, paramValue);
+289 }
+290 return passedArgs;
+291 }
+292
+293 boolean hasPermission(CommandIssuer issuer) {
+294 return this.manager.hasPermission(issuer, getRequiredPermissions());
+295 }
+296
+297 /**
+298 * @see #getRequiredPermissions()
+299 * @deprecated
+300 */
+301 @Deprecated
+302 public String getPermission() {
+303 if (this.permission == null || this.permission.isEmpty()) {
+304 return null;
+305 }
+306 return ACFPatterns.COMMA.split(this.permission)[0];
+307 }
+308
+309 void computePermissions() {
+310 this.permissions.clear();
+311 this.permissions.addAll(this.scope.getRequiredPermissions());
+312 if (this.permission != null && !this.permission.isEmpty()) {
+313 this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission)));
+314 }
+315 }
+316
+317 public Set<String> getRequiredPermissions() {
+318 return this.permissions;
+319 }
+320
+321 public boolean requiresPermission(String permission) {
+322 return getRequiredPermissions().contains(permission);
+323 }
+324
+325 public String getPrefSubCommand() {
+326 return prefSubCommand;
+327 }
+328
+329 public String getSyntaxText() {
+330 return syntaxText;
+331 }
+332
+333 public String getHelpText() {
+334 return helpText != null ? helpText : "";
+335 }
+336
+337 public boolean isPrivate() {
+338 return isPrivate;
+339 }
+340
+341 public String getCommand() {
+342 return command;
+343 }
+344
+345 public void addSubcommand(String cmd) {
+346 this.registeredSubcommands.add(cmd);
+347 }
+348
+349 public void addSubcommands(Collection<String> cmd) {
+350 this.registeredSubcommands.addAll(cmd);
+351 }
+352
+353 public <T extends Annotation> T getAnnotation(Class<T> annotation) {
+354 return method.getAnnotation(annotation);
+355 }
+356}