mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2025-01-24 01:01:51 +01:00
feat: Implement command flag system (#2827)
* feat: Implement command flag system * docs: Add javadocs and annotation * chore: Implement suggested improvements * chore: Add shortcuts for flaggroup in MultiverseCommand * chore: Add check if flaggroup already registered
This commit is contained in:
parent
fe8118854e
commit
747cab75fd
@ -7,6 +7,20 @@
|
||||
|
||||
package com.onarandombox.MultiverseCore;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import buscript.Buscript;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import com.onarandombox.MultiverseCore.MVWorld.NullLocation;
|
||||
@ -18,6 +32,7 @@ import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseCoreConfig;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseMessaging;
|
||||
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
|
||||
import com.onarandombox.MultiverseCore.commands.CreateCommand;
|
||||
import com.onarandombox.MultiverseCore.commands.DebugCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.AnchorCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.CheckCommand;
|
||||
@ -25,7 +40,6 @@ import com.onarandombox.MultiverseCore.commandsold.CloneCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.ConfigCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.ConfirmCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.CoordCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.CreateCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.DeleteCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.EnvironmentCommand;
|
||||
import com.onarandombox.MultiverseCore.commandsold.GameruleCommand;
|
||||
@ -105,20 +119,6 @@ import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The implementation of the Multiverse-{@link Core}.
|
||||
*/
|
||||
@ -743,7 +743,6 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
|
||||
this.commandHandler.registerCommand(new VersionCommand(this));
|
||||
this.commandHandler.registerCommand(new ListCommand(this));
|
||||
this.commandHandler.registerCommand(new InfoCommand(this));
|
||||
this.commandHandler.registerCommand(new CreateCommand(this));
|
||||
this.commandHandler.registerCommand(new CloneCommand(this));
|
||||
this.commandHandler.registerCommand(new ImportCommand(this));
|
||||
this.commandHandler.registerCommand(new ReloadCommand(this));
|
||||
@ -770,7 +769,6 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
|
||||
this.commandHandler.registerCommand(new AnchorCommand(this));
|
||||
// Misc Commands
|
||||
this.commandHandler.registerCommand(new EnvironmentCommand(this));
|
||||
// this.commandHandler.registerCommand(new DebugCommand(this));
|
||||
this.commandHandler.registerCommand(new SilentCommand(this));
|
||||
this.commandHandler.registerCommand(new GeneratorCommand(this));
|
||||
this.commandHandler.registerCommand(new CheckCommand(this));
|
||||
@ -780,6 +778,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
|
||||
|
||||
//**NEW ACF COMMAND HANDLER**
|
||||
this.commandManager.registerCommand(new DebugCommand(this));
|
||||
this.commandManager.registerCommand(new CreateCommand(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,108 @@
|
||||
package com.onarandombox.MultiverseCore.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import co.aikar.commands.CommandIssuer;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlag;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandValueFlag;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.command.CommandException;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@CommandAlias("mv")
|
||||
public class CreateCommand extends MultiverseCommand {
|
||||
|
||||
public CreateCommand(@NotNull MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
|
||||
registerFlagGroup(CommandFlagGroup.builder("mvcreate")
|
||||
.add(CommandValueFlag.builder("--seed", String.class)
|
||||
.addAlias("-s")
|
||||
.completion(() -> Collections.singleton(String.valueOf(new Random().nextLong())))
|
||||
.build())
|
||||
.add(CommandValueFlag.builder("--generator", String.class)
|
||||
.addAlias("-g")
|
||||
.completion(() -> Arrays.stream(Bukkit.getServer().getPluginManager().getPlugins())
|
||||
.filter(Plugin::isEnabled)
|
||||
.filter(genplugin -> this.plugin.getUnsafeCallWrapper().wrap(
|
||||
() -> genplugin.getDefaultWorldGenerator("world", ""),
|
||||
genplugin.getName(),
|
||||
"Get generator"
|
||||
) != null)
|
||||
.map(genplugin -> genplugin.getDescription().getName())
|
||||
.collect(Collectors.toList()))
|
||||
.build())
|
||||
.add(CommandValueFlag.builder("--world-type", WorldType.class)
|
||||
.addAlias("-t")
|
||||
.context((value) -> {
|
||||
try {
|
||||
return WorldType.valueOf(value.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new CommandException("Invalid world type: " + value);
|
||||
}
|
||||
})
|
||||
.completion(() -> {
|
||||
List<String> types = new ArrayList<>();
|
||||
for (WorldType type : WorldType.values()) {
|
||||
types.add(type.name().toLowerCase());
|
||||
}
|
||||
return types;
|
||||
})
|
||||
.build())
|
||||
.add(CommandFlag.builder("--adjust-spawn")
|
||||
.addAlias("-n")
|
||||
.build())
|
||||
.add(CommandFlag.builder("--no-structures")
|
||||
.addAlias("-a")
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Subcommand("create")
|
||||
@CommandPermission("multiverse.core.create")
|
||||
@CommandCompletion("WORLDNAME @flags:groupName=mvcreate")
|
||||
@Syntax("<name> <env> -s [seed] -g [generator[:id]] -t [worldtype] [-n] -a [true|false]")
|
||||
@Description("") //TODO
|
||||
public void onCreateCommand(CommandIssuer issuer,
|
||||
|
||||
@Syntax("<name>")
|
||||
@Description("") //TODO
|
||||
String worldName,
|
||||
|
||||
@Syntax("<env>")
|
||||
@Description("") //TODO
|
||||
World.Environment environment,
|
||||
|
||||
@Optional
|
||||
@Syntax("[world-flags]")
|
||||
@Description("") //TODO
|
||||
String[] flags
|
||||
) {
|
||||
ParsedCommandFlags parsedFlags = parseFlags(flags);
|
||||
|
||||
issuer.sendMessage(worldName + " " + environment.toString());
|
||||
issuer.sendMessage("--seed: " + parsedFlags.hasFlag("--seed") + " " + String.valueOf(parsedFlags.flagValue("--seed", String.class)));
|
||||
issuer.sendMessage("--generator: " + parsedFlags.hasFlag("--generator") + " " + String.valueOf(parsedFlags.flagValue("--generator", String.class)));
|
||||
issuer.sendMessage("--world-type: " + parsedFlags.hasFlag("--world-type") + " " + String.valueOf(parsedFlags.flagValue("--world-type", WorldType.class)));
|
||||
issuer.sendMessage("--adjust-spawn: " + parsedFlags.hasFlag("--adjust-spawn") + " " + String.valueOf(parsedFlags.flagValue("--adjust-spawn", String.class)));
|
||||
issuer.sendMessage("--no-structures: " + parsedFlags.hasFlag("--no-structures") + " " + String.valueOf(parsedFlags.flagValue("--no-structures", String.class)));
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
@CommandAlias("mv")
|
||||
public class DebugCommand extends MultiverseCommand {
|
||||
|
||||
public DebugCommand(MultiverseCore plugin) {
|
||||
public DebugCommand(@NotNull MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@ -27,7 +27,6 @@ public class DebugCommand extends MultiverseCommand {
|
||||
this.displayDebugMode(issuer);
|
||||
}
|
||||
|
||||
|
||||
@Subcommand("debug")
|
||||
@CommandPermission("multiverse.core.debug")
|
||||
@Syntax("<{@@mv-core.debug_change_syntax}>")
|
||||
|
@ -2,12 +2,38 @@ package com.onarandombox.MultiverseCore.commands;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagGroup;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.ParsedCommandFlags;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A base command for Multiverse.
|
||||
*/
|
||||
public class MultiverseCommand extends BaseCommand {
|
||||
|
||||
protected final MultiverseCore plugin;
|
||||
protected final MVWorldManager worldManager;
|
||||
protected final CommandFlagsManager flagsManager;
|
||||
|
||||
protected MultiverseCommand(MultiverseCore plugin) {
|
||||
private String flagGroupName;
|
||||
|
||||
protected MultiverseCommand(@NotNull MultiverseCore plugin) {
|
||||
this.plugin = plugin;
|
||||
this.worldManager = plugin.getMVWorldManager();
|
||||
this.flagsManager = plugin.getCommandManager().getFlagsManager();
|
||||
}
|
||||
|
||||
protected void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
|
||||
if (flagGroupName != null) {
|
||||
throw new IllegalStateException("Flag group already registered! (name: " + flagGroupName + ")");
|
||||
}
|
||||
flagsManager.registerFlagGroup(flagGroup);
|
||||
flagGroupName = flagGroup.getName();
|
||||
}
|
||||
|
||||
protected @NotNull ParsedCommandFlags parseFlags(@NotNull String[] flags) {
|
||||
return flagsManager.parse(flagGroupName, flags);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,24 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.PaperCommandCompletions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MVCommandCompletions extends PaperCommandCompletions {
|
||||
protected final MVCommandManager commandManager;
|
||||
|
||||
public MVCommandCompletions(MVCommandManager mvCommandManager) {
|
||||
super(mvCommandManager);
|
||||
this.commandManager = mvCommandManager;
|
||||
|
||||
registerAsyncCompletion("flags", this::suggestFlags);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<String> suggestFlags(@NotNull BukkitCommandCompletionContext context) {
|
||||
return this.commandManager.getFlagsManager().suggest(
|
||||
context.getConfig("groupName", ""), context.getContextValue(String[].class));
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import co.aikar.commands.CommandCompletions;
|
||||
import co.aikar.commands.CommandContexts;
|
||||
import co.aikar.commands.PaperCommandManager;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.commandtools.flags.CommandFlagsManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Main class to manage permissions.
|
||||
@ -15,8 +17,9 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
public class MVCommandManager extends PaperCommandManager {
|
||||
|
||||
private final MultiverseCore plugin;
|
||||
private CommandFlagsManager flagsManager;
|
||||
|
||||
public MVCommandManager(MultiverseCore plugin) {
|
||||
public MVCommandManager(@NotNull MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
|
||||
@ -26,13 +29,25 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
this.locales.loadLanguages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class responsible for flag handling.
|
||||
*
|
||||
* @return A not-null {@link CommandFlagsManager}.
|
||||
*/
|
||||
public synchronized @NotNull CommandFlagsManager getFlagsManager() {
|
||||
if (this.flagsManager == null) {
|
||||
this.flagsManager = new CommandFlagsManager();
|
||||
}
|
||||
return flagsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets class responsible for parsing string args into objects.
|
||||
*
|
||||
* @return A not-null {@link CommandContexts}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized CommandContexts<BukkitCommandExecutionContext> getCommandContexts() {
|
||||
public synchronized @NotNull CommandContexts<BukkitCommandExecutionContext> getCommandContexts() {
|
||||
if (this.contexts == null) {
|
||||
this.contexts = new MVCommandContexts(this);
|
||||
}
|
||||
@ -45,7 +60,7 @@ public class MVCommandManager extends PaperCommandManager {
|
||||
* @return A not-null {@link CommandCompletions}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized CommandCompletions<BukkitCommandCompletionContext> getCommandCompletions() {
|
||||
public synchronized @NotNull CommandCompletions<BukkitCommandCompletionContext> getCommandCompletions() {
|
||||
if (this.completions == null) {
|
||||
this.completions = new MVCommandCompletions(this);
|
||||
}
|
||||
|
@ -0,0 +1,93 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools.flags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a flag.
|
||||
*/
|
||||
public class CommandFlag {
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull Builder<?> builder(@NotNull String key){
|
||||
return new Builder<>(key);
|
||||
}
|
||||
|
||||
private final String key;
|
||||
private final List<String> aliases;
|
||||
|
||||
/**
|
||||
* Creates a new flag.
|
||||
*
|
||||
* @param builder The builder.
|
||||
*/
|
||||
protected CommandFlag(@NotNull Builder<?> builder) {
|
||||
key = builder.key;
|
||||
aliases = builder.aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key of this flag.
|
||||
*
|
||||
* @return The key of this flag.
|
||||
*/
|
||||
public @NotNull String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aliases of this flag.
|
||||
*
|
||||
* @return The aliases of this flag.
|
||||
*/
|
||||
public @NotNull List<String> getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param <S> The type of the builder.
|
||||
*/
|
||||
public static class Builder<S extends Builder<?>> {
|
||||
private final String key;
|
||||
private final List<String> aliases;
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
*/
|
||||
public Builder(@NotNull String key) {
|
||||
this.key = key;
|
||||
aliases = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one or more alias to the flag.
|
||||
*
|
||||
* @param alias The alias to add.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S addAlias(@NotNull String...alias){
|
||||
Collections.addAll(this.aliases, alias);
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the flag.
|
||||
*
|
||||
* @return The flag.
|
||||
*/
|
||||
public @NotNull CommandFlag build(){
|
||||
return new CommandFlag(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools.flags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A group of flags.
|
||||
*/
|
||||
public class CommandFlagGroup {
|
||||
/**
|
||||
* A builder for a flag group.
|
||||
*
|
||||
* @param name The name of the group.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull Builder builder(@NotNull String name) {
|
||||
return new Builder(name);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final List<String> keys;
|
||||
private final Map<String, CommandFlag> keysFlagMap;
|
||||
|
||||
/**
|
||||
* Creates a new flag group.
|
||||
*
|
||||
* @param builder The builder.
|
||||
*/
|
||||
protected CommandFlagGroup(@NotNull Builder builder) {
|
||||
name = builder.name;
|
||||
keys = builder.keys;
|
||||
keysFlagMap = builder.keysFlagMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this group.
|
||||
*
|
||||
* @return The name of this group.
|
||||
*/
|
||||
public @NotNull String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this group contains a flag with the given key. Works with alias keys.
|
||||
*
|
||||
* @param key The key to check.
|
||||
* @return True if the group contains a flag with the given key, false otherwise.
|
||||
*/
|
||||
public boolean hasKey(@Nullable String key) {
|
||||
return keysFlagMap.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remaining keys after the given flags have been removed. Works with alias keys.
|
||||
*
|
||||
* @param flags The flags to remove.
|
||||
* @return The remaining keys.
|
||||
*/
|
||||
public @NotNull Set<String> getRemainingKeys(@NotNull String[] flags) {
|
||||
Set<String> keysRemaining = new HashSet<>(this.keys);
|
||||
for (String flag : flags) {
|
||||
CommandFlag mvFlag = this.getFlagByKey(flag);
|
||||
if (mvFlag != null) {
|
||||
keysRemaining.remove(mvFlag.getKey());
|
||||
}
|
||||
}
|
||||
return keysRemaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flag by its key. Alias keys are supported as well.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @return The flag if found, null otherwise.
|
||||
*/
|
||||
public @Nullable CommandFlag getFlagByKey(String key) {
|
||||
return keysFlagMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link CommandFlagGroup}.
|
||||
*/
|
||||
public static class Builder {
|
||||
private final String name;
|
||||
private final List<String> keys;
|
||||
private final Map<String, CommandFlag> keysFlagMap;
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
* @param name The name of the flag group.
|
||||
*/
|
||||
public Builder(@NotNull String name) {
|
||||
this.name = name;
|
||||
this.keys = new ArrayList<>();
|
||||
this.keysFlagMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a flag to the group.
|
||||
*
|
||||
* @param flag The flag to add.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull Builder add(CommandFlag flag) {
|
||||
keys.add(flag.getKey());
|
||||
keysFlagMap.put(flag.getKey(), flag);
|
||||
flag.getAliases().forEach((alias) -> keysFlagMap.put(alias, flag));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the flag group.
|
||||
*
|
||||
* @return The flag group.
|
||||
*/
|
||||
public @NotNull CommandFlagGroup build() {
|
||||
return new CommandFlagGroup(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools.flags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Manages all the flag groups and parsing.
|
||||
*/
|
||||
public class CommandFlagsManager {
|
||||
private final Map<String, CommandFlagGroup> flagGroupMap;
|
||||
|
||||
/**
|
||||
* Creates a new FlagsManager.
|
||||
*/
|
||||
public CommandFlagsManager() {
|
||||
flagGroupMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a flag group.
|
||||
*
|
||||
* @param flagGroup The target flag group to register.
|
||||
*/
|
||||
public void registerFlagGroup(@NotNull CommandFlagGroup flagGroup) {
|
||||
flagGroupMap.put(flagGroup.getName(), flagGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flag group by name.
|
||||
*
|
||||
* @param groupName The target flag group name.
|
||||
* @return The flag group if found, null otherwise.
|
||||
*/
|
||||
public @Nullable CommandFlagGroup getFlagGroup(@Nullable String groupName) {
|
||||
return this.flagGroupMap.get(groupName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocompletes suggestions for flags.
|
||||
*
|
||||
* @param groupName The target flag group name.
|
||||
* @param flags The current flags so far.
|
||||
* @return The list of suggestions.
|
||||
*/
|
||||
public @NotNull Collection<String> suggest(@Nullable String groupName, @NotNull String[] flags) {
|
||||
CommandFlagGroup flagGroup = this.getFlagGroup(groupName);
|
||||
if (flagGroup == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Collection<String> suggestions = new ArrayList<>();
|
||||
CommandFlag currentFlag = (flags.length <= 1) ? null : flagGroup.getFlagByKey(flags[flags.length - 2]);
|
||||
|
||||
if (currentFlag instanceof CommandValueFlag) {
|
||||
CommandValueFlag<?> valueFlag = (CommandValueFlag<?>) currentFlag;
|
||||
if (valueFlag.getCompletion() != null) {
|
||||
suggestions.addAll(valueFlag.getCompletion().get());
|
||||
}
|
||||
if (valueFlag.isOptional()) {
|
||||
suggestions.addAll(flagGroup.getRemainingKeys(flags));
|
||||
}
|
||||
} else {
|
||||
suggestions.addAll(flagGroup.getRemainingKeys(flags));
|
||||
}
|
||||
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the flags.
|
||||
*
|
||||
* @param groupName The target flag group name.
|
||||
* @param flags The flags to parse.
|
||||
* @return The parsed flags.
|
||||
*
|
||||
* @throws InvalidCommandArgument If the flags are invalid.
|
||||
*/
|
||||
public @NotNull ParsedCommandFlags parse(@Nullable String groupName, @NotNull String[] flags) {
|
||||
CommandFlagGroup flagGroup = this.getFlagGroup(groupName);
|
||||
if (flagGroup == null) {
|
||||
return ParsedCommandFlags.EMPTY;
|
||||
}
|
||||
|
||||
return new CommandFlagsParser(this.getFlagGroup(groupName), flags).parse();
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools.flags;
|
||||
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
|
||||
/**
|
||||
* Parses flags from a string array. Each parser should only be used once.
|
||||
*/
|
||||
public class CommandFlagsParser {
|
||||
private final CommandFlagGroup flagGroup;
|
||||
private final String[] flags;
|
||||
|
||||
private ParsedCommandFlags parsedFlags;
|
||||
private boolean nextArgMayBeKey;
|
||||
private boolean nextArgMayBeValue;
|
||||
private CommandFlag currentFlag;
|
||||
|
||||
/**
|
||||
* Creates a new CommandFlagsParser.
|
||||
*
|
||||
* @param flagGroup The flag group to parse flags for.
|
||||
* @param flags The flags to parse.
|
||||
*/
|
||||
public CommandFlagsParser(CommandFlagGroup flagGroup, String[] flags) {
|
||||
this.flagGroup = flagGroup;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the flags.
|
||||
*
|
||||
* @return The parsed flags.
|
||||
*/
|
||||
public ParsedCommandFlags parse() {
|
||||
parsedFlags = new ParsedCommandFlags();
|
||||
|
||||
// First argument is always a key
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = false;
|
||||
|
||||
for (String flag : flags) {
|
||||
if (this.nextArgMayBeKey) {
|
||||
if (parseKey(flag)) continue;
|
||||
}
|
||||
if (this.nextArgMayBeValue) {
|
||||
if (parseValue(flag)) continue;
|
||||
}
|
||||
throw new InvalidCommandArgument(flag + " is not a valid flag.");
|
||||
}
|
||||
|
||||
if (!this.nextArgMayBeKey && this.nextArgMayBeValue) {
|
||||
throw new InvalidCommandArgument(currentFlag.getKey() + " requires a value!");
|
||||
}
|
||||
|
||||
return parsedFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a key.
|
||||
*
|
||||
* @param flag The flag to parse.
|
||||
* @return True if the flag was parsed as a key, false otherwise.
|
||||
*/
|
||||
private boolean parseKey(String flag) {
|
||||
CommandFlag potentialFlag = flagGroup.getFlagByKey(flag);
|
||||
if (potentialFlag == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.currentFlag = potentialFlag;
|
||||
|
||||
if (this.currentFlag instanceof CommandValueFlag) {
|
||||
CommandValueFlag<?> valueFlag = (CommandValueFlag<?>) this.currentFlag;
|
||||
|
||||
if (valueFlag.isOptional()) {
|
||||
parsedFlags.addFlagResult(valueFlag.getKey(), valueFlag.getDefaultValue());
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
this.nextArgMayBeKey = false;
|
||||
this.nextArgMayBeValue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
parsedFlags.addFlagResult(this.currentFlag.getKey(), null);
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a value.
|
||||
*
|
||||
* @param flag The flag to parse.
|
||||
* @return True if the flag was parsed as a value, false otherwise.
|
||||
*/
|
||||
private boolean parseValue(String flag) {
|
||||
if (this.currentFlag == null) {
|
||||
throw new InvalidCommandArgument("Some flag logic error occurred at " + flag + "");
|
||||
}
|
||||
if (flagGroup.hasKey(flag)) {
|
||||
throw new InvalidCommandArgument(currentFlag.getKey() + " requires a value!");
|
||||
}
|
||||
|
||||
Object flagValue;
|
||||
CommandValueFlag<?> valueFlag = (CommandValueFlag<?>) this.currentFlag;
|
||||
flagValue = valueFlag.getContext() != null ? valueFlag.getContext().apply(flag) : flag;
|
||||
parsedFlags.addFlagResult(valueFlag.getKey(), flagValue);
|
||||
|
||||
// After a value, the next argument must be a key
|
||||
this.nextArgMayBeKey = true;
|
||||
this.nextArgMayBeValue = false;
|
||||
this.currentFlag = null;
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools.flags;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a flag with a value.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
*/
|
||||
public class CommandValueFlag<T> extends CommandFlag {
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param type The type of the value.
|
||||
* @return The builder.
|
||||
*/
|
||||
public static @NotNull <T> Builder<T, ?> builder(@NotNull String key, @NotNull Class<T> type) {
|
||||
return new Builder<>(key, type);
|
||||
}
|
||||
|
||||
private final Class<T> type;
|
||||
private final boolean optional;
|
||||
private final T defaultValue;
|
||||
private final Function<String, T> context;
|
||||
private final Supplier<Collection<String>> completion;
|
||||
|
||||
/**
|
||||
* Creates a new flag.
|
||||
*
|
||||
* @param builder The builder.
|
||||
*/
|
||||
protected CommandValueFlag(@NotNull Builder<T, ?> builder) {
|
||||
super(builder);
|
||||
type = builder.type;
|
||||
optional = builder.optional;
|
||||
defaultValue = builder.defaultValue;
|
||||
context = builder.context;
|
||||
completion = builder.completion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the value.
|
||||
*
|
||||
* @return The type of the value.
|
||||
*/
|
||||
public @NotNull Class<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it is optional for users to specify a value.
|
||||
*
|
||||
* @return True if the value is optional, false otherwise.
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value. May be null.
|
||||
*
|
||||
* @return The default value.
|
||||
*/
|
||||
public @Nullable T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context. May be null for {@link String} value type.
|
||||
*
|
||||
* @return The context.
|
||||
*/
|
||||
public @Nullable Function<String, T> getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the completion. May be null.
|
||||
*
|
||||
* @return The completion.
|
||||
*/
|
||||
public @Nullable Supplier<Collection<String>> getCompletion() {
|
||||
return completion;
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for a flag.
|
||||
*
|
||||
* @param <T> The type of the value.
|
||||
* @param <S> The type of the builder.
|
||||
*/
|
||||
public static class Builder<T, S extends Builder<T, S>> extends CommandFlag.Builder<S> {
|
||||
private final Class<T> type;
|
||||
private boolean optional = false;
|
||||
private T defaultValue = null;
|
||||
private Function<String, T> context = null;
|
||||
private Supplier<Collection<String>> completion = null;
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* @param key The key for the new flag.
|
||||
* @param type The type of the value.
|
||||
*/
|
||||
public Builder(@NotNull String key, @NotNull Class<T> type) {
|
||||
super(key);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag as optional for users to specify a value.
|
||||
*
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S optional() {
|
||||
this.optional = true;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value. Used if optional is true and user does not specify a value.
|
||||
*
|
||||
* @param defaultValue The default value.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S defaultValue(@NotNull T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the context callback for parsing string into value type.
|
||||
*
|
||||
* @param context The context.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S context(@NotNull Function<String, T> context) {
|
||||
this.context = context;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the completion callback for autocomplete.
|
||||
*
|
||||
* @param completion The completion.
|
||||
* @return The builder.
|
||||
*/
|
||||
public @NotNull S completion(@NotNull Supplier<Collection<String>> completion) {
|
||||
this.completion = completion;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the flag.
|
||||
*
|
||||
* @return The flag.
|
||||
*/
|
||||
@Override
|
||||
public @NotNull CommandFlag build() {
|
||||
if (context == null && !String.class.equals(type)) {
|
||||
throw new IllegalStateException("Context is required for none-string value flags");
|
||||
}
|
||||
return new CommandValueFlag<>(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.onarandombox.MultiverseCore.commandtools.flags;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Object to contain the results of the flags present and its values.
|
||||
*/
|
||||
public class ParsedCommandFlags
|
||||
{
|
||||
public static final ParsedCommandFlags EMPTY = new ParsedCommandFlags();
|
||||
|
||||
private final Map<String, Object> flagValues;
|
||||
|
||||
public ParsedCommandFlags() {
|
||||
flagValues = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a flag result to the parsed flags.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @param value The value of the flag.
|
||||
*/
|
||||
void addFlagResult(@NotNull String key, @Nullable Object value) {
|
||||
flagValues.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a flag is present.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @return True if the flag is present, false otherwise.
|
||||
*/
|
||||
public boolean hasFlag(@Nullable String key) {
|
||||
return this.flagValues.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a flag.
|
||||
*
|
||||
* @param key The key of the flag.
|
||||
* @return The value of the flag, null if flag does not exist or no value.
|
||||
*/
|
||||
public @Nullable <T> T flagValue(@Nullable String key, @NotNull Class<T> type) {
|
||||
Object value = this.flagValues.get(key);
|
||||
return (T) value;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user