mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-07-05 16:40:04 +00:00
8c0195970b
* Consistenty use javax annotations. - Unfortunately jetbrains annotations seem to be exposed transitively via core somewhere, but with the correct IDE settings, annotations can be defaulted to javax - Cleaning up of import order in #1195 - Must be merged before #1195 * Add and apply .editorconfig from P2 - Does not rearrange entries * Address some comments * add back some javadoc comments * Address final comments Co-authored-by: NotMyFault <mc.cache@web.de>
220 lines
8.9 KiB
Java
220 lines
8.9 KiB
Java
/*
|
|
* WorldEdit, a Minecraft world manipulation toolkit
|
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
|
* Copyright (C) WorldEdit team and contributors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package com.sk89q.worldedit.command.util;
|
|
|
|
import com.fastasyncworldedit.core.configuration.Caption;
|
|
import com.google.common.base.Strings;
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.util.concurrent.ListenableFuture;
|
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
|
import com.sk89q.worldedit.extension.platform.Actor;
|
|
import com.sk89q.worldedit.internal.command.exception.ExceptionConverter;
|
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
|
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
|
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
|
import com.sk89q.worldedit.util.task.FutureForwardingTask;
|
|
import com.sk89q.worldedit.util.task.Supervisor;
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.enginehub.piston.exception.CommandException;
|
|
import org.enginehub.piston.exception.CommandExecutionException;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.util.concurrent.Callable;
|
|
import java.util.function.Consumer;
|
|
|
|
import static com.google.common.base.Preconditions.checkArgument;
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
|
|
public final class AsyncCommandBuilder<T> {
|
|
|
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
|
|
|
private final Callable<T> callable;
|
|
private final Actor sender;
|
|
|
|
@Nullable
|
|
private Supervisor supervisor;
|
|
@Nullable
|
|
private String description;
|
|
@Nullable
|
|
private Component delayMessage;
|
|
@Nullable
|
|
private Component workingMessage;
|
|
|
|
@Nullable
|
|
private Component successMessage;
|
|
@Nullable
|
|
private Consumer<T> consumer;
|
|
|
|
@Nullable
|
|
private Component failureMessage;
|
|
@Nullable
|
|
private ExceptionConverter exceptionConverter;
|
|
|
|
private AsyncCommandBuilder(Callable<T> callable, Actor sender) {
|
|
checkNotNull(callable);
|
|
checkNotNull(sender);
|
|
this.callable = callable;
|
|
this.sender = sender;
|
|
}
|
|
|
|
public static <T> AsyncCommandBuilder<T> wrap(Callable<T> callable, Actor sender) {
|
|
return new AsyncCommandBuilder<>(callable, sender);
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> registerWithSupervisor(Supervisor supervisor, String description) {
|
|
this.supervisor = checkNotNull(supervisor);
|
|
this.description = checkNotNull(description);
|
|
return this;
|
|
}
|
|
|
|
@Deprecated
|
|
public AsyncCommandBuilder<T> sendMessageAfterDelay(String message) {
|
|
return sendMessageAfterDelay(TextComponent.of(checkNotNull(message)));
|
|
}
|
|
|
|
@Deprecated
|
|
public AsyncCommandBuilder<T> sendMessageAfterDelay(Component message) {
|
|
return setDelayMessage(message);
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> setDelayMessage(Component message) {
|
|
this.delayMessage = checkNotNull(message);
|
|
return this;
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> setWorkingMessage(Component message) {
|
|
checkNotNull(this.delayMessage, "Must have a delay message if using a working message");
|
|
this.workingMessage = checkNotNull(message);
|
|
return this;
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> onSuccess(@Nullable Component message, @Nullable Consumer<T> consumer) {
|
|
checkArgument(message != null || consumer != null, "Can't have null message AND consumer");
|
|
this.successMessage = message;
|
|
this.consumer = consumer;
|
|
return this;
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> onSuccess(@Nullable String message, @Nullable Consumer<T> consumer) {
|
|
checkArgument(message != null || consumer != null, "Can't have null message AND consumer");
|
|
this.successMessage = message == null ? null : TextComponent.of(message, TextColor.LIGHT_PURPLE);
|
|
this.consumer = consumer;
|
|
return this;
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> onFailure(@Nullable Component message, @Nullable ExceptionConverter exceptionConverter) {
|
|
checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter");
|
|
this.failureMessage = message;
|
|
this.exceptionConverter = exceptionConverter;
|
|
return this;
|
|
}
|
|
|
|
public AsyncCommandBuilder<T> onFailure(@Nullable String message, @Nullable ExceptionConverter exceptionConverter) {
|
|
checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter");
|
|
this.failureMessage = message == null ? null : ErrorFormat.wrap(message);
|
|
this.exceptionConverter = exceptionConverter;
|
|
return this;
|
|
}
|
|
|
|
public ListenableFuture<T> buildAndExec(ListeningExecutorService executor) {
|
|
final ListenableFuture<T> future = checkNotNull(executor).submit(this::runTask);
|
|
if (delayMessage != null) {
|
|
FutureProgressListener.addProgressListener(future, sender, delayMessage);
|
|
}
|
|
if (supervisor != null && description != null) {
|
|
supervisor.monitor(FutureForwardingTask.create(future, description, sender));
|
|
}
|
|
return future;
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
private T runTask() {
|
|
T result = null;
|
|
try {
|
|
result = callable.call();
|
|
if (consumer != null) {
|
|
consumer.accept(result);
|
|
}
|
|
if (successMessage != null) {
|
|
sender.print(successMessage);
|
|
}
|
|
} catch (Throwable orig) {
|
|
Component failure = failureMessage != null ? failureMessage : TextComponent.of("An error occurred");
|
|
try {
|
|
if (exceptionConverter != null) {
|
|
try {
|
|
if (orig instanceof com.sk89q.minecraft.util.commands.CommandException) {
|
|
throw new CommandExecutionException(orig, ImmutableList.of());
|
|
}
|
|
exceptionConverter.convert(orig);
|
|
throw orig;
|
|
} catch (CommandException converted) {
|
|
Component message;
|
|
|
|
// TODO remove this once WG migrates to piston and can use piston exceptions everywhere
|
|
message = tryExtractOldCommandException(converted);
|
|
|
|
if (message == null) {
|
|
if (Strings.isNullOrEmpty(converted.getMessage())) {
|
|
message = Caption.of("worldedit.error.unknown");
|
|
} else {
|
|
message = converted.getRichMessage();
|
|
}
|
|
}
|
|
sender.print(failure.append(TextComponent.of(": ")).append(message));
|
|
}
|
|
} else {
|
|
throw orig;
|
|
}
|
|
} catch (Throwable unknown) {
|
|
sender.print(failure.append(Caption.of("worldedit.command.error.report")));
|
|
LOGGER.error("Uncaught exception occurred in task: " + description, orig);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// this is needed right now since worldguard is still on the 2011 command framework which throws and converts
|
|
// com.sk89q.minecraft.util.commands.CommandException. the ExceptionConverter currently expects converted
|
|
// exceptions to be org.enginehub.piston.CommandException, throw it wraps the resulting InvocationTargetException in
|
|
// a CommandExecutionException. here, we unwrap those layers to retrieve the original WG error message
|
|
@SuppressWarnings("deprecation")
|
|
private Component tryExtractOldCommandException(CommandException converted) {
|
|
Component message = null;
|
|
if (converted instanceof CommandExecutionException) {
|
|
Throwable parentCause = converted;
|
|
while ((parentCause = parentCause.getCause()) != null) {
|
|
if (parentCause instanceof com.sk89q.minecraft.util.commands.CommandException) {
|
|
final String msg = parentCause.getMessage();
|
|
if (!Strings.isNullOrEmpty(msg)) {
|
|
message = TextComponent.of(msg);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return message;
|
|
}
|
|
|
|
}
|