Add adventure based help menu
This commit is contained in:
parent
bad944e1a5
commit
3f96837cf1
8 changed files with 480 additions and 16 deletions
|
|
@ -30,8 +30,11 @@ import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public final class CommandHelpHandler<C> {
|
public final class CommandHelpHandler<C> {
|
||||||
|
|
||||||
|
|
@ -142,31 +145,51 @@ public final class CommandHelpHandler<C> {
|
||||||
final String rootFragment = queryFragments[0];
|
final String rootFragment = queryFragments[0];
|
||||||
|
|
||||||
/* Determine which command we are querying for */
|
/* Determine which command we are querying for */
|
||||||
Command<C> queryCommand = null;
|
final List<Command<C>> availableCommands = new LinkedList<>();
|
||||||
String queryCommandName = "";
|
final Set<String> availableCommandLabels = new HashSet<>();
|
||||||
|
|
||||||
outer:
|
|
||||||
for (final VerboseHelpEntry<C> entry : verboseEntries) {
|
for (final VerboseHelpEntry<C> entry : verboseEntries) {
|
||||||
final Command<C> command = entry.getCommand();
|
final Command<C> command = entry.getCommand();
|
||||||
@SuppressWarnings("unchecked") final StaticArgument<C> staticArgument = (StaticArgument<C>) command.getArguments()
|
@SuppressWarnings("unchecked") final StaticArgument<C> staticArgument = (StaticArgument<C>) command.getArguments()
|
||||||
.get(0);
|
.get(0);
|
||||||
for (final String alias : staticArgument.getAliases()) {
|
for (final String alias : staticArgument.getAliases()) {
|
||||||
if (alias.equalsIgnoreCase(rootFragment)) {
|
if (alias.toLowerCase(Locale.ENGLISH).startsWith(rootFragment.toLowerCase(Locale.ENGLISH))) {
|
||||||
/* We found our command */
|
availableCommands.add(command);
|
||||||
queryCommand = command;
|
availableCommandLabels.add(staticArgument.getName());
|
||||||
queryCommandName = staticArgument.getName();
|
break;
|
||||||
break outer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rootFragment.equalsIgnoreCase(staticArgument.getName())) {
|
||||||
|
availableCommandLabels.clear();
|
||||||
|
availableCommands.clear();
|
||||||
|
availableCommandLabels.add(staticArgument.getName());
|
||||||
|
availableCommands.add(command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No command found, return all possible commands */
|
/* No command found, return all possible commands */
|
||||||
if (queryCommand == null) {
|
if (availableCommands.isEmpty()) {
|
||||||
return new IndexHelpTopic<>(verboseEntries);
|
return new IndexHelpTopic<>(Collections.emptyList());
|
||||||
|
} else if (availableCommandLabels.size() > 1) {
|
||||||
|
final List<VerboseHelpEntry<C>> syntaxHints = new ArrayList<>();
|
||||||
|
for (final Command<C> command : availableCommands) {
|
||||||
|
final List<CommandArgument<C, ?>> arguments = command.getArguments();
|
||||||
|
final String description = command.getCommandMeta().getOrDefault("description", "");
|
||||||
|
syntaxHints.add(new VerboseHelpEntry<>(command,
|
||||||
|
this.commandManager.getCommandSyntaxFormatter()
|
||||||
|
.apply(arguments, null),
|
||||||
|
description));
|
||||||
|
}
|
||||||
|
syntaxHints.sort(Comparator.comparing(VerboseHelpEntry::getSyntaxString));
|
||||||
|
return new IndexHelpTopic<>(syntaxHints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Traverse command to find the most specific help topic */
|
/* Traverse command to find the most specific help topic */
|
||||||
final CommandTree.Node<CommandArgument<C, ?>> node = this.commandManager.getCommandTree().getNamedNode(queryCommandName);
|
final CommandTree.Node<CommandArgument<C, ?>> node = this.commandManager.getCommandTree()
|
||||||
|
.getNamedNode(availableCommandLabels.iterator()
|
||||||
|
.next());
|
||||||
|
|
||||||
final List<CommandArgument<C, ?>> traversedNodes = new LinkedList<>();
|
final List<CommandArgument<C, ?>> traversedNodes = new LinkedList<>();
|
||||||
CommandTree.Node<CommandArgument<C, ?>> head = node;
|
CommandTree.Node<CommandArgument<C, ?>> head = node;
|
||||||
|
|
@ -196,7 +219,9 @@ public final class CommandHelpHandler<C> {
|
||||||
/* Attempt to parse the longest possible description for the children */
|
/* Attempt to parse the longest possible description for the children */
|
||||||
final List<String> childSuggestions = new LinkedList<>();
|
final List<String> childSuggestions = new LinkedList<>();
|
||||||
for (final CommandTree.Node<CommandArgument<C, ?>> child : head.getChildren()) {
|
for (final CommandTree.Node<CommandArgument<C, ?>> child : head.getChildren()) {
|
||||||
childSuggestions.add(this.commandManager.getCommandSyntaxFormatter().apply(traversedNodes, child));
|
final List<CommandArgument<C, ?>> traversedNodesSub = new LinkedList<>(traversedNodes);
|
||||||
|
traversedNodesSub.add(child.getValue());
|
||||||
|
childSuggestions.add(this.commandManager.getCommandSyntaxFormatter().apply(traversedNodesSub, child));
|
||||||
}
|
}
|
||||||
return new MultiHelpTopic<>(currentDescription, childSuggestions);
|
return new MultiHelpTopic<>(currentDescription, childSuggestions);
|
||||||
}
|
}
|
||||||
|
|
@ -250,7 +275,6 @@ public final class CommandHelpHandler<C> {
|
||||||
*
|
*
|
||||||
* @return {@code true} if the topic is entry, else {@code false}
|
* @return {@code true} if the topic is entry, else {@code false}
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return this.getEntries().isEmpty();
|
return this.getEntries().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,13 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>sonatype</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.intellectualsites</groupId>
|
<groupId>com.intellectualsites</groupId>
|
||||||
|
|
@ -82,5 +89,15 @@
|
||||||
<artifactId>commodore</artifactId>
|
<artifactId>commodore</artifactId>
|
||||||
<version>1.9</version>
|
<version>1.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.intellectualsites</groupId>
|
||||||
|
<artifactId>cloud-minecraft-extras</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-platform-bukkit</artifactId>
|
||||||
|
<version>4.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import com.intellectualsites.commands.execution.AsynchronousCommandExecutionCoor
|
||||||
import com.intellectualsites.commands.execution.CommandExecutionCoordinator;
|
import com.intellectualsites.commands.execution.CommandExecutionCoordinator;
|
||||||
import com.intellectualsites.commands.meta.SimpleCommandMeta;
|
import com.intellectualsites.commands.meta.SimpleCommandMeta;
|
||||||
import com.intellectualsites.commands.paper.PaperCommandManager;
|
import com.intellectualsites.commands.paper.PaperCommandManager;
|
||||||
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
|
|
@ -82,6 +83,9 @@ public final class BukkitTest extends JavaPlugin {
|
||||||
Function.identity()
|
Function.identity()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final BukkitAudiences bukkitAudiences = BukkitAudiences.create(this);
|
||||||
|
final MinecraftHelp<CommandSender> minecraftHelp = new MinecraftHelp<>(bukkitAudiences::audience, mgr);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
((PaperCommandManager<CommandSender>) mgr).registerBrigadier();
|
((PaperCommandManager<CommandSender>) mgr).registerBrigadier();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
|
@ -176,7 +180,16 @@ public final class BukkitTest extends JavaPlugin {
|
||||||
.argument(BooleanArgument.required("bool"))
|
.argument(BooleanArgument.required("bool"))
|
||||||
.argument(StringArgument.required("string"))
|
.argument(StringArgument.required("string"))
|
||||||
.handler(c -> c.getSender().sendMessage("Executed the command"))
|
.handler(c -> c.getSender().sendMessage("Executed the command"))
|
||||||
.build());
|
.build())
|
||||||
|
.command(mgr.commandBuilder("annotationass").handler(c -> c.getSender()
|
||||||
|
.sendMessage(ChatColor.YELLOW + "Du e en ananas!")).build())
|
||||||
|
.command(mgr.commandBuilder("cloud")
|
||||||
|
.literal("help")
|
||||||
|
.argument(StringArgument.<CommandSender>newBuilder("query").greedy()
|
||||||
|
.asOptionalWithDefault("")
|
||||||
|
.build(), "Help query")
|
||||||
|
.handler(c -> minecraftHelp.queryCommands(c.<String>get("query").orElse(""),
|
||||||
|
c.getSender())).build());
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +204,7 @@ public final class BukkitTest extends JavaPlugin {
|
||||||
player.sendMessage(ChatColor.GOLD + "Your input was: " + ChatColor.AQUA + input + ChatColor.GREEN + " (" + number + ")");
|
player.sendMessage(ChatColor.GOLD + "Your input was: " + ChatColor.AQUA + input + ChatColor.GREEN + " (" + number + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@CommandMethod("cloud help")
|
@CommandMethod("cloud debug")
|
||||||
private void doHelp() {
|
private void doHelp() {
|
||||||
final Set<CloudBukkitCapabilities> capabilities = this.mgr.queryCapabilities();
|
final Set<CloudBukkitCapabilities> capabilities = this.mgr.queryCapabilities();
|
||||||
Bukkit.broadcastMessage(ChatColor.GOLD + "" + ChatColor.BOLD + "Capabilities");
|
Bukkit.broadcastMessage(ChatColor.GOLD + "" + ChatColor.BOLD + "Capabilities");
|
||||||
|
|
|
||||||
66
cloud-minecraft/cloud-minecraft-extras/pom.xml
Normal file
66
cloud-minecraft/cloud-minecraft-extras/pom.xml
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~
|
||||||
|
~ MIT License
|
||||||
|
~
|
||||||
|
~ Copyright (c) 2020 Alexander Söderberg
|
||||||
|
~
|
||||||
|
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
~ of this software and associated documentation files (the "Software"), to deal
|
||||||
|
~ in the Software without restriction, including without limitation the rights
|
||||||
|
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
~ copies of the Software, and to permit persons to whom the Software is
|
||||||
|
~ furnished to do so, subject to the following conditions:
|
||||||
|
~
|
||||||
|
~ The above copyright notice and this permission notice shall be included in all
|
||||||
|
~ copies or substantial portions of the Software.
|
||||||
|
~
|
||||||
|
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
~ SOFTWARE.
|
||||||
|
~
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>cloud</artifactId>
|
||||||
|
<groupId>com.intellectualsites</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>cloud-minecraft-extras</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>sonatype</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-api</artifactId>
|
||||||
|
<version>4.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.intellectualsites</groupId>
|
||||||
|
<artifactId>cloud-core</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-text-minimessage</artifactId>
|
||||||
|
<version>4.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Alexander Söderberg
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
package com.intellectualsites.commands;
|
||||||
|
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that maps the command sender type to an adventure {@link net.kyori.adventure.audience.Audience}
|
||||||
|
*
|
||||||
|
* @param <C> Command sender type
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface AudienceProvider<C> extends Function<C, Audience> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a command sender to an {@link Audience}
|
||||||
|
*
|
||||||
|
* @param sender Command sender
|
||||||
|
* @return Mapped audience
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
Audience apply(@Nonnull C sender);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Alexander Söderberg
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
package com.intellectualsites.commands;
|
||||||
|
|
||||||
|
import com.intellectualsites.commands.arguments.CommandArgument;
|
||||||
|
import com.intellectualsites.commands.arguments.StaticArgument;
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import net.kyori.adventure.text.minimessage.Template;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opinionated extension of {@link CommandHelpHandler} for Minecraft
|
||||||
|
*
|
||||||
|
* @param <C> Command sender type
|
||||||
|
*/
|
||||||
|
public final class MinecraftHelp<C> {
|
||||||
|
|
||||||
|
/* General help */
|
||||||
|
public static final String MESSAGE_HELP_HEADER = "help_header";
|
||||||
|
public static final String MESSAGE_HELP_FOOTER = "help_footer";
|
||||||
|
/* Query specific */
|
||||||
|
public static final String MESSAGE_QUERY_QUERY = "help_query_query";
|
||||||
|
public static final String MESSAGE_QUERY_AVAILABLE_COMMANDS = "help_query_available_comments";
|
||||||
|
public static final String MESSAGE_QUERY_COMMAND_SYNTAX = "help_query_command_syntax";
|
||||||
|
public static final String MESSAGE_QUERY_COMMAND_SYNTAX_LAST = "help_query_command_syntax_last";
|
||||||
|
public static final String MESSAGE_QUERY_LONGEST_PATH = "help_query_longest_path";
|
||||||
|
public static final String MESSAGE_QUERY_SUGGESTION = "help_query_suggestion";
|
||||||
|
public static final String MESSAGE_QUERY_VERBOSE_SYNTAX = "help_query_verbose_syntax";
|
||||||
|
public static final String MESSAGE_QUERY_VERBOSE_DESCRIPTION = "help_query_verbose_description";
|
||||||
|
public static final String MESSAGE_QUERY_VERBOSE_ARGS = "help_query_verbose_args";
|
||||||
|
public static final String MESSAGE_QUERY_VERBOSE_OPTIONAL = "help_query_verbose_optional";
|
||||||
|
public static final String MESSAGE_QUERY_VERBOSE_REQUIRED = "help_query_verbose_required";
|
||||||
|
public static final String MESSAGE_QUERY_VERBOSE_LITERAL = "help_query_verbose_literal";
|
||||||
|
|
||||||
|
private final MiniMessage miniMessage = MiniMessage.builder().build();
|
||||||
|
private final Map<String, String> messageMap = new HashMap<>();
|
||||||
|
|
||||||
|
private final AudienceProvider<C> audienceProvider;
|
||||||
|
private final CommandManager<C> commandManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Minecraft help instance
|
||||||
|
*
|
||||||
|
* @param audienceProvider Provider that maps the command sender type to {@link Audience}
|
||||||
|
* @param commandManager Command manager instance
|
||||||
|
*/
|
||||||
|
public MinecraftHelp(@Nonnull final AudienceProvider<C> audienceProvider,
|
||||||
|
@Nonnull final CommandManager<C> commandManager) {
|
||||||
|
this.audienceProvider = audienceProvider;
|
||||||
|
this.commandManager = commandManager;
|
||||||
|
/* Default messages */
|
||||||
|
this.messageMap.put(MESSAGE_HELP_HEADER, "<gold><bold>------------ Help ------------</bold></gold>");
|
||||||
|
this.messageMap.put(MESSAGE_HELP_FOOTER, "<gold><bold>----------------------------</bold></gold>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_QUERY, "<gray>Showing search results for query: \"<green>/<query></green>\"</gray>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_AVAILABLE_COMMANDS, "<dark_gray>└─</dark_gray><gray> Available Commands:</gray>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_COMMAND_SYNTAX, "<dark_gray> ├─</dark_gray> <green>"
|
||||||
|
+ "<hover:show_text:\"<gray><description></gray>\">/<command></hover></green>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_COMMAND_SYNTAX_LAST, "<dark_gray> └─</dark_gray> <green>"
|
||||||
|
+ "<hover:show_text:\"<gray><description></gray>\">/<command></hover></green>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_LONGEST_PATH, "<dark_gray>└─</dark_gray> <green>/<command></green>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_SUGGESTION, "<dark_gray><indentation><prefix></dark_gray> <green><suggestion></green>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_VERBOSE_SYNTAX, "<dark_gray>└─</dark_gray> <gold>Command:"
|
||||||
|
+ " </gold><green>/<command></green>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_VERBOSE_DESCRIPTION, "<dark_gray> ├─</dark_gray>"
|
||||||
|
+ " <gold>Description:</gold> <gray><description></gray>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_VERBOSE_ARGS, "<dark_gray> └─</dark_gray> <gold>Args:</gold>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_VERBOSE_OPTIONAL, "<dark_gray> <prefix></dark_gray> <white><syntax><white> "
|
||||||
|
+ "<yellow>(Optional)</yellow> <dark_gray>-</dark_gray> <gray><description></gray>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_VERBOSE_REQUIRED, "<dark_gray> <prefix></dark_gray> <white><syntax><white> "
|
||||||
|
+ "<dark_gray>-</dark_gray> <gray><description></gray>");
|
||||||
|
this.messageMap.put(MESSAGE_QUERY_VERBOSE_LITERAL, "<gray><syntax></gray>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the command manager instance
|
||||||
|
*
|
||||||
|
* @return Command manager
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public CommandManager<C> getCommandManager() {
|
||||||
|
return this.commandManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the audience provider that was used to create this instance
|
||||||
|
*
|
||||||
|
* @return Audience provider
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public AudienceProvider<C> getAudienceProvider() {
|
||||||
|
return this.audienceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a command sender to an {@link Audience}
|
||||||
|
*
|
||||||
|
* @param sender Sender to map
|
||||||
|
* @return Mapped audience
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public Audience getAudience(@Nonnull final C sender) {
|
||||||
|
return this.audienceProvider.apply(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a message
|
||||||
|
*
|
||||||
|
* @param key Message key
|
||||||
|
* @param message Message
|
||||||
|
*/
|
||||||
|
public void setMessage(@Nonnull final String key, @Nonnull final String message) {
|
||||||
|
this.messageMap.put(key, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query commands and send the results to the recipient
|
||||||
|
*
|
||||||
|
* @param query Command query (without leading '/')
|
||||||
|
* @param recipient Recipient
|
||||||
|
*/
|
||||||
|
public void queryCommands(@Nonnull final String query,
|
||||||
|
@Nonnull final C recipient) {
|
||||||
|
final Audience audience = this.getAudience(recipient);
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_HELP_HEADER)));
|
||||||
|
this.printTopic(recipient, query, this.commandManager.getCommandHelpHandler().queryHelp(query));
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_HELP_FOOTER)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printTopic(@Nonnull final C sender,
|
||||||
|
@Nonnull final String query,
|
||||||
|
@Nonnull final CommandHelpHandler.HelpTopic<C> helpTopic) {
|
||||||
|
this.getAudience(sender).sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_QUERY),
|
||||||
|
Template.of("query", query)));
|
||||||
|
if (helpTopic instanceof CommandHelpHandler.IndexHelpTopic) {
|
||||||
|
this.printIndexHelpTopic(sender, (CommandHelpHandler.IndexHelpTopic<C>) helpTopic);
|
||||||
|
} else if (helpTopic instanceof CommandHelpHandler.MultiHelpTopic) {
|
||||||
|
this.printMultiHelpTopic(sender, (CommandHelpHandler.MultiHelpTopic<C>) helpTopic);
|
||||||
|
} else if (helpTopic instanceof CommandHelpHandler.VerboseHelpTopic) {
|
||||||
|
this.printVerboseHelpTopic(sender, (CommandHelpHandler.VerboseHelpTopic<C>) helpTopic);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown help topic type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printIndexHelpTopic(@Nonnull final C sender, @Nonnull final CommandHelpHandler.IndexHelpTopic<C> helpTopic) {
|
||||||
|
final Audience audience = this.getAudience(sender);
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_AVAILABLE_COMMANDS)));
|
||||||
|
final Iterator<CommandHelpHandler.VerboseHelpEntry<C>> iterator = helpTopic.getEntries().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
final CommandHelpHandler.VerboseHelpEntry<C> entry = iterator.next();
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_COMMAND_SYNTAX),
|
||||||
|
Template.of("command", entry.getSyntaxString()),
|
||||||
|
Template.of("description", entry.getDescription())));
|
||||||
|
} else {
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_COMMAND_SYNTAX_LAST),
|
||||||
|
Template.of("command", entry.getSyntaxString()),
|
||||||
|
Template.of("description", entry.getDescription())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printMultiHelpTopic(@Nonnull final C sender, @Nonnull final CommandHelpHandler.MultiHelpTopic<C> helpTopic) {
|
||||||
|
final Audience audience = this.getAudience(sender);
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_LONGEST_PATH),
|
||||||
|
Template.of("command", helpTopic.getLongestPath())));
|
||||||
|
final int headerIndentation = helpTopic.getLongestPath().length();
|
||||||
|
final Iterator<String> iterator = helpTopic.getChildSuggestions().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
final String suggestion = iterator.next();
|
||||||
|
|
||||||
|
final StringBuilder indentation = new StringBuilder();
|
||||||
|
for (int i = 0; i < headerIndentation; i++) {
|
||||||
|
indentation.append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String prefix;
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
prefix = "├─";
|
||||||
|
} else {
|
||||||
|
prefix = "└─";
|
||||||
|
}
|
||||||
|
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_SUGGESTION),
|
||||||
|
Template.of("indentation", indentation.toString()),
|
||||||
|
Template.of("prefix", prefix),
|
||||||
|
Template.of("suggestion", suggestion)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printVerboseHelpTopic(@Nonnull final C sender, @Nonnull final CommandHelpHandler.VerboseHelpTopic<C> helpTopic) {
|
||||||
|
final Audience audience = this.getAudience(sender);
|
||||||
|
final String command = this.commandManager.getCommandSyntaxFormatter()
|
||||||
|
.apply(helpTopic.getCommand().getArguments(), null);
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_VERBOSE_SYNTAX),
|
||||||
|
Template.of("command", command)));
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_VERBOSE_DESCRIPTION),
|
||||||
|
Template.of("description", helpTopic.getDescription())));
|
||||||
|
audience.sendMessage(this.miniMessage.parse(this.messageMap.get(MESSAGE_QUERY_VERBOSE_ARGS)));
|
||||||
|
|
||||||
|
final Iterator<CommandArgument<C, ?>> iterator = helpTopic.getCommand().getArguments().iterator();
|
||||||
|
/* Skip the first one because it's the command literal */
|
||||||
|
iterator.next();
|
||||||
|
|
||||||
|
boolean hasLast;
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
final CommandArgument<C, ?> argument = iterator.next();
|
||||||
|
|
||||||
|
String description = helpTopic.getCommand().getArgumentDescription(argument);
|
||||||
|
if (description.isEmpty()) {
|
||||||
|
description = "No description";
|
||||||
|
}
|
||||||
|
|
||||||
|
String syntax = this.commandManager.getCommandSyntaxFormatter()
|
||||||
|
.apply(Collections.singletonList(argument), null);
|
||||||
|
|
||||||
|
if (argument instanceof StaticArgument) {
|
||||||
|
syntax = this.messageMap.get(MESSAGE_QUERY_VERBOSE_LITERAL).replace("<syntax>", syntax);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String prefix = iterator.hasNext() ? "├─" : "└─";
|
||||||
|
hasLast = !iterator.hasNext();
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
if (argument.isRequired()) {
|
||||||
|
message = this.messageMap.get(MESSAGE_QUERY_VERBOSE_REQUIRED);
|
||||||
|
} else {
|
||||||
|
message = this.messageMap.get(MESSAGE_QUERY_VERBOSE_OPTIONAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
audience.sendMessage(this.miniMessage.parse(message,
|
||||||
|
Template.of("prefix", prefix),
|
||||||
|
Template.of("syntax", syntax),
|
||||||
|
Template.of("description", description)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Alexander Söderberg
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft extras
|
||||||
|
*/
|
||||||
|
package com.intellectualsites.commands;
|
||||||
1
pom.xml
1
pom.xml
|
|
@ -20,6 +20,7 @@
|
||||||
<module>cloud-minecraft/cloud-brigadier</module>
|
<module>cloud-minecraft/cloud-brigadier</module>
|
||||||
<module>cloud-minecraft/cloud-bungee</module>
|
<module>cloud-minecraft/cloud-bungee</module>
|
||||||
<module>cloud-minecraft/cloud-velocity</module>
|
<module>cloud-minecraft/cloud-velocity</module>
|
||||||
|
<module>cloud-minecraft/cloud-minecraft-extras</module>
|
||||||
</modules>
|
</modules>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<inceptionYear>2020</inceptionYear>
|
<inceptionYear>2020</inceptionYear>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue