├── .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 | [](https://discord.gg/6gR2YH3) [](http://ci.anvilpowered.org/viewType.html?buildTypeId=Anvil_Build&guest=1) [](https://www.gnu.org/licenses/lgpl-3.0.html) [](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