├── .editorconfig ├── .github └── renovate.json ├── .gitignore ├── .teamcity ├── pom.xml └── settings.kts ├── LICENSE ├── README.md ├── app └── plugin │ ├── build.gradle.kts │ ├── core │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── org │ │ └── anvilpowered │ │ └── anvil │ │ └── plugin │ │ └── core │ │ ├── AnvilPlugin.kt │ │ ├── PluginMessages.kt │ │ └── command │ │ ├── AnvilCommandFactory.kt │ │ ├── common │ │ └── Help.kt │ │ ├── gameuser │ │ ├── GameUserCommand.kt │ │ └── Info.kt │ │ └── plugin │ │ ├── Info.kt │ │ ├── List.kt │ │ └── PluginCommandFactory.kt │ ├── paper │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── org │ │ └── anvilpowered │ │ └── anvil │ │ └── plugin │ │ └── paper │ │ └── AnvilPaperPluginBootstrap.kt │ ├── sponge │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── org │ │ └── anvilpowered │ │ └── anvil │ │ └── plugin │ │ └── sponge │ │ └── AnvilSpongePluginBootstrap.kt │ └── velocity │ ├── build.gradle.kts │ └── src │ └── main │ └── kotlin │ └── org │ └── anvilpowered │ └── anvil │ └── plugin │ └── velocity │ └── AnvilVelocityPluginBootstrap.kt ├── authors ├── build-logic ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── anvil-publish.gradle.kts │ └── anvil-sign.gradle.kts ├── build.gradle.kts ├── core ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── anvilpowered │ └── anvil │ └── core │ ├── AnvilApi.kt │ ├── PlatformType.kt │ ├── command │ ├── CommandExecutor.kt │ ├── CommandSource.kt │ ├── LoggingExecutor.kt │ ├── PlayerCommand.kt │ ├── TimeCommand.kt │ └── config │ │ ├── ConfigCommandFactory.kt │ │ ├── Generate.kt │ │ ├── Get.kt │ │ └── KeyArgument.kt │ ├── config │ ├── AbstractKeyBuilder.kt │ ├── ConfigurateFileType.kt │ ├── ConfigurateRegistry.kt │ ├── ConfigurateRegistryExporter.kt │ ├── DefaultRegistry.kt │ ├── EnvironmentRegistry.kt │ ├── Key.kt │ ├── KeyBuilderDsl.kt │ ├── KeyBuilding.kt │ ├── KeyNamespace.kt │ ├── ListKey.kt │ ├── ListKeyBuilder.kt │ ├── MapKey.kt │ ├── MapKeyBuilder.kt │ ├── Registration.kt │ ├── Registry.kt │ ├── Serialization.kt │ ├── SimpleKey.kt │ ├── SimpleKeyBuilder.kt │ └── TypeTokens.kt │ ├── db │ ├── DomainEntity.kt │ ├── MutableRepository.kt │ ├── Pagination.kt │ ├── Repository.kt │ └── SizedIterable.kt │ ├── platform │ ├── Platform.kt │ ├── PluginManager.kt │ ├── PluginMeta.kt │ └── Server.kt │ └── user │ ├── ArgumentExtensions.kt │ ├── Player.kt │ ├── PlayerService.kt │ └── Subject.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── paper ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── anvilpowered │ └── anvil │ └── paper │ ├── AnvilPaperApi.kt │ ├── command │ ├── AnvilPaperCommandSource.kt │ ├── PaperCommandExecutor.kt │ └── PaperSourceConverter.kt │ ├── platform │ ├── PaperPlatform.kt │ ├── PaperPluginManager.kt │ ├── PaperPluginMeta.kt │ └── PaperServer.kt │ └── user │ ├── AnvilPaperPlayer.kt │ ├── AnvilPaperSubject.kt │ └── PaperPlayerService.kt ├── settings.gradle.kts ├── sponge ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── anvilpowered │ └── anvil │ └── sponge │ ├── AnvilSpongeApi.kt │ ├── command │ ├── AnvilSpongeCommandSource.kt │ └── SpongeCommandExecutor.kt │ ├── platform │ ├── SpongePlatform.kt │ ├── SpongePluginManager.kt │ ├── SpongePluginMeta.kt │ └── SpongeServer.kt │ └── user │ ├── AnvilSpongePlayer.kt │ ├── AnvilSpongeSubject.kt │ └── SpongePlayerService.kt ├── velocity ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── org │ └── anvilpowered │ └── anvil │ └── velocity │ ├── AnvilVelocityApi.kt │ ├── command │ ├── AnvilVelocityCommandSource.kt │ ├── PlayerCommand.kt │ ├── VelocityCommandExecutor.kt │ └── VelocitySourceConverter.kt │ ├── platform │ ├── VelocityPlatform.kt │ ├── VelocityPluginManager.kt │ ├── VelocityPluginMeta.kt │ └── VelocityServer.kt │ └── user │ ├── AnvilVelocityPlayer.kt │ ├── AnvilVelocitySubject.kt │ ├── ArgumentExtensions.kt │ └── VelocityPlayerService.kt └── version /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 4 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | ij_kotlin_allow_trailing_comma_on_call_site = true 12 | ij_kotlin_allow_trailing_comma = true 13 | 14 | [*.{json,yml,yaml,xml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "addLabels": [ 6 | "dependency" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Intellij ### 2 | .idea/ 3 | *.iws 4 | out/ 5 | *.iml 6 | .idea_modules/ 7 | atlassian-ide-plugin.xml 8 | 9 | ### Eclipse ### 10 | .metadata 11 | bin/ 12 | tmp/ 13 | *.tmp 14 | *.bak 15 | *.swp 16 | *~.nib 17 | local.properties 18 | .settings/ 19 | .loadpath 20 | .recommenders 21 | .externalToolBuilders/ 22 | *.launch 23 | .factorypath 24 | .recommenders/ 25 | .apt_generated/ 26 | .project 27 | .classpath 28 | 29 | ### Linux ### 30 | *~ 31 | .fuse_hidden* 32 | .directory 33 | .Trash-* 34 | .nfs* 35 | 36 | ### macOS ### 37 | .DS_Store 38 | .AppleDouble 39 | .LSOverride 40 | Icon 41 | ._* 42 | .DocumentRevisions-V100 43 | .fseventsd 44 | .Spotlight-V100 45 | .TemporaryItems 46 | .Trashes 47 | .VolumeIcon.icns 48 | .com.apple.timemachine.donotpresent 49 | .AppleDB 50 | .AppleDesktop 51 | Network Trash Folder 52 | Temporary Items 53 | .apdisk 54 | 55 | ### NetBeans ### 56 | nbproject/private/ 57 | build/ 58 | nbbuild/ 59 | dist/ 60 | nbdist/ 61 | .nb-gradle/ 62 | 63 | ### Windows ### 64 | # Windows thumbnail cache files 65 | Thumbs.db 66 | ehthumbs.db 67 | ehthumbs_vista.db 68 | *.stackdump 69 | [Dd]esktop.ini 70 | $RECYCLE.BIN/ 71 | *.lnk 72 | 73 | ### Gradle ### 74 | .gradle 75 | # build/ already defined under netbeans 76 | gradle-app.setting 77 | !gradle-wrapper.jar 78 | .gradletasknamecache 79 | 80 | ### Kotlin/JS ### 81 | yarn.lock 82 | -------------------------------------------------------------------------------- /.teamcity/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | Anvil Config DSL Script 5 | anvil 6 | anvil_dsl 7 | 1.0-SNAPSHOT 8 | 9 | 10 | org.jetbrains.teamcity 11 | configs-dsl-kotlin-parent 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 16 | 17 | jetbrains-all 18 | https://download.jetbrains.com/teamcity-repository 19 | 20 | true 21 | 22 | 23 | 24 | teamcity-server 25 | https://ci.anvilpowered.org/app/dsl-plugins-repository 26 | 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | JetBrains 35 | https://download.jetbrains.com/teamcity-repository 36 | 37 | 38 | 39 | 40 | ${basedir} 41 | 42 | 43 | kotlin-maven-plugin 44 | org.jetbrains.kotlin 45 | ${kotlin.version} 46 | 47 | 48 | 49 | 50 | compile 51 | process-sources 52 | 53 | compile 54 | 55 | 56 | 57 | test-compile 58 | process-test-sources 59 | 60 | test-compile 61 | 62 | 63 | 64 | 65 | 66 | org.jetbrains.teamcity 67 | teamcity-configs-maven-plugin 68 | ${teamcity.dsl.version} 69 | 70 | kotlin 71 | target/generated-configs 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.jetbrains.teamcity 80 | configs-dsl-kotlin-latest 81 | ${teamcity.dsl.version} 82 | compile 83 | 84 | 85 | org.jetbrains.teamcity 86 | configs-dsl-kotlin-plugins-latest 87 | 1.0-SNAPSHOT 88 | pom 89 | compile 90 | 91 | 92 | org.jetbrains.kotlin 93 | kotlin-stdlib-jdk8 94 | ${kotlin.version} 95 | compile 96 | 97 | 98 | org.jetbrains.kotlin 99 | kotlin-script-runtime 100 | ${kotlin.version} 101 | compile 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Anvil 2 | 3 | [![Discord](https://img.shields.io/discord/675484700357296138)](https://discord.gg/6gR2YH3) [![TeamCity Full Build Status](https://img.shields.io/teamcity/build/e/Anvil_Build?server=http%3A%2F%2Fci.anvilpowered.org)](http://ci.anvilpowered.org/viewType.html?buildTypeId=Anvil_Build&guest=1) [![GitHub](https://img.shields.io/github/license/AnvilPowered/Anvil)](https://www.gnu.org/licenses/lgpl-3.0.html) [![Maven](https://img.shields.io/maven-central/v/org.anvilpowered/anvil-api?color=blue)](https://search.maven.org/artifact/org.anvilpowered/anvil-api) 4 | 5 | [CI](http://ci.anvilpowered.org) (Release candidate jars) 6 | 7 | Anvil is a mineraft plugin api that aims to help developers create structured cross-platform plugins. 8 | Included is an entity framework and many services that abstract platform-specific actions so that they can be used in common code. 9 | 10 | Anvil is not only cross-platform in the context of plugin platforms, but also in the context of databases. 11 | Currently, MongoDB and Xodus are supported, with SQL on the way. 12 | With Anvil, you can write a central abstract set of logic that applies to several database types. 13 | 14 | ## Quick start 15 | 16 | ```groovy 17 | repositories { 18 | mavenCentral(); 19 | } 20 | dependencies { 21 | implementation 'org.anvilpowered:anvil-api:0.1' 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /app/plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.shadow) 3 | } 4 | 5 | dependencies { 6 | implementation(project(":anvil-app-plugin-paper")) 7 | implementation(project(":anvil-app-plugin-sponge")) 8 | implementation(project(":anvil-app-plugin-velocity")) 9 | } 10 | 11 | tasks { 12 | shadowJar { 13 | archiveFileName = "anvil-plugin-${project.version}.jar" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/plugin/core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | api(project(":anvil-core")) 3 | api(platform(libs.adventure.bom)) 4 | compileOnlyApi("net.kyori:adventure-api") 5 | // compileOnlyApi(libs.logging.api) 6 | } 7 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/AnvilPlugin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core 20 | 21 | import org.anvilpowered.anvil.core.command.CommandSource 22 | import org.anvilpowered.anvil.plugin.core.command.AnvilCommandFactory 23 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 24 | import org.apache.logging.log4j.Logger 25 | 26 | class AnvilPlugin( 27 | private val logger: Logger, 28 | private val anvilCommandFactory: AnvilCommandFactory, 29 | ) { 30 | 31 | fun enable() { 32 | logger.info("Enabled anvil plugin") 33 | logger.info("Please note that this plugin is not required to use Anvil plugins") 34 | } 35 | 36 | fun disable() { 37 | logger.info("Disabled anvil plugin") 38 | } 39 | 40 | fun registerCommands(callback: (LiteralCommandNode) -> Unit) { 41 | logger.info("Building command tree...") 42 | val command = anvilCommandFactory.create() 43 | logger.info("Registering commands...") 44 | callback(command) 45 | logger.info("Finished registering commands.") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/PluginMessages.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core 20 | 21 | import net.kyori.adventure.text.Component 22 | import net.kyori.adventure.text.format.NamedTextColor 23 | 24 | object PluginMessages { 25 | val pluginPrefix = Component.text("[Anvil Agent] ").color(NamedTextColor.GOLD) 26 | val notEnoughArgs = Component.text("Not enough arguments!").color(NamedTextColor.RED) 27 | val noPermission = Component.text("Insufficient Permissions!").color(NamedTextColor.RED) 28 | } 29 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/AnvilCommandFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command 20 | 21 | import net.kyori.adventure.text.Component 22 | import org.anvilpowered.anvil.core.command.CommandSource 23 | import org.anvilpowered.anvil.plugin.core.command.common.addHelp 24 | import org.anvilpowered.anvil.plugin.core.command.plugin.PluginCommandFactory 25 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 26 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 27 | 28 | private val children = mapOf( 29 | "help" to Component.text("Shows this help message"), 30 | "plugin" to Component.text("Plugin management"), 31 | "version" to Component.text("Shows the Anvil Agent version"), 32 | ) 33 | 34 | class AnvilCommandFactory(private val pluginCommandFactory: PluginCommandFactory) { 35 | fun create(): LiteralCommandNode = 36 | ArgumentBuilder.literal("anvil") 37 | .addHelp("anvil", children) 38 | .then(pluginCommandFactory.create()) 39 | .build() 40 | } 41 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/common/Help.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command.common 20 | 21 | import net.kyori.adventure.text.Component 22 | import net.kyori.adventure.text.JoinConfiguration 23 | import net.kyori.adventure.text.format.NamedTextColor 24 | import org.anvilpowered.anvil.core.command.CommandSource 25 | import org.anvilpowered.anvil.plugin.core.PluginMessages 26 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 27 | import org.anvilpowered.kbrig.builder.executesSingleSuccess 28 | 29 | // TODO: Idea: Automatically detect usage from command node tree 30 | 31 | fun > B.executesUsage(usage: String): B = 32 | executes { 33 | it.source.sendMessage( 34 | Component.text() 35 | .append(PluginMessages.pluginPrefix) 36 | .append(Component.text("Command usage: ", NamedTextColor.GOLD)) 37 | .append(Component.text("/$usage", NamedTextColor.AQUA)), 38 | ) 39 | 0 40 | } 41 | 42 | fun > B.addHelp(baseName: String, children: Map): B = 43 | executes { context -> 44 | context.source.sendMessage( 45 | Component.text() 46 | .append(PluginMessages.pluginPrefix) 47 | .append(Component.text("Command usage: ", NamedTextColor.GOLD)) 48 | .append(Component.text("/$baseName", NamedTextColor.GREEN)) 49 | .append(Component.space()) 50 | .append(Component.text("${children.keys.joinToString("|")} ...", NamedTextColor.GREEN)) 51 | .append(Component.newline()) 52 | .append(Component.text("For more information see ", NamedTextColor.AQUA)) 53 | .append(Component.text("/$baseName help", NamedTextColor.GREEN)), 54 | ) 55 | 0 56 | }.then( 57 | ArgumentBuilder.literal("help").executesSingleSuccess { context -> 58 | context.source.sendMessage( 59 | Component.text() 60 | .append(PluginMessages.pluginPrefix) 61 | .append(Component.text("Command usage: ", NamedTextColor.GOLD)) 62 | .append(Component.text("/$baseName", NamedTextColor.GREEN)) 63 | .append(Component.newline()) 64 | .append(Component.text("Subcommands:", NamedTextColor.AQUA)) 65 | .append(Component.newline()) 66 | .append( 67 | Component.join( 68 | JoinConfiguration.newlines(), 69 | children.map { (command, description) -> 70 | Component.text() 71 | .append(Component.text(" /$baseName ", NamedTextColor.DARK_GRAY)) 72 | .append(Component.text(command, NamedTextColor.GREEN)) 73 | .append(Component.space()) 74 | .append(description.color(NamedTextColor.GRAY)) 75 | }, 76 | ), 77 | ), 78 | ) 79 | }, 80 | ) 81 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/gameuser/GameUserCommand.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command.gameuser 20 | 21 | import net.kyori.adventure.text.Component 22 | import org.anvilpowered.anvil.core.AnvilApi 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.anvil.core.user.requiresPermission 25 | import org.anvilpowered.anvil.plugin.core.command.common.addHelp 26 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 27 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 28 | 29 | private val children = mapOf( 30 | "help" to Component.text("Shows this help message"), 31 | "info" to Component.text("Shows information about a game user"), 32 | ) 33 | 34 | object GameUserCommand { 35 | context(AnvilApi) 36 | fun create(): LiteralCommandNode = 37 | ArgumentBuilder.literal("gameuser") 38 | .addHelp("anvil gameuser", children) 39 | .requiresPermission("anvil.agent.gameuser") 40 | .build() 41 | } 42 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/gameuser/Info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command.gameuser 20 | 21 | import net.kyori.adventure.text.Component 22 | import org.anvilpowered.anvil.core.AnvilApi 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.anvil.plugin.core.command.common.executesUsage 25 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 26 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 27 | 28 | private val children = mapOf( 29 | "help" to Component.text("Shows this help message"), 30 | "info" to Component.text("Shows information about a game user"), 31 | ) 32 | 33 | context(AnvilApi) 34 | fun GameUserCommand.createInfo(): LiteralCommandNode = 35 | ArgumentBuilder.literal("info") 36 | .executesUsage("anvil gameuser info ") 37 | .build() 38 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/plugin/Info.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command.plugin 20 | 21 | import net.kyori.adventure.text.Component 22 | import net.kyori.adventure.text.format.NamedTextColor 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.anvil.plugin.core.command.common.executesUsage 25 | import org.anvilpowered.kbrig.Command 26 | import org.anvilpowered.kbrig.argument.StringArgumentType 27 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 28 | import org.anvilpowered.kbrig.context.get 29 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 30 | 31 | fun PluginCommandFactory.createInfo(): LiteralCommandNode = 32 | ArgumentBuilder.literal("info") 33 | .executesUsage("anvil plugin info ") 34 | .then( 35 | ArgumentBuilder.required("name", StringArgumentType.SingleWord) 36 | .executes { context -> 37 | val name = context.get("name") 38 | val plugin = pluginManager.plugins.find { it.name == name } 39 | if (plugin == null) { 40 | context.source.sendMessage( 41 | Component.text() 42 | .append(Component.text("Plugin not found: ").color(NamedTextColor.RED)) 43 | .append(Component.text(name).color(NamedTextColor.WHITE)), 44 | ) 45 | 0 46 | } else { 47 | context.source.sendMessage( 48 | Component.text() 49 | .append(Component.text("Plugin: ").color(NamedTextColor.AQUA)) 50 | .append(Component.text(plugin.name).color(NamedTextColor.WHITE)), 51 | ) 52 | Command.SINGLE_SUCCESS 53 | } 54 | } 55 | .build(), 56 | ).build() 57 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/plugin/List.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command.plugin 20 | 21 | import net.kyori.adventure.text.Component 22 | import net.kyori.adventure.text.format.NamedTextColor 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 25 | import org.anvilpowered.kbrig.builder.executesSingleSuccess 26 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 27 | 28 | fun PluginCommandFactory.createList(): LiteralCommandNode = 29 | ArgumentBuilder.literal("list") 30 | .executesSingleSuccess { context -> 31 | val pluginNamesString = pluginManager.plugins.joinToString(", ") { it.name } 32 | context.source.sendMessage( 33 | Component.text("Plugins: $pluginNamesString").color(NamedTextColor.AQUA), 34 | ) 35 | }.build() 36 | -------------------------------------------------------------------------------- /app/plugin/core/src/main/kotlin/org/anvilpowered/anvil/plugin/core/command/plugin/PluginCommandFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.core.command.plugin 20 | 21 | import net.kyori.adventure.text.Component 22 | import org.anvilpowered.anvil.core.command.CommandSource 23 | import org.anvilpowered.anvil.core.platform.PluginManager 24 | import org.anvilpowered.anvil.core.user.requiresPermission 25 | import org.anvilpowered.anvil.plugin.core.command.common.addHelp 26 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 27 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 28 | 29 | private val children = mapOf( 30 | "help" to Component.text("Shows this help message"), 31 | "list" to Component.text("Lists all plugins"), 32 | "info " to Component.text("Shows information about a plugin"), 33 | ) 34 | 35 | class PluginCommandFactory(val pluginManager: PluginManager) { 36 | fun create(): LiteralCommandNode = 37 | ArgumentBuilder.literal("plugin") 38 | .addHelp("anvil plugin", children) 39 | .requiresPermission("anvil.agent.plugin") 40 | .then(createList()) 41 | .then(createInfo()) 42 | .build() 43 | } 44 | -------------------------------------------------------------------------------- /app/plugin/paper/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.shadow) 3 | alias(libs.plugins.pluginyml) 4 | } 5 | 6 | dependencies { 7 | implementation(project(":anvil-app-plugin-core")) 8 | implementation(project(":anvil-paper")) 9 | compileOnly(libs.brigadier) 10 | compileOnly(libs.paper) 11 | } 12 | 13 | paper { 14 | name = "anvil-agent" 15 | main = "org.anvilpowered.anvil.plugin.AnvilPaperPluginBootstrap" 16 | foliaSupported = true 17 | apiVersion = "1.19" 18 | authors = rootProject.file("authors").readLines().map { it.substringBefore(',') } 19 | } 20 | -------------------------------------------------------------------------------- /app/plugin/paper/src/main/kotlin/org/anvilpowered/anvil/plugin/paper/AnvilPaperPluginBootstrap.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:Suppress("UnstableApiUsage") 20 | 21 | package org.anvilpowered.anvil.plugin.paper 22 | 23 | import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents 24 | import org.anvilpowered.anvil.core.AnvilApi 25 | import org.anvilpowered.anvil.paper.command.toPaper 26 | import org.anvilpowered.anvil.paper.createPaper 27 | import org.anvilpowered.anvil.plugin.core.AnvilPlugin 28 | import org.bukkit.event.Listener 29 | import org.bukkit.plugin.java.JavaPlugin 30 | import org.koin.dsl.koinApplication 31 | 32 | class AnvilPaperPluginBootstrap : JavaPlugin(), Listener { 33 | 34 | private lateinit var plugin: AnvilPlugin 35 | 36 | override fun onEnable() { 37 | val bootstrapPlugin = this 38 | logger.info { "Registering events" } 39 | plugin = koinApplication { modules(AnvilApi.createPaper(bootstrapPlugin).module) }.koin.get() 40 | plugin.enable() 41 | lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS) { event -> 42 | plugin.registerCommands { command -> 43 | event.registrar().register(command.toPaper()) 44 | } 45 | } 46 | } 47 | 48 | override fun onDisable() = plugin.disable() 49 | } 50 | -------------------------------------------------------------------------------- /app/plugin/sponge/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.spongepowered.gradle.plugin.config.PluginLoaders 2 | 3 | plugins { 4 | alias(libs.plugins.sponge) 5 | alias(libs.plugins.shadow) 6 | } 7 | 8 | // TODO: Should not be necessary, but it seems sponge is nuking the repositories define in settings 9 | repositories { 10 | mavenLocal() 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation(project(":anvil-app-plugin-core")) 16 | implementation(project(":anvil-sponge")) 17 | compileOnly(libs.brigadier) 18 | } 19 | 20 | sponge { 21 | apiVersion("8.1.0-SNAPSHOT") 22 | license("AGPL-3.0") 23 | loader { 24 | name(PluginLoaders.JAVA_PLAIN) 25 | version("1.0") 26 | } 27 | plugin("anvil-agent") { 28 | displayName("Anvil Agent") 29 | version.set(project.version.toString()) 30 | entrypoint("org.anvilpowered.anvil.agent.AnvilSpongePlugin") 31 | description("Agent plugin for the Anvil system") 32 | // dependency("spongeapi") { 33 | // loadOrder(LoadOrder.AFTER) 34 | // } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/plugin/sponge/src/main/kotlin/org/anvilpowered/anvil/plugin/sponge/AnvilSpongePluginBootstrap.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.sponge 20 | 21 | import com.google.inject.Inject 22 | import org.apache.logging.log4j.Logger 23 | import org.spongepowered.api.event.Listener 24 | import org.spongepowered.api.event.lifecycle.ConstructPluginEvent 25 | import org.spongepowered.plugin.builtin.jvm.Plugin 26 | 27 | @Plugin("anvil-agent") 28 | class AnvilSpongePluginBootstrap @Inject constructor( 29 | private val logger: Logger, 30 | ) { 31 | 32 | @Listener 33 | fun onServerStart(event: ConstructPluginEvent) { 34 | logger.warn("Hello, world! ${event.plugin()}") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/plugin/velocity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("kapt") 3 | } 4 | 5 | dependencies { 6 | implementation(project(":anvil-app-plugin-core")) 7 | implementation(project(":anvil-velocity")) 8 | compileOnly(libs.velocity) 9 | kapt(libs.velocity) 10 | } 11 | -------------------------------------------------------------------------------- /app/plugin/velocity/src/main/kotlin/org/anvilpowered/anvil/plugin/velocity/AnvilVelocityPluginBootstrap.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.plugin.velocity 20 | 21 | import com.google.inject.Inject 22 | import com.google.inject.Injector 23 | import com.velocitypowered.api.command.BrigadierCommand 24 | import com.velocitypowered.api.event.Subscribe 25 | import com.velocitypowered.api.event.proxy.ProxyInitializeEvent 26 | import com.velocitypowered.api.plugin.Plugin 27 | import com.velocitypowered.api.proxy.ProxyServer 28 | import org.anvilpowered.anvil.core.AnvilApi 29 | import org.anvilpowered.anvil.plugin.core.AnvilPlugin 30 | import org.anvilpowered.anvil.velocity.command.toVelocity 31 | import org.anvilpowered.anvil.velocity.createVelocity 32 | import org.koin.dsl.koinApplication 33 | 34 | @Plugin( 35 | id = "anvil-agent", 36 | name = "Anvil Agent", 37 | version = "0.4.0-SNAPSHOT", 38 | authors = ["AnvilPowered"], 39 | ) 40 | class AnvilVelocityPluginBootstrap @Inject constructor( 41 | private val proxyServer: ProxyServer, 42 | private val injector: Injector, 43 | ) { 44 | 45 | private lateinit var plugin: AnvilPlugin 46 | 47 | @Subscribe 48 | fun onProxyInit(event: ProxyInitializeEvent) { 49 | plugin = koinApplication { modules(AnvilApi.createVelocity(injector).module) }.koin.get() 50 | plugin.registerCommands { command -> 51 | proxyServer.commandManager.register(BrigadierCommand(command.toVelocity())) 52 | } 53 | proxyServer.eventManager.register(this, plugin) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /authors: -------------------------------------------------------------------------------- 1 | alexstaeding,Alexander Städing 2 | -------------------------------------------------------------------------------- /build-logic/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | `kotlin-dsl` 5 | } 6 | 7 | dependencies { 8 | implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}") 9 | } 10 | 11 | tasks { 12 | withType { 13 | kotlinOptions.jvmTarget = "17" 14 | } 15 | withType { 16 | options.encoding = "UTF-8" 17 | sourceCompatibility = "17" 18 | targetCompatibility = "17" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /build-logic/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | dependencyResolutionManagement { 4 | repositories { 5 | gradlePluginPortal() 6 | mavenCentral() 7 | } 8 | versionCatalogs { 9 | register("libs") { 10 | from(files("../gradle/libs.versions.toml")) // include from parent project 11 | } 12 | } 13 | } 14 | 15 | rootProject.name = "build-logic" 16 | -------------------------------------------------------------------------------- /build-logic/src/main/kotlin/anvil-publish.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.net.URI 2 | 3 | plugins { 4 | `maven-publish` 5 | } 6 | 7 | extensions.configure { 8 | withJavadocJar() 9 | withSourcesJar() 10 | } 11 | 12 | extensions.configure { 13 | repositories { 14 | maven { 15 | credentials { 16 | username = System.getenv("SONATYPE_USERNAME") 17 | password = System.getenv("SONATYPE_PASSWORD") 18 | } 19 | val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 20 | val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots" 21 | url = URI(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl) 22 | } 23 | } 24 | publications.register("maven") { 25 | from(components["java"]) 26 | pom { 27 | name.set("anvil") 28 | url.set("https://www.anvilpowered.org") 29 | scm { 30 | url.set("https://github.com/anvilpowered/anvil") 31 | connection.set("scm:git:https://github.com/anvilpowered/anvil.git") 32 | developerConnection.set("scm:git:https://github.com/anvilpowered/anvil.git") 33 | } 34 | licenses { 35 | license { 36 | name.set("GNU AFFERO GENERAL PUBLIC LICENSE Version 3") 37 | url.set("https://www.gnu.org/licenses/agpl-3.0.html") 38 | distribution.set("repo") 39 | } 40 | } 41 | developers { 42 | rootProject.file("authors").readLines() 43 | .asSequence() 44 | .map { it.split(",") } 45 | .forEach { (_id, _name) -> developer { id.set(_id); name.set(_name) } } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /build-logic/src/main/kotlin/anvil-sign.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | signing 3 | } 4 | 5 | extensions.configure { 6 | if (System.getenv("AGENT_NAME")?.contains("publishing") != true) { 7 | return@configure 8 | } 9 | extensions.configure { 10 | useInMemoryPgpKeys( 11 | /* defaultKeyId = */ System.getenv("SIGNING_KEY_ID"), 12 | /* defaultSecretKey = */ System.getenv("SIGNING_KEY"), 13 | /* defaultPassword = */ System.getenv("SIGNING_PASSWORD"), 14 | ) 15 | publications.withType { 16 | val signingTasks = sign(this) 17 | tasks.withType { 18 | dependsOn(signingTasks) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | import java.io.ByteArrayOutputStream 3 | 4 | plugins { 5 | alias(libs.plugins.kotlin.jvm) 6 | alias(libs.plugins.ktlint) 7 | alias(libs.plugins.kotlin.serialization) 8 | } 9 | 10 | val projectVersion: String = run { 11 | val rawVersion = file("version").readLines().first() 12 | if (project.hasProperty("rawVersion")) { 13 | rawVersion 14 | } else { 15 | val branch = System.getenv("VCS_BRANCH")?.replace('/', '-') ?: "unknown-branch" 16 | System.getenv("BUILD_NUMBER")?.let { buildNumber -> 17 | val gitRev = ByteArrayOutputStream() 18 | exec { 19 | commandLine("git", "rev-parse", "--short", "HEAD") 20 | standardOutput = gitRev 21 | }.assertNormalExitValue() 22 | rawVersion.replace("SNAPSHOT", "BETA$buildNumber-$branch-${gitRev.toString().trim()}") 23 | } ?: rawVersion 24 | } 25 | } 26 | 27 | logger.warn("Resolved project version $projectVersion") 28 | 29 | allprojects { 30 | apply(plugin = "org.jetbrains.kotlin.jvm") 31 | apply(plugin = "org.jlleitschuh.gradle.ktlint") 32 | apply(plugin = "java-library") 33 | 34 | group = "org.anvilpowered" 35 | version = projectVersion 36 | 37 | kotlin { 38 | compilerOptions { 39 | jvmTarget = JvmTarget.JVM_21 40 | freeCompilerArgs = listOf( 41 | "-opt-in=kotlin.RequiresOptIn", 42 | "-Xcontext-receivers", 43 | ) 44 | } 45 | } 46 | 47 | java { 48 | toolchain.languageVersion.set(JavaLanguageVersion.of(21)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("anvil-publish") 3 | id("anvil-sign") 4 | `java-library` 5 | } 6 | 7 | dependencies { 8 | api(libs.kbrig.brigadier) 9 | api(libs.kotlinx.serialization) 10 | api(libs.kotlinx.coroutines) 11 | api(libs.configurate.core) 12 | api(libs.configurate.hocon) 13 | api(libs.configurate.yaml) 14 | api(libs.configurate.extra.kotlin) 15 | api(libs.koin) 16 | 17 | compileOnlyApi(libs.logging.api) 18 | compileOnly(libs.annotations) 19 | compileOnly(platform(libs.adventure.bom)) 20 | compileOnly("net.kyori:adventure-api") 21 | compileOnly("net.kyori:adventure-text-minimessage") 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/AnvilApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core 20 | 21 | import org.apache.logging.log4j.Logger 22 | import org.koin.core.module.Module 23 | import java.nio.file.Path 24 | 25 | /** 26 | * To create an instance of this interface, use the `AnvilApi.create` function. 27 | * This is available for each platform in the corresponding `anvil-` module. 28 | * 29 | * Generally, the method will look something like this: 30 | * ```kt 31 | * AnvilApi.create<<>>("my-plugin", ....) 32 | * ``` 33 | * 34 | * For example, for Velocity: 35 | * 36 | * ```kt 37 | * AnvilApi.createVelocity("my-plugin", ....) 38 | * ``` 39 | */ 40 | interface AnvilApi { 41 | 42 | val logger: Logger 43 | 44 | val configDir: Path 45 | 46 | val module: Module 47 | 48 | companion object 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/PlatformType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core 20 | 21 | interface PlatformType { 22 | 23 | val platformDelegate: Any 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/CommandExecutor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command 20 | 21 | interface CommandExecutor { 22 | 23 | suspend fun execute(source: CommandSource, command: String): Boolean 24 | 25 | suspend fun executeAsConsole(command: String): Boolean 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/CommandSource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import org.anvilpowered.anvil.core.PlatformType 23 | import org.anvilpowered.anvil.core.user.Player 24 | import org.anvilpowered.anvil.core.user.Subject 25 | 26 | interface CommandSource : PlatformType, Audience, Subject { 27 | 28 | /** 29 | * The [Player] associated with the executed command, if any. 30 | */ 31 | val player: Player? 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/LoggingExecutor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command 20 | 21 | import org.apache.logging.log4j.Logger 22 | 23 | fun CommandExecutor.withLogging(logger: Logger, prefix: String = "command"): CommandExecutor = object : CommandExecutor { 24 | private fun log(success: Boolean, prefix: String, command: String) { 25 | if (success) { 26 | logger.info("$prefix: $command") 27 | } else { 28 | logger.error("Failed to execute $prefix: $command") 29 | } 30 | } 31 | 32 | override suspend fun execute(source: CommandSource, command: String): Boolean { 33 | val success = this@withLogging.execute(source, command) 34 | log(success, prefix, command) 35 | return success 36 | } 37 | 38 | override suspend fun executeAsConsole(command: String): Boolean { 39 | val success = this@withLogging.executeAsConsole(command) 40 | log(success, "console via $prefix", command) 41 | return success 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/PlayerCommand.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command 20 | 21 | import net.kyori.adventure.text.Component 22 | import net.kyori.adventure.text.format.NamedTextColor 23 | import org.anvilpowered.anvil.core.user.Player 24 | import org.anvilpowered.anvil.core.user.PlayerService 25 | import org.anvilpowered.kbrig.argument.StringArgumentType 26 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 27 | import org.anvilpowered.kbrig.builder.RequiredArgumentBuilder 28 | import org.anvilpowered.kbrig.context.CommandContext 29 | import org.anvilpowered.kbrig.context.CommandContextScopeDsl 30 | import org.anvilpowered.kbrig.context.CommandExecutionScope 31 | import org.anvilpowered.kbrig.context.executesScoped 32 | import org.anvilpowered.kbrig.context.get 33 | import org.anvilpowered.kbrig.context.yieldError 34 | import org.anvilpowered.kbrig.suggestion.suggestsScoped 35 | 36 | fun ArgumentBuilder.Companion.requirePlayerArgument( 37 | playerService: PlayerService, 38 | argumentName: String = "player", 39 | command: suspend (context: CommandContext, player: Player) -> Int, 40 | ): RequiredArgumentBuilder = 41 | required("player", StringArgumentType.SingleWord) 42 | .suggestPlayerArgument(playerService) 43 | .executesScoped { yield(command(context, extractPlayerArgument(playerService, argumentName))) } 44 | 45 | fun ArgumentBuilder.Companion.requirePlayerArgumentScoped( 46 | playerService: PlayerService, 47 | argumentName: String = "player", 48 | command: suspend CommandExecutionScope.(player: Player) -> Unit, 49 | ): RequiredArgumentBuilder = 50 | required("player", StringArgumentType.SingleWord) 51 | .suggestPlayerArgument(playerService) 52 | .executesScoped { command(extractPlayerArgument(playerService, argumentName)) } 53 | 54 | fun RequiredArgumentBuilder.suggestPlayerArgument( 55 | playerService: PlayerService, 56 | ): RequiredArgumentBuilder = 57 | suggestsScoped { playerService.getAll().suggestAllFiltered { it.username } } 58 | 59 | @CommandContextScopeDsl 60 | suspend fun CommandExecutionScope.extractPlayerArgument( 61 | playerService: PlayerService, 62 | argumentName: String = "player", 63 | ): Player { 64 | val playerName = context.get(argumentName) 65 | val player = playerService[playerName] 66 | if (player == null) { 67 | context.source.sendMessage( 68 | Component.text() 69 | .append(Component.text("Player with name ", NamedTextColor.RED)) 70 | .append(Component.text(playerName, NamedTextColor.GOLD)) 71 | .append(Component.text(" not found!", NamedTextColor.RED)) 72 | .build(), 73 | ) 74 | yieldError() 75 | } 76 | return player 77 | } 78 | 79 | @CommandContextScopeDsl 80 | suspend fun CommandExecutionScope.extractPlayerSource(): Player { 81 | val player = extractPlayerSourceOrNull() 82 | if (player == null) { 83 | context.source.sendMessage(Component.text("You must be a player to use this command!", NamedTextColor.RED)) 84 | yieldError() 85 | } 86 | return player 87 | } 88 | 89 | @CommandContextScopeDsl 90 | fun CommandContext.Scope.extractPlayerSourceOrNull(): Player? = context.source.player 91 | 92 | @CommandContextScopeDsl 93 | suspend fun CommandContext.Scope.extractPlayerSourceOrAbort(): Player = extractPlayerSourceOrNull() ?: abort() 94 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/config/ConfigCommandFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command.config 20 | 21 | import org.anvilpowered.anvil.core.command.CommandSource 22 | import org.anvilpowered.anvil.core.config.ConfigurateRegistry 23 | import org.anvilpowered.anvil.core.config.ConfigurateRegistryExporter 24 | import org.anvilpowered.anvil.core.config.KeyNamespace 25 | import org.anvilpowered.anvil.core.config.Registry 26 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 27 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 28 | import org.spongepowered.configurate.serialize.TypeSerializerCollection 29 | 30 | class ConfigCommandFactory( 31 | val registry: Registry, 32 | val configurateRegistryClosure: ConfigurateRegistry.Factory.DiscoveryClosure, 33 | val keyNamespace: KeyNamespace, 34 | val exporters: List, 35 | val serializers: TypeSerializerCollection, 36 | ) { 37 | fun create(): LiteralCommandNode { 38 | return ArgumentBuilder.literal("config") 39 | .then(createGet()) 40 | .then(createGenerate()) 41 | .build() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/config/Get.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command.config 20 | 21 | import kotlinx.serialization.json.Json 22 | import net.kyori.adventure.text.Component 23 | import net.kyori.adventure.text.event.ClickEvent 24 | import net.kyori.adventure.text.format.NamedTextColor 25 | import net.kyori.adventure.text.format.TextDecoration 26 | import org.anvilpowered.anvil.core.command.CommandSource 27 | import org.anvilpowered.anvil.core.config.serialize 28 | import org.anvilpowered.anvil.core.config.serializeDefault 29 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 30 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 31 | 32 | private val prettyJson = Json { 33 | prettyPrint = true 34 | encodeDefaults = true 35 | } 36 | 37 | fun ConfigCommandFactory.createGet(): LiteralCommandNode = 38 | ArgumentBuilder.literal("get") 39 | .then( 40 | keyNamespace.keyArgument { context, key -> 41 | val defaultValue = registry.serializeDefault(key, prettyJson) 42 | val currentValue = registry.serialize(key, prettyJson) 43 | context.source.sendMessage( 44 | Component.text() 45 | .append(Component.text("Key ").color(NamedTextColor.GREEN)) 46 | .append(Component.text(key.name).color(NamedTextColor.GOLD).decorate(TextDecoration.BOLD)) 47 | .append(Component.newline()) 48 | .append(Component.text("Type: ").color(NamedTextColor.GREEN)) 49 | .append(Component.text(key.type.type.toString()).color(NamedTextColor.GRAY)) 50 | .append(Component.newline()) 51 | .append(Component.text("Default value: ").color(NamedTextColor.GREEN)) 52 | .append( 53 | Component.text(defaultValue).color(NamedTextColor.GRAY) 54 | .hoverEvent(Component.text("Click to copy default value").color(NamedTextColor.GRAY)) 55 | .clickEvent(ClickEvent.copyToClipboard(defaultValue)), 56 | ) 57 | .append(Component.newline()) 58 | .append(Component.text("Current value: ").color(NamedTextColor.GREEN)) 59 | .append( 60 | Component.text(currentValue).color(NamedTextColor.GRAY) 61 | .hoverEvent(Component.text("Click to copy current value").color(NamedTextColor.GRAY)) 62 | .clickEvent(ClickEvent.copyToClipboard(currentValue)), 63 | ) 64 | .build(), 65 | ) 66 | 1 67 | }, 68 | ).build() 69 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/command/config/KeyArgument.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.command.config 20 | 21 | import net.kyori.adventure.text.Component 22 | import net.kyori.adventure.text.format.NamedTextColor 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.anvil.core.config.Key 25 | import org.anvilpowered.anvil.core.config.KeyNamespace 26 | import org.anvilpowered.kbrig.argument.StringArgumentType 27 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 28 | import org.anvilpowered.kbrig.builder.RequiredArgumentBuilder 29 | import org.anvilpowered.kbrig.context.CommandContext 30 | import org.anvilpowered.kbrig.context.get 31 | 32 | fun KeyNamespace.keyArgument( 33 | argumentName: String = "key", 34 | command: (context: CommandContext, key: Key<*>) -> Int, 35 | ): RequiredArgumentBuilder = 36 | ArgumentBuilder.required(argumentName, StringArgumentType.SingleWord) 37 | .suggests { _, builder -> 38 | keys.filter { it.name.contains(builder.remainingLowerCase, ignoreCase = true) }.forEach { key -> 39 | builder.suggest(key.name) 40 | } 41 | builder.build() 42 | }.executes { context -> 43 | val keyName = context.get(argumentName) 44 | keys.find { it.name == keyName }?.let { key -> 45 | command(context, key) 46 | } ?: run { 47 | context.source.sendMessage( 48 | Component.text() 49 | .append(Component.text("Key with name ", NamedTextColor.RED)) 50 | .append(Component.text(keyName, NamedTextColor.GOLD)) 51 | .append(Component.text(" not found!", NamedTextColor.RED)) 52 | .build(), 53 | ) 54 | 0 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/AbstractKeyBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | 23 | abstract class AbstractKeyBuilder< 24 | T : Any, K : Key, B : Key.FacetedBuilder, 25 | AF : Key.BuilderFacet, NF : Key.NamedBuilderFacet, 26 | >(val type: TypeToken) : Key.FacetedBuilder { 27 | 28 | var name: String? = null 29 | var fallback: T? = null 30 | var description: String? = null 31 | 32 | protected abstract fun self(): B 33 | 34 | override fun name(name: String): B { 35 | this.name = name 36 | return self() 37 | } 38 | 39 | override fun fallback(fallback: T?): B { 40 | this.fallback = fallback 41 | return self() 42 | } 43 | 44 | override fun description(description: String?): B { 45 | this.description = description 46 | return self() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/ConfigurateFileType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import org.koin.core.module.Module 22 | import org.koin.core.module.dsl.named 23 | import org.koin.core.module.dsl.withOptions 24 | import org.spongepowered.configurate.CommentedConfigurationNode 25 | import org.spongepowered.configurate.hocon.HoconConfigurationLoader 26 | import org.spongepowered.configurate.kotlin.objectMapperFactory 27 | import org.spongepowered.configurate.loader.AbstractConfigurationLoader 28 | import org.spongepowered.configurate.serialize.TypeSerializerCollection 29 | import org.spongepowered.configurate.yaml.NodeStyle 30 | import org.spongepowered.configurate.yaml.YamlConfigurationLoader 31 | import java.nio.file.Path 32 | 33 | sealed interface ConfigurateFileType>> { 34 | val name: String 35 | val fileExtension: String 36 | fun createBuilder(serializers: TypeSerializerCollection): B 37 | 38 | data object Hocon : ConfigurateFileType { 39 | override val name: String = "HOCON" 40 | override val fileExtension: String = "conf" 41 | override fun toString(): String = fullName 42 | override fun createBuilder(serializers: TypeSerializerCollection): HoconConfigurationLoader.Builder = 43 | HoconConfigurationLoader.builder().configure(serializers) 44 | } 45 | 46 | data object Yaml : ConfigurateFileType { 47 | override val name: String = "YAML" 48 | override val fileExtension: String = "yaml" 49 | override fun toString(): String = fullName 50 | override fun createBuilder(serializers: TypeSerializerCollection): YamlConfigurationLoader.Builder = 51 | YamlConfigurationLoader.builder().configure(serializers).nodeStyle(NodeStyle.BLOCK) 52 | } 53 | 54 | companion object { 55 | fun fromName(fileEnding: String): ConfigurateFileType<*>? = when (fileEnding) { 56 | Yaml.fileExtension -> Yaml 57 | Hocon.fileExtension -> Hocon 58 | else -> null 59 | } 60 | } 61 | } 62 | 63 | val ConfigurateFileType<*>.fullName: String 64 | get() = "$name ($fileExtension)" 65 | 66 | context(Module) 67 | fun ConfigurateFileType<*>.registerExporter(basePath: Path) { 68 | single { 69 | ConfigurateRegistryExporter( 70 | type = this@registerExporter, 71 | basePath = basePath, 72 | pluginMeta = get(), 73 | keyNamespace = get(), 74 | ) 75 | }.withOptions { named(fileExtension) } 76 | } 77 | 78 | private fun > B.configure(serializers: TypeSerializerCollection): B = 79 | defaultOptions { 80 | it.serializers { builder -> 81 | builder.registerAll(serializers) 82 | builder.registerAnnotatedObjects(objectMapperFactory()) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/ConfigurateRegistry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import org.anvilpowered.anvil.core.config.ConfigurateRegistry.Factory.DiscoveryClosure 22 | import org.apache.logging.log4j.Logger 23 | import org.spongepowered.configurate.ConfigurationNode 24 | import org.spongepowered.configurate.serialize.TypeSerializerCollection 25 | import java.nio.file.Path 26 | import kotlin.io.path.createDirectory 27 | import kotlin.io.path.extension 28 | import kotlin.io.path.listDirectoryEntries 29 | import kotlin.io.path.notExists 30 | 31 | class ConfigurateRegistry( 32 | private val rootNode: ConfigurationNode, 33 | private val delegate: Registry? = null, 34 | ) : Registry { 35 | override fun getDefault(key: Key): T = delegate?.getDefault(key) ?: key.fallback 36 | override fun getDefault(key: ListKey, index: Int): E { 37 | return delegate?.getDefault(key, index) 38 | ?: key.fallback.getOrNull(index) 39 | ?: throw NoSuchElementException("No default value for key ${key.name} at index $index") 40 | } 41 | 42 | override fun getDefault(key: MapKey, mapKey: K): V { 43 | return delegate?.getDefault(key, mapKey) 44 | ?: key.fallback[mapKey] 45 | ?: throw NoSuchElementException("No default value for key ${key.name} at key $mapKey") 46 | } 47 | 48 | override fun getStrict(key: SimpleKey): T? = rootNode.node(key.configNodePath)[key.type] 49 | override fun getStrict(key: ListKey): List? = rootNode.node(key.configNodePath)[key.type] 50 | override fun getStrict(key: ListKey, index: Int): E? = getStrict(key)?.let { return it[index] } 51 | override fun getStrict(key: MapKey): Map? = rootNode.node(key.configNodePath)[key.type] 52 | override fun getStrict(key: MapKey, mapKey: K): V? = getStrict(key)?.let { return it[mapKey] } 53 | 54 | companion object Factory { 55 | 56 | data class DiscoverResult internal constructor( 57 | val registry: Registry, 58 | val path: Path, 59 | val type: ConfigurateFileType<*>, 60 | ) 61 | 62 | fun discover( 63 | basePath: Path, 64 | logger: Logger, 65 | serializers: TypeSerializerCollection = TypeSerializerCollection.defaults(), 66 | delegate: Registry? = null, 67 | ): DiscoverResult? { 68 | if (basePath.notExists()) { 69 | basePath.createDirectory() 70 | } 71 | 72 | val configFiles = basePath.listDirectoryEntries() 73 | .map { it to ConfigurateFileType.fromName(it.extension) } 74 | .mapNotNull { (path, type) -> type?.let { path to it } } 75 | .toList() 76 | 77 | if (configFiles.isEmpty()) { 78 | return null 79 | } else if (configFiles.size >= 2) { 80 | throw IllegalStateException( 81 | "Detected multiple configuration files for plugin ${basePath.fileName}: ${configFiles.map { it.first }}. " + 82 | "Please make sure there is only one configuration file per plugin", 83 | ) 84 | } 85 | 86 | val (path, type) = configFiles.single() 87 | return DiscoverResult(ConfigurateRegistry(type.createBuilder(serializers).path(path).build().load(), delegate), path, type) 88 | } 89 | 90 | fun createDiscoveryClosure( 91 | basePath: Path, 92 | logger: Logger, 93 | serializers: TypeSerializerCollection = TypeSerializerCollection.defaults(), 94 | delegate: Registry? = null, 95 | ) = DiscoveryClosure { discover(basePath, logger, serializers, delegate) } 96 | 97 | fun interface DiscoveryClosure { 98 | fun discover(): DiscoverResult? 99 | } 100 | } 101 | } 102 | 103 | val Key<*>.configNodePath: List 104 | get() = name.split('_').map { it.lowercase() } 105 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/ConfigurateRegistryExporter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import org.anvilpowered.anvil.core.platform.PluginMeta 22 | import org.koin.core.module.Module 23 | import org.spongepowered.configurate.CommentedConfigurationNode 24 | import org.spongepowered.configurate.serialize.TypeSerializerCollection 25 | import java.nio.file.Path 26 | 27 | class ConfigurateRegistryExporter( 28 | val type: ConfigurateFileType<*>, 29 | val basePath: Path, 30 | val pluginMeta: PluginMeta, 31 | val keyNamespace: KeyNamespace, 32 | ) { 33 | 34 | val configPath: Path = basePath.resolve("${pluginMeta.name}.${type.fileExtension}") 35 | 36 | fun export(registry: Registry, serializers: TypeSerializerCollection) { 37 | val loader = type.createBuilder(serializers).path(configPath).build() 38 | val root = loader.createNode() 39 | root.setAllFrom(registry, keyNamespace) 40 | loader.save(root) 41 | } 42 | 43 | companion object { 44 | context(Module) 45 | fun registerAll(basePath: Path) { 46 | ConfigurateFileType.Hocon.registerExporter(basePath) 47 | ConfigurateFileType.Yaml.registerExporter(basePath) 48 | } 49 | } 50 | } 51 | 52 | private fun CommentedConfigurationNode.setAllFrom(registry: Registry, keyNamespace: KeyNamespace) { 53 | for (key in keyNamespace.keys) { 54 | setFrom(key, registry) 55 | } 56 | } 57 | 58 | private fun CommentedConfigurationNode.setFrom(key: Key, registry: Registry) { 59 | node(key.configNodePath).let { node -> 60 | node.set(key.type, registry[key]) 61 | node.comment(key.description) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/DefaultRegistry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | /** 22 | * A [Registry] that always returns the default value for all keys. 23 | */ 24 | object DefaultRegistry : Registry { 25 | override fun getDefault(key: Key): T = key.fallback 26 | override fun getDefault(key: ListKey, index: Int): E = key.fallback.getOrNull(index) 27 | ?: throw NoSuchElementException("No default value for key ${key.name} at index $index") 28 | 29 | override fun getDefault(key: MapKey, mapKey: K): V = key.fallback[mapKey] 30 | ?: throw NoSuchElementException("No default value for key ${key.name} at key $mapKey") 31 | 32 | override fun getStrict(key: SimpleKey): T? = null 33 | override fun getStrict(key: ListKey): List? = null 34 | override fun getStrict(key: ListKey, index: Int): E? = null 35 | 36 | override fun getStrict(key: MapKey): Map? = null 37 | override fun getStrict(key: MapKey, mapKey: K): V? = null 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/EnvironmentRegistry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | /** 22 | * A [Registry] implementation that checks environment variables. 23 | */ 24 | class EnvironmentRegistry(private val prefix: String, private val delegate: Registry? = null) : Registry { 25 | 26 | private val Key<*>.environmentName: String 27 | get() = prefix + "_" + name 28 | 29 | override fun getDefault(key: Key): T { 30 | return delegate?.getDefault(key) ?: key.fallback 31 | } 32 | 33 | override fun getDefault(key: ListKey, index: Int): E { 34 | return delegate?.getDefault(key, index) 35 | ?: key.fallback.getOrNull(index) 36 | ?: throw NoSuchElementException("No default value for key ${key.name} at index $index") 37 | } 38 | 39 | override fun getDefault(key: MapKey, mapKey: K): V { 40 | return delegate?.getDefault(key, mapKey) 41 | ?: key.fallback[mapKey] 42 | ?: throw NoSuchElementException("No default value for key ${key.name} with mapKey $mapKey") 43 | } 44 | 45 | override fun getStrict(key: SimpleKey): T? { 46 | val value = System.getenv(key.environmentName) ?: return delegate?.getStrict(key) 47 | return key.deserialize(value) 48 | } 49 | 50 | override fun getStrict(key: ListKey): List? { 51 | val value = System.getenv(key.environmentName) ?: return delegate?.getStrict(key) 52 | return key.deserialize(value) 53 | } 54 | 55 | override fun getStrict(key: ListKey, index: Int): E? { 56 | val value = System.getenv(key.environmentName) ?: return delegate?.getStrict(key, index) 57 | return key.deserialize(value)[index] 58 | } 59 | 60 | override fun getStrict(key: MapKey): Map? { 61 | val value = System.getenv(key.environmentName) ?: return delegate?.getStrict(key) 62 | return key.deserialize(value) 63 | } 64 | 65 | override fun getStrict(key: MapKey, mapKey: K): V? { 66 | val value = System.getenv(key.environmentName) ?: return delegate?.getStrict(key, mapKey) 67 | return key.deserialize(value)[mapKey] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/Key.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import kotlinx.serialization.json.Json 23 | 24 | interface Key : Comparable> { 25 | 26 | val type: TypeToken 27 | 28 | val name: String 29 | 30 | val fallback: T 31 | 32 | val description: String? 33 | 34 | /** 35 | * Serializes the given value in a simple [String] representation. 36 | */ 37 | fun serialize(value: T, json: Json = Json): String 38 | 39 | /** 40 | * Deserializes the given value from a simple [String] representation. 41 | */ 42 | fun deserialize(value: String, json: Json = Json): T? 43 | 44 | @KeyBuilderDsl 45 | interface BuilderFacet, B : BuilderFacet> { 46 | /** 47 | * Sets the fallback value of the generated [Key]. 48 | * 49 | * This value is used when a [Registry] does not have a value or default value for this key. 50 | * 51 | * @param fallback The fallback value to set 52 | * @return `this` 53 | */ 54 | @KeyBuilderDsl 55 | fun fallback(fallback: T?): B 56 | 57 | /** 58 | * Sets the description of the generated [Key]. 59 | * 60 | * This is used for documentation; for example, in a configuration file. 61 | * 62 | * @param description The description to set or `null` to remove it 63 | * @return `this` 64 | */ 65 | @KeyBuilderDsl 66 | fun description(description: String?): B 67 | } 68 | 69 | @KeyBuilderDsl 70 | interface NamedBuilderFacet, B : BuilderFacet> : BuilderFacet { 71 | /** 72 | * Sets the name of the generated [Key]. 73 | * 74 | * The name is used to identify the key in a [Registry]. 75 | * It is also used as an underscore-separated node path in configuration files. 76 | * 77 | * Example: `JOIN_LISTENER_ENABLED` will become (in HOCON): 78 | * 79 | * ``` 80 | * join { 81 | * listener { 82 | * enabled = ... 83 | * } 84 | * } 85 | * ``` 86 | * 87 | * @param name The name to set 88 | * @return `this` 89 | */ 90 | @KeyBuilderDsl 91 | fun name(name: String): B 92 | } 93 | 94 | interface Builder, B : Builder> : NamedBuilderFacet { 95 | /** 96 | * Generates a [Key] based on this builder. 97 | * 98 | * @return The generated [Key] 99 | */ 100 | context(KeyNamespace) 101 | @KeyBuilderDsl 102 | fun build(): K 103 | } 104 | 105 | @KeyBuilderDsl 106 | interface FacetedBuilder< 107 | T : Any, K : Key, B : FacetedBuilder, 108 | AF : BuilderFacet, NF : NamedBuilderFacet, 109 | > : Builder { 110 | 111 | /** 112 | * @return This builder as an (anonymous) [BuilderFacet] 113 | */ 114 | fun asAnonymousFacet(): AF 115 | 116 | /** 117 | * @return This builder as a [NamedBuilderFacet] 118 | */ 119 | fun asNamedFacet(): NF 120 | } 121 | 122 | companion object { 123 | val comparator: Comparator> = Comparator.comparing, String> { it.name } 124 | .thenComparing(Comparator.comparing { it.type.type.typeName }) 125 | 126 | fun equals(a: Key<*>?, b: Key<*>?): Boolean { 127 | if (a === b) return true 128 | if (a == null || b == null) return false 129 | return a.name == b.name && a.type.type.typeName == b.type.type.typeName 130 | } 131 | 132 | fun hashCode(key: Key<*>): Int { 133 | var result = key.type.hashCode() 134 | result = 31 * result + key.name.hashCode() 135 | return result 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/KeyBuilderDsl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | @DslMarker 22 | annotation class KeyBuilderDsl 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/KeyNamespace.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import org.jetbrains.annotations.ApiStatus 23 | 24 | interface KeyNamespace { 25 | val name: String 26 | 27 | val keys: Set> 28 | 29 | operator fun get(keyName: String, type: TypeToken): Key? 30 | 31 | @ApiStatus.Internal 32 | fun add(key: Key) 33 | 34 | companion object { 35 | fun create(name: String): KeyNamespace { 36 | return KeyNamespaceImpl(name) 37 | } 38 | } 39 | } 40 | 41 | internal class KeyNamespaceImpl(override val name: String) : KeyNamespace { 42 | private val keyMap: MutableMap> = mutableMapOf() 43 | 44 | private val _keys: MutableSet> = mutableSetOf() 45 | override val keys: Set> by ::_keys 46 | 47 | override fun get(keyName: String, type: TypeToken): Key? { 48 | val key = keyMap[keyName] ?: return null 49 | if (key.type != type) { 50 | throw TypeCastException("Key $name has type ${key.type} which does not match provided type $type") 51 | } 52 | @Suppress("UNCHECKED_CAST") 53 | return key as Key 54 | } 55 | 56 | override fun add(key: Key) { 57 | check(keyMap.put(key.name, key) == null) { "Key with name ${key.name} already exists" } 58 | assert(_keys.add(key)) { "Unable to add key" } 59 | } 60 | } 61 | 62 | inline operator fun KeyNamespace.get(keyName: String): Key? = get(keyName, TypeToken.get(T::class.java)) 63 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/ListKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import kotlinx.serialization.KSerializer 23 | import kotlinx.serialization.builtins.ListSerializer 24 | import kotlinx.serialization.json.Json 25 | 26 | context(KeyNamespace) 27 | class ListKey internal constructor( 28 | override val type: TypeToken>, 29 | override val name: String, 30 | override val fallback: List, 31 | override val description: String?, 32 | val elementType: TypeToken, 33 | val elementSerializer: KSerializer, 34 | ) : Key> { 35 | 36 | private val namespace: KeyNamespace = this@KeyNamespace 37 | private val serializer = ListSerializer(elementSerializer) 38 | 39 | init { 40 | namespace.add(this) 41 | } 42 | 43 | fun serializeElement(element: E, json: Json = Json): String = 44 | json.encodeToString(elementSerializer, element) 45 | 46 | fun deserializeElement(element: String, json: Json = Json): E = 47 | json.decodeFromString(elementSerializer, element.prepareForDecode(elementType)) 48 | 49 | override fun serialize(value: List, json: Json): String = Json.encodeToString(serializer, value) 50 | override fun deserialize(value: String, json: Json): List = Json.decodeFromString(serializer, value) 51 | 52 | override fun compareTo(other: Key>): Int = Key.comparator.compare(this, other) 53 | override fun equals(other: Any?): Boolean = (other as Key<*>?)?.let { Key.equals(this, it) } ?: false 54 | override fun hashCode(): Int = Key.hashCode(this) 55 | override fun toString(): String = "ListKey<$elementType>(name='$name')" 56 | 57 | @KeyBuilderDsl 58 | interface BuilderFacet> : Key.BuilderFacet, ListKey, B> { 59 | 60 | /** 61 | * Sets the element serializer of the generated [Key]. 62 | * 63 | * This is entirely optional, as the default serializer will be used if this is not set. 64 | * The default serializer requires the element type to be trivially serializable or annotated with `@Serializable` 65 | * from the kotlinx-serialization framework. 66 | * 67 | * @param serializer The element serializer to set or `null` to use the default 68 | * @return `this` 69 | */ 70 | @KeyBuilderDsl 71 | fun elementSerializer(serializer: KSerializer?): B 72 | } 73 | 74 | @KeyBuilderDsl 75 | interface AnonymousBuilderFacet : 76 | BuilderFacet>, 77 | Key.BuilderFacet, ListKey, AnonymousBuilderFacet> 78 | 79 | @KeyBuilderDsl 80 | interface NamedBuilderFacet : 81 | BuilderFacet>, 82 | Key.NamedBuilderFacet, ListKey, NamedBuilderFacet> 83 | 84 | @KeyBuilderDsl 85 | interface Builder : 86 | BuilderFacet>, 87 | Key.Builder, ListKey, Builder> 88 | 89 | @KeyBuilderDsl 90 | interface FacetedBuilder : 91 | BuilderFacet>, 92 | Key.FacetedBuilder, ListKey, FacetedBuilder, AnonymousBuilderFacet, NamedBuilderFacet> 93 | } 94 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/ListKeyBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeFactory 22 | import io.leangen.geantyref.TypeToken 23 | import kotlinx.serialization.KSerializer 24 | 25 | class ListKeyBuilder( 26 | private val elementType: TypeToken, 27 | ) : AbstractKeyBuilder, ListKey, ListKey.FacetedBuilder, ListKey.AnonymousBuilderFacet, ListKey.NamedBuilderFacet>( 28 | createListTypeToken(elementType), 29 | ), 30 | ListKey.FacetedBuilder { 31 | 32 | private var elementSerializer: KSerializer? = null 33 | 34 | override fun self(): ListKey.FacetedBuilder = this 35 | 36 | override fun elementSerializer(serializer: KSerializer?): ListKey.FacetedBuilder { 37 | this.elementSerializer = serializer 38 | return this 39 | } 40 | 41 | context(KeyNamespace) 42 | @Suppress("UNCHECKED_CAST") 43 | override fun build(): ListKey = ListKey( 44 | type, 45 | requireNotNull(name) { "Name is null" }, 46 | requireNotNull(fallback) { "Fallback is null" }, 47 | description, 48 | elementType, 49 | elementSerializer ?: elementType.getDefaultSerializer(), 50 | ) 51 | 52 | override fun asAnonymousFacet(): ListKey.AnonymousBuilderFacet { 53 | return object : ListKey.AnonymousBuilderFacet { 54 | override fun fallback(fallback: List?): ListKey.AnonymousBuilderFacet { 55 | this@ListKeyBuilder.fallback(fallback) 56 | return this 57 | } 58 | 59 | override fun description(description: String?): ListKey.AnonymousBuilderFacet { 60 | this@ListKeyBuilder.description(description) 61 | return this 62 | } 63 | 64 | override fun elementSerializer(serializer: KSerializer?): ListKey.AnonymousBuilderFacet { 65 | this@ListKeyBuilder.elementSerializer(serializer) 66 | return this 67 | } 68 | } 69 | } 70 | 71 | override fun asNamedFacet(): ListKey.NamedBuilderFacet { 72 | return object : ListKey.NamedBuilderFacet { 73 | override fun fallback(fallback: List?): ListKey.NamedBuilderFacet { 74 | this@ListKeyBuilder.fallback(fallback) 75 | return this 76 | } 77 | 78 | override fun description(description: String?): ListKey.NamedBuilderFacet { 79 | this@ListKeyBuilder.description(description) 80 | return this 81 | } 82 | 83 | override fun name(name: String): ListKey.NamedBuilderFacet { 84 | this@ListKeyBuilder.name(name) 85 | return this 86 | } 87 | 88 | override fun elementSerializer(serializer: KSerializer?): ListKey.NamedBuilderFacet { 89 | this@ListKeyBuilder.elementSerializer(serializer) 90 | return this 91 | } 92 | } 93 | } 94 | } 95 | 96 | @Suppress("UNCHECKED_CAST") 97 | private fun createListTypeToken(elementType: TypeToken): TypeToken> = 98 | TypeToken.get(TypeFactory.parameterizedClass(List::class.java, elementType.type)) as TypeToken> 99 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/MapKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import kotlinx.serialization.KSerializer 23 | import kotlinx.serialization.builtins.MapSerializer 24 | import kotlinx.serialization.json.Json 25 | 26 | context(KeyNamespace) 27 | class MapKey internal constructor( 28 | override val type: TypeToken>, 29 | override val name: String, 30 | override val fallback: Map, 31 | override val description: String?, 32 | val keyType: TypeToken, 33 | val keySerializer: KSerializer, 34 | val valueType: TypeToken, 35 | val valueSerializer: KSerializer, 36 | ) : Key> { 37 | 38 | private val namespace: KeyNamespace = this@KeyNamespace 39 | private val serializer = MapSerializer(keySerializer, valueSerializer) 40 | 41 | init { 42 | namespace.add(this) 43 | } 44 | 45 | fun serializeKey(key: K, json: Json = Json): String = json.encodeToString(keySerializer, key) 46 | fun deserializeKey(key: String, json: Json = Json): K = json.decodeFromString(keySerializer, key.prepareForDecode(keyType)) 47 | fun serializeValue(value: V, json: Json = Json): String = json.encodeToString(valueSerializer, value) 48 | fun deserializeValue(value: String, json: Json = Json): V = json.decodeFromString(valueSerializer, value.prepareForDecode(valueType)) 49 | 50 | override fun serialize(value: Map, json: Json): String = json.encodeToString(serializer, value) 51 | override fun deserialize(value: String, json: Json): Map = json.decodeFromString(serializer, value) 52 | 53 | override fun compareTo(other: Key>): Int = Key.comparator.compare(this, other) 54 | override fun equals(other: Any?): Boolean = (other as Key<*>?)?.let { Key.equals(this, it) } ?: false 55 | override fun hashCode(): Int = Key.hashCode(this) 56 | override fun toString(): String = "MapKey<$keyType, $valueType>(name='$name')" 57 | 58 | @KeyBuilderDsl 59 | interface BuilderFacet> : Key.BuilderFacet, MapKey, B> { 60 | 61 | /** 62 | * Sets the key serializer of the generated [Key]. 63 | * 64 | * This is entirely optional, as the default serializer will be used if this is not set. 65 | * The default serializer requires the element type to be trivially serializable or annotated with `@Serializable` 66 | * from the kotlinx-serialization framework. 67 | * 68 | * @param serializer The key serializer to set or `null` to use the default 69 | * @return `this` 70 | */ 71 | @KeyBuilderDsl 72 | fun keySerializer(serializer: KSerializer?): B 73 | 74 | /** 75 | * Sets the value serializer of the generated [Key]. 76 | * 77 | * This is entirely optional, as the default serializer will be used if this is not set. 78 | * The default serializer requires the element type to be trivially serializable or annotated with `@Serializable` 79 | * from the kotlinx-serialization framework. 80 | * 81 | * @param serializer The value serializer to set or `null` to use the default 82 | * @return `this` 83 | */ 84 | @KeyBuilderDsl 85 | fun valueSerializer(serializer: KSerializer?): B 86 | } 87 | 88 | @KeyBuilderDsl 89 | interface AnonymousBuilderFacet : 90 | BuilderFacet>, 91 | Key.BuilderFacet, MapKey, AnonymousBuilderFacet> 92 | 93 | @KeyBuilderDsl 94 | interface NamedBuilderFacet : 95 | BuilderFacet>, 96 | Key.NamedBuilderFacet, MapKey, NamedBuilderFacet> 97 | 98 | @KeyBuilderDsl 99 | interface Builder : 100 | BuilderFacet>, 101 | Key.Builder, MapKey, Builder> 102 | 103 | @KeyBuilderDsl 104 | interface FacetedBuilder : 105 | BuilderFacet>, 106 | Key.FacetedBuilder, MapKey, FacetedBuilder, AnonymousBuilderFacet, NamedBuilderFacet> 107 | } 108 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/MapKeyBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeFactory 22 | import io.leangen.geantyref.TypeToken 23 | import kotlinx.serialization.KSerializer 24 | 25 | class MapKeyBuilder( 26 | private val mapKeyType: TypeToken, 27 | private val mapValueType: TypeToken, 28 | ) : AbstractKeyBuilder< 29 | Map, MapKey, MapKey.FacetedBuilder, MapKey.AnonymousBuilderFacet, 30 | MapKey.NamedBuilderFacet, 31 | >(createMapTypeToken(mapKeyType, mapValueType)), 32 | MapKey.FacetedBuilder { 33 | 34 | private var keySerializer: KSerializer? = null 35 | private var valueSerializer: KSerializer? = null 36 | 37 | override fun self(): MapKey.FacetedBuilder = this 38 | 39 | override fun keySerializer(serializer: KSerializer?): MapKey.FacetedBuilder { 40 | this.keySerializer = serializer 41 | return this 42 | } 43 | 44 | override fun valueSerializer(serializer: KSerializer?): MapKey.FacetedBuilder { 45 | this.valueSerializer = serializer 46 | return this 47 | } 48 | 49 | context(KeyNamespace) 50 | @Suppress("UNCHECKED_CAST") 51 | override fun build(): MapKey = MapKey( 52 | type, 53 | requireNotNull(name) { "Name is null" }, 54 | requireNotNull(fallback) { "Fallback is null" }, 55 | description, 56 | mapKeyType, 57 | keySerializer ?: mapKeyType.getDefaultSerializer(), 58 | mapValueType, 59 | valueSerializer ?: mapValueType.getDefaultSerializer(), 60 | ) 61 | 62 | override fun asAnonymousFacet(): MapKey.AnonymousBuilderFacet { 63 | return object : MapKey.AnonymousBuilderFacet { 64 | override fun fallback(fallback: Map?): MapKey.AnonymousBuilderFacet { 65 | this@MapKeyBuilder.fallback(fallback) 66 | return this 67 | } 68 | 69 | override fun description(description: String?): MapKey.AnonymousBuilderFacet { 70 | this@MapKeyBuilder.description(description) 71 | return this 72 | } 73 | 74 | override fun keySerializer(serializer: KSerializer?): MapKey.AnonymousBuilderFacet { 75 | this@MapKeyBuilder.keySerializer(serializer) 76 | return this 77 | } 78 | 79 | override fun valueSerializer(serializer: KSerializer?): MapKey.AnonymousBuilderFacet { 80 | this@MapKeyBuilder.valueSerializer(serializer) 81 | return this 82 | } 83 | } 84 | } 85 | 86 | override fun asNamedFacet(): MapKey.NamedBuilderFacet { 87 | return object : MapKey.NamedBuilderFacet { 88 | override fun name(name: String): MapKey.NamedBuilderFacet { 89 | this@MapKeyBuilder.name(name) 90 | return this 91 | } 92 | 93 | override fun fallback(fallback: Map?): MapKey.NamedBuilderFacet { 94 | this@MapKeyBuilder.fallback(fallback) 95 | return this 96 | } 97 | 98 | override fun description(description: String?): MapKey.NamedBuilderFacet { 99 | this@MapKeyBuilder.description(description) 100 | return this 101 | } 102 | 103 | override fun keySerializer(serializer: KSerializer?): MapKey.NamedBuilderFacet { 104 | this@MapKeyBuilder.keySerializer(serializer) 105 | return this 106 | } 107 | 108 | override fun valueSerializer(serializer: KSerializer?): MapKey.NamedBuilderFacet { 109 | this@MapKeyBuilder.valueSerializer(serializer) 110 | return this 111 | } 112 | } 113 | } 114 | } 115 | 116 | @Suppress("UNCHECKED_CAST") 117 | private fun createMapTypeToken(mapKeyType: TypeToken, mapValueType: TypeToken): TypeToken> = 118 | TypeToken.get(TypeFactory.parameterizedClass(Map::class.java, mapKeyType.type, mapValueType.type)) as TypeToken> 119 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/Registration.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import org.anvilpowered.anvil.core.AnvilApi 22 | import org.anvilpowered.anvil.core.command.config.ConfigCommandFactory 23 | import org.anvilpowered.anvil.core.platform.PluginMeta 24 | import org.koin.core.module.Module 25 | import org.spongepowered.configurate.serialize.TypeSerializerCollection 26 | 27 | context(Module) 28 | fun Registry.Companion.configureDefaults( 29 | anvil: AnvilApi, 30 | serializers: TypeSerializerCollection = TypeSerializerCollection.defaults(), 31 | ) { 32 | ConfigurateRegistryExporter.registerAll(anvil.configDir) 33 | val configurateRegistryClosure = ConfigurateRegistry.createDiscoveryClosure(anvil.configDir, anvil.logger, serializers) 34 | val configurateRegistry = configurateRegistryClosure.discover() 35 | if (configurateRegistry == null) { 36 | anvil.logger.warn("No configuration file found, using environment variables only.") 37 | } else { 38 | anvil.logger.info("Using configuration file: ${configurateRegistry.path}") 39 | } 40 | single { configurateRegistryClosure } 41 | single { EnvironmentRegistry(get().name.uppercase(), configurateRegistry?.registry) } 42 | single { ConfigCommandFactory(get(), get(), get(), getAll(), serializers) } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/Registry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | interface Registry { 22 | fun getDefault(key: Key): T 23 | fun getDefault(key: ListKey, index: Int): E 24 | fun getDefault(key: MapKey, mapKey: K): V 25 | 26 | fun getStrict(key: SimpleKey): T? 27 | fun getStrict(key: ListKey): List? 28 | fun getStrict(key: ListKey, index: Int): E? 29 | fun getStrict(key: MapKey): Map? 30 | fun getStrict(key: MapKey, mapKey: K): V? 31 | 32 | operator fun get(key: SimpleKey): T = getStrict(key) ?: getDefault(key) 33 | operator fun get(key: ListKey): List = getStrict(key) ?: getDefault(key) 34 | operator fun get(key: ListKey, index: Int): E = getStrict(key, index) ?: getDefault(key, index) 35 | operator fun get(key: MapKey): Map = getStrict(key) ?: getDefault(key) 36 | operator fun get(key: MapKey, mapKey: K): V = getStrict(key, mapKey) ?: getDefault(key, mapKey) 37 | 38 | @Suppress("UNCHECKED_CAST") 39 | operator fun get(key: Key): T = when (key) { 40 | is SimpleKey -> get(key) 41 | is ListKey<*> -> get(key) as T 42 | is MapKey<*, *> -> get(key) as T 43 | else -> throw IllegalArgumentException("Unknown key type: ${key::class.simpleName}") 44 | } 45 | 46 | companion object 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/Serialization.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import kotlinx.serialization.KSerializer 23 | import kotlinx.serialization.json.Json 24 | import kotlinx.serialization.serializer 25 | 26 | fun Registry.serializeDefault(key: Key, json: Json = Json): String = key.serialize(getDefault(key), json) 27 | 28 | fun Registry.serializeStrict(key: SimpleKey, json: Json = Json): String? = 29 | getStrict(key)?.let { key.serialize(it, json) } 30 | 31 | fun Registry.serialize(key: SimpleKey, json: Json = Json): String = key.serialize(get(key), json) 32 | 33 | fun Registry.serializeStrict(key: ListKey, json: Json = Json): String? = 34 | getStrict(key)?.let { key.serialize(it, json) } 35 | 36 | fun Registry.serialize(key: ListKey, json: Json = Json): String = key.serialize(get(key), json) 37 | 38 | fun Registry.serializeStrict(key: MapKey, json: Json = Json): String? = 39 | getStrict(key)?.let { key.serialize(it, json) } 40 | 41 | fun Registry.serialize(key: MapKey, json: Json = Json): String = key.serialize(get(key), json) 42 | 43 | fun Registry.serialize(key: Key<*>, json: Json = Json): String = when (key) { 44 | is SimpleKey<*> -> serialize(key, json) 45 | is ListKey<*> -> serialize(key, json) 46 | is MapKey<*, *> -> serialize(key, json) 47 | else -> throw IllegalArgumentException("Unknown key type: ${key::class.simpleName}") 48 | } 49 | 50 | fun TypeToken.getDefaultSerializer(): KSerializer { 51 | @Suppress("UNCHECKED_CAST") 52 | return serializer(type) as KSerializer 53 | } 54 | 55 | internal fun String.prepareForDecode(targetType: TypeToken): String { 56 | // We use the JSON deserializer for all values 57 | // It expects input String to be quoted when the target type is a String 58 | return when (targetType.type) { 59 | String::class.java -> "\"$this\"" 60 | else -> this 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/SimpleKey.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import kotlinx.serialization.KSerializer 23 | import kotlinx.serialization.json.Json 24 | 25 | context(KeyNamespace) 26 | class SimpleKey internal constructor( 27 | override val type: TypeToken, 28 | override val name: String, 29 | override val fallback: T, 30 | override val description: String?, 31 | val serializer: KSerializer, 32 | ) : Key { 33 | private val namespace: KeyNamespace = this@KeyNamespace 34 | 35 | init { 36 | namespace.add(this) 37 | } 38 | 39 | override fun serialize(value: T, json: Json): String = json.encodeToString(serializer, value) 40 | override fun deserialize(value: String, json: Json): T = json.decodeFromString(serializer, value.prepareForDecode(type)) 41 | 42 | override fun compareTo(other: Key): Int = Key.comparator.compare(this, other) 43 | override fun equals(other: Any?): Boolean = (other as Key<*>?)?.let { Key.equals(this, it) } ?: false 44 | override fun hashCode(): Int = Key.hashCode(this) 45 | override fun toString(): String = "SimpleKey(type=$type, name='$name')" 46 | 47 | @KeyBuilderDsl 48 | interface BuilderFacet> : Key.BuilderFacet, B> { 49 | 50 | /** 51 | * Sets the serializer of the generated [Key]. 52 | * 53 | * This is entirely optional, as the default serializer will be used if this is not set. 54 | * The default serializer requires the element type to be trivially serializable or annotated with `@Serializable` 55 | * from the kotlinx-serialization framework. 56 | * 57 | * @param serializer The serializer to set or `null` to use the default 58 | * @return `this` 59 | */ 60 | @KeyBuilderDsl 61 | fun serializer(serializer: KSerializer?): B 62 | } 63 | 64 | @KeyBuilderDsl 65 | interface AnonymousBuilderFacet : 66 | BuilderFacet>, 67 | Key.BuilderFacet, AnonymousBuilderFacet> 68 | 69 | @KeyBuilderDsl 70 | interface NamedBuilderFacet : 71 | BuilderFacet>, 72 | Key.NamedBuilderFacet, NamedBuilderFacet> 73 | 74 | @KeyBuilderDsl 75 | interface Builder : 76 | BuilderFacet>, 77 | Key.Builder, Builder> 78 | 79 | @KeyBuilderDsl 80 | interface FacetedBuilder : 81 | BuilderFacet>, 82 | Key.FacetedBuilder, FacetedBuilder, AnonymousBuilderFacet, NamedBuilderFacet> 83 | } 84 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/SimpleKeyBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import kotlinx.serialization.KSerializer 23 | 24 | class SimpleKeyBuilder( 25 | type: TypeToken, 26 | ) : AbstractKeyBuilder, SimpleKey.FacetedBuilder, SimpleKey.AnonymousBuilderFacet, SimpleKey.NamedBuilderFacet>( 27 | type, 28 | ), 29 | SimpleKey.FacetedBuilder { 30 | 31 | private var serializer: KSerializer? = null 32 | 33 | override fun self(): SimpleKey.FacetedBuilder = this 34 | 35 | override fun serializer(serializer: KSerializer?): SimpleKey.FacetedBuilder { 36 | this.serializer = serializer 37 | return self() 38 | } 39 | 40 | context(KeyNamespace) 41 | override fun build(): SimpleKey = SimpleKey( 42 | type, 43 | requireNotNull(name) { "Name is null" }, 44 | requireNotNull(fallback) { "Fallback is null" }, 45 | description, 46 | serializer ?: type.getDefaultSerializer(), 47 | ) 48 | 49 | override fun asAnonymousFacet(): SimpleKey.AnonymousBuilderFacet { 50 | return object : SimpleKey.AnonymousBuilderFacet { 51 | override fun fallback(fallback: T?): SimpleKey.AnonymousBuilderFacet { 52 | this@SimpleKeyBuilder.fallback(fallback).let { this } 53 | return this 54 | } 55 | 56 | override fun description(description: String?): SimpleKey.AnonymousBuilderFacet { 57 | this@SimpleKeyBuilder.description(description) 58 | return this 59 | } 60 | 61 | override fun serializer(serializer: KSerializer?): SimpleKey.AnonymousBuilderFacet { 62 | this@SimpleKeyBuilder.serializer(serializer) 63 | return this 64 | } 65 | } 66 | } 67 | 68 | override fun asNamedFacet(): SimpleKey.NamedBuilderFacet { 69 | return object : SimpleKey.NamedBuilderFacet { 70 | override fun name(name: String): SimpleKey.NamedBuilderFacet { 71 | this@SimpleKeyBuilder.name(name) 72 | return this 73 | } 74 | 75 | override fun fallback(fallback: T?): SimpleKey.NamedBuilderFacet { 76 | this@SimpleKeyBuilder.fallback(fallback) 77 | return this 78 | } 79 | 80 | override fun description(description: String?): SimpleKey.NamedBuilderFacet { 81 | this@SimpleKeyBuilder.description(description) 82 | return this 83 | } 84 | 85 | override fun serializer(serializer: KSerializer?): SimpleKey.NamedBuilderFacet { 86 | this@SimpleKeyBuilder.serializer(serializer) 87 | return this 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/config/TypeTokens.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.config 20 | 21 | import io.leangen.geantyref.TypeToken 22 | import net.kyori.adventure.text.Component 23 | import java.time.ZoneId 24 | 25 | @Suppress("PropertyName") 26 | open class TypeTokens { 27 | val BOOLEAN: TypeToken = TypeToken.get(Boolean::class.javaObjectType) 28 | val INTEGER: TypeToken = TypeToken.get(Int::class.javaObjectType) 29 | val STRING: TypeToken = TypeToken.get(String::class.java) 30 | val COMPONENT: TypeToken = TypeToken.get(Component::class.java) 31 | val ZONE_ID: TypeToken = TypeToken.get(ZoneId::class.java) 32 | 33 | companion object : TypeTokens() 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/db/DomainEntity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.db 20 | 21 | import java.util.UUID 22 | 23 | interface DomainEntity { 24 | val uuid: UUID 25 | // TODO: createdUtc, updatedUtc 26 | } 27 | 28 | interface DomainFacet { 29 | suspend fun getOriginal(): E 30 | } 31 | 32 | interface Creates 33 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/db/MutableRepository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.db 20 | 21 | interface MutableRepository> : Repository { 22 | suspend fun create(item: C): E 23 | suspend fun put(item: C): PutResult 24 | 25 | data class PutResult( 26 | val entity: E, 27 | val created: Boolean, 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/db/Pagination.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.db 20 | 21 | import kotlin.reflect.KProperty1 22 | 23 | interface Pagination> { 24 | fun limit(n: Int, offset: Long = 0): Pagination 25 | fun sortBy(field: KProperty1>, direction: SortDirection = SortDirection.ASCENDING): Pagination 26 | fun build(): List 27 | } 28 | 29 | enum class SortDirection { 30 | ASCENDING, 31 | DESCENDING, 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/db/Repository.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.db 20 | 21 | import java.util.UUID 22 | 23 | interface Repository { 24 | suspend fun findById(id: UUID): E? 25 | suspend fun exists(id: UUID): Boolean 26 | suspend fun countAll(): Long 27 | suspend fun deleteById(id: UUID): Boolean 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/db/SizedIterable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.db 20 | 21 | interface SizedIterable : Iterable { 22 | fun limit(n: Int, offset: Long = 0): SizedIterable 23 | 24 | fun count(): Long 25 | 26 | fun empty(): Boolean 27 | 28 | fun copy(): SizedIterable 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/platform/Platform.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.platform 20 | 21 | interface Platform { 22 | val name: String 23 | val version: String 24 | 25 | val isProxy: Boolean 26 | val plugins: List 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/platform/PluginManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.platform 20 | 21 | interface PluginManager { 22 | val plugins: List 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/platform/PluginMeta.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.platform 20 | 21 | interface PluginMeta { 22 | val name: String 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/platform/Server.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.platform 20 | 21 | import net.kyori.adventure.audience.Audience 22 | 23 | interface Server { 24 | 25 | val platform: Platform 26 | 27 | val broadcastAudience: Audience 28 | 29 | val systemSubject: Audience 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/user/ArgumentExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.user 20 | 21 | import org.anvilpowered.anvil.core.command.CommandSource 22 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 23 | 24 | fun > B.requiresPermission(permission: String): B = 25 | requires { it.hasPermissionSet(permission) } 26 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/user/Player.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.user 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import net.kyori.adventure.text.Component 23 | import java.util.UUID 24 | 25 | /** 26 | * An online player. 27 | */ 28 | interface Player : Subject, Audience { 29 | 30 | val id: UUID 31 | 32 | val username: String 33 | 34 | val displayname: Component 35 | 36 | val latencyMs: Int 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/user/PlayerService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.user 20 | 21 | import java.util.UUID 22 | 23 | interface PlayerService { 24 | 25 | operator fun get(username: String): Player? 26 | 27 | operator fun get(id: UUID): Player? 28 | 29 | fun getAll(startsWith: String = ""): Sequence 30 | 31 | fun count(): Int 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/kotlin/org/anvilpowered/anvil/core/user/Subject.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.core.user 20 | 21 | import org.anvilpowered.anvil.core.PlatformType 22 | 23 | interface Subject : PlatformType { 24 | 25 | /** 26 | * Checks if the subject has the specified permission. 27 | * 28 | * - A value of `true` indicates that the subject has the permission explicitly set. 29 | * - A value of `false` indicates that the subject has the permission explicitly set to false. 30 | * - A value of `null` indicates that the subject does not have the permission explicitly set. 31 | */ 32 | fun hasPermission(permission: String): Boolean? 33 | } 34 | 35 | fun Subject.hasPermissionSet(permission: String): Boolean = hasPermission(permission) == true 36 | fun Subject.hasPermissionUnset(permission: String): Boolean = hasPermission(permission) == null 37 | fun Subject.hasPermissionNotSet(permission: String): Boolean = !hasPermissionSet(permission) 38 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | systemProp.org.gradle.unsafe.kotlin.assignment=true 2 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | configurate = "4.2.0-SNAPSHOT" 3 | kotlin = "2.0.0" 4 | log4j = "2.23.0" 5 | 6 | [libraries] 7 | adventure-bom = "net.kyori:adventure-bom:4.17.0" 8 | annotations = "org.jetbrains:annotations:24.1.0" 9 | brigadier = "com.mojang:brigadier:1.0.18" 10 | configurate-core = { module = "org.spongepowered:configurate-core", version.ref = "configurate" } 11 | configurate-hocon = { module = "org.spongepowered:configurate-hocon", version.ref = "configurate" } 12 | configurate-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate" } 13 | configurate-extra-kotlin = { module = "org.spongepowered:configurate-extra-kotlin", version.ref = "configurate" } 14 | kbrig-brigadier = "org.anvilpowered:kbrig-brigadier:0.2.0-SNAPSHOT" 15 | koin = "io.insert-koin:koin-core:3.5.6" 16 | kotest = "io.kotest:kotest-runner-junit5-jvm:5.8.0" 17 | kotlinx-coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1" 18 | kotlinx-serialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2" 19 | logging-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } 20 | logging-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } 21 | paper = "io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT" 22 | sponge = "org.spongepowered:spongeapi:8.2.0" 23 | velocity = "com.velocitypowered:velocity-api:3.2.0-SNAPSHOT" 24 | 25 | [plugins] 26 | kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } 27 | kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 28 | kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } 29 | ktlint = "org.jlleitschuh.gradle.ktlint:11.6.1" 30 | pluginyml = "net.minecrell.plugin-yml.paper:0.6.0" 31 | shadow = "io.github.goooler.shadow:8.1.7" 32 | sponge = "org.spongepowered.gradle.plugin:2.2.0" 33 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anvilpowered/anvil/b2e5cbbaa4915535e5ab61bda2b93c689d7826b0/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /paper/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("anvil-publish") 3 | id("anvil-sign") 4 | } 5 | 6 | dependencies { 7 | api(project(":anvil-core")) 8 | compileOnlyApi(libs.paper) 9 | } 10 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/AnvilPaperApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:Suppress("UnstableApiUsage") 20 | 21 | package org.anvilpowered.anvil.paper 22 | 23 | import org.anvilpowered.anvil.core.AnvilApi 24 | import org.anvilpowered.anvil.core.command.CommandExecutor 25 | import org.anvilpowered.anvil.core.platform.PluginManager 26 | import org.anvilpowered.anvil.core.platform.PluginMeta 27 | import org.anvilpowered.anvil.core.platform.Server 28 | import org.anvilpowered.anvil.core.user.PlayerService 29 | import org.anvilpowered.anvil.paper.command.PaperCommandExecutor 30 | import org.anvilpowered.anvil.paper.platform.PaperPluginManager 31 | import org.anvilpowered.anvil.paper.platform.PaperPluginMeta 32 | import org.anvilpowered.anvil.paper.platform.PaperServer 33 | import org.anvilpowered.anvil.paper.user.PaperPlayerService 34 | import org.apache.logging.log4j.LogManager 35 | import org.apache.logging.log4j.Logger 36 | import org.bukkit.plugin.java.JavaPlugin 37 | import org.koin.core.module.Module 38 | import org.koin.core.module.dsl.singleOf 39 | import org.koin.dsl.bind 40 | import org.koin.dsl.module 41 | import java.nio.file.Path 42 | 43 | interface AnvilPaperApi : AnvilApi { 44 | val plugin: JavaPlugin 45 | } 46 | 47 | fun AnvilApi.Companion.createPaper(plugin: JavaPlugin): AnvilPaperApi { 48 | val logger = LogManager.getLogger(plugin.pluginMeta.name) 49 | val paperModule = module { 50 | single { plugin } 51 | single { logger } 52 | single { PaperServer } 53 | single { PaperPluginManager } 54 | single { PaperPlayerService } 55 | single { PaperPluginMeta(plugin.pluginMeta) } 56 | single { PaperPlayerService }.bind() 57 | singleOf(::PaperCommandExecutor).bind() 58 | } 59 | 60 | return object : AnvilPaperApi { 61 | override val plugin: JavaPlugin = plugin 62 | override val logger: Logger = logger 63 | override val configDir: Path = plugin.dataFolder.toPath() 64 | override val module: Module = paperModule 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/command/AnvilPaperCommandSource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.paper.command 20 | 21 | import io.papermc.paper.command.brigadier.CommandSourceStack 22 | import net.kyori.adventure.audience.Audience 23 | import net.kyori.adventure.audience.ForwardingAudience 24 | import org.anvilpowered.anvil.core.command.CommandSource 25 | import org.anvilpowered.anvil.core.user.Player 26 | import org.anvilpowered.anvil.core.user.Subject 27 | import org.anvilpowered.anvil.paper.user.toAnvilPlayer 28 | import org.anvilpowered.anvil.paper.user.toAnvilSubject 29 | import org.bukkit.command.CommandSender 30 | import org.bukkit.entity.Player as PaperPlayer 31 | 32 | fun CommandSender.toAnvilCommandSource(): CommandSource = AnvilPaperCommandSource(this) 33 | 34 | @Suppress("UnstableApiUsage") 35 | fun CommandSourceStack.toAnvilCommandSource(): CommandSource = AnvilPaperCommandSource(sender) 36 | 37 | private class AnvilPaperCommandSource( 38 | override val platformDelegate: CommandSender, 39 | ) : CommandSource, 40 | ForwardingAudience, 41 | Subject by platformDelegate.toAnvilSubject() { 42 | 43 | val delegateAudiences = listOf(platformDelegate) 44 | override fun audiences(): Iterable = delegateAudiences 45 | 46 | override val player: Player? = (platformDelegate as? PaperPlayer)?.toAnvilPlayer() 47 | } 48 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/command/PaperCommandExecutor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.paper.command 20 | 21 | import kotlinx.coroutines.asCoroutineDispatcher 22 | import kotlinx.coroutines.withContext 23 | import org.anvilpowered.anvil.core.command.CommandExecutor 24 | import org.anvilpowered.anvil.core.command.CommandSource 25 | import org.bukkit.Bukkit 26 | import org.bukkit.command.CommandSender 27 | import org.bukkit.plugin.java.JavaPlugin 28 | import java.util.concurrent.Executor 29 | 30 | class PaperCommandExecutor(private val plugin: JavaPlugin) : CommandExecutor { 31 | 32 | private val executor = Executor { runnable -> plugin.server.scheduler.runTask(plugin, runnable) } 33 | .asCoroutineDispatcher() 34 | 35 | override suspend fun execute(source: CommandSource, command: String): Boolean = 36 | withContext(executor) { Bukkit.dispatchCommand(source.platformDelegate as CommandSender, command) } 37 | 38 | override suspend fun executeAsConsole(command: String): Boolean = 39 | withContext(executor) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command) } 40 | } 41 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/command/PaperSourceConverter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:JvmName("PaperSourceConverter") 20 | @file:Suppress("UnstableApiUsage") 21 | 22 | package org.anvilpowered.anvil.paper.command 23 | 24 | import io.papermc.paper.command.brigadier.CommandSourceStack 25 | import org.anvilpowered.anvil.core.command.CommandSource 26 | import org.anvilpowered.kbrig.brigadier.toBrigadier 27 | import org.anvilpowered.kbrig.tree.ArgumentCommandNode 28 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 29 | import org.anvilpowered.kbrig.tree.mapSource 30 | import com.mojang.brigadier.tree.ArgumentCommandNode as BrigadierArgumentCommandNode 31 | import com.mojang.brigadier.tree.LiteralCommandNode as BrigadierLiteralCommandNode1 32 | 33 | /** 34 | * Converts a kbrig argument command node to a paper brigadier argument command node. 35 | */ 36 | fun ArgumentCommandNode.toPaper(): BrigadierArgumentCommandNode = 37 | mapSource { it.toAnvilCommandSource() }.toBrigadier() 38 | 39 | /** 40 | * Converts a kbrig literal command node to a paper brigadier literal command node. 41 | */ 42 | fun LiteralCommandNode.toPaper(): BrigadierLiteralCommandNode1 = 43 | mapSource { it.toAnvilCommandSource() }.toBrigadier() 44 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/platform/PaperPlatform.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:Suppress("UnstableApiUsage") 20 | 21 | package org.anvilpowered.anvil.paper.platform 22 | 23 | import org.anvilpowered.anvil.core.platform.Platform 24 | import org.anvilpowered.anvil.core.platform.PluginMeta 25 | import org.bukkit.Bukkit 26 | 27 | internal object PaperPlatform : Platform { 28 | override val isProxy: Boolean = false 29 | override val plugins: List 30 | get() = Bukkit.getPluginManager().plugins.map { it.pluginMeta.toAnvilPluginMeta() } 31 | override val name: String 32 | get() = "paper" 33 | override val version: String 34 | get() = Bukkit.getBukkitVersion() 35 | } 36 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/platform/PaperPluginManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:Suppress("UnstableApiUsage") 20 | 21 | package org.anvilpowered.anvil.paper.platform 22 | 23 | import org.anvilpowered.anvil.core.platform.PluginManager 24 | import org.anvilpowered.anvil.core.platform.PluginMeta 25 | import org.bukkit.Bukkit 26 | 27 | internal object PaperPluginManager : PluginManager { 28 | override val plugins: List 29 | get() = Bukkit.getPluginManager().plugins.map { it.pluginMeta.toAnvilPluginMeta() } 30 | } 31 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/platform/PaperPluginMeta.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:Suppress("UnstableApiUsage") 20 | 21 | package org.anvilpowered.anvil.paper.platform 22 | 23 | import org.anvilpowered.anvil.core.platform.PluginMeta 24 | import io.papermc.paper.plugin.configuration.PluginMeta as PaperPluginMeta 25 | 26 | internal fun PaperPluginMeta.toAnvilPluginMeta() = PaperPluginMeta(this) 27 | 28 | class PaperPluginMeta(private val delegate: PaperPluginMeta) : PluginMeta { 29 | override val name: String 30 | get() = delegate.name 31 | } 32 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/platform/PaperServer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.paper.platform 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import org.anvilpowered.anvil.core.platform.Platform 23 | import org.anvilpowered.anvil.core.platform.Server 24 | import org.bukkit.Bukkit 25 | 26 | object PaperServer : Server { 27 | override val platform: Platform 28 | get() = PaperPlatform 29 | override val broadcastAudience: Audience 30 | get() = Bukkit.getServer() 31 | override val systemSubject: Audience 32 | get() = Bukkit.getConsoleSender() 33 | } 34 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/user/AnvilPaperPlayer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.paper.user 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import net.kyori.adventure.audience.ForwardingAudience 23 | import net.kyori.adventure.text.Component 24 | import org.anvilpowered.anvil.core.user.Player 25 | import org.anvilpowered.anvil.core.user.Subject 26 | import java.util.UUID 27 | import org.bukkit.entity.Player as PaperPlayer 28 | 29 | fun PaperPlayer.toAnvilPlayer(): Player = AnvilPaperPlayer(this) 30 | 31 | private class AnvilPaperPlayer( 32 | override val platformDelegate: PaperPlayer, 33 | ) : Player, 34 | ForwardingAudience, 35 | Subject by platformDelegate.toAnvilSubject() { 36 | 37 | val delegateAudiences = listOf(platformDelegate) 38 | override fun audiences(): Iterable = delegateAudiences 39 | 40 | override val id: UUID = platformDelegate.uniqueId 41 | override val username: String = platformDelegate.name 42 | override val displayname: Component = platformDelegate.displayName() 43 | override val latencyMs: Int 44 | get() = platformDelegate.ping 45 | } 46 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/user/AnvilPaperSubject.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.paper.user 20 | 21 | import org.anvilpowered.anvil.core.user.Subject 22 | import org.bukkit.permissions.Permissible 23 | 24 | fun Permissible.toAnvilSubject(): Subject = AnvilPaperSubject(this) 25 | 26 | private class AnvilPaperSubject( 27 | override val platformDelegate: Permissible, 28 | ) : Subject { 29 | override fun hasPermission(permission: String): Boolean? { 30 | return if (platformDelegate.hasPermission(permission)) { 31 | true 32 | } else if (platformDelegate.isPermissionSet(permission)) { 33 | false 34 | } else { 35 | null 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /paper/src/main/kotlin/org/anvilpowered/anvil/paper/user/PaperPlayerService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.paper.user 20 | 21 | import org.anvilpowered.anvil.core.user.Player 22 | import org.anvilpowered.anvil.core.user.PlayerService 23 | import org.bukkit.Bukkit 24 | import java.util.UUID 25 | 26 | object PaperPlayerService : PlayerService { 27 | override fun get(username: String): Player? = 28 | Bukkit.getPlayerExact(username)?.toAnvilPlayer() 29 | 30 | override fun get(id: UUID): Player? = 31 | Bukkit.getPlayer(id)?.toAnvilPlayer() 32 | 33 | override fun getAll(startsWith: String): Sequence = when (startsWith) { 34 | "" -> Bukkit.getOnlinePlayers().asSequence().map { it.toAnvilPlayer() } 35 | else -> Bukkit.matchPlayer(startsWith).asSequence().map { it.toAnvilPlayer() } 36 | } 37 | 38 | override fun count(): Int = Bukkit.getOnlinePlayers().size 39 | } 40 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | dependencyResolutionManagement { 4 | // repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 5 | repositories { 6 | maven("https://repo.anvilpowered.org/repository/maven-public/") 7 | mavenCentral() 8 | maven("https://oss.sonatype.org/content/repositories/snapshots/") 9 | maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") 10 | maven("https://libraries.minecraft.net") 11 | maven("https://repo.papermc.io/repository/maven-public/") 12 | maven("https://repo.spongepowered.org/repository/maven-public/") 13 | } 14 | } 15 | 16 | pluginManagement { 17 | includeBuild("build-logic") 18 | repositories { 19 | mavenCentral() 20 | gradlePluginPortal() 21 | } 22 | } 23 | 24 | rootProject.name = "anvil" 25 | 26 | sequenceOf( 27 | "app-plugin", 28 | "app-plugin-core", 29 | "app-plugin-paper", 30 | "app-plugin-sponge", 31 | "app-plugin-velocity", 32 | "core", 33 | "paper", 34 | "sponge", 35 | "velocity", 36 | ).forEach { 37 | val project = ":anvil-$it" 38 | include(project) 39 | project(project).projectDir = file(it.replace('-', '/')) 40 | } 41 | -------------------------------------------------------------------------------- /sponge/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("anvil-publish") 3 | id("anvil-sign") 4 | } 5 | 6 | dependencies { 7 | api(project(":anvil-core")) 8 | compileOnlyApi(libs.sponge) 9 | implementation(libs.kotlinx.coroutines) 10 | } 11 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/AnvilSpongeApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge 20 | 21 | import com.google.inject.Injector 22 | import com.google.inject.Key 23 | import org.anvilpowered.anvil.core.AnvilApi 24 | import org.anvilpowered.anvil.core.command.CommandExecutor 25 | import org.anvilpowered.anvil.core.platform.PluginManager 26 | import org.anvilpowered.anvil.core.platform.PluginMeta 27 | import org.anvilpowered.anvil.core.platform.Server 28 | import org.anvilpowered.anvil.core.user.PlayerService 29 | import org.anvilpowered.anvil.sponge.command.SpongeCommandExecutor 30 | import org.anvilpowered.anvil.sponge.platform.SpongePluginManager 31 | import org.anvilpowered.anvil.sponge.platform.SpongePluginMeta 32 | import org.anvilpowered.anvil.sponge.platform.SpongeServer 33 | import org.anvilpowered.anvil.sponge.user.SpongePlayerService 34 | import org.apache.logging.log4j.Logger 35 | import org.koin.dsl.bind 36 | import org.koin.dsl.module 37 | import org.spongepowered.api.config.ConfigDir 38 | import org.spongepowered.plugin.metadata.PluginMetadata 39 | import java.nio.file.Path 40 | 41 | interface AnvilSpongeApi : AnvilApi { 42 | 43 | companion object 44 | } 45 | 46 | /** 47 | * Creates an Anvil API instance for Sponge. 48 | * 49 | * The returned API instance can be used to access the Anvil API. 50 | * It is intended to be used as a context receiver. 51 | * 52 | * For example, you can access it in a class like this: 53 | * ```kt 54 | * context(AnvilSpongeApi) // or AnvilApi if in common code 55 | * class MyPlugin { 56 | * fun foo() { 57 | * logger.info { "Hello, world!" } // logger property of [AnvilApi] is accessed through context receiver 58 | * } 59 | * } 60 | * ``` 61 | * 62 | * In order to invoke this constructor, you must have an instance of [AnvilSpongeApi] in the calling context. 63 | * To bring an instance of [AnvilSpongeApi] into the calling context, you can use the [with] function: 64 | * 65 | * ```kt 66 | * private val plugin = with(AnvilApi.createSponge(logger, proxyServer)) { 67 | * AnvilSpongePlugin() 68 | * } 69 | * ``` 70 | * 71 | * Context receivers may also be used on individual functions. 72 | * This is particularly useful for top-level functions: 73 | * 74 | * ```kt 75 | * context(AnvilSpongeApi) // or AnvilApi if in common code 76 | * fun foo() { 77 | * logger.info { "Hello, world!" } // logger property of [AnvilApi] is accessed through context receiver 78 | * } 79 | * ``` 80 | */ 81 | fun AnvilApi.Companion.createSponge(injector: Injector): AnvilSpongeApi { 82 | val logger = injector.getInstance(Logger::class.java) 83 | 84 | val spongeModule = module { 85 | single { logger } 86 | single { SpongeServer } 87 | single { SpongePluginManager } 88 | single { SpongePlayerService } 89 | single { SpongePluginMeta(injector.getInstance(PluginMetadata::class.java)) } 90 | single { SpongePlayerService }.bind() 91 | single { SpongeCommandExecutor }.bind() 92 | } 93 | 94 | return object : AnvilSpongeApi { 95 | override val logger: Logger = logger 96 | override val configDir: Path = injector.getInstance(Key.get(Path::class.java, ConfigDir(sharedRoot = false))) 97 | override val module = spongeModule 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/command/AnvilSpongeCommandSource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.command 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import net.kyori.adventure.audience.ForwardingAudience 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.anvil.core.user.Player 25 | import org.anvilpowered.anvil.core.user.Subject 26 | import org.anvilpowered.anvil.sponge.user.toAnvilPlayer 27 | import org.anvilpowered.anvil.sponge.user.toAnvilSubject 28 | import org.spongepowered.api.command.parameter.CommandContext 29 | import org.spongepowered.api.entity.living.player.server.ServerPlayer 30 | 31 | fun CommandContext.toAnvilCommandSource(): CommandSource = AnvilSpongeCommandSource(this) 32 | 33 | private class AnvilSpongeCommandSource( 34 | override val platformDelegate: CommandContext, 35 | ) : CommandSource, 36 | ForwardingAudience, 37 | Subject by platformDelegate.cause().toAnvilSubject() { 38 | 39 | val delegateAudiences = listOf(platformDelegate.cause().audience()) 40 | override fun audiences(): Iterable = delegateAudiences 41 | 42 | override val player: Player? = platformDelegate.cause().first(ServerPlayer::class.java).orElse(null)?.toAnvilPlayer() 43 | } 44 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/command/SpongeCommandExecutor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.command 20 | 21 | import org.anvilpowered.anvil.core.command.CommandExecutor 22 | import org.anvilpowered.anvil.core.command.CommandSource 23 | import org.spongepowered.api.Sponge 24 | import org.spongepowered.api.service.permission.Subject as SpongeSubject 25 | 26 | object SpongeCommandExecutor : CommandExecutor { 27 | override suspend fun execute(source: CommandSource, command: String): Boolean = 28 | Sponge.server().commandManager().process(source.platformDelegate as SpongeSubject, source, command).isSuccess 29 | 30 | override suspend fun executeAsConsole(command: String): Boolean = 31 | Sponge.server().commandManager().process(Sponge.systemSubject(), command).isSuccess 32 | } 33 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/platform/SpongePlatform.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.platform 20 | 21 | import org.anvilpowered.anvil.core.platform.Platform 22 | import org.anvilpowered.anvil.core.platform.PluginMeta 23 | import org.spongepowered.api.Sponge 24 | import org.spongepowered.api.Platform as SPlatform 25 | 26 | internal object SpongePlatform : Platform { 27 | override val isProxy: Boolean = false 28 | override val plugins: List 29 | get() = Sponge.pluginManager().plugins().map { it.metadata().toAnvilPluginMeta() } 30 | override val name: String 31 | get() = "sponge" 32 | override val version: String 33 | get() = Sponge.platform().container(SPlatform.Component.IMPLEMENTATION).metadata().version().qualifier 34 | } 35 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/platform/SpongePluginManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.platform 20 | 21 | import org.anvilpowered.anvil.core.platform.PluginManager 22 | import org.anvilpowered.anvil.core.platform.PluginMeta 23 | import org.spongepowered.api.Sponge 24 | 25 | internal object SpongePluginManager : PluginManager { 26 | override val plugins: List 27 | get() = Sponge.pluginManager().plugins().map { it.metadata().toAnvilPluginMeta() } 28 | } 29 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/platform/SpongePluginMeta.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.platform 20 | 21 | import org.anvilpowered.anvil.core.platform.PluginMeta 22 | import org.spongepowered.plugin.metadata.PluginMetadata 23 | 24 | internal fun PluginMetadata.toAnvilPluginMeta() = SpongePluginMeta(this) 25 | 26 | internal class SpongePluginMeta(private val delegate: PluginMetadata) : PluginMeta { 27 | override val name: String 28 | get() = delegate.id() 29 | } 30 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/platform/SpongeServer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.platform 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import org.anvilpowered.anvil.core.platform.Platform 23 | import org.anvilpowered.anvil.core.platform.Server 24 | import org.spongepowered.api.Sponge 25 | 26 | object SpongeServer : Server { 27 | override val platform: Platform 28 | get() = SpongePlatform 29 | override val broadcastAudience: Audience 30 | get() = Sponge.server().broadcastAudience() 31 | override val systemSubject: Audience 32 | get() = Sponge.game().systemSubject() 33 | } 34 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/user/AnvilSpongePlayer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.user 20 | 21 | import net.kyori.adventure.text.Component 22 | import org.anvilpowered.anvil.core.user.Player 23 | import org.anvilpowered.anvil.core.user.Subject 24 | import org.spongepowered.api.entity.living.player.server.ServerPlayer 25 | import java.util.UUID 26 | 27 | fun ServerPlayer.toAnvilPlayer(): Player = AnvilSpongePlayer(this) 28 | 29 | private class AnvilSpongePlayer( 30 | override val platformDelegate: ServerPlayer, 31 | ) : Player, 32 | Subject by platformDelegate.toAnvilSubject() { 33 | override val id: UUID = platformDelegate.uniqueId() 34 | override val username: String = platformDelegate.name() 35 | override val displayname: Component = platformDelegate.displayName().get() 36 | override val latencyMs: Int 37 | get() = platformDelegate.connection().latency() 38 | } 39 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/user/AnvilSpongeSubject.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.user 20 | 21 | import org.anvilpowered.anvil.core.user.Subject 22 | import org.spongepowered.api.util.Tristate 23 | import org.spongepowered.api.service.permission.Subject as SpongeSubject 24 | 25 | fun SpongeSubject.toAnvilSubject(): Subject = AnvilSpongeSubject(this) 26 | 27 | private class AnvilSpongeSubject( 28 | override val platformDelegate: SpongeSubject, 29 | ) : Subject { 30 | override fun hasPermission(permission: String): Boolean? = 31 | platformDelegate.permissionValue(permission).toBoolean() 32 | } 33 | 34 | private fun Tristate.toBoolean(): Boolean? = when (this) { 35 | Tristate.TRUE -> true 36 | Tristate.FALSE -> false 37 | Tristate.UNDEFINED -> null 38 | } 39 | -------------------------------------------------------------------------------- /sponge/src/main/kotlin/org/anvilpowered/anvil/sponge/user/SpongePlayerService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.sponge.user 20 | 21 | import org.anvilpowered.anvil.core.user.Player 22 | import org.anvilpowered.anvil.core.user.PlayerService 23 | import org.spongepowered.api.Sponge 24 | import java.util.UUID 25 | 26 | object SpongePlayerService : PlayerService { 27 | override fun get(username: String): Player? = 28 | Sponge.server().player(username).orElse(null)?.toAnvilPlayer() 29 | 30 | override fun get(id: UUID): Player? = 31 | Sponge.server().player(id).orElse(null)?.toAnvilPlayer() 32 | 33 | override fun getAll(startsWith: String): Sequence = when (startsWith) { 34 | "" -> Sponge.server().onlinePlayers().asSequence().map { it.toAnvilPlayer() } 35 | else -> Sponge.server().onlinePlayers().asSequence().filter { it.name().startsWith(startsWith) }.map { it.toAnvilPlayer() } 36 | } 37 | 38 | override fun count(): Int = Sponge.server().onlinePlayers().size 39 | } 40 | -------------------------------------------------------------------------------- /velocity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("anvil-publish") 3 | id("anvil-sign") 4 | } 5 | 6 | dependencies { 7 | api(project(":anvil-core")) 8 | compileOnlyApi(libs.velocity) 9 | } 10 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/AnvilVelocityApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity 20 | 21 | import com.google.inject.Injector 22 | import com.google.inject.Key 23 | import com.velocitypowered.api.plugin.PluginContainer 24 | import com.velocitypowered.api.plugin.PluginDescription 25 | import com.velocitypowered.api.plugin.annotation.DataDirectory 26 | import com.velocitypowered.api.proxy.ProxyServer 27 | import org.anvilpowered.anvil.core.AnvilApi 28 | import org.anvilpowered.anvil.core.command.CommandExecutor 29 | import org.anvilpowered.anvil.core.platform.PluginManager 30 | import org.anvilpowered.anvil.core.platform.PluginMeta 31 | import org.anvilpowered.anvil.core.platform.Server 32 | import org.anvilpowered.anvil.core.user.PlayerService 33 | import org.anvilpowered.anvil.velocity.command.VelocityCommandExecutor 34 | import org.anvilpowered.anvil.velocity.platform.VelocityPluginManager 35 | import org.anvilpowered.anvil.velocity.platform.VelocityPluginMeta 36 | import org.anvilpowered.anvil.velocity.platform.VelocityServer 37 | import org.anvilpowered.anvil.velocity.user.VelocityPlayerService 38 | import org.apache.logging.log4j.LogManager 39 | import org.apache.logging.log4j.Logger 40 | import org.koin.core.module.Module 41 | import org.koin.core.module.dsl.singleOf 42 | import org.koin.dsl.bind 43 | import org.koin.dsl.module 44 | import java.nio.file.Path 45 | 46 | /** 47 | * A subtype of [AnvilApi] that also provides access to Velocity-specific APIs such as [ProxyServer]. 48 | * 49 | * To create an instance of this interface, use [AnvilApi.Companion.createVelocity]. 50 | * 51 | * If you are using Java, the method [AnvilVelocityApi.doNotUse] is provided as an alternative. 52 | */ 53 | interface AnvilVelocityApi : AnvilApi { 54 | 55 | companion object { 56 | /** 57 | * Creates an Anvil API instance for Velocity. 58 | * 59 | * This method is meant as an alternative to [AnvilApi.Companion.createVelocity] for Java users. 60 | * 61 | * In Kotlin, you should use [AnvilApi.Companion.createVelocity] instead. 62 | */ 63 | @JvmStatic 64 | @JvmName("create") 65 | fun doNotUse(injector: Injector): AnvilVelocityApi = 66 | AnvilApi.createVelocity(injector) 67 | } 68 | } 69 | 70 | /** 71 | * Creates an Anvil API instance for Velocity. 72 | * 73 | * The returned API instance can be used to access the Anvil API. 74 | * It is intended to be used as a context receiver. 75 | * 76 | * For example, you can access it in a class like this: 77 | * ```kt 78 | * context(AnvilVelocityApi) // or AnvilApi if in common code 79 | * class MyPlugin { 80 | * fun foo() { 81 | * logger.info { "Hello, world!" } // logger property of [AnvilApi] is accessed through context receiver 82 | * } 83 | * } 84 | * ``` 85 | * 86 | * In order to invoke this constructor, you must have an instance of [AnvilVelocityApi] in the calling context. 87 | * To bring an instance of [AnvilVelocityApi] into the calling context, you can use the [with] function: 88 | * 89 | * ```kt 90 | * private val plugin = with(AnvilApi.createVelocity(logger, proxyServer)) { 91 | * AnvilVelocityPlugin() 92 | * } 93 | * ``` 94 | * 95 | * Context receivers may also be used on individual functions. 96 | * This is particularly useful for top-level functions: 97 | * 98 | * ```kt 99 | * context(AnvilVelocityApi) // or AnvilApi if in common code 100 | * fun foo() { 101 | * logger.info { "Hello, world!" } // logger property of [AnvilApi] is accessed through context receiver 102 | * } 103 | * ``` 104 | */ 105 | fun AnvilApi.Companion.createVelocity(injector: Injector): AnvilVelocityApi { 106 | val proxyServer = injector.getInstance(ProxyServer::class.java) 107 | val pluginDescription = injector.getInstance(PluginDescription::class.java) 108 | val logger = LogManager.getLogger(pluginDescription.id) 109 | val velocityModule = module { 110 | single { logger } 111 | single { VelocityServer(proxyServer) } 112 | single { VelocityPluginManager(proxyServer.pluginManager) } 113 | single { proxyServer } 114 | single { pluginDescription } 115 | single { injector.getInstance(PluginContainer::class.java) } 116 | single { VelocityPluginMeta(pluginDescription) } 117 | singleOf(::VelocityPlayerService).bind() 118 | singleOf(::VelocityCommandExecutor).bind() 119 | } 120 | 121 | return object : AnvilVelocityApi { 122 | override val logger: Logger = logger 123 | override val configDir: Path = injector.getInstance(Key.get(Path::class.java, DataDirectory())) 124 | override val module: Module = velocityModule 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/command/AnvilVelocityCommandSource.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.command 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import net.kyori.adventure.audience.ForwardingAudience 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.anvil.core.user.Player 25 | import org.anvilpowered.anvil.core.user.Subject 26 | import org.anvilpowered.anvil.velocity.user.toAnvilPlayer 27 | import org.anvilpowered.anvil.velocity.user.toAnvilSubject 28 | import com.velocitypowered.api.command.CommandSource as VelocityCommandSource 29 | import com.velocitypowered.api.proxy.Player as VelocityPlayer 30 | 31 | fun VelocityCommandSource.toAnvilCommandSource(): CommandSource = AnvilVelocityCommandSource(this) 32 | 33 | private class AnvilVelocityCommandSource( 34 | override val platformDelegate: VelocityCommandSource, 35 | ) : CommandSource, 36 | ForwardingAudience, 37 | Subject by platformDelegate.toAnvilSubject() { 38 | 39 | val delegateAudiences = listOf(platformDelegate) 40 | override fun audiences(): Iterable = delegateAudiences 41 | 42 | override val player: Player? = (platformDelegate as? VelocityPlayer)?.toAnvilPlayer() 43 | } 44 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/command/PlayerCommand.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Catalyst - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.command 20 | 21 | import com.velocitypowered.api.command.CommandSource 22 | import com.velocitypowered.api.proxy.Player 23 | import com.velocitypowered.api.proxy.ProxyServer 24 | import net.kyori.adventure.text.Component 25 | import net.kyori.adventure.text.format.NamedTextColor 26 | import org.anvilpowered.kbrig.argument.StringArgumentType 27 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 28 | import org.anvilpowered.kbrig.builder.RequiredArgumentBuilder 29 | import org.anvilpowered.kbrig.context.CommandContext 30 | import org.anvilpowered.kbrig.context.CommandContextScopeDsl 31 | import org.anvilpowered.kbrig.context.CommandExecutionScope 32 | import org.anvilpowered.kbrig.context.executesScoped 33 | import org.anvilpowered.kbrig.context.get 34 | import org.anvilpowered.kbrig.context.yieldError 35 | import org.anvilpowered.kbrig.suggestion.suggestsScoped 36 | import kotlin.jvm.optionals.getOrNull 37 | 38 | fun ArgumentBuilder.Companion.requirePlayerArgument( 39 | proxyServer: ProxyServer, 40 | argumentName: String = "player", 41 | command: suspend (context: CommandContext, player: Player) -> Int, 42 | ): RequiredArgumentBuilder = 43 | required("player", StringArgumentType.SingleWord) 44 | .suggestPlayerArgument(proxyServer) 45 | .executesScoped { yield(command(context, extractPlayerArgument(proxyServer, argumentName))) } 46 | 47 | fun ArgumentBuilder.Companion.requirePlayerArgumentScoped( 48 | proxyServer: ProxyServer, 49 | argumentName: String = "player", 50 | command: suspend CommandExecutionScope.(player: Player) -> Unit, 51 | ): RequiredArgumentBuilder = 52 | required("player", StringArgumentType.SingleWord) 53 | .suggestPlayerArgument(proxyServer) 54 | .executesScoped { command(extractPlayerArgument(proxyServer, argumentName)) } 55 | 56 | fun RequiredArgumentBuilder.suggestPlayerArgument( 57 | proxyServer: ProxyServer, 58 | ): RequiredArgumentBuilder = 59 | suggestsScoped { proxyServer.allPlayers.suggestAllFiltered { it.username } } 60 | 61 | @CommandContextScopeDsl 62 | suspend fun CommandExecutionScope.extractPlayerArgument( 63 | proxyServer: ProxyServer, 64 | argumentName: String = "player", 65 | ): Player { 66 | val playerName = context.get(argumentName) 67 | val player = proxyServer.getPlayer(playerName).getOrNull() 68 | if (player == null) { 69 | context.source.sendMessage( 70 | Component.text() 71 | .append(Component.text("Player with name ", NamedTextColor.RED)) 72 | .append(Component.text(playerName, NamedTextColor.GOLD)) 73 | .append(Component.text(" not found!", NamedTextColor.RED)) 74 | .build(), 75 | ) 76 | yieldError() 77 | } 78 | return player 79 | } 80 | 81 | @CommandContextScopeDsl 82 | suspend fun CommandExecutionScope.extractPlayerSource(): Player { 83 | val player = extractPlayerSourceOrNull() 84 | if (player == null) { 85 | context.source.sendMessage(Component.text("You must be a player to use this command!", NamedTextColor.RED)) 86 | yieldError() 87 | } 88 | return player 89 | } 90 | 91 | @CommandContextScopeDsl 92 | fun CommandContext.Scope.extractPlayerSourceOrNull(): Player? = context.source as? Player 93 | 94 | @CommandContextScopeDsl 95 | suspend fun CommandContext.Scope.extractPlayerSourceOrAbort(): Player = extractPlayerSourceOrNull() ?: abort() 96 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/command/VelocityCommandExecutor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.command 20 | 21 | import com.velocitypowered.api.proxy.ProxyServer 22 | import kotlinx.coroutines.future.await 23 | import org.anvilpowered.anvil.core.command.CommandExecutor 24 | import org.anvilpowered.anvil.core.command.CommandSource 25 | import com.velocitypowered.api.command.CommandSource as VelocityCommandSource 26 | 27 | class VelocityCommandExecutor( 28 | private val proxyServer: ProxyServer, 29 | ) : CommandExecutor { 30 | override suspend fun execute(source: CommandSource, command: String): Boolean { 31 | return proxyServer.commandManager.executeAsync( 32 | source.platformDelegate as VelocityCommandSource, 33 | command, 34 | ).await() 35 | } 36 | 37 | override suspend fun executeAsConsole(command: String): Boolean { 38 | return proxyServer.commandManager.executeAsync( 39 | proxyServer.consoleCommandSource, 40 | command, 41 | ).await() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/command/VelocitySourceConverter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | @file:JvmName("VelocitySourceConverter") 20 | 21 | package org.anvilpowered.anvil.velocity.command 22 | 23 | import org.anvilpowered.anvil.core.command.CommandSource 24 | import org.anvilpowered.kbrig.brigadier.toBrigadier 25 | import org.anvilpowered.kbrig.tree.ArgumentCommandNode 26 | import org.anvilpowered.kbrig.tree.LiteralCommandNode 27 | import org.anvilpowered.kbrig.tree.mapSource 28 | import com.mojang.brigadier.tree.ArgumentCommandNode as BrigadierArgumentCommandNode 29 | import com.mojang.brigadier.tree.LiteralCommandNode as BrigadierLiteralCommandNode1 30 | import com.velocitypowered.api.command.CommandSource as VelocityCommandSource 31 | 32 | /** 33 | * Converts a kbrig argument command node to a velocity brigadier argument command node. 34 | */ 35 | fun ArgumentCommandNode.toVelocity(): BrigadierArgumentCommandNode = 36 | mapSource { it.toAnvilCommandSource() }.toBrigadier() 37 | 38 | /** 39 | * Converts a kbrig literal command node to a velocity brigadier literal command node. 40 | */ 41 | fun LiteralCommandNode.toVelocity(): BrigadierLiteralCommandNode1 = 42 | mapSource { it.toAnvilCommandSource() }.toBrigadier() 43 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/platform/VelocityPlatform.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.platform 20 | 21 | import com.velocitypowered.api.proxy.ProxyServer 22 | import org.anvilpowered.anvil.core.platform.Platform 23 | import org.anvilpowered.anvil.core.platform.PluginMeta 24 | 25 | internal class VelocityPlatform(private val proxyServer: ProxyServer) : Platform { 26 | override val isProxy: Boolean = true 27 | override val plugins: List 28 | get() = proxyServer.pluginManager.plugins.map { it.description.toAnvilPluginMeta() } 29 | override val name: String = "velocity" 30 | override val version: String = proxyServer.version.version 31 | } 32 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/platform/VelocityPluginManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.platform 20 | 21 | import org.anvilpowered.anvil.core.platform.PluginManager 22 | import org.anvilpowered.anvil.core.platform.PluginMeta 23 | import com.velocitypowered.api.plugin.PluginManager as BackingPluginManager 24 | 25 | internal class VelocityPluginManager(private val backing: BackingPluginManager) : PluginManager { 26 | override val plugins: List 27 | get() = backing.plugins.map { it.description.toAnvilPluginMeta() } 28 | } 29 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/platform/VelocityPluginMeta.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.platform 20 | 21 | import com.velocitypowered.api.plugin.PluginDescription 22 | import org.anvilpowered.anvil.core.platform.PluginMeta 23 | 24 | internal fun PluginDescription.toAnvilPluginMeta() = VelocityPluginMeta(this) 25 | 26 | internal class VelocityPluginMeta(private val delegate: PluginDescription) : PluginMeta { 27 | override val name: String 28 | get() = delegate.id 29 | } 30 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/platform/VelocityServer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.platform 20 | 21 | import com.velocitypowered.api.proxy.ProxyServer 22 | import net.kyori.adventure.audience.Audience 23 | import org.anvilpowered.anvil.core.platform.Platform 24 | import org.anvilpowered.anvil.core.platform.Server 25 | 26 | class VelocityServer(proxyServer: ProxyServer) : Server { 27 | override val platform: Platform = VelocityPlatform(proxyServer) 28 | override val broadcastAudience: Audience = proxyServer 29 | override val systemSubject: Audience = proxyServer.consoleCommandSource 30 | } 31 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/user/AnvilVelocityPlayer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.user 20 | 21 | import net.kyori.adventure.audience.Audience 22 | import net.kyori.adventure.audience.ForwardingAudience 23 | import net.kyori.adventure.text.Component 24 | import org.anvilpowered.anvil.core.user.Player 25 | import org.anvilpowered.anvil.core.user.Subject 26 | import java.util.UUID 27 | import com.velocitypowered.api.proxy.Player as VelocityPlayer 28 | 29 | fun VelocityPlayer.toAnvilPlayer(): Player = AnvilVelocityPlayer(this) 30 | 31 | private class AnvilVelocityPlayer( 32 | override val platformDelegate: VelocityPlayer, 33 | ) : Player, 34 | ForwardingAudience, 35 | Subject by platformDelegate.toAnvilSubject() { 36 | 37 | val delegateAudiences = listOf(platformDelegate) 38 | override fun audiences(): Iterable = delegateAudiences 39 | 40 | override val id: UUID = platformDelegate.uniqueId 41 | override val username: String = platformDelegate.username 42 | override val displayname: Component = Component.text(platformDelegate.username) 43 | override val latencyMs: Int 44 | get() = platformDelegate.ping.toInt() 45 | } 46 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/user/AnvilVelocitySubject.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.user 20 | 21 | import com.velocitypowered.api.permission.Tristate 22 | import org.anvilpowered.anvil.core.user.Subject 23 | import com.velocitypowered.api.permission.PermissionSubject as VelocitySubject 24 | 25 | fun VelocitySubject.toAnvilSubject(): Subject = AnvilVelocitySubject(this) 26 | 27 | private class AnvilVelocitySubject( 28 | override val platformDelegate: VelocitySubject, 29 | ) : Subject { 30 | override fun hasPermission(permission: String): Boolean? = 31 | platformDelegate.getPermissionValue(permission).toBoolean() 32 | } 33 | 34 | private fun Tristate.toBoolean(): Boolean? = when (this) { 35 | Tristate.TRUE -> true 36 | Tristate.FALSE -> false 37 | Tristate.UNDEFINED -> null 38 | } 39 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/user/ArgumentExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.user 20 | 21 | import com.velocitypowered.api.command.CommandSource 22 | import org.anvilpowered.kbrig.builder.ArgumentBuilder 23 | 24 | fun > B.requiresPermission(permission: String): B = 25 | requires { it.hasPermission(permission) } 26 | -------------------------------------------------------------------------------- /velocity/src/main/kotlin/org/anvilpowered/anvil/velocity/user/VelocityPlayerService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Anvil - AnvilPowered.org 3 | * Copyright (C) 2019-2024 Contributors 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package org.anvilpowered.anvil.velocity.user 20 | 21 | import com.velocitypowered.api.proxy.ProxyServer 22 | import org.anvilpowered.anvil.core.user.Player 23 | import org.anvilpowered.anvil.core.user.PlayerService 24 | import java.util.UUID 25 | 26 | class VelocityPlayerService(private val proxyServer: ProxyServer) : PlayerService { 27 | override fun get(username: String): Player? = 28 | proxyServer.getPlayer(username).orElse(null)?.toAnvilPlayer() 29 | 30 | override fun get(id: UUID): Player? = 31 | proxyServer.getPlayer(id).orElse(null)?.toAnvilPlayer() 32 | 33 | override fun getAll(startsWith: String): Sequence = when (startsWith) { 34 | "" -> proxyServer.allPlayers.asSequence().map { it.toAnvilPlayer() } 35 | else -> proxyServer.matchPlayer(startsWith).asSequence().map { it.toAnvilPlayer() } 36 | } 37 | 38 | override fun count(): Int = proxyServer.playerCount 39 | } 40 | -------------------------------------------------------------------------------- /version: -------------------------------------------------------------------------------- 1 | 0.4.0-SNAPSHOT 2 | --------------------------------------------------------------------------------