├── .gitignore
├── .idea
├── .gitignore
├── codeStyles
│ └── codeStyleConfig.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── kotlinc.xml
├── misc.xml
├── uiDesigner.xml
└── vcs.xml
├── README.MD
├── bungee
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── github
│ └── mqzn
│ └── commands
│ ├── BungeeCaption.java
│ ├── BungeeCommandManager.java
│ ├── BungeeCommandRequirement.java
│ ├── BungeeCommandSyntaxBuilder.java
│ ├── BungeeSenderWrapper.java
│ ├── BungeeSubCommandBuilder.java
│ ├── InternalBungeeCommand.java
│ ├── arguments
│ ├── ArgumentOnlinePlayer.java
│ └── BungeeArgument.java
│ └── help
│ └── BungeeCommandHelpProvider.java
├── common
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── github
│ │ └── mqzn
│ │ └── commands
│ │ ├── annotations
│ │ ├── AnnotationParser.java
│ │ ├── base
│ │ │ ├── Arg.java
│ │ │ ├── Command.java
│ │ │ ├── CommandsGroup.java
│ │ │ ├── Cooldown.java
│ │ │ ├── Default.java
│ │ │ ├── ExecutionMeta.java
│ │ │ ├── Flag.java
│ │ │ ├── Greedy.java
│ │ │ ├── Range.java
│ │ │ └── Suggest.java
│ │ └── subcommands
│ │ │ ├── SubCommand.java
│ │ │ ├── SubCommandExecution.java
│ │ │ ├── SubCommandInfo.java
│ │ │ └── SubCommands.java
│ │ ├── arguments
│ │ ├── AbstractArgument.java
│ │ ├── Argument.java
│ │ ├── ArgumentBoolean.java
│ │ ├── ArgumentData.java
│ │ ├── ArgumentDouble.java
│ │ ├── ArgumentEnum.java
│ │ ├── ArgumentFloat.java
│ │ ├── ArgumentInteger.java
│ │ ├── ArgumentLiteral.java
│ │ ├── ArgumentLong.java
│ │ ├── ArgumentNumber.java
│ │ ├── ArgumentStringArray.java
│ │ └── ArgumentWord.java
│ │ ├── base
│ │ ├── Command.java
│ │ ├── CommandInfo.java
│ │ ├── CommandRequirement.java
│ │ ├── Information.java
│ │ ├── SenderProvider.java
│ │ ├── SenderWrapper.java
│ │ ├── SuggestionProvider.java
│ │ ├── caption
│ │ │ ├── Caption.java
│ │ │ ├── CaptionKey.java
│ │ │ ├── CaptionRegistry.java
│ │ │ └── Message.java
│ │ ├── context
│ │ │ ├── CommandArgs.java
│ │ │ ├── CommandContext.java
│ │ │ ├── Context.java
│ │ │ └── DelegateCommandContext.java
│ │ ├── cooldown
│ │ │ ├── CommandCooldown.java
│ │ │ └── CooldownCaption.java
│ │ ├── manager
│ │ │ ├── AbstractCommandManager.java
│ │ │ ├── AmbiguityChecker.java
│ │ │ ├── ArgumentNumberComparator.java
│ │ │ ├── ArgumentNumberSuggestionProcessor.java
│ │ │ ├── ArgumentTypeRegistry.java
│ │ │ ├── CommandExecutionCoordinator.java
│ │ │ ├── CommandManager.java
│ │ │ ├── CommandSuggestionEngine.java
│ │ │ ├── FlagRegistry.java
│ │ │ ├── SenderProviderRegistry.java
│ │ │ ├── SuggestionProviderRegistry.java
│ │ │ └── flags
│ │ │ │ ├── CommandFlag.java
│ │ │ │ ├── ContextFlagRegistry.java
│ │ │ │ └── FlagInfo.java
│ │ └── syntax
│ │ │ ├── CommandAliases.java
│ │ │ ├── CommandExecution.java
│ │ │ ├── CommandSyntax.java
│ │ │ ├── CommandSyntaxBuilder.java
│ │ │ ├── SubCommandBuilder.java
│ │ │ ├── SubCommandSyntax.java
│ │ │ ├── SyntaxFlags.java
│ │ │ └── tree
│ │ │ ├── CommandTree.java
│ │ │ └── SubCommandArgumentTree.java
│ │ ├── exceptions
│ │ ├── CommandException.java
│ │ ├── CommandExceptionHandler.java
│ │ ├── UnknownCommandSenderType.java
│ │ └── types
│ │ │ ├── ArgumentParseException.java
│ │ │ └── SyntaxAmbiguityException.java
│ │ ├── help
│ │ ├── CommandHelpProvider.java
│ │ ├── CommandHelpStyle.java
│ │ ├── CommandSyntaxPageDisplayer.java
│ │ ├── SubCommandHelp.java
│ │ └── UnknownPageCaption.java
│ │ └── utilities
│ │ ├── ArgumentSyntaxUtility.java
│ │ ├── Pair.java
│ │ ├── TimeParser.java
│ │ └── text
│ │ ├── ItemPageTextDisplayer.java
│ │ ├── PaginatedText.java
│ │ ├── TextConvertible.java
│ │ └── TextPage.java
│ └── test
│ └── java
│ └── io
│ └── github
│ └── mqzn
│ └── commands
│ └── test
│ ├── ClientSender.java
│ ├── ClientSenderWrapper.java
│ ├── CustomException.java
│ ├── TestBootstrap.java
│ ├── TestCommandManager.java
│ └── annotations
│ └── TestAnnotatedCommand.java
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img.png
├── jcord
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── github
│ └── mqzn
│ └── commands
│ ├── JCordCommandManager.java
│ ├── JCordCommandSyntaxBuilder.java
│ └── JCordSubCommandBuilder.java
├── settings.gradle
├── spigot
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── io
│ │ └── github
│ │ └── mqzn
│ │ └── commands
│ │ ├── InternalSpigotCommand.java
│ │ ├── SpigotCaption.java
│ │ ├── SpigotCommandManager.java
│ │ ├── SpigotCommandRequirement.java
│ │ ├── SpigotCommandSyntaxBuilder.java
│ │ ├── SpigotSenderWrapper.java
│ │ ├── SpigotSubCommandBuilder.java
│ │ ├── arguments
│ │ ├── ArgumentLocation.java
│ │ ├── ArgumentOfflinePlayer.java
│ │ ├── ArgumentOnlinePlayer.java
│ │ ├── ArgumentUUID.java
│ │ ├── ArgumentWorld.java
│ │ └── SpigotArgument.java
│ │ └── help
│ │ └── SpigotCommandHelpProvider.java
│ └── resources
│ └── plugin.yml
└── velocity
├── build.gradle
└── src
└── main
└── java
└── io
└── github
└── commands
├── InternalVelocityCommand.java
├── VelocityCaption.java
├── VelocityCommandManager.java
├── VelocityCommandRequirement.java
├── VelocitySenderWrapper.java
├── VelocitySubCommandBuilder.java
├── arguments
├── ArgumentOnlinePlayer.java
└── VelocityArgument.java
└── help
└── VelocityCommandHelpProvider.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | # mCommands (NO LONGER MAINTAINED, DONT RECOMMEND TO USE !)
6 | **I Recommend Going for [Imperat](https://github.com/VelixDevelopments/Imperat)**
7 |
8 | An advanced general purpose command dispatching framework
9 | designed using OOP concepts.The library is user-friendly and provides
10 | high performance along with a high quality of production code.
11 |
12 | This library utilizes [Kyori Adventure](https://github.com/KyoriPowered/adventure) for
13 | messages and text styles
14 |
15 | so in the installation you must include the dependencies of Kyori in your project's dependencies control tool file
16 | here's an example using build.gradle:
17 |
18 | ```gradle
19 |
20 | dependencies {
21 | compileOnly "net.kyori:adventure-api:4.13.1"
22 | compileOnly "net.kyori:adventure-platform-bukkit:4.3.0"
23 | }
24 |
25 | ```
26 |
27 | ## Installation
28 |
29 | mCommands has its own repo in maven central
30 | so all you have to do is like this:
31 |
32 | ```gradle
33 | repositories {
34 | mavenCentral()
35 | }
36 |
37 | dependencies {
38 | implementation 'io.github.mqzn:mCommands-:'
39 | }
40 | ```
41 |
42 | ## Platforms
43 |
44 | ### Common
45 |
46 | The main platform that contain the core of the library
47 |
48 | ```gradle
49 | implementation 'io.github.mqzn:mCommands-common:'
50 | ```
51 |
52 | ### Spigot
53 |
54 | The spigot platform is for minecraft spigot api development
55 |
56 | ```gradle
57 | implementation 'io.github.mqzn:mCommands-spigot:'
58 | ```
59 |
60 | ### Bungee
61 |
62 | This bungeecord platform is for minecraft bungeecord proxy api development, allows you
63 | to declare and register bungeecord commands.
64 |
65 | ```gradle
66 | implementation 'io.github.mqzn:mCommands-bungee:'
67 | ```
68 |
69 | ## Wiki
70 | If you want to learn how to fully utilize the amazing potential of this library.
71 | you must read the wiki pages starting from [here](https://github.com/Mqzn/mCommands/wiki)
72 | You will also need the wiki in order to make something cool like the example below:
73 |
74 | ### Code Example
75 | Here's a quick example on how to create a command using mCommands.
76 | ```java
77 | public final class SpigotPluginTest extends JavaPlugin {
78 |
79 | private SpigotCommandManager commandManager;
80 |
81 | @Override
82 | public void onEnable() {
83 | var cmd = Command.builder(commandManager, "test")
84 | .info(new CommandInfo("test.perm", "Test cmd", "testis"))
85 | .requirement(SpigotCommandRequirement.ONLY_PLAYER_EXECUTABLE)
86 | .cooldown(new CommandCooldown(5, TimeUnit.MINUTES))
87 | .executionMeta(
88 | SpigotCommandSyntaxBuilder.builder(commandManager, "test")
89 | .argument(Argument.literal("testsub"))
90 | .execute((sender, context) -> sender.sendMessage("Test sub works !"))
91 | .build()
92 | )
93 | .defaultExecutor((s, context) -> s.sendMessage("OMG NO ARGS !"))
94 | .build();
95 |
96 | commandManager.register(cmd);
97 | }
98 |
99 | }
100 | ```
101 |
102 |
103 |
--------------------------------------------------------------------------------
/bungee/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'com.github.johnrengelman.shadow' version '7.1.0'
4 | id 'maven-publish'
5 | id 'signing'
6 | }
7 |
8 | group 'io.github.mqzn'
9 | version '1.1.7'
10 |
11 | repositories {
12 | mavenCentral()
13 | maven {
14 | url 'https://oss.sonatype.org/content/repositories/snapshots'
15 | }
16 | }
17 |
18 | dependencies {
19 | implementation project(":common")
20 | compileOnly 'org.jetbrains:annotations:24.0.1'
21 | compileOnly 'net.md-5:bungeecord-api:1.16-R0.3'
22 | compileOnly "net.kyori:adventure-api:4.13.1"
23 | compileOnly "net.kyori:adventure-platform-bungeecord:4.3.0"
24 | }
25 |
26 | def targetJavaVersion = 17
27 |
28 | java {
29 | def javaVersion = JavaVersion.toVersion(targetJavaVersion)
30 | sourceCompatibility = javaVersion
31 | targetCompatibility = javaVersion
32 | if (JavaVersion.current() < javaVersion) {
33 | toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
34 | }
35 | withSourcesJar()
36 | withJavadocJar()
37 |
38 | }
39 |
40 | compileJava {
41 | options.encoding = "UTF-8"
42 | }
43 |
44 | shadowJar {
45 | setArchiveName("mCommands-Bungee-${project.version}.jar")
46 | }
47 |
48 | publishing {
49 |
50 | publications {
51 |
52 | mavenJava(MavenPublication) {
53 | groupId project.group
54 | artifactId 'mCommands-bungee'
55 | version project.version
56 | from components.java
57 |
58 |
59 | pom {
60 | name = 'mCommands'
61 | description = 'Advanced command dispatching java library'
62 | url = 'https://github.com/Mqzn/mCommands'
63 | inceptionYear = '2023'
64 |
65 | licenses {
66 | license {
67 | name = 'MIT License'
68 | url = 'http://www.opensource.org/licenses/mit-license.php'
69 | }
70 | }
71 | developers {
72 | developer {
73 | id = 'mqzn'
74 | name = 'Mqzen'
75 | email = 'mezoahmed2507@gmail.com'
76 | }
77 | }
78 | scm {
79 | connection = 'scm:git:git:github.com/Mqzn/mCommands.git'
80 | developerConnection = 'scm:git:ssh://github.com/Mqzn/mCommands.git'
81 | url = 'https://github.com/Mqzn/mCommands'
82 | }
83 | }
84 |
85 | }
86 |
87 | }
88 | repositories {
89 | maven {
90 | name = "OSSRH"
91 | url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
92 |
93 | credentials {
94 | username = project.properties["ossrhUsername"]
95 | password = project.properties["ossrhPassword"]
96 | }
97 |
98 | }
99 |
100 | }
101 | }
102 |
103 | signing {
104 | sign publishing.publications.mavenJava
105 | }
106 |
107 | apply plugin: 'java'
108 | apply plugin: 'com.github.johnrengelman.shadow'
109 | apply plugin: 'maven-publish'
110 | apply plugin: 'signing'
111 |
112 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/BungeeCaption.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.base.caption.Caption;
4 | import io.github.mqzn.commands.base.caption.CaptionKey;
5 | import io.github.mqzn.commands.base.caption.Message;
6 | import net.kyori.adventure.text.Component;
7 | import net.kyori.adventure.text.format.NamedTextColor;
8 | import net.md_5.bungee.api.CommandSender;
9 |
10 | public interface BungeeCaption {
11 |
12 | Caption UNKNOWN_COMMAND = Caption.builder(CaptionKey.UNKNOWN_COMMAND)
13 | .withMessage((sender, context, ex) -> Message.prefixed(Message.EXECUTION_ERROR)
14 | .append(Component.text(String.format("Unknown Command In ExecutionMeta '%s'", context.rawFormat()))))
15 | .build();
16 |
17 | Caption NO_PERMISSION = Caption.builder(CaptionKey.NO_PERMISSION)
18 | .withMessage((sender, context, ex) -> Message.prefixed(Message.EXECUTION_ERROR)
19 | .append(Component.text("You don't have the permission to do this !", NamedTextColor.GRAY)))
20 | .build();
21 |
22 |
23 | Caption ONLY_PLAYER_EXECUTABLE = Caption.builder(CaptionKey.ONLY_PLAYER_EXECUTABLE)
24 | .withMessage((sender, context, ex) -> Message.prefixed(Message.EXECUTION_ERROR).append(Component.text("Only a player can execute this !", NamedTextColor.RED)))
25 | .build();
26 |
27 | Caption INVALID_ARGUMENT = Caption.builder(CaptionKey.INVALID_ARGUMENT)
28 | .withMessage((sender, context, ex) -> {
29 | String msg = ex == null ? "Invalid argument used" : ex.getMessage();
30 | return Message.prefixed(Message.INVALID_ARGUMENT_ERROR).append(Component.text(msg, NamedTextColor.DARK_GRAY));
31 | })
32 | .build();
33 |
34 | Caption NO_HELP_TOPIC_AVAILABLE = Caption.builder(CaptionKey.NO_HELP_TOPIC_AVAILABLE)
35 | .withMessage((sender, context, ex) -> Message.prefixed(Message.EXECUTION_ERROR).append(Component.text("There's no help topic for this command '/" + context.commandUsed().name() + "'", NamedTextColor.RED)))
36 | .build();
37 | }
38 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/BungeeCommandManager.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.arguments.ArgumentOnlinePlayer;
4 | import io.github.mqzn.commands.base.Command;
5 | import io.github.mqzn.commands.base.manager.AbstractCommandManager;
6 | import net.md_5.bungee.api.CommandSender;
7 | import net.md_5.bungee.api.connection.ProxiedPlayer;
8 | import net.md_5.bungee.api.plugin.Plugin;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | public final class BungeeCommandManager extends AbstractCommandManager {
12 |
13 |
14 | public BungeeCommandManager(@NotNull Plugin plugin) {
15 | super(plugin, new BungeeSenderWrapper(plugin));
16 |
17 | captionRegistry.registerCaption(BungeeCaption.UNKNOWN_COMMAND);
18 | captionRegistry.registerCaption(BungeeCaption.INVALID_ARGUMENT);
19 | captionRegistry.registerCaption(BungeeCaption.NO_PERMISSION);
20 | captionRegistry.registerCaption(BungeeCaption.ONLY_PLAYER_EXECUTABLE);
21 | captionRegistry.registerCaption(BungeeCaption.NO_HELP_TOPIC_AVAILABLE);
22 |
23 | typeRegistry().registerArgumentConverter(ProxiedPlayer.class, ArgumentOnlinePlayer::new);
24 | }
25 |
26 | @Override
27 | public char commandPrefix() {
28 | return '/';
29 | }
30 |
31 | @Override
32 | public > void registerCommand(C command) {
33 | super.registerCommand(command);
34 | bootstrap.getProxy().getPluginManager().registerCommand(bootstrap, new InternalBungeeCommand(this, command));
35 | }
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/BungeeCommandRequirement.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.base.CommandRequirement;
4 | import io.github.mqzn.commands.base.caption.CaptionKey;
5 | import io.github.mqzn.commands.base.context.Context;
6 | import net.md_5.bungee.api.CommandSender;
7 | import net.md_5.bungee.api.connection.ProxiedPlayer;
8 |
9 | public interface BungeeCommandRequirement extends CommandRequirement {
10 |
11 | BungeeCommandRequirement ONLY_PLAYER_EXECUTABLE = new BungeeCommandRequirement() {
12 | @Override
13 | public boolean accepts(CommandSender sender, Context commandContext) {
14 | return !(sender instanceof ProxiedPlayer);
15 | }
16 |
17 | @Override
18 | public CaptionKey caption() {
19 | return CaptionKey.ONLY_PLAYER_EXECUTABLE;
20 | }
21 |
22 | };
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/BungeeCommandSyntaxBuilder.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.base.syntax.CommandSyntaxBuilder;
4 | import net.md_5.bungee.api.CommandSender;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public final class BungeeCommandSyntaxBuilder extends CommandSyntaxBuilder {
8 |
9 | private BungeeCommandSyntaxBuilder(BungeeCommandManager commandManager,
10 | @NotNull Class senderClass, @NotNull String label) {
11 | super(commandManager, senderClass, label);
12 | }
13 |
14 | public static BungeeCommandSyntaxBuilder builder(BungeeCommandManager manager, @NotNull Class senderClass, @NotNull String label) {
15 | return new BungeeCommandSyntaxBuilder<>(manager, senderClass, label);
16 | }
17 |
18 | public static BungeeCommandSyntaxBuilder builder(BungeeCommandManager manager, @NotNull String label) {
19 | return builder(manager, CommandSender.class, label);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/BungeeSenderWrapper.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.base.SenderWrapper;
4 | import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
5 | import net.kyori.adventure.text.TextComponent;
6 | import net.md_5.bungee.api.ChatColor;
7 | import net.md_5.bungee.api.CommandSender;
8 | import net.md_5.bungee.api.connection.ProxiedPlayer;
9 | import net.md_5.bungee.api.plugin.Plugin;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | final class BungeeSenderWrapper implements SenderWrapper {
14 |
15 | @NotNull
16 | private final BungeeAudiences audiences;
17 |
18 | public BungeeSenderWrapper(Plugin plugin) {
19 | audiences = BungeeAudiences.create(plugin);
20 | }
21 |
22 | @Override
23 | public Class senderType() {
24 | return CommandSender.class;
25 | }
26 |
27 | @Override
28 | public boolean isConsole(CommandSender sender) {
29 | return !(sender instanceof ProxiedPlayer);
30 | }
31 |
32 | @Override
33 | public void sendMessage(CommandSender sender, String msg) {
34 | sender.sendMessage(net.md_5.bungee.api.chat.
35 | TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&', msg)));
36 | }
37 |
38 | @Override
39 | public boolean canBeSender(Class> type) {
40 | return CommandSender.class.isAssignableFrom(type);
41 | }
42 |
43 | @Override
44 | public boolean hasPermission(CommandSender sender, @Nullable String name) {
45 | if (name == null || name.isEmpty())
46 | return true;
47 |
48 | return sender.hasPermission(name);
49 | }
50 |
51 | @Override
52 | public String senderName(CommandSender sender) {
53 | return sender.getName();
54 | }
55 |
56 | @Override
57 | public void sendMessage(CommandSender sender, TextComponent component) {
58 | audiences.sender(sender)
59 | .sendMessage(component);
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/BungeeSubCommandBuilder.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.base.syntax.SubCommandBuilder;
4 | import net.md_5.bungee.api.CommandSender;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public final class BungeeSubCommandBuilder extends SubCommandBuilder {
8 | private BungeeSubCommandBuilder(BungeeCommandManager manager, @NotNull Class senderClass, @NotNull String label, @NotNull String name) {
9 | super(manager, senderClass, label, name);
10 | }
11 |
12 | /**
13 | * @param manager the bungee command-manager
14 | * @param senderClass the type of the sender to use
15 | * @param label the command label
16 | * @param name the name of the subcommand
17 | * @param the type of the sender to use while building the subcommand's syntax
18 | * @return the builder of subcommands in the bungee-cord platform
19 | */
20 | public static BungeeSubCommandBuilder builder(BungeeCommandManager manager,
21 | @NotNull Class senderClass,
22 | @NotNull String label,
23 | @NotNull String name) {
24 | return new BungeeSubCommandBuilder<>(manager, senderClass, label, name);
25 | }
26 |
27 | public static BungeeSubCommandBuilder builder(BungeeCommandManager manager, @NotNull String label, @NotNull String name) {
28 | return builder(manager, CommandSender.class, label, name);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/InternalBungeeCommand.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands;
2 |
3 | import io.github.mqzn.commands.base.Command;
4 | import net.md_5.bungee.api.CommandSender;
5 | import net.md_5.bungee.api.plugin.TabExecutor;
6 | import org.jetbrains.annotations.ApiStatus;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | @ApiStatus.Internal
10 | final class InternalBungeeCommand extends net.md_5.bungee.api.plugin.Command implements TabExecutor {
11 |
12 | @NotNull
13 | private final BungeeCommandManager manager;
14 |
15 | @NotNull
16 | private final Command command;
17 |
18 | public InternalBungeeCommand(@NotNull BungeeCommandManager manager, @NotNull Command command) {
19 | super(command.name(), command.info().permission(), command.info().aliases());
20 | this.manager = manager;
21 | this.command = command;
22 | }
23 |
24 | @Override
25 | public void execute(CommandSender commandSender, String[] args) {
26 | manager.executeCommand(command, commandSender, args);
27 | }
28 |
29 |
30 | @Override
31 | public Iterable onTabComplete(CommandSender commandSender, String[] args) {
32 | return manager.suggest(command, commandSender, args);
33 | }
34 |
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/arguments/ArgumentOnlinePlayer.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import io.github.mqzn.commands.exceptions.types.ArgumentParseException;
4 | import net.md_5.bungee.api.ProxyServer;
5 | import net.md_5.bungee.api.connection.ProxiedPlayer;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.UnknownNullability;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public final class ArgumentOnlinePlayer extends AbstractArgument {
13 |
14 |
15 | public ArgumentOnlinePlayer(@NotNull String id) {
16 | super(id, ProxiedPlayer.class);
17 | }
18 |
19 | public ArgumentOnlinePlayer(@NotNull String id, boolean optional, boolean useRemainingSpace) {
20 | super(id, ProxiedPlayer.class, optional, useRemainingSpace);
21 | }
22 |
23 | public ArgumentOnlinePlayer(String id, boolean useRemainingSpace) {
24 | super(id, ProxiedPlayer.class, useRemainingSpace);
25 | }
26 |
27 | public ArgumentOnlinePlayer(@NotNull ArgumentData data) {
28 | super(data, ProxiedPlayer.class);
29 | }
30 |
31 | @Override
32 | public ProxiedPlayer parse(@UnknownNullability S sender, @NotNull String command, @NotNull String input) throws ArgumentParseException {
33 |
34 | ProxiedPlayer player = ProxyServer.getInstance().getPlayer(input);
35 | if (player == null || !player.isConnected()) {
36 | throw new ArgumentParseException(String.format("Player %s is offline or doesn't exist", input), input, command);
37 | }
38 |
39 | return player;
40 | }
41 |
42 | @Override
43 | public @NotNull List suggestions() {
44 | return new ArrayList<>(ProxyServer.getInstance().getPlayers());
45 | }
46 |
47 | @Override
48 | public boolean isSuggestionDynamic() {
49 | return true;
50 | }
51 |
52 | @Override
53 | public String toString(ProxiedPlayer obj) {
54 | return obj.getName();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/arguments/BungeeArgument.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | public interface BungeeArgument {
4 |
5 | static ArgumentOnlinePlayer onlinePlayer(String id) {
6 | return new ArgumentOnlinePlayer(id);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/bungee/src/main/java/io/github/mqzn/commands/help/BungeeCommandHelpProvider.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.help;
2 |
3 | import net.md_5.bungee.api.CommandSender;
4 |
5 | public interface BungeeCommandHelpProvider extends CommandHelpProvider {
6 | }
7 |
--------------------------------------------------------------------------------
/common/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.8.21'
3 | repositories {
4 | mavenCentral()
5 | }
6 | dependencies {
7 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
8 | }
9 | }
10 |
11 |
12 | plugins {
13 | id 'java'
14 | id 'maven-publish'
15 | id 'signing'
16 | id "org.jetbrains.kotlin.jvm" version "1.8.21"
17 | }
18 |
19 |
20 | group 'io.github.mqzn'
21 | version '1.1.7'
22 |
23 | repositories {
24 | mavenCentral()
25 | }
26 |
27 | dependencies {
28 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
29 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
30 |
31 | testImplementation 'org.projectlombok:lombok:1.18.22'
32 | testImplementation 'org.jetbrains:annotations:23.0.0'
33 | testImplementation "net.kyori:adventure-api:4.13.1"
34 |
35 | compileOnly 'org.jetbrains:annotations:24.0.1'
36 | compileOnly "net.kyori:adventure-api:4.13.1"
37 |
38 | }
39 |
40 | java {
41 | withSourcesJar()
42 | withJavadocJar()
43 | }
44 |
45 | def targetJavaVersion = 17
46 |
47 | java {
48 | def javaVersion = JavaVersion.toVersion(targetJavaVersion)
49 | sourceCompatibility = javaVersion
50 | targetCompatibility = javaVersion
51 | if (JavaVersion.current() < javaVersion) {
52 | toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
53 | }
54 |
55 | withSourcesJar()
56 | withJavadocJar()
57 |
58 | }
59 |
60 | kotlin {
61 | sourceCompatibility = targetJavaVersion
62 | targetCompatibility = targetJavaVersion
63 | }
64 |
65 |
66 | publishing {
67 | publications {
68 | mavenJava(MavenPublication) {
69 | groupId project.group
70 | artifactId 'mCommands-common'
71 | version project.version
72 | from components.java
73 |
74 |
75 | pom {
76 | name = 'mCommands'
77 | description = 'Advanced command dispatching java library'
78 | url = 'https://github.com/Mqzn/mCommands'
79 | inceptionYear = '2023'
80 |
81 | licenses {
82 | license {
83 | name = 'MIT License'
84 | url = 'http://www.opensource.org/licenses/mit-license.php'
85 | }
86 | }
87 | developers {
88 | developer {
89 | id = 'mqzn'
90 | name = 'Mqzen'
91 | email = 'mezoahmed2507@gmail.com'
92 | }
93 | }
94 | scm {
95 | connection = 'scm:git:git:github.com/Mqzn/mCommands.git'
96 | developerConnection = 'scm:git:ssh://github.com/Mqzn/mCommands.git'
97 | url = 'https://github.com/Mqzn/mCommands'
98 | }
99 | }
100 |
101 | }
102 |
103 | }
104 | repositories {
105 | maven {
106 | name = "OSSRH"
107 | url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
108 |
109 | credentials {
110 | username = project.properties["ossrhUsername"]
111 | password = project.properties["ossrhPassword"]
112 | }
113 |
114 | }
115 |
116 | }
117 | }
118 |
119 | signing {
120 | sign publishing.publications.mavenJava
121 | }
122 |
123 | test {
124 | useJUnitPlatform()
125 | }
126 |
127 | apply plugin: 'java'
128 | apply plugin: 'kotlin'
129 | apply plugin: 'maven-publish'
130 | apply plugin: 'signing'
131 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Arg.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target({ElementType.PARAMETER})
10 | public @interface Arg {
11 |
12 | String id();
13 |
14 | boolean optional() default false;
15 |
16 | String defaultValue() default "";
17 |
18 | String description() default "";
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Command.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import io.github.mqzn.commands.base.CommandRequirement;
4 | import io.github.mqzn.commands.base.manager.CommandExecutionCoordinator;
5 |
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Retention;
8 | import java.lang.annotation.RetentionPolicy;
9 | import java.lang.annotation.Target;
10 |
11 | @Retention(RetentionPolicy.RUNTIME)
12 | @Target(ElementType.TYPE)
13 | public @interface Command {
14 | String name();
15 |
16 | CommandExecutionCoordinator.Type executionType() default CommandExecutionCoordinator.Type.SYNC;
17 |
18 | String permission() default "";
19 |
20 | String description() default "";
21 |
22 | String[] aliases() default {};
23 |
24 | Class extends CommandRequirement>>[] requirements() default {};
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/CommandsGroup.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.TYPE)
10 | public @interface CommandsGroup {
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Cooldown.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Target(ElementType.TYPE)
11 | public @interface Cooldown {
12 |
13 | long value();
14 |
15 | TimeUnit unit() default TimeUnit.SECONDS;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Default.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.METHOD)
10 | public @interface Default {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/ExecutionMeta.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Target({ElementType.METHOD, ElementType.TYPE})
11 | public @interface ExecutionMeta {
12 |
13 | String syntax() default "";
14 |
15 | Class> senderType() default Object.class;
16 |
17 | String description() default "";
18 |
19 | String permission() default "";
20 |
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Flag.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.PARAMETER)
10 | public @interface Flag {
11 |
12 | String name();
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Greedy.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.PARAMETER)
10 | public @interface Greedy {
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Range.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.PARAMETER)
10 | public @interface Range {
11 |
12 | String min() default "";
13 |
14 | String max() default "";
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/base/Suggest.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.base;
2 |
3 | import io.github.mqzn.commands.base.SuggestionProvider;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | @Retention(RetentionPolicy.RUNTIME)
11 | @Target(ElementType.PARAMETER)
12 | public @interface Suggest {
13 |
14 | String[] value() default {};
15 |
16 | Class extends SuggestionProvider> provider() default SuggestionProvider.class;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/subcommands/SubCommand.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.subcommands;
2 |
3 | import java.lang.annotation.*;
4 |
5 | @Retention(RetentionPolicy.RUNTIME)
6 | @Target({ElementType.TYPE})
7 | @Repeatable(SubCommands.class)
8 | public @interface SubCommand {
9 |
10 | Class> value();
11 | }
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/subcommands/SubCommandExecution.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.subcommands;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.METHOD)
10 | public @interface SubCommandExecution {
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/subcommands/SubCommandInfo.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.subcommands;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target(ElementType.TYPE)
10 | public @interface SubCommandInfo {
11 |
12 | String name();
13 |
14 | Class> parent() default Object.class;
15 |
16 | Class>[] children() default {};
17 |
18 | String[] aliases() default {};
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/annotations/subcommands/SubCommands.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.annotations.subcommands;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target({ElementType.TYPE})
10 | public @interface SubCommands {
11 |
12 | SubCommand[] value() default {};
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentBoolean.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import io.github.mqzn.commands.exceptions.types.ArgumentParseException;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.UnknownNullability;
6 |
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | public final class ArgumentBoolean extends AbstractArgument {
11 | ArgumentBoolean(String id) {
12 | super(id, Boolean.class);
13 | }
14 |
15 | ArgumentBoolean(ArgumentData data) {
16 | super(data, Boolean.class);
17 | }
18 |
19 | @Override
20 | public Boolean parse(@UnknownNullability S sender, @NotNull String command, @NotNull String input) throws ArgumentParseException {
21 |
22 | if (!input.equalsIgnoreCase("true") && !input.equalsIgnoreCase("false") && !input.equalsIgnoreCase("no") && !input.equalsIgnoreCase("yes"))
23 | throw new ArgumentParseException("Argument '" + id() + "' should be boolean, the input '" + input + "' is not a valid boolean", input, command);
24 |
25 | return input.equalsIgnoreCase("true")
26 | || input.equalsIgnoreCase("yes");
27 | }
28 |
29 | @Override
30 | public @NotNull List suggestions() {
31 | return Arrays.asList(true, false);
32 | }
33 |
34 | @Override
35 | public Class>[] alternativeTypes() {
36 | return new Class[]{boolean.class};
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentData.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public final class ArgumentData {
6 |
7 | @NotNull
8 | private final String id;
9 |
10 | private final boolean optional;
11 |
12 | private final boolean useRemainingSpace;
13 |
14 | private ArgumentData(@NotNull String id, boolean optional, boolean useRemainingSpace) {
15 | this.id = id;
16 | this.optional = optional;
17 | this.useRemainingSpace = useRemainingSpace;
18 | }
19 |
20 | private ArgumentData(@NotNull String id) {
21 | this(id, false, false);
22 | }
23 |
24 | public static ArgumentData of(@NotNull String id, boolean optional, boolean useRemainingSpace) {
25 | return new ArgumentData(id, optional, useRemainingSpace);
26 | }
27 |
28 | public static ArgumentData of(@NotNull String id) {
29 | return new ArgumentData(id);
30 | }
31 |
32 | public @NotNull String getId() {
33 | return id;
34 | }
35 |
36 | public boolean isOptional() {
37 | return optional;
38 | }
39 |
40 | public boolean isUseRemainingSpace() {
41 | return useRemainingSpace;
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentDouble.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public final class ArgumentDouble extends ArgumentNumber {
6 |
7 |
8 | ArgumentDouble(@NotNull String id) {
9 | super(id, Double.class, Double::parseDouble,
10 | ((s, radix) -> (double) Long.parseLong(s, radix)), Double::compare);
11 | }
12 |
13 | ArgumentDouble(@NotNull ArgumentData data) {
14 | super(data, Double.class, Double::parseDouble,
15 | ((s, radix) -> (double) Long.parseLong(s, radix)), Double::compare);
16 | }
17 |
18 | @Override
19 | public Class>[] alternativeTypes() {
20 | return new Class[]{double.class};
21 | }
22 |
23 |
24 | @Override
25 | public Double increment(Double num) {
26 | return num + 1D;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentEnum.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import io.github.mqzn.commands.exceptions.types.ArgumentParseException;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.Locale;
9 | import java.util.function.UnaryOperator;
10 |
11 | public final class ArgumentEnum> extends AbstractArgument {
12 |
13 | private final Class enumClass;
14 | private final E[] values;
15 | private Format format = Format.DEFAULT;
16 |
17 | public ArgumentEnum(@NotNull String id, Class enumClass) {
18 | super(id, enumClass);
19 | this.enumClass = enumClass;
20 | this.values = enumClass.getEnumConstants();
21 | }
22 |
23 | public ArgumentEnum(@NotNull ArgumentData data, Class enumClass) {
24 | super(data, enumClass);
25 | this.enumClass = enumClass;
26 | this.values = enumClass.getEnumConstants();
27 | }
28 |
29 | public ArgumentEnum setFormat(@NotNull Format format) {
30 | this.format = format;
31 | return this;
32 | }
33 |
34 | @NotNull
35 | @Override
36 | public E parse(@NotNull S sender,
37 | @NotNull String command,
38 | @NotNull String input) throws ArgumentParseException {
39 | for (E value : this.values) {
40 | if (this.format.formatter.apply(value.name()).equals(input)) {
41 | return value;
42 | }
43 | }
44 | throw new ArgumentParseException("Not a " + this.enumClass.getSimpleName() + " value", input, command);
45 | }
46 |
47 | public List entries() {
48 | return Arrays.stream(values).map(x -> format.formatter.apply(x.name())).toList();
49 | }
50 |
51 | @Override
52 | public String toString(E obj) {
53 | return obj.name();
54 | }
55 |
56 | public enum Format {
57 | DEFAULT(name -> name),
58 | LOWER_CASED(name -> name.toLowerCase(Locale.ROOT)),
59 | UPPER_CASED(name -> name.toUpperCase(Locale.ROOT));
60 |
61 | private final UnaryOperator formatter;
62 |
63 | Format(@NotNull UnaryOperator formatter) {
64 | this.formatter = formatter;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentFloat.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public final class ArgumentFloat extends ArgumentNumber {
6 |
7 | ArgumentFloat(@NotNull String id) {
8 | super(id, Float.class, Float::parseFloat,
9 | ((s, radix) -> (float) Long.parseLong(s, radix)), Float::compare);
10 | }
11 |
12 | ArgumentFloat(@NotNull ArgumentData data) {
13 | super(data, Float.class, Float::parseFloat,
14 | ((s, radix) -> (float) Long.parseLong(s, radix)), Float::compare);
15 | }
16 |
17 |
18 | @Override
19 | public Class>[] alternativeTypes() {
20 | return new Class[]{float.class};
21 | }
22 |
23 | @Override
24 | public Float increment(Float num) {
25 | return num + 1F;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentInteger.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | public final class ArgumentInteger extends ArgumentNumber {
4 |
5 | ArgumentInteger(String id) {
6 | super(id, Integer.class,
7 | Integer::parseInt,
8 | Integer::parseInt,
9 | Integer::compare);
10 | }
11 |
12 | ArgumentInteger(ArgumentData data) {
13 | super(data, Integer.class,
14 | Integer::parseInt,
15 | Integer::parseInt,
16 | Integer::compare);
17 | }
18 |
19 | @Override
20 | public Class>[] alternativeTypes() {
21 | return new Class[]{int.class};
22 | }
23 |
24 | @Override
25 | public Integer increment(Integer num) {
26 | return num + 1;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentLiteral.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import io.github.mqzn.commands.base.syntax.CommandAliases;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 | import org.jetbrains.annotations.UnknownNullability;
7 |
8 | public final class ArgumentLiteral extends AbstractArgument {
9 |
10 | @NotNull
11 | private CommandAliases commandAliases = CommandAliases.of();
12 |
13 | ArgumentLiteral(String id) {
14 | super(id, String.class);
15 | suggestions.add(id);
16 | }
17 |
18 | ArgumentLiteral(ArgumentData data) {
19 | super(data, String.class);
20 | suggestions.add(data.getId());
21 | }
22 |
23 | @Override
24 | public String parse(@UnknownNullability S sender, @NotNull String command, @NotNull String input) {
25 | return input;
26 | }
27 |
28 | @Override
29 | public @Nullable String defaultValue() {
30 | return id();
31 | }
32 |
33 | @Override
34 | public @NotNull Argument setDefaultValue(@Nullable String value) {
35 | throw new UnsupportedOperationException("Argument is a literal, it cannot have a default value !");
36 | }
37 |
38 | @Override
39 | public boolean isOptional() {
40 | return false;
41 | }
42 |
43 | public ArgumentLiteral aliases(String... aliases) {
44 | this.commandAliases = CommandAliases.of(aliases);
45 | for (String aliase : aliases) {
46 | if (!suggestions.contains(aliase)) {
47 | suggestions.add(aliase);
48 | }
49 | }
50 | return this;
51 | }
52 |
53 | @Override
54 | public Class>[] alternativeTypes() {
55 | return super.alternativeTypes();
56 | }
57 |
58 | @Override
59 | public Argument suggest(@NotNull String suggestion) {
60 | throw new UnsupportedOperationException("You cannot do that for a literal argument");
61 | }
62 |
63 | public @NotNull CommandAliases getAliases() {
64 | return commandAliases;
65 | }
66 |
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentLong.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public final class ArgumentLong extends ArgumentNumber {
6 |
7 | ArgumentLong(@NotNull String id) {
8 | super(id, Long.class, Long::parseLong, Long::parseLong, Long::compare);
9 | }
10 |
11 | ArgumentLong(@NotNull ArgumentData data) {
12 | super(data, Long.class, Long::parseLong, Long::parseLong, Long::compare);
13 | }
14 |
15 |
16 | @Override
17 | public Class>[] alternativeTypes() {
18 | return new Class[]{long.class};
19 | }
20 |
21 | @Override
22 | public Long increment(Long num) {
23 | return num + 1;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentNumber.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import io.github.mqzn.commands.exceptions.types.ArgumentParseException;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 | import org.jetbrains.annotations.UnknownNullability;
7 |
8 | import java.math.BigDecimal;
9 | import java.util.Comparator;
10 | import java.util.function.BiFunction;
11 | import java.util.function.Function;
12 | import java.util.regex.Pattern;
13 |
14 | /**
15 | * A class that represents any numeric argument
16 | *
17 | * @param the type of the number
18 | */
19 | public abstract class ArgumentNumber extends AbstractArgument {
20 |
21 | protected final BiFunction radixParser;
22 |
23 | protected final Function parser;
24 |
25 | protected final Comparator comparator;
26 |
27 |
28 | protected boolean hasMin, hasMax;
29 |
30 | @Nullable
31 | protected T min, max;
32 |
33 | ArgumentNumber(@NotNull String id, Class type,
34 | Function parser,
35 | BiFunction radixParser,
36 | Comparator comparator) {
37 | super(id, type);
38 | this.radixParser = radixParser;
39 | this.parser = parser;
40 | this.comparator = comparator;
41 |
42 | }
43 |
44 | ArgumentNumber(@NotNull ArgumentData data, Class type,
45 | Function parser,
46 | BiFunction radixParser,
47 | Comparator comparator) {
48 | super(data, type);
49 | this.radixParser = radixParser;
50 | this.parser = parser;
51 | this.comparator = comparator;
52 | }
53 |
54 | @Override
55 | public @NotNull T parse(@UnknownNullability S sender,
56 | @NotNull String command,
57 | @NotNull String input) throws ArgumentParseException {
58 | try {
59 | final T value;
60 | final int radix = getRadix(input);
61 | if (radix == 10) {
62 | value = parser.apply(parseValue(input));
63 | } else {
64 | value = radixParser.apply(parseValue(input), radix);
65 | }
66 |
67 | // Check range
68 | if (hasMin && comparator.compare(value, min) < 0) {
69 | throw new ArgumentParseException(String.format("Input '%s' is lower than the minimum allowed value", input), input, command);
70 | }
71 | if (hasMax && comparator.compare(value, max) > 0) {
72 | throw new ArgumentParseException(String.format("Input '%s' is higher than the maximum allowed value", input), input, command);
73 | }
74 |
75 | return value;
76 | } catch (NumberFormatException | NullPointerException e) {
77 | throw new ArgumentParseException(String.format("Input '%s' is not a number, or it's invalid for the given type", input), input, command);
78 | }
79 | }
80 |
81 |
82 | @NotNull
83 | public ArgumentNumber min(@NotNull T value) {
84 | this.min = value;
85 | this.hasMin = true;
86 | return this;
87 | }
88 |
89 | @NotNull
90 | @SuppressWarnings("UnusedReturnValue")
91 | public ArgumentNumber max(@NotNull T value) {
92 | this.max = value;
93 | this.hasMax = true;
94 |
95 | return this;
96 | }
97 |
98 | @NotNull
99 | public ArgumentNumber between(@NotNull T min, @NotNull T max) {
100 | this.min = min;
101 | this.max = max;
102 | this.hasMin = true;
103 | this.hasMax = true;
104 | return this;
105 | }
106 |
107 |
108 | /**
109 | * Gets if the argument has a minimum.
110 | *
111 | * @return true if the argument has a minimum
112 | */
113 | public boolean hasMin() {
114 | return hasMin;
115 | }
116 |
117 | /**
118 | * Gets the minimum value for this argument.
119 | *
120 | * @return the minimum of this argument
121 | */
122 | public @Nullable T getMin() {
123 | return min;
124 | }
125 |
126 | /**
127 | * Gets if the argument has a maximum.
128 | *
129 | * @return true if the argument has a maximum
130 | */
131 | public boolean hasMax() {
132 | return hasMax;
133 | }
134 |
135 | /**
136 | * Gets the maximum value for this argument.
137 | *
138 | * @return the maximum of this argument
139 | */
140 | public @Nullable T getMax() {
141 | return max;
142 | }
143 |
144 | @NotNull
145 | protected String parseValue(@NotNull String value) {
146 | if (value.startsWith("0b")) {
147 | value = value.replaceFirst(Pattern.quote("0b"), "");
148 | } else if (value.startsWith("0x")) {
149 | value = value.replaceFirst(Pattern.quote("0x"), "");
150 | } else if (value.toLowerCase().contains("e")) {
151 | value = removeScientificNotation(value);
152 | }
153 | // TODO number suffix support (k,m,b,t)
154 | assert value != null;
155 | return value;
156 | }
157 |
158 | protected int getRadix(@NotNull String value) {
159 | if (value.startsWith("0b")) {
160 | return 2;
161 | } else if (value.startsWith("0x")) {
162 | return 16;
163 | }
164 | return 10;
165 | }
166 |
167 | @Nullable
168 | protected String removeScientificNotation(@NotNull String value) {
169 | try {
170 | return new BigDecimal(value).toPlainString();
171 | } catch (NumberFormatException e) {
172 | return null;
173 | }
174 | }
175 |
176 |
177 | public abstract T increment(T num);
178 |
179 | public Function getParser() {
180 | return parser;
181 | }
182 |
183 | }
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentStringArray.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.jetbrains.annotations.UnknownNullability;
5 |
6 | import java.util.regex.Pattern;
7 |
8 | public final class ArgumentStringArray extends AbstractArgument {
9 |
10 | ArgumentStringArray(String id) {
11 | super(id, String[].class, false, true);
12 | }
13 |
14 | @Override
15 | public String[] parse(@UnknownNullability S sender,
16 | @NotNull String command,
17 | @NotNull String input) {
18 | return input.split(Pattern.quote(" "));
19 | }
20 |
21 | @Override
22 | public String toString(String[] obj) {
23 | return String.join(" ", obj);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/arguments/ArgumentWord.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.arguments;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.jetbrains.annotations.UnknownNullability;
5 |
6 | public final class ArgumentWord extends AbstractArgument {
7 |
8 | ArgumentWord(String id) {
9 | super(id, String.class);
10 | }
11 |
12 | ArgumentWord(ArgumentData data) {
13 | super(data, String.class);
14 | }
15 |
16 | @Override
17 | public String parse(@UnknownNullability S sender,
18 | @NotNull String command,
19 | @NotNull String input) {
20 | return input;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/CommandInfo.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base;
2 |
3 | /**
4 | * A record that holds some information to it
5 | * such as the permission of the command, it's description
6 | * and it's aliases !
7 | *
8 | * @param permission the permission of the command
9 | * @param description the description explaining the purpose of the command
10 | * @param aliases the aliases of the command
11 | */
12 | public record CommandInfo(String permission,
13 | String description,
14 | String... aliases) {
15 |
16 |
17 | public static final CommandInfo EMPTY_INFO = new CommandInfo(null, "");
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/CommandRequirement.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base;
2 |
3 | import io.github.mqzn.commands.base.caption.CaptionKey;
4 | import io.github.mqzn.commands.base.context.Context;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | /**
8 | * Represents a requirement/criteria
9 | * that must be true for the command to be executed
10 | *
11 | * @param the sender type
12 | */
13 | public interface CommandRequirement {
14 |
15 | /**
16 | * Whether the criteria are true or not
17 | *
18 | * @param sender the command sender
19 | * @param commandContext the context used
20 | * @return Whether the criteria are true or not
21 | */
22 | boolean accepts(S sender, Context commandContext);
23 |
24 | /**
25 | * The caption that will be sent
26 | * to the user if the criteria is false
27 | *
28 | * @return null if no caption to send,
29 | * otherwise it will return the key of the caption to send
30 | */
31 | @Nullable CaptionKey caption();
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/Information.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base;
2 |
3 | public record Information(String permission, String description) {
4 | }
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/SenderProvider.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public interface SenderProvider {
6 |
7 |
8 | static SenderProvider self() {
9 |
10 | return (s) -> s;
11 | }
12 |
13 | C mapSender(@NotNull S sender);
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/SenderWrapper.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base;
2 |
3 | import net.kyori.adventure.text.TextComponent;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | public interface SenderWrapper {
7 |
8 | Class senderType();
9 |
10 | boolean isConsole(S sender);
11 |
12 | void sendMessage(S sender, String msg);
13 |
14 | void sendMessage(S sender, TextComponent component);
15 |
16 | boolean canBeSender(Class> type);
17 |
18 | boolean hasPermission(S sender, @Nullable String name);
19 |
20 | String senderName(S sender);
21 | }
22 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/SuggestionProvider.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * An interface that represents
9 | * a function to provide suggestions for
10 | * an argument for annotation parsing purposes
11 | *
12 | * @author Mqzen
13 | */
14 | public interface SuggestionProvider {
15 |
16 | /**
17 | * The suggestions to be used for the argument
18 | *
19 | * @return the suggestions
20 | */
21 | @NotNull List suggestions();
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/caption/Caption.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.caption;
2 |
3 | import io.github.mqzn.commands.base.context.Context;
4 | import net.kyori.adventure.text.Component;
5 | import net.kyori.adventure.text.TextComponent;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | public interface Caption {
10 |
11 |
12 | static @NotNull Builder builder(CaptionKey key) {
13 | return new Builder<>(key);
14 | }
15 |
16 | @NotNull CaptionKey key();
17 |
18 | @NotNull TextComponent message(S sender, Context context, Throwable exception);
19 |
20 | interface CaptionResult {
21 |
22 | @NotNull TextComponent messageResult(@NotNull S sender,
23 | @NotNull Context context,
24 | @Nullable Throwable exception);
25 |
26 | }
27 |
28 | final class Builder {
29 |
30 | @NotNull
31 | private final CaptionKey key;
32 |
33 | @NotNull
34 | private CaptionResult messageCreator = (cmd, s, ex) -> Component.empty();
35 |
36 | Builder(@NotNull CaptionKey key) {
37 | this.key = key;
38 | }
39 |
40 | public @NotNull Builder withMessage(@NotNull CaptionResult messageCreator) {
41 | this.messageCreator = messageCreator;
42 | return this;
43 | }
44 |
45 |
46 | public Caption build() {
47 | return new ImmutableCaption<>(key, messageCreator);
48 | }
49 |
50 | record ImmutableCaption(CaptionKey key, CaptionResult messageCreator) implements Caption {
51 |
52 |
53 | @Override
54 | public @NotNull TextComponent message(@NotNull S sender,
55 | @NotNull Context context,
56 | @Nullable Throwable exception) {
57 | return messageCreator.messageResult(sender, context, exception);
58 | }
59 |
60 | }
61 |
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/caption/CaptionKey.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.caption;
2 |
3 |
4 | import java.util.Objects;
5 |
6 | public final class CaptionKey {
7 |
8 |
9 | public final static CaptionKey UNKNOWN_COMMAND = CaptionKey.of("execution.unknown-command");
10 | public final static CaptionKey NO_PERMISSION = CaptionKey.of("execution.no-permission");
11 | public final static CaptionKey ONLY_PLAYER_EXECUTABLE = CaptionKey.of("execution.only-player-allowed");
12 | public final static CaptionKey INVALID_ARGUMENT = CaptionKey.of("argument.parsing-invalid");
13 | public static final CaptionKey NO_HELP_TOPIC_AVAILABLE = CaptionKey.of("execution.unknown-help-topic");
14 | public static final CaptionKey UNKNOWN_HELP_PAGE = CaptionKey.of("execution.unknown-help-page");
15 | public static final CaptionKey COMMAND_IN_COOLDOWN = CaptionKey.of("execution.command-cooldown");
16 |
17 | private final String key;
18 |
19 | private CaptionKey(String key) {
20 | this.key = key;
21 | }
22 |
23 | public static CaptionKey of(String key) {
24 | return new CaptionKey(key);
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return key;
30 | }
31 |
32 | @Override
33 | public boolean equals(Object o) {
34 | if (this == o) return true;
35 | if (!(o instanceof CaptionKey key1)) return false;
36 | return Objects.equals(key, key1.key);
37 | }
38 |
39 | @Override
40 | public int hashCode() {
41 | return Objects.hash(key);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/caption/CaptionRegistry.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.caption;
2 |
3 | import io.github.mqzn.commands.base.context.Context;
4 | import io.github.mqzn.commands.base.manager.CommandManager;
5 | import org.jetbrains.annotations.NotNull;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class CaptionRegistry {
12 |
13 | private final CommandManager, S> manager;
14 |
15 | @NotNull
16 | private final Map> captions;
17 |
18 | public CaptionRegistry(CommandManager, S> manager) {
19 | this.manager = manager;
20 | this.captions = new HashMap<>();
21 | }
22 |
23 | public void registerCaption(Caption caption) {
24 | captions.put(caption.key(), caption);
25 | }
26 |
27 | public void unregisterCaption(Caption caption) {
28 | captions.remove(caption.key());
29 | }
30 |
31 | @Nullable
32 | public Caption getCaption(CaptionKey key) {
33 | return captions.get(key);
34 | }
35 |
36 | public void sendCaption(@NotNull S sender,
37 | @NotNull Context commandContext,
38 | @Nullable Throwable exception,
39 | @NotNull CaptionKey key) {
40 | var caption = getCaption(key);
41 |
42 | if (caption == null) return;
43 | sendCaption(sender, commandContext, exception, caption);
44 | }
45 |
46 | public void sendCaption(S sender, Context commandContext, CaptionKey key) {
47 | this.sendCaption(sender, commandContext, null, key);
48 | }
49 |
50 | public void sendCaption(@NotNull S sender,
51 | @NotNull Context commandContext,
52 | @Nullable Throwable exception,
53 | @NotNull Caption caption) {
54 | var text = caption.message(sender, commandContext, exception);
55 | manager.getSenderWrapper().sendMessage(sender, text);
56 | }
57 |
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/caption/Message.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.caption;
2 |
3 | import net.kyori.adventure.text.Component;
4 | import net.kyori.adventure.text.TextComponent;
5 | import net.kyori.adventure.text.format.NamedTextColor;
6 |
7 | public interface Message {
8 |
9 | TextComponent PREFIX = Component.text("[", NamedTextColor.DARK_GRAY)
10 | .append(Component.text("!", NamedTextColor.DARK_RED))
11 | .append(Component.text("]", NamedTextColor.DARK_GRAY))
12 | .append(Component.space());
13 |
14 | TextComponent EXECUTION_ERROR = Component.text("Execution Error: ", NamedTextColor.RED);
15 |
16 | TextComponent INVALID_ARGUMENT_ERROR = Component.text("Invalid Argument: ", NamedTextColor.RED);
17 |
18 |
19 | static TextComponent prefixed(TextComponent component) {
20 | return PREFIX.append(component);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/context/CommandArgs.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.context;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Iterator;
8 | import java.util.List;
9 |
10 | public final class CommandArgs implements Iterable {
11 |
12 | private final List args = new ArrayList<>();
13 |
14 | private CommandArgs(Context context) {
15 | args.addAll(context.getRawArguments());
16 | }
17 |
18 | public static CommandArgs create(Context context) {
19 | return new CommandArgs(context);
20 | }
21 |
22 | @Nullable
23 | public String getRaw(int index) {
24 | if (!verifyIndex(index)) return null;
25 | return args.get(index);
26 | }
27 |
28 | @Nullable
29 | public String getAfterRaw(String raw) {
30 | int index = args.indexOf(raw);
31 | if (!verifyIndex(index)) return null;
32 | return args.get(index);
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "Raw-arguments => " + String.join(" ", this);
38 | }
39 |
40 | /**
41 | * Returns an iterator over elements of type {@code T}.
42 | *
43 | * @return an Iterator.
44 | */
45 | @NotNull
46 | @Override
47 | public Iterator iterator() {
48 | return args.iterator();
49 | }
50 |
51 | private boolean verifyIndex(int index) {
52 | return index >= 0 && index < args.size();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/context/Context.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.context;
2 |
3 | import io.github.mqzn.commands.arguments.Argument;
4 | import io.github.mqzn.commands.base.Command;
5 | import io.github.mqzn.commands.base.manager.flags.ContextFlagRegistry;
6 | import io.github.mqzn.commands.base.syntax.CommandSyntax;
7 | import io.github.mqzn.commands.exceptions.types.ArgumentParseException;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import java.util.List;
12 |
13 | public interface Context {
14 |
15 |
16 | /**
17 | * Fetches the number of flags used in the raw arguments
18 | *
19 | * @return the count of flags used in raw args
20 | */
21 | int flagsUsed();
22 |
23 | /**
24 | * Fetches the sender for this context
25 | *
26 | * @return the context command sender
27 | */
28 | @NotNull S sender();
29 |
30 | /**
31 | * The command found and used in the context
32 | * made by the command sender
33 | *
34 | * @return the command used !
35 | * @see Command
36 | */
37 | @NotNull Command commandUsed();
38 |
39 | /**
40 | * The raw arguments used in the context
41 | * made by the command sender
42 | *
43 | * @return The raw arguments
44 | */
45 | @NotNull List getRawArguments();
46 |
47 | /**
48 | * The raw arguments formatted using the
49 | * command used
50 | *
51 | * @return the raw format used in the context
52 | * @see Command
53 | * @see CommandContext
54 | */
55 | @NotNull String rawFormat();
56 |
57 | /**
58 | * Fetches the raw argument from the input in the
59 | * constructor
60 | *
61 | * @param index the index of the raw argument to fetch
62 | * @return the raw argument at a specific position
63 | */
64 | @Nullable String getRawArgument(int index);
65 |
66 |
67 | /**
68 | * Fetches the parsed argument value
69 | * may return null if the value parsed is not valid
70 | * some cases of failed argument parsing may be like this one:
71 | * an integer argument with min of 1 and max of 10, however the input was "one"
72 | * or may be "-1" which is not a valid value .
73 | *
74 | * @param id the argument name/id
75 | * @param the type of arg value
76 | * @return the parsed value of the argument
77 | */
78 | @Nullable T getArgument(String id);
79 |
80 |
81 | /**
82 | * Fetches the parsed argument value
83 | * may return null if the value parsed is not valid
84 | * some cases of failed argument parsing may be like this one:
85 | * an integer argument with min of 1 and max of 10, however the input was "one"
86 | * or may be "-1" which is not a valid value .
87 | *
88 | * @param index the argument index/position
89 | * @param the type of arg value
90 | * @return the parsed value of the argument
91 | */
92 | @Nullable T getArgument(int index);
93 |
94 |
95 | /**
96 | * Fetches the original required argument
97 | * stated by the syntax executed
98 | *
99 | * @param index the index of the arg
100 | * @return the original required argument
101 | */
102 | @Nullable Argument> getRequiredArgument(int index);
103 |
104 | /**
105 | * Parses the arguments into the used syntax
106 | * this algorithm should provide good reasonable performance
107 | */
108 | void parse() throws ArgumentParseException;
109 |
110 | /**
111 | * The number of parsed args
112 | *
113 | * @return the number of arguments parsed in the context
114 | */
115 | int parsedArguments();
116 |
117 | /**
118 | * The flags used in the command
119 | *
120 | * @return the flag registry for the flags used in the context
121 | * of the command executed by the command sender
122 | */
123 | @NotNull ContextFlagRegistry flags();
124 |
125 | /**
126 | * @return The syntax used in the context of the command
127 | */
128 | @NotNull CommandSyntax syntaxUsed();
129 |
130 | /**
131 | * The length of the args used in the raw context
132 | *
133 | * @return The length of the args used in the raw context
134 | */
135 | int length();
136 |
137 | default int getLastIndex() {
138 | return length() - 1;
139 | }
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/cooldown/CommandCooldown.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.cooldown;
2 |
3 | import java.time.Duration;
4 | import java.util.Objects;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | public class CommandCooldown {
8 |
9 | public static final CommandCooldown EMPTY = new CommandCooldown(0, TimeUnit.SECONDS);
10 | private final long value;
11 | private final TimeUnit unit;
12 | private final Duration duration;
13 |
14 | public CommandCooldown(long value, TimeUnit unit) {
15 | this.value = value;
16 | this.unit = unit;
17 | this.duration = Duration.of(value, unit.toChronoUnit());
18 | }
19 |
20 | public boolean isEmpty() {
21 | return value <= 0;
22 | }
23 |
24 | public long toMillis() {
25 | return duration.toMillis();
26 | }
27 |
28 | public long getValue() {
29 | return value;
30 | }
31 |
32 | public TimeUnit getUnit() {
33 | return unit;
34 | }
35 |
36 | @Override
37 | public boolean equals(Object other) {
38 | if (this == other) return true;
39 | if (!(other instanceof CommandCooldown that)) return false;
40 | return value == that.value && unit == that.unit;
41 | }
42 |
43 | @Override
44 | public int hashCode() {
45 | return Objects.hash(value, unit);
46 | }
47 | }
48 |
49 |
50 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/cooldown/CooldownCaption.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.cooldown;
2 |
3 | import io.github.mqzn.commands.base.caption.Caption;
4 | import io.github.mqzn.commands.base.caption.CaptionKey;
5 | import io.github.mqzn.commands.base.caption.Message;
6 | import io.github.mqzn.commands.base.context.Context;
7 | import io.github.mqzn.commands.utilities.TimeParser;
8 | import net.kyori.adventure.text.Component;
9 | import net.kyori.adventure.text.TextComponent;
10 | import net.kyori.adventure.text.format.NamedTextColor;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.Locale;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | public final class CooldownCaption implements Caption {
17 |
18 | public static String formatUnit(TimeUnit unit) {
19 | var unitName = unit.name().toLowerCase(Locale.getDefault());
20 | unitName = unitName.substring(0, unitName.length() - 1);
21 | return unitName + "(s)";
22 | }
23 |
24 | public static long calculateRemainingTime(long lastTime, CommandCooldown commandCooldown) {
25 | var diff = System.currentTimeMillis() - lastTime;
26 | return commandCooldown.toMillis() - diff;
27 | }
28 |
29 | @Override
30 | public @NotNull CaptionKey key() {
31 | return CaptionKey.COMMAND_IN_COOLDOWN;
32 | }
33 |
34 | @Override
35 | public @NotNull TextComponent message(S sender, Context context, Throwable exception) {
36 | var command = context.commandUsed();
37 | var manager = command.manager();
38 | var cooldown = command.cooldown();
39 | var lastTimeCommandExecuted = manager.getCommandCooldown(manager.getSenderWrapper().senderName(sender));
40 | if (lastTimeCommandExecuted == null) lastTimeCommandExecuted = 0L;
41 | // Send a caption telling the user that he's in a cooldown
42 | // Calculating remaining time
43 | var parser = TimeParser.parse(calculateRemainingTime(lastTimeCommandExecuted, cooldown));
44 | var timeData = parser.highestLogicalUnitValue();
45 |
46 | return cooldownMessage(timeData.getLeft(), timeData.getRight(), context);
47 | }
48 |
49 | public TextComponent cooldownMessage(long time, TimeUnit unit, Context context) {
50 | return Message.prefixed(Message.EXECUTION_ERROR)
51 | .append(
52 | Component.text(
53 | String.format(
54 | "Command '" + context.commandUsed().name()
55 | + "' is in cooldown for %d %s", time, formatUnit(unit)
56 | ), NamedTextColor.YELLOW
57 | )
58 | );
59 | }
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/AmbiguityChecker.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.arguments.ArgumentLiteral;
4 | import io.github.mqzn.commands.base.Command;
5 | import io.github.mqzn.commands.base.syntax.CommandSyntax;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class AmbiguityChecker {
11 | private final Command command;
12 | private final List> syntaxes;
13 |
14 | private AmbiguityChecker(Command command, List> syntaxes) {
15 | this.command = command;
16 | this.syntaxes = syntaxes;
17 | }
18 |
19 | public static AmbiguityChecker of(Command command) {
20 | return new AmbiguityChecker<>(command, command.syntaxes());
21 | }
22 |
23 | public static boolean hasLiteralArgs(CommandSyntax syntax) {
24 | if (syntax.isSubCommand()) return true;
25 | for (Object arg : syntax.getArguments()) {
26 | if (arg instanceof ArgumentLiteral) {
27 | return true;
28 | }
29 | }
30 | return false;
31 | }
32 |
33 | public List> findAmbiguity() {
34 | for (CommandSyntax syntax : syntaxes) {
35 | if (syntax.useSpace() && !hasLiteralArgs(syntax) && syntaxes.size() > 1) {
36 | return syntaxes;
37 | }
38 | }
39 |
40 | List> ambiguous = new ArrayList<>();
41 | for (int first = 0; first < syntaxes.size(); first++) {
42 | CommandSyntax firstSyntax = syntaxes.get(first);
43 | for (int second = 0; second < syntaxes.size(); second++) {
44 | if (first == second) continue;
45 | CommandSyntax secondSyntax = syntaxes.get(second);
46 | if (areAmbiguous(firstSyntax, secondSyntax)) {
47 | ambiguous.add(firstSyntax);
48 | ambiguous.add(secondSyntax);
49 | }
50 | }
51 | }
52 | return ambiguous;
53 | }
54 |
55 | private boolean areAmbiguous(CommandSyntax s1, CommandSyntax s2) {
56 | int s1Length = CommandSyntax.getArguments(command.tree(), s1).size();
57 | int s2Length = CommandSyntax.getArguments(command.tree(), s2).size();
58 |
59 | return (!hasLiteralArgs(s1) && !hasLiteralArgs(s2) && s1Length == s2Length) ||
60 | (s1Length == s2Length && s1.equals(s2));
61 | }
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/ArgumentNumberComparator.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.arguments.*;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | public final class ArgumentNumberComparator {
9 |
10 | private final Map>, ArgumentComparator>> comparators;
11 |
12 | public ArgumentNumberComparator() {
13 | comparators = new HashMap<>();
14 | registerComparator(ArgumentInteger.class, new IntegerComparator());
15 | registerComparator(ArgumentDouble.class, new DoubleComparator());
16 | registerComparator(ArgumentFloat.class, new FloatComparator());
17 | registerComparator(ArgumentLong.class, new LongComparator());
18 | }
19 |
20 | public void registerComparator(Class extends ArgumentNumber> argClass, ArgumentComparator comparator) {
21 | comparators.put(argClass, comparator);
22 | }
23 |
24 | @SuppressWarnings("unchecked")
25 | public ArgumentComparator comparatorOfArg(Class extends ArgumentNumber> clazzArg) {
26 | return (ArgumentComparator) comparators.get(clazzArg);
27 | }
28 |
29 | public interface ArgumentComparator {
30 | boolean greaterThan(N n1, N n2);
31 |
32 | boolean greaterThanOrEqual(N n1, N n2);
33 |
34 | boolean lessThan(N n1, N n2);
35 |
36 | boolean lessThanOrEqual(N n1, N n2);
37 | }
38 |
39 | private static class IntegerComparator implements ArgumentComparator {
40 | @Override
41 | public boolean greaterThan(Integer n1, Integer n2) {
42 | return n1 > n2;
43 | }
44 |
45 | @Override
46 | public boolean greaterThanOrEqual(Integer n1, Integer n2) {
47 | return n1 >= n2;
48 | }
49 |
50 | @Override
51 | public boolean lessThan(Integer n1, Integer n2) {
52 | return n1 < n2;
53 | }
54 |
55 | @Override
56 | public boolean lessThanOrEqual(Integer n1, Integer n2) {
57 | return n1 <= n2;
58 | }
59 | }
60 |
61 | private static class DoubleComparator implements ArgumentComparator {
62 | @Override
63 | public boolean greaterThan(Double n1, Double n2) {
64 | return n1 > n2;
65 | }
66 |
67 | @Override
68 | public boolean greaterThanOrEqual(Double n1, Double n2) {
69 | return n1 >= n2;
70 | }
71 |
72 | @Override
73 | public boolean lessThan(Double n1, Double n2) {
74 | return n1 < n2;
75 | }
76 |
77 | @Override
78 | public boolean lessThanOrEqual(Double n1, Double n2) {
79 | return n1 <= n2;
80 | }
81 | }
82 |
83 | private static class FloatComparator implements ArgumentComparator {
84 | @Override
85 | public boolean greaterThan(Float n1, Float n2) {
86 | return n1 > n2;
87 | }
88 |
89 | @Override
90 | public boolean greaterThanOrEqual(Float n1, Float n2) {
91 | return n1 >= n2;
92 | }
93 |
94 | @Override
95 | public boolean lessThan(Float n1, Float n2) {
96 | return n1 < n2;
97 | }
98 |
99 | @Override
100 | public boolean lessThanOrEqual(Float n1, Float n2) {
101 | return n1 <= n2;
102 | }
103 | }
104 |
105 | private static class LongComparator implements ArgumentComparator {
106 | @Override
107 | public boolean greaterThan(Long n1, Long n2) {
108 | return n1 > n2;
109 | }
110 |
111 | @Override
112 | public boolean greaterThanOrEqual(Long n1, Long n2) {
113 | return n1 >= n2;
114 | }
115 |
116 | @Override
117 | public boolean lessThan(Long n1, Long n2) {
118 | return n1 < n2;
119 | }
120 |
121 | @Override
122 | public boolean lessThanOrEqual(Long n1, Long n2) {
123 | return n1 <= n2;
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/ArgumentNumberSuggestionProcessor.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.arguments.ArgumentNumber;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | public final class ArgumentNumberSuggestionProcessor {
8 |
9 | @NotNull
10 | private final CommandManager, ?> manager;
11 |
12 | private ArgumentNumberSuggestionProcessor(@NotNull CommandManager, ?> manager) {
13 | this.manager = manager;
14 | }
15 |
16 | public static ArgumentNumberSuggestionProcessor create(@NotNull CommandManager, ?> manager) {
17 | return new ArgumentNumberSuggestionProcessor(manager);
18 | }
19 |
20 | @SuppressWarnings("unchecked")
21 | public void provide(@NotNull ArgumentNumber argumentNumber) {
22 |
23 | ArgumentNumberComparator.ArgumentComparator comparator
24 | = manager.typeRegistry().getComparator((Class extends ArgumentNumber>) argumentNumber.getClass());
25 |
26 | @Nullable N end = argumentNumber.getMax();
27 | @Nullable N start = argumentNumber.getMin();
28 |
29 | if (start == null && end == null) {
30 | return;
31 | } else if (end == null) {
32 | argumentNumber.suggest(start);
33 | return;
34 | } else if (start == null) {
35 | argumentNumber.suggest(end);
36 | return;
37 | }
38 |
39 | while (comparator.lessThanOrEqual(start, end)) {
40 | argumentNumber.suggest(start);
41 | start = argumentNumber.increment(start);
42 | }
43 |
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/ArgumentTypeRegistry.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.arguments.Argument;
4 | import io.github.mqzn.commands.arguments.ArgumentData;
5 | import io.github.mqzn.commands.arguments.ArgumentNumber;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | import java.util.HashMap;
10 | import java.util.Map;
11 | import java.util.function.Function;
12 |
13 | public final class ArgumentTypeRegistry {
14 |
15 | @NotNull
16 | private final ArgumentNumberComparator argumentNumberComparator;
17 |
18 | @NotNull
19 | private final Map, Function>> argumentCreatorMapper = new HashMap<>();
20 |
21 |
22 | ArgumentTypeRegistry() {
23 |
24 | this.argumentNumberComparator = new ArgumentNumberComparator();
25 |
26 | argumentCreatorMapper.put(Integer.class, Argument::integer);
27 | argumentCreatorMapper.put(int.class, Argument::integer);
28 |
29 | argumentCreatorMapper.put(Double.class, Argument::Double);
30 | argumentCreatorMapper.put(double.class, Argument::Double);
31 |
32 | argumentCreatorMapper.put(Float.class, Argument::Float);
33 | argumentCreatorMapper.put(float.class, Argument::Float);
34 |
35 | argumentCreatorMapper.put(Long.class, Argument::Long);
36 | argumentCreatorMapper.put(long.class, Argument::Long);
37 |
38 | argumentCreatorMapper.put(Boolean.class, Argument::Boolean);
39 | argumentCreatorMapper.put(boolean.class, Argument::Boolean);
40 |
41 | argumentCreatorMapper.put(String[].class, (data) -> Argument.Array(data.getId()));
42 | }
43 |
44 |
45 | @Nullable
46 | public Argument> convertArgument(@NotNull ArgumentData data, @NotNull Class> clazz) {
47 | var mapper = argumentCreatorMapper.get(clazz);
48 | if (mapper == null) {
49 | return null;
50 | }
51 | return mapper.apply(data);
52 | }
53 |
54 | public void registerArgumentConverter(Class> type, Function> mapper) {
55 | argumentCreatorMapper.put(type, mapper);
56 | }
57 |
58 |
59 | public ArgumentNumberComparator.ArgumentComparator getComparator(Class extends ArgumentNumber> argNumClass) {
60 | return argumentNumberComparator.comparatorOfArg(argNumClass);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/CommandExecutionCoordinator.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.base.Command;
4 | import io.github.mqzn.commands.base.context.CommandContext;
5 | import io.github.mqzn.commands.base.syntax.CommandSyntax;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.util.concurrent.CompletableFuture;
9 |
10 | public sealed abstract class CommandExecutionCoordinator {
11 |
12 | @NotNull
13 | protected final Command command;
14 |
15 | private CommandExecutionCoordinator(@NotNull Command manager) {
16 | this.command = manager;
17 | }
18 |
19 | static CommandExecutionCoordinator async(@NotNull Command manager) {
20 | return new AsyncCommandCoordinator<>(manager);
21 | }
22 |
23 | static CommandExecutionCoordinator sync(@NotNull Command manager) {
24 | return new SyncCommandCoordinator<>(manager);
25 | }
26 |
27 | public static CommandExecutionCoordinator fromType(@NotNull Command manager, Type type) {
28 | return type == Type.SYNC ? sync(manager) : async(manager);
29 | }
30 |
31 | public Command command() {
32 | return command;
33 | }
34 |
35 | public abstract Type type();
36 |
37 | public abstract CompletableFuture coordinateExecution(@NotNull C sender,
38 | @NotNull CommandSyntax syntax,
39 | @NotNull CommandContext context);
40 |
41 | public enum ExecutionResult {
42 | SUCCESS,
43 | FAILED
44 | }
45 |
46 |
47 | public enum Type {
48 | ASYNC,
49 | SYNC
50 | }
51 |
52 | final static class AsyncCommandCoordinator extends CommandExecutionCoordinator {
53 |
54 | private AsyncCommandCoordinator(@NotNull Command manager) {
55 | super(manager);
56 | }
57 |
58 | @Override
59 | public Type type() {
60 | return Type.ASYNC;
61 | }
62 |
63 | @Override
64 | public CompletableFuture coordinateExecution(@NotNull C sender,
65 | @NotNull CommandSyntax syntax,
66 | @NotNull CommandContext context) {
67 | return CompletableFuture.supplyAsync(() -> {
68 | try {
69 | syntax.execute(sender, context);
70 | return ExecutionResult.SUCCESS;
71 | } catch (Exception ex) {
72 | ex.printStackTrace();
73 | return ExecutionResult.FAILED;
74 | }
75 |
76 | });
77 |
78 | }
79 | }
80 |
81 |
82 | final static class SyncCommandCoordinator extends CommandExecutionCoordinator {
83 | public SyncCommandCoordinator(Command manager) {
84 | super(manager);
85 | }
86 |
87 | @Override
88 | public Type type() {
89 | return Type.SYNC;
90 | }
91 |
92 | @Override
93 | public CompletableFuture coordinateExecution(@NotNull C sender,
94 | @NotNull CommandSyntax syntax,
95 | @NotNull CommandContext context) {
96 | try {
97 | syntax.execute(sender, context);
98 | return CompletableFuture.completedFuture(ExecutionResult.SUCCESS);
99 | } catch (Exception ex) {
100 | ex.printStackTrace();
101 | return CompletableFuture.completedFuture(ExecutionResult.FAILED);
102 | }
103 |
104 | }
105 |
106 |
107 | }
108 |
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/FlagRegistry.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.base.manager.flags.FlagInfo;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | import java.util.Collection;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 | import java.util.concurrent.atomic.AtomicBoolean;
11 |
12 | public final class FlagRegistry {
13 |
14 | @NotNull
15 | public final static String FLAG_IDENTIFIER = "-";
16 | @NotNull
17 | private static final AtomicBoolean flagRegistryCreated = new AtomicBoolean(false);
18 | @NotNull
19 | private final Map flags = new HashMap<>();
20 |
21 | private FlagRegistry() {
22 | flagRegistryCreated.set(true);
23 | }
24 |
25 | static FlagRegistry create() throws IllegalAccessException {
26 |
27 | if (flagRegistryCreated.get()) {
28 | throw new IllegalAccessException("Error trying to create another instance of flag registry !");
29 | }
30 |
31 | return new FlagRegistry();
32 | }
33 |
34 | public void registerFlag(@NotNull FlagInfo flag) {
35 | flags.put(flag.getName(), flag);
36 | }
37 |
38 |
39 | public void unregisterFlag(String flag) {
40 | flags.remove(flag);
41 |
42 | for (var f : flags.values()) {
43 | if (f.hasAliase(flag)) {
44 | flags.remove(flag);
45 | break;
46 | }
47 |
48 | }
49 |
50 | }
51 |
52 | public @Nullable FlagInfo getFlag(String flag) {
53 | for (FlagInfo f : flags.values()) {
54 | if (f.getName().equalsIgnoreCase(flag) || f.hasAliase(flag))
55 | return f;
56 | }
57 |
58 | return null;
59 | }
60 |
61 |
62 | public @NotNull Collection flags() {
63 | return flags.values();
64 | }
65 |
66 | public boolean flagExists(String flagAlias) {
67 | return getFlag(flagAlias) != null;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/SenderProviderRegistry.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.base.SenderProvider;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public final class SenderProviderRegistry {
11 |
12 | @NotNull
13 | private final Map, SenderProvider, ?>> senderProviders = new HashMap<>();
14 |
15 |
16 | @SuppressWarnings("unchecked")
17 | private @Nullable SenderProvider getSenderProvider(Class clazz) {
18 | return (SenderProvider) senderProviders.get(clazz);
19 | }
20 |
21 | public void registerSenderProvider(Class clazz, SenderProvider provider) {
22 | senderProviders.put(clazz, provider);
23 | }
24 |
25 | public boolean hasProviderFor(Class clazz) {
26 | return senderProviders.get(clazz) != null;
27 | }
28 |
29 | public @Nullable C provideSender(@NotNull S sender, Class clazz) {
30 |
31 | SenderProvider provider = getSenderProvider(clazz);
32 | if (provider != null)
33 | return provider.mapSender(sender);
34 |
35 | return null;
36 | }
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/SuggestionProviderRegistry.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager;
2 |
3 | import io.github.mqzn.commands.base.SuggestionProvider;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | public final class SuggestionProviderRegistry {
10 |
11 | private final Map, SuggestionProvider> providers = new HashMap<>();
12 |
13 | SuggestionProviderRegistry() {
14 |
15 | }
16 |
17 | public void register(SuggestionProvider provider) {
18 | providers.put(provider.getClass(), provider);
19 | }
20 |
21 | public void unregister(Class extends SuggestionProvider> clazz) {
22 | providers.remove(clazz);
23 | }
24 |
25 | @SuppressWarnings("unchecked")
26 | public @Nullable SP getProvider(Class clazz) {
27 | return (SP) providers.get(clazz);
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/flags/CommandFlag.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager.flags;
2 |
3 | import io.github.mqzn.commands.base.Information;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | public sealed interface CommandFlag permits CommandFlag.Builder.SimpleCommandFlag {
8 |
9 | static @NotNull CommandFlag from(FlagInfo info) {
10 | Builder builder = CommandFlag.builder(info.getName())
11 | .withAliases(info.getAliases());
12 |
13 | if (info.getInformation() != null) {
14 |
15 | var flagInformation = info.getInformation();
16 | if (flagInformation.permission() != null)
17 | builder.withPermission(flagInformation.permission());
18 |
19 | if (flagInformation.description() != null)
20 | builder.withDescription(flagInformation.description());
21 |
22 | }
23 |
24 | return builder.build();
25 | }
26 |
27 | static @NotNull Builder builder(String flagName) {
28 | return new Builder(flagName);
29 | }
30 |
31 | @NotNull String name();
32 |
33 | @Nullable Information info();
34 |
35 | @NotNull String[] aliases();
36 |
37 | default boolean hasAliase(String aliase) {
38 | for (var a : aliases())
39 | if (a.equalsIgnoreCase(aliase)) return true;
40 |
41 | return false;
42 | }
43 |
44 | final class Builder {
45 |
46 | @NotNull
47 | private final String name;
48 |
49 | @Nullable
50 | private String permission = null;
51 |
52 | @Nullable
53 | private String description = null;
54 |
55 | @NotNull
56 | private String[] aliases = new String[0];
57 |
58 | Builder(@NotNull String name) {
59 | this.name = name;
60 | }
61 |
62 |
63 | public @NotNull Builder withAliases(@NotNull String... aliases) {
64 | this.aliases = aliases;
65 | return this;
66 | }
67 |
68 | @SuppressWarnings("UnusedReturnValue")
69 | public @NotNull Builder withPermission(@NotNull String permission) {
70 | this.permission = permission;
71 | return this;
72 | }
73 |
74 | @SuppressWarnings("UnusedReturnValue")
75 | public @NotNull Builder withDescription(@NotNull String description) {
76 | this.description = description;
77 | return this;
78 | }
79 |
80 | public CommandFlag build() {
81 | Information info = new Information(permission, description);
82 | return new SimpleCommandFlag(name, info, aliases);
83 | }
84 |
85 |
86 | record SimpleCommandFlag(@NotNull String name,
87 | @Nullable Information info,
88 | @NotNull String... aliases) implements CommandFlag {
89 | }
90 |
91 | }
92 |
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/flags/ContextFlagRegistry.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager.flags;
2 |
3 | import io.github.mqzn.commands.arguments.Argument;
4 | import io.github.mqzn.commands.base.Command;
5 | import io.github.mqzn.commands.base.Information;
6 | import io.github.mqzn.commands.base.context.CommandContext;
7 | import io.github.mqzn.commands.base.context.Context;
8 | import io.github.mqzn.commands.base.manager.CommandManager;
9 | import io.github.mqzn.commands.base.manager.FlagRegistry;
10 | import io.github.mqzn.commands.base.syntax.CommandSyntax;
11 | import io.github.mqzn.commands.base.syntax.SubCommandSyntax;
12 | import org.jetbrains.annotations.NotNull;
13 | import org.jetbrains.annotations.Nullable;
14 |
15 | import java.util.*;
16 | import java.util.regex.Matcher;
17 | import java.util.regex.Pattern;
18 |
19 | public final class ContextFlagRegistry {
20 |
21 | @NotNull
22 | public static final Pattern FLAG_PATTERN = Pattern.compile(FlagRegistry.FLAG_IDENTIFIER + "[a-z]+", Pattern.CASE_INSENSITIVE);
23 |
24 | @NotNull
25 | private final CommandManager, S> manager;
26 |
27 | @NotNull
28 | private final Context commandContext;
29 |
30 | @NotNull
31 | private final Map flagsUsed = new HashMap<>();
32 |
33 |
34 | private ContextFlagRegistry(@NotNull CommandManager, S> manager,
35 | @NotNull Context commandContext) {
36 | this.manager = manager;
37 | this.commandContext = commandContext;
38 | }
39 |
40 | public static @NotNull ContextFlagRegistry create(
41 | @NotNull CommandManager, S> manager,
42 | @NotNull CommandContext commandContext
43 | ) {
44 | return new ContextFlagRegistry<>(manager, commandContext);
45 | }
46 |
47 | public static boolean isRawArgumentFlag(String rawArg) {
48 | Matcher matcher = FLAG_PATTERN.matcher(rawArg);
49 | return matcher.matches();
50 | }
51 |
52 | public FlagExtractionResult extractFlags(@NotNull S sender, @NotNull Command command, @NotNull CommandSyntax syntax) {
53 |
54 | List> argumentList = (syntax instanceof SubCommandSyntax sub) ? command.tree().getParentalArguments(sub.key())
55 | : syntax.getArguments();
56 |
57 | for (int r = 0; r < argumentList.size()+commandContext.flagsUsed(); r++) {
58 | String raw = commandContext.getRawArgument(r);
59 |
60 | if (raw == null)
61 | break;
62 |
63 | if (isRawArgumentFlag(raw)) {
64 | var extracted = extractFlagsUsed(sender, raw);
65 | boolean foundOneAtLeast = !extracted.isEmpty();
66 |
67 | if (!foundOneAtLeast) {
68 | manager.getSenderWrapper().sendMessage(sender, "The flag(s) used are unknown to the command flags registry !");
69 | return FlagExtractionResult.FAILED;
70 | }
71 |
72 | for (CommandFlag flag : extracted)
73 | this.flagsUsed.put(flag.name(), flag);
74 | }
75 |
76 | }
77 |
78 |
79 | for (var flag : flagsUsed.values()) {
80 |
81 | Information flagInfo = flag.info();
82 | if (!syntax.getFlags().hasFlag(flag.name())) {
83 | manager.getSenderWrapper().sendMessage(sender, "The flag '" + FlagRegistry.FLAG_IDENTIFIER + flag.name() + "' is not allowed in this syntax");
84 | return FlagExtractionResult.FAILED;
85 | } else if (flagInfo != null && flagInfo.permission() != null && !manager.getSenderWrapper().hasPermission(sender, flagInfo.permission())) {
86 | manager.getSenderWrapper().sendMessage(sender, "No permission to use the flag '" + FlagRegistry.FLAG_IDENTIFIER + flag.name() + "'");
87 | return FlagExtractionResult.FAILED;
88 | }
89 |
90 | }
91 |
92 | if (flagsUsed.isEmpty()) return FlagExtractionResult.FOUND_NONE;
93 | else return FlagExtractionResult.SUCCESS;
94 |
95 | }
96 |
97 | @NotNull
98 | private Set extractFlagsUsed(@NotNull S sender, @NotNull String flagRaw) {
99 | final Set flags = new LinkedHashSet<>();
100 |
101 | //first check if it's single
102 |
103 | //there's more !
104 | //examples: -x , -xyz
105 |
106 | for (FlagInfo flagInfo : manager.flagRegistry().flags()) {
107 |
108 | boolean foundFlagAliase = false;
109 | for (String aliase : flagInfo.getAliases()) {
110 | if (flagRaw.contains(aliase)) {
111 |
112 | if (foundFlagAliase) {
113 | manager.getSenderWrapper().sendMessage(sender, "Warning: you used the same flag '" + flagRaw + "' twice !");
114 | break;
115 | }
116 |
117 | flags.add(CommandFlag.from(flagInfo));
118 | foundFlagAliase = true;
119 | }
120 |
121 | }
122 |
123 | }
124 |
125 | return flags;
126 | }
127 |
128 | public boolean isPresent(String flagName) {
129 | return getFlag(flagName) != null;
130 | }
131 |
132 | public @Nullable CommandFlag getFlag(String flagName) {
133 | return flagsUsed.get(flagName);
134 | }
135 |
136 | public int count() {
137 | return flagsUsed.size();
138 | }
139 |
140 | public enum FlagExtractionResult {
141 |
142 | SUCCESS,
143 |
144 | FOUND_NONE,
145 |
146 | FAILED
147 |
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/manager/flags/FlagInfo.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.manager.flags;
2 |
3 | import io.github.mqzn.commands.base.Information;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | public final class FlagInfo {
8 |
9 | @NotNull
10 | private final String name;
11 |
12 | @Nullable
13 | private final Information information;
14 |
15 | private final String[] aliases;
16 |
17 |
18 | private FlagInfo(@NotNull String name, @Nullable Information information, String... aliases) {
19 | this.name = name;
20 | this.information = information;
21 | this.aliases = aliases;
22 | }
23 |
24 | public static @NotNull Builder builder(String name) {
25 | return new Builder(name);
26 | }
27 |
28 | public boolean hasAliase(String aliase) {
29 | for (var a : aliases)
30 | if (a.equalsIgnoreCase(aliase)) return true;
31 |
32 | return false;
33 |
34 | }
35 |
36 | public @NotNull String getName() {
37 | return name;
38 | }
39 |
40 | public @Nullable Information getInformation() {
41 | return information;
42 | }
43 |
44 | public String[] getAliases() {
45 | return aliases;
46 | }
47 |
48 | public static final class Builder {
49 | private final String name;
50 |
51 | @Nullable
52 | private Information information = null;
53 |
54 | private String[] aliases = new String[0];
55 |
56 | Builder(String name) {
57 | this.name = name;
58 | }
59 |
60 | public @NotNull Builder info(@Nullable Information information) {
61 | this.information = information;
62 | return this;
63 | }
64 |
65 | public @NotNull Builder aliases(@NotNull String... aliases) {
66 | this.aliases = aliases;
67 | return this;
68 | }
69 |
70 |
71 | public @NotNull FlagInfo build() {
72 | return new FlagInfo(name, information, aliases);
73 | }
74 |
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/syntax/CommandAliases.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.syntax;
2 |
3 |
4 | public final class CommandAliases {
5 |
6 | private final String[] array;
7 |
8 | CommandAliases(String[] array) {
9 | this.array = array;
10 | }
11 |
12 | public static CommandAliases of(String... arr) {
13 | return new CommandAliases(arr);
14 | }
15 |
16 | public String[] getArray() {
17 | return array;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/syntax/CommandExecution.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.syntax;
2 |
3 | import io.github.mqzn.commands.base.context.Context;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | public interface CommandExecution {
7 |
8 | void execute(@NotNull C sender, Context commandContext);
9 | }
10 |
--------------------------------------------------------------------------------
/common/src/main/java/io/github/mqzn/commands/base/syntax/CommandSyntaxBuilder.java:
--------------------------------------------------------------------------------
1 | package io.github.mqzn.commands.base.syntax;
2 |
3 | import io.github.mqzn.commands.arguments.Argument;
4 | import io.github.mqzn.commands.base.Information;
5 | import io.github.mqzn.commands.base.manager.CommandManager;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class CommandSyntaxBuilder {
13 | @NotNull
14 | protected final CommandManager, S> manager;
15 |
16 | @NotNull
17 | protected final String commandLabel;
18 |
19 | @NotNull
20 | protected final List> arguments = new ArrayList<>();
21 |
22 | @Nullable
23 | protected Class senderClass;
24 |
25 | @Nullable
26 | protected CommandExecution execution;
27 |
28 | @NotNull
29 | protected SyntaxFlags flags = SyntaxFlags.of();
30 |
31 | @Nullable
32 | protected Information info = null;
33 |
34 | protected CommandSyntaxBuilder(@NotNull CommandManager, S> manager,
35 | @NotNull Class senderClass,
36 | @NotNull String label) {
37 | this.manager = manager;
38 | this.senderClass = senderClass;
39 | this.commandLabel = label;
40 | }
41 |
42 | public static CommandSyntaxBuilder genericBuilder(@NotNull CommandManager, S> manager,
43 | @NotNull Class