├── .github └── FUNDING.yml ├── settings.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── vcs.xml ├── .gitignore ├── misc.xml └── runConfigurations │ ├── Clean_CommandAPI.xml │ ├── Publish_CommandAPI.xml │ └── Build_CommandAPI.xml ├── bungee ├── build.gradle.kts └── src │ └── main │ └── java │ └── net │ └── j4c0b3y │ └── api │ └── command │ └── bungee │ ├── locale │ └── BungeeCommandLocale.java │ ├── annotation │ └── ConsoleSender.java │ ├── provider │ ├── actor │ │ ├── CommandSenderProvider.java │ │ ├── BungeeActorProvider.java │ │ ├── ConsoleCommandSenderProvider.java │ │ └── ProxiedPlayerSenderProvider.java │ └── argument │ │ └── ServerInfoProvider.java │ ├── actor │ └── BungeeActor.java │ ├── BungeeCommandWrapper.java │ └── BungeeCommandHandler.java ├── .gitignore ├── core └── src │ └── main │ └── java │ └── net │ └── j4c0b3y │ └── api │ └── command │ ├── execution │ ├── argument │ │ ├── flag │ │ │ ├── FlagAction.java │ │ │ └── CommandFlag.java │ │ └── CommandArgument.java │ ├── usage │ │ ├── UsageHandler.java │ │ └── impl │ │ │ └── SimpleUsageHandler.java │ ├── ProvidedParameter.java │ ├── locale │ │ └── CommandLocale.java │ └── CommandExecution.java │ ├── actor │ ├── ConsoleActor.java │ ├── ProxyActor.java │ ├── PlayerActor.java │ └── Actor.java │ ├── wrapper │ ├── binding │ │ ├── condition │ │ │ ├── ExecuteCondition.java │ │ │ └── ConditionHandler.java │ │ ├── provider │ │ │ ├── ProviderType.java │ │ │ ├── impl │ │ │ │ ├── context │ │ │ │ │ ├── LabelProvider.java │ │ │ │ │ ├── CommandExecutionProvider.java │ │ │ │ │ ├── InstanceProvider.java │ │ │ │ │ ├── CommandHandleProvider.java │ │ │ │ │ └── CommandWrapperProvider.java │ │ │ │ ├── argument │ │ │ │ │ ├── StringProvider.java │ │ │ │ │ ├── CharacterProvider.java │ │ │ │ │ ├── UUIDProvider.java │ │ │ │ │ ├── NumberProvider.java │ │ │ │ │ ├── MapProvider.java │ │ │ │ │ ├── ArrayProvider.java │ │ │ │ │ ├── EnumProvider.java │ │ │ │ │ └── BooleanProvider.java │ │ │ │ └── actor │ │ │ │ │ ├── ActorProvider.java │ │ │ │ │ ├── ProxyActorProvider.java │ │ │ │ │ ├── PlayerActorProvider.java │ │ │ │ │ └── ConsoleActorProvider.java │ │ │ └── Provider.java │ │ ├── modifier │ │ │ ├── ArgumentModifier.java │ │ │ ├── impl │ │ │ │ ├── LengthModifier.java │ │ │ │ └── RangeModifier.java │ │ │ └── ModifierHandler.java │ │ ├── ParameterBinding.java │ │ ├── BindingHandler.java │ │ └── BindingBuilder.java │ ├── suggestion │ │ └── CommandSuggestion.java │ ├── CommandParameter.java │ ├── CommandWrapper.java │ └── CommandHandle.java │ ├── exception │ ├── binding │ │ └── InvalidBindingException.java │ ├── registration │ │ ├── InvalidHandleException.java │ │ ├── InvalidWrapperException.java │ │ ├── InvalidParameterException.java │ │ ├── MissingProviderException.java │ │ ├── ParameterStructureException.java │ │ └── RegistrationException.java │ └── execution │ │ ├── MissingValidatorException.java │ │ ├── UnknownFlagException.java │ │ └── ExitMessage.java │ ├── annotation │ ├── parameter │ │ ├── Last.java │ │ ├── Optional.java │ │ ├── Text.java │ │ ├── modifier │ │ │ ├── Modifier.java │ │ │ ├── Length.java │ │ │ └── Range.java │ │ ├── Named.java │ │ ├── Default.java │ │ ├── Manual.java │ │ ├── Option.java │ │ ├── classifier │ │ │ ├── Classifier.java │ │ │ ├── Label.java │ │ │ └── Sender.java │ │ └── Flag.java │ ├── command │ │ ├── condition │ │ │ └── Condition.java │ │ ├── Usage.java │ │ ├── Requires.java │ │ ├── Help.java │ │ └── Command.java │ └── registration │ │ ├── Ignore.java │ │ └── Register.java │ ├── utils │ ├── ClassUtils.java │ ├── StringUtils.java │ ├── ListUtils.java │ └── AnnotationUtils.java │ └── CommandHandler.java ├── bukkit ├── build.gradle.kts └── src │ └── main │ └── java │ └── net │ └── j4c0b3y │ └── api │ └── command │ └── bukkit │ ├── locale │ └── BukkitCommandLocale.java │ ├── provider │ ├── actor │ │ ├── CommandSenderProvider.java │ │ ├── BukkitActorProvider.java │ │ ├── PlayerSenderProvider.java │ │ └── ConsoleCommandSenderProvider.java │ └── argument │ │ ├── EnchantmentProvider.java │ │ ├── WorldProvider.java │ │ ├── OfflinePlayerProvider.java │ │ └── PlayerProvider.java │ ├── utils │ └── ClassUtils.java │ ├── actor │ └── BukkitActor.java │ ├── listener │ └── AsyncTabListener.java │ ├── BukkitCommandWrapper.java │ ├── BukkitCommandRegistry.java │ └── BukkitCommandHandler.java ├── velocity ├── build.gradle.kts └── src │ └── main │ └── java │ └── net │ └── j4c0b3y │ └── api │ └── command │ └── velocity │ ├── locale │ └── VelocityCommandLocale.java │ ├── provider │ ├── actor │ │ ├── CommandSourceProvider.java │ │ ├── VelocityActorProvider.java │ │ ├── PlayerSenderProvider.java │ │ └── ConsoleCommandSourceProvider.java │ └── argument │ │ ├── PlayerProvider.java │ │ └── RegisteredServerProvider.java │ ├── actor │ └── VelocityActor.java │ ├── VelocityCommandWrapper.java │ └── VelocityCommandHandler.java ├── LICENSE.md ├── README.md ├── gradlew.bat └── gradlew /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://donate.j4c0b3y.net 2 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "CommandAPI" 2 | include("core", "bukkit", "velocity", "bungee") 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/J4C0B3Y/CommandAPI/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !.gitignore 4 | 5 | !vcs.xml 6 | !encodings.xml 7 | !codeStyleSettings.xml 8 | !misc.xml 9 | 10 | !runConfigurations 11 | !runConfigurations/* 12 | 13 | !modules 14 | !modules/* -------------------------------------------------------------------------------- /bungee/build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | repositories { 3 | maven("https://repo.codemc.org/repository/maven-public/") 4 | maven("https://libraries.minecraft.net") 5 | } 6 | 7 | dependencies { 8 | compileOnly("net.md-5:bungeecord-api:1.21-R0.1-SNAPSHOT") 9 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | gradle.properties 7 | jars/ 8 | 9 | *.iws 10 | *.iml 11 | *.ipr 12 | out/ 13 | !**/src/main/**/out/ 14 | !**/src/test/**/out/ 15 | 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Aug 26 22:56:20 AEST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/argument/flag/FlagAction.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution.argument.flag; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 1/09/2024 7 | */ 8 | public enum FlagAction { 9 | STRIP, 10 | ARGUMENT, 11 | ERROR 12 | } 13 | -------------------------------------------------------------------------------- /bukkit/build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | repositories { 3 | maven("https://repo.codemc.org/repository/nms/") 4 | maven("https://repo.codemc.org/repository/maven-public/") 5 | maven("https://libraries.minecraft.net") 6 | } 7 | 8 | dependencies { 9 | compileOnly("com.destroystokyo.paper:paper-api:1.12.2-R0.1-SNAPSHOT") 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/actor/ConsoleActor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.actor; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 28/08/2024 7 | */ 8 | public interface ConsoleActor { 9 | boolean isConsole(); 10 | void sendMessage(String message); 11 | String getName(); 12 | } 13 | -------------------------------------------------------------------------------- /velocity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | repositories { 3 | maven("https://nexus.velocitypowered.com/repository/maven-public/") 4 | } 5 | 6 | java { 7 | sourceCompatibility = JavaVersion.VERSION_17 8 | targetCompatibility = JavaVersion.VERSION_17 9 | } 10 | 11 | dependencies { 12 | compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") 13 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/actor/ProxyActor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.actor; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 28/08/2024 7 | */ 8 | public interface ProxyActor { 9 | boolean isProxy(); 10 | boolean hasPermission(String permission); 11 | void sendMessage(String message); 12 | String getName(); 13 | } 14 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/locale/BungeeCommandLocale.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.locale; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 20/10/2024 7 | */ 8 | public class BungeeCommandLocale { 9 | 10 | public String getBungeeOnly() { 11 | return "&cThis command can only be run through bungee."; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/condition/ExecuteCondition.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.condition; 2 | 3 | import net.j4c0b3y.api.command.actor.Actor; 4 | 5 | /** 6 | * @author J4C0B3Y 7 | * @version CommandAPI 8 | * @since 25/10/2024 9 | */ 10 | public interface ExecuteCondition { 11 | boolean validate(Actor actor, T annotation); 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/binding/InvalidBindingException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.binding; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 27/08/2024 7 | */ 8 | public class InvalidBindingException extends RuntimeException { 9 | public InvalidBindingException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/registration/InvalidHandleException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.registration; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 28/08/2024 7 | */ 8 | public class InvalidHandleException extends RuntimeException { 9 | public InvalidHandleException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/registration/InvalidWrapperException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.registration; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 28/08/2024 7 | */ 8 | public class InvalidWrapperException extends RuntimeException { 9 | public InvalidWrapperException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/execution/MissingValidatorException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.execution; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 25/10/2024 7 | */ 8 | public class MissingValidatorException extends RuntimeException { 9 | 10 | public MissingValidatorException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/registration/InvalidParameterException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.registration; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 3/11/2024 7 | */ 8 | public class InvalidParameterException extends RuntimeException { 9 | public InvalidParameterException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/registration/MissingProviderException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.registration; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 27/08/2024 7 | */ 8 | public class MissingProviderException extends RuntimeException { 9 | public MissingProviderException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/registration/ParameterStructureException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.registration; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 28/08/2024 7 | */ 8 | public class ParameterStructureException extends RuntimeException { 9 | public ParameterStructureException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/actor/PlayerActor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.actor; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * @author J4C0B3Y 7 | * @version CommandAPI 8 | * @since 28/08/2024 9 | */ 10 | public interface PlayerActor { 11 | boolean isPlayer(); 12 | UUID getUniqueId(); 13 | boolean hasPermission(String permission); 14 | void sendMessage(String message); 15 | String getName(); 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/ProviderType.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | /** 7 | * @author J4C0B3Y 8 | * @version CommandAPI 9 | * @since 30/08/2024 10 | */ 11 | @Getter 12 | @RequiredArgsConstructor 13 | public enum ProviderType { 14 | ARGUMENT(true), 15 | CONTEXT(false); 16 | 17 | private final boolean consumer; 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/modifier/ArgumentModifier.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.modifier; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 5 | 6 | /** 7 | * @author J4C0B3Y 8 | * @version CommandAPI 9 | * @since 27/08/2024 10 | */ 11 | public interface ArgumentModifier { 12 | T modify(T value, CommandExecution execution, CommandParameter parameter); 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Last.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Last { 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Optional.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 31/08/2024 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Optional { 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Text.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Last 14 | @Target(ElementType.PARAMETER) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Text { 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/command/condition/Condition.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.command.condition; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 25/10/2024 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Condition { 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/modifier/Modifier.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter.modifier; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/2024 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Modifier { 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/argument/CommandArgument.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution.argument; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 6 | 7 | /** 8 | * @author J4C0B3Y 9 | * @version CommandAPI 10 | * @since 27/08/2024 11 | */ 12 | @Getter 13 | @RequiredArgsConstructor 14 | public class CommandArgument { 15 | private final String value; 16 | private final CommandParameter parameter; 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/utils/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.utils; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.lang.invoke.MethodType; 6 | 7 | /** 8 | * @author J4C0B3Y 9 | * @version CommandAPI 10 | * @since 17/10/2024 11 | */ 12 | @UtilityClass 13 | public class ClassUtils { 14 | 15 | @SuppressWarnings("unchecked") 16 | public Class wrap(Class type) { 17 | return (Class) MethodType.methodType(type).wrap().returnType(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Named.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/2024 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Named { 16 | String value(); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/registration/Ignore.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.registration; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target({ElementType.TYPE, ElementType.METHOD}) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Ignore { 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/registration/RegistrationException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.registration; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 30/08/2024 7 | */ 8 | public class RegistrationException extends RuntimeException { 9 | public RegistrationException(String message) { 10 | super(message); 11 | } 12 | 13 | public RegistrationException(String message, Throwable throwable) { 14 | super(message, throwable); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Default.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Default { 16 | String value(); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Manual.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 24/10/2024 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Manual { 16 | String value(); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Option.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 30/08/2024 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Option { 16 | String[] value(); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/classifier/Classifier.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter.classifier; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/2024 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Classifier { 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/Flag.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Flag { 16 | String[] value() default {}; 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/classifier/Label.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter.classifier; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 1/09/2024 12 | */ 13 | @Classifier 14 | @Target(ElementType.PARAMETER) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Label { 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/classifier/Sender.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter.classifier; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Classifier 14 | @Target(ElementType.PARAMETER) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Sender { 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/command/Usage.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.command; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Usage { 16 | String value(); 17 | String[] expanded() default {}; 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/execution/UnknownFlagException.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.execution; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @author J4C0B3Y 7 | * @version CommandAPI 8 | * @since 7/09/2024 9 | */ 10 | @Getter 11 | public class UnknownFlagException extends ExitMessage { 12 | public UnknownFlagException(String message, boolean showUsage) { 13 | super(message, showUsage); 14 | } 15 | 16 | public UnknownFlagException(String message) { 17 | this(message, false); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/locale/VelocityCommandLocale.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.locale; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 20/10/2024 7 | */ 8 | public class VelocityCommandLocale { 9 | 10 | public String getVelocityOnly() { 11 | return "&cThis command can only be run through velocity."; 12 | } 13 | 14 | public String getPlayerOffline(String argument) { 15 | return "&cA player with name '" + argument + "' is not on the network."; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/command/Requires.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.command; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Requires { 16 | String value(); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/command/Help.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.command; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 30/08/24 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Help { 16 | String command() default "help"; 17 | boolean register() default true; 18 | } 19 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/annotation/ConsoleSender.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.annotation; 2 | 3 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Classifier; 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 | /** 11 | * @author J4C0B3Y 12 | * @version CommandAPI 13 | * @since 25/10/2024 14 | */ 15 | @Classifier 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Target(ElementType.PARAMETER) 18 | public @interface ConsoleSender { 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/modifier/Length.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter.modifier; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Modifier 14 | @Target(ElementType.PARAMETER) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Length { 17 | int min() default 1; 18 | int max() default Integer.MAX_VALUE; 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/registration/Register.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.registration; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Register { 16 | String name(); 17 | String[] aliases() default {}; 18 | String description() default ""; 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/parameter/modifier/Range.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.parameter.modifier; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 28/08/2024 12 | */ 13 | @Modifier 14 | @Target(ElementType.PARAMETER) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Range { 17 | double min() default -Double.MAX_VALUE; 18 | double max() default Double.MAX_VALUE; 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/suggestion/CommandSuggestion.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.suggestion; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import net.j4c0b3y.api.command.CommandHandler; 6 | import net.j4c0b3y.api.command.actor.Actor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author J4C0B3Y 12 | * @version CommandAPI 13 | * @since 27/10/2024 14 | */ 15 | @Getter 16 | @RequiredArgsConstructor 17 | public class CommandSuggestion { 18 | private final Actor actor; 19 | private final List arguments; 20 | private final CommandHandler handler; 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/usage/UsageHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution.usage; 2 | 3 | import net.j4c0b3y.api.command.actor.Actor; 4 | import net.j4c0b3y.api.command.wrapper.CommandHandle; 5 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 30/08/24 13 | */ 14 | public interface UsageHandler { 15 | List getUsageMessage(Actor actor, CommandHandle handle, String label); 16 | List getHelpMessage(Actor actor, CommandWrapper wrapper, String label, List arguments); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/actor/Actor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.actor; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import net.j4c0b3y.api.command.CommandHandler; 6 | 7 | /** 8 | * @author J4C0B3Y 9 | * @version CommandAPI 10 | * @since 28/08/2024 11 | */ 12 | @Getter 13 | @RequiredArgsConstructor 14 | public abstract class Actor implements PlayerActor, ConsoleActor, ProxyActor { 15 | private final CommandHandler handler; 16 | 17 | public abstract boolean hasPermission(String permission); 18 | public abstract void sendMessage(String message); 19 | 20 | public abstract String getName(); 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/exception/execution/ExitMessage.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.exception.execution; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @author J4C0B3Y 7 | * @version CommandAPI 8 | * @since 27/08/2024 9 | */ 10 | @Getter 11 | public class ExitMessage extends RuntimeException { 12 | private final boolean showUsage; 13 | 14 | public ExitMessage(String message, boolean showUsage) { 15 | super(message); 16 | this.showUsage = showUsage; 17 | } 18 | 19 | public ExitMessage(String message) { 20 | this(message, false); 21 | } 22 | 23 | public ExitMessage() { 24 | this(null, true); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/annotation/command/Command.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.annotation.command; 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 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/2024 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Command { 16 | String name(); 17 | String description() default ""; 18 | String[] aliases() default {}; 19 | 20 | boolean hidden() default false; 21 | boolean async() default false; 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/ProvidedParameter.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.Setter; 6 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 29/08/2024 12 | */ 13 | @Getter 14 | @RequiredArgsConstructor 15 | public class ProvidedParameter { 16 | private final CommandParameter parameter; 17 | private @Setter String argument; 18 | 19 | private boolean provided; 20 | private Object value; 21 | 22 | public void provide(Object value) { 23 | this.value = value; 24 | this.provided = true; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/locale/BukkitCommandLocale.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.locale; 2 | 3 | /** 4 | * @author J4C0B3Y 5 | * @version CommandAPI 6 | * @since 20/10/2024 7 | */ 8 | public class BukkitCommandLocale { 9 | 10 | public String getInvalidWorld(String argument) { 11 | return "&cA world with name '" + argument + "' doesn't exist."; 12 | } 13 | 14 | public String getPlayerOffline(String argument) { 15 | return "&cA player with name '" + argument + "' is not online."; 16 | } 17 | 18 | public String getInvalidOfflinePlayer(String argument) { 19 | return "&cA player with name '" + argument + "' has never joined before."; 20 | } 21 | 22 | public String getBukkitOnly() { 23 | return "&cThis command can only be run through bukkit."; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/context/LabelProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.context; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 1/09/2024 12 | */ 13 | public class LabelProvider extends Provider { 14 | 15 | public LabelProvider() { 16 | super(ProviderType.CONTEXT); 17 | } 18 | 19 | @Override 20 | public String provide(CommandExecution execution, CommandArgument argument) { 21 | return execution.getLabel(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/StringProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/24 12 | */ 13 | public class StringProvider extends Provider { 14 | 15 | public StringProvider() { 16 | super(ProviderType.ARGUMENT, "string"); 17 | } 18 | 19 | @Override 20 | public String provide(CommandExecution execution, CommandArgument argument) { 21 | return argument.getValue(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/actor/ActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor; 2 | 3 | import net.j4c0b3y.api.command.actor.Actor; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 31/08/2024 13 | */ 14 | public class ActorProvider extends Provider { 15 | 16 | public ActorProvider() { 17 | super(ProviderType.CONTEXT); 18 | } 19 | 20 | @Override 21 | public Actor provide(CommandExecution execution, CommandArgument argument) { 22 | return execution.getActor(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/context/CommandExecutionProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.context; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/2024 12 | */ 13 | public class CommandExecutionProvider extends Provider { 14 | 15 | public CommandExecutionProvider() { 16 | super(ProviderType.CONTEXT); 17 | } 18 | 19 | @Override 20 | public CommandExecution provide(CommandExecution execution, CommandArgument argument) { 21 | return execution; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/context/InstanceProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.context; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 27/08/2024 12 | */ 13 | public class InstanceProvider extends Provider { 14 | private final T instance; 15 | 16 | public InstanceProvider(T instance) { 17 | super(ProviderType.CONTEXT); 18 | this.instance = instance; 19 | } 20 | 21 | @Override 22 | public T provide(CommandExecution execution, CommandArgument argument) { 23 | return instance; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/context/CommandHandleProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.context; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.CommandHandle; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 1/09/2024 13 | */ 14 | public class CommandHandleProvider extends Provider { 15 | 16 | public CommandHandleProvider() { 17 | super(ProviderType.CONTEXT); 18 | } 19 | 20 | @Override 21 | public CommandHandle provide(CommandExecution execution, CommandArgument argument) { 22 | return execution.getHandle(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.utils; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.util.Collections; 6 | 7 | /** 8 | * @author J4C0B3Y 9 | * @version CommandAPI 10 | * @since 30/08/24 11 | */ 12 | @UtilityClass 13 | public class StringUtils { 14 | public String repeat(String content, int amount) { 15 | return String.join("", Collections.nCopies(amount, content)); 16 | } 17 | 18 | public boolean startsWithIgnoreCase(String content, String prefix) { 19 | return content.toLowerCase().startsWith(prefix.toLowerCase()); 20 | } 21 | 22 | public String decapitalize(String content) { 23 | if (content == null || content.isEmpty()) return content; 24 | 25 | char[] characters = content.toCharArray(); 26 | characters[0] = Character.toLowerCase(characters[0]); 27 | 28 | return new String(characters); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/context/CommandWrapperProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.context; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 1/09/2024 13 | */ 14 | public class CommandWrapperProvider extends Provider { 15 | 16 | public CommandWrapperProvider() { 17 | super(ProviderType.CONTEXT); 18 | } 19 | 20 | @Override 21 | public CommandWrapper provide(CommandExecution execution, CommandArgument argument) { 22 | return execution.getHandle().getWrapper(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024-Present J4C0B3Y 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Clean_CommandAPI.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 19 | true 20 | true 21 | false 22 | false 23 | 24 | 25 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/actor/CommandSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | import org.bukkit.command.CommandSender; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 9/1/24 13 | */ 14 | public class CommandSenderProvider extends Provider { 15 | private final BukkitActorProvider bukkitActorProvider; 16 | 17 | public CommandSenderProvider(BukkitActorProvider bukkitActorProvider) { 18 | super(ProviderType.CONTEXT); 19 | this.bukkitActorProvider = bukkitActorProvider; 20 | } 21 | 22 | @Override 23 | public CommandSender provide(CommandExecution execution, CommandArgument argument) { 24 | return bukkitActorProvider.provide(execution, argument).getSender(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/provider/actor/CommandSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | import net.md_5.bungee.api.CommandSender; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 25/10/2024 13 | */ 14 | public class CommandSenderProvider extends Provider { 15 | private final BungeeActorProvider bungeeActorProvider; 16 | 17 | public CommandSenderProvider(BungeeActorProvider bungeeActorProvider) { 18 | super(ProviderType.CONTEXT); 19 | this.bungeeActorProvider = bungeeActorProvider; 20 | } 21 | 22 | @Override 23 | public CommandSender provide(CommandExecution execution, CommandArgument argument) { 24 | return bungeeActorProvider.provide(execution, argument).getSender(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/provider/actor/CommandSourceProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.provider.actor; 2 | 3 | import com.velocitypowered.api.command.CommandSource; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 20/10/2024 13 | */ 14 | public class CommandSourceProvider extends Provider { 15 | private final VelocityActorProvider velocityActorProvider; 16 | 17 | public CommandSourceProvider(VelocityActorProvider velocityActorProvider) { 18 | super(ProviderType.CONTEXT); 19 | this.velocityActorProvider = velocityActorProvider; 20 | } 21 | 22 | @Override 23 | public CommandSource provide(CommandExecution execution, CommandArgument argument) { 24 | return velocityActorProvider.provide(execution, null).getSource(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Publish_CommandAPI.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 18 | 20 | true 21 | true 22 | false 23 | false 24 | 25 | 26 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/actor/ProxyActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor; 2 | 3 | import net.j4c0b3y.api.command.actor.ProxyActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | 10 | /** 11 | * @author J4C0B3Y 12 | * @version CommandAPI 13 | * @since 9/1/24 14 | */ 15 | public class ProxyActorProvider extends Provider { 16 | 17 | public ProxyActorProvider() { 18 | super(ProviderType.CONTEXT); 19 | } 20 | 21 | @Override 22 | public ProxyActor provide(CommandExecution execution, CommandArgument argument) { 23 | if (!execution.getActor().isProxy()) { 24 | throw new ExitMessage(execution.getHandler().getLocale().getProxyOnly()); 25 | } 26 | 27 | return execution.getActor(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/actor/PlayerActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor; 2 | 3 | import net.j4c0b3y.api.command.actor.PlayerActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | 10 | /** 11 | * @author J4C0B3Y 12 | * @version CommandAPI 13 | * @since 1/09/2024 14 | */ 15 | public class PlayerActorProvider extends Provider { 16 | 17 | public PlayerActorProvider() { 18 | super(ProviderType.CONTEXT); 19 | } 20 | 21 | @Override 22 | public PlayerActor provide(CommandExecution execution, CommandArgument argument) { 23 | if (!execution.getActor().isPlayer()) { 24 | throw new ExitMessage(execution.getHandler().getLocale().getPlayerOnly()); 25 | } 26 | 27 | return execution.getActor(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/actor/ConsoleActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor; 2 | 3 | import net.j4c0b3y.api.command.actor.ConsoleActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | 10 | /** 11 | * @author J4C0B3Y 12 | * @version CommandAPI 13 | * @since 9/1/24 14 | */ 15 | public class ConsoleActorProvider extends Provider { 16 | 17 | public ConsoleActorProvider() { 18 | super(ProviderType.CONTEXT); 19 | } 20 | 21 | @Override 22 | public ConsoleActor provide(CommandExecution execution, CommandArgument argument) { 23 | if (!execution.getActor().isConsole()) { 24 | throw new ExitMessage(execution.getHandler().getLocale().getConsoleOnly()); 25 | } 26 | 27 | return execution.getActor(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/ParameterBinding.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | 8 | import java.lang.annotation.Annotation; 9 | import java.util.List; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 27/08/2024 15 | */ 16 | @Getter 17 | @RequiredArgsConstructor 18 | public class ParameterBinding { 19 | private final Class type; 20 | private final Provider provider; 21 | private final List> classifiers; 22 | 23 | public boolean provides(CommandParameter parameter) { 24 | if (parameter.getClassifiers().size() != classifiers.size()) { 25 | return false; 26 | } 27 | 28 | for (Annotation classifier : parameter.getClassifiers()) { 29 | if (!classifiers.contains(classifier.annotationType())) { 30 | return false; 31 | } 32 | } 33 | 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/utils/ListUtils.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.utils; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.function.Function; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 28/08/2024 15 | */ 16 | @UtilityClass 17 | public class ListUtils { 18 | public List map(List list, Function mapper) { 19 | List mapped = new ArrayList<>(); 20 | 21 | for (T item : list) { 22 | mapped.add(mapper.apply(item)); 23 | } 24 | 25 | return mapped; 26 | } 27 | 28 | public List map(T[] array, Function mapper) { 29 | return map(Arrays.asList(array), mapper); 30 | } 31 | 32 | public List reversed(List list) { 33 | List reversed = new ArrayList<>(list); 34 | Collections.reverse(reversed); 35 | return reversed; 36 | } 37 | 38 | public List asList(T[] array) { 39 | return new ArrayList<>(Arrays.asList(array)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/CharacterProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 27/08/2024 13 | */ 14 | public class CharacterProvider extends Provider { 15 | 16 | public CharacterProvider() { 17 | super(ProviderType.ARGUMENT, "character"); 18 | } 19 | 20 | @Override 21 | public Character provide(CommandExecution execution, CommandArgument argument) { 22 | String value = argument.getValue(); 23 | 24 | if (value.length() > 1) { 25 | throw new ExitMessage(execution.getHandler().getLocale() 26 | .getInvalidType("character", argument.getValue()) 27 | ); 28 | } 29 | 30 | return value.charAt(0); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Build_CommandAPI.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 20 | 22 | true 23 | true 24 | false 25 | false 26 | 27 | 28 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/UUIDProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | import java.util.UUID; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 25/10/2024 15 | */ 16 | public class UUIDProvider extends Provider { 17 | 18 | public UUIDProvider() { 19 | super(ProviderType.ARGUMENT, "uuid"); 20 | } 21 | 22 | @Override 23 | public UUID provide(CommandExecution execution, CommandArgument argument) { 24 | try { 25 | return UUID.fromString(argument.getValue()); 26 | } catch (IllegalArgumentException exception) { 27 | throw new ExitMessage(execution.getHandler().getLocale() 28 | .getInvalidType("uuid", argument.getValue()) 29 | ); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/actor/BukkitActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.bukkit.BukkitCommandHandler; 4 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 5 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 6 | import net.j4c0b3y.api.command.execution.CommandExecution; 7 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 9/1/24 15 | */ 16 | public class BukkitActorProvider extends Provider { 17 | private final BukkitCommandHandler handler; 18 | 19 | public BukkitActorProvider(BukkitCommandHandler handler) { 20 | super(ProviderType.CONTEXT); 21 | this.handler = handler; 22 | } 23 | 24 | @Override 25 | public BukkitActor provide(CommandExecution execution, CommandArgument argument) { 26 | if (!(execution.getActor() instanceof BukkitActor)) { 27 | throw new ExitMessage(handler.getBukkitLocale().getBukkitOnly()); 28 | } 29 | 30 | return (BukkitActor) execution.getActor(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/provider/actor/BungeeActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.bungee.BungeeCommandHandler; 4 | import net.j4c0b3y.api.command.bungee.actor.BungeeActor; 5 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 6 | import net.j4c0b3y.api.command.execution.CommandExecution; 7 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 25/10/2024 15 | */ 16 | public class BungeeActorProvider extends Provider { 17 | private final BungeeCommandHandler handler; 18 | 19 | public BungeeActorProvider(BungeeCommandHandler handler) { 20 | super(ProviderType.CONTEXT); 21 | this.handler = handler; 22 | } 23 | 24 | @Override 25 | public BungeeActor provide(CommandExecution execution, CommandArgument argument) { 26 | if (!(execution.getActor() instanceof BungeeActor)) { 27 | throw new ExitMessage(handler.getBungeeLocale().getBungeeOnly()); 28 | } 29 | 30 | return (BungeeActor) execution.getActor(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/Provider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 7 | 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 27/08/2024 15 | */ 16 | @Getter 17 | public abstract class Provider { 18 | private final boolean consumer; 19 | private final String defaultName; 20 | 21 | public Provider(ProviderType type, String defaultName) { 22 | this.consumer = type.isConsumer(); 23 | this.defaultName = defaultName; 24 | } 25 | 26 | public Provider(ProviderType type) { 27 | this(type, null); 28 | } 29 | 30 | public T flagDefault(CommandExecution execution) { 31 | return null; 32 | } 33 | 34 | public boolean isAsync() { 35 | return false; 36 | } 37 | 38 | public abstract T provide(CommandExecution execution, CommandArgument argument); 39 | 40 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 41 | return Collections.emptyList(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/modifier/impl/LengthModifier.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.modifier.impl; 2 | 3 | import net.j4c0b3y.api.command.annotation.parameter.modifier.Length; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 7 | import net.j4c0b3y.api.command.wrapper.binding.modifier.ArgumentModifier; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 28/08/2024 13 | */ 14 | public class LengthModifier implements ArgumentModifier { 15 | 16 | @Override 17 | public String modify(String value, CommandExecution execution, CommandParameter parameter) { 18 | Length length = parameter.getAnnotation(Length.class); 19 | 20 | if (value.length() < length.min()) { 21 | throw new ExitMessage(execution.getHandler().getLocale().getBelowMinimum( 22 | String.valueOf(length.min()), value 23 | )); 24 | } 25 | 26 | if (value.length() > length.max()) { 27 | throw new ExitMessage(execution.getHandler().getLocale().getAboveMaximum( 28 | String.valueOf(length.max()), value 29 | )); 30 | } 31 | 32 | return value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/provider/actor/VelocityActorProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.velocity.VelocityCommandHandler; 7 | import net.j4c0b3y.api.command.velocity.actor.VelocityActor; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 20/10/2024 15 | */ 16 | public class VelocityActorProvider extends Provider { 17 | private final VelocityCommandHandler handler; 18 | 19 | public VelocityActorProvider(VelocityCommandHandler handler) { 20 | super(ProviderType.CONTEXT); 21 | this.handler = handler; 22 | } 23 | 24 | @Override 25 | public VelocityActor provide(CommandExecution execution, CommandArgument argument) { 26 | if (!(execution.getActor() instanceof VelocityActor)) { 27 | throw new ExitMessage(handler.getVelocityLocale().getVelocityOnly()); 28 | } 29 | 30 | return (VelocityActor) execution.getActor(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/modifier/impl/RangeModifier.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.modifier.impl; 2 | 3 | import net.j4c0b3y.api.command.annotation.parameter.modifier.Range; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 7 | import net.j4c0b3y.api.command.wrapper.binding.modifier.ArgumentModifier; 8 | 9 | /** 10 | * @author J4C0B3Y 11 | * @version CommandAPI 12 | * @since 28/08/2024 13 | */ 14 | public class RangeModifier implements ArgumentModifier { 15 | 16 | @Override 17 | public T modify(T value, CommandExecution execution, CommandParameter parameter) { 18 | Range range = parameter.getAnnotation(Range.class); 19 | 20 | if (value.doubleValue() < range.min()) { 21 | throw new ExitMessage(execution.getHandler().getLocale().getBelowMinimum( 22 | String.valueOf(range.min()), value.toString() 23 | )); 24 | } 25 | 26 | if (value.doubleValue() > range.max()) { 27 | throw new ExitMessage(execution.getHandler().getLocale().getAboveMaximum( 28 | String.valueOf(range.max()), value.toString() 29 | )); 30 | } 31 | 32 | return value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/actor/PlayerSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import org.bukkit.entity.Player; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 9/1/24 15 | */ 16 | public class PlayerSenderProvider extends Provider { 17 | private final BukkitActorProvider bukkitActorProvider; 18 | 19 | public PlayerSenderProvider(BukkitActorProvider bukkitActorProvider) { 20 | super(ProviderType.CONTEXT); 21 | this.bukkitActorProvider = bukkitActorProvider; 22 | } 23 | 24 | @Override 25 | public Player provide(CommandExecution execution, CommandArgument argument) { 26 | BukkitActor bukkitActor = bukkitActorProvider.provide(execution, null); 27 | 28 | if (!bukkitActor.isPlayer()) { 29 | throw new ExitMessage(execution.getHandler().getLocale().getPlayerOnly()); 30 | } 31 | 32 | return (Player) bukkitActor.getSender(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/provider/actor/PlayerSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.provider.actor; 2 | 3 | import com.velocitypowered.api.proxy.Player; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.velocity.actor.VelocityActor; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 20/10/2024 15 | */ 16 | public class PlayerSenderProvider extends Provider { 17 | private final VelocityActorProvider velocityActorProvider; 18 | 19 | public PlayerSenderProvider(VelocityActorProvider velocityActorProvider) { 20 | super(ProviderType.CONTEXT); 21 | this.velocityActorProvider = velocityActorProvider; 22 | } 23 | 24 | @Override 25 | public Player provide(CommandExecution execution, CommandArgument argument) { 26 | VelocityActor velocityActor = velocityActorProvider.provide(execution, null); 27 | 28 | if (!velocityActor.isPlayer()) { 29 | throw new ExitMessage(execution.getHandler().getLocale().getPlayerOnly()); 30 | } 31 | 32 | return (Player) velocityActor.getSource(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/provider/actor/ConsoleCommandSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.bungee.actor.BungeeActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import net.md_5.bungee.api.CommandSender; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 25/10/2024 15 | */ 16 | public class ConsoleCommandSenderProvider extends Provider { 17 | private final BungeeActorProvider bungeeActorProvider; 18 | 19 | public ConsoleCommandSenderProvider(BungeeActorProvider bungeeActorProvider) { 20 | super(ProviderType.CONTEXT); 21 | this.bungeeActorProvider = bungeeActorProvider; 22 | } 23 | 24 | @Override 25 | public CommandSender provide(CommandExecution execution, CommandArgument argument) { 26 | BungeeActor bungeeActor = bungeeActorProvider.provide(execution, argument); 27 | 28 | if (!bungeeActor.isConsole()) { 29 | throw new ExitMessage(execution.getHandler().getLocale().getConsoleOnly()); 30 | } 31 | 32 | return bungeeActor.getSender(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/provider/actor/ProxiedPlayerSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.bungee.actor.BungeeActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import net.md_5.bungee.api.connection.ProxiedPlayer; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 25/10/2024 15 | */ 16 | public class ProxiedPlayerSenderProvider extends Provider { 17 | private final BungeeActorProvider bungeeActorProvider; 18 | 19 | public ProxiedPlayerSenderProvider(BungeeActorProvider bungeeActorProvider) { 20 | super(ProviderType.CONTEXT); 21 | this.bungeeActorProvider = bungeeActorProvider; 22 | } 23 | 24 | @Override 25 | public ProxiedPlayer provide(CommandExecution execution, CommandArgument argument) { 26 | BungeeActor bungeeActor = bungeeActorProvider.provide(execution, null); 27 | 28 | if (!bungeeActor.isPlayer()) { 29 | throw new ExitMessage(execution.getHandler().getLocale().getPlayerOnly()); 30 | } 31 | 32 | return (ProxiedPlayer) bungeeActor.getSender(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/utils/AnnotationUtils.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.utils; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.lang.annotation.Annotation; 6 | import java.lang.reflect.AnnotatedElement; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.function.Function; 11 | 12 | /** 13 | * @author J4C0B3Y 14 | * @version CommandAPI 15 | * @since 28/08/2024 16 | */ 17 | @UtilityClass 18 | public class AnnotationUtils { 19 | public R getValue(AnnotatedElement element, Class type, Function mapper, R fallback) { 20 | T annotation = element.getAnnotation(type); 21 | 22 | if (annotation == null) { 23 | return fallback; 24 | } 25 | 26 | return mapper.apply(annotation); 27 | } 28 | 29 | public List getSpecial(List annotations, Class type) { 30 | List special = new ArrayList<>(); 31 | 32 | for (Annotation annotation : annotations) { 33 | if (annotation.annotationType().isAnnotationPresent(type)) { 34 | special.add(annotation); 35 | } 36 | } 37 | 38 | return special; 39 | } 40 | 41 | public List getSpecial(Annotation[] annotations, Class type) { 42 | return getSpecial(Arrays.asList(annotations), type); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/actor/ConsoleCommandSenderProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.actor; 2 | 3 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import org.bukkit.command.ConsoleCommandSender; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 9/1/24 15 | */ 16 | public class ConsoleCommandSenderProvider extends Provider { 17 | private final BukkitActorProvider bukkitActorProvider; 18 | 19 | public ConsoleCommandSenderProvider(BukkitActorProvider bukkitActorProvider) { 20 | super(ProviderType.CONTEXT); 21 | this.bukkitActorProvider = bukkitActorProvider; 22 | } 23 | 24 | @Override 25 | public ConsoleCommandSender provide(CommandExecution execution, CommandArgument argument) { 26 | BukkitActor bukkitActor = bukkitActorProvider.provide(execution, null); 27 | 28 | if (!bukkitActor.isConsole()) { 29 | throw new ExitMessage(execution.getHandler().getLocale().getConsoleOnly()); 30 | } 31 | 32 | return (ConsoleCommandSender) bukkitActor.getSender(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/argument/flag/CommandFlag.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution.argument.flag; 2 | 3 | import lombok.experimental.UtilityClass; 4 | import net.j4c0b3y.api.command.CommandHandler; 5 | import net.j4c0b3y.api.command.exception.execution.UnknownFlagException; 6 | import net.j4c0b3y.api.command.utils.StringUtils; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 1/09/2024 12 | */ 13 | @UtilityClass 14 | public class CommandFlag { 15 | public String getName(String flag) { 16 | return flag.replaceAll("^-+", ""); 17 | } 18 | 19 | public String getFlag(String name) { 20 | return StringUtils.repeat("-", Math.min(name.length(), 2)) + name; 21 | } 22 | 23 | public String validate(String argument, CommandHandler handler) throws UnknownFlagException { 24 | int length = argument.length(); 25 | int hyphens = length - getName(argument).length(); 26 | 27 | if (hyphens == 1 && length != 2) { 28 | throw new UnknownFlagException(handler.getLocale().getFlagDoubleHyphen(argument)); 29 | } 30 | 31 | if (hyphens == 2 && length < 4) { 32 | throw new UnknownFlagException(handler.getLocale().getFlagNameTooShort(argument)); 33 | } 34 | 35 | if (hyphens >= 3) { 36 | throw new UnknownFlagException(handler.getLocale().getFlagNameHyphen(argument)); 37 | } 38 | 39 | return hyphens != 0 ? argument.substring(hyphens) : null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/provider/actor/ConsoleCommandSourceProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.provider.actor; 2 | 3 | import com.velocitypowered.api.proxy.ConsoleCommandSource; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.velocity.actor.VelocityActor; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 25/10/2024 15 | */ 16 | public class ConsoleCommandSourceProvider extends Provider { 17 | private final VelocityActorProvider velocityActorProvider; 18 | 19 | public ConsoleCommandSourceProvider(VelocityActorProvider velocityActorProvider) { 20 | super(ProviderType.CONTEXT); 21 | this.velocityActorProvider = velocityActorProvider; 22 | } 23 | 24 | @Override 25 | public ConsoleCommandSource provide(CommandExecution execution, CommandArgument argument) { 26 | VelocityActor velocityActor = velocityActorProvider.provide(execution, argument); 27 | 28 | if (!velocityActor.isConsole()) { 29 | throw new ExitMessage(execution.getHandler().getLocale().getConsoleOnly()); 30 | } 31 | 32 | return (ConsoleCommandSource) velocityActor.getSource(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/NumberProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | 9 | import java.util.function.Function; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 20/10/2024 15 | */ 16 | public class NumberProvider extends Provider { 17 | private final Function parser; 18 | private final String type; 19 | private final T flagDefault; 20 | 21 | public NumberProvider(Function parser, String type, T flagDefault) { 22 | super(ProviderType.ARGUMENT); 23 | this.parser = parser; 24 | this.type = type; 25 | this.flagDefault = flagDefault; 26 | } 27 | 28 | @Override 29 | public T flagDefault(CommandExecution execution) { 30 | return flagDefault; 31 | } 32 | 33 | @Override 34 | public T provide(CommandExecution execution, CommandArgument argument) { 35 | try { 36 | return parser.apply(argument.getValue()); 37 | } catch (NumberFormatException exception) { 38 | throw new ExitMessage(execution.getHandler().getLocale() 39 | .getInvalidType(type, argument.getValue()) 40 | ); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/utils/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.utils; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | * @author J4C0B3Y 10 | * @version CommandAPI 11 | * @since 30/08/2024 12 | */ 13 | @UtilityClass 14 | public class ClassUtils { 15 | public void ifPresent(String className, Runnable callback) { 16 | try { 17 | Class.forName(className); 18 | callback.run(); 19 | } catch (ClassNotFoundException exception) { 20 | // ignored 21 | } 22 | } 23 | 24 | public Object getField(Object object, Class type, String name) throws ReflectiveOperationException { 25 | Field field = type.getDeclaredField(name); 26 | field.setAccessible(true); 27 | return field.get(object); 28 | } 29 | 30 | public Object getField(Object object, String name) throws ReflectiveOperationException { 31 | return getField(object, object.getClass(), name); 32 | } 33 | 34 | public void setField(Object object, Class type, String name, Object value) throws ReflectiveOperationException { 35 | Field field = type.getDeclaredField(name); 36 | field.setAccessible(true); 37 | field.set(object, value); 38 | } 39 | 40 | public Constructor getConstructor(Class clazz, Class ...parameters) throws ReflectiveOperationException { 41 | Constructor constructor = clazz.getDeclaredConstructor(parameters); 42 | constructor.setAccessible(true); 43 | return constructor; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/argument/EnchantmentProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 9 | import org.bukkit.enchantments.Enchantment; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * @author J4C0B3Y 16 | * @version CommandAPI 17 | * @since 25/10/2024 18 | */ 19 | public class EnchantmentProvider extends Provider { 20 | 21 | public EnchantmentProvider() { 22 | super(ProviderType.ARGUMENT, "enchantment"); 23 | } 24 | 25 | @Override 26 | public Enchantment provide(CommandExecution execution, CommandArgument argument) { 27 | Enchantment enchantment = Enchantment.getByName(argument.getValue().toUpperCase()); 28 | 29 | if (enchantment == null) { 30 | throw new ExitMessage(execution.getHandler().getLocale() 31 | .getInvalidEnum(argument.getValue(), suggest(null, null)) 32 | ); 33 | } 34 | 35 | return enchantment; 36 | } 37 | 38 | @Override 39 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 40 | List suggestions = new ArrayList<>(); 41 | 42 | for (Enchantment enchantment : Enchantment.values()) { 43 | suggestions.add(enchantment.getName()); 44 | } 45 | 46 | return suggestions; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/modifier/ModifierHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.modifier; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 5 | 6 | import java.lang.annotation.Annotation; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author J4C0B3Y 14 | * @version CommandAPI 15 | * @since 27/08/2024 16 | */ 17 | public class ModifierHandler { 18 | private final Map, Map, List>>> modifiers = new HashMap<>(); 19 | 20 | public void put(Class type, Class annotation, ArgumentModifier modifier) { 21 | modifiers.computeIfAbsent(annotation, key -> new HashMap<>()).computeIfAbsent(type, key -> new ArrayList<>()).add(modifier); 22 | } 23 | 24 | @SuppressWarnings("unchecked") 25 | public T modify(T value, CommandExecution execution, CommandParameter parameter) { 26 | for (Annotation annotation : parameter.getModifiers()) { 27 | if (value == null) break; 28 | 29 | Map, List>> map = this.modifiers.get(annotation.annotationType()); 30 | if (map == null) continue; 31 | 32 | List> modifiers = map.get(value.getClass()); 33 | if (modifiers == null) continue; 34 | 35 | for (ArgumentModifier modifier : modifiers) { 36 | value = ((ArgumentModifier) modifier).modify(value, execution, parameter); 37 | } 38 | } 39 | 40 | return value; 41 | } 42 | 43 | public void clear() { 44 | modifiers.clear(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/MapProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.function.Supplier; 14 | 15 | /** 16 | * @author J4C0B3Y 17 | * @version CommandAPI 18 | * @since 1/02/2025 19 | */ 20 | public class MapProvider> extends Provider { 21 | 22 | private final Supplier supplier; 23 | private final String keyName; 24 | 25 | public MapProvider(Supplier supplier, String keyName, String valueName) { 26 | super(ProviderType.ARGUMENT, valueName); 27 | this.supplier = supplier; 28 | this.keyName = keyName; 29 | } 30 | 31 | @Override 32 | public T provide(CommandExecution execution, CommandArgument argument) { 33 | T value = supplier.get().get(argument.getValue()); 34 | 35 | if (value == null) { 36 | throw new ExitMessage(execution.getHandler().getLocale() 37 | .getMapEntryNotFound(argument.getValue(), keyName, getDefaultName()) 38 | ); 39 | } 40 | 41 | return value; 42 | } 43 | 44 | @Override 45 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 46 | return new ArrayList<>(supplier.get().keySet()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/condition/ConditionHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.condition; 2 | 3 | import net.j4c0b3y.api.command.actor.Actor; 4 | import net.j4c0b3y.api.command.annotation.command.condition.Condition; 5 | import net.j4c0b3y.api.command.exception.execution.MissingValidatorException; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * @author J4C0B3Y 13 | * @version CommandAPI 14 | * @since 25/10/2024 15 | */ 16 | public class ConditionHandler { 17 | private final Map, ExecuteCondition> conditions = new HashMap<>(); 18 | 19 | public void put(Class annotation, ExecuteCondition condition) { 20 | if (!annotation.isAnnotation() || !annotation.isAnnotationPresent(Condition.class)) { 21 | throw new IllegalArgumentException(annotation.getSimpleName() + " must be an annotation marked @Condition."); 22 | } 23 | 24 | conditions.put(annotation, condition); 25 | } 26 | 27 | @SuppressWarnings("unchecked") 28 | public boolean validate(T annotation, Actor actor) { 29 | Class type = annotation.annotationType(); 30 | 31 | if (!type.isAnnotationPresent(Condition.class)) { 32 | throw new IllegalArgumentException("Cannot validate using a non @Condition annotation."); 33 | } 34 | 35 | if (!conditions.containsKey(annotation.annotationType())) { 36 | throw new MissingValidatorException("No validator bound for condition '@" + type.getSimpleName() + "'."); 37 | } 38 | 39 | ExecuteCondition condition = (ExecuteCondition) conditions.get(type); 40 | return condition.validate(actor, annotation); 41 | } 42 | 43 | public void clear() { 44 | conditions.clear(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/actor/BukkitActor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.actor; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.CommandHandler; 5 | import net.j4c0b3y.api.command.actor.Actor; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.command.ConsoleCommandSender; 8 | import org.bukkit.entity.Player; 9 | 10 | import java.util.UUID; 11 | 12 | /** 13 | * @author J4C0B3Y 14 | * @version CommandAPI 15 | * @since 30/08/2024 16 | */ 17 | @Getter 18 | public class BukkitActor extends Actor { 19 | private final CommandSender sender; 20 | 21 | public BukkitActor(CommandSender sender, CommandHandler handler) { 22 | super(handler); 23 | this.sender = sender; 24 | } 25 | 26 | @Override 27 | public boolean hasPermission(String permission) { 28 | return permission == null || sender.hasPermission(permission); 29 | } 30 | 31 | @Override 32 | public void sendMessage(String message) { 33 | sender.sendMessage(getHandler().getTranslator().apply(message)); 34 | } 35 | 36 | @Override 37 | public boolean isConsole() { 38 | return sender instanceof ConsoleCommandSender; 39 | } 40 | 41 | @Override 42 | public boolean isPlayer() { 43 | return sender instanceof Player; 44 | } 45 | 46 | @Override 47 | public UUID getUniqueId() { 48 | return isPlayer() ? ((Player) sender).getUniqueId() : null; 49 | } 50 | 51 | @Override 52 | public String getName() { 53 | return sender.getName(); 54 | } 55 | 56 | public Player getPlayer() { 57 | if (!isPlayer()) { 58 | throw new IllegalStateException("Sender is not a player!"); 59 | } 60 | 61 | return (Player) sender; 62 | } 63 | 64 | @Override 65 | public boolean isProxy() { 66 | return false; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/provider/argument/PlayerProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.provider.argument; 2 | 3 | import com.velocitypowered.api.proxy.Player; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.velocity.VelocityCommandHandler; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 15/6/2025 20 | */ 21 | public class PlayerProvider extends Provider { 22 | private final VelocityCommandHandler handler; 23 | 24 | public PlayerProvider(VelocityCommandHandler handler) { 25 | super(ProviderType.ARGUMENT, "player"); 26 | this.handler = handler; 27 | } 28 | 29 | @Override 30 | public Player provide(CommandExecution execution, CommandArgument argument) { 31 | Optional player = handler.getProxy().getPlayer(argument.getValue()); 32 | 33 | if (player.isEmpty()) { 34 | throw new ExitMessage(handler.getVelocityLocale().getPlayerOffline(argument.getValue())); 35 | } 36 | 37 | return player.get(); 38 | } 39 | 40 | @Override 41 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 42 | List suggestions = new ArrayList<>(); 43 | 44 | for (Player player : handler.getProxy().getAllPlayers()) { 45 | suggestions.add(player.getUsername()); 46 | } 47 | 48 | return suggestions; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/ArrayProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.execution.CommandExecution; 4 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 7 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 8 | 9 | import java.lang.reflect.Array; 10 | import java.util.List; 11 | 12 | /** 13 | * @author J4C0B3Y 14 | * @version CommandAPI 15 | * @since 4/10/2025 16 | */ 17 | public class ArrayProvider extends Provider { 18 | 19 | private final Provider provider; 20 | private final Class type; 21 | 22 | public ArrayProvider(Provider provider, Class type) { 23 | super(ProviderType.ARGUMENT, provider.getDefaultName() + "s"); 24 | 25 | if (type.isPrimitive()) { 26 | throw new IllegalArgumentException("Primitive array parameters are not supported."); 27 | } 28 | 29 | this.provider = provider; 30 | this.type = type; 31 | } 32 | 33 | @Override 34 | @SuppressWarnings("unchecked") 35 | public T[] provide(CommandExecution execution, CommandArgument argument) { 36 | String[] arguments = argument.getValue().split(" "); 37 | T[] values = (T[]) Array.newInstance(type, arguments.length); 38 | 39 | for (int i = 0; i < arguments.length; i++) { 40 | values[i] = (T) provider.provide(execution, 41 | new CommandArgument(arguments[i], argument.getParameter()) 42 | ); 43 | } 44 | 45 | return values; 46 | } 47 | 48 | @Override 49 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 50 | return provider.suggest(suggestion, argument); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/argument/WorldProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.argument; 2 | 3 | import net.j4c0b3y.api.command.bukkit.BukkitCommandHandler; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.World; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 20/10/2024 20 | */ 21 | public class WorldProvider extends Provider { 22 | private final BukkitCommandHandler handler; 23 | 24 | public WorldProvider(BukkitCommandHandler handler) { 25 | super(ProviderType.ARGUMENT, "world"); 26 | this.handler = handler; 27 | } 28 | 29 | @Override 30 | public World flagDefault(CommandExecution execution) { 31 | return Bukkit.getWorlds().get(0); 32 | } 33 | 34 | @Override 35 | public World provide(CommandExecution execution, CommandArgument argument) { 36 | World world = Bukkit.getWorld(argument.getValue()); 37 | 38 | if (world == null) { 39 | throw new ExitMessage(handler.getBukkitLocale().getInvalidWorld(argument.getValue())); 40 | } 41 | 42 | return world; 43 | } 44 | 45 | @Override 46 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 47 | List suggestions = new ArrayList<>(); 48 | 49 | for (World world : Bukkit.getWorlds()) { 50 | suggestions.add(world.getName()); 51 | } 52 | 53 | return suggestions; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/listener/AsyncTabListener.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.listener; 2 | 3 | import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; 4 | import lombok.RequiredArgsConstructor; 5 | import net.j4c0b3y.api.command.bukkit.BukkitCommandHandler; 6 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 7 | import net.j4c0b3y.api.command.utils.ListUtils; 8 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 9 | import org.bukkit.command.Command; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.event.EventHandler; 12 | import org.bukkit.event.Listener; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 30/08/2024 20 | */ 21 | @RequiredArgsConstructor 22 | public class AsyncTabListener implements Listener { 23 | private final BukkitCommandHandler handler; 24 | 25 | @EventHandler 26 | public void onTabComplete(AsyncTabCompleteEvent event) { 27 | if (!event.isCommand() || !event.getBuffer().contains(" ")) return; 28 | 29 | List arguments = ListUtils.asList(event.getBuffer().split(" ", -1)); 30 | String name = arguments.remove(0); 31 | 32 | if (event.getSender() instanceof Player) { 33 | name = name.replaceFirst("/", ""); 34 | } 35 | 36 | Command command = handler.getRegistry().getKnownCommands().get(name); 37 | if (command == null) return; 38 | 39 | CommandWrapper wrapper = handler.getRegistry().getWrappers().get(command); 40 | if (wrapper == null) return; 41 | 42 | List suggestions = wrapper.suggest(new BukkitActor(event.getSender(), handler), arguments); 43 | 44 | if (suggestions.isEmpty()) { 45 | return; 46 | } 47 | 48 | for (String suggestion : suggestions) { 49 | event.getCompletions().add(suggestion); 50 | } 51 | 52 | event.setHandled(true); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/provider/argument/ServerInfoProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.provider.argument; 2 | 3 | import net.j4c0b3y.api.command.bungee.BungeeCommandHandler; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 10 | import net.md_5.bungee.api.ProxyServer; 11 | import net.md_5.bungee.api.config.ServerInfo; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 25/10/2024 20 | */ 21 | public class ServerInfoProvider extends Provider { 22 | private final BungeeCommandHandler handler; 23 | private final ProxyServer proxy; 24 | 25 | public ServerInfoProvider(BungeeCommandHandler handler) { 26 | super(ProviderType.ARGUMENT, "server"); 27 | this.handler = handler; 28 | this.proxy = handler.getPlugin().getProxy(); 29 | } 30 | 31 | @Override 32 | public ServerInfo provide(CommandExecution execution, CommandArgument argument) { 33 | ServerInfo server = proxy.getServerInfo(argument.getValue()); 34 | 35 | if (server == null) { 36 | throw new ExitMessage(handler.getLocale().getInvalidServer(argument.getValue())); 37 | } 38 | 39 | return server; 40 | } 41 | 42 | @Override 43 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 44 | List suggestions = new ArrayList<>(); 45 | 46 | for (ServerInfo server : proxy.getServers().values()) { 47 | suggestions.add(server.getName()); 48 | } 49 | 50 | return suggestions; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/actor/BungeeActor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee.actor; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.CommandHandler; 5 | import net.j4c0b3y.api.command.actor.Actor; 6 | import net.md_5.bungee.api.CommandSender; 7 | import net.md_5.bungee.api.ProxyServer; 8 | import net.md_5.bungee.api.chat.TextComponent; 9 | import net.md_5.bungee.api.connection.ProxiedPlayer; 10 | 11 | import java.util.UUID; 12 | 13 | /** 14 | * @author J4C0B3Y 15 | * @version CommandAPI 16 | * @since 30/08/2024 17 | */ 18 | @Getter 19 | public class BungeeActor extends Actor { 20 | private final CommandSender sender; 21 | 22 | public BungeeActor(CommandSender sender, CommandHandler handler) { 23 | super(handler); 24 | this.sender = sender; 25 | } 26 | 27 | @Override 28 | public boolean hasPermission(String permission) { 29 | return permission == null || sender.hasPermission(permission); 30 | } 31 | 32 | @Override 33 | public void sendMessage(String message) { 34 | sender.sendMessage(new TextComponent(getHandler().getTranslator().apply(message))); 35 | } 36 | 37 | @Override 38 | public boolean isConsole() { 39 | return sender.equals(ProxyServer.getInstance().getConsole()); 40 | } 41 | 42 | @Override 43 | public boolean isPlayer() { 44 | return sender instanceof ProxiedPlayer; 45 | } 46 | 47 | @Override 48 | public UUID getUniqueId() { 49 | return isPlayer() ? ((ProxiedPlayer) sender).getUniqueId() : null; 50 | } 51 | 52 | @Override 53 | public String getName() { 54 | return sender.getName(); 55 | } 56 | 57 | public ProxiedPlayer getPlayer() { 58 | if (!isPlayer()) { 59 | throw new IllegalStateException("Sender is not a player!"); 60 | } 61 | 62 | return (ProxiedPlayer) sender; 63 | } 64 | 65 | @Override 66 | public boolean isProxy() { 67 | return true; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/provider/argument/RegisteredServerProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.provider.argument; 2 | 3 | import com.velocitypowered.api.proxy.server.RegisteredServer; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.velocity.VelocityCommandHandler; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 10 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 20/10/2024 20 | */ 21 | public class RegisteredServerProvider extends Provider { 22 | private final VelocityCommandHandler handler; 23 | 24 | public RegisteredServerProvider(VelocityCommandHandler handler) { 25 | super(ProviderType.ARGUMENT, "server"); 26 | this.handler = handler; 27 | } 28 | 29 | @Override 30 | public RegisteredServer provide(CommandExecution execution, CommandArgument argument) { 31 | Optional server = handler.getProxy().getServer(argument.getValue()); 32 | 33 | if (server.isEmpty()) { 34 | throw new ExitMessage(handler.getLocale().getInvalidServer(argument.getValue())); 35 | } 36 | 37 | return server.get(); 38 | } 39 | 40 | @Override 41 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 42 | List suggestions = new ArrayList<>(); 43 | 44 | for (RegisteredServer server : handler.getProxy().getAllServers()) { 45 | suggestions.add(server.getServerInfo().getName()); 46 | } 47 | 48 | return suggestions; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/EnumProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.utils.StringUtils; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * @author J4C0B3Y 16 | * @version CommandAPI 17 | * @since 20/10/2024 18 | */ 19 | public class EnumProvider> extends Provider { 20 | private final Class type; 21 | 22 | public EnumProvider(Class type, String name) { 23 | super(ProviderType.ARGUMENT, name); 24 | this.type = type; 25 | } 26 | 27 | public EnumProvider(Class type) { 28 | this(type, StringUtils.decapitalize(type.getSimpleName())); 29 | } 30 | 31 | @Override 32 | public T provide(CommandExecution execution, CommandArgument argument) { 33 | String name = argument.getValue(); 34 | 35 | for (T constant : type.getEnumConstants()) { 36 | if (constant.name().equalsIgnoreCase(name)) { 37 | return constant; 38 | } 39 | } 40 | 41 | throw new ExitMessage(execution.getHandler().getLocale() 42 | .getInvalidEnum(name, suggest(null, null)) 43 | ); 44 | } 45 | 46 | @Override 47 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 48 | List suggestions = new ArrayList<>(); 49 | 50 | for (T constant : type.getEnumConstants()) { 51 | suggestions.add(constant.name()); 52 | } 53 | 54 | return suggestions; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/argument/OfflinePlayerProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.argument; 2 | 3 | import net.j4c0b3y.api.command.bukkit.BukkitCommandHandler; 4 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 5 | import net.j4c0b3y.api.command.execution.CommandExecution; 6 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 9 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.OfflinePlayer; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 9/1/24 20 | */ 21 | public class OfflinePlayerProvider extends Provider { 22 | private final BukkitCommandHandler handler; 23 | 24 | public OfflinePlayerProvider(BukkitCommandHandler bukkitCommandHandler) { 25 | super(ProviderType.ARGUMENT, "player"); 26 | this.handler = bukkitCommandHandler; 27 | } 28 | 29 | @Override 30 | @SuppressWarnings("deprecation") 31 | public OfflinePlayer provide(CommandExecution execution, CommandArgument argument) { 32 | OfflinePlayer player = Bukkit.getOfflinePlayer(argument.getValue()); 33 | 34 | if (!player.hasPlayedBefore() && !player.isOnline() && player.getFirstPlayed() == 0) { 35 | throw new ExitMessage(handler.getBukkitLocale() 36 | .getInvalidOfflinePlayer(argument.getValue()) 37 | ); 38 | } 39 | 40 | return player; 41 | } 42 | 43 | @Override 44 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 45 | List suggestions = new ArrayList<>(); 46 | 47 | for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { 48 | suggestions.add(player.getName()); 49 | } 50 | 51 | return suggestions; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/BindingHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding; 2 | 3 | import net.j4c0b3y.api.command.utils.ListUtils; 4 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 5 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument.ArrayProvider; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author J4C0B3Y 15 | * @version CommandAPI 16 | * @since 27/08/2024 17 | */ 18 | public class BindingHandler { 19 | private final Map, List>> bindings = new HashMap<>(); 20 | 21 | public void put(Class type, ParameterBinding binding) { 22 | bindings.computeIfAbsent(type, key -> new ArrayList<>()).add(binding); 23 | } 24 | 25 | public Provider assign(CommandParameter parameter) { 26 | Class type = parameter.getType(); 27 | 28 | if (type.isArray()) { 29 | return new ArrayProvider<>(assign(type.getComponentType()), type.getComponentType()); 30 | } 31 | 32 | List> bindings = this.bindings.get(parameter.getType()); 33 | if (bindings == null) return null; 34 | 35 | for (ParameterBinding binding : ListUtils.reversed(bindings)) { 36 | if (binding.provides(parameter)) { 37 | return binding.getProvider(); 38 | } 39 | } 40 | 41 | return null; 42 | } 43 | 44 | @SuppressWarnings("unchecked") 45 | public Provider assign(Class type) { 46 | List> bindings = this.bindings.get(type); 47 | if (bindings == null) return null; 48 | 49 | for (ParameterBinding binding : ListUtils.reversed(bindings)) { 50 | if (binding.getClassifiers().isEmpty()) { 51 | return (Provider) binding.getProvider(); 52 | } 53 | } 54 | 55 | return null; 56 | } 57 | 58 | public void clear() { 59 | bindings.clear(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/actor/VelocityActor.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity.actor; 2 | 3 | import com.velocitypowered.api.command.CommandSource; 4 | import com.velocitypowered.api.proxy.ConsoleCommandSource; 5 | import com.velocitypowered.api.proxy.Player; 6 | import lombok.Getter; 7 | import net.j4c0b3y.api.command.actor.Actor; 8 | import net.j4c0b3y.api.command.velocity.VelocityCommandHandler; 9 | 10 | import java.util.UUID; 11 | 12 | /** 13 | * @author J4C0B3Y 14 | * @version CommandAPI 15 | * @since 30/08/2024 16 | */ 17 | @Getter 18 | public class VelocityActor extends Actor { 19 | private final CommandSource source; 20 | private final VelocityCommandHandler handler; 21 | 22 | public VelocityActor(CommandSource source, VelocityCommandHandler handler) { 23 | super(handler); 24 | this.handler = handler; 25 | this.source = source; 26 | } 27 | 28 | @Override 29 | public boolean hasPermission(String permission) { 30 | return permission == null || source.hasPermission(permission); 31 | } 32 | 33 | @Override 34 | public void sendMessage(String message) { 35 | String translated = handler.getTranslator().apply(message); 36 | source.sendMessage(handler.getVelocityTranslator().apply(translated)); 37 | } 38 | 39 | @Override 40 | public boolean isConsole() { 41 | return source instanceof ConsoleCommandSource; 42 | } 43 | 44 | @Override 45 | public boolean isPlayer() { 46 | return source instanceof Player; 47 | } 48 | 49 | @Override 50 | public UUID getUniqueId() { 51 | return isPlayer() ? ((Player) source).getUniqueId() : null; 52 | } 53 | 54 | @Override 55 | public String getName() { 56 | return isPlayer() ? ((Player) source).getUsername() : "CONSOLE"; 57 | } 58 | 59 | public Player getPlayer() { 60 | if (!isPlayer()) { 61 | throw new IllegalStateException("Source is not a player!"); 62 | } 63 | 64 | return (Player) source; 65 | } 66 | 67 | @Override 68 | public boolean isProxy() { 69 | return true; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/usage/impl/SimpleUsageHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution.usage.impl; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import net.j4c0b3y.api.command.actor.Actor; 5 | import net.j4c0b3y.api.command.execution.usage.UsageHandler; 6 | import net.j4c0b3y.api.command.wrapper.CommandHandle; 7 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * @author J4C0B3Y 15 | * @version CommandAPI 16 | * @since 1/09/2024 17 | */ 18 | @RequiredArgsConstructor 19 | public class SimpleUsageHandler implements UsageHandler { 20 | 21 | @Override 22 | public List getUsageMessage(Actor actor, CommandHandle handle, String label) { 23 | return Collections.singletonList("&7Usage: " + getFullUsage(handle, label)); 24 | } 25 | 26 | @Override 27 | public List getHelpMessage(Actor actor, CommandWrapper wrapper, String label, List arguments) { 28 | if (arguments.isEmpty() || !arguments.get(0).equals(wrapper.getHelp().command())) { 29 | return null; 30 | } 31 | 32 | List lines = new ArrayList<>(); 33 | 34 | lines.add(""); 35 | lines.add("&7&m---&7 Showing help for &f/" + label + "&7. &m---"); 36 | lines.add(""); 37 | 38 | for (CommandHandle handle : wrapper.getHandles().values()) { 39 | if (handle.isHidden() || !actor.hasPermission(handle.getPermission())) continue; 40 | 41 | String description = handle.hasDescription() ? " (" + handle.getDescription() + ")" : ""; 42 | lines.add("&7 » &f" + getFullUsage(handle, label) + "&7" + description); 43 | } 44 | 45 | lines.add(""); 46 | return lines; 47 | } 48 | 49 | private String getFullUsage(CommandHandle handle, String label) { 50 | String labelSpace = !handle.getName().isEmpty() ? " " : ""; 51 | String nameSpace = !handle.getUsage().isEmpty() ? " " : ""; 52 | 53 | return "/" + label + labelSpace + handle.getName() + nameSpace + handle.getUsage(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/provider/impl/argument/BooleanProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument; 2 | 3 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 4 | import net.j4c0b3y.api.command.execution.CommandExecution; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 7 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 8 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | /** 15 | * @author J4C0B3Y 16 | * @version CommandAPI 17 | * @since 27/08/2024 18 | */ 19 | public class BooleanProvider extends Provider { 20 | private final static List TRUE_VALUES = Arrays.asList("true", "yes"); 21 | private final static List FALSE_VALUES = Arrays.asList("false", "no"); 22 | 23 | public BooleanProvider() { 24 | super(ProviderType.ARGUMENT, "boolean"); 25 | } 26 | 27 | @Override 28 | public Boolean flagDefault(CommandExecution execution) { 29 | return false; 30 | } 31 | 32 | @Override 33 | public Boolean provide(CommandExecution execution, CommandArgument argument) { 34 | String lowered = argument.getValue().toLowerCase(); 35 | 36 | for (String value : TRUE_VALUES) { 37 | if (lowered.equals(value)) { 38 | return true; 39 | } 40 | } 41 | 42 | for (String value : FALSE_VALUES) { 43 | if (lowered.equals(value)) { 44 | return false; 45 | } 46 | } 47 | 48 | throw new ExitMessage(execution.getHandler().getLocale() 49 | .getInvalidType("boolean", argument.getValue()) 50 | ); 51 | } 52 | 53 | @Override 54 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 55 | List suggestions = new ArrayList<>(); 56 | 57 | suggestions.addAll(TRUE_VALUES); 58 | suggestions.addAll(FALSE_VALUES); 59 | 60 | return suggestions; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/BungeeCommandWrapper.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee; 2 | 3 | import net.j4c0b3y.api.command.bungee.actor.BungeeActor; 4 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 5 | import net.md_5.bungee.api.CommandSender; 6 | import net.md_5.bungee.api.ProxyServer; 7 | import net.md_5.bungee.api.plugin.Command; 8 | import net.md_5.bungee.api.plugin.TabExecutor; 9 | 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | /** 14 | * @author J4C0B3Y 15 | * @version CommandAPI 16 | * @since 30/08/2024 17 | */ 18 | public class BungeeCommandWrapper extends CommandWrapper { 19 | private final BungeeCommandHandler bungeeHandler; 20 | private final BungeeCommand command; 21 | 22 | public BungeeCommandWrapper(Object instance, String name, List aliases, BungeeCommandHandler handler) { 23 | super(instance, name, aliases, handler); 24 | this.bungeeHandler = handler; 25 | this.command = new BungeeCommand(this); 26 | } 27 | 28 | @Override 29 | public void register() { 30 | ProxyServer.getInstance().getPluginManager().registerCommand(bungeeHandler.getPlugin(), command); 31 | } 32 | 33 | public static class BungeeCommand extends Command implements TabExecutor { 34 | private final BungeeCommandWrapper wrapper; 35 | 36 | public BungeeCommand(BungeeCommandWrapper wrapper) { 37 | super(wrapper.getName(), wrapper.getPermission(), wrapper.getAliases().toArray(new String[0])); 38 | this.wrapper = wrapper; 39 | } 40 | 41 | @Override 42 | public void execute(CommandSender sender, String[] arguments) { 43 | wrapper.dispatch(new BungeeActor(sender, wrapper.getHandler()), getName(), Arrays.asList(arguments)); 44 | } 45 | 46 | @Override 47 | public Iterable onTabComplete(CommandSender sender, String[] arguments) { 48 | return wrapper.suggest(new BungeeActor(sender, wrapper.getHandler()), Arrays.asList(arguments)); 49 | } 50 | 51 | @Override 52 | public boolean hasPermission(CommandSender sender) { 53 | return !wrapper.hasPermission() || sender.hasPermission(wrapper.getPermission()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CommandAPI 2 | 3 | Powerful multi-platform annotation based command api. 4 | 5 | ###### Trusted and used by [Refine Development](https://refinedev.xyz/). 6 | 7 | ## Features 8 | 9 | - Asynchronous execution and tab completion 10 | - Annotation based command registration 11 | - Inbuilt command usage and help handler 12 | - Flexible flags system (eg, --silent) 13 | - Small and lightweight (~100kb) 14 | - Works on all major platforms 15 | - Supports spigot 1.8+ 16 | 17 | ## Support 18 | 19 | If you need any assistance using or installing my CommandAPI, 20 | feel free to contact me by either adding me on discord (@J4C0B3Y) 21 | or by creating an issue and explaining your problem or question. 22 | 23 | ## Installation 24 | 25 | Prebuilt jars can be found in [releases](https://github.com/J4C0B3Y/CommandAPI/releases). 26 | 27 | > **NOTE:**
28 | > It is recommended to relocate the library to prevent 29 | > version mismatches with other plugins that use the api. 30 | 31 | ### Maven & Gradle 32 | 33 | - Replace `PLATFORM` with your desired platform. (eg, bukkit). 34 | - Replace `VERSION` with the latest release version on GitHub. 35 | 36 | ```kts 37 | repositories { 38 | maven("https://repo.j4c0b3y.net/public/") 39 | } 40 | 41 | dependencies { 42 | implementation("net.j4c0b3y.CommandAPI:PLATFORM:VERSION") 43 | } 44 | ``` 45 | 46 | ```xml 47 | 48 | 49 | j4c0b3y-public 50 | https://repo.j4c0b3y.net/public/ 51 | 52 | 53 | 54 | 55 | 56 | net.j4c0b3y.CommandAPI 57 | PLATFORM 58 | VERSION 59 | 60 | 61 | ``` 62 | 63 | ### Building 64 | 65 | 1. Clone this repository and enter its directory. 66 | 2. Run the intellij build configuration by clicking the top right icon. 67 | 3. Alternatively you can run `gradle classes shadow delete copy install`. 68 | 4. The output jar files will be located in the `jars` directory. 69 | 70 | ## Usage 71 | 72 | Coming soon, for now message me on discord for help. 73 | 74 | ### Want more? 75 | 76 | Each and every class in my command api has detailed javadocs explaining what 77 | methods and variables are used for, and functionality of internal methods. 78 | 79 | > Made with ❤ // J4C0B3Y 2024 80 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/VelocityCommandWrapper.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity; 2 | 3 | import com.velocitypowered.api.command.CommandManager; 4 | import com.velocitypowered.api.command.CommandMeta; 5 | import com.velocitypowered.api.command.SimpleCommand; 6 | import net.j4c0b3y.api.command.utils.ListUtils; 7 | import net.j4c0b3y.api.command.velocity.actor.VelocityActor; 8 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 9 | 10 | import java.util.Arrays; 11 | import java.util.List; 12 | import java.util.concurrent.CompletableFuture; 13 | 14 | /** 15 | * @author J4C0B3Y 16 | * @version CommandAPI 17 | * @since 30/08/2024 18 | */ 19 | public class VelocityCommandWrapper extends CommandWrapper implements SimpleCommand { 20 | private final VelocityCommandHandler velocityHandler; 21 | 22 | public VelocityCommandWrapper(Object instance, String name, List aliases, VelocityCommandHandler handler) { 23 | super(instance, name, aliases, handler); 24 | this.velocityHandler = handler; 25 | } 26 | 27 | @Override 28 | public void register() { 29 | CommandManager manager = velocityHandler.getProxy().getCommandManager(); 30 | 31 | CommandMeta meta = manager.metaBuilder(getName()) 32 | .aliases(getAliases().toArray(new String[0])) 33 | .build(); 34 | 35 | manager.register(meta, this); 36 | } 37 | 38 | @Override 39 | public void execute(Invocation invocation) { 40 | dispatch(new VelocityActor(invocation.source(), velocityHandler), invocation.alias(), Arrays.asList(invocation.arguments())); 41 | } 42 | 43 | @Override 44 | public List suggest(Invocation invocation) { 45 | List arguments = ListUtils.asList(invocation.arguments()); 46 | 47 | if (arguments.isEmpty()) { 48 | arguments.add(""); 49 | } 50 | 51 | return suggest(new VelocityActor(invocation.source(), velocityHandler), arguments); 52 | } 53 | 54 | @Override 55 | public CompletableFuture> suggestAsync(Invocation invocation) { 56 | return CompletableFuture.supplyAsync(() -> suggest(invocation)); 57 | } 58 | 59 | @Override 60 | public boolean hasPermission(Invocation invocation) { 61 | return !hasPermission() || invocation.source().hasPermission(getPermission()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/provider/argument/PlayerProvider.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit.provider.argument; 2 | 3 | import net.j4c0b3y.api.command.actor.Actor; 4 | import net.j4c0b3y.api.command.bukkit.BukkitCommandHandler; 5 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 6 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 7 | import net.j4c0b3y.api.command.execution.CommandExecution; 8 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 9 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 10 | import net.j4c0b3y.api.command.wrapper.binding.provider.ProviderType; 11 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 12 | import org.bukkit.Bukkit; 13 | import org.bukkit.entity.Player; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * @author J4C0B3Y 20 | * @version CommandAPI 21 | * @since 1/09/24 22 | */ 23 | public class PlayerProvider extends Provider { 24 | private final BukkitCommandHandler handler; 25 | 26 | public PlayerProvider(BukkitCommandHandler handler) { 27 | super(ProviderType.ARGUMENT, "player"); 28 | this.handler = handler; 29 | } 30 | 31 | @Override 32 | public Player provide(CommandExecution execution, CommandArgument argument) { 33 | Player player = Bukkit.getPlayer(argument.getValue()); 34 | 35 | if (player == null || !canSee(execution.getActor(), player)) { 36 | throw new ExitMessage(handler.getBukkitLocale().getPlayerOffline(argument.getValue())); 37 | } 38 | 39 | return player; 40 | } 41 | 42 | @Override 43 | public List suggest(CommandSuggestion suggestion, CommandArgument argument) { 44 | List suggestions = new ArrayList<>(); 45 | 46 | for (Player player : Bukkit.getOnlinePlayers()) { 47 | if (canSee(suggestion.getActor(), player)) { 48 | suggestions.add(player.getName()); 49 | } 50 | } 51 | 52 | return suggestions; 53 | } 54 | 55 | private boolean canSee(Actor actor, Player target) { 56 | if (!(actor instanceof BukkitActor)) return true; 57 | BukkitActor bukkitActor = (BukkitActor) actor; 58 | 59 | if (!bukkitActor.isPlayer()) return true; 60 | Player player = (Player) bukkitActor.getSender(); 61 | 62 | return player.canSee(target); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/j4c0b3y/api/command/bungee/BungeeCommandHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bungee; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import net.j4c0b3y.api.command.CommandHandler; 6 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Sender; 7 | import net.j4c0b3y.api.command.bungee.actor.BungeeActor; 8 | import net.j4c0b3y.api.command.bungee.annotation.ConsoleSender; 9 | import net.j4c0b3y.api.command.bungee.locale.BungeeCommandLocale; 10 | import net.j4c0b3y.api.command.bungee.provider.actor.BungeeActorProvider; 11 | import net.j4c0b3y.api.command.bungee.provider.actor.CommandSenderProvider; 12 | import net.j4c0b3y.api.command.bungee.provider.actor.ConsoleCommandSenderProvider; 13 | import net.j4c0b3y.api.command.bungee.provider.actor.ProxiedPlayerSenderProvider; 14 | import net.j4c0b3y.api.command.bungee.provider.argument.ServerInfoProvider; 15 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 16 | import net.md_5.bungee.api.ChatColor; 17 | import net.md_5.bungee.api.CommandSender; 18 | import net.md_5.bungee.api.config.ServerInfo; 19 | import net.md_5.bungee.api.connection.ProxiedPlayer; 20 | import net.md_5.bungee.api.plugin.Plugin; 21 | 22 | import java.util.List; 23 | import java.util.logging.Logger; 24 | 25 | /** 26 | * @author J4C0B3Y 27 | * @version CommandAPI 28 | * @since 27/08/2024 29 | */ 30 | @Getter @Setter 31 | public class BungeeCommandHandler extends CommandHandler { 32 | private final Plugin plugin; 33 | 34 | private BungeeCommandLocale bungeeLocale = new BungeeCommandLocale(); 35 | 36 | public BungeeCommandHandler(Plugin plugin) { 37 | this.plugin = plugin; 38 | 39 | setTranslator(text -> ChatColor.translateAlternateColorCodes('&', text)); 40 | bindDefaults(); 41 | } 42 | 43 | @Override 44 | public CommandWrapper wrap(Object wrapper, String name, List aliases) { 45 | return new BungeeCommandWrapper(wrapper, name, aliases, this); 46 | } 47 | 48 | @Override 49 | public Logger getLogger() { 50 | return plugin.getLogger(); 51 | } 52 | 53 | @Override 54 | public void bindDefaults() { 55 | super.bindDefaults(); 56 | 57 | BungeeActorProvider actorProvider = new BungeeActorProvider(this); 58 | 59 | bind(BungeeActor.class).annotated(Sender.class).to(actorProvider); 60 | bind(ProxiedPlayer.class).annotated(Sender.class).to(new ProxiedPlayerSenderProvider(actorProvider)); 61 | bind(CommandSender.class).annotated(Sender.class).to(new CommandSenderProvider(actorProvider)); 62 | bind(CommandSender.class).annotated(ConsoleSender.class).to(new ConsoleCommandSenderProvider(actorProvider)); 63 | 64 | bind(ServerInfo.class).to(new ServerInfoProvider(this)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/j4c0b3y/api/command/velocity/VelocityCommandHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.velocity; 2 | 3 | import com.velocitypowered.api.command.CommandSource; 4 | import com.velocitypowered.api.proxy.ConsoleCommandSource; 5 | import com.velocitypowered.api.proxy.Player; 6 | import com.velocitypowered.api.proxy.ProxyServer; 7 | import com.velocitypowered.api.proxy.server.RegisteredServer; 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | import net.j4c0b3y.api.command.CommandHandler; 11 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Sender; 12 | import net.j4c0b3y.api.command.velocity.actor.VelocityActor; 13 | import net.j4c0b3y.api.command.velocity.locale.VelocityCommandLocale; 14 | import net.j4c0b3y.api.command.velocity.provider.actor.CommandSourceProvider; 15 | import net.j4c0b3y.api.command.velocity.provider.actor.ConsoleCommandSourceProvider; 16 | import net.j4c0b3y.api.command.velocity.provider.actor.PlayerSenderProvider; 17 | import net.j4c0b3y.api.command.velocity.provider.actor.VelocityActorProvider; 18 | import net.j4c0b3y.api.command.velocity.provider.argument.PlayerProvider; 19 | import net.j4c0b3y.api.command.velocity.provider.argument.RegisteredServerProvider; 20 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 21 | import net.kyori.adventure.text.Component; 22 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 23 | 24 | import java.util.List; 25 | import java.util.function.Function; 26 | import java.util.logging.Logger; 27 | 28 | /** 29 | * @author J4C0B3Y 30 | * @version CommandAPI 31 | * @since 27/08/2024 32 | */ 33 | @Getter @Setter 34 | public class VelocityCommandHandler extends CommandHandler { 35 | private final Object plugin; 36 | private final ProxyServer proxy; 37 | private final Logger logger; 38 | 39 | private VelocityCommandLocale velocityLocale = new VelocityCommandLocale(); 40 | private Function velocityTranslator = LegacyComponentSerializer.legacyAmpersand()::deserialize; 41 | 42 | public VelocityCommandHandler(Object plugin, ProxyServer proxy, Logger logger) { 43 | this.plugin = plugin; 44 | this.proxy = proxy; 45 | this.logger = logger; 46 | 47 | bindDefaults(); 48 | } 49 | 50 | @Override 51 | public CommandWrapper wrap(Object wrapper, String name, List aliases) { 52 | return new VelocityCommandWrapper(wrapper, name, aliases, this); 53 | } 54 | 55 | @Override 56 | public void bindDefaults() { 57 | super.bindDefaults(); 58 | 59 | VelocityActorProvider actorProvider = new VelocityActorProvider(this); 60 | 61 | bind(VelocityActor.class).annotated(Sender.class).to(actorProvider); 62 | bind(Player.class).annotated(Sender.class).to(new PlayerSenderProvider(actorProvider)); 63 | bind(CommandSource.class).annotated(Sender.class).to(new CommandSourceProvider(actorProvider)); 64 | bind(ConsoleCommandSource.class).annotated(Sender.class).to(new ConsoleCommandSourceProvider(actorProvider)); 65 | 66 | bind(Player.class).to(new PlayerProvider(this)); 67 | 68 | bind(RegisteredServer.class).to(new RegisteredServerProvider(this)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/BukkitCommandWrapper.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 5 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 6 | import net.j4c0b3y.api.command.wrapper.CommandHandle; 7 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 8 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 9 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.command.*; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | /** 17 | * @author J4C0B3Y 18 | * @version CommandAPI 19 | * @since 30/08/2024 20 | */ 21 | @Getter 22 | public class BukkitCommandWrapper extends CommandWrapper implements CommandExecutor, TabCompleter { 23 | private final BukkitCommandHandler bukkitHandler; 24 | private final PluginCommand command; 25 | 26 | public BukkitCommandWrapper(Object instance, String name, List aliases, BukkitCommandHandler handler) { 27 | super(instance, name, aliases, handler); 28 | this.bukkitHandler = handler; 29 | this.command = handler.getRegistry().getPluginCommand(this); 30 | 31 | this.command.setExecutor(this); 32 | this.command.setTabCompleter(this); 33 | this.command.setPermission(getPermission()); 34 | this.command.setDescription(getDescription()); 35 | this.command.setAliases(getAliases()); 36 | 37 | registerPermissions(); 38 | } 39 | 40 | @Override 41 | public void setPermission(String permission) { 42 | this.command.setPermission(permission); 43 | super.setPermission(permission); 44 | } 45 | 46 | @Override 47 | public void register() { 48 | bukkitHandler.getRegistry().register(this); 49 | } 50 | 51 | @Override 52 | public boolean onCommand(CommandSender sender, Command command, String label, String[] arguments) { 53 | dispatch(new BukkitActor(sender, getHandler()), label, Arrays.asList(arguments)); 54 | return true; 55 | } 56 | 57 | @Override 58 | public List onTabComplete(CommandSender sender, Command command, String label, String[] arguments) { 59 | return suggest(new BukkitActor(sender, getHandler()), Arrays.asList(arguments)); 60 | } 61 | 62 | @Override 63 | protected List suggestValue(Provider provider, CommandSuggestion suggestion, CommandArgument argument) { 64 | if (provider.isAsync() || Bukkit.isPrimaryThread()) { 65 | return super.suggestValue(provider, suggestion, argument); 66 | } 67 | 68 | try { 69 | return bukkitHandler.callSync(() -> 70 | super.suggestValue(provider, suggestion, argument) 71 | ).get(); 72 | } catch (Exception exception) { 73 | throw new RuntimeException("Failed to execute synchronous suggestion!", exception); 74 | } 75 | } 76 | 77 | private void registerPermissions() { 78 | BukkitCommandRegistry registry = bukkitHandler.getRegistry(); 79 | registry.registerPermission(getPermission()); 80 | 81 | for (CommandHandle handle : getHandles().values()) { 82 | registry.registerPermission(handle.getPermission()); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/locale/CommandLocale.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution.locale; 2 | 3 | import net.j4c0b3y.api.command.annotation.command.Help; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | /** 11 | * @author J4C0B3Y 12 | * @version CommandAPI 13 | * @since 1/09/2024 14 | */ 15 | public class CommandLocale { 16 | 17 | public List getNoPermission() { 18 | return Collections.singletonList( 19 | "&cYou do not have permission to execute this command!" 20 | ); 21 | } 22 | 23 | public List getExceptionOccurred() { 24 | return Arrays.asList( 25 | "&cAn exception occurred whilst executing this command!", 26 | "&7Please report this to a server staff member." 27 | ); 28 | } 29 | 30 | public List getInvalidSubcommand(String label, Help help) { 31 | List lines = new ArrayList<>(); 32 | 33 | lines.add("&cThat subcommand could not be found!"); 34 | 35 | if (help != null) { 36 | lines.add("&7Run '/" + label + " " + help.command() + "' for a list of commands."); 37 | } 38 | 39 | return lines; 40 | } 41 | 42 | public String getMissingArgument(String parameter) { 43 | return "&cMissing argument for '" + parameter + "'."; 44 | } 45 | 46 | public String getFlagNameHyphen(String argument) { 47 | return "&cFlag '" + argument + "' cannot start with '-'."; 48 | } 49 | 50 | public String getFlagNameTooShort(String argument) { 51 | return "&cFlag '" + argument + "' must be more then one character."; 52 | } 53 | 54 | public String getFlagDoubleHyphen(String argument) { 55 | return "&cFlag '" + argument + "' must start with '--'."; 56 | } 57 | 58 | public String getFlagValueRequired(String argument) { 59 | return "&cFlag '" + argument + "' requires a value."; 60 | } 61 | 62 | public String getFlagSpecified(String argument) { 63 | return "&cFlag '" + argument + "' already specified."; 64 | } 65 | 66 | public String getUnknownFlag(String argument) { 67 | return "&cUnknown flag '" + argument + "'."; 68 | } 69 | 70 | public String getConsoleOnly() { 71 | return "&cThis command can only be run by console."; 72 | } 73 | 74 | public String getProxyOnly() { 75 | return "&cThis command can only be run on a proxy."; 76 | } 77 | 78 | public String getPlayerOnly() { 79 | return "&cThis command can only be run by players."; 80 | } 81 | 82 | public String getInvalidType(String expected, String argument) { 83 | return "&cType '" + expected + "' expected, '" + argument + "' found."; 84 | } 85 | 86 | public String getBelowMinimum(String minimum, String argument) { 87 | return "&cMinimum '" + minimum + "', found '" + argument + "'"; 88 | } 89 | 90 | public String getAboveMaximum(String maximum, String argument) { 91 | return "&cMaximum '" + maximum + "', found '" + argument + "'"; 92 | } 93 | 94 | public String getInvalidServer(String argument) { 95 | return "&cA server with name '" + argument + "' doesn't exist."; 96 | } 97 | 98 | public String getInvalidEnum(String argument, List valid) { 99 | return "&cNo value found for '" + argument + "', " + 100 | "valid: " + String.join(", ", valid) + "."; 101 | } 102 | 103 | public String getMapEntryNotFound(String argument, String keyName, String valueName) { 104 | return "&cA" + valueName + " with " + keyName + " '" + argument + "' was not found!"; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/BukkitCommandRegistry.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.bukkit.utils.ClassUtils; 5 | import net.j4c0b3y.api.command.exception.registration.RegistrationException; 6 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.command.Command; 9 | import org.bukkit.command.PluginCommand; 10 | import org.bukkit.command.SimpleCommandMap; 11 | import org.bukkit.permissions.Permission; 12 | import org.bukkit.permissions.PermissionDefault; 13 | import org.bukkit.plugin.Plugin; 14 | import org.bukkit.plugin.PluginManager; 15 | 16 | import java.lang.reflect.Constructor; 17 | import java.util.*; 18 | 19 | /** 20 | * @author J4C0B3Y 21 | * @version CommandAPI 22 | * @since 31/08/2024 23 | */ 24 | @Getter 25 | public class BukkitCommandRegistry { 26 | private final BukkitCommandHandler handler; 27 | 28 | private final SimpleCommandMap commandMap; 29 | private final Map knownCommands; 30 | private final Constructor pluginCommand; 31 | 32 | private final Map wrappers = new HashMap<>(); 33 | 34 | @SuppressWarnings("unchecked") 35 | public BukkitCommandRegistry(BukkitCommandHandler handler) { 36 | this.handler = handler; 37 | 38 | try { 39 | this.commandMap = (SimpleCommandMap) ClassUtils.getField(Bukkit.getServer(), "commandMap"); 40 | this.knownCommands = (Map) ClassUtils.getField(this.commandMap, SimpleCommandMap.class, "knownCommands"); 41 | } catch (Exception exception) { 42 | throw new IllegalStateException("Failed to access command map!", exception); 43 | } 44 | 45 | try { 46 | this.pluginCommand = ClassUtils.getConstructor(PluginCommand.class, String.class, Plugin.class); 47 | } catch (Exception exception) { 48 | throw new IllegalStateException("Failed to access command constructor!", exception); 49 | } 50 | } 51 | 52 | public void register(BukkitCommandWrapper wrapper) { 53 | try { 54 | List labels = new ArrayList<>(); 55 | labels.add(wrapper.getName()); 56 | labels.addAll(wrapper.getAliases()); 57 | 58 | for (String label : labels) { 59 | Command command = knownCommands.get(label); 60 | if (command == null) continue; 61 | 62 | if (command instanceof PluginCommand) { 63 | Plugin plugin = ((PluginCommand) command).getPlugin(); 64 | if (plugin == handler.getPlugin()) continue; 65 | 66 | if (handler.isDebug()) { 67 | String origin = plugin.getDescription().getName(); 68 | handler.getLogger().warning("Overriding command '" + label + "' from '" + origin + "'."); 69 | } 70 | } 71 | 72 | knownCommands.remove(label); 73 | } 74 | 75 | commandMap.register(handler.getPlugin().getName(), wrapper.getCommand()); 76 | wrappers.put(wrapper.getCommand(), wrapper); 77 | } catch (Exception exception) { 78 | throw new RegistrationException("Failed to register wrapper in command map!", exception); 79 | } 80 | } 81 | 82 | public void registerPermission(String permission, String description) { 83 | if (permission == null) return; 84 | 85 | PluginManager pluginManager = handler.getPlugin().getServer().getPluginManager(); 86 | if (pluginManager.getPermission(permission) != null) return; 87 | 88 | pluginManager.addPermission(new Permission(permission, description, PermissionDefault.OP)); 89 | } 90 | 91 | public void registerPermission(String permission) { 92 | registerPermission(permission, "A permission registered by " + handler.getPlugin().getName()); 93 | } 94 | 95 | public PluginCommand getPluginCommand(BukkitCommandWrapper wrapper) { 96 | try { 97 | return pluginCommand.newInstance(wrapper.getName(), handler.getPlugin()); 98 | } catch (Exception exception) { 99 | throw new RegistrationException("Failed to instantiate plugin command!", exception); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/binding/BindingBuilder.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper.binding; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import net.j4c0b3y.api.command.CommandHandler; 5 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Classifier; 6 | import net.j4c0b3y.api.command.annotation.parameter.modifier.Modifier; 7 | import net.j4c0b3y.api.command.exception.binding.InvalidBindingException; 8 | import net.j4c0b3y.api.command.utils.ClassUtils; 9 | import net.j4c0b3y.api.command.wrapper.binding.condition.ExecuteCondition; 10 | import net.j4c0b3y.api.command.wrapper.binding.modifier.ArgumentModifier; 11 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 12 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.context.InstanceProvider; 13 | 14 | import java.lang.annotation.Annotation; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.function.Consumer; 18 | 19 | /** 20 | * @author J4C0B3Y 21 | * @version CommandAPI 22 | * @since 27/08/2024 23 | */ 24 | @RequiredArgsConstructor 25 | public class BindingBuilder { 26 | private final Class type; 27 | private final CommandHandler handler; 28 | 29 | private final List> classifiers = new ArrayList<>(); 30 | private Class modifier; 31 | 32 | public BindingBuilder annotated(Class annotation) { 33 | boolean classifier = annotation.isAnnotationPresent(Classifier.class); 34 | boolean modifier = annotation.isAnnotationPresent(Modifier.class); 35 | 36 | if (classifier && modifier) { 37 | throw new InvalidBindingException("Annotation '" + annotation.getSimpleName() + "' cannot be @Classifier and @Modifier."); 38 | } 39 | 40 | if (classifier) { 41 | if (this.modifier != null) { 42 | throw new InvalidBindingException("Cannot bind both @Classifier and @Modifier."); 43 | } 44 | 45 | if (classifiers.contains(annotation)) { 46 | throw new InvalidBindingException("Cannot bind @Classifier '" + annotation.getSimpleName() + "' multiple times."); 47 | } 48 | 49 | classifiers.add(annotation); 50 | return this; 51 | } 52 | 53 | if (modifier) { 54 | if (!classifiers.isEmpty()) { 55 | throw new InvalidBindingException("Cannot bind both @Modifier and @Classifier."); 56 | } 57 | 58 | if (this.modifier != null) { 59 | throw new InvalidBindingException("Cannot bind multiple @Modifier at once."); 60 | } 61 | 62 | this.modifier = annotation; 63 | return this; 64 | } 65 | 66 | throw new InvalidBindingException("Annotation '" + annotation.getSimpleName() + "' must have @Classifier or @Modifier."); 67 | } 68 | 69 | public void to(Provider provider) { 70 | if (modifier != null) { 71 | throw new InvalidBindingException("@Modifier cannot be bound to a provider."); 72 | } 73 | 74 | to(type -> handler.getBindingHandler().put(type, new ParameterBinding<>(type, provider, classifiers))); 75 | } 76 | 77 | public void to(T instance) { 78 | to(new InstanceProvider<>(instance)); 79 | } 80 | 81 | public void to(ArgumentModifier modifier) { 82 | if (this.modifier == null) { 83 | throw new InvalidBindingException("No @Modifier was provided."); 84 | } 85 | 86 | to(type -> handler.getModifierHandler().put(type, this.modifier, modifier)); 87 | } 88 | 89 | public void to(ExecuteCondition condition) { 90 | if (modifier != null) { 91 | throw new InvalidBindingException("Cannot bind @Modifier to a condition."); 92 | } 93 | 94 | if (!classifiers.isEmpty()) { 95 | throw new InvalidBindingException("Cannot bind @Classifier to a condition."); 96 | } 97 | 98 | handler.getConditionHandler().put(type, condition); 99 | } 100 | 101 | private void to(Consumer> binder) { 102 | // If the type is a primitive, bind its wrapper class. 103 | if (type.isPrimitive()) { 104 | binder.accept(ClassUtils.wrap(type)); 105 | } 106 | 107 | binder.accept(type); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/CommandParameter.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.annotation.command.Requires; 5 | import net.j4c0b3y.api.command.annotation.parameter.*; 6 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Classifier; 7 | import net.j4c0b3y.api.command.annotation.parameter.modifier.Modifier; 8 | import net.j4c0b3y.api.command.exception.registration.InvalidParameterException; 9 | import net.j4c0b3y.api.command.exception.registration.MissingProviderException; 10 | import net.j4c0b3y.api.command.utils.AnnotationUtils; 11 | import net.j4c0b3y.api.command.utils.ListUtils; 12 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 13 | 14 | import java.lang.annotation.Annotation; 15 | import java.lang.reflect.Parameter; 16 | import java.util.Arrays; 17 | import java.util.Collections; 18 | import java.util.List; 19 | 20 | /** 21 | * @author J4C0B3Y 22 | * @version CommandAPI 23 | * @since 27/08/2024 24 | */ 25 | @Getter 26 | public class CommandParameter { 27 | private final Class type; 28 | 29 | private final List annotations; 30 | private final List classifiers; 31 | private final List modifiers; 32 | 33 | private final String name; 34 | private final String defaultValue; 35 | private final boolean optional; 36 | 37 | private final List options; 38 | private final List flagNames; 39 | 40 | private final Provider provider; 41 | private final String permission; 42 | 43 | private final boolean last; 44 | private final boolean array; 45 | private final boolean combine; 46 | 47 | public CommandParameter(CommandHandle handle, Parameter parameter) { 48 | this.type = parameter.getType(); 49 | 50 | this.annotations = Arrays.asList(parameter.getAnnotations()); 51 | this.classifiers = AnnotationUtils.getSpecial(annotations, Classifier.class); 52 | this.modifiers = AnnotationUtils.getSpecial(annotations, Modifier.class); 53 | 54 | this.provider = handle.getWrapper().getHandler().getBindingHandler().assign(this); 55 | 56 | if (this.provider == null) { 57 | throw new MissingProviderException("Parameter '" + parameter.getName() + "' has no valid providers bound for '" + type.getSimpleName() + "'."); 58 | } 59 | 60 | this.permission = AnnotationUtils.getValue(parameter, Requires.class, Requires::value, null); 61 | 62 | String name = AnnotationUtils.getValue(parameter, Named.class, Named::value, provider.getDefaultName()); 63 | this.name = name != null ? name : parameter.getName(); 64 | 65 | this.defaultValue = AnnotationUtils.getValue(parameter, Default.class, Default::value, null); 66 | this.optional = defaultValue != null || parameter.isAnnotationPresent(Optional.class); 67 | 68 | if (hasPermission() && !optional) { 69 | throw new InvalidParameterException("Parameter '" + parameter.getName() + "' has @Requires but is not optional."); 70 | } 71 | 72 | this.options = AnnotationUtils.getValue(parameter, Option.class, option -> ListUtils.map(option.value(), String::toLowerCase), Collections.emptyList()); 73 | this.flagNames = AnnotationUtils.getValue(parameter, Flag.class, flag -> ListUtils.asList(flag.value()), null); 74 | 75 | // Use the parameter name if no flag names are specified. 76 | if (flagNames != null && flagNames.isEmpty()) { 77 | flagNames.add(name); 78 | } 79 | 80 | this.array = type.isArray(); 81 | this.last = !AnnotationUtils.getSpecial(annotations, Last.class).isEmpty() || type.isArray(); 82 | this.combine = parameter.isAnnotationPresent(Text.class) || this.array; 83 | 84 | if (isCombine() && isFlag()) { 85 | throw new InvalidParameterException("Parameter '" + parameter.getName() + "' cannot be a flag."); 86 | } 87 | } 88 | 89 | public boolean isBoolean() { 90 | return type == boolean.class || type == Boolean.class; 91 | } 92 | 93 | public boolean isFlag() { 94 | return flagNames != null && !flagNames.isEmpty(); 95 | } 96 | 97 | public boolean hasPermission() { 98 | return permission != null; 99 | } 100 | 101 | public boolean hasOption(String option) { 102 | return options.contains(option.toLowerCase()); 103 | } 104 | 105 | @SuppressWarnings("unchecked") 106 | public T getAnnotation(Class type) { 107 | for (Annotation annotation : annotations) { 108 | if (annotation.annotationType().equals(type)) { 109 | return (T) annotation; 110 | } 111 | } 112 | 113 | return null; 114 | } 115 | 116 | public boolean hasAnnotation(Class type) { 117 | return getAnnotation(type) != null; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/j4c0b3y/api/command/bukkit/BukkitCommandHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.bukkit; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import net.j4c0b3y.api.command.CommandHandler; 6 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Sender; 7 | import net.j4c0b3y.api.command.bukkit.actor.BukkitActor; 8 | import net.j4c0b3y.api.command.bukkit.listener.AsyncTabListener; 9 | import net.j4c0b3y.api.command.bukkit.locale.BukkitCommandLocale; 10 | import net.j4c0b3y.api.command.bukkit.provider.actor.BukkitActorProvider; 11 | import net.j4c0b3y.api.command.bukkit.provider.actor.CommandSenderProvider; 12 | import net.j4c0b3y.api.command.bukkit.provider.actor.ConsoleCommandSenderProvider; 13 | import net.j4c0b3y.api.command.bukkit.provider.actor.PlayerSenderProvider; 14 | import net.j4c0b3y.api.command.bukkit.provider.argument.EnchantmentProvider; 15 | import net.j4c0b3y.api.command.bukkit.provider.argument.OfflinePlayerProvider; 16 | import net.j4c0b3y.api.command.bukkit.provider.argument.PlayerProvider; 17 | import net.j4c0b3y.api.command.bukkit.provider.argument.WorldProvider; 18 | import net.j4c0b3y.api.command.bukkit.utils.ClassUtils; 19 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 20 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument.EnumProvider; 21 | import org.bukkit.*; 22 | import org.bukkit.block.Biome; 23 | import org.bukkit.block.BlockFace; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.command.ConsoleCommandSender; 26 | import org.bukkit.enchantments.Enchantment; 27 | import org.bukkit.entity.EntityType; 28 | import org.bukkit.entity.Player; 29 | import org.bukkit.plugin.Plugin; 30 | import org.bukkit.potion.PotionType; 31 | 32 | import java.util.List; 33 | import java.util.concurrent.Callable; 34 | import java.util.concurrent.CompletableFuture; 35 | import java.util.concurrent.Future; 36 | import java.util.logging.Logger; 37 | 38 | /** 39 | * @author J4C0B3Y 40 | * @version CommandAPI 41 | * @since 27/08/2024 42 | */ 43 | @Getter @Setter 44 | public class BukkitCommandHandler extends CommandHandler { 45 | private final Plugin plugin; 46 | private final BukkitCommandRegistry registry; 47 | 48 | private BukkitCommandLocale bukkitLocale = new BukkitCommandLocale(); 49 | 50 | public BukkitCommandHandler(Plugin plugin) { 51 | this.plugin = plugin; 52 | this.registry = new BukkitCommandRegistry(this); 53 | 54 | setTranslator(text -> ChatColor.translateAlternateColorCodes('&', text)); 55 | 56 | ClassUtils.ifPresent("com.destroystokyo.paper.event.server.AsyncTabCompleteEvent", () -> { 57 | plugin.getServer().getPluginManager().registerEvents(new AsyncTabListener(this), plugin); 58 | plugin.getLogger().info("Enabled async tab completion support."); 59 | }); 60 | 61 | bindDefaults(); 62 | } 63 | 64 | @Override 65 | public CommandWrapper wrap(Object wrapper, String name, List aliases) { 66 | return new BukkitCommandWrapper(wrapper, name, aliases, this); 67 | } 68 | 69 | @Override 70 | public Logger getLogger() { 71 | return plugin.getLogger(); 72 | } 73 | 74 | @Override 75 | public void runTask(Runnable task, boolean async) { 76 | if (async == !Bukkit.isPrimaryThread()) { 77 | task.run(); 78 | return; 79 | } 80 | 81 | if (async) { 82 | CompletableFuture.runAsync(task); 83 | return; 84 | } 85 | 86 | Bukkit.getScheduler().runTask(plugin, task); 87 | } 88 | 89 | protected Future callSync(Callable task) { 90 | return Bukkit.getScheduler().callSyncMethod(plugin, task); 91 | } 92 | 93 | @Override 94 | public void bindDefaults() { 95 | super.bindDefaults(); 96 | 97 | BukkitActorProvider actorProvider = new BukkitActorProvider(this); 98 | 99 | bind(BukkitActor.class).annotated(Sender.class).to(actorProvider); 100 | bind(Player.class).annotated(Sender.class).to(new PlayerSenderProvider(actorProvider)); 101 | bind(CommandSender.class).annotated(Sender.class).to(new CommandSenderProvider(actorProvider)); 102 | bind(ConsoleCommandSender.class).annotated(Sender.class).to(new ConsoleCommandSenderProvider(actorProvider)); 103 | 104 | bind(Player.class).to(new PlayerProvider(this)); 105 | bind(OfflinePlayer.class).to(new OfflinePlayerProvider(this)); 106 | 107 | bind(World.class).to(new WorldProvider(this)); 108 | bind(Enchantment.class).to(new EnchantmentProvider()); 109 | 110 | bind(EntityEffect.class).to(new EnumProvider<>(EntityEffect.class, "effect")); 111 | bind(WeatherType.class).to(new EnumProvider<>(WeatherType.class, "weather")); 112 | bind(EntityType.class).to(new EnumProvider<>(EntityType.class, "entity")); 113 | bind(PotionType.class).to(new EnumProvider<>(PotionType.class, "potion")); 114 | bind(TreeSpecies.class).to(new EnumProvider<>(TreeSpecies.class, "tree")); 115 | bind(GameMode.class).to(new EnumProvider<>(GameMode.class, "gamemode")); 116 | bind(ChatColor.class).to(new EnumProvider<>(ChatColor.class, "color")); 117 | bind(BlockFace.class).to(new EnumProvider<>(BlockFace.class, "face")); 118 | bind(DyeColor.class).to(new EnumProvider<>(DyeColor.class, "color")); 119 | bind(TreeType.class).to(new EnumProvider<>(TreeType.class, "tree")); 120 | bind(Art.class).to(new EnumProvider<>(Art.class, "painting")); 121 | 122 | bind(World.Environment.class).to(new EnumProvider<>(World.Environment.class)); 123 | bind(Instrument.class).to(new EnumProvider<>(Instrument.class)); 124 | bind(Difficulty.class).to(new EnumProvider<>(Difficulty.class)); 125 | bind(WorldType.class).to(new EnumProvider<>(WorldType.class)); 126 | bind(SkullType.class).to(new EnumProvider<>(SkullType.class)); 127 | bind(Material.class).to(new EnumProvider<>(Material.class)); 128 | bind(Effect.class).to(new EnumProvider<>(Effect.class)); 129 | bind(Sound.class).to(new EnumProvider<>(Sound.class)); 130 | bind(Biome.class).to(new EnumProvider<>(Biome.class)); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import net.j4c0b3y.api.command.actor.Actor; 6 | import net.j4c0b3y.api.command.actor.ConsoleActor; 7 | import net.j4c0b3y.api.command.actor.PlayerActor; 8 | import net.j4c0b3y.api.command.actor.ProxyActor; 9 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Label; 10 | import net.j4c0b3y.api.command.annotation.parameter.classifier.Sender; 11 | import net.j4c0b3y.api.command.annotation.parameter.modifier.Length; 12 | import net.j4c0b3y.api.command.annotation.parameter.modifier.Range; 13 | import net.j4c0b3y.api.command.annotation.registration.Ignore; 14 | import net.j4c0b3y.api.command.annotation.registration.Register; 15 | import net.j4c0b3y.api.command.exception.registration.RegistrationException; 16 | import net.j4c0b3y.api.command.execution.CommandExecution; 17 | import net.j4c0b3y.api.command.execution.argument.flag.FlagAction; 18 | import net.j4c0b3y.api.command.execution.locale.CommandLocale; 19 | import net.j4c0b3y.api.command.execution.usage.UsageHandler; 20 | import net.j4c0b3y.api.command.execution.usage.impl.SimpleUsageHandler; 21 | import net.j4c0b3y.api.command.wrapper.CommandHandle; 22 | import net.j4c0b3y.api.command.wrapper.CommandWrapper; 23 | import net.j4c0b3y.api.command.wrapper.binding.BindingBuilder; 24 | import net.j4c0b3y.api.command.wrapper.binding.BindingHandler; 25 | import net.j4c0b3y.api.command.wrapper.binding.condition.ConditionHandler; 26 | import net.j4c0b3y.api.command.wrapper.binding.modifier.ModifierHandler; 27 | import net.j4c0b3y.api.command.wrapper.binding.modifier.impl.LengthModifier; 28 | import net.j4c0b3y.api.command.wrapper.binding.modifier.impl.RangeModifier; 29 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor.ActorProvider; 30 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor.ConsoleActorProvider; 31 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor.PlayerActorProvider; 32 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.actor.ProxyActorProvider; 33 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.argument.*; 34 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.context.CommandExecutionProvider; 35 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.context.CommandHandleProvider; 36 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.context.CommandWrapperProvider; 37 | import net.j4c0b3y.api.command.wrapper.binding.provider.impl.context.LabelProvider; 38 | 39 | import java.util.Arrays; 40 | import java.util.List; 41 | import java.util.UUID; 42 | import java.util.concurrent.CompletableFuture; 43 | import java.util.function.Function; 44 | import java.util.logging.Logger; 45 | 46 | /** 47 | * @author J4C0B3Y 48 | * @version CommandAPI 49 | * @since 26/08/2024 50 | */ 51 | @Getter @Setter 52 | public abstract class CommandHandler { 53 | private final BindingHandler bindingHandler = new BindingHandler(); 54 | private final ModifierHandler modifierHandler = new ModifierHandler(); 55 | private final ConditionHandler conditionHandler = new ConditionHandler(); 56 | 57 | private UsageHandler usageHandler = new SimpleUsageHandler(); 58 | private CommandLocale locale = new CommandLocale(); 59 | 60 | private FlagAction unknownFlagAction = FlagAction.ARGUMENT; 61 | private Function translator = content -> content; 62 | 63 | private boolean debug; 64 | 65 | public abstract CommandWrapper wrap(Object wrapper, String name, List aliases); 66 | public abstract Logger getLogger(); 67 | 68 | public BindingBuilder bind(Class type) { 69 | return new BindingBuilder<>(type, this); 70 | } 71 | 72 | public void register(Object wrapper, String name, String permission, String... aliases) { 73 | if (wrapper.getClass().isAnnotationPresent(Ignore.class)) return; 74 | 75 | try { 76 | CommandWrapper wrapped = wrap(wrapper, name, Arrays.asList(aliases)); 77 | 78 | if (permission != null) { 79 | wrapped.setPermission(permission); 80 | } 81 | 82 | wrapped.register(); 83 | } catch (Exception exception) { 84 | throw new RegistrationException("Failed to register command '" + name + "'", exception); 85 | } 86 | } 87 | 88 | public void register(Object wrapper, String name) { 89 | register(wrapper, name, null); 90 | } 91 | 92 | public void register(Object wrapper) { 93 | Class clazz = wrapper.getClass(); 94 | Register annotation = clazz.getAnnotation(Register.class); 95 | 96 | if (annotation == null) { 97 | throw new RegistrationException("Wrapper '" + clazz.getSimpleName() + "' must be annotated @Register."); 98 | } 99 | 100 | register(wrapper, annotation.name(), null, annotation.aliases()); 101 | } 102 | 103 | public void register(Class clazz) { 104 | try { 105 | register(clazz.getConstructor().newInstance()); 106 | } catch (ReflectiveOperationException exception) { 107 | throw new RegistrationException("Failed to instantiate wrapper!", exception); 108 | } 109 | } 110 | 111 | public void runTask(Runnable task, boolean async) { 112 | if (!async) { 113 | task.run(); 114 | return; 115 | } 116 | 117 | CompletableFuture.runAsync(task); 118 | } 119 | 120 | public void bindDefaults() { 121 | bind(String.class).to(new StringProvider()); 122 | bind(char.class).to(new CharacterProvider()); 123 | bind(boolean.class).to(new BooleanProvider()); 124 | bind(UUID.class).to(new UUIDProvider()); 125 | 126 | bind(int.class).to(new NumberProvider<>(Integer::parseInt, "integer", 0)); 127 | bind(double.class).to(new NumberProvider<>(Double::parseDouble, "double", 0D)); 128 | bind(float.class).to(new NumberProvider<>(Float::parseFloat, "float", 0f)); 129 | bind(long.class).to(new NumberProvider<>(Long::parseLong, "long", 0L)); 130 | bind(short.class).to(new NumberProvider<>(Short::parseShort, "short", (short) 0)); 131 | 132 | bind(String.class).annotated(Length.class).to(new LengthModifier()); 133 | bind(int.class).annotated(Range.class).to(new RangeModifier<>()); 134 | bind(double.class).annotated(Range.class).to(new RangeModifier<>()); 135 | bind(float.class).annotated(Range.class).to(new RangeModifier<>()); 136 | bind(long.class).annotated(Range.class).to(new RangeModifier<>()); 137 | 138 | bind(String.class).annotated(Label.class).to(new LabelProvider()); 139 | bind(Actor.class).annotated(Sender.class).to(new ActorProvider()); 140 | bind(ProxyActor.class).annotated(Sender.class).to(new ProxyActorProvider()); 141 | bind(PlayerActor.class).annotated(Sender.class).to(new PlayerActorProvider()); 142 | bind(ConsoleActor.class).annotated(Sender.class).to(new ConsoleActorProvider()); 143 | 144 | bind(CommandExecution.class).to(new CommandExecutionProvider()); 145 | bind(CommandHandle.class).to(new CommandHandleProvider()); 146 | bind(CommandWrapper.class).to(new CommandWrapperProvider()); 147 | 148 | bind(CommandHandler.class).to(this); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/execution/CommandExecution.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.execution; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.CommandHandler; 5 | import net.j4c0b3y.api.command.actor.Actor; 6 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 7 | import net.j4c0b3y.api.command.exception.execution.UnknownFlagException; 8 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 9 | import net.j4c0b3y.api.command.execution.argument.flag.CommandFlag; 10 | import net.j4c0b3y.api.command.wrapper.CommandHandle; 11 | import net.j4c0b3y.api.command.wrapper.CommandParameter; 12 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 13 | 14 | import java.lang.annotation.Annotation; 15 | import java.util.*; 16 | 17 | /** 18 | * @author J4C0B3Y 19 | * @version CommandAPI 20 | * @since 27/08/2024 21 | */ 22 | @Getter 23 | public class CommandExecution { 24 | private final Actor actor; 25 | private final CommandHandle handle; 26 | private final String label; 27 | private final List arguments; 28 | private final CommandHandler handler; 29 | 30 | private final List providedParameters = new ArrayList<>(); 31 | 32 | public CommandExecution(Actor actor, CommandHandle handle, String label, List arguments) { 33 | this.actor = actor; 34 | this.handle = handle; 35 | this.label = label; 36 | this.arguments = arguments; 37 | this.handler = handle.getWrapper().getHandler(); 38 | 39 | for (CommandParameter parameter : handle.getParameters()) { 40 | providedParameters.add(new ProvidedParameter(parameter)); 41 | } 42 | } 43 | 44 | public CommandExecution(Actor actor, CommandHandler handler, String label, List arguments) { 45 | this.actor = actor; 46 | this.handle = null; 47 | this.label = label; 48 | this.arguments = arguments; 49 | this.handler = handler; 50 | } 51 | 52 | public void execute() { 53 | if (handle == null) { 54 | throw new IllegalStateException("Cannot run command execution without a handle."); 55 | } 56 | 57 | // Wrapper conditions 58 | for (Annotation condition : handle.getWrapper().getConditions()) { 59 | if (!handler.getConditionHandler().validate(condition, actor)) { 60 | return; 61 | } 62 | } 63 | 64 | // Handle conditions 65 | for (Annotation condition : handle.getConditions()) { 66 | if (!handler.getConditionHandler().validate(condition, actor)) { 67 | return; 68 | } 69 | } 70 | 71 | if (providedParameters.isEmpty()) { 72 | complete(); 73 | } 74 | 75 | List arguments = new ArrayList<>(this.arguments); 76 | 77 | extractFlags(arguments); 78 | parseArguments(arguments); 79 | 80 | for (ProvidedParameter provided : providedParameters) { 81 | if (provided.isProvided()) { 82 | continue; 83 | } 84 | 85 | CommandParameter parameter = provided.getParameter(); 86 | Provider provider = parameter.getProvider(); 87 | 88 | handler.runTask(() -> 89 | handle.getWrapper().handleExceptions(actor, handle, label, () -> { 90 | boolean skip = provided.getArgument() == null && provider.isConsumer(); 91 | 92 | if (!skip && !actor.hasPermission(parameter.getPermission())) { 93 | handler.getLocale().getNoPermission().forEach(actor::sendMessage); 94 | return null; 95 | } 96 | 97 | provided.provide(skip ? null : provider.provide(this, 98 | new CommandArgument(provided.getArgument(), parameter) 99 | )); 100 | 101 | if (provided.isProvided()) { 102 | provided.provide(handler.getModifierHandler().modify( 103 | provided.getValue(), this, parameter 104 | )); 105 | } 106 | 107 | complete(); 108 | return null; 109 | }), 110 | provider.isAsync() 111 | ); 112 | } 113 | } 114 | 115 | private void extractFlags(List arguments) { 116 | Map flags = new HashMap<>(); 117 | 118 | for (ProvidedParameter provided : providedParameters) { 119 | CommandParameter parameter = provided.getParameter(); 120 | 121 | if (!parameter.isFlag()) { 122 | continue; 123 | } 124 | 125 | for (String flag : parameter.getFlagNames()) { 126 | flags.put(flag, provided); 127 | } 128 | } 129 | 130 | Iterator iterator = arguments.iterator(); 131 | 132 | while (iterator.hasNext()) { 133 | String argument = iterator.next(); 134 | 135 | try { 136 | argument = CommandFlag.validate(argument, handler); 137 | 138 | if (argument == null) { 139 | continue; 140 | } 141 | 142 | ProvidedParameter parameter = flags.get(argument); 143 | 144 | if (parameter == null) { 145 | throw new UnknownFlagException(handler.getLocale().getUnknownFlag(argument), true); 146 | } 147 | 148 | if (parameter.getArgument() != null || parameter.isProvided()) { 149 | throw new ExitMessage(handler.getLocale().getFlagSpecified(argument)); 150 | } 151 | 152 | if (parameter.getParameter().isBoolean()) { 153 | parameter.provide(true); 154 | iterator.remove(); 155 | continue; 156 | } 157 | 158 | if (!iterator.hasNext()) { 159 | throw new ExitMessage(handler.getLocale().getFlagValueRequired(argument), true); 160 | } 161 | 162 | iterator.remove(); 163 | String value = iterator.next(); 164 | 165 | if (CommandFlag.validate(value, handler) != null) { 166 | throw new ExitMessage(handler.getLocale().getFlagValueRequired(argument), true); 167 | } 168 | 169 | parameter.setArgument(value); 170 | iterator.remove(); 171 | } catch (UnknownFlagException exception) { 172 | switch (handler.getUnknownFlagAction()) { 173 | case ERROR: throw exception; 174 | case STRIP: iterator.remove(); 175 | } 176 | } 177 | } 178 | } 179 | 180 | private void parseArguments(List arguments) { 181 | int offset = 0; 182 | 183 | for (int i = 0; i < providedParameters.size(); i++) { 184 | ProvidedParameter provided = providedParameters.get(i); 185 | CommandParameter parameter = provided.getParameter(); 186 | 187 | if (parameter.isFlag()) { 188 | if (!provided.isProvided()) { 189 | // If no argument for a flag was given, provide its default value. 190 | if (provided.getArgument() == null) { 191 | provided.setArgument(parameter.getDefaultValue()); 192 | } 193 | 194 | // If the @Default is null, use the provider's flag default. 195 | if (provided.getArgument() == null) { 196 | provided.provide(parameter.getProvider().flagDefault(this)); 197 | } 198 | } 199 | 200 | offset++; 201 | continue; 202 | } 203 | 204 | if (!parameter.getProvider().isConsumer()) { 205 | offset++; 206 | continue; 207 | } 208 | 209 | int adjusted = i - offset; 210 | 211 | if (parameter.isCombine()) { 212 | arguments = combineRemaining(arguments, adjusted); 213 | } 214 | 215 | if (adjusted >= arguments.size()) { 216 | if (parameter.isOptional()) { 217 | provided.setArgument(parameter.getDefaultValue()); 218 | continue; 219 | } 220 | 221 | if (!handle.hasExpandedUsage()) { 222 | throw new ExitMessage(handler.getLocale().getMissingArgument(parameter.getName()), true); 223 | } else { 224 | handle.getExpandedUsage().forEach(actor::sendMessage); 225 | return; 226 | } 227 | } 228 | 229 | provided.setArgument(arguments.get(adjusted)); 230 | } 231 | } 232 | 233 | private List combineRemaining(List arguments, int startIndex) { 234 | List previous = new ArrayList<>(arguments.subList(0, startIndex)); 235 | String combined = String.join(" ", arguments.subList(startIndex, arguments.size())); 236 | 237 | if (!combined.isEmpty()) { 238 | previous.add(combined); 239 | } 240 | 241 | return previous; 242 | } 243 | 244 | private void complete() { 245 | for (ProvidedParameter parameter : providedParameters) { 246 | if (!parameter.isProvided()) { 247 | return; 248 | } 249 | } 250 | 251 | List arguments = new ArrayList<>(); 252 | 253 | for (ProvidedParameter parameter : providedParameters) { 254 | arguments.add(parameter.getValue()); 255 | } 256 | 257 | handle.invoke(actor, label, arguments); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/CommandWrapper.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import net.j4c0b3y.api.command.CommandHandler; 6 | import net.j4c0b3y.api.command.actor.Actor; 7 | import net.j4c0b3y.api.command.annotation.command.Command; 8 | import net.j4c0b3y.api.command.annotation.command.Help; 9 | import net.j4c0b3y.api.command.annotation.command.Requires; 10 | import net.j4c0b3y.api.command.annotation.command.condition.Condition; 11 | import net.j4c0b3y.api.command.annotation.registration.Ignore; 12 | import net.j4c0b3y.api.command.annotation.registration.Register; 13 | import net.j4c0b3y.api.command.exception.execution.ExitMessage; 14 | import net.j4c0b3y.api.command.exception.registration.InvalidWrapperException; 15 | import net.j4c0b3y.api.command.execution.CommandExecution; 16 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 17 | import net.j4c0b3y.api.command.utils.AnnotationUtils; 18 | import net.j4c0b3y.api.command.utils.ListUtils; 19 | import net.j4c0b3y.api.command.utils.StringUtils; 20 | import net.j4c0b3y.api.command.wrapper.binding.provider.Provider; 21 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 22 | 23 | import java.lang.annotation.Annotation; 24 | import java.lang.reflect.InvocationTargetException; 25 | import java.lang.reflect.Method; 26 | import java.util.*; 27 | import java.util.concurrent.Callable; 28 | import java.util.logging.Level; 29 | 30 | /** 31 | * @author J4C0B3Y 32 | * @version CommandAPI 33 | * @since 27/08/2024 34 | */ 35 | @Getter @Setter 36 | public abstract class CommandWrapper { 37 | private final String name; 38 | private final List aliases; 39 | private final Object object; 40 | private final CommandHandler handler; 41 | 42 | private final String description; 43 | private String permission; 44 | private final Help help; 45 | 46 | private final Map handles = new LinkedHashMap<>(); 47 | private final List conditions; 48 | 49 | public CommandWrapper(Object object, String name, List aliases, CommandHandler handler) { 50 | this.name = name.toLowerCase(); 51 | this.aliases = ListUtils.map(aliases, String::toLowerCase); 52 | this.object = object; 53 | this.handler = handler; 54 | 55 | Class clazz = object.getClass(); 56 | 57 | if (clazz.isAnnotationPresent(Ignore.class)) { 58 | throw new InvalidWrapperException("Wrapper '" + clazz.getSimpleName() + "' is marked @Disabled"); 59 | } 60 | 61 | this.description = AnnotationUtils.getValue(clazz, Register.class, Register::description, ""); 62 | this.permission = AnnotationUtils.getValue(clazz, Requires.class, Requires::value, null); 63 | this.help = clazz.getAnnotation(Help.class); 64 | 65 | for (Method method : clazz.getDeclaredMethods()) { 66 | if (!method.isAnnotationPresent(Command.class)) continue; 67 | 68 | CommandHandle handle = new CommandHandle(this, method); 69 | 70 | if (handles.containsKey(handle.getName().toLowerCase())) { 71 | throw new InvalidWrapperException("Duplicate handle '" + handle.getName() + "'."); 72 | } 73 | 74 | handles.put(handle.getName().toLowerCase(), handle); 75 | } 76 | 77 | if (handles.isEmpty()) { 78 | handler.getLogger().warning("Wrapper '" + clazz.getSimpleName() + "' doesn't contain any handles."); 79 | } 80 | 81 | this.conditions = AnnotationUtils.getSpecial(clazz.getAnnotations(), Condition.class); 82 | } 83 | 84 | public abstract void register(); 85 | 86 | public boolean hasHelp() { 87 | return help != null; 88 | } 89 | 90 | public boolean hasPermission() { 91 | return permission != null; 92 | } 93 | 94 | public CommandHandle getHandle(String label) { 95 | label = label.toLowerCase(); 96 | 97 | if (handles.containsKey(label)) { 98 | return handles.get(label); 99 | } 100 | 101 | for (CommandHandle handle : handles.values()) { 102 | for (String alias : handle.getAliases()) { 103 | if (alias.equalsIgnoreCase(label)) { 104 | return handle; 105 | } 106 | } 107 | } 108 | 109 | return null; 110 | } 111 | 112 | public CommandHandle getHandle(List arguments) { 113 | for (int i = arguments.size(); i >= 0; i--) { 114 | CommandHandle handle = getHandle(String.join(" ", arguments.subList(0, i))); 115 | 116 | if (handle != null) { 117 | return handle; 118 | } 119 | } 120 | 121 | return null; 122 | } 123 | 124 | public void dispatch(Actor actor, String label, List arguments) { 125 | CommandHandle handle = getHandle(arguments); 126 | 127 | handleExceptions(actor, handle, label, () -> { 128 | dispatch(actor, handle, label, arguments); 129 | return null; 130 | }); 131 | } 132 | 133 | private void dispatch(Actor actor, CommandHandle handle, String label, List arguments) { 134 | boolean interceptHelp = hasHelp() && this.help.register() && !this.help.command().isEmpty(); 135 | boolean showHelp = interceptHelp && !arguments.isEmpty() && arguments.get(0).equalsIgnoreCase(this.help.command()); 136 | 137 | if (handle == null || showHelp) { 138 | // Wrapper conditions for help message. 139 | for (Annotation condition : getConditions()) { 140 | if (!handler.getConditionHandler().validate(condition, actor)) { 141 | return; 142 | } 143 | } 144 | 145 | if (hasHelp()) { 146 | List message = handler.getUsageHandler().getHelpMessage(actor, this, label, arguments); 147 | 148 | if (message != null) { 149 | message.forEach(actor::sendMessage); 150 | return; 151 | } 152 | } 153 | 154 | handler.getLocale().getInvalidSubcommand(label, this.help).forEach(actor::sendMessage); 155 | return; 156 | } 157 | 158 | if (!actor.hasPermission(handle.getPermission())) { 159 | handler.getLocale().getNoPermission().forEach(actor::sendMessage); 160 | return; 161 | } 162 | 163 | new CommandExecution(actor, handle, label, handle.stripLabel(arguments)).execute(); 164 | } 165 | 166 | public List suggest(Actor actor, List arguments) { 167 | CommandHandle handle = getHandle(arguments); 168 | List suggestions = new ArrayList<>(); 169 | 170 | boolean suggestHandles = handle == null || !actor.hasPermission(handle.getPermission()); 171 | boolean rootCommand = handle != null && handle.getName().isEmpty(); 172 | 173 | if (suggestHandles || rootCommand) { 174 | suggestions.addAll(suggestHandles(actor, arguments)); 175 | } 176 | 177 | if (!suggestHandles || rootCommand) { 178 | suggestions.addAll(handle.suggest(actor, handle.stripLabel(arguments))); 179 | } 180 | 181 | String prefix = !arguments.isEmpty() ? arguments.get(arguments.size() - 1) : ""; 182 | suggestions.removeIf(suggestion -> !StringUtils.startsWithIgnoreCase(suggestion, prefix)); 183 | 184 | if (suggestions.size() == 1 && suggestions.get(0).isEmpty()) { 185 | // https://bugs.mojang.com/browse/MC-165562 186 | suggestions.set(0, " "); 187 | } 188 | 189 | return suggestions; 190 | } 191 | 192 | private List suggestHandles(Actor actor, List arguments) { 193 | List suggestions = new ArrayList<>(); 194 | 195 | for (CommandHandle handle : handles.values()) { 196 | if (handle.isHidden() || !actor.hasPermission(handle.getPermission())) { 197 | continue; 198 | } 199 | 200 | List matches = handle.matches(label -> 201 | StringUtils.startsWithIgnoreCase(label, String.join(" ", arguments)) 202 | ); 203 | 204 | if (matches.isEmpty()) { 205 | continue; 206 | } 207 | 208 | for (String match : matches) { 209 | suggestions.add(match.split(" ")[arguments.size() - 1]); 210 | } 211 | } 212 | 213 | if (hasHelp() && help.register()) { 214 | suggestions.add(help.command()); 215 | } 216 | 217 | return suggestions; 218 | } 219 | 220 | protected List suggestValue(Provider provider, CommandSuggestion suggestion, CommandArgument argument) { 221 | return provider.suggest(suggestion, argument); 222 | } 223 | 224 | public void handleExceptions(Actor actor, CommandHandle handle, String label, Callable task) { 225 | try { 226 | task.call(); 227 | } catch (Exception exception) { 228 | Throwable throwable = exception; 229 | 230 | while (throwable instanceof InvocationTargetException) { 231 | throwable = throwable.getCause(); 232 | } 233 | 234 | if (throwable instanceof ExitMessage) { 235 | if (throwable.getMessage() != null) { 236 | actor.sendMessage(throwable.getMessage()); 237 | } 238 | 239 | if (((ExitMessage) throwable).isShowUsage()) { 240 | handler.getUsageHandler().getUsageMessage(actor, handle, label).forEach(actor::sendMessage); 241 | } 242 | 243 | return; 244 | } 245 | 246 | handler.getLocale().getExceptionOccurred().forEach(actor::sendMessage); 247 | 248 | handler.getLogger().log(Level.SEVERE, 249 | "Failed to execute command '/" + 250 | handle.getFullName() + "'.", 251 | throwable 252 | ); 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /core/src/main/java/net/j4c0b3y/api/command/wrapper/CommandHandle.java: -------------------------------------------------------------------------------- 1 | package net.j4c0b3y.api.command.wrapper; 2 | 3 | import lombok.Getter; 4 | import net.j4c0b3y.api.command.actor.Actor; 5 | import net.j4c0b3y.api.command.annotation.command.Command; 6 | import net.j4c0b3y.api.command.annotation.command.Requires; 7 | import net.j4c0b3y.api.command.annotation.command.Usage; 8 | import net.j4c0b3y.api.command.annotation.command.condition.Condition; 9 | import net.j4c0b3y.api.command.annotation.parameter.Manual; 10 | import net.j4c0b3y.api.command.exception.execution.UnknownFlagException; 11 | import net.j4c0b3y.api.command.exception.registration.ParameterStructureException; 12 | import net.j4c0b3y.api.command.execution.argument.CommandArgument; 13 | import net.j4c0b3y.api.command.execution.argument.flag.CommandFlag; 14 | import net.j4c0b3y.api.command.execution.argument.flag.FlagAction; 15 | import net.j4c0b3y.api.command.utils.AnnotationUtils; 16 | import net.j4c0b3y.api.command.utils.ListUtils; 17 | import net.j4c0b3y.api.command.wrapper.suggestion.CommandSuggestion; 18 | 19 | import java.lang.annotation.Annotation; 20 | import java.lang.reflect.Method; 21 | import java.lang.reflect.Parameter; 22 | import java.util.ArrayList; 23 | import java.util.Arrays; 24 | import java.util.Collections; 25 | import java.util.List; 26 | import java.util.function.Function; 27 | 28 | /** 29 | * @author J4C0B3Y 30 | * @version CommandAPI 31 | * @since 27/08/2024 32 | */ 33 | @Getter 34 | public class CommandHandle { 35 | private final CommandWrapper wrapper; 36 | private final Method method; 37 | 38 | private final String name; 39 | private final String description; 40 | private final List aliases; 41 | private final boolean hidden; 42 | private final boolean async; 43 | 44 | private final List parameters = new ArrayList<>(); 45 | private final List conditions; 46 | 47 | private final String permission; 48 | private final String usage; 49 | private final List expandedUsage; 50 | 51 | public CommandHandle(CommandWrapper wrapper, Method method) { 52 | this.wrapper = wrapper; 53 | this.method = method; 54 | 55 | Command command = method.getAnnotation(Command.class); 56 | 57 | this.name = command.name(); 58 | this.description = command.description(); 59 | this.aliases = Arrays.asList(command.aliases()); 60 | this.hidden = command.hidden(); 61 | this.async = command.async(); 62 | 63 | for (Parameter parameter : method.getParameters()) { 64 | parameters.add(new CommandParameter(this, parameter)); 65 | } 66 | 67 | List nonFlagParameters = new ArrayList<>(); 68 | 69 | for (CommandParameter parameter : parameters) { 70 | if (!parameter.isFlag()) { 71 | nonFlagParameters.add(parameter); 72 | } 73 | } 74 | 75 | boolean optionalArguments = false; 76 | 77 | for (CommandParameter parameter : nonFlagParameters) { 78 | if (!parameter.isOptional() && optionalArguments) { 79 | throw new ParameterStructureException("Required parameter '" + parameter.getName() + "' cannot be after @Default."); 80 | } 81 | 82 | if (parameter.isLast() && nonFlagParameters.indexOf(parameter) != nonFlagParameters.size() - 1) { 83 | throw new ParameterStructureException("Parameter '" + parameter.getName() + "' must be the last parameter."); 84 | } 85 | 86 | if (parameter.isOptional()) { 87 | optionalArguments = true; 88 | } 89 | } 90 | 91 | this.conditions = AnnotationUtils.getSpecial(method.getAnnotations(), Condition.class); 92 | this.permission = AnnotationUtils.getValue(method, Requires.class, Requires::value, null); 93 | 94 | Usage usage = method.getAnnotation(Usage.class); 95 | 96 | this.usage = usage != null && !usage.value().isEmpty() ? usage.value() : generateUsage(); 97 | this.expandedUsage = usage != null && usage.expanded().length > 0 ? ListUtils.asList(usage.expanded()) : null; 98 | } 99 | 100 | public String getFullName() { 101 | String space = !name.isEmpty() ? " " : ""; 102 | return wrapper.getName() + space + name; 103 | } 104 | 105 | public boolean hasDescription() { 106 | return !description.isEmpty(); 107 | } 108 | 109 | public boolean hasPermission() { 110 | return permission != null; 111 | } 112 | 113 | public boolean hasExpandedUsage() { 114 | return expandedUsage != null; 115 | } 116 | 117 | public String generateUsage() { 118 | List arguments = new ArrayList<>(); 119 | List flags = new ArrayList<>(); 120 | 121 | for (CommandParameter parameter : parameters) { 122 | if (parameter.isFlag()) { 123 | flags.add(parameter); 124 | continue; 125 | } 126 | 127 | if (!parameter.getProvider().isConsumer()) { 128 | continue; 129 | } 130 | 131 | String left = parameter.isOptional() ? "[" : "<"; 132 | String right = parameter.isOptional() ? "]" : ">"; 133 | 134 | arguments.add(left + parameter.getName() + right); 135 | } 136 | 137 | for (CommandParameter parameter : flags) { 138 | arguments.add(CommandFlag.getFlag(parameter.getFlagNames().get(0))); 139 | 140 | if (!parameter.isBoolean()) { 141 | arguments.add("<" + parameter.getName() + ">"); 142 | } 143 | } 144 | 145 | return String.join(" ", arguments); 146 | } 147 | 148 | public void invoke(Actor actor, String label, List arguments) { 149 | wrapper.getHandler().runTask(() -> 150 | wrapper.handleExceptions(actor, this, label, () -> { 151 | method.invoke(wrapper.getObject(), arguments.toArray()); 152 | return null; 153 | }), 154 | async 155 | ); 156 | } 157 | 158 | public List matches(Function matcher) { 159 | List matches = new ArrayList<>(); 160 | 161 | if (matcher.apply(name)) { 162 | matches.add(name); 163 | } 164 | 165 | for (String alias : aliases) { 166 | if (matcher.apply(alias)) { 167 | matches.add(alias); 168 | } 169 | } 170 | 171 | return matches; 172 | } 173 | 174 | public String getLabel(List arguments) { 175 | for (int i = arguments.size(); i >= 0; i--) { 176 | String label = String.join(" ", arguments.subList(0, i)).toLowerCase(); 177 | 178 | if (label.equalsIgnoreCase(name)) { 179 | return name; 180 | } 181 | 182 | for (String alias : aliases) { 183 | if (label.equalsIgnoreCase(alias)) { 184 | return alias; 185 | } 186 | } 187 | } 188 | 189 | return null; 190 | } 191 | 192 | public List stripLabel(List arguments) { 193 | String label = getLabel(arguments); 194 | 195 | if (label.isEmpty()) { 196 | return arguments; 197 | } 198 | 199 | int length = label.split(" ").length; 200 | return arguments.subList(length, arguments.size()); 201 | } 202 | 203 | public CommandParameter getFlag(String name) { 204 | for (CommandParameter parameter : parameters) { 205 | if (parameter.isFlag() && parameter.getFlagNames().contains(name)) { 206 | return parameter; 207 | } 208 | } 209 | 210 | return null; 211 | } 212 | 213 | public List suggest(Actor actor, List arguments) { 214 | if (arguments.isEmpty()) { 215 | return Collections.emptyList(); 216 | } 217 | 218 | String prefix = arguments.get(arguments.size() - 1); 219 | List suggestions = new ArrayList<>(); 220 | 221 | // Flag value suggestions 222 | 223 | if (arguments.size() >= 2) { 224 | try { 225 | String flag = CommandFlag.validate(arguments.get(arguments.size() - 2), wrapper.getHandler()); 226 | 227 | if (flag != null) { 228 | CommandParameter parameter = getFlag(flag); 229 | 230 | if (parameter != null && !parameter.isBoolean()) { 231 | suggestions.addAll(wrapper.suggestValue(parameter.getProvider(), 232 | new CommandSuggestion(actor, arguments, wrapper.getHandler()), 233 | new CommandArgument(prefix, parameter) 234 | )); 235 | 236 | return suggestions; 237 | } 238 | } 239 | } catch (UnknownFlagException ignored) { 240 | } 241 | } 242 | 243 | // Flag name suggestions 244 | if (prefix.startsWith("-")) { 245 | for (CommandParameter parameter : this.parameters) { 246 | if (!parameter.isFlag()) continue; 247 | 248 | for (String name : parameter.getFlagNames()) { 249 | String flag = CommandFlag.getFlag(name); 250 | 251 | if (flag.startsWith(prefix)) { 252 | suggestions.add(flag); 253 | } 254 | } 255 | } 256 | } 257 | 258 | // Calculate flag offset 259 | 260 | int offset = 0; 261 | boolean ignore = wrapper.getHandler().getUnknownFlagAction() == FlagAction.ARGUMENT; 262 | 263 | for (int i = 0; i < arguments.size() - 1; i++) { 264 | try { 265 | String flag = CommandFlag.validate(arguments.get(i), wrapper.getHandler()); 266 | if (flag == null) continue; 267 | if (!ignore) offset++; 268 | 269 | CommandParameter parameter = getFlag(flag); 270 | if (parameter == null) continue; 271 | if (ignore) offset++; 272 | 273 | if (parameter.isBoolean() || i + 1 >= arguments.size() - 1) { 274 | continue; 275 | } 276 | 277 | String next = CommandFlag.validate(arguments.get(i + 1), wrapper.getHandler()); 278 | 279 | if (next == null || getFlag(next) == null) { 280 | offset++; 281 | } 282 | } catch (UnknownFlagException exception) { 283 | if (wrapper.getHandler().getUnknownFlagAction() != FlagAction.ARGUMENT) { 284 | offset++; 285 | } 286 | } 287 | } 288 | 289 | // Argument suggestions 290 | 291 | List parameters = new ArrayList<>(); 292 | 293 | for (CommandParameter parameter : this.parameters) { 294 | if (parameter.getProvider().isConsumer() && !parameter.isFlag()) { 295 | parameters.add(parameter); 296 | } 297 | } 298 | 299 | int parameterIndex = arguments.size() - offset - 1; 300 | 301 | if (!parameters.isEmpty()) { 302 | CommandParameter last = parameters.get(parameters.size() - 1); 303 | 304 | if (parameterIndex >= parameters.size() && last.isArray()) { 305 | parameterIndex = parameters.size() - 1; 306 | } 307 | } 308 | 309 | 310 | if (parameterIndex >= parameters.size()) { 311 | return suggestions; 312 | } 313 | 314 | CommandParameter parameter = parameters.get(parameterIndex); 315 | Requires requires = parameter.getAnnotation(Requires.class); 316 | boolean manual = parameter.hasAnnotation(Manual.class); 317 | 318 | if (!manual && (requires == null || (!requires.value().isEmpty() && actor.hasPermission(requires.value())))) { 319 | suggestions.addAll(wrapper.suggestValue(parameter.getProvider(), 320 | new CommandSuggestion(actor, arguments, wrapper.getHandler()), 321 | new CommandArgument(prefix, parameter) 322 | )); 323 | } 324 | 325 | return suggestions; 326 | } 327 | } 328 | --------------------------------------------------------------------------------