├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── libs.versions.toml ├── lombok.config ├── settings.gradle ├── springlify-commander ├── README.md ├── springlify-commander-bukkit │ ├── springlify-commander-bukkit.gradle │ └── src │ │ └── main │ │ └── java │ │ └── dev │ │ └── temez │ │ └── springlify │ │ └── commander │ │ ├── argument │ │ └── adapter │ │ │ └── impl │ │ │ ├── GameModeParameterAdapter.java │ │ │ ├── OfflinePlayerParameterAdapter.java │ │ │ ├── PlayerParameterAdapter.java │ │ │ └── WorldParameterAdapter.java │ │ ├── command │ │ ├── invocation │ │ │ └── BukkitInvocationFactory.java │ │ ├── platform │ │ │ ├── BukkitCommandFactory.java │ │ │ ├── BukkitCommandRegistrar.java │ │ │ └── CommanderBukkitCommand.java │ │ └── sender │ │ │ └── BukkitCommandSender.java │ │ └── initializer │ │ └── BukkitCommandInitializer.java └── springlify-commander-commons │ ├── springlify-commander-commons.gradle │ └── src │ └── main │ └── java │ └── dev │ └── temez │ └── springlify │ └── commander │ ├── annotation │ ├── CommandRoot.java │ ├── CommanderCommand.java │ ├── SenderDetailsSource.java │ ├── context │ │ ├── External.java │ │ └── Global.java │ ├── filter │ │ ├── ApplyFilters.java │ │ ├── RequirePermission.java │ │ └── ValidateWith.java │ └── parameter │ │ ├── Adapter.java │ │ └── Completer.java │ ├── argument │ ├── adapter │ │ ├── ParameterAdapter.java │ │ ├── impl │ │ │ ├── FloatParameterAdapter.java │ │ │ ├── IntegerParameterAdapter.java │ │ │ └── StringParameterAdapter.java │ │ └── resolver │ │ │ ├── ContextParameterAdapterResolver.java │ │ │ └── ParameterAdapterResolver.java │ └── completer │ │ └── ParameterCompleter.java │ ├── command │ ├── Command.java │ ├── CommandImpl.java │ ├── CommandType.java │ ├── completer │ │ ├── CommandCompleter.java │ │ ├── ProviderCommandCompleter.java │ │ └── provider │ │ │ ├── CompletionProvider.java │ │ │ ├── MethodParameterCompletionProvider.java │ │ │ └── impl │ │ │ ├── ExternalAdapterCompletionProvider.java │ │ │ ├── ExternalCompleterCompletionProvider.java │ │ │ ├── GenericCompletionProvider.java │ │ │ └── SubCommandCompletionProvider.java │ ├── discoverer │ │ ├── CommandDiscoverer.java │ │ ├── CommandDiscovererImpl.java │ │ ├── ProviderSubcommandDiscoverer.java │ │ ├── SubcommandDiscoverer.java │ │ └── provider │ │ │ ├── ClassSubCommandDiscoveryProvider.java │ │ │ ├── MethodSubcommandDiscoveryProvider.java │ │ │ └── SubcommandDiscoveryProvider.java │ ├── executor │ │ ├── CommandExecutor.java │ │ ├── ProviderCommandExecutor.java │ │ ├── details │ │ │ ├── ProviderSenderDetailsResolver.java │ │ │ ├── SenderDetailsResolver.java │ │ │ └── provider │ │ │ │ ├── SenderDetailsProvider.java │ │ │ │ └── impl │ │ │ │ ├── AnnotationSenderDetailsProvider.java │ │ │ │ └── GenericSenderDetailsProvider.java │ │ └── provider │ │ │ ├── ParameterProvider.java │ │ │ └── impl │ │ │ ├── ExternalParameterProvider.java │ │ │ └── GenericParameterProvider.java │ ├── filter │ │ ├── CommandFilter.java │ │ ├── CommandFilterService.java │ │ ├── ProviderCommandFilterService.java │ │ ├── impl │ │ │ └── RequirePermissionFilter.java │ │ ├── provider │ │ │ ├── CommandFilterProvider.java │ │ │ └── impl │ │ │ │ ├── AnnotationBasedCommandFilterProvider.java │ │ │ │ ├── GlobalFilterProvider.java │ │ │ │ └── SimpleCommandFilterProvider.java │ │ ├── resolver │ │ │ ├── CommandFilterResolver.java │ │ │ └── ContextFilterResolver.java │ │ └── simple │ │ │ ├── SimpleCommandFilter.java │ │ │ └── impl │ │ │ └── CommandSourceFilter.java │ ├── invocation │ │ ├── CommandInvocation.java │ │ ├── CommandInvocationFactory.java │ │ └── CommandInvocationImpl.java │ ├── metadata │ │ ├── CommandInvocationMetadata.java │ │ └── CommandInvocationMetadataImpl.java │ ├── platform │ │ ├── PlatformCommandFactory.java │ │ └── PlatformCommandRegistrar.java │ ├── preprocessor │ │ ├── ExecutionPreprocessorService.java │ │ ├── ExecutionPreprocessorServiceImpl.java │ │ ├── InvocationPreprocessor.java │ │ └── impl │ │ │ └── SubcommandPreprocessor.java │ └── sender │ │ ├── Sender.java │ │ └── SenderDetailsFactory.java │ ├── exception │ ├── CommandException.java │ ├── CommandExecutionException.java │ ├── CommanderException.java │ ├── argument │ │ ├── ArgumentAdapterException.java │ │ ├── ArgumentAdapterNotFoundException.java │ │ └── ArgumentException.java │ ├── details │ │ └── SenderDetailsException.java │ ├── discovery │ │ └── CommandDiscoveryException.java │ ├── filter │ │ ├── CommandFilterException.java │ │ └── CommandFilterNotFoundException.java │ └── handler │ │ ├── CommandExceptionHandler.java │ │ ├── CommanderExceptionHandler.java │ │ ├── CommanderExceptionHandlerImpl.java │ │ └── impl │ │ ├── ArgumentExceptionHandler.java │ │ └── CommandFilterExceptionHandler.java │ ├── initializer │ └── AbstractCommandInitializer.java │ └── service │ ├── CommandService.java │ ├── CommandServiceImpl.java │ └── chat │ └── CommanderChatService.java ├── springlify-examples └── example-bukkit-plugin │ ├── example-bukkit-plugin.gradle │ └── src │ └── main │ ├── java │ └── dev │ │ └── temez │ │ └── springlify │ │ └── example │ │ ├── application │ │ ├── SpringlifyExampleApplication.java │ │ └── SpringlifyExamplePlugin.java │ │ ├── command │ │ └── ExampleCommand.java │ │ ├── configuration │ │ └── ExampleConfiguration.java │ │ └── service │ │ └── commander │ │ └── CommanderChatServiceImpl.java │ └── resources │ ├── application.yml │ └── plugin.yml ├── springlify-platform ├── README.md ├── springlify-platform-bukkit │ ├── README.md │ ├── springlify-platform-bukkit.gradle │ └── src │ │ ├── main │ │ └── java │ │ │ └── dev │ │ │ └── temez │ │ │ └── springlify │ │ │ └── platform │ │ │ ├── annotation │ │ │ ├── BukkitCommand.java │ │ │ └── ConditionalOnPluginEnabled.java │ │ │ ├── condition │ │ │ └── OnPluginEnabledCondition.java │ │ │ ├── configuration │ │ │ ├── BukkitPluginConfiguration.java │ │ │ └── bukkit │ │ │ │ ├── ColorConfiguration.java │ │ │ │ ├── EnchantmentConfiguration.java │ │ │ │ ├── LocationConfiguration.java │ │ │ │ ├── PotionEffectConfiguration.java │ │ │ │ ├── SkinTextureConfiguration.java │ │ │ │ ├── converter │ │ │ │ ├── StringEnchantmentConverter.java │ │ │ │ └── StringPotionEffectTypeConverter.java │ │ │ │ ├── item │ │ │ │ ├── ItemStackConfiguration.java │ │ │ │ └── meta │ │ │ │ │ ├── ItemMetaConfiguration.java │ │ │ │ │ ├── LeatherArmorItemMetaConfiguration.java │ │ │ │ │ ├── PotionItemMetaConfiguration.java │ │ │ │ │ └── SkullItemMetaConfiguration.java │ │ │ │ └── mapper │ │ │ │ └── schema │ │ │ │ ├── ColorMappingSchema.java │ │ │ │ ├── LocationMappingSchema.java │ │ │ │ ├── PotionEffectMappingSchema.java │ │ │ │ └── item │ │ │ │ └── ItemStackMappingSchema.java │ │ │ ├── initializer │ │ │ ├── BukkitTaskInitializer.java │ │ │ ├── CommandHandlerInitializer.java │ │ │ └── EventHandlerInitializer.java │ │ │ ├── item │ │ │ ├── InitializingItemBuilderFactory.java │ │ │ ├── ItemBuilder.java │ │ │ └── ItemBuilderFactory.java │ │ │ ├── server │ │ │ └── BukkitServerPlatformAdapter.java │ │ │ └── task │ │ │ ├── AbstractTask.java │ │ │ └── SyncTimerTask.java │ │ └── test │ │ └── java │ │ └── dev │ │ └── temez │ │ └── springlify │ │ └── platform │ │ └── server │ │ └── BukkitServerPlatformAdapterTest.java ├── springlify-platform-commons │ ├── README.md │ ├── springlify-platform-commons.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── dev │ │ │ │ └── temez │ │ │ │ └── springlify │ │ │ │ └── platform │ │ │ │ ├── configuration │ │ │ │ ├── KyoriAdventureConfiguration.java │ │ │ │ └── mapper │ │ │ │ │ ├── ConfigurationMapper.java │ │ │ │ │ ├── ConfigurationMapperImpl.java │ │ │ │ │ ├── resolver │ │ │ │ │ ├── ContextSchemaResolver.java │ │ │ │ │ └── SchemaResolver.java │ │ │ │ │ └── schema │ │ │ │ │ └── MappingSchema.java │ │ │ │ ├── exception │ │ │ │ ├── FormattingException.java │ │ │ │ ├── MappingException.java │ │ │ │ └── RegistryException.java │ │ │ │ ├── registry │ │ │ │ ├── MapRegistry.java │ │ │ │ ├── Registry.java │ │ │ │ └── RegistryEntry.java │ │ │ │ ├── server │ │ │ │ └── ServerPlatformAdapter.java │ │ │ │ └── text │ │ │ │ ├── converter │ │ │ │ ├── LegacyTextConverter.java │ │ │ │ ├── MiniMessageTextConverter.java │ │ │ │ └── TextConverter.java │ │ │ │ └── formatter │ │ │ │ ├── Replacer.java │ │ │ │ ├── TextFormatter.java │ │ │ │ └── TextFormatterImpl.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ └── test │ │ └── java │ │ └── dev │ │ └── temez │ │ └── springlify │ │ └── platform │ │ ├── configuration │ │ └── mapper │ │ │ └── resolver │ │ │ └── ContextSchemaResolverTest.java │ │ └── text │ │ └── converter │ │ └── TextConverterIntegrationTest.java └── springlify-platform-velocity │ ├── springlify-platform-velocity.gradle │ └── src │ └── main │ └── java │ └── dev │ └── temez │ └── springlify │ └── platform │ ├── annotation │ ├── VelocityCommand.java │ └── VelocityEventListener.java │ ├── configuration │ └── VelocityPluginConfiguration.java │ ├── initializer │ ├── EventListenerInitializer.java │ └── VelocityCommandInitializer.java │ └── server │ └── VelocityServerPlatformAdapter.java └── springlify-starter ├── README.md ├── springlify-starter-bukkit ├── README.md ├── springlify-starter-bukkit.gradle └── src │ └── main │ └── java │ └── dev │ └── temez │ └── springlify │ └── starter │ └── plugin │ └── SpringlifyBukkitPlugin.java ├── springlify-starter-commons ├── README.md ├── springlify-starter-commons.gradle └── src │ └── main │ └── java │ └── dev │ └── temez │ └── springlify │ └── starter │ ├── annotation │ └── SpringlifyApplication.java │ ├── configuration │ ├── SpringlifyPluginConfiguration.java │ └── loader │ │ ├── ConfigurationLoader.java │ │ └── ConfigurationLoaderImpl.java │ ├── initializer │ ├── SpringlifyInitializer.java │ ├── SpringlifyInitializerImpl.java │ ├── event │ │ └── ContextPreShutdownEvent.java │ └── loader │ │ ├── ClassLoaderFactory.java │ │ ├── CompoundClassLoader.java │ │ └── CompoundClassLoaderFactory.java │ └── plugin │ └── SpringlifyPlugin.java └── springlify-starter-velocity ├── springlify-starter-velocity.gradle └── src └── main └── java └── dev └── temez └── springlify └── starter └── plugin └── SpringlifyVelocityPlugin.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | /.idea/ 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | 40 | /logs/ 41 | /gradle/wrapper/ 42 | /gradlew 43 | /gradlew.bat 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # springlify 2 | 3 | # WARNING! Library is unstable and currently in development. 4 | 5 | 6 | 7 | 8 | 9 | ### dependencies 10 | 11 | #### Gradle 12 | 13 | ````groovy 14 | dependencies { 15 | implementation 'dev.temez.springlify:springlify--:0.7.2.1-SNAPSHOT' 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { 21 | name = "StarMC" 22 | url = "https://repo.star-mc.ru/public" 23 | } 24 | } 25 | ```` 26 | #### Maven 27 | 28 | ```xml 29 | 30 | dev.temez.springlify 31 | springlify-- 32 | 0.7.2.0-SNAPSHOT 33 | 34 | 35 | 36 | starmc-repo-public 37 | StarMC repositories 38 | https://repo.star-mc.ru/public 39 | 40 | ``` 41 | 42 | This library provides complex solutions for developing on Bukkit/Velocity platforms. It enables usage 43 | of `Spring Framework` and contains some utilities to make it easier on Minecraft related platforms. 44 | 45 | Library consists of `3 major modules`. Each module has common submodule, and platform-specific implementation. 46 | 47 | ### springlify-starter 48 | 49 | A core module of library, which enables usage of `Spring Framework` and has minor platform-specific improvements. 50 | 51 | ### springlify-platform 52 | 53 | An optional module, contains utility classes and abstraction level for localization and configuring your plugins. 54 | 55 | ### springlify-commander 56 | 57 | Library for fast annotation-driven command implementation. 58 | 59 | Next, select a link to the module documentation. 60 | 61 | - [springlify-starter](/springlify-starter/README.md) 62 | - [springlify-platform](/springlify-platform/README.md) 63 | - [springlify-commander](/springlify-commander/README.md) 64 | 65 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | plugins { 3 | id 'java-library' 4 | id 'maven-publish' 5 | alias libs.plugins.springframework.boot 6 | alias libs.plugins.spring.dependencymanagement 7 | } 8 | 9 | allprojects { 10 | apply plugin: 'java-library' 11 | apply plugin: 'org.springframework.boot' 12 | apply plugin: 'io.spring.dependency-management' 13 | 14 | version = '0.7.2.1-SNAPSHOT' 15 | group = 'dev.temez.springlify' 16 | 17 | compileJava { 18 | options.encoding = 'UTF-8' 19 | sourceCompatibility = '17' 20 | targetCompatibility = '17' 21 | } 22 | 23 | java { 24 | withSourcesJar() 25 | withJavadocJar() 26 | } 27 | 28 | dependencies { 29 | annotationProcessor libs.projectlombok.lombok 30 | 31 | compileOnlyApi libs.projectlombok.lombok 32 | compileOnlyApi libs.jetbrains.annotations 33 | 34 | testAnnotationProcessor libs.projectlombok.lombok 35 | 36 | testCompileOnly libs.projectlombok.lombok 37 | testCompileOnly libs.jetbrains.annotations 38 | 39 | testImplementation libs.spring.boot.starter.test 40 | } 41 | 42 | test { 43 | useJUnitPlatform() 44 | } 45 | 46 | if (!project.name.contains('example')) { 47 | publishing { 48 | publications { 49 | "$project.name"(MavenPublication) { 50 | from components.java 51 | artifactId = project.name 52 | groupId = project.group 53 | version = project.version 54 | pom { 55 | developers { 56 | developer { 57 | id = 'temez' 58 | name = 'Artem I.' 59 | email = 'temezf@gmail.com' 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | publishing { 70 | repositories { 71 | maven { 72 | name = 'StarMC' 73 | url = 'https://repo.star-mc.ru/public' 74 | credentials { 75 | username = System.getenv('STARMC_REPO_USER') 76 | password = System.getenv('STARMC_REPO_TOKEN') 77 | } 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | spring-boot = '3.2.4' 3 | spring-dependencymanagement = '1.1.4' 4 | jetbrains-annotations = '24.1.0' 5 | johnrengelman-shadow = '8.1.0' 6 | kyori-adventure = '4.14.0' 7 | paper-paperapi = '1.16.5-R0.1-SNAPSHOT' 8 | reflections-reflections = '0.10.2' 9 | mojang-authlib = '1.5.25' 10 | tr7zw-item-nbt-api = '2.12.4' 11 | velocitypowered-velocitiyapi = '3.3.0-SNAPSHOT' 12 | 13 | [libraries] 14 | projectlombok-lombok = { module = "org.projectlombok:lombok" } 15 | jetbrains-annotations = { module = 'org.jetbrains:annotations', version.ref = 'jetbrains-annotations' } 16 | spring-boot-starter-test = { module = 'org.springframework.boot:spring-boot-starter-test' } 17 | spring-boot-starter = { module = 'org.springframework.boot:spring-boot-starter' } 18 | spring-boot-configuration-processor = { module = 'org.springframework.boot:spring-boot-configuration-processor' } 19 | kyori-adventure-text-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = 'kyori-adventure' } 20 | kyori-adventure-text-serializer-legacy = { module = "net.kyori:adventure-text-serializer-legacy", version.ref = 'kyori-adventure' } 21 | paper-paperapi = { module = 'com.destroystokyo.paper:paper-api', version.ref = 'paper-paperapi' } 22 | velocitypowered-velocitiyapi = { module = 'com.velocitypowered:velocity-api', version.ref = 'velocitypowered-velocitiyapi' } 23 | mojang-authlib = { module = 'com.mojang:authlib', version.ref = 'mojang-authlib' } 24 | tr7zw-item-nbt-api = { module = 'de.tr7zw:item-nbt-api', version.ref = 'tr7zw-item-nbt-api' } 25 | reflections-reflections = { module = "org.reflections:reflections", version.ref = 'reflections-reflections' } 26 | 27 | [plugins] 28 | springframework-boot = { id = 'org.springframework.boot', version.ref = 'spring-boot' } 29 | spring-dependencymanagement = { id = 'io.spring.dependency-management', version.ref = 'spring-dependencymanagement' } 30 | johnrengelman-shadow = { id = 'com.github.johnrengelman.shadow', version.ref = 'johnrengelman-shadow' } -------------------------------------------------------------------------------- /lombok.config: -------------------------------------------------------------------------------- 1 | lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier 2 | lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value 3 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | 7 | dependencyResolutionManagement { 8 | repositories { 9 | mavenCentral() 10 | mavenLocal() 11 | maven { 12 | name = "StarMC" 13 | url = "https://repo.star-mc.ru/public" 14 | } 15 | maven { 16 | name = 'CodeMC' 17 | url = 'https://repo.codemc.io/repository/maven-public/' 18 | } 19 | maven { 20 | name = 'Paper' 21 | url = 'https://repo.papermc.io/repository/maven-public/' 22 | } 23 | } 24 | } 25 | 26 | rootProject.name = 'springlify' 27 | 28 | [ 29 | 'springlify-commander:springlify-commander-bukkit', 30 | 'springlify-commander:springlify-commander-commons', 31 | 32 | 'springlify-starter:springlify-starter-bukkit', 33 | 'springlify-starter:springlify-starter-velocity', 34 | 'springlify-starter:springlify-starter-commons', 35 | 36 | 'springlify-platform:springlify-platform-bukkit', 37 | 'springlify-platform:springlify-platform-velocity', 38 | 'springlify-platform:springlify-platform-commons', 39 | 40 | 'springlify-examples:example-bukkit-plugin', 41 | ].forEach { 42 | include it 43 | } 44 | 45 | rootProject.children.each { project -> 46 | { 47 | setProjectBuildFileName(project) 48 | } 49 | } 50 | 51 | void setProjectBuildFileName(project) { 52 | project.buildFileName = "${project.name}.gradle" 53 | project.children.each { subproject -> 54 | { 55 | setProjectBuildFileName(subproject) 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /springlify-commander/README.md: -------------------------------------------------------------------------------- 1 | # springlify-commander 2 | 3 | Module for fast annotation-driven command implementation. 4 | Let's look through example from `Bukkit` platform. 5 | 6 | ```java 7 | 8 | @Slf4j 9 | @CommanderCommand( 10 | name = "example", 11 | type = CommandType.SHARED 12 | ) 13 | public class ExampleCommand { 14 | 15 | @CommandRoot 16 | public void execute(@NotNull CommandSender commandSender, @NotNull World world) { 17 | log.info("This is example command!"); 18 | } 19 | 20 | @CommanderCommand( 21 | name = "sub", 22 | type = CommandType.INGAME 23 | ) 24 | @RequirePermisison("permission.admin") 25 | public void executeSub(@NotNull Player player, @NotNull Integer someInteger) { 26 | log.info("This is simple admin subcommand!"); 27 | } 28 | 29 | @CommanderCommand( 30 | name = "other", 31 | type = CommandType.SHARED 32 | ) 33 | public static class SubExampleCommand { 34 | 35 | @CommandRoot 36 | public void execute(@NotNull CommandSender commandSender, @Completer(ExternalWorldCompleter.class) @NotNull World world) { 37 | log.info("This is other subcommand!"); 38 | } 39 | 40 | @CommanderCommand( 41 | name = "sub", 42 | type = CommandType.INGAME 43 | ) 44 | @SenderDetailsSource(ResidentDetailsFactory.class) 45 | public void executeSub(@NotNull Resident resident, @Adapter(ExternalIntegerAdapter.class) @NotNull Integer someInteger) { 46 | log.info("This is subcommand for sub subcommand for other!"); 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | In this example: 53 | 54 | - Commands are defined using the `@CommanderCommand` annotation, specifying the command name and type. 55 | - The `@CommandRoot` annotation designates the method as the root command handler. 56 | - Subcommands are defined within the same class or as nested classes, each annotated with @CommanderCommand. 57 | - Method parameters are automatically injected based on the sender and provided arguments. 58 | - Additional annotations like `@RequirePermission`, `@Completer`, `@SenderDetailsSource`, and `@Adapter` provide fine-grained 59 | control over command behavior and argument handling. 60 | 61 | With `springlify-commander`, implementing complex command structures becomes more straightforward and maintainable, 62 | allowing developers to focus on the functionality of their commands rather than boilerplate code. 63 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/springlify-commander-bukkit.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | dependencies { 4 | compileOnly libs.paper.paperapi 5 | 6 | api project(":springlify-platform:springlify-platform-bukkit") 7 | api project(":springlify-commander:springlify-commander-commons") 8 | } -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/GameModeParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 6 | import org.apache.commons.lang.StringUtils; 7 | import org.bukkit.GameMode; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * A parameter adapter for completing and parsing Bukkit game mode arguments. 15 | * This class implements the {@link ParameterAdapter} interface for {@link GameMode} types. 16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Component 20 | public class GameModeParameterAdapter implements ParameterAdapter { 21 | 22 | /** 23 | * Provides a list of game mode names and their respective numeric values for completion. 24 | * 25 | * @param commandSender the command sender 26 | * @return an unmodifiable list of game mode names and their respective numeric values 27 | */ 28 | @Override 29 | public @NotNull List complete(@NotNull Sender commandSender) { 30 | return List.of("0", "1", "2", "3", "creative", "survival", "adventure", "spectator"); 31 | } 32 | 33 | /** 34 | * Parses the raw argument into a Bukkit game mode. 35 | * 36 | * @param commandSender the command sender 37 | * @param rawArgument the raw argument string 38 | * @return the parsed Bukkit game mode 39 | * @throws ArgumentException if the argument does not represent a valid game mode 40 | */ 41 | @Override 42 | public @NotNull GameMode parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 43 | if (StringUtils.isNumeric(rawArgument)) { 44 | int gamemodeCode = Integer.parseInt(rawArgument); 45 | GameMode gameMode = GameMode.getByValue(gamemodeCode); 46 | if (gameMode == null) { 47 | throw new ArgumentException("commander.parameters.invalid-gamemode"); 48 | } 49 | return gameMode; 50 | } 51 | 52 | try { 53 | return GameMode.valueOf(rawArgument.toUpperCase()); 54 | } catch (IllegalArgumentException e) { 55 | throw new ArgumentException("commander.parameters.invalid-gamemode"); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/OfflinePlayerParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.OfflinePlayer; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * A parameter adapter for completing and parsing Bukkit offline player arguments. 15 | * This class implements the {@link ParameterAdapter} interface for {@link OfflinePlayer} types. 16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Component 20 | public class OfflinePlayerParameterAdapter implements ParameterAdapter { 21 | 22 | /** 23 | * Provides a list of all player names (online and offline) for completion. 24 | * 25 | * @param commandSender the command sender 26 | * @return an unmodifiable list of all player names 27 | */ 28 | @Override 29 | public @NotNull List complete(@NotNull Sender commandSender) { 30 | return Bukkit.getOnlinePlayers() 31 | .stream() 32 | .map(OfflinePlayer::getName) 33 | .toList(); 34 | } 35 | 36 | /** 37 | * Parses the raw argument into a Bukkit offline player. 38 | * 39 | * @param commandSender the command sender 40 | * @param rawArgument the raw argument string 41 | * @return the parsed Bukkit offline player 42 | * @throws ArgumentException if the player has not played before on the server 43 | */ 44 | @Override 45 | public @NotNull OfflinePlayer parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 46 | OfflinePlayer player = Bukkit.getOfflinePlayer(rawArgument); 47 | if (!player.hasPlayedBefore()) { 48 | throw new ArgumentException("commander.parameters.player-have-not-played-on-this-server"); 49 | } 50 | return player; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/PlayerParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | 4 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 5 | import dev.temez.springlify.commander.command.sender.Sender; 6 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.List; 13 | import java.util.Optional; 14 | 15 | /** 16 | * A parameter adapter for completing and parsing Bukkit player arguments. 17 | * This class implements the {@link ParameterAdapter} interface for {@link Player} types. 18 | * 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Component 22 | public class PlayerParameterAdapter implements ParameterAdapter { 23 | 24 | /** 25 | * Provides a list of online player names for completion. 26 | * If the command sender is a player, filters out players who are not visible to the sender. 27 | * 28 | * @param commandSender the command sender 29 | * @return an unmodifiable list of online player names 30 | */ 31 | @Override 32 | public @NotNull List complete(@NotNull Sender commandSender) { 33 | return Bukkit.getOnlinePlayers() 34 | .stream() 35 | .map(Player::getName) 36 | .toList(); 37 | } 38 | 39 | /** 40 | * Parses the raw argument into a Bukkit player. 41 | * 42 | * @param commandSender the command sender 43 | * @param rawArgument the raw argument string 44 | * @return the parsed Bukkit player 45 | * @throws ArgumentException if the player is offline 46 | */ 47 | @Override 48 | public @NotNull Player parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 49 | return Optional.ofNullable(Bukkit.getPlayer(rawArgument)) 50 | .orElseThrow(() -> new ArgumentException("commander.parameters.player-is-offline")); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/WorldParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.World; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | import java.util.Optional; 13 | 14 | /** 15 | * A parameter adapter for completing and parsing Bukkit world arguments. 16 | * This class implements the {@link ParameterAdapter} interface for {@link World} types. 17 | * 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Component 21 | public class WorldParameterAdapter implements ParameterAdapter { 22 | 23 | /** 24 | * Provides a list of world names for completion. 25 | * 26 | * @param commandSender the command sender 27 | * @return an unmodifiable list of world names 28 | */ 29 | @Override 30 | public @NotNull List complete(@NotNull Sender commandSender) { 31 | return Bukkit.getWorlds() 32 | .stream() 33 | .map(World::getName) 34 | .toList(); 35 | } 36 | 37 | /** 38 | * Parses the raw argument into a Bukkit world. 39 | * 40 | * @param commandSender the command sender 41 | * @param rawArgument the raw argument string 42 | * @return the parsed Bukkit world 43 | * @throws ArgumentException if the world does not exist 44 | */ 45 | @Override 46 | public @NotNull World parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 47 | return Optional.ofNullable(Bukkit.getWorld(rawArgument)) 48 | .orElseThrow(() -> new ArgumentException("commander.parameters.commander-world-does-not-exist")); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/command/invocation/BukkitInvocationFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.invocation; 2 | 3 | 4 | import dev.temez.springlify.commander.command.Command; 5 | import dev.temez.springlify.commander.command.sender.BukkitCommandSender; 6 | import lombok.AccessLevel; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.experimental.FieldDefaults; 9 | import org.bukkit.command.CommandSender; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * A factory class for creating instances of {@link CommandInvocation} specific to the Bukkit platform. 17 | * This class implements the {@link CommandInvocationFactory} interface. 18 | * 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Component 22 | @RequiredArgsConstructor 23 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 24 | public class BukkitInvocationFactory implements CommandInvocationFactory { 25 | 26 | /** 27 | * Creates a new {@link CommandInvocation} instance for the given command and arguments. 28 | * This method expects the first object in the arguments array to be a {@link CommandSender} 29 | * and the second object to be a {@link List} of {@link String} representing the command arguments. 30 | * 31 | * @param command the command for which the invocation is being created 32 | * @param objects the arguments for the command invocation, expecting a {@link CommandSender} and a {@link List} of {@link String} 33 | * @return a new {@link CommandInvocation} instance 34 | */ 35 | @Override 36 | @SuppressWarnings("unchecked") 37 | public @NotNull CommandInvocation create(@NotNull Command command, Object @NotNull ... objects) { 38 | return new CommandInvocationImpl( 39 | new BukkitCommandSender((CommandSender) objects[0]), 40 | command, 41 | (List) objects[1] 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/command/platform/BukkitCommandFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.platform; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.filter.CommandFilterService; 5 | import dev.temez.springlify.commander.service.CommandService; 6 | import lombok.AccessLevel; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.experimental.FieldDefaults; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * A factory class for creating instances of {@link CommanderBukkitCommand}. 14 | * This class implements the {@link PlatformCommandFactory} interface for {@link CommanderBukkitCommand}. 15 | * It uses the provided {@link CommandService} and {@link CommandFilterService} to create the command instances. 16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Component 20 | @RequiredArgsConstructor 21 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 22 | public class BukkitCommandFactory implements PlatformCommandFactory { 23 | 24 | @NotNull 25 | CommandService commandService; 26 | 27 | @NotNull 28 | CommandFilterService commandFilterService; 29 | 30 | /** 31 | * Creates a new instance of {@link CommanderBukkitCommand} for the given registered command. 32 | * 33 | * @param registeredCommand the command to create a {@link CommanderBukkitCommand} for 34 | * @return a new {@link CommanderBukkitCommand} instance 35 | */ 36 | @Override 37 | public @NotNull CommanderBukkitCommand create(@NotNull Command registeredCommand) { 38 | return new CommanderBukkitCommand(registeredCommand, commandService, commandFilterService); 39 | } 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/command/platform/BukkitCommandRegistrar.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.platform; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.experimental.FieldDefaults; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.command.CommandMap; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * A class responsible for registering Bukkit commands. 14 | * This class implements the {@link PlatformCommandRegistrar} interface specifically for {@link CommanderBukkitCommand}. 15 | * It registers the command with the Bukkit {@link CommandMap}. 16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Slf4j 20 | @Component 21 | @RequiredArgsConstructor 22 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 23 | public class BukkitCommandRegistrar implements PlatformCommandRegistrar { 24 | 25 | /** 26 | * Registers a Bukkit command with the Bukkit command map. 27 | * 28 | * @param platformCommand the Bukkit command to register 29 | */ 30 | @Override 31 | public void register(@NotNull CommanderBukkitCommand platformCommand) { 32 | CommandMap commandMap = Bukkit.getCommandMap(); 33 | commandMap.register("commander", platformCommand); 34 | log.debug("Registered {} as Bukkit command", platformCommand.getName()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/command/sender/BukkitCommandSender.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.sender; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.experimental.FieldDefaults; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.UUID; 12 | 13 | /** 14 | * A wrapper class for Bukkit's {@link CommandSender} that implements the {@link Sender} interface. 15 | * This class provides methods to interact with the command sender, including checking for permissions 16 | * and retrieving the sender's UUID. 17 | * 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Getter 21 | @RequiredArgsConstructor 22 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 23 | public class BukkitCommandSender implements Sender { 24 | 25 | /** 26 | * The underlying platform-specific command sender. 27 | */ 28 | @NotNull 29 | CommandSender platformSender; 30 | 31 | /** 32 | * Returns the UUID of the command sender if they are a player. 33 | * 34 | * @return the UUID of the player 35 | * @throws UnsupportedOperationException if the command sender is the console 36 | */ 37 | @Override 38 | public @NotNull UUID getUuid() throws UnsupportedOperationException { 39 | if (isConsoleSender()) { 40 | throw new UnsupportedOperationException("Command sender is console!"); 41 | } 42 | return ((Player) platformSender).getUniqueId(); 43 | } 44 | 45 | /** 46 | * Checks if the command sender is the console. 47 | * 48 | * @return {@code true} if the sender is the console, {@code false} otherwise 49 | */ 50 | @Override 51 | public boolean isConsoleSender() { 52 | return !(platformSender instanceof Player); 53 | } 54 | 55 | /** 56 | * Checks if the command sender has the specified permission. 57 | * 58 | * @param permission the permission to check 59 | * @return {@code true} if the sender has the permission, {@code false} otherwise 60 | */ 61 | @Override 62 | public boolean hasPermission(@NotNull String permission) { 63 | return platformSender.hasPermission(permission); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-bukkit/src/main/java/dev/temez/springlify/commander/initializer/BukkitCommandInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.initializer; 2 | 3 | import dev.temez.springlify.commander.command.discoverer.CommandDiscoverer; 4 | import dev.temez.springlify.commander.command.platform.CommanderBukkitCommand; 5 | import dev.temez.springlify.commander.command.platform.PlatformCommandFactory; 6 | import dev.temez.springlify.commander.command.platform.PlatformCommandRegistrar; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.springframework.context.annotation.Lazy; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Initializes and registers Bukkit-specific commands. 13 | * Extends {@link AbstractCommandInitializer} with {@link CommanderBukkitCommand} as the platform-specific command type. 14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | @Component 18 | public class BukkitCommandInitializer extends AbstractCommandInitializer { 19 | 20 | /** 21 | * Constructs a {@code BukkitCommandInitializer} with the specified dependencies. 22 | * 23 | * @param commandFactory the factory for creating Bukkit-specific commands 24 | * @param commandRegistrar the registrar for registering Bukkit-specific commands 25 | * @param commandDiscoverer the discoverer for discovering commands 26 | */ 27 | @Lazy 28 | public BukkitCommandInitializer( 29 | @NotNull PlatformCommandFactory commandFactory, 30 | @NotNull PlatformCommandRegistrar commandRegistrar, 31 | @NotNull CommandDiscoverer commandDiscoverer 32 | ) { 33 | super(commandFactory, commandRegistrar, commandDiscoverer); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/springlify-commander-commons.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | dependencies { 4 | api project(":springlify-platform:springlify-platform-commons") 5 | } -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/CommandRoot.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * Marks a method within a command handler class as the root command handler. 8 | *

9 | * The method annotated with {@code @CommandRoot} serves as the entry point for a command hierarchy. 10 | * When a command is executed, the method annotated with {@code @CommandRoot} is invoked first to handle the command. 11 | *

12 | * 13 | * @see CommanderCommand 14 | * @since 0.7.0.0-RC1 15 | */ 16 | @Documented 17 | @Retention(RetentionPolicy.RUNTIME) 18 | @Target(ElementType.METHOD) 19 | public @interface CommandRoot { 20 | 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/CommanderCommand.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation; 2 | 3 | import dev.temez.springlify.commander.command.CommandType; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * Marks a method or class as a command in the Commander framework. 11 | *

12 | * Commands annotated with {@code CommanderCommand} can be registered and executed by the Commander module. 13 | * This annotation provides metadata about the command such as its name, description, and aliases. 14 | *

15 | * 16 | * @see CommandType 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Component 20 | @Documented 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Target({ElementType.TYPE, ElementType.METHOD}) 23 | public @interface CommanderCommand { 24 | 25 | /** 26 | * Specifies the type of the command. 27 | * 28 | * @return the type of the command 29 | */ 30 | @NotNull CommandType type() default CommandType.SHARED; 31 | 32 | /** 33 | * Specifies the name of the command. 34 | * 35 | * @return the name of the command 36 | */ 37 | @NotNull String name(); 38 | 39 | /** 40 | * Provides a description of the command. 41 | * 42 | * @return the description of the command 43 | */ 44 | @NotNull String description() default ""; 45 | 46 | /** 47 | * Specifies alias names for the command. 48 | *

49 | * Aliases can be used as alternative names to invoke the command. 50 | *

51 | * 52 | * @return an array of alias names for the command 53 | */ 54 | @NotNull String[] alias() default {}; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/SenderDetailsSource.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation; 2 | 3 | import dev.temez.springlify.commander.command.sender.SenderDetailsFactory; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * Indicates that detailed sender information support should be enabled for a command method. 10 | *

11 | * Methods annotated with {@code @EnableDetailsSupport} will receive additional sender details 12 | * when invoked as part of a command execution. 13 | *

14 | *

15 | * The {@link SenderDetailsFactory} specified in the annotation value determines how sender details are constructed. 16 | *

17 | * 18 | * @see SenderDetailsFactory 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Documented 22 | @Retention(RetentionPolicy.RUNTIME) 23 | @Target(ElementType.METHOD) 24 | public @interface SenderDetailsSource { 25 | 26 | /** 27 | * Specifies the class of the sender details factory to be used for constructing sender details. 28 | * 29 | * @return The class of the sender details factory. 30 | */ 31 | @NotNull 32 | Class> value(); 33 | } 34 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/context/External.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.context; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * An annotation used to mark commander components as external. 7 | *

8 | * This annotation can be applied to filters, parameter adapters, and parameter completers to indicate that they are 9 | * external to the current module or system. 10 | *

11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | @Documented 15 | @Target(ElementType.TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface External { 18 | } 19 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/context/Global.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.context; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * An annotation used to mark commander components as global. 7 | *

8 | * This annotation can be applied to simple command filters to indicate that they are 9 | * global components, meaning they are available and applicable across all commands and contexts. 10 | *

11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | @Documented 15 | @Target(ElementType.TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface Global { 18 | } 19 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/filter/ApplyFilters.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.filter; 2 | 3 | import dev.temez.springlify.commander.command.filter.simple.SimpleCommandFilter; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * An annotation to apply filters to commands. 10 | *

11 | * This annotation is used to specify one or more filters to be applied to individual commands. 12 | *

13 | *

14 | * The {@code SimpleCommandFilter} type parameter specifies the type of filters that can be applied. 15 | *

16 | * 17 | * @see SimpleCommandFilter 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Documented 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Target(value = ElementType.METHOD) 23 | public @interface ApplyFilters { 24 | 25 | /** 26 | * Specifies one or more filters to be applied to the command. 27 | * 28 | * @return An array of filter classes to be applied. 29 | */ 30 | @NotNull 31 | Class[] value(); 32 | } 33 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/filter/RequirePermission.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.filter; 2 | 3 | import dev.temez.springlify.commander.command.filter.impl.RequirePermissionFilter; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.springframework.core.annotation.Order; 6 | 7 | import java.lang.annotation.*; 8 | 9 | 10 | /** 11 | * An annotation to specify a required permission for executing a command method. 12 | *

13 | * This annotation is used to specify a required permission for executing a command method. 14 | *

15 | *

16 | * The {@code value} attribute specifies the required permission. 17 | *

18 | * 19 | * @see RequirePermissionFilter 20 | * @since 0.7.0.0-RC1 21 | */ 22 | @Order() 23 | @Documented 24 | @ValidateWith(RequirePermissionFilter.class) 25 | @Retention(RetentionPolicy.RUNTIME) 26 | @Target(ElementType.METHOD) 27 | public @interface RequirePermission { 28 | 29 | /** 30 | * Specifies the required permission for executing the command method. 31 | * 32 | * @return The required permission. 33 | */ 34 | @NotNull 35 | String value(); 36 | } 37 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/filter/ValidateWith.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.filter; 2 | 3 | import dev.temez.springlify.commander.command.filter.CommandFilter; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.annotation.*; 7 | 8 | 9 | /** 10 | * An annotation to specify validation filters for command annotations. 11 | *

12 | * This annotation is used to specify a validation filter for command annotations. It can be applied to other annotations 13 | * to enforce validation rules on commands. 14 | *

15 | *

16 | * The {@code CommandFilter} type parameter specifies the type of validation filter to be applied. 17 | *

18 | * 19 | * @see CommandFilter 20 | * @since 0.7.0.0-RC1 21 | */ 22 | @Documented 23 | @Retention(RetentionPolicy.RUNTIME) 24 | @Target(value = ElementType.ANNOTATION_TYPE) 25 | public @interface ValidateWith { 26 | 27 | /** 28 | * Specifies the validation filter class to be applied. 29 | * 30 | * @return The class of the validation filter. 31 | */ 32 | @NotNull 33 | Class> value(); 34 | } 35 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/parameter/Adapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.parameter; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * An annotation used to specify an external parameter adapter for a method parameter. 10 | *

11 | * This annotation should be applied to method parameters in command methods to specify the adapter that will 12 | * convert the raw input string into the appropriate parameter type. 13 | *

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | @Documented 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Target(ElementType.PARAMETER) 20 | public @interface Adapter { 21 | 22 | /** 23 | * The class of the argument adapter to be used for this parameter. 24 | * 25 | * @return The class of the argument adapter. 26 | */ 27 | @NotNull Class> value(); 28 | } 29 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/annotation/parameter/Completer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.annotation.parameter; 2 | 3 | import dev.temez.springlify.commander.argument.completer.ParameterCompleter; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * An annotation used to specify an external parameter completer for a method parameter. 10 | *

11 | * This annotation should be applied to method parameters in command methods to specify the completer that will 12 | * provide completion suggestions for the parameter. 13 | *

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | @Documented 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Target(ElementType.PARAMETER) 20 | public @interface Completer { 21 | 22 | /** 23 | * The class of the argument completer to be used for this parameter. 24 | * 25 | * @return The class of the argument completer. 26 | */ 27 | @NotNull Class value(); 28 | } 29 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/argument/adapter/ParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter; 2 | 3 | import dev.temez.springlify.commander.argument.completer.ParameterCompleter; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Unmodifiable; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | 13 | /** 14 | * An interface for adapting raw command parameters into typed objects. 15 | *

16 | * Implementations of this interface are responsible for parsing raw command parameters into typed objects of type {@code T}. 17 | * They may also provide completion suggestions for command parameters. 18 | *

19 | * 20 | * @param The type of the object to which the raw argument will be adapted. 21 | * @see ParameterCompleter 22 | * @since 0.7.0.0-RC1 23 | */ 24 | public interface ParameterAdapter extends ParameterCompleter { 25 | 26 | /** 27 | * Parses the raw command parameter into a typed object of type {@code T}. 28 | * 29 | * @param commandSender The command sender from which the raw argument was received. 30 | * @param rawArgument The raw command parameter to parse. 31 | * @return The parsed object of type {@code T}. 32 | * @throws ArgumentException If an error occurs during parsing. 33 | */ 34 | @NotNull T parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException; 35 | 36 | /** 37 | * Generates a list of completion suggestions for the provided command sender. 38 | *

39 | * This default implementation returns an empty list, indicating that no completion suggestions are provided. 40 | *

41 | * 42 | * @param commandSender The command sender for whom completion suggestions are generated. 43 | * @return A list of completion suggestions. 44 | */ 45 | @Override 46 | default @Unmodifiable @NotNull List complete(@NotNull Sender commandSender) { 47 | return Collections.emptyList(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/FloatParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 6 | import lombok.AccessLevel; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.experimental.FieldDefaults; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * An {@link ParameterAdapter} implementation for parsing raw command parameters into {@code Float} objects. 14 | *

15 | * This adapter parses the raw command parameter into a {@code Float} using {@link Float#parseFloat(String)}. 16 | *

17 | * 18 | * @see ParameterAdapter 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Component 22 | @RequiredArgsConstructor 23 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 24 | public class FloatParameterAdapter implements ParameterAdapter { 25 | 26 | /** 27 | * Parses the raw command parameter into a {@code Float}. 28 | * 29 | * @param commandSender The command sender from which the raw argument was received. 30 | * @param rawArgument The raw command parameter to parse. 31 | * @return The parsed {@code Float}. 32 | * @throws ArgumentException If the raw argument cannot be parsed into a {@code Float}. 33 | */ 34 | @Override 35 | public @NotNull Float parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 36 | try { 37 | return Float.parseFloat(rawArgument); 38 | } catch (NumberFormatException e) { 39 | throw new ArgumentException("commander.parameters.parameters-must-be-float"); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/IntegerParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | 4 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 5 | import dev.temez.springlify.commander.command.sender.Sender; 6 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 7 | import lombok.AccessLevel; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.experimental.FieldDefaults; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * An {@link ParameterAdapter} implementation for parsing raw command parameters into {@code Integer} objects. 15 | *

16 | * This adapter parses the raw command parameter into an {@code Integer} using {@link Integer#parseInt(String)}. 17 | *

18 | * 19 | * @see ParameterAdapter 20 | * @since 0.7.0.0-RC1 21 | */ 22 | @Component 23 | @RequiredArgsConstructor 24 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 25 | public class IntegerParameterAdapter implements ParameterAdapter { 26 | 27 | /** 28 | * Parses the raw command parameter into an {@code Integer}. 29 | * 30 | * @param commandSender The command sender from which the raw argument was received. 31 | * @param rawArgument The raw command parameter to parse. 32 | * @return The parsed {@code Integer}. 33 | * @throws ArgumentException If the raw argument cannot be parsed into an {@code Integer}. 34 | */ 35 | @Override 36 | public @NotNull Integer parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 37 | try { 38 | return Integer.parseInt(rawArgument); 39 | } catch (NumberFormatException e) { 40 | throw new ArgumentException("commander.parameters.parameters-must-be-integer"); 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/argument/adapter/impl/StringParameterAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.impl; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 6 | import lombok.AccessLevel; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.experimental.FieldDefaults; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * An {@link ParameterAdapter} implementation for parsing raw command parameters into {@code String} objects. 14 | *

15 | * This adapter simply returns the raw command parameter as is, without any parsing. 16 | *

17 | * 18 | * @see ParameterAdapter 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Component 22 | @RequiredArgsConstructor 23 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 24 | public class StringParameterAdapter implements ParameterAdapter { 25 | 26 | /** 27 | * Parses the raw command parameter into a {@code String}. 28 | * 29 | * @param commandSender The command sender from which the raw argument was received. 30 | * @param rawArgument The raw command parameter to parse. 31 | * @return The parsed {@code String}. 32 | * @throws ArgumentException If an error occurs during parsing. 33 | */ 34 | @Override 35 | public @NotNull String parse(@NotNull Sender commandSender, @NotNull String rawArgument) throws ArgumentException { 36 | return rawArgument; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/argument/adapter/resolver/ParameterAdapterResolver.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.adapter.resolver; 2 | 3 | import dev.temez.springlify.commander.argument.adapter.ParameterAdapter; 4 | import dev.temez.springlify.commander.exception.argument.ArgumentAdapterException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | 8 | /** 9 | * An interface for resolving parameter adapters based on the parameter type. 10 | *

11 | * Implementations of this interface provide a mechanism for obtaining the appropriate parameter adapter 12 | * for a given parameter type. 13 | *

14 | * 15 | * @see ParameterAdapter 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface ParameterAdapterResolver { 19 | 20 | /** 21 | * Retrieves the parameter adapter for the specified parameter type. 22 | * 23 | * @param parameterType The class representing the type of parameter for which an adapter is needed. 24 | * @param The type of the parameter. 25 | * @return The parameter adapter for the specified parameter type. 26 | * @throws ArgumentAdapterException If a parameter adapter cannot be resolved for the specified type. 27 | */ 28 | @NotNull ParameterAdapter getAdapter(@NotNull Class parameterType) throws ArgumentAdapterException; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/argument/completer/ParameterCompleter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.argument.completer; 2 | 3 | import dev.temez.springlify.commander.command.sender.Sender; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * An interface for providing completion suggestions for command parameters. 11 | *

12 | * Implementations of this interface are responsible for generating a list of completion suggestions 13 | * based on the input provided by the command sender. 14 | *

15 | * 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface ParameterCompleter { 19 | 20 | /** 21 | * Generates a list of completion suggestions for the provided command sender. 22 | * 23 | * @param commandSender The command sender for whom completion suggestions are generated. 24 | * @return A list of completion suggestions. 25 | */ 26 | @Unmodifiable 27 | @NotNull List complete(@NotNull Sender commandSender); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/Command.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command; 2 | 3 | import dev.temez.springlify.commander.command.metadata.CommandInvocationMetadata; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Interface representing a command. 11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | public interface Command { 15 | 16 | /** 17 | * Retrieves the parent command of this command. 18 | * 19 | * @return The parent command. 20 | */ 21 | @NotNull 22 | Command getParentCommand(); 23 | 24 | /** 25 | * Sets the parent command of this command. 26 | * 27 | * @param command The parent command to set. 28 | */ 29 | void setParentCommand(@NotNull Command command); 30 | 31 | /** 32 | * Retrieves the name of the command. 33 | * 34 | * @return The name of the command. 35 | */ 36 | @NotNull 37 | String getName(); 38 | 39 | /** 40 | * Retrieves the description of the command. 41 | * 42 | * @return The description of the command. 43 | */ 44 | @NotNull 45 | String getDescription(); 46 | 47 | /** 48 | * Retrieves the aliases of the command. 49 | * 50 | * @return An unmodifiable list of aliases. 51 | */ 52 | @NotNull 53 | @Unmodifiable 54 | List getAlias(); 55 | 56 | /** 57 | * Retrieves the type of the command. 58 | * 59 | * @return The type of the command. 60 | */ 61 | @NotNull 62 | CommandType getType(); 63 | 64 | /** 65 | * Retrieves the subcommands of the command. 66 | * 67 | * @return An unmodifiable list of subcommands. 68 | */ 69 | @NotNull 70 | @Unmodifiable 71 | List getSubcommands(); 72 | 73 | /** 74 | * Retrieves the metadata associated with the command invocation. 75 | * 76 | * @return The metadata associated with the command invocation. 77 | */ 78 | @NotNull 79 | CommandInvocationMetadata getCommandInvocationMetadata(); 80 | 81 | /** 82 | * Retrieves the root command of the command hierarchy. 83 | * 84 | * @return The root command of the hierarchy. 85 | */ 86 | @NotNull 87 | Command getRootCommand(); 88 | 89 | /** 90 | * Retrieves the full name of the command, including its parent commands (if any). 91 | * 92 | * @return The full name of the command. 93 | */ 94 | @NotNull 95 | String getFullName(); 96 | } 97 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/CommandImpl.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command; 2 | 3 | import dev.temez.springlify.commander.command.metadata.CommandInvocationMetadata; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.Setter; 8 | import lombok.experimental.FieldDefaults; 9 | import lombok.experimental.NonFinal; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | /** 19 | * Implementation of {@link Command}. 20 | * 21 | * @since 0.7.0.0-RC1 22 | */ 23 | @Getter 24 | @RequiredArgsConstructor 25 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 26 | public class CommandImpl implements Command { 27 | 28 | @NotNull 29 | String name; 30 | 31 | @NotNull 32 | String description; 33 | 34 | @NotNull 35 | List alias; 36 | 37 | @NotNull 38 | CommandType type; 39 | 40 | @NotNull 41 | List subcommands; 42 | 43 | @NotNull 44 | CommandInvocationMetadata commandInvocationMetadata; 45 | 46 | @Setter 47 | @Nullable 48 | @NonFinal 49 | Command parentCommand; 50 | 51 | /** 52 | * Retrieves the root command of the command hierarchy. 53 | * 54 | * @return The root command of the hierarchy. 55 | */ 56 | @Override 57 | public @NotNull Command getRootCommand() { 58 | Command command = this; 59 | while (command.getParentCommand() != null) { 60 | command = command.getParentCommand(); 61 | } 62 | return command; 63 | } 64 | 65 | /** 66 | * Retrieves the full name of the command, including its parent commands (if any). 67 | * 68 | * @return The full name of the command. 69 | */ 70 | @Override 71 | public @NotNull String getFullName() { 72 | List commandChain = new ArrayList<>(); 73 | Command command = this; 74 | commandChain.add(command); 75 | while (command.getParentCommand() != null) { 76 | commandChain.add(command.getParentCommand()); 77 | command = command.getParentCommand(); 78 | } 79 | Collections.reverse(commandChain); 80 | return commandChain.stream().map(Command::getName).collect(Collectors.joining(" ")); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/CommandType.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command; 2 | 3 | /** 4 | * Enumerates the types of commands supported by the Commander framework. 5 | *

6 | * Each command can be categorized into one of the supported types: in-game commands, 7 | * shared commands (usable by both in-game and console), or console commands. 8 | *

9 | * 10 | * @since 0.7.0.0-RC1 11 | */ 12 | public enum CommandType { 13 | 14 | /** 15 | * Represents an in-game command, usable only by players in the game. 16 | */ 17 | INGAME, 18 | 19 | /** 20 | * Represents a shared command, usable by both players in-game and from the console. 21 | */ 22 | SHARED, 23 | 24 | /** 25 | * Represents a console command, usable only from the server console. 26 | */ 27 | CONSOLE 28 | } 29 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/completer/CommandCompleter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.completer; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Interface for command completers that provide completion suggestions for commands. 11 | *

12 | * Implementations of this interface are responsible for generating completion suggestions 13 | * based on the current state of the command invocation. 14 | *

15 | * 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface CommandCompleter { 19 | 20 | /** 21 | * Provides a list of completion suggestions for the given command invocation. 22 | * 23 | * @param commandInvocation The current state of the command invocation. 24 | * @return An unmodifiable list of completion suggestions. 25 | */ 26 | @NotNull @Unmodifiable List complete(@NotNull CommandInvocation commandInvocation); 27 | 28 | /** 29 | * Provides a sorted list of completion suggestions for the given command invocation. 30 | * 31 | * @param commandInvocation The current state of the command invocation. 32 | * @return An unmodifiable and sorted list of completion suggestions. 33 | */ 34 | @NotNull @Unmodifiable List completeSorted(@NotNull CommandInvocation commandInvocation); 35 | } 36 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/completer/provider/CompletionProvider.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.completer.provider; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * An interface defining a provider for command completion suggestions. 11 | *

12 | * Implementations of this interface should provide logic to determine if they support a given 13 | * command invocation and to generate completion suggestions for it. 14 | *

15 | * 16 | * @see CommandInvocation 17 | * @since 0.7.0.0-RC1 18 | */ 19 | public interface CompletionProvider { 20 | 21 | /** 22 | * Determines whether this provider supports the given command invocation. 23 | * 24 | * @param commandInvocation The current state of the command invocation. 25 | * @return {@code true} if this provider supports the given command invocation, {@code false} otherwise. 26 | */ 27 | boolean supports(@NotNull CommandInvocation commandInvocation); 28 | 29 | /** 30 | * Generates a list of completion suggestions for the given command invocation. 31 | * 32 | * @param commandInvocation The current state of the command invocation. 33 | * @return An unmodifiable list of completion suggestions. 34 | */ 35 | @NotNull @Unmodifiable List complete(@NotNull CommandInvocation commandInvocation); 36 | } 37 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/discoverer/CommandDiscoverer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.discoverer; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.exception.discovery.CommandDiscoveryException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Interface for discovering commands. 9 | * 10 | * @since 0.7.0.0-RC1 11 | */ 12 | public interface CommandDiscoverer { 13 | 14 | /** 15 | * Discovers the command associated with the given executor. 16 | * 17 | * @param executor the executor for which to discover the command 18 | * @return the discovered command 19 | * @throws CommandDiscoveryException if an error occurs during command discovery 20 | */ 21 | @NotNull Command discover(@NotNull Object executor) throws CommandDiscoveryException; 22 | } 23 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/discoverer/ProviderSubcommandDiscoverer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.discoverer; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.discoverer.provider.SubcommandDiscoveryProvider; 5 | import dev.temez.springlify.commander.exception.discovery.CommandDiscoveryException; 6 | import lombok.AccessLevel; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.experimental.FieldDefaults; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | /** 16 | * Component for discovering subcommands using multiple providers. 17 | * 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Component 21 | @RequiredArgsConstructor 22 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 23 | public class ProviderSubcommandDiscoverer implements SubcommandDiscoverer { 24 | 25 | /** 26 | * List of subcommand discovery providers. 27 | */ 28 | @NotNull 29 | List providers; 30 | 31 | /** 32 | * Discovers subcommands associated with the given executor. 33 | * 34 | * @param executor the executor for which to discover subcommands 35 | * @return a list of discovered subcommands 36 | * @throws CommandDiscoveryException if an error occurs during subcommand discovery 37 | */ 38 | @Override 39 | public @NotNull List discover(@NotNull Object executor) throws CommandDiscoveryException { 40 | return providers.stream() 41 | .filter(provider -> provider.supports(executor)) 42 | .map(provider -> provider.discover(executor)) 43 | .flatMap(Collection::stream) 44 | .toList(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/discoverer/SubcommandDiscoverer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.discoverer; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.exception.discovery.CommandDiscoveryException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Interface for discovering subcommands associated with an executor. 11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | public interface SubcommandDiscoverer { 15 | 16 | /** 17 | * Discovers subcommands associated with the given executor. 18 | * 19 | * @param executor the executor for which to discover subcommands 20 | * @return a list of discovered subcommands 21 | * @throws CommandDiscoveryException if an error occurs during subcommand discovery 22 | */ 23 | @NotNull List discover(@NotNull Object executor) throws CommandDiscoveryException; 24 | } 25 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/discoverer/provider/SubcommandDiscoveryProvider.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.discoverer.provider; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.exception.discovery.CommandDiscoveryException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Interface for providing subcommand discovery based on an executor. 11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | public interface SubcommandDiscoveryProvider { 15 | 16 | /** 17 | * Checks if the provider supports discovering subcommands for the given executor. 18 | * 19 | * @param executor the executor to check support for 20 | * @return {@code true} if the provider supports the executor, {@code false} otherwise 21 | */ 22 | boolean supports(@NotNull Object executor); 23 | 24 | /** 25 | * Discovers subcommands associated with the given executor. 26 | * 27 | * @param executor the executor for which to discover subcommands 28 | * @return a list of discovered subcommands 29 | * @throws CommandDiscoveryException if an error occurs during subcommand discovery 30 | */ 31 | @NotNull List discover(@NotNull Object executor) throws CommandDiscoveryException; 32 | } 33 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/executor/CommandExecutor.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.executor; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import dev.temez.springlify.commander.exception.CommandExecutionException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | /** 10 | * An interface representing a command executor responsible for executing commands. 11 | *

12 | * Implementations of this interface handle the execution logic for commands based on the provided {@link CommandInvocation}. 13 | *

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | public interface CommandExecutor { 18 | 19 | /** 20 | * Executes a command based on the provided {@link CommandInvocation}. 21 | *

22 | * This method processes the command invocation and performs the necessary actions defined by the command. 23 | * Implementations should handle any exceptions that occur during execution. 24 | *

25 | * 26 | * @param commandInvocation The command invocation containing the details of the command to be executed. 27 | * @throws CommandExecutionException If an error occurs during command execution. 28 | */ 29 | void execute(@NotNull CommandInvocation commandInvocation) throws CommandExecutionException, InvocationTargetException; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/executor/details/ProviderSenderDetailsResolver.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.executor.details; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.executor.details.provider.SenderDetailsProvider; 5 | import dev.temez.springlify.commander.command.sender.Sender; 6 | import dev.temez.springlify.commander.exception.details.SenderDetailsException; 7 | import lombok.AccessLevel; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.experimental.FieldDefaults; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * Implementation of {@link SenderDetailsResolver} that delegates the resolution to a list of {@link SenderDetailsProvider}s. 17 | * 18 | * @see SenderDetailsProvider 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Component 22 | @RequiredArgsConstructor 23 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 24 | public class ProviderSenderDetailsResolver implements SenderDetailsResolver { 25 | 26 | @NotNull 27 | List providers; 28 | 29 | /** 30 | * Resolves details about the sender of the given command by delegating to a list of {@link SenderDetailsProvider}s. 31 | * 32 | * @param command The command whose sender details are to be resolved. 33 | * @param sender The sender of the command. 34 | * @return The resolved sender details. 35 | * @throws SenderDetailsException If an error occurs while resolving sender details. 36 | */ 37 | @Override 38 | public @NotNull Object resolve(@NotNull Command command, @NotNull Sender sender) throws SenderDetailsException { 39 | List supportedProviders = providers.stream() 40 | .filter(provider -> provider.supports(command)) 41 | .toList(); 42 | if (supportedProviders.isEmpty()) { 43 | throw new SenderDetailsException("No matching provider found for command method %s" 44 | .formatted(command.getCommandInvocationMetadata().getCommandMethod())); 45 | } 46 | if (supportedProviders.size() > 1) { 47 | throw new SenderDetailsException("No unique provider found for command method %s" 48 | .formatted(command.getCommandInvocationMetadata().getCommandMethod())); 49 | } 50 | return supportedProviders.get(0).getSenderDetails(command, sender); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/executor/details/SenderDetailsResolver.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.executor.details; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.details.SenderDetailsException; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Interface for resolving details about the sender of a command. 10 | * 11 | * @since 0.7.0.0-RC1 12 | */ 13 | public interface SenderDetailsResolver { 14 | 15 | /** 16 | * Resolves details about the sender of the given command. 17 | * 18 | * @param command The command whose sender details are to be resolved. 19 | * @param sender The sender of the command. 20 | * @return The resolved sender details. 21 | * @throws SenderDetailsException If an error occurs while resolving sender details. 22 | */ 23 | @NotNull 24 | Object resolve(@NotNull Command command, @NotNull Sender sender) throws SenderDetailsException; 25 | } 26 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/executor/details/provider/SenderDetailsProvider.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.executor.details.provider; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * A provider interface for resolving details about the sender of a command. 9 | *

10 | * Implementations of this interface determine whether they support a specific command and provide a way to resolve sender details for that command. 11 | *

12 | * 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface SenderDetailsProvider { 16 | 17 | /** 18 | * Determines whether this provider supports the given command. 19 | * 20 | * @param command The command to check support for. 21 | * @return {@code true} if this provider supports the command, {@code false} otherwise. 22 | */ 23 | boolean supports(@NotNull Command command); 24 | 25 | /** 26 | * Resolves details about the sender of the given command. 27 | * 28 | * @param command The command whose sender details are to be resolved. 29 | * @param sender The sender of the command. 30 | * @return An object containing details about the sender. 31 | */ 32 | @NotNull Object getSenderDetails(@NotNull Command command, @NotNull Sender sender); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/executor/details/provider/impl/GenericSenderDetailsProvider.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.executor.details.provider.impl; 2 | 3 | import dev.temez.springlify.commander.annotation.SenderDetailsSource; 4 | import dev.temez.springlify.commander.command.Command; 5 | import dev.temez.springlify.commander.command.executor.details.provider.SenderDetailsProvider; 6 | import dev.temez.springlify.commander.command.sender.Sender; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * A generic implementation of the {@link SenderDetailsProvider} interface. 12 | *

13 | * This provider supports all commands and resolves sender details by returning the platform-specific sender object. 14 | *

15 | * 16 | * @see SenderDetailsProvider 17 | * @see Sender 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Component 21 | public class GenericSenderDetailsProvider implements SenderDetailsProvider { 22 | 23 | /** 24 | * Determines whether this provider supports the given command. 25 | * 26 | * @param command The command to check support for. 27 | * @return {@code true} indicating that this provider supports all commands. 28 | */ 29 | @Override 30 | public boolean supports(@NotNull Command command) { 31 | return !command.getCommandInvocationMetadata().getCommandMethod().isAnnotationPresent(SenderDetailsSource.class); 32 | } 33 | 34 | /** 35 | * Resolves details about the sender of the given command. 36 | * 37 | * @param command The command whose sender details are to be resolved. 38 | * @param sender The sender of the command. 39 | * @return The platform-specific sender object. 40 | */ 41 | @Override 42 | @NotNull 43 | public Object getSenderDetails(@NotNull Command command, @NotNull Sender sender) { 44 | return sender.getPlatformSender(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/executor/provider/ParameterProvider.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.executor.provider; 2 | 3 | import dev.temez.springlify.commander.command.sender.Sender; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.reflect.Parameter; 7 | 8 | /** 9 | * A provider interface for parsing command parameters. 10 | *

11 | * Implementations of this interface are responsible for parsing raw arguments into 12 | * appropriate parameter types based on the method parameter definition. 13 | *

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | public interface ParameterProvider { 18 | 19 | /** 20 | * Parses the raw argument into the appropriate parameter type. 21 | * 22 | * @param sender The sender of the command. 23 | * @param rawArgument The raw argument to be parsed. 24 | * @param parameter The method parameter definition. 25 | * @return The parsed parameter object. 26 | */ 27 | @NotNull 28 | Object parse(@NotNull Sender sender, @NotNull String rawArgument, @NotNull Parameter parameter); 29 | 30 | /** 31 | * Checks if the provider supports parsing for the given parameter. 32 | * 33 | * @param parameter The method parameter definition. 34 | * @return {@code true} if the provider supports parsing for the parameter, {@code false} otherwise. 35 | */ 36 | boolean supports(@NotNull Parameter parameter); 37 | } 38 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/CommandFilter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter; 2 | 3 | import dev.temez.springlify.commander.command.sender.Sender; 4 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.lang.annotation.Annotation; 8 | 9 | /** 10 | * Represents a command filter that operates based on an annotation type. 11 | * 12 | * @param The type of annotation associated with the filter. 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface CommandFilter { 16 | 17 | /** 18 | * Performs filtering based on the provided annotation. 19 | * 20 | * @param sender The sender executing the command. 21 | * @param annotation The annotation associated with the filter. 22 | * @throws CommandFilterException If an error occurs during the filtering process. 23 | */ 24 | void doFilter(@NotNull Sender sender, @NotNull A annotation) throws CommandFilterException; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/CommandFilterService.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Service interface for command filtering operations. 10 | * 11 | * @since 0.7.0.0-RC1 12 | */ 13 | public interface CommandFilterService { 14 | 15 | /** 16 | * Filters the command execution based on the sender and the command. 17 | * 18 | * @param sender The sender executing the command. 19 | * @param command The command being executed. 20 | * @throws CommandFilterException If an error occurs during the filtering process. 21 | */ 22 | void filter(@NotNull Sender sender, @NotNull Command command) throws CommandFilterException; 23 | 24 | /** 25 | * Checks if the sender has access to execute the given command. 26 | * 27 | * @param sender The sender executing the command. 28 | * @param command The command to check accessibility for. 29 | * @return {@code true} if the sender has access to execute the command, {@code false} otherwise. 30 | */ 31 | boolean isAccessible(@NotNull Sender sender, @NotNull Command command); 32 | } 33 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/ProviderCommandFilterService.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.filter.provider.CommandFilterProvider; 5 | import dev.temez.springlify.commander.command.sender.Sender; 6 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 7 | import lombok.AccessLevel; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.experimental.FieldDefaults; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * Service implementation for filtering command execution. 17 | * 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Service 21 | @RequiredArgsConstructor 22 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 23 | public class ProviderCommandFilterService implements CommandFilterService { 24 | 25 | @NotNull 26 | List providers; 27 | 28 | /** 29 | * Filters the command execution based on the sender and the command. 30 | * 31 | * @param sender The sender executing the command. 32 | * @param command The command being executed. 33 | * @throws CommandFilterException If an error occurs during the filtering process. 34 | */ 35 | @Override 36 | public void filter(@NotNull Sender sender, @NotNull Command command) throws CommandFilterException { 37 | providers.stream() 38 | .filter(provider -> provider.supports(command)) 39 | .forEach(provider -> provider.filter(sender, command)); 40 | } 41 | 42 | /** 43 | * Checks if the sender has access to execute the given command. 44 | * 45 | * @param sender The sender executing the command. 46 | * @param command The command to check accessibility for. 47 | * @return {@code true} if the sender has access to execute the command, {@code false} otherwise. 48 | */ 49 | @Override 50 | public boolean isAccessible(@NotNull Sender sender, @NotNull Command command) { 51 | try { 52 | filter(sender, command); 53 | return true; 54 | } catch (CommandFilterException exception) { 55 | return false; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/impl/RequirePermissionFilter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter.impl; 2 | 3 | 4 | import dev.temez.springlify.commander.annotation.filter.RequirePermission; 5 | import dev.temez.springlify.commander.command.filter.CommandFilter; 6 | import dev.temez.springlify.commander.command.sender.Sender; 7 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * A command filter implementation for the {@link RequirePermission} annotation. 13 | *

14 | * This filter checks if the sender has the required permission specified in the {@link RequirePermission} annotation. 15 | *

16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Component 20 | public class RequirePermissionFilter implements CommandFilter { 21 | 22 | /** 23 | * Performs the filtering logic based on the {@link RequirePermission} annotation. 24 | * 25 | * @param sender The sender of the command. 26 | * @param annotation The {@link RequirePermission} annotation specifying the required permission. 27 | * @throws CommandFilterException If the sender does not have the required permission. 28 | */ 29 | @Override 30 | public void doFilter(@NotNull Sender sender, @NotNull RequirePermission annotation) throws CommandFilterException { 31 | if (!sender.hasPermission(annotation.value())) { 32 | throw new CommandFilterException("commander.filter.permission.no-permission"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/provider/CommandFilterProvider.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter.provider; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * A provider interface for filtering commands before execution. 10 | *

11 | * Implementations of this interface can determine whether a command is supported and apply filtering logic 12 | * based on various criteria such as the sender, the command itself, or any other contextual information. 13 | *

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | public interface CommandFilterProvider { 18 | 19 | /** 20 | * Checks if the provider supports the given command. 21 | * 22 | * @param command The command to check. 23 | * @return {@code true} if the provider supports the command, {@code false} otherwise. 24 | */ 25 | boolean supports(@NotNull Command command); 26 | 27 | /** 28 | * Filters a command before its execution. 29 | *

30 | * This method applies filtering logic to the given command based on the sender and any other relevant 31 | * contextual information. If the command is not allowed to execute, a {@link CommandFilterException} may be thrown. 32 | *

33 | * 34 | * @param sender The sender of the command. 35 | * @param command The command to filter. 36 | * @throws CommandFilterException If the command is not allowed to execute based on the applied filtering criteria. 37 | */ 38 | void filter(@NotNull Sender sender, @NotNull Command command) throws CommandFilterException; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/resolver/CommandFilterResolver.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter.resolver; 2 | 3 | import dev.temez.springlify.commander.command.filter.CommandFilter; 4 | import dev.temez.springlify.commander.exception.filter.CommandFilterNotFoundException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.lang.annotation.Annotation; 8 | 9 | /** 10 | * Resolves command filters based on annotations. 11 | * 12 | * @see CommandFilter 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface CommandFilterResolver { 16 | 17 | /** 18 | * Retrieves a command filter based on its annotation class. 19 | * 20 | * @param
The type of the annotation. 21 | * @param annotation The annotation class. 22 | * @return The command filter corresponding to the annotation class. 23 | * @throws CommandFilterNotFoundException If no command filter is found for the given annotation class. 24 | */ 25 | @NotNull CommandFilter getFilter(@NotNull Class annotation) throws CommandFilterNotFoundException; 26 | 27 | /** 28 | * Retrieves a command filter based on its annotation instance. 29 | * 30 | * @param The type of the annotation. 31 | * @param annotation The annotation instance. 32 | * @return The command filter corresponding to the annotation instance. 33 | * @throws CommandFilterNotFoundException If no command filter is found for the given annotation. 34 | */ 35 | @NotNull CommandFilter getFilter(@NotNull A annotation) throws CommandFilterNotFoundException; 36 | } 37 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/simple/SimpleCommandFilter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter.simple; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Interface for implementing simple command filters. 10 | * 11 | * @since 0.7.0.0-RC1 12 | */ 13 | public interface SimpleCommandFilter { 14 | 15 | /** 16 | * Performs filtering on the command execution. 17 | * 18 | * @param sender The sender executing the command. 19 | * @param command The command being executed. 20 | * @throws CommandFilterException If an error occurs during the filtering process. 21 | */ 22 | void doFilter(@NotNull Sender sender, @NotNull Command command) throws CommandFilterException; 23 | } 24 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/filter/simple/impl/CommandSourceFilter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.filter.simple.impl; 2 | 3 | import dev.temez.springlify.commander.annotation.context.Global; 4 | import dev.temez.springlify.commander.command.Command; 5 | import dev.temez.springlify.commander.command.CommandType; 6 | import dev.temez.springlify.commander.command.filter.simple.SimpleCommandFilter; 7 | import dev.temez.springlify.commander.command.sender.Sender; 8 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 9 | import lombok.RequiredArgsConstructor; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * A global command filter that restricts command execution based on the command source. 15 | * 16 | * @since 0.7.0.0-RC1 17 | */ 18 | @Global 19 | @Component 20 | @RequiredArgsConstructor 21 | public class CommandSourceFilter implements SimpleCommandFilter { 22 | 23 | /** 24 | * Performs filtering based on the command source. 25 | * 26 | * @param sender The sender executing the command. 27 | * @param command The command being executed. 28 | * @throws CommandFilterException If the command source is not allowed for the given command. 29 | */ 30 | @Override 31 | public void doFilter(@NotNull Sender sender, @NotNull Command command) throws CommandFilterException { 32 | if (sender.isConsoleSender() && command.getType() == CommandType.INGAME) { 33 | throw new CommandFilterException("commander.filter.command-source.available-only-from-game"); 34 | } 35 | if (!sender.isConsoleSender() && command.getType() == CommandType.CONSOLE) { 36 | throw new CommandFilterException("commander.filter.command-source.available-only-from-console"); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/invocation/CommandInvocation.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.invocation; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Unmodifiable; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Interface representing a command invocation. 12 | * 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface CommandInvocation { 16 | 17 | /** 18 | * Retrieves the sender of the command invocation. 19 | * 20 | * @return The sender of the command invocation. 21 | */ 22 | @NotNull Sender getSender(); 23 | 24 | /** 25 | * Retrieves the command associated with the invocation. 26 | * 27 | * @return The command associated with the invocation. 28 | */ 29 | @NotNull Command getCommand(); 30 | 31 | /** 32 | * Sets the command associated with the invocation. 33 | * 34 | * @param command The command to set. 35 | */ 36 | void setCommand(@NotNull Command command); 37 | 38 | /** 39 | * Retrieves the arguments passed with the command invocation. 40 | * 41 | * @return An unmodifiable list of arguments. 42 | */ 43 | @NotNull @Unmodifiable List getArguments(); 44 | 45 | /** 46 | * Sets the arguments for the command invocation. 47 | * 48 | * @param args The arguments to set. 49 | */ 50 | void setArguments(@NotNull List args); 51 | 52 | /** 53 | * Retrieves the index of the last argument. 54 | * 55 | * @return The index of the last argument. 56 | */ 57 | int getLastArgumentIndex(); 58 | 59 | /** 60 | * Retrieves the last argument. 61 | * 62 | * @return The last argument. 63 | * @throws IndexOutOfBoundsException If there are no arguments. 64 | */ 65 | @NotNull String getLastArgument() throws IndexOutOfBoundsException; 66 | } 67 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/invocation/CommandInvocationFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.invocation; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Factory interface for creating command invocations. 8 | * 9 | * @since 0.7.0.0-RC1 10 | */ 11 | public interface CommandInvocationFactory { 12 | 13 | /** 14 | * Creates a command invocation with the specified registered command and additional objects. 15 | * 16 | * @param registeredCommand The registered command for the invocation. 17 | * @param objects Additional objects associated with the invocation. 18 | * @return A command invocation. 19 | */ 20 | @NotNull CommandInvocation create(@NotNull Command registeredCommand, Object @NotNull ... objects); 21 | } 22 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/invocation/CommandInvocationImpl.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.invocation; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.sender.Sender; 5 | import lombok.AccessLevel; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.Setter; 9 | import lombok.experimental.FieldDefaults; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Implementation of {@link CommandInvocation}. 16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Getter 20 | @RequiredArgsConstructor 21 | @FieldDefaults(level = AccessLevel.PRIVATE) 22 | public class CommandInvocationImpl implements CommandInvocation { 23 | 24 | @NotNull 25 | final Sender sender; 26 | 27 | @NotNull 28 | @Setter 29 | Command command; 30 | 31 | @NotNull 32 | @Setter 33 | List arguments; 34 | 35 | /** 36 | * Retrieves the index of the last argument. 37 | * 38 | * @return The index of the last argument. 39 | */ 40 | @Override 41 | public int getLastArgumentIndex() { 42 | return arguments.isEmpty() ? 0 : arguments.size() - 1; 43 | } 44 | 45 | /** 46 | * Retrieves the last argument. 47 | * 48 | * @return The last argument. 49 | * @throws IndexOutOfBoundsException If there are no arguments. 50 | */ 51 | @Override 52 | public @NotNull String getLastArgument() throws IndexOutOfBoundsException { 53 | return arguments.get(getLastArgumentIndex()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/metadata/CommandInvocationMetadata.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.metadata; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Unmodifiable; 5 | 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Parameter; 8 | import java.util.List; 9 | 10 | /** 11 | * Interface representing metadata associated with a command invocation. 12 | * 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface CommandInvocationMetadata { 16 | 17 | /** 18 | * Retrieves the executor of the command. 19 | * 20 | * @return The executor of the command. 21 | */ 22 | @NotNull Object getExecutor(); 23 | 24 | /** 25 | * Retrieves the method associated with the command. 26 | * 27 | * @return The method associated with the command. 28 | */ 29 | Method getCommandMethod(); 30 | 31 | /** 32 | * Retrieves the parameters of the command method. 33 | * 34 | * @return An unmodifiable list of parameters. 35 | * @throws UnsupportedOperationException If parameter retrieval is not supported. 36 | */ 37 | @NotNull @Unmodifiable List getParameters() throws UnsupportedOperationException; 38 | 39 | /** 40 | * Retrieves the parameter at the specified index. 41 | * 42 | * @param index The index of the parameter. 43 | * @return The parameter at the specified index. 44 | * @throws IllegalArgumentException If the index is invalid. 45 | * @throws UnsupportedOperationException If parameter retrieval is not supported. 46 | */ 47 | @NotNull Parameter getParameter(int index) throws IllegalArgumentException, UnsupportedOperationException; 48 | 49 | /** 50 | * Retrieves the count of parameters associated with the command method. 51 | * 52 | * @return The count of parameters. 53 | * @throws UnsupportedOperationException If parameter count retrieval is not supported. 54 | */ 55 | int getParameterCount() throws UnsupportedOperationException; 56 | } 57 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/platform/PlatformCommandFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.platform; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Generic factory interface for creating platform-specific commands. 8 | * 9 | * @param The type of platform-specific command to create. 10 | * @since 0.7.0.0-RC1 11 | */ 12 | public interface PlatformCommandFactory { 13 | 14 | /** 15 | * Creates a platform-specific command for the given registered command. 16 | * 17 | * @param registeredCommand The registered command. 18 | * @return A platform-specific command of type T. 19 | */ 20 | @NotNull 21 | T create(@NotNull Command registeredCommand); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/platform/PlatformCommandRegistrar.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.platform; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Generic interface for registering platform-specific commands. 7 | * 8 | * @param The type of platform-specific command to register. 9 | * @since 0.7.0.0-RC1 10 | */ 11 | public interface PlatformCommandRegistrar { 12 | 13 | /** 14 | * Registers the platform-specific command. 15 | * 16 | * @param platformCommand The platform-specific command to register. 17 | */ 18 | void register(@NotNull T platformCommand); 19 | } 20 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/preprocessor/ExecutionPreprocessorService.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.preprocessor; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Service interface for pre-processing command executions. 8 | *

9 | * Implementations of this interface can perform pre-processing tasks on command invocations 10 | * before their execution, such as validation, normalization, or modification of command parameters. 11 | *

12 | * 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface ExecutionPreprocessorService { 16 | 17 | /** 18 | * Processes the given command invocation before execution. 19 | * 20 | * @param commandInvocation The command invocation to preprocess. 21 | */ 22 | void process(@NotNull CommandInvocation commandInvocation); 23 | } 24 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/preprocessor/ExecutionPreprocessorServiceImpl.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.preprocessor; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import dev.temez.springlify.commander.exception.CommandException; 5 | import lombok.AccessLevel; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.experimental.FieldDefaults; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.core.annotation.Order; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.Comparator; 14 | import java.util.List; 15 | import java.util.Optional; 16 | import java.util.stream.Collectors; 17 | 18 | /** 19 | * Implementation of {@link ExecutionPreprocessorService} for pre-processing command executions. 20 | *

21 | * This service orchestrates the pre-processing of command invocations by delegating to registered {@link InvocationPreprocessor} instances. 22 | *

23 | * 24 | * @since 0.7.0.0-RC1 25 | */ 26 | @Slf4j 27 | @Service 28 | @RequiredArgsConstructor 29 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 30 | public class ExecutionPreprocessorServiceImpl implements ExecutionPreprocessorService { 31 | 32 | @NotNull 33 | List invocationPreprocessors; 34 | 35 | /** 36 | * Processes the given command invocation by executing pre-processing steps. 37 | * 38 | * @param commandInvocation The command invocation to preprocess. 39 | * @throws CommandException If an error occurs during the pre-processing. 40 | */ 41 | @Override 42 | public void process(@NotNull CommandInvocation commandInvocation) throws CommandException { 43 | List invocationPreprocessors = this.invocationPreprocessors.stream() 44 | .sorted(Comparator.comparingInt( 45 | preprocessor -> Optional 46 | .ofNullable(preprocessor.getClass().getAnnotation(Order.class)) 47 | .map(Order::value) 48 | .orElse(0) 49 | )) 50 | .toList(); 51 | 52 | log.debug( 53 | "Discovered {} preprocessors: {}", 54 | invocationPreprocessors.size(), 55 | invocationPreprocessors 56 | .stream() 57 | .map(preprocessor -> preprocessor.getClass().getSimpleName()) 58 | .collect(Collectors.joining(" ")) 59 | ); 60 | 61 | invocationPreprocessors.forEach(preprocessor -> preprocessor.process(commandInvocation)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/preprocessor/InvocationPreprocessor.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.preprocessor; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Interface for pre-processing command invocations before execution. 8 | *

9 | * Implementations of this interface can perform pre-processing tasks on command invocations 10 | * such as validation, normalization, or modification of command parameters. 11 | *

12 | * 13 | * @since 0.7.0.0-RC1 14 | */ 15 | public interface InvocationPreprocessor { 16 | 17 | /** 18 | * Processes the given command invocation before execution. 19 | * 20 | * @param invocation The command invocation to preprocess. 21 | */ 22 | void process(@NotNull CommandInvocation invocation); 23 | } 24 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/preprocessor/impl/SubcommandPreprocessor.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.preprocessor.impl; 2 | 3 | import dev.temez.springlify.commander.command.Command; 4 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 5 | import dev.temez.springlify.commander.command.preprocessor.InvocationPreprocessor; 6 | import dev.temez.springlify.commander.exception.CommandException; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import org.springframework.core.annotation.Order; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.Comparator; 13 | 14 | /** 15 | * Preprocessor for handling subcommands within command invocations. 16 | *

17 | * This preprocessor extracts and processes subcommands from command invocations. 18 | *

19 | * 20 | * @since 0.7.0.0-RC1 21 | */ 22 | @Order 23 | @Component 24 | public class SubcommandPreprocessor implements InvocationPreprocessor { 25 | 26 | /** 27 | * Processes the command invocation by handling subcommands. 28 | * 29 | * @param invocation The command invocation to preprocess. 30 | * @throws CommandException If an error occurs during the preprocessing. 31 | */ 32 | @Override 33 | public void process(@NotNull CommandInvocation invocation) throws CommandException { 34 | Command subCommand = getSubCommand(invocation); 35 | if (subCommand != null) { 36 | invocation.setArguments(invocation.getArguments().stream().skip(1).toList()); 37 | invocation.setCommand(subCommand); 38 | process(invocation); 39 | } 40 | } 41 | 42 | /** 43 | * Retrieves the subcommand from the command invocation. 44 | * 45 | * @param invocation The command invocation. 46 | * @return The subcommand, or {@code null} if not found. 47 | */ 48 | private @Nullable Command getSubCommand(@NotNull CommandInvocation invocation) { 49 | if (invocation.getArguments().isEmpty()) { 50 | return null; 51 | } 52 | String possibleSubcommand = invocation.getArguments().get(0); 53 | return invocation.getCommand().getSubcommands() 54 | .stream() 55 | .sorted(Comparator.comparingInt(a -> a.getName().length())) 56 | .filter(subcommand -> possibleSubcommand.equalsIgnoreCase(subcommand.getName())) 57 | .findFirst() 58 | .orElse(null); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/sender/Sender.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.sender; 2 | 3 | 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.UUID; 7 | 8 | /** 9 | * Interface representing a sender of commands. 10 | * 11 | * @param The type of the platform-specific sender. 12 | * @since 0.7.0.0-RC1 13 | */ 14 | public interface Sender { 15 | 16 | /** 17 | * Retrieves the platform-specific sender object. 18 | * 19 | * @return The platform-specific sender object. 20 | */ 21 | @NotNull T getPlatformSender(); 22 | 23 | /** 24 | * Retrieves the UUID of the sender. 25 | * 26 | * @return The UUID of the sender. 27 | * @throws UnsupportedOperationException If UUID retrieval is not supported. 28 | */ 29 | @NotNull UUID getUuid() throws UnsupportedOperationException; 30 | 31 | /** 32 | * Checks if the sender is a console sender. 33 | * 34 | * @return {@code true} if the sender is a console sender, {@code false} otherwise. 35 | */ 36 | boolean isConsoleSender(); 37 | 38 | /** 39 | * Checks if the sender has the specified permission. 40 | * 41 | * @param permission The permission to check. 42 | * @return {@code true} if the sender has the permission, {@code false} otherwise. 43 | */ 44 | boolean hasPermission(@NotNull String permission); 45 | } 46 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/command/sender/SenderDetailsFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.command.sender; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * A factory interface for constructing sender details. 7 | *

8 | * Implementations of this interface are responsible for creating sender details objects 9 | * based on the provided {@link Sender}. 10 | *

11 | *

12 | * The {@code SenderDetails} type parameter specifies the type of sender details object 13 | * that will be constructed by implementations of this interface. 14 | *

15 | * 16 | * @param The type of sender details to be constructed. 17 | * @see Sender 18 | * @since 0.7.0.0-RC1 19 | */ 20 | public interface SenderDetailsFactory { 21 | 22 | /** 23 | * Constructs sender details based on the provided command sender. 24 | * 25 | * @param commandSender The command sender for which sender details are to be constructed. 26 | * @return The constructed sender details object. 27 | * @throws NullPointerException if {@code commandSender} is {@code null}. 28 | */ 29 | @NotNull T getDetails(@NotNull Sender commandSender); 30 | } 31 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/CommandException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class CommandException extends CommanderException { 6 | 7 | public CommandException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/CommandExecutionException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class CommandExecutionException extends CommandException { 6 | 7 | public CommandExecutionException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/CommanderException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class CommanderException extends RuntimeException { 6 | 7 | public CommanderException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/argument/ArgumentAdapterException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.argument; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class ArgumentAdapterException extends ArgumentException { 6 | 7 | public ArgumentAdapterException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/argument/ArgumentAdapterNotFoundException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.argument; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class ArgumentAdapterNotFoundException extends ArgumentAdapterException { 6 | 7 | public ArgumentAdapterNotFoundException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/argument/ArgumentException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.argument; 2 | 3 | import dev.temez.springlify.commander.exception.CommanderException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class ArgumentException extends CommanderException { 7 | 8 | public ArgumentException(@NotNull String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/details/SenderDetailsException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.details; 2 | 3 | import dev.temez.springlify.commander.exception.CommandException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class SenderDetailsException extends CommandException { 7 | 8 | public SenderDetailsException(@NotNull String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/discovery/CommandDiscoveryException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.discovery; 2 | 3 | import dev.temez.springlify.commander.exception.CommandException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class CommandDiscoveryException extends CommandException { 7 | 8 | public CommandDiscoveryException(@NotNull String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/filter/CommandFilterException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.filter; 2 | 3 | import dev.temez.springlify.commander.exception.CommandException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class CommandFilterException extends CommandException { 7 | 8 | public CommandFilterException(@NotNull String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/filter/CommandFilterNotFoundException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.filter; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class CommandFilterNotFoundException extends CommandFilterException { 6 | 7 | public CommandFilterNotFoundException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/handler/CommandExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.handler; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public interface CommandExceptionHandler { 7 | 8 | void handle(@NotNull CommandInvocation invocation, @NotNull Exception exception); 9 | 10 | boolean supports(@NotNull Exception exception); 11 | } 12 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/handler/CommanderExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.handler; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public interface CommanderExceptionHandler { 7 | 8 | void handle(@NotNull CommandInvocation invocation, @NotNull Exception exception) throws RuntimeException; 9 | } 10 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/handler/CommanderExceptionHandlerImpl.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.handler; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import lombok.AccessLevel; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.experimental.FieldDefaults; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.List; 11 | 12 | @Component 13 | @RequiredArgsConstructor 14 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 15 | public class CommanderExceptionHandlerImpl implements CommanderExceptionHandler { 16 | 17 | @NotNull 18 | List exceptionHandlers; 19 | 20 | @Override 21 | public void handle(@NotNull CommandInvocation invocation, @NotNull Exception exception) throws RuntimeException { 22 | List handlers = exceptionHandlers.stream() 23 | .filter(commandExceptionHandler -> commandExceptionHandler.supports(exception)) 24 | .toList(); 25 | if (handlers.isEmpty()) { 26 | throw new RuntimeException(exception.getMessage(), exception); 27 | } 28 | handlers.forEach(handler -> handler.handle(invocation, exception)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/handler/impl/ArgumentExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.handler.impl; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import dev.temez.springlify.commander.exception.argument.ArgumentException; 5 | import dev.temez.springlify.commander.exception.handler.CommandExceptionHandler; 6 | import dev.temez.springlify.commander.service.chat.CommanderChatService; 7 | import lombok.AccessLevel; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.experimental.FieldDefaults; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | @RequiredArgsConstructor 15 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 16 | public class ArgumentExceptionHandler implements CommandExceptionHandler { 17 | 18 | @NotNull 19 | CommanderChatService commanderChatService; 20 | 21 | @Override 22 | public void handle(@NotNull CommandInvocation invocation, @NotNull Exception exception) { 23 | commanderChatService.sendErrorMessage(invocation.getSender(), exception.getMessage()); 24 | } 25 | 26 | @Override 27 | public boolean supports(@NotNull Exception exception) { 28 | return exception.getClass().equals(ArgumentException.class); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/exception/handler/impl/CommandFilterExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.exception.handler.impl; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import dev.temez.springlify.commander.exception.filter.CommandFilterException; 5 | import dev.temez.springlify.commander.exception.handler.CommandExceptionHandler; 6 | import dev.temez.springlify.commander.service.chat.CommanderChatService; 7 | import lombok.AccessLevel; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.experimental.FieldDefaults; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | @RequiredArgsConstructor 15 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 16 | public class CommandFilterExceptionHandler implements CommandExceptionHandler { 17 | 18 | @NotNull 19 | CommanderChatService commanderChatService; 20 | 21 | @Override 22 | public void handle(@NotNull CommandInvocation invocation, @NotNull Exception exception) { 23 | commanderChatService.sendErrorMessage(invocation.getSender(), exception.getMessage()); 24 | } 25 | 26 | @Override 27 | public boolean supports(@NotNull Exception exception) { 28 | return exception.getClass().equals(CommandFilterException.class); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/initializer/AbstractCommandInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.initializer; 2 | 3 | import dev.temez.springlify.commander.annotation.CommanderCommand; 4 | import dev.temez.springlify.commander.command.Command; 5 | import dev.temez.springlify.commander.command.discoverer.CommandDiscoverer; 6 | import dev.temez.springlify.commander.command.platform.PlatformCommandFactory; 7 | import dev.temez.springlify.commander.command.platform.PlatformCommandRegistrar; 8 | import lombok.AccessLevel; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.experimental.FieldDefaults; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.springframework.beans.factory.config.BeanPostProcessor; 14 | 15 | /** 16 | * An abstract command initializer responsible for initializing and registering platform-specific commands. 17 | * This class implements the {@link BeanPostProcessor} interface. 18 | * 19 | * @param the type of platform-specific command 20 | * @since 0.7.0.0-RC1 21 | */ 22 | @Slf4j 23 | @RequiredArgsConstructor 24 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 25 | public abstract class AbstractCommandInitializer implements BeanPostProcessor { 26 | 27 | /** 28 | * The factory for creating platform-specific commands. 29 | */ 30 | @NotNull 31 | PlatformCommandFactory commandFactory; 32 | 33 | /** 34 | * The registrar for registering platform-specific commands. 35 | */ 36 | @NotNull 37 | PlatformCommandRegistrar commandRegistrar; 38 | 39 | /** 40 | * The discoverer for discovering commands. 41 | */ 42 | @NotNull 43 | CommandDiscoverer commandDiscoverer; 44 | 45 | /** 46 | * Processes the bean after initialization, discovering and registering commands. 47 | * 48 | * @param bean the bean being post-processed 49 | * @param beanName the name of the bean 50 | * @return the processed bean 51 | */ 52 | @Override 53 | public @NotNull Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) { 54 | Class beanClass = bean.getClass(); 55 | if (beanClass.getDeclaringClass() == null && beanClass.isAnnotationPresent(CommanderCommand.class)) { 56 | Command command = commandDiscoverer.discover(bean); 57 | T platformCommand = commandFactory.create(command); 58 | commandRegistrar.register(platformCommand); 59 | log.debug("Registered command {} for bean {}", command.getFullName(), beanName); 60 | } 61 | return bean; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/service/CommandService.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.service; 2 | 3 | import dev.temez.springlify.commander.command.invocation.CommandInvocation; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Unmodifiable; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Service interface for command-related operations. 11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | public interface CommandService { 15 | 16 | /** 17 | * Completes the command invocation based on the provided command invocation. 18 | * 19 | * @param commandInvocation The command invocation to complete. 20 | * @return An unmodifiable list of completion suggestions. 21 | */ 22 | @NotNull @Unmodifiable List complete(@NotNull CommandInvocation commandInvocation); 23 | 24 | /** 25 | * Executes the command invocation. 26 | * 27 | * @param commandInvocation The command invocation to execute. 28 | */ 29 | void execute(@NotNull CommandInvocation commandInvocation); 30 | } 31 | -------------------------------------------------------------------------------- /springlify-commander/springlify-commander-commons/src/main/java/dev/temez/springlify/commander/service/chat/CommanderChatService.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.commander.service.chat; 2 | 3 | import dev.temez.springlify.commander.command.sender.Sender; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public interface CommanderChatService { 7 | 8 | void sendMessage(@NotNull Sender sender, @NotNull String message, Object @NotNull ... replacers); 9 | 10 | void sendErrorMessage(@NotNull Sender sender, @NotNull String message, Object @NotNull ... replacers); 11 | } 12 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/example-bukkit-plugin.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | plugins { 4 | alias libs.plugins.johnrengelman.shadow 5 | } 6 | 7 | dependencies { 8 | 9 | compileOnly libs.paper.paperapi 10 | 11 | implementation project(":springlify-starter:springlify-starter-bukkit") 12 | implementation project(":springlify-platform:springlify-platform-bukkit") 13 | implementation project(":springlify-commander:springlify-commander-bukkit") 14 | } -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/java/dev/temez/springlify/example/application/SpringlifyExampleApplication.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.example.application; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | @SpringBootApplication( 6 | scanBasePackages = { 7 | "dev.temez.springlify.example", 8 | "dev.temez.springlify" 9 | } 10 | ) 11 | public class SpringlifyExampleApplication { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/java/dev/temez/springlify/example/application/SpringlifyExamplePlugin.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.example.application; 2 | 3 | import dev.temez.springlify.starter.annotation.SpringlifyApplication; 4 | import dev.temez.springlify.starter.plugin.SpringlifyBukkitPlugin; 5 | 6 | @SpringlifyApplication( 7 | springApplicationClass = SpringlifyExampleApplication.class 8 | ) 9 | public class SpringlifyExamplePlugin extends SpringlifyBukkitPlugin { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/java/dev/temez/springlify/example/command/ExampleCommand.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.example.command; 2 | 3 | import dev.temez.springlify.commander.annotation.CommandRoot; 4 | import dev.temez.springlify.commander.annotation.CommanderCommand; 5 | import dev.temez.springlify.commander.command.CommandType; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.bukkit.World; 8 | import org.bukkit.command.CommandSender; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | @CommanderCommand( 12 | name = "example", 13 | type = CommandType.SHARED 14 | ) 15 | @Slf4j 16 | public class ExampleCommand { 17 | 18 | @CommandRoot 19 | public void execute(@NotNull CommandSender commandSender, @NotNull World world) { 20 | log.info("This is example command!"); 21 | } 22 | 23 | @CommanderCommand( 24 | name = "sub", 25 | type = CommandType.SHARED 26 | ) 27 | public void executeSub(@NotNull CommandSender player, @NotNull Integer someInteger) { 28 | log.info("This is simple subcommand!"); 29 | } 30 | 31 | @CommanderCommand( 32 | name = "othersub", 33 | type = CommandType.SHARED 34 | ) 35 | public static class SubExampleCommand { 36 | 37 | @CommandRoot 38 | public void execute(@NotNull CommandSender commandSender, @NotNull World world) { 39 | log.info("This is othersub subcommand!"); 40 | } 41 | 42 | @CommanderCommand( 43 | name = "sub", 44 | type = CommandType.SHARED 45 | ) 46 | public void executeSub(@NotNull CommandSender commandSender, @NotNull Integer someInteger) { 47 | log.info("This is subcommand for othersub subcommand!"); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/java/dev/temez/springlify/example/configuration/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.example.configuration; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.item.ItemStackConfiguration; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.experimental.FieldDefaults; 8 | import net.kyori.adventure.text.minimessage.MiniMessage; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.boot.context.properties.ConfigurationProperties; 11 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Configuration 17 | public class ExampleConfiguration { 18 | 19 | @Bean 20 | MiniMessage miniMessage() { 21 | return MiniMessage.miniMessage(); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/java/dev/temez/springlify/example/service/commander/CommanderChatServiceImpl.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.example.service.commander; 2 | 3 | import dev.temez.springlify.commander.command.sender.Sender; 4 | import dev.temez.springlify.commander.service.chat.CommanderChatService; 5 | import lombok.AccessLevel; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.experimental.FieldDefaults; 8 | import org.bukkit.command.CommandSender; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | @RequiredArgsConstructor 14 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 15 | public class CommanderChatServiceImpl implements CommanderChatService { 16 | 17 | @Override 18 | public void sendMessage(@NotNull Sender sender, @NotNull String message, Object @NotNull ... replacers) { 19 | ((CommandSender) sender.getPlatformSender()).sendMessage(message); 20 | 21 | } 22 | 23 | @Override 24 | public void sendErrorMessage(@NotNull Sender sender, @NotNull String message, Object @NotNull ... replacers) { 25 | sendMessage(sender, message, replacers); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | 3 | profiles: 4 | active: dev 5 | 6 | springlify: 7 | platform: 8 | text-converter-mode: mini_message 9 | -------------------------------------------------------------------------------- /springlify-examples/example-bukkit-plugin/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: example-bukkit-plugin 2 | main: dev.temez.springlify.example.application.SpringlifyExamplePlugin 3 | version: '${version}' 4 | api-version: 1.20 5 | 6 | authors: 7 | - temez (temezf@gmail.com) 8 | -------------------------------------------------------------------------------- /springlify-platform/README.md: -------------------------------------------------------------------------------- 1 | # springlify-platform 2 | 3 | This module contains classes that simplify development on selected platforms. 4 | 5 | ## Features 6 | 7 | - Platform Configuration Classes: Includes classes for configuring platform-specific settings. 8 | - Text Converters with Cyrillic Support: Provides convenient tools for converting text with Cyrillic characters. 9 | 10 | - [springlify-starter-bukkit](/springlify-platform-bukkit/README.md) 11 | - [springlify-starter-commons](/springlify-platform-commons/README.md) 12 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/README.md: -------------------------------------------------------------------------------- 1 | # springlify-platform-bukkit 2 | 3 | This module contains classes that simplify development on `Bukkit` platform. 4 | 5 | ## Features 6 | 7 | - Platform Configuration Classes such as `LocationConfguration` and `ItemStackConfiguration` 8 | - Mapping schemas for mapping these classes to `Bukkit` format. 9 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/springlify-platform-bukkit.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | dependencies { 4 | compileOnly libs.paper.paperapi 5 | compileOnly libs.mojang.authlib 6 | 7 | api libs.tr7zw.item.nbt.api 8 | api project(":springlify-starter:springlify-starter-bukkit") 9 | api project(":springlify-platform:springlify-platform-commons") 10 | 11 | testImplementation libs.paper.paperapi 12 | testImplementation libs.mojang.authlib 13 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/annotation/BukkitCommand.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.springframework.core.annotation.AliasFor; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.lang.annotation.*; 8 | 9 | /** 10 | * The {@code VelocityCommand} annotation is a custom annotation used to mark classes 11 | * as Velocity commands, for continuous auto registering with spring post processor. 12 | * 13 | *

Usage example: 14 | *

{@code
15 |  * @VelocityComand(command="mycommand", alias = {"alias1", "alias2"})
16 |  * public class MyCommand implements CommandExecutor {
17 |  *
18 |  *  // Command execution logic
19 |  *
20 |  * }
21 |  * }
22 | * 23 | *

In this example, `MyCommand` is marked as a Velocity command with the primary command 24 | * "mycommand" and two aliases "alias1" and "alias2." 25 | * 26 | * @since 0.7.0.0-RC1 27 | */ 28 | @Target(ElementType.TYPE) 29 | @Retention(RetentionPolicy.RUNTIME) 30 | @Component 31 | @Documented 32 | public @interface BukkitCommand { 33 | 34 | /** 35 | * Alias for the {@link Component} annotation's value attribute. 36 | * Specifies the name of the bean. 37 | * 38 | * @return The primary bean name. 39 | */ 40 | @AliasFor(annotation = Component.class) 41 | String value() default ""; 42 | 43 | /** 44 | * Specifies the primary command name. 45 | * 46 | * @return The primary command name. 47 | */ 48 | @NotNull 49 | String command(); 50 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/annotation/ConditionalOnPluginEnabled.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.annotation; 2 | 3 | import dev.temez.springlify.platform.condition.OnPluginEnabledCondition; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.springframework.context.annotation.Conditional; 6 | 7 | import java.lang.annotation.*; 8 | 9 | 10 | @Documented 11 | @Target({ElementType.TYPE, ElementType.METHOD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Conditional(OnPluginEnabledCondition.class) 14 | public @interface ConditionalOnPluginEnabled { 15 | 16 | @NotNull String value(); 17 | 18 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/condition/OnPluginEnabledCondition.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.condition; 2 | 3 | import dev.temez.springlify.platform.annotation.ConditionalOnPluginEnabled; 4 | import org.bukkit.Bukkit; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.springframework.context.annotation.Condition; 7 | import org.springframework.context.annotation.ConditionContext; 8 | import org.springframework.core.type.AnnotatedTypeMetadata; 9 | 10 | import java.util.Map; 11 | 12 | public class OnPluginEnabledCondition implements Condition { 13 | 14 | @Override 15 | @SuppressWarnings("DataFlowIssue") 16 | public boolean matches(@NotNull ConditionContext context,@NotNull AnnotatedTypeMetadata metadata) { 17 | Map attributes = metadata.getAnnotationAttributes(ConditionalOnPluginEnabled.class.getName()); 18 | String pluginName = attributes.get("value").toString(); 19 | return Bukkit.getPluginManager().isPluginEnabled(pluginName); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/ColorConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import lombok.experimental.FieldDefaults; 8 | 9 | /** 10 | * Configuration class representing the color properties. 11 | * 12 | *

This class is used for configuring color properties using RGB values.

13 | * 14 | * @since 0.7.0.0-RC1 15 | */ 16 | @Getter 17 | @Setter 18 | @ToString 19 | @FieldDefaults(level = AccessLevel.PRIVATE) 20 | public class ColorConfiguration { 21 | 22 | /** 23 | * The red component of the color. 24 | */ 25 | int red; 26 | 27 | /** 28 | * The green component of the color. 29 | */ 30 | int green; 31 | 32 | /** 33 | * The blue component of the color. 34 | */ 35 | int blue; 36 | } 37 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/EnchantmentConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import lombok.experimental.FieldDefaults; 8 | import org.bukkit.enchantments.Enchantment; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * Configuration class representing the enchantment properties. 13 | * 14 | *

This class is used for configuring enchantment properties, such as the enchantment itself, level, and level restriction.

15 | * 16 | * @since 0.7.0.0-RC1 17 | */ 18 | @Getter 19 | @Setter 20 | @ToString 21 | @FieldDefaults(level = AccessLevel.PRIVATE) 22 | public class EnchantmentConfiguration { 23 | 24 | /** 25 | * The enchantment. 26 | */ 27 | @NotNull 28 | Enchantment enchantment; 29 | 30 | /** 31 | * The level of the enchantment. Default value is 1. 32 | */ 33 | int level = 1; 34 | 35 | /** 36 | * Indicates whether to ignore level restrictions. Default value is true. 37 | */ 38 | boolean ignoreLevelRestriction = true; 39 | } 40 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/LocationConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import lombok.experimental.FieldDefaults; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Configuration class representing the location properties. 12 | * 13 | *

This class is used for configuring location properties, such as world, coordinates, yaw, and pitch.

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | @Getter 18 | @Setter 19 | @ToString 20 | @FieldDefaults(level = AccessLevel.PRIVATE) 21 | public class LocationConfiguration { 22 | 23 | /** 24 | * The world name. 25 | */ 26 | @NotNull 27 | String world; 28 | 29 | /** 30 | * The x-coordinate. 31 | */ 32 | double x; 33 | 34 | /** 35 | * The y-coordinate. 36 | */ 37 | double y; 38 | 39 | /** 40 | * The z-coordinate. 41 | */ 42 | double z; 43 | 44 | /** 45 | * The yaw angle. 46 | */ 47 | float yaw; 48 | 49 | /** 50 | * The pitch angle. 51 | */ 52 | float pitch; 53 | } 54 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/PotionEffectConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import lombok.experimental.FieldDefaults; 8 | import org.bukkit.potion.PotionEffectType; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.time.Duration; 12 | 13 | /** 14 | * Configuration class representing the potion effect properties. 15 | * 16 | *

This class is used for configuring potion effect properties, such as the effect type, duration, amplifier, and visibility.

17 | * 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Getter 21 | @Setter 22 | @ToString 23 | @FieldDefaults(level = AccessLevel.PRIVATE) 24 | public class PotionEffectConfiguration { 25 | 26 | /** 27 | * The type of potion effect. 28 | */ 29 | @NotNull 30 | PotionEffectType type; 31 | 32 | /** 33 | * The duration of the potion effect. 34 | */ 35 | Duration duration; 36 | 37 | /** 38 | * The amplifier level of the potion effect. 39 | */ 40 | int amplifier; 41 | 42 | /** 43 | * Indicates whether the effect is ambient. Default value is false. 44 | */ 45 | boolean ambient = false; 46 | 47 | /** 48 | * Indicates whether particles are shown. Default value is true. 49 | */ 50 | boolean particles = true; 51 | 52 | /** 53 | * Indicates whether the effect icon is shown. Default value is true. 54 | */ 55 | boolean showIcon = true; 56 | } 57 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/SkinTextureConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import lombok.experimental.FieldDefaults; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Configuration class representing the skin texture properties. 12 | * 13 | *

This class is used for configuring skin texture properties, such as the texture and signature.

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | @Getter 18 | @Setter 19 | @ToString 20 | @FieldDefaults(level = AccessLevel.PRIVATE) 21 | public class SkinTextureConfiguration { 22 | 23 | /** 24 | * The texture of the skin. 25 | */ 26 | @NotNull 27 | String texture; 28 | 29 | /** 30 | * The signature of the skin. 31 | */ 32 | @NotNull 33 | String signature; 34 | } 35 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/converter/StringEnchantmentConverter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.converter; 2 | 3 | import org.bukkit.NamespacedKey; 4 | import org.bukkit.enchantments.Enchantment; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; 8 | import org.springframework.core.convert.converter.Converter; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Converter for converting a string representation of an enchantment to an Enchantment object. 13 | * 14 | *

This converter is used by Spring Boot's type conversion mechanism to convert string values to Enchantment objects 15 | * when binding configuration properties.

16 | * 17 | * @see Enchantment 18 | * @since 0.7.0.0-RC1 19 | */ 20 | @Component 21 | @ConfigurationPropertiesBinding 22 | public class StringEnchantmentConverter implements Converter { 23 | 24 | /** 25 | * Converts the given string representation of an enchantment to an Enchantment object. 26 | * 27 | *

This method converts the string representation to an Enchantment object using the enchantment's key.

28 | * 29 | * @param source the string representation of the enchantment 30 | * @return the corresponding Enchantment object, or {@code null} if the string does not represent a valid enchantment 31 | */ 32 | @Override 33 | public @Nullable Enchantment convert(@NotNull String source) { 34 | return Enchantment.getByKey(NamespacedKey.minecraft(source.toLowerCase())); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/converter/StringPotionEffectTypeConverter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.converter; 2 | 3 | import org.bukkit.potion.PotionEffectType; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; 7 | import org.springframework.core.convert.converter.Converter; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Converter for converting a string representation of a potion effect type to a PotionEffectType object. 12 | * 13 | *

This converter is used by Spring Boot's type conversion mechanism to convert string values to PotionEffectType 14 | * objects when binding configuration properties.

15 | * 16 | * @see PotionEffectType 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Component 20 | @ConfigurationPropertiesBinding 21 | public class StringPotionEffectTypeConverter implements Converter { 22 | 23 | /** 24 | * Converts the given string representation of a potion effect type to a PotionEffectType object. 25 | * 26 | *

This method converts the string representation to a PotionEffectType object using the effect type's name.

27 | * 28 | * @param source the string representation of the potion effect type 29 | * @return the corresponding PotionEffectType object, or {@code null} if the string does not represent a valid potion effect type 30 | */ 31 | @Override 32 | public @Nullable PotionEffectType convert(@NotNull String source) { 33 | return PotionEffectType.getByName(source); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/item/ItemStackConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.item; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.item.meta.ItemMetaConfiguration; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | import lombok.experimental.FieldDefaults; 9 | import org.bukkit.Material; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 13 | 14 | /** 15 | * Configuration class representing an ItemStack with its properties. 16 | * 17 | *

This class is used for configuring ItemStacks, including the material, amount, and item meta.

18 | * 19 | * @since 0.7.0.0-RC1 20 | */ 21 | @Getter 22 | @Setter 23 | @ToString 24 | @FieldDefaults(level = AccessLevel.PRIVATE) 25 | public class ItemStackConfiguration { 26 | 27 | /** 28 | * The material of the ItemStack. 29 | */ 30 | @NotNull 31 | Material material; 32 | 33 | /** 34 | * The amount of items in the ItemStack. Default value is 1. 35 | */ 36 | int amount = 1; 37 | 38 | /** 39 | * The item meta configuration for the ItemStack. 40 | * 41 | *

This property represents additional metadata for the ItemStack, such as display name, lore, etc.

42 | */ 43 | @Nullable 44 | @NestedConfigurationProperty 45 | ItemMetaConfiguration itemMeta; 46 | } 47 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/item/meta/ItemMetaConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.item.meta; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.EnchantmentConfiguration; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | import lombok.experimental.FieldDefaults; 9 | import org.bukkit.inventory.ItemFlag; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 13 | 14 | import java.util.ArrayList; 15 | import java.util.HashSet; 16 | import java.util.List; 17 | import java.util.Set; 18 | 19 | /** 20 | * Configuration class representing the item meta properties. 21 | * 22 | *

This class is used for configuring the general item meta properties, such as display name, lore, enchantments, etc.

23 | * 24 | * @since 0.7.0.0-RC1 25 | */ 26 | @Getter 27 | @Setter 28 | @ToString 29 | @FieldDefaults(level = AccessLevel.PRIVATE) 30 | public class ItemMetaConfiguration { 31 | 32 | /** 33 | * The display name of the item. 34 | */ 35 | @Nullable 36 | String displayName; 37 | 38 | /** 39 | * The lore of the item. 40 | */ 41 | @NotNull 42 | List lore = new ArrayList<>(); 43 | 44 | /** 45 | * The custom model data of the item. Default value is 0. 46 | */ 47 | int modelData = 0; 48 | 49 | /** 50 | * The durability of the item. Default value is 0. 51 | */ 52 | int durability = 0; 53 | 54 | /** 55 | * The set of item flags for the item. 56 | */ 57 | @NotNull 58 | Set itemFlags = new HashSet<>(); 59 | 60 | /** 61 | * Indicates if the item is unbreakable. Default value is false. 62 | */ 63 | boolean unbreakable = false; 64 | 65 | /** 66 | * The set of enchantments applied to the item. 67 | */ 68 | @NotNull 69 | Set enchantments = new HashSet<>(); 70 | 71 | /** 72 | * The leather armor item meta configuration. 73 | */ 74 | @Nullable 75 | @NestedConfigurationProperty 76 | LeatherArmorItemMetaConfiguration leatherArmorMeta; 77 | 78 | /** 79 | * The potion item meta configuration. 80 | */ 81 | @Nullable 82 | @NestedConfigurationProperty 83 | PotionItemMetaConfiguration potionMeta; 84 | 85 | /** 86 | * The skull item meta configuration. 87 | */ 88 | @Nullable 89 | @NestedConfigurationProperty 90 | SkullItemMetaConfiguration skullMeta; 91 | } 92 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/item/meta/LeatherArmorItemMetaConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.item.meta; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.ColorConfiguration; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | import lombok.experimental.FieldDefaults; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 11 | 12 | /** 13 | * Configuration class representing the item meta properties for leather armor. 14 | * 15 | *

This class is used for configuring the item meta properties specific to leather armor, such as color.

16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Getter 20 | @Setter 21 | @ToString 22 | @FieldDefaults(level = AccessLevel.PRIVATE) 23 | public class LeatherArmorItemMetaConfiguration { 24 | 25 | /** 26 | * The color configuration for the leather armor. 27 | */ 28 | @NotNull 29 | @NestedConfigurationProperty 30 | ColorConfiguration color; 31 | } 32 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/item/meta/PotionItemMetaConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.item.meta; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.ColorConfiguration; 4 | import dev.temez.springlify.platform.configuration.bukkit.PotionEffectConfiguration; 5 | import lombok.AccessLevel; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | import lombok.experimental.FieldDefaults; 10 | import org.bukkit.potion.PotionType; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * Configuration class representing the item meta properties for potions. 20 | * 21 | *

This class is used for configuring the item meta properties specific to potions, such as effects and color.

22 | * 23 | * @since 0.7.0.0-RC1 24 | */ 25 | @Getter 26 | @Setter 27 | @ToString 28 | @FieldDefaults(level = AccessLevel.PRIVATE) 29 | public class PotionItemMetaConfiguration { 30 | 31 | /** 32 | * The list of potion effects applied to the potion. 33 | */ 34 | @NotNull 35 | List effects = new ArrayList<>(); 36 | 37 | /** 38 | * The main effect type of the potion. 39 | */ 40 | @Nullable 41 | PotionType mainEffectType; 42 | 43 | /** 44 | * The color configuration for the potion. 45 | */ 46 | @Nullable 47 | @NestedConfigurationProperty 48 | ColorConfiguration color; 49 | } 50 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/item/meta/SkullItemMetaConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.item.meta; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.SkinTextureConfiguration; 4 | import lombok.AccessLevel; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | import lombok.experimental.FieldDefaults; 9 | import org.jetbrains.annotations.Nullable; 10 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 11 | 12 | /** 13 | * Configuration class representing the item meta properties for skulls. 14 | * 15 | *

This class is used for configuring the item meta properties specific to skulls, such as owner and skin.

16 | * 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Getter 20 | @Setter 21 | @ToString 22 | @FieldDefaults(level = AccessLevel.PRIVATE) 23 | public class SkullItemMetaConfiguration { 24 | 25 | /** 26 | * The owner of the skull. 27 | */ 28 | @Nullable 29 | String owner; 30 | 31 | /** 32 | * The skin texture configuration for the skull. 33 | */ 34 | @Nullable 35 | @NestedConfigurationProperty 36 | SkinTextureConfiguration skin; 37 | } 38 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/mapper/schema/ColorMappingSchema.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.mapper.schema; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.ColorConfiguration; 4 | import dev.temez.springlify.platform.configuration.mapper.schema.MappingSchema; 5 | import org.bukkit.Color; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * Mapping schema for converting ColorConfiguration to Color. 11 | * 12 | *

This component is responsible for mapping properties from {@link ColorConfiguration} to {@link Color} instances.

13 | * 14 | * @since 0.7.0.0-RC1 15 | */ 16 | @Component 17 | public class ColorMappingSchema implements MappingSchema { 18 | 19 | /** 20 | * Maps a ColorConfiguration instance to a Color instance. 21 | * 22 | * @param source The source ColorConfiguration to map from. 23 | * @return The resulting Color mapped from the configuration. 24 | */ 25 | @Override 26 | public @NotNull Color map(@NotNull ColorConfiguration source) { 27 | return Color.fromBGR(source.getRed(), source.getGreen(), source.getBlue()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/mapper/schema/LocationMappingSchema.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.mapper.schema; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.LocationConfiguration; 4 | import dev.temez.springlify.platform.configuration.mapper.schema.MappingSchema; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Location; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * Mapping schema for converting LocationConfiguration to Location. 12 | * 13 | *

This component is responsible for mapping properties from {@link LocationConfiguration} to {@link Location} instances.

14 | * 15 | * @since 0.7.0.0-RC1 16 | */ 17 | @Component 18 | public class LocationMappingSchema implements MappingSchema { 19 | 20 | /** 21 | * Maps a LocationConfiguration instance to a Location instance. 22 | * 23 | * @param source The source LocationConfiguration to map from. 24 | * @return The resulting Location mapped from the configuration. 25 | */ 26 | @Override 27 | public @NotNull Location map(@NotNull LocationConfiguration source) { 28 | return new Location( 29 | Bukkit.getWorld(source.getWorld()), 30 | source.getX(), 31 | source.getY(), 32 | source.getZ(), 33 | source.getYaw(), 34 | source.getPitch() 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/configuration/bukkit/mapper/schema/PotionEffectMappingSchema.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.bukkit.mapper.schema; 2 | 3 | import dev.temez.springlify.platform.configuration.bukkit.PotionEffectConfiguration; 4 | import dev.temez.springlify.platform.configuration.mapper.schema.MappingSchema; 5 | import org.bukkit.potion.PotionEffect; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * Mapping schema for converting PotionEffectConfiguration to PotionEffect. 11 | * 12 | *

This component is responsible for mapping properties from {@link PotionEffectConfiguration} to {@link PotionEffect} instances.

13 | * 14 | * @since 0.7.0.0-RC1 15 | */ 16 | @Component 17 | public class PotionEffectMappingSchema implements MappingSchema { 18 | 19 | /** 20 | * Maps a PotionEffectConfiguration instance to a PotionEffect instance. 21 | * 22 | * @param source The source PotionEffectConfiguration to map from. 23 | * @return The resulting PotionEffect mapped from the configuration. 24 | */ 25 | @Override 26 | public @NotNull PotionEffect map(@NotNull PotionEffectConfiguration source) { 27 | return new PotionEffect( 28 | source.getType(), 29 | (int) (source.getDuration().toSeconds() * 20), 30 | source.getAmplifier(), 31 | source.isAmbient(), 32 | source.isShowIcon() 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/initializer/BukkitTaskInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.initializer; 2 | 3 | import dev.temez.springlify.platform.task.AbstractTask; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.springframework.beans.BeansException; 7 | import org.springframework.beans.factory.config.BeanPostProcessor; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Slf4j 11 | @Component 12 | public class BukkitTaskInitializer implements BeanPostProcessor { 13 | 14 | @Override 15 | public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException { 16 | if(bean instanceof AbstractTask task) { 17 | task.start(); 18 | log.debug("Started {} with taskId {}", task.getClass().getSimpleName(), task.getTaskId()); 19 | } 20 | return bean; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/initializer/CommandHandlerInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.initializer; 2 | 3 | import dev.temez.springlify.platform.annotation.BukkitCommand; 4 | import dev.temez.springlify.platform.server.ServerPlatformAdapter; 5 | import lombok.AccessLevel; 6 | import lombok.experimental.FieldDefaults; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.plugin.java.JavaPlugin; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.beans.BeansException; 12 | import org.springframework.beans.factory.config.BeanPostProcessor; 13 | import org.springframework.context.annotation.Lazy; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Slf4j 17 | @Component 18 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 19 | public class CommandHandlerInitializer implements BeanPostProcessor { 20 | 21 | @NotNull 22 | ServerPlatformAdapter serverPlatformAdapter; 23 | 24 | @Lazy 25 | public CommandHandlerInitializer(@NotNull ServerPlatformAdapter serverPlatformAdapter) { 26 | this.serverPlatformAdapter = serverPlatformAdapter; 27 | } 28 | 29 | @Override 30 | public @NotNull Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException { 31 | Class beanClass = bean.getClass(); 32 | if (bean instanceof CommandExecutor executor && !(bean instanceof JavaPlugin)) { 33 | BukkitCommand commandAnnotation = beanClass.getAnnotation(BukkitCommand.class); 34 | if (commandAnnotation == null) { 35 | log.warn("{} implements CommandExecutor but is not annotated with @BukkitCommand, so it won't be registered.", beanClass.getName()); 36 | return bean; 37 | } 38 | serverPlatformAdapter.registerCommandExecutor(commandAnnotation.command(), executor); 39 | return bean; 40 | } 41 | if (beanClass.isAnnotationPresent(BukkitCommand.class)) { 42 | log.warn("Class, annotated with @BukkitCommand {} should implement CommandExecutor.", beanClass.getName()); 43 | } 44 | return bean; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/initializer/EventHandlerInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.initializer; 2 | 3 | import dev.temez.springlify.platform.server.ServerPlatformAdapter; 4 | import lombok.AccessLevel; 5 | import lombok.experimental.FieldDefaults; 6 | import org.bukkit.event.Listener; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; 10 | import org.springframework.context.annotation.Lazy; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * Initializes and registers event listeners with the {@link ServerPlatformAdapter}. 15 | * 16 | *

This class implements the {@link DestructionAwareBeanPostProcessor} interface 17 | * to handle the registration of {@link Listener} beans after they are initialized 18 | * and their unregistration before they are destroyed.

19 | * 20 | * @see ServerPlatformAdapter 21 | * @see Listener 22 | * @since 0.7.0.0-RC1 23 | */ 24 | @Component 25 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 26 | public class EventHandlerInitializer implements DestructionAwareBeanPostProcessor { 27 | 28 | @NotNull 29 | ServerPlatformAdapter platformAdapter; 30 | 31 | /** 32 | * Constructs an {@code EventHandlerInitializer} with the specified {@link ServerPlatformAdapter}. 33 | * 34 | * @param platformAdapter the platform adapter used to register and unregister listeners 35 | */ 36 | @Lazy 37 | public EventHandlerInitializer(@NotNull ServerPlatformAdapter platformAdapter) { 38 | this.platformAdapter = platformAdapter; 39 | } 40 | 41 | /** 42 | * {@inheritDoc} 43 | * 44 | * @param bean the bean being processed 45 | * @param beanName the name of the bean 46 | * @return the processed bean 47 | * @throws BeansException if any error occurs during processing 48 | */ 49 | @Override 50 | public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException { 51 | if (bean instanceof Listener listener) { 52 | platformAdapter.registerEventListener(listener); 53 | } 54 | return bean; 55 | } 56 | 57 | /** 58 | * {@inheritDoc} 59 | * 60 | * @param bean the bean being processed 61 | * @param beanName the name of the bean 62 | */ 63 | @Override 64 | public void postProcessBeforeDestruction(@NotNull Object bean, @NotNull String beanName) { 65 | if (bean instanceof Listener listener) { 66 | platformAdapter.unregisterEventListener(listener); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/item/InitializingItemBuilderFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.item; 2 | 3 | import dev.temez.springlify.platform.text.converter.TextConverter; 4 | import jakarta.annotation.PostConstruct; 5 | import lombok.AccessLevel; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.experimental.FieldDefaults; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.bukkit.Material; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * Component for initializing item builders with a text converter. 16 | * 17 | *

This component implements the {@link ItemBuilderFactory} interface and initializes 18 | * item builders with a specified text converter during initialization.

19 | * 20 | * @see ItemBuilderFactory 21 | * @since 0.7.0.0-RC1 22 | */ 23 | @Slf4j 24 | @Component 25 | @RequiredArgsConstructor 26 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 27 | public class InitializingItemBuilderFactory implements ItemBuilderFactory { 28 | 29 | /** 30 | * The text converter used by item builders. 31 | */ 32 | @NotNull 33 | TextConverter textConverter; 34 | 35 | /** 36 | * Initializes the item builder factory by setting the text converter. 37 | */ 38 | @PostConstruct 39 | private void initialize() { 40 | ItemBuilder.setTextConverter(textConverter); 41 | log.debug("Using {} in ItemBuilder", textConverter.getClass().getSimpleName()); 42 | } 43 | 44 | /** 45 | * Creates a new item builder for the specified material. 46 | * 47 | * @param material the material of the item 48 | * @return the new item builder 49 | */ 50 | @Override 51 | public @NotNull ItemBuilder.MaterialItemBuilder fromMaterial(@NotNull Material material) { 52 | return ItemBuilder.fromMaterial(material); 53 | } 54 | 55 | /** 56 | * Creates a new item builder based on the specified ItemStack. 57 | * 58 | * @param item the ItemStack to base the item builder on 59 | * @return the new item builder 60 | */ 61 | @Override 62 | public @NotNull ItemBuilder.ItemStackItemBuilder fromItemStack(@NotNull ItemStack item) { 63 | return ItemBuilder.fromItem(item); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/item/ItemBuilderFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.item; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.inventory.ItemStack; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public interface ItemBuilderFactory { 8 | 9 | @NotNull 10 | ItemBuilder fromMaterial(@NotNull Material material); 11 | 12 | @NotNull 13 | ItemBuilder fromItemStack(@NotNull ItemStack item); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/task/AbstractTask.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.task; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.experimental.FieldDefaults; 7 | import lombok.experimental.NonFinal; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.plugin.java.JavaPlugin; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | @RequiredArgsConstructor 13 | @FieldDefaults(makeFinal = true, level = AccessLevel.PROTECTED) 14 | public abstract class AbstractTask implements Runnable { 15 | 16 | @NotNull JavaPlugin plugin; 17 | 18 | int period; 19 | 20 | @Getter 21 | @NonFinal 22 | int taskId; 23 | 24 | public void start() { 25 | beforeStart(); 26 | taskId = Bukkit.getScheduler() 27 | .runTaskTimer(plugin, this::doTaskCycle, 0, period) 28 | .getTaskId(); 29 | } 30 | 31 | public void cancel() { 32 | onCancel(); 33 | Bukkit.getScheduler().cancelTask(taskId); 34 | } 35 | 36 | protected void doTaskCycle() { 37 | run(); 38 | } 39 | 40 | protected void onCancel() { 41 | 42 | } 43 | 44 | protected void beforeStart() { 45 | 46 | } 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-bukkit/src/main/java/dev/temez/springlify/platform/task/SyncTimerTask.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.task; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.experimental.FieldDefaults; 6 | import lombok.experimental.NonFinal; 7 | import org.bukkit.plugin.java.JavaPlugin; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | @Getter 11 | @FieldDefaults(makeFinal = true, level = AccessLevel.PROTECTED) 12 | public abstract class SyncTimerTask extends AbstractTask { 13 | 14 | long time; 15 | 16 | @NonFinal 17 | long remainingTime; 18 | 19 | 20 | public SyncTimerTask(@NotNull JavaPlugin plugin, int period, long time) { 21 | super(plugin, period); 22 | this.time = time; 23 | this.remainingTime = time; 24 | } 25 | 26 | public long getElapsedTime() { 27 | return time - remainingTime; 28 | } 29 | 30 | @Override 31 | public void doTaskCycle() { 32 | remainingTime -= period; 33 | run(); 34 | if (remainingTime <= 0) { 35 | cancel(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/README.md: -------------------------------------------------------------------------------- 1 | # springlify-platform-commons 2 | 3 | This module contains classes that simplify development on selected platforms. 4 | 5 | ## Features 6 | 7 | - Platform Configuration Classes: Includes classes for configuring platform-specific settings. 8 | - Text Converters with `Kyori Adventure Api` support: Provides convenient tools for converting text to `Component`. 9 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/springlify-platform-commons.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection DependencyNotationArgument 2 | //file:noinspection GroovyAssignabilityCheck 3 | dependencies { 4 | annotationProcessor libs.spring.boot.configuration.processor 5 | 6 | api libs.spring.boot.configuration.processor 7 | api libs.kyori.adventure.text.serializer.legacy 8 | api libs.kyori.adventure.text.minimessage 9 | api project(":springlify-starter:springlify-starter-commons") 10 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/configuration/KyoriAdventureConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration; 2 | 3 | import net.kyori.adventure.text.minimessage.MiniMessage; 4 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class KyoriAdventureConfiguration { 12 | 13 | @Bean 14 | @ConditionalOnExpression( 15 | "'${springlify.platform.text-converter-mode}'.equalsIgnoreCase('mini_message')" 16 | ) 17 | @ConditionalOnMissingBean(MiniMessage.class) 18 | MiniMessage miniMessage() { 19 | return MiniMessage.builder().build(); 20 | } 21 | 22 | @Bean 23 | @ConditionalOnExpression( 24 | "'${springlify.platform.text-converter-mode}'.equalsIgnoreCase('legacy')" 25 | ) 26 | @ConditionalOnMissingBean(LegacyComponentSerializer.class) 27 | LegacyComponentSerializer legacyComponentSerializer() { 28 | return LegacyComponentSerializer.legacyAmpersand(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/configuration/mapper/ConfigurationMapper.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.mapper; 2 | 3 | import dev.temez.springlify.platform.configuration.mapper.schema.MappingSchema; 4 | import dev.temez.springlify.platform.exception.MappingException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.Collection; 8 | 9 | /** 10 | * Interface for mapping configurations between different data structures or formats. 11 | * 12 | *

This interface defines methods for mapping configurations from source objects to result objects, 13 | * as well as retrieving mapping schemas for a given source and result class.

14 | * 15 | * @see MappingSchema 16 | * @see MappingException 17 | * @since 0.7.0.0-RC1 18 | */ 19 | public interface ConfigurationMapper { 20 | 21 | /** 22 | * Maps a source object to a result object of the specified class. 23 | * 24 | * @param the type of the source object 25 | * @param the type of the result object 26 | * @param source the source object to map 27 | * @param resultClass the class of the result object 28 | * @return the mapped result object 29 | * @throws MappingException if schema was not resolved 30 | */ 31 | @NotNull R map(@NotNull S source, @NotNull Class resultClass) throws MappingException; 32 | 33 | /** 34 | * Maps a collection of source objects to a collection of result objects of the specified class. 35 | * 36 | * @param the type of the source objects 37 | * @param the type of the result objects 38 | * @param source the collection of source objects to map 39 | * @param resultClass the class of the result objects 40 | * @return the collection of mapped result objects 41 | * @throws MappingException if schema was not resolved 42 | */ 43 | @NotNull Collection map(@NotNull Collection source, @NotNull Class resultClass) throws MappingException; 44 | 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/configuration/mapper/resolver/SchemaResolver.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.mapper.resolver; 2 | 3 | import dev.temez.springlify.platform.configuration.mapper.schema.MappingSchema; 4 | import dev.temez.springlify.platform.exception.MappingException; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Interface for resolving mapping schemas between source and result classes. 9 | * 10 | *

This interface defines a method for retrieving the mapping schema for a given pair of source and result classes.

11 | * 12 | * @see MappingSchema 13 | * @see MappingException 14 | * @since 0.7.0.0-RC1 15 | */ 16 | public interface SchemaResolver { 17 | 18 | /** 19 | * Retrieves the mapping schema for mapping between the specified source and result classes. 20 | * 21 | * @param the type of the source objects 22 | * @param the type of the result objects 23 | * @param sourceClass the class of the source objects 24 | * @param resultClass the class of the result objects 25 | * @return the mapping schema for the specified source and result classes 26 | * @throws MappingException if there is an error retrieving the mapping schema 27 | */ 28 | @NotNull MappingSchema getSchema(@NotNull Class sourceClass, @NotNull Class resultClass) throws MappingException; 29 | } 30 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/configuration/mapper/schema/MappingSchema.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.mapper.schema; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * Interface representing a mapping schema for mapping between source and result objects. 9 | * 10 | *

This interface defines a method for mapping a single source object to a result object, 11 | * as well as a default method for mapping a collection of source objects to a collection of result objects.

12 | * 13 | * @param the type of the source objects 14 | * @param the type of the result objects 15 | * @since 0.7.0.0-RC1 16 | */ 17 | public interface MappingSchema { 18 | 19 | /** 20 | * Maps a source object to a result object. 21 | * 22 | * @param source the source object to map 23 | * @return the mapped result object 24 | */ 25 | @NotNull 26 | R map(@NotNull S source); 27 | 28 | /** 29 | * Maps a collection of source objects to a collection of result objects. 30 | * 31 | * @param sourceList the collection of source objects to map 32 | * @return the collection of mapped result objects 33 | */ 34 | default @NotNull Collection map(@NotNull Collection sourceList) { 35 | return sourceList.stream() 36 | .map(this::map) 37 | .toList(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/exception/FormattingException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class FormattingException extends RuntimeException { 6 | 7 | public FormattingException(@NotNull String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/exception/MappingException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Exception thrown to indicate an error related to mapping operations. 7 | * 8 | *

This exception is typically thrown when there is an issue with mapping between different data formats or structures.

9 | * 10 | * @since 0.7.0.0-RC1 11 | */ 12 | public class MappingException extends RuntimeException { 13 | 14 | /** 15 | * Constructs a new mapping exception with the specified detail message. 16 | * 17 | * @param message the detail message 18 | */ 19 | public MappingException(@NotNull String message) { 20 | super(message); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/exception/RegistryException.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Exception thrown to indicate an error related to registry operations. 7 | * 8 | *

This exception is typically thrown when there is an issue with accessing or manipulating registry entries.

9 | * 10 | * @since 0.7.0.0-RC1 11 | */ 12 | public class RegistryException extends RuntimeException { 13 | 14 | /** 15 | * Constructs a new registry exception with the specified detail message. 16 | * 17 | * @param message the detail message 18 | */ 19 | public RegistryException(@NotNull String message) { 20 | super(message); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/registry/Registry.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.registry; 2 | 3 | import dev.temez.springlify.platform.exception.RegistryException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.List; 7 | import java.util.Optional; 8 | 9 | /** 10 | * Interface representing a registry of entries. 11 | * 12 | *

This interface provides methods for accessing and manipulating a collection of registry entries.

13 | * 14 | * @param the type of the registry entry 15 | * @param the type of the identifier 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface Registry, I> { 19 | 20 | /** 21 | * Retrieves an unmodifiable list of entries in the registry. 22 | * 23 | * @return the unmodifiable list of entries 24 | */ 25 | @NotNull 26 | List getRegistry(); 27 | 28 | /** 29 | * Retrieves the entry with the specified identifier from the registry. 30 | * 31 | * @param id the identifier of the entry to retrieve 32 | * @return the entry with the specified identifier 33 | * @throws RegistryException if the entry with the specified identifier is not found 34 | */ 35 | default @NotNull T get(@NotNull I id) throws RegistryException { 36 | return getOptional(id) 37 | .orElseThrow(() -> new RegistryException("Entry in %s with id %s not found".formatted(getClass().getSimpleName(), id))); 38 | } 39 | 40 | /** 41 | * Retrieves the entry with the specified identifier from the registry, or null if not found. 42 | * 43 | * @param id the identifier of the entry to retrieve 44 | * @return the entry optional with the specified identifier 45 | */ 46 | default @NotNull Optional getOptional(@NotNull I id) { 47 | return getRegistry() 48 | .stream().filter(entry -> entry.getId().equals(id)) 49 | .findFirst(); 50 | } 51 | 52 | /** 53 | * Retrieves the next entry in the registry after the specified entry. 54 | * 55 | * @param entry the current entry 56 | * @return the next entry optional after the specified entry. 57 | */ 58 | default @NotNull Optional next(@NotNull T entry) { 59 | int index = getRegistry().indexOf(entry); 60 | if (index == -1 || index == getRegistry().size() - 1) { 61 | return Optional.empty(); 62 | } 63 | return Optional.of(getRegistry().get(index + 1)); 64 | } 65 | 66 | /** 67 | * Retrieves the default entry in the registry. 68 | * 69 | * @return the default entry 70 | */ 71 | default @NotNull T defaultValue() { 72 | return getRegistry().get(0); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/registry/RegistryEntry.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.registry; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Interface representing a registry entry with an identifier. 7 | * 8 | *

This interface defines a method for retrieving the identifier of the registry entry.

9 | * 10 | * @param the type of the identifier 11 | * @since 0.7.0.0-RC1 12 | */ 13 | public interface RegistryEntry { 14 | 15 | /** 16 | * Retrieves the identifier of the registry entry. 17 | * 18 | * @return the identifier 19 | */ 20 | @NotNull 21 | I getId(); 22 | } 23 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/server/ServerPlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.server; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Interface for adapting different server platforms to the Springlify framework. 7 | * 8 | *

This interface defines methods for registering and unregistering event listeners. 9 | * Implementations of this interface will handle the specific logic for their respective 10 | * server platforms.

11 | * 12 | * @since 0.7.0.0-RC1 13 | */ 14 | public interface ServerPlatformAdapter { 15 | 16 | /** 17 | * Registers the specified event listener with the server platform. 18 | * 19 | * @param listener the event listener to be registered 20 | */ 21 | void registerEventListener(@NotNull Object listener); 22 | 23 | /** 24 | * Unregisters the specified event listener from the server platform. 25 | * 26 | * @param listener the event listener to be unregistered 27 | */ 28 | void unregisterEventListener(@NotNull Object listener); 29 | 30 | /** 31 | * Registers a command executor with the platform (e.g., a server) associated with the plugin. 32 | * 33 | * @param command The command to register. 34 | * @param commandExecutor The command executor. 35 | * @param alias The command aliases. 36 | */ 37 | void registerCommandExecutor(@NotNull String command, @NotNull Object commandExecutor, @NotNull String... alias); 38 | } 39 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/text/converter/TextConverter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.text.converter; 2 | 3 | import net.kyori.adventure.text.Component; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | /** 10 | * Interface for converting text to adventure components. 11 | * 12 | *

This interface defines methods for parsing text lines into adventure components, 13 | * as well as providing a reset component for formatting.

14 | * 15 | * @see Component 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface TextConverter { 19 | 20 | /** 21 | * Parses a single text line into an adventure component. 22 | * 23 | * @param line the text line to parse 24 | * @return the adventure component representing the parsed line 25 | */ 26 | @NotNull 27 | Component parse(@NotNull String line); 28 | 29 | /** 30 | * Parses a collection of text lines into a list of adventure components. 31 | * 32 | * @param lines the collection of text lines to parse 33 | * @return the list of adventure components representing the parsed lines 34 | */ 35 | @NotNull 36 | List parse(@NotNull Collection lines); 37 | 38 | /** 39 | * Retrieves the reset component for formatting. 40 | * 41 | * @return the reset component 42 | */ 43 | @NotNull 44 | Component getResetComponent(); 45 | 46 | @NotNull 47 | String revert(@NotNull Component component); 48 | } 49 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/text/formatter/Replacer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.text.formatter; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.Getter; 5 | import lombok.experimental.FieldDefaults; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | @Getter 9 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 10 | public class Replacer { 11 | 12 | @NotNull 13 | String pattern; 14 | 15 | @NotNull 16 | String content; 17 | 18 | private Replacer(@NotNull Object pattern, @NotNull Object content) { 19 | this.pattern = pattern.toString(); 20 | this.content = content.toString(); 21 | } 22 | 23 | public static @NotNull Replacer of(@NotNull Object pattern, @NotNull Object content) { 24 | return new Replacer(pattern, content); 25 | } 26 | 27 | @NotNull String apply(@NotNull String string) { 28 | return string.replaceAll(pattern, content); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/text/formatter/TextFormatter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.text.formatter; 2 | 3 | import dev.temez.springlify.platform.exception.FormattingException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collection; 7 | import java.util.List; 8 | 9 | public interface TextFormatter { 10 | 11 | @NotNull String format(@NotNull String line, Object @NotNull ... replacers) throws FormattingException; 12 | 13 | @NotNull String format(@NotNull String line, @NotNull List replacers); 14 | 15 | @NotNull List format(@NotNull Collection lines, Object @NotNull ... replacers) throws FormattingException; 16 | 17 | @NotNull List format(@NotNull Collection lines, @NotNull List replacers); 18 | } 19 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/java/dev/temez/springlify/platform/text/formatter/TextFormatterImpl.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.text.formatter; 2 | 3 | import dev.temez.springlify.platform.exception.FormattingException; 4 | import lombok.AccessLevel; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.experimental.FieldDefaults; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Unmodifiable; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collection; 13 | import java.util.List; 14 | 15 | @Component 16 | @RequiredArgsConstructor 17 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 18 | public class TextFormatterImpl implements TextFormatter { 19 | 20 | @Override 21 | public @NotNull String format(@NotNull String line, Object @NotNull ... replacers) throws FormattingException { 22 | return format(line, parseReplacers(replacers)); 23 | } 24 | 25 | @Override 26 | public @NotNull String format(@NotNull String line, @NotNull List replacers) { 27 | for (Replacer replacer : replacers) { 28 | line = replacer.apply(line); 29 | } 30 | return line; 31 | } 32 | 33 | @Override 34 | public @NotNull List format(@NotNull Collection lines, Object @NotNull ... replacers) throws FormattingException { 35 | return format(lines, parseReplacers(replacers)); 36 | } 37 | 38 | @Override 39 | public @NotNull List format(@NotNull Collection lines, @NotNull List replacers) { 40 | return lines.stream() 41 | .map(line -> format(line, replacers)) 42 | .toList(); 43 | } 44 | 45 | private @NotNull @Unmodifiable List parseReplacers(Object @NotNull [] replacers) throws FormattingException { 46 | if (replacers.length % 2 != 0) { 47 | throw new FormattingException("Replacers array must have an even number length!"); 48 | } 49 | List result = new ArrayList<>(); 50 | for (int i = 0; i < replacers.length; i += 2) { 51 | result.add(Replacer.of(replacers[i], replacers[i + 1])); 52 | } 53 | return List.copyOf(result); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "springlify.platform.text-converter-mode", 5 | "type": "java.lang.String", 6 | "description": "Specifies which text converter should be used.", 7 | "defaultValue": "mini_message" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/test/java/dev/temez/springlify/platform/configuration/mapper/resolver/ContextSchemaResolverTest.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration.mapper.resolver; 2 | 3 | import dev.temez.springlify.platform.configuration.mapper.schema.MappingSchema; 4 | import dev.temez.springlify.platform.exception.MappingException; 5 | import lombok.AccessLevel; 6 | import lombok.experimental.FieldDefaults; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.jupiter.MockitoExtension; 12 | import org.springframework.context.ApplicationContext; 13 | import org.springframework.core.ResolvableType; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static org.junit.jupiter.api.Assertions.assertThrows; 17 | import static org.mockito.ArgumentMatchers.any; 18 | import static org.mockito.Mockito.mock; 19 | import static org.mockito.Mockito.when; 20 | 21 | @ExtendWith(MockitoExtension.class) 22 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 23 | class ContextSchemaResolverTest { 24 | 25 | @NotNull 26 | ApplicationContext applicationContext = mock(ApplicationContext.class); 27 | 28 | @NotNull 29 | SchemaResolver schemaResolver = new ContextSchemaResolver(applicationContext); 30 | 31 | @Test 32 | void givenApplicationContextWithNoSchemas_whenGetSchema_thenThrowException() { 33 | when(applicationContext.getBeanNamesForType(any(ResolvableType.class))).thenReturn(new String[]{}); 34 | assertThrows(MappingException.class, () -> schemaResolver.getSchema(Test.class, Test.class)); 35 | } 36 | 37 | @Test 38 | void givenApplicationContextWithMultipleSchemas_whenGetSchema_thenThrowException() { 39 | when(applicationContext.getBeanNamesForType(any(ResolvableType.class))).thenReturn(new String[]{"schema1", "schema2"}); 40 | assertThrows(MappingException.class, () -> schemaResolver.getSchema(Test.class, Test.class)); 41 | } 42 | 43 | 44 | @Test 45 | void givenApplicationContextWithSchema_whenGetSchema_thenReturnSchema(@Mock MappingSchema mappingSchema) { 46 | when(applicationContext.getBeanNamesForType(any(ResolvableType.class))).thenReturn(new String[]{"schema1"}); 47 | when(applicationContext.getBean("schema1")).thenReturn(mappingSchema); 48 | 49 | MappingSchema resolvedSchema = schemaResolver.getSchema(Test.class, Test.class); 50 | 51 | assertThat(resolvedSchema).isNotNull(); 52 | assertThat(resolvedSchema).isEqualTo(mappingSchema); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-commons/src/test/java/dev/temez/springlify/platform/text/converter/TextConverterIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.text.converter; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.experimental.FieldDefaults; 5 | import org.junit.jupiter.api.Nested; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.test.context.TestPropertySource; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | @SpringBootTest(classes = { 15 | LegacyTextConverter.class, 16 | MiniMessageTextConverter.class, 17 | }) 18 | class TextConverterIntegrationTest { 19 | 20 | @Nested 21 | @TestPropertySource(properties = { 22 | "springlify.platform.text-converter-mode=legacy" 23 | }) 24 | @FieldDefaults(level = AccessLevel.PRIVATE) 25 | class LegacyTextConverterTst { 26 | 27 | @Autowired 28 | ApplicationContext applicationContext; 29 | 30 | @Test 31 | void givenLegacyTextConverterEnabled_whenApplicationContextInitialized_thenTextConverterShouldBeLegacyTextConverter() { 32 | assertThat(applicationContext.getBean(TextConverter.class)).isInstanceOf(LegacyTextConverter.class); 33 | } 34 | } 35 | 36 | @Nested 37 | @TestPropertySource(properties = { 38 | "springlify.platform.text-converter-mode=mini_message" 39 | }) 40 | @FieldDefaults(level = AccessLevel.PRIVATE) 41 | class MiniMessageTextConverterTst { 42 | 43 | @Autowired 44 | ApplicationContext applicationContext; 45 | 46 | @Test 47 | void givenLegacyTextConverterEnabled_whenApplicationContextInitialized_thenTextConverterShouldBeLegacyMiniMessageTextConverter() { 48 | assertThat(applicationContext.getBean(TextConverter.class)).isInstanceOf(MiniMessageTextConverter.class); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-velocity/springlify-platform-velocity.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | dependencies { 4 | compileOnly libs.velocitypowered.velocitiyapi 5 | 6 | api project(":springlify-starter:springlify-starter-velocity") 7 | api project(":springlify-platform:springlify-platform-commons") 8 | 9 | testImplementation libs.velocitypowered.velocitiyapi 10 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-velocity/src/main/java/dev/temez/springlify/platform/annotation/VelocityCommand.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.annotation; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.springframework.core.annotation.AliasFor; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | 13 | /** 14 | * The {@code VelocityCommand} annotation is a custom annotation used to mark classes 15 | * as Velocity commands, for continuous auto registering with spring post processor. 16 | * 17 | *

Usage example: 18 | *

{@code
19 |  * @VelocityComand(command="mycommand, alias = {"alias1", "alias2"})
20 |  * public class MyCommand {
21 |  *
22 |  *  // Command execution logic
23 |  *
24 |  * }
25 |  * }
26 | * 27 | *

In this example, `MyCommand` is marked as a Velocity command with the primary command 28 | * "mycommand" and two aliases "alias1" and "alias2." 29 | * 30 | * @since 0.7.1.0-SNAPSHOT 31 | */ 32 | @Target(ElementType.TYPE) 33 | @Retention(RetentionPolicy.RUNTIME) 34 | @Component 35 | public @interface VelocityCommand { 36 | 37 | /** 38 | * Alias for the {@link Component} annotation's value attribute. 39 | * Specifies the name of the bean. 40 | * 41 | * @return The primary bean name. 42 | */ 43 | @AliasFor(annotation = Component.class) 44 | String value() default ""; 45 | 46 | /** 47 | * Specifies the primary command name. 48 | * 49 | * @return The primary command name. 50 | */ 51 | @NotNull 52 | String command(); 53 | 54 | /** 55 | * Specifies an array of alias names for the command. 56 | * 57 | * @return An array of alias names for the command. 58 | */ 59 | @NotNull 60 | String[] alias() default {}; 61 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-velocity/src/main/java/dev/temez/springlify/platform/annotation/VelocityEventListener.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.annotation; 2 | 3 | import org.springframework.core.annotation.AliasFor; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * The {@code VelocityEventHandler} annotation is a custom annotation used to mark classes as event 13 | * handlers when developing plugins for Velocity. 14 | * 15 | *

This annotation is used to declare that a class is an event listener, 16 | * and should be registered. 17 | * 18 | *

Usage example: 19 | *

{@code
20 |  * @Service
21 |  * @VelocityEventHandler
22 |  * public class MyListenableService {
23 |  *
24 |  *  @Subscribe
25 |  *  private void onEvent(@NotNull PlayerJoinEvent event) {
26 |  *    //event handling logic
27 |  *  }
28 |  *
29 |  * }
30 |  * }
31 | * 32 | *

In this example, `MyListenableService` is marked as an event handler class, and the 33 | * `onPlayerJoin` method is an event handler for the "PlayerJoinEvent." 34 | * 35 | * @since 0.7.1.0-SNAPSHOT 36 | */ 37 | @Retention(RetentionPolicy.RUNTIME) 38 | @Target({ElementType.TYPE}) 39 | @Component 40 | public @interface VelocityEventListener { 41 | 42 | 43 | /** 44 | * Alias for the {@link Component} annotation's value attribute. 45 | * Specifies the name of the bean. 46 | * 47 | * @return The primary bean name. 48 | */ 49 | @AliasFor(annotation = Component.class) 50 | String value() default ""; 51 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-velocity/src/main/java/dev/temez/springlify/platform/configuration/VelocityPluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.configuration; 2 | 3 | import com.velocitypowered.api.command.CommandManager; 4 | import com.velocitypowered.api.event.EventManager; 5 | import com.velocitypowered.api.plugin.PluginManager; 6 | import com.velocitypowered.api.proxy.ConsoleCommandSource; 7 | import com.velocitypowered.api.proxy.ProxyServer; 8 | import com.velocitypowered.api.scheduler.Scheduler; 9 | import dev.temez.springlify.starter.plugin.SpringlifyVelocityPlugin; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | @Configuration 15 | public class VelocityPluginConfiguration { 16 | 17 | @Bean 18 | @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") 19 | ProxyServer proxyServer(@NotNull SpringlifyVelocityPlugin plugin) { 20 | return plugin.getServer(); 21 | } 22 | 23 | @Bean 24 | ConsoleCommandSource consoleCommandSource(@NotNull ProxyServer proxyServer) { 25 | return proxyServer.getConsoleCommandSource(); 26 | } 27 | 28 | @Bean 29 | PluginManager pluginManager(@NotNull ProxyServer proxyServer) { 30 | return proxyServer.getPluginManager(); 31 | } 32 | 33 | @Bean 34 | EventManager eventManager(@NotNull ProxyServer proxyServer) { 35 | return proxyServer.getEventManager(); 36 | } 37 | 38 | @Bean 39 | CommandManager commandManager(@NotNull ProxyServer proxyServer) { 40 | return proxyServer.getCommandManager(); 41 | } 42 | 43 | @Bean 44 | Scheduler scheduler(@NotNull ProxyServer proxyServer) { 45 | return proxyServer.getScheduler(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-velocity/src/main/java/dev/temez/springlify/platform/initializer/EventListenerInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.initializer; 2 | 3 | import dev.temez.springlify.platform.annotation.VelocityEventListener; 4 | import dev.temez.springlify.platform.server.ServerPlatformAdapter; 5 | import lombok.AccessLevel; 6 | import lombok.experimental.FieldDefaults; 7 | import lombok.extern.log4j.Log4j2; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; 10 | import org.springframework.context.annotation.Lazy; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * The {@code ListenableServiceInitializer} class is a Spring DestructionAwareBeanPostProcessor. 15 | * It automatically registers and unregisters event listeners annotated with 16 | * {@link VelocityEventListener} when Spring beans are initialized and destroyed. 17 | * 18 | *

This class performs the following tasks: 19 | * - Detects beans annotated with {@link VelocityEventListener}. 20 | * - Registers event listeners with Velocity's event manager upon bean initialization. 21 | * - Unregisters event listeners from Velocity's event manager when beans are destroyed. 22 | * - Logs debug messages when registering and unregistering event listeners. 23 | * 24 | * @since 0.7.1.0-SNAPSHOT 25 | */ 26 | @Log4j2 27 | @Component 28 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 29 | public class EventListenerInitializer implements DestructionAwareBeanPostProcessor { 30 | 31 | @NotNull 32 | ServerPlatformAdapter serverPlatformAdapter; 33 | 34 | @Lazy 35 | public EventListenerInitializer(@NotNull ServerPlatformAdapter serverPlatformAdapter) { 36 | this.serverPlatformAdapter = serverPlatformAdapter; 37 | } 38 | 39 | @Override 40 | public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) { 41 | if (bean.getClass().isAnnotationPresent(VelocityEventListener.class)) { 42 | serverPlatformAdapter.registerEventListener(bean); 43 | } 44 | return bean; 45 | } 46 | 47 | @Override 48 | public void postProcessBeforeDestruction(@NotNull Object bean, @NotNull String beanName) { 49 | if (bean.getClass().isAnnotationPresent(VelocityEventListener.class)) { 50 | serverPlatformAdapter.unregisterEventListener(bean); 51 | log.debug("Unregistered {} from event manager.", bean.getClass().getSimpleName()); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /springlify-platform/springlify-platform-velocity/src/main/java/dev/temez/springlify/platform/server/VelocityServerPlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.platform.server; 2 | 3 | import com.velocitypowered.api.command.Command; 4 | import com.velocitypowered.api.command.CommandManager; 5 | import com.velocitypowered.api.event.EventManager; 6 | import dev.temez.springlify.starter.plugin.SpringlifyVelocityPlugin; 7 | import lombok.AccessLevel; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.experimental.FieldDefaults; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.springframework.stereotype.Component; 13 | 14 | @Slf4j 15 | @Component 16 | @RequiredArgsConstructor 17 | @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) 18 | public class VelocityServerPlatformAdapter implements ServerPlatformAdapter { 19 | 20 | @NotNull 21 | EventManager eventManager; 22 | 23 | @NotNull 24 | CommandManager commandManager; 25 | 26 | @NotNull 27 | SpringlifyVelocityPlugin plugin; 28 | 29 | @Override 30 | public void registerEventListener(@NotNull Object listener) { 31 | eventManager.register(plugin, listener); 32 | log.debug("Registered {} as an event listener", listener.getClass().getSimpleName()); 33 | 34 | } 35 | 36 | @Override 37 | public void unregisterEventListener(@NotNull Object listener) { 38 | eventManager.unregisterListener(plugin, listener); 39 | log.debug("Unregistered event listener: {}", listener.getClass().getSimpleName()); 40 | 41 | } 42 | 43 | @Override 44 | public void registerCommandExecutor(@NotNull String command, @NotNull Object commandExecutor, @NotNull String... alias) { 45 | commandManager.register(command, (Command) commandExecutor, alias); 46 | log.debug("Registered {} as a command executor", commandExecutor.getClass().getSimpleName()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /springlify-starter/README.md: -------------------------------------------------------------------------------- 1 | # springlify-starter 2 | 3 | A core module of the library that enables the usage of the `Spring Framework` with minor platform-specific improvements. 4 | It contains necessary abstractions and mechanisms to ensure compatibility with platforms such as `Bukkit`, `Velocity` 5 | and others. 6 | 7 | The module includes a `Spring Boot` configuration loader and a platform adapter for registering event listeners. 8 | 9 | Features 10 | 11 | - Spring Framework Integration: Seamlessly integrate Spring into your Minecraft plugin development. 12 | - Configuration Loader: Easily load and manage Spring configurations while developing plugins. 13 | - Platform Adapter: Easily register event listeners and command handlers specific to the platform. 14 | 15 | Select a link to the platform documentation. 16 | 17 | - [springlify-starter-bukkit](/springlify-starter-bukkit/README.md) 18 | - [springlify-starter-commons](/springlify-starter-commons/README.md) -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-bukkit/README.md: -------------------------------------------------------------------------------- 1 | # springlify-starter 2 | 3 | First, you need to create a Spring application class. Notice, spring application class and plugin main are not the same 4 | things. 5 | Specify base `scanBasePackages` for scanning through the library classes and our application ones. 6 | 7 | ```java 8 | @SpringBootApplication( 9 | scanBasePackages = { 10 | "dev.temez.springlify", 11 | "dev.temez.demo" 12 | } 13 | ) 14 | public class SpringlifyDemoApplication { 15 | 16 | } 17 | ``` 18 | 19 | Then, the main class of your plugin. You should extend your class from `SpringlifyBukkitPlugin`. 20 | 21 | ```java 22 | @SpringlifyApplication( 23 | springApplicationClass = SpringlifyExampleApplication.class 24 | ) 25 | public final class SpringlifyDemoPlugin extends SpringlifyBukkitPlugin { 26 | 27 | 28 | } 29 | ``` 30 | 31 | To build your project, use `./gradlew shadowJar` task. 32 | 33 | You are now ready to implement the main functionality of your plugin. 34 | Refer to the examples provided in `springlify-examples:example-bukkit-plugin` for guidance and good luck. 35 | 36 | ### Other starter features 37 | 38 | #### 1. Event handler auto registration 39 | 40 | Starter has a build in `EventHandlerInitializer`. 41 | It automatically will register and unregister a classes, which implement `Listener` as Bukkit event listeners. 42 | 43 | ```java 44 | 45 | @Component 46 | public class PlayerJoinListener implements Listener { 47 | 48 | @EventHandler 49 | public void onPlayerJoin(@NotNull PlayerJoinEvent event) { 50 | event.getPlayer().sendMessage("Welcome to the server!"); 51 | } 52 | } 53 | ``` 54 | 55 | #### 2. Command executor and completer auto registration 56 | 57 | Starter has a build in `CommandHandlerInitializer`. It will register classes which implement 58 | `CommandExecutor` and `TabCompleter` as Bukkit command executors and completers. 59 | 60 | ```java 61 | 62 | @BukkitCommand(command = "test") 63 | public class HelloCommand implements CommandExecutor { 64 | 65 | @Override 66 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String @NotNull [] args) { 67 | sender.sendMessage("Hello world!"); 68 | return true; 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-bukkit/springlify-starter-bukkit.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | dependencies { 4 | compileOnly libs.paper.paperapi 5 | 6 | api project(":springlify-starter:springlify-starter-commons") 7 | 8 | testImplementation libs.paper.paperapi 9 | } -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-bukkit/src/main/java/dev/temez/springlify/starter/plugin/SpringlifyBukkitPlugin.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.plugin; 2 | 3 | import dev.temez.springlify.starter.configuration.loader.ConfigurationLoader; 4 | import dev.temez.springlify.starter.configuration.loader.ConfigurationLoaderImpl; 5 | import dev.temez.springlify.starter.initializer.SpringlifyInitializer; 6 | import dev.temez.springlify.starter.initializer.SpringlifyInitializerImpl; 7 | import dev.temez.springlify.starter.initializer.loader.ClassLoaderFactory; 8 | import dev.temez.springlify.starter.initializer.loader.CompoundClassLoaderFactory; 9 | import lombok.AccessLevel; 10 | import lombok.Getter; 11 | import lombok.Setter; 12 | import lombok.experimental.FieldDefaults; 13 | import lombok.experimental.NonFinal; 14 | import org.bukkit.plugin.java.JavaPlugin; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.springframework.context.ConfigurableApplicationContext; 17 | 18 | /** 19 | * Base class for Bukkit plugins using the Springlify. 20 | * 21 | *

This abstract class extends {@link JavaPlugin} and implements {@link SpringlifyPlugin}. 22 | * It initializes necessary components for integrating Spring with Bukkit {@link ClassLoaderFactory}, and {@link ConfigurationLoader}. 23 | * It also provides lifecycle management methods for enabling and disabling the plugin.

24 | * 25 | * @see JavaPlugin 26 | * @see SpringlifyPlugin 27 | * @see ClassLoaderFactory 28 | * @see ConfigurationLoader 29 | * @since 0.7.0.0-RC1 30 | */ 31 | @Setter 32 | @Getter 33 | @FieldDefaults(makeFinal = true, level = AccessLevel.PROTECTED) 34 | public abstract class SpringlifyBukkitPlugin extends JavaPlugin implements SpringlifyPlugin { 35 | 36 | @NotNull 37 | ClassLoaderFactory classLoaderFactory = new CompoundClassLoaderFactory(); 38 | 39 | @NotNull 40 | ConfigurationLoader configurationLoader = new ConfigurationLoaderImpl(); 41 | 42 | @NotNull 43 | SpringlifyInitializer initializer = new SpringlifyInitializerImpl(classLoaderFactory, configurationLoader); 44 | 45 | @NonFinal 46 | ConfigurableApplicationContext context; 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | @Override 52 | public void onEnable() { 53 | initialize(); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public void onDisable() { 61 | shutdown(); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public ClassLoader getPluginClassLoader() { 69 | return getClassLoader(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/README.md: -------------------------------------------------------------------------------- 1 | # springlify-starter-commons 2 | 3 | A cross-platform part of `Springlify` starter. 4 | It contains necessary abstractions and mechanisms to ensure compatibility with platforms such as `Bukkit`, `Velocity` 5 | and others. 6 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/springlify-starter-commons.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | api libs.reflections.reflections 3 | api libs.spring.boot.starter 4 | } -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/annotation/SpringlifyApplication.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.annotation; 2 | 3 | 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * Annotation to mark a class as a Springlify application. 13 | * 14 | *

This annotation is used to specify the main Spring application class that will be 15 | * used to initialize the Spring context within a Bukkit plugin.

16 | * 17 | *

Usage:

18 | *
19 |  * @SpringlifyApplication(springApplicationClass = MySpringApplication.class)
20 |  * public class MyPlugin extends SpringlifyBukkitPlugin {
21 |  *     // Plugin code here
22 |  * }
23 |  * 
24 | * 25 | * @since 0.7.0.0-RC1 26 | */ 27 | @Target(ElementType.TYPE) 28 | @Retention(RetentionPolicy.RUNTIME) 29 | public @interface SpringlifyApplication { 30 | 31 | /** 32 | * Specifies the main Spring application class. 33 | * 34 | * @return the Spring application class 35 | */ 36 | @NotNull Class springApplicationClass(); 37 | } 38 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/configuration/SpringlifyPluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.configuration; 2 | 3 | import dev.temez.springlify.starter.initializer.SpringlifyInitializer; 4 | import dev.temez.springlify.starter.plugin.SpringlifyPlugin; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | /** 10 | * Spring configuration class for integrating Springlify plugins. 11 | * 12 | *

This class provides Spring beans for the {@link SpringlifyInitializer} 13 | * by retrieving them from the provided {@link SpringlifyPlugin} instance.

14 | * 15 | * @see SpringlifyInitializer 16 | * @see SpringlifyPlugin 17 | * @since 0.7.0.0-RC1 18 | */ 19 | @Configuration 20 | public class SpringlifyPluginConfiguration { 21 | 22 | 23 | /** 24 | * Provides the {@link SpringlifyInitializer} as a Spring bean. 25 | * 26 | * @param plugin the Springlify plugin instance 27 | * @return the Springlify initializer 28 | */ 29 | @Bean 30 | @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") 31 | SpringlifyInitializer springlifyInitializer(@NotNull SpringlifyPlugin plugin) { 32 | return plugin.getInitializer(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/configuration/loader/ConfigurationLoader.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.configuration.loader; 2 | 3 | import dev.temez.springlify.starter.plugin.SpringlifyPlugin; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.springframework.context.ConfigurableApplicationContext; 6 | 7 | /** 8 | * Interface for loading configurations into the Spring context of Springlify plugins. 9 | * 10 | *

This interface defines a method for loading configurations into a {@link ConfigurableApplicationContext} 11 | * for a given {@link SpringlifyPlugin}. Implementations of this interface will provide the logic 12 | * for loading configurations from various sources into the Spring context.

13 | * 14 | * @see ConfigurableApplicationContext 15 | * @see SpringlifyPlugin 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface ConfigurationLoader { 19 | 20 | /** 21 | * Loads configurations into the specified {@link ConfigurableApplicationContext} for the given {@link SpringlifyPlugin}. 22 | * 23 | * @param context the Spring application context 24 | * @param plugin the Springlify plugin instance 25 | * @throws IllegalStateException if there is an error during the loading process 26 | */ 27 | void load(@NotNull ConfigurableApplicationContext context, @NotNull SpringlifyPlugin plugin) throws IllegalStateException; 28 | } 29 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/initializer/SpringlifyInitializer.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.initializer; 2 | 3 | import dev.temez.springlify.starter.plugin.SpringlifyPlugin; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.springframework.context.ConfigurableApplicationContext; 6 | 7 | /** 8 | * Interface for initializing the Spring context of Springlify plugins. 9 | * 10 | *

This interface defines a method for initializing a {@link ConfigurableApplicationContext} for a given 11 | * {@link SpringlifyPlugin}. Implementations of this interface will provide the logic for setting up 12 | * the Spring context.

13 | * 14 | * @see ConfigurableApplicationContext 15 | * @see SpringlifyPlugin 16 | * @since 0.7.0.0-RC1 17 | */ 18 | public interface SpringlifyInitializer { 19 | 20 | /** 21 | * Initializes the Spring context for the specified {@link SpringlifyPlugin}. 22 | * 23 | * @param plugin the Springlify plugin instance 24 | * @return the initialized Spring application context 25 | * @throws IllegalStateException if there is an error during initialization 26 | */ 27 | @NotNull 28 | ConfigurableApplicationContext initialize(@NotNull SpringlifyPlugin plugin) throws IllegalStateException; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/initializer/event/ContextPreShutdownEvent.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.initializer.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | public class ContextPreShutdownEvent extends ApplicationEvent { 6 | 7 | public ContextPreShutdownEvent(Object source) { 8 | super(source); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/initializer/loader/ClassLoaderFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.initializer.loader; 2 | 3 | import dev.temez.springlify.starter.plugin.SpringlifyPlugin; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Interface for creating class loaders for Springlify plugins. 8 | * 9 | *

This interface defines a method for creating a {@link ClassLoader} specific to a {@link SpringlifyPlugin}. 10 | * Implementations of this interface will provide the logic for creating and configuring the class loader.

11 | * 12 | * @see ClassLoader 13 | * @see SpringlifyPlugin 14 | * @since 0.7.0.0-RC1 15 | */ 16 | public interface ClassLoaderFactory { 17 | 18 | /** 19 | * Creates a new {@link ClassLoader} for the specified {@link SpringlifyPlugin}. 20 | * 21 | * @param plugin the Springlify plugin instance 22 | * @return the created class loader 23 | */ 24 | @NotNull 25 | ClassLoader createClassLoader(@NotNull SpringlifyPlugin plugin); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-commons/src/main/java/dev/temez/springlify/starter/initializer/loader/CompoundClassLoaderFactory.java: -------------------------------------------------------------------------------- 1 | package dev.temez.springlify.starter.initializer.loader; 2 | 3 | import dev.temez.springlify.starter.plugin.SpringlifyPlugin; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Factory for creating a compound class loader for Springlify plugins. 11 | * 12 | *

This class implements {@link ClassLoaderFactory} and provides a method for creating a {@link CompoundClassLoader} 13 | * that combines multiple class loaders. The created class loader includes the class loader of the plugin 14 | * and the context class loader of the current thread.

15 | * 16 | * @see ClassLoaderFactory 17 | * @see CompoundClassLoader 18 | * @see SpringlifyPlugin 19 | * @since 0.7.0.0-RC1 20 | */ 21 | public class CompoundClassLoaderFactory implements ClassLoaderFactory { 22 | 23 | /** 24 | * {@inheritDoc} 25 | * 26 | * @param plugin the Springlify plugin instance 27 | * @return the created compound class loader 28 | */ 29 | @Override 30 | public @NotNull ClassLoader createClassLoader(@NotNull SpringlifyPlugin plugin) { 31 | List loaders = new ArrayList<>(2); 32 | loaders.add(plugin.getClass().getClassLoader()); 33 | loaders.add(Thread.currentThread().getContextClassLoader()); 34 | return new CompoundClassLoader(loaders); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /springlify-starter/springlify-starter-velocity/springlify-starter-velocity.gradle: -------------------------------------------------------------------------------- 1 | //file:noinspection GroovyAssignabilityCheck 2 | //file:noinspection DependencyNotationArgument 3 | dependencies { 4 | compileOnly libs.velocitypowered.velocitiyapi 5 | 6 | api project(":springlify-starter:springlify-starter-commons") 7 | 8 | testImplementation libs.velocitypowered.velocitiyapi 9 | } --------------------------------------------------------------------------------