Skip to content

Commit f9c5fce

Browse files
committed
Implement the majority of CommandAPI#528. Implement the main logic and documentation examples (Java, Kotlin). Fix typo in Kotlin DSL example
Only thing left to do with this is manual testing, implementing this for the Kotlin DSL, and adding a global and documentation changelog entry
1 parent f41a41e commit f9c5fce

File tree

11 files changed

+267
-54
lines changed

11 files changed

+267
-54
lines changed

commandapi-core/src/main/java/dev/jorel/commandapi/CommandAPIHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ void register(CommandMetaData<CommandSender> meta, final Argument[] args,
603603
Optional<String> shortDescription = meta.shortDescription;
604604
Optional<String> fullDescription = meta.fullDescription;
605605
Optional<String[]> usageDescription = meta.usageDescription;
606+
Optional<Object> helpTopic = meta.helpTopic;
606607

607608
// Handle command conflicts
608609
boolean hasRegisteredCommand = false;
@@ -619,7 +620,7 @@ void register(CommandMetaData<CommandSender> meta, final Argument[] args,
619620
argumentsString.add(arg.getNodeName() + ":" + arg.getClass().getSimpleName());
620621
}
621622
RegisteredCommand registeredCommandInformation = new RegisteredCommand(commandName, argumentsString, List.of(args), shortDescription,
622-
fullDescription, usageDescription, aliases, permission, namespace);
623+
fullDescription, usageDescription, helpTopic, aliases, permission, namespace);
623624
registeredCommands.add(registeredCommandInformation);
624625

625626
// Handle previewable arguments

commandapi-core/src/main/java/dev/jorel/commandapi/CommandMetaData.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ final class CommandMetaData<CommandSender> {
4747
*/
4848
Optional<String[]> usageDescription = Optional.empty();
4949

50+
/**
51+
* An optional HelpTopic object for the command (for Bukkit)
52+
*/
53+
Optional<Object> helpTopic = Optional.empty();
54+
5055
/**
5156
* Create command metadata
5257
* @param commandName The command's name
@@ -69,6 +74,7 @@ public CommandMetaData(CommandMetaData<CommandSender> original) {
6974
this.shortDescription = original.shortDescription.isPresent() ? Optional.of(original.shortDescription.get()) : Optional.empty();
7075
this.fullDescription = original.fullDescription.isPresent() ? Optional.of(original.fullDescription.get()) : Optional.empty();
7176
this.usageDescription = original.usageDescription.isPresent() ? Optional.of(original.usageDescription.get()) : Optional.empty();
77+
this.helpTopic = original.helpTopic.isPresent() ? Optional.of(original.helpTopic.get()) : Optional.empty();
7278
}
7379

7480
}

commandapi-core/src/main/java/dev/jorel/commandapi/RegisteredCommand.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public record RegisteredCommand(
5050
* usage
5151
*/
5252
Optional<String[]> usageDescription,
53+
54+
/**
55+
* @return An {@link Optional} containing this command's help topic (for Bukkit)
56+
*/
57+
Optional<Object> helpTopic,
5358

5459
/**
5560
* @return a {@link String}{@code []} of aliases for this command
@@ -74,7 +79,7 @@ public int hashCode() {
7479
int result = 1;
7580
result = prime * result + Arrays.hashCode(aliases);
7681
result = prime * result + Arrays.hashCode(usageDescription.orElse(null));
77-
result = prime * result + Objects.hash(argsAsStr, commandName, fullDescription, permission, shortDescription, namespace);
82+
result = prime * result + Objects.hash(argsAsStr, commandName, fullDescription, permission, shortDescription, helpTopic, namespace);
7883
return result;
7984
}
8085

@@ -89,14 +94,15 @@ public boolean equals(Object obj) {
8994
RegisteredCommand other = (RegisteredCommand) obj;
9095
return Arrays.equals(aliases, other.aliases) && Objects.equals(argsAsStr, other.argsAsStr) && Objects.equals(commandName, other.commandName)
9196
&& Objects.equals(namespace, other.namespace) && Arrays.equals(usageDescription.orElse(null), other.usageDescription.orElse(null))
92-
&& Objects.equals(fullDescription, other.fullDescription) && Objects.equals(permission, other.permission) && Objects.equals(shortDescription, other.shortDescription);
97+
&& Objects.equals(fullDescription, other.fullDescription) && Objects.equals(permission, other.permission) && Objects.equals(shortDescription, other.shortDescription)
98+
&& Objects.equals(helpTopic, other.helpTopic);
9399
}
94100

95101
@Override
96102
public String toString() {
97103
return "RegisteredCommand [commandName=" + commandName + ", argsAsStr=" + argsAsStr + ", shortDescription=" + shortDescription + ", fullDescription=" + fullDescription
98104
+ ", usageDescription=" + (usageDescription.isPresent() ? "Optional[" + Arrays.toString(usageDescription.get()) + "]" : "Optional.empty")
99-
+ ", aliases=" + Arrays.toString(aliases) + ", permission=" + permission + ", namespace=" + namespace + "]";
105+
+ ", aliases=" + Arrays.toString(aliases) + ", permission=" + permission + ", namespace=" + namespace + ", helpTopic=" + helpTopic + "]";
100106
}
101107

102108
}

commandapi-documentation-code/src/main/java/dev/jorel/commandapi/examples/java/Examples.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import org.bukkit.command.ProxiedCommandSender;
5555
import org.bukkit.enchantments.Enchantment;
5656
import org.bukkit.entity.*;
57+
import org.bukkit.help.HelpTopic;
5758
import org.bukkit.inventory.ComplexRecipe;
5859
import org.bukkit.inventory.ItemStack;
5960
import org.bukkit.inventory.Recipe;
@@ -1682,6 +1683,52 @@ void help() {
16821683
/* ANCHOR_END: help2 */
16831684
}
16841685

1686+
/* ANCHOR: help3 */
1687+
public HelpTopic makeHelp(String command) {
1688+
return new HelpTopic() {
1689+
1690+
@Override
1691+
public String getShortText() {
1692+
return "Says hi";
1693+
}
1694+
1695+
@Override
1696+
public String getFullText(CommandSender forWho) {
1697+
String helpText = "";
1698+
if (forWho instanceof Player player) {
1699+
// Make use of the player's locale to make language-specific help!
1700+
Locale playerLocale = player.locale();
1701+
if (playerLocale.getLanguage().equals("en")) {
1702+
helpText = "Broadcasts hi to everyone on the server";
1703+
} else if (playerLocale.getLanguage().equals("de")) {
1704+
helpText = "Sendet Hallo an alle auf dem Server";
1705+
}
1706+
} else {
1707+
helpText = "Broadcasts hi to everyone on the server";
1708+
}
1709+
return helpText;
1710+
}
1711+
1712+
// Allow anyone to see this help topic
1713+
@Override
1714+
public boolean canSee(CommandSender player) {
1715+
return true;
1716+
}
1717+
};
1718+
}
1719+
/* ANCHOR_END: help3 */
1720+
1721+
void help2() {
1722+
/* ANCHOR: help4 */
1723+
new CommandAPICommand("mycmd")
1724+
.withHelp(makeHelp("mycmd"))
1725+
.executes((sender, args) -> {
1726+
Bukkit.broadcastMessage("Hi!");
1727+
})
1728+
.register();
1729+
/* ANCHOR_END: help4 */
1730+
}
1731+
16851732
void listed() {
16861733
/* ANCHOR: listed1 */
16871734
new CommandAPICommand("mycommand")

commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/Examples.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import org.bukkit.command.CommandSender
3636
import org.bukkit.command.ProxiedCommandSender
3737
import org.bukkit.enchantments.Enchantment
3838
import org.bukkit.entity.*
39+
import org.bukkit.help.HelpTopic
3940
import org.bukkit.inventory.ComplexRecipe
4041
import org.bukkit.inventory.ItemStack
4142
import org.bukkit.inventory.Recipe
@@ -1603,6 +1604,42 @@ CommandAPICommand("mycmd")
16031604
/* ANCHOR_END: help2 */
16041605
}
16051606

1607+
/* ANCHOR: help3 */
1608+
fun makeHelp(command: String): HelpTopic = object: HelpTopic() {
1609+
override fun getShortText(): String = "Says hi"
1610+
1611+
override fun getFullText(forWho: CommandSender): String {
1612+
var helpText = ""
1613+
if (forWho is Player) {
1614+
// Make use of the player's locale to make language-specific help!
1615+
val playerLocale = forWho.locale()
1616+
if (playerLocale.getLanguage() == "en") {
1617+
helpText = "Broadcasts hi to everyone on the server"
1618+
} else if (playerLocale.getLanguage() == "de") {
1619+
helpText = "Sendet Hallo an alle auf dem Server"
1620+
}
1621+
} else {
1622+
helpText = "Broadcasts hi to everyone on the server"
1623+
}
1624+
return helpText
1625+
}
1626+
1627+
// Allow anyone to see this help topic
1628+
override fun canSee(player: CommandSender): Boolean = true
1629+
}
1630+
/* ANCHOR_END: help3 */
1631+
1632+
fun help2() {
1633+
/* ANCHOR: help4 */
1634+
return CommandAPICommand("mycmd")
1635+
.withHelp(makeHelp("mycmd"))
1636+
.executes(CommandExecutor { _, _ ->
1637+
Bukkit.broadcastMessage("Hi!")
1638+
})
1639+
.register()
1640+
/* ANCHOR_END: help4 */
1641+
}
1642+
16061643
fun listed() {
16071644
/* ANCHOR: listed1 */
16081645
CommandAPICommand("mycommand")

commandapi-documentation-code/src/main/kotlin/dev/jorel/commandapi/examples/kotlin/ExamplesKotlinDSL.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ fun help() {
910910
/* ANCHOR: help1 */
911911
commandAPICommand("mycmd") {
912912
withShortDescription("Says hi")
913-
withFullDescription("Broadcasts ho to everyone on the server")
913+
withFullDescription("Broadcasts hi to everyone on the server")
914914
anyExecutor { _, _ ->
915915
Bukkit.broadcastMessage("Hi!")
916916
}

commandapi-platforms/commandapi-bukkit/commandapi-bukkit-core/src/main/java/dev/jorel/commandapi/CommandAPIBukkit.java

Lines changed: 89 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,33 @@
77

88
import java.io.File;
99
import java.io.IOException;
10-
import java.util.*;
10+
import java.util.ArrayList;
11+
import java.util.Arrays;
12+
import java.util.Collection;
13+
import java.util.HashMap;
14+
import java.util.HashSet;
15+
import java.util.Iterator;
16+
import java.util.List;
17+
import java.util.Map;
18+
import java.util.Optional;
19+
import java.util.Set;
1120
import java.util.function.Function;
1221
import java.util.function.Predicate;
1322
import java.util.logging.Level;
1423
import java.util.logging.Logger;
1524

16-
import dev.jorel.commandapi.arguments.AbstractArgument;
17-
import dev.jorel.commandapi.commandsenders.*;
1825
import org.bukkit.Bukkit;
1926
import org.bukkit.ChatColor;
2027
import org.bukkit.Keyed;
21-
import org.bukkit.command.*;
28+
import org.bukkit.command.BlockCommandSender;
29+
import org.bukkit.command.Command;
30+
import org.bukkit.command.CommandMap;
31+
import org.bukkit.command.CommandSender;
32+
import org.bukkit.command.ConsoleCommandSender;
33+
import org.bukkit.command.PluginCommand;
34+
import org.bukkit.command.ProxiedCommandSender;
35+
import org.bukkit.command.RemoteConsoleCommandSender;
36+
import org.bukkit.command.SimpleCommandMap;
2237
import org.bukkit.entity.Player;
2338
import org.bukkit.event.EventHandler;
2439
import org.bukkit.event.EventPriority;
@@ -38,10 +53,22 @@
3853
import com.mojang.brigadier.tree.LiteralCommandNode;
3954
import com.mojang.brigadier.tree.RootCommandNode;
4055

56+
import dev.jorel.commandapi.arguments.AbstractArgument;
4157
import dev.jorel.commandapi.arguments.Argument;
4258
import dev.jorel.commandapi.arguments.LiteralArgument;
4359
import dev.jorel.commandapi.arguments.MultiLiteralArgument;
4460
import dev.jorel.commandapi.arguments.SuggestionProviders;
61+
import dev.jorel.commandapi.commandsenders.AbstractCommandSender;
62+
import dev.jorel.commandapi.commandsenders.AbstractPlayer;
63+
import dev.jorel.commandapi.commandsenders.BukkitBlockCommandSender;
64+
import dev.jorel.commandapi.commandsenders.BukkitCommandSender;
65+
import dev.jorel.commandapi.commandsenders.BukkitConsoleCommandSender;
66+
import dev.jorel.commandapi.commandsenders.BukkitEntity;
67+
import dev.jorel.commandapi.commandsenders.BukkitFeedbackForwardingCommandSender;
68+
import dev.jorel.commandapi.commandsenders.BukkitNativeProxyCommandSender;
69+
import dev.jorel.commandapi.commandsenders.BukkitPlayer;
70+
import dev.jorel.commandapi.commandsenders.BukkitProxiedCommandSender;
71+
import dev.jorel.commandapi.commandsenders.BukkitRemoteConsoleCommandSender;
4572
import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException;
4673
import dev.jorel.commandapi.nms.NMS;
4774
import dev.jorel.commandapi.preprocessor.RequireField;
@@ -329,56 +356,70 @@ void updateHelpForCommands(List<RegisteredCommand> commands) {
329356
Map<String, HelpTopic> helpTopicsToAdd = new HashMap<>();
330357

331358
for (RegisteredCommand command : commands) {
332-
// Generate short description
359+
// Don't override the plugin help topic
360+
String commandPrefix = generateCommandHelpPrefix(command.commandName());
361+
StringBuilder aliasSb = new StringBuilder();
333362
final String shortDescription;
334-
final Optional<String> shortDescriptionOptional = command.shortDescription();
335-
final Optional<String> fullDescriptionOptional = command.fullDescription();
336-
if (shortDescriptionOptional.isPresent()) {
337-
shortDescription = shortDescriptionOptional.get();
338-
} else if (fullDescriptionOptional.isPresent()) {
339-
shortDescription = fullDescriptionOptional.get();
363+
364+
// Must be empty string, not null as defined by OBC::CustomHelpTopic
365+
final String permission = command.permission().getPermission().orElse("");
366+
367+
HelpTopic helpTopic;
368+
if (command.helpTopic().isPresent()) {
369+
helpTopic = (HelpTopic) command.helpTopic().get();
370+
shortDescription = "";
340371
} else {
341-
shortDescription = "A command by the " + config.getPlugin().getName() + " plugin.";
342-
}
343-
344-
// Generate full description
345-
StringBuilder sb = new StringBuilder();
346-
if (fullDescriptionOptional.isPresent()) {
347-
sb.append(ChatColor.GOLD).append("Description: ").append(ChatColor.WHITE).append(fullDescriptionOptional.get()).append("\n");
348-
}
349-
350-
generateHelpUsage(sb, command);
351-
sb.append("\n");
372+
// Generate short description
373+
final Optional<String> shortDescriptionOptional = command.shortDescription();
374+
final Optional<String> fullDescriptionOptional = command.fullDescription();
375+
if (shortDescriptionOptional.isPresent()) {
376+
shortDescription = shortDescriptionOptional.get();
377+
} else if (fullDescriptionOptional.isPresent()) {
378+
shortDescription = fullDescriptionOptional.get();
379+
} else {
380+
shortDescription = "A command by the " + config.getPlugin().getName() + " plugin.";
381+
}
382+
383+
// Generate full description
384+
StringBuilder sb = new StringBuilder();
385+
if (fullDescriptionOptional.isPresent()) {
386+
sb.append(ChatColor.GOLD).append("Description: ").append(ChatColor.WHITE).append(fullDescriptionOptional.get()).append("\n");
387+
}
388+
389+
generateHelpUsage(sb, command);
390+
sb.append("\n");
391+
392+
// Generate aliases. We make a copy of the StringBuilder because we
393+
// want to change the output when we register aliases
394+
aliasSb = new StringBuilder(sb.toString());
395+
if (command.aliases().length > 0) {
396+
sb.append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE).append(String.join(", ", command.aliases()));
397+
}
352398

353-
// Generate aliases. We make a copy of the StringBuilder because we
354-
// want to change the output when we register aliases
355-
StringBuilder aliasSb = new StringBuilder(sb.toString());
356-
if (command.aliases().length > 0) {
357-
sb.append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE).append(String.join(", ", command.aliases()));
399+
helpTopic = generateHelpTopic(commandPrefix, shortDescription, sb.toString().trim(), permission);
358400
}
359-
360-
// Must be empty string, not null as defined by OBC::CustomHelpTopic
361-
String permission = command.permission().getPermission().orElse("");
362-
363-
// Don't override the plugin help topic
364-
String commandPrefix = generateCommandHelpPrefix(command.commandName());
365-
helpTopicsToAdd.put(commandPrefix, generateHelpTopic(commandPrefix, shortDescription, sb.toString().trim(), permission));
401+
helpTopicsToAdd.put(commandPrefix, helpTopic);
366402

367403
for (String alias : command.aliases()) {
368-
StringBuilder currentAliasSb = new StringBuilder(aliasSb.toString());
369-
currentAliasSb.append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE);
370-
371-
// We want to get all aliases (including the original command name),
372-
// except for the current alias
373-
List<String> aliases = new ArrayList<>(Arrays.asList(command.aliases()));
374-
aliases.add(command.commandName());
375-
aliases.remove(alias);
376-
377-
currentAliasSb.append(ChatColor.WHITE).append(String.join(", ", aliases));
378-
379-
// Don't override the plugin help topic
380-
commandPrefix = generateCommandHelpPrefix(alias);
381-
helpTopicsToAdd.put(commandPrefix, generateHelpTopic(commandPrefix, shortDescription, currentAliasSb.toString().trim(), permission));
404+
if (command.helpTopic().isPresent()) {
405+
helpTopic = (HelpTopic) command.helpTopic().get();
406+
} else {
407+
StringBuilder currentAliasSb = new StringBuilder(aliasSb.toString());
408+
currentAliasSb.append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE);
409+
410+
// We want to get all aliases (including the original command name),
411+
// except for the current alias
412+
List<String> aliases = new ArrayList<>(Arrays.asList(command.aliases()));
413+
aliases.add(command.commandName());
414+
aliases.remove(alias);
415+
416+
currentAliasSb.append(ChatColor.WHITE).append(String.join(", ", aliases));
417+
418+
// Don't override the plugin help topic
419+
commandPrefix = generateCommandHelpPrefix(alias);
420+
helpTopic = generateHelpTopic(commandPrefix, shortDescription, currentAliasSb.toString().trim(), permission);
421+
}
422+
helpTopicsToAdd.put(commandPrefix, helpTopic);
382423
}
383424
}
384425

0 commit comments

Comments
 (0)