fancydialogs: Setup cloud command manager

This commit is contained in:
Oliver
2025-05-15 21:15:30 +02:00
committed by Oliver
parent b25a74df01
commit 92469ec4fb
3 changed files with 176 additions and 0 deletions

View File

@@ -55,6 +55,10 @@ dependencies {
implementation("de.oliver.FancyAnalytics:logger:0.0.6")
compileOnly("org.lushplugins:ChatColorHandler:5.1.3")
implementation("org.incendo:cloud-core:2.1.0-SNAPSHOT")
implementation("org.incendo:cloud-paper:2.0.0-SNAPSHOT")
implementation("org.incendo:cloud-annotations:2.1.0-SNAPSHOT")
annotationProcessor("org.incendo:cloud-annotations:2.1.0-SNAPSHOT")
implementation("org.jetbrains:annotations:24.0.0")
}

View File

@@ -1,6 +1,7 @@
package com.fancyinnovations.fancydialogs;
import com.fancyinnovations.fancydialogs.api.Dialog;
import com.fancyinnovations.fancydialogs.commands.CloudCommandManager;
import com.fancyinnovations.fancydialogs.config.FancyDialogsConfig;
import com.fancyinnovations.fancydialogs.listener.PlayerJoinListener;
import com.fancyinnovations.fancydialogs.registry.DialogRegistry;
@@ -92,6 +93,11 @@ public class FancyDialogsPlugin extends JavaPlugin {
registerListeners();
new CloudCommandManager(this, false)
.registerArguments()
.registerExceptionHandlers()
.registerCommands();
fancyLogger.info("Successfully enabled FancyDialogs version %s".formatted(getDescription().getVersion()));
}

View File

@@ -0,0 +1,166 @@
package com.fancyinnovations.fancydialogs.commands;
import com.fancyinnovations.fancydialogs.FancyDialogsPlugin;
import de.oliver.fancylib.translations.Translator;
import io.leangen.geantyref.TypeToken;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.annotations.AnnotationParser;
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
import org.incendo.cloud.bukkit.parser.WorldParser;
import org.incendo.cloud.bukkit.parser.location.LocationParser;
import org.incendo.cloud.exception.ArgumentParseException;
import org.incendo.cloud.exception.InvalidCommandSenderException;
import org.incendo.cloud.exception.NoPermissionException;
import org.incendo.cloud.exception.handling.ExceptionHandlerRegistration;
import org.incendo.cloud.exception.parsing.NumberParseException;
import org.incendo.cloud.exception.parsing.ParserException;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.paper.LegacyPaperCommandManager;
import org.incendo.cloud.parser.standard.BooleanParser;
import org.incendo.cloud.parser.standard.EnumParser;
import org.jetbrains.annotations.NotNull;
import static org.incendo.cloud.exception.handling.ExceptionHandler.unwrappingHandler;
public class CloudCommandManager {
private final @NotNull FancyDialogsPlugin plugin;
private final @NotNull LegacyPaperCommandManager<CommandSender> commandManager;
private final @NotNull AnnotationParser<CommandSender> annotationParser;
public CloudCommandManager(final @NotNull FancyDialogsPlugin plugin, final boolean isBrigadier) {
this.plugin = plugin;
// Creating instance of Cloud's LegacyPaperCommandManager, which is used for anything command-related.
this.commandManager = LegacyPaperCommandManager.createNative(plugin, ExecutionCoordinator.simpleCoordinator());
// Registering Brigadier, if available.
if (isBrigadier && commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER))
commandManager.registerBrigadier();
// Creating instance of AnnotationParser, which is used for parsing and registering commands.
this.annotationParser = new AnnotationParser<>(commandManager, CommandSender.class);
}
/**
* Registers arguments (parsers and suggestion providers) to the {@link LegacyPaperCommandManager}.
*/
public @NotNull CloudCommandManager registerArguments() {
// annotationParser.parse(NpcArgument.INSTANCE);
return this;
}
/**
* Registers exception handlers to the {@link LegacyPaperCommandManager}.
*/
public @NotNull CloudCommandManager registerExceptionHandlers() {
final Translator translator = plugin.getTranslator();
// Unwrapping some causes of ArgumentParseException to be handled in standalone exception handlers.
commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(NumberParseException.class));
commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(BooleanParser.BooleanParseException.class));
commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(EnumParser.EnumParseException.class));
commandManager.exceptionController().registerHandler(ArgumentParseException.class, unwrappingHandler(WorldParser.WorldParseException.class));
// Overriding some default handlers to send specialized messages.
commandManager.exceptionController().registerHandler(NoPermissionException.class, (exceptionContext) -> {
translator.translate("command_missing_permissions").send(exceptionContext.context().sender());
});
// DEV NOTE: No need to compare sender types until we decide to make a console-only command. Should get the job done for the time being.
commandManager.exceptionController().registerHandler(InvalidCommandSenderException.class, (exceptionContext) -> {
translator.translate("command_player_only").send(exceptionContext.context().sender());
});
commandManager.exceptionController().registerHandler(NumberParseException.class, (exceptionContext) -> {
translator.translate("command_invalid_number")
.replaceStripped("input", exceptionContext.exception().input())
.replace("min", exceptionContext.exception().range().min().toString())
.replace("max", exceptionContext.exception().range().max().toString())
.send(exceptionContext.context().sender());
});
commandManager.exceptionController().registerHandler(BooleanParser.BooleanParseException.class, (exceptionContext) -> {
translator.translate("command_invalid_boolean")
.replaceStripped("input", exceptionContext.exception().input())
.send(exceptionContext.context().sender());
});
commandManager.exceptionController().registerHandler(WorldParser.WorldParseException.class, (exceptionContext) -> {
translator.translate("command_invalid_world")
.replaceStripped("input", exceptionContext.exception().input())
.send(exceptionContext.context().sender());
});
// DEV NOTE: Temporary solution until https://github.com/Incendo/cloud-minecraft/pull/70 is merged.
commandManager.exceptionController().register(ExceptionHandlerRegistration.<CommandSender, ArgumentParseException>builder(TypeToken.get(ArgumentParseException.class))
.exceptionFilter(exception -> exception.getCause() instanceof ParserException parserException && parserException.argumentParserClass() == LocationParser.class)
.exceptionHandler(exceptionContext -> {
final ParserException exception = (ParserException) exceptionContext.exception().getCause();
final String input = exception.captionVariables()[0].value(); // Should never throw.
translator.translate("command_invalid_location")
.replaceStripped("input", !input.isBlank() ? input : "N/A") // Under certain conditions, input is not passed to the exception.
.send(exceptionContext.context().sender());
}).build()
);
// commandManager.exceptionController().registerHandler(EnumParser.EnumParseException.class, (exceptionContext) -> {
// String translationKey = "command_invalid_enum_generic";
// // Comparing exception enum class and choosing specialized messages.
// if (exceptionContext.exception().enumClass() == ListCMD.SortType.class)
// translationKey = "command_invalid_list_sort_type";
// else if (exceptionContext.exception().enumClass() == NearbyCMD.SortType.class)
// translationKey = "command_invalid_nearby_sort_type";
// else if (exceptionContext.exception().enumClass() == EntityType.class)
// translationKey = "command_invalid_entity_type";
// else if (exceptionContext.exception().enumClass() == GlowingColor.class)
// translationKey = "command_invalid_glowing_color";
// // Sending error message to the sender. In case no specialized message has been found, a generic one is used instead.
// translator.translate(translationKey)
// .replaceStripped("input", exceptionContext.exception().input())
// .replace("enum", exceptionContext.exception().enumClass().getSimpleName().toLowerCase())
// .send(exceptionContext.context().sender());
// });
// // ReplyingParseException is thrown from custom argument types and is handled there.
// commandManager.exceptionController().registerHandler(ReplyingParseException.class, context -> context.exception().runnable().run());
// // InvalidSyntaxException is thrown when user specified syntax don't match any command.
// commandManager.exceptionController().registerHandler(InvalidSyntaxException.class, (exceptionContext) -> {
// // Creating a StringBuilder which is then appended with (known/existing) command literals.
// final StringBuilder translationKeyBuilder = new StringBuilder("command_syntax.");
// // Iterating over current command chain and appending literals, as described above.
// exceptionContext.exception().currentChain().stream()
// .filter(c -> c.type() == CommandComponent.ComponentType.LITERAL)
// .forEach(literal -> translationKeyBuilder.append(literal.name()).append(' '));
// // Trimming input (last character ends up being blank) and replacing whitespaces with underscores, as that's how translations are defined inside the language file.
// final String translationKey = translationKeyBuilder.toString().trim().replace(' ', '_');
// // Getting the message, it's not finished as there we need to handle fallback language etc.
// final @Nullable Message message = Optional.ofNullable(plugin.getTranslator().getSelectedLanguage().getMessage(translationKey))
// .orElse(plugin.getTranslator().getFallbackLanguage().getMessage(translationKey));
// // "Fall-backing" to generic syntax error, if no specialized syntax message has been defined in the language file.
// if (message == null) {
// plugin.getTranslator().translate("command_invalid_syntax_generic")
// .replace("syntax", exceptionContext.exception().correctSyntax())
// .send(exceptionContext.context().sender());
// return;
// }
// message.send(exceptionContext.context().sender());
// });
// Returning this instance of CloudCommandManager to keep "builder-like" flow.
return this;
}
/**
* Registers plugin commands to the {@link LegacyPaperCommandManager}.
*/
public @NotNull CloudCommandManager registerCommands() {
// annotationParser.parse(AttributeCMD.INSTANCE);
return this;
}
/**
* Returns the internal {@link LegacyPaperCommandManager} associated with this instance of {@link CloudCommandManager}.
*/
public @NotNull LegacyPaperCommandManager<CommandSender> getCommandManager() {
return commandManager;
}
/**
* Returns the internal {@link AnnotationParser} associated with this instance of {@link CloudCommandManager}.
*/
public @NotNull AnnotationParser<CommandSender> getAnnotationParser() {
return annotationParser;
}
}