Skip to content

Commit 5bcf7a2

Browse files
committed
refactor: Update DI library
1 parent e9002ff commit 5bcf7a2

10 files changed

Lines changed: 147 additions & 162 deletions

File tree

gradle/libs.versions.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ creative = "1.11.14"
77
customblockdata = "1.2.1"
88
dataframe = "0.15.0"
99
dependencyversions = "0.52.0"
10+
dependencies-kt = "0.1.3-dev.0"
1011
dokka = "2.1.0"
1112
exposed = "1.0.0"
1213
fastutil = "8.5.18"
@@ -40,13 +41,13 @@ sqlite-jdbc = "3.50.2.0"
4041
sqlite = "2.5.2"
4142
vault = "1.7"
4243
version-catalog-update = "1.0.0"
43-
kodein = "7.30.0"
4444
worldguard = "7.1.0-SNAPSHOT"
4545

4646
[libraries]
4747
creative-api = { module = "team.unnamed:creative-api", version.ref = "creative" }
4848
creative-serializer-minecraft = { module = "team.unnamed:creative-serializer-minecraft", version.ref = "creative" }
4949
creative-server = { module = "team.unnamed:creative-server", version.ref = "creative" }
50+
dependencies = { module = "com.mineinabyss.dependencies:core", version.ref = "dependencies-kt" }
5051
exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
5152
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
5253
exposed-javatime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" }
@@ -60,7 +61,6 @@ junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "jun
6061
kermit = "co.touchlab:kermit:2.0.5"
6162
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
6263
koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" }
63-
kodein-di = { module = "org.kodein.di:kodein-di", version.ref = "kodein" }
6464
kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
6565
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
6666
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
@@ -115,7 +115,7 @@ platform = [
115115
"creative-server",
116116
"kermit",
117117
"koin-core",
118-
"kodein-di",
118+
"dependencies",
119119
"kotlin-reflect",
120120
"kotlin-stdlib",
121121
"kotlinx-coroutines",
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
package com.mineinabyss.idofront
22

3-
import com.mineinabyss.idofront.messaging.ComponentLogger
3+
import com.mineinabyss.dependencies.DI
4+
import com.mineinabyss.dependencies.get
5+
import com.mineinabyss.dependencies.single
6+
import com.mineinabyss.idofront.features.singlePluginLogger
47
import com.mineinabyss.idofront.plugin.Services
58
import com.mineinabyss.idofront.plugin.listeners
69
import com.mineinabyss.idofront.serialization.recipes.options.IngredientOptionsListener
710
import com.mineinabyss.idofront.services.SerializableItemStackService
811
import com.mineinabyss.idofront.services.impl.SerializableItemStackServiceImpl
912
import org.bukkit.plugin.java.JavaPlugin
10-
import org.kodein.di.*
1113

12-
class IdofrontPlugin : JavaPlugin(), DIAware {
14+
class IdofrontPlugin : JavaPlugin(), DI {
1315
override val di = DI {
14-
bindSingleton { ComponentLogger.forPlugin(this@IdofrontPlugin) }
15-
bindSingleton { IngredientOptionsListener(this@IdofrontPlugin) }
16-
bindSingleton { SerializableItemStackServiceImpl() }
16+
singlePluginLogger(this@IdofrontPlugin)
17+
single { IngredientOptionsListener(this@IdofrontPlugin) }
18+
single<SerializableItemStackService> { SerializableItemStackServiceImpl() }
1719
}
1820

19-
val direct = di.direct
20-
2121
override fun onLoad() {
22-
Services.register<SerializableItemStackService>(this, direct.instance())
22+
Services.register<SerializableItemStackService>(this, get())
2323
}
2424

2525
override fun onEnable() {
26-
listeners(direct.instance<IngredientOptionsListener>())
26+
listeners(get<IngredientOptionsListener>())
2727
}
2828
}

idofront-features/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ plugins {
99
}
1010

1111
dependencies {
12-
api(libs.kodein.di)
1312
compileOnly(libs.kotlinx.serialization.json)
1413
compileOnly(libs.minecraft.mccoroutine)
1514
compileOnly(idofrontLibs.kotlinx.coroutines)
1615
implementation(projects.idofrontUtil)
1716
implementation(projects.idofrontCommands)
1817
implementation(projects.idofrontLogging)
1918
implementation(projects.idofrontConfig)
20-
api("com.mineinabyss.features:core:0.1")
19+
api(idofrontLibs.dependencies)
2120
}
2221
val compileKotlin: KotlinCompile by tasks
2322

Lines changed: 20 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,21 @@
11
package com.mineinabyss.idofront.features
22

33
import com.github.shynixn.mccoroutine.bukkit.registerSuspendingEvents
4-
import com.mineinabyss.features.*
5-
import com.mineinabyss.idofront.commands.brigadier.*
6-
import com.mineinabyss.idofront.commands.brigadier.context.IdoCommandContext
7-
import com.mineinabyss.idofront.messaging.error
8-
import com.mineinabyss.idofront.messaging.success
4+
import com.mineinabyss.dependencies.*
95
import com.mineinabyss.idofront.plugin.Plugins
106
import com.mineinabyss.idofront.plugin.unregisterListeners
117
import kotlinx.coroutines.CoroutineScope
128
import kotlinx.coroutines.Job
139
import kotlinx.coroutines.launch
10+
import org.bukkit.Bukkit
1411
import org.bukkit.event.Listener
1512
import org.bukkit.plugin.Plugin
16-
import org.kodein.di.DirectDI
17-
import org.kodein.di.direct
18-
import org.kodein.di.instance
1913

20-
context(di: DirectDI)
21-
inline val plugin get() = di.instance<Plugin>()
14+
context(di: MutableDI)
15+
inline val plugin get() = di.get<Plugin>()
2216

23-
fun FeatureDI.listeners(vararg listeners: Listener) {
24-
val plugin = instance<Plugin>()
17+
fun MutableDI.listeners(vararg listeners: Listener) {
18+
val plugin = get<Plugin>()
2519
val manager = plugin.server.pluginManager
2620

2721
addCloseable { plugin.unregisterListeners(*listeners) }
@@ -35,92 +29,26 @@ fun FeatureDI.listeners(vararg listeners: Listener) {
3529
}
3630
}
3731

38-
39-
fun FeatureBuilder.FeatureDependenciesBuilder.plugins(vararg names: String) {
40-
condition {
41-
val notEnabled = names.filterNot { Plugins.isEnabled(it) }
42-
require(notEnabled.isEmpty()) { "Plugin dependencies not found: $notEnabled" }
43-
}
32+
fun requirePlugins(vararg names: String) {
33+
val notEnabled = names.filterNot { Plugins.isEnabled(it) }
34+
require(notEnabled.isEmpty()) { "Plugin dependencies not found $notEnabled" }
4435
}
4536

46-
fun FeatureDI.task(job: Job) {
47-
val scope = instance<CoroutineScope>()
37+
fun MutableDI.task(job: Job) {
38+
val scope = get<CoroutineScope>()
4839
scope.launch { job.join() }
4940
}
5041

51-
data class DICommandContext(val manager: FeatureManager, val feature: Feature<*>)
52-
53-
context(di: DICommandContext)
54-
inline fun <reified T : Any> IdoCommandContext.get(): T = di.manager.getInstance(di.feature)?.di?.direct?.instance<T>() ?: error("Command tried to get feature config of an unloaded feature: ${di.feature.name}.")
55-
56-
fun FeatureBuilder.commands(block: context(DICommandContext) RootIdoCommands.() -> Unit) {
57-
onLoad {
58-
val context = DICommandContext(instance(), instance())
59-
instance<Plugin>().commands {
60-
block(context, this)
61-
}
62-
}
63-
}
64-
65-
val MainCommandFeature = feature("Main Command") {
66-
onLoad {
67-
plugin.commands {
68-
val main = get<MainCommand>()
69-
val manager = get<FeatureManager>()
70-
main.names.invoke {
71-
description = main.description
72-
permission = main.permission
73-
main.subcommands.forEach { subcommand ->
74-
val feature = manager.getNamed(subcommand.featureName) ?: error("Feature name not found: ${subcommand.featureName}")
75-
val context = DICommandContext(manager, feature)
76-
subcommand.create(context, this)
77-
}
78-
79-
if (main.reloadCommandName != null) {
80-
main.reloadCommandName {
81-
permission = main.reloadCommandPermission
82-
83-
executes {
84-
manager.reloadAll()
85-
}
86-
87-
executes.args(
88-
"feature" to Args.string().oneOf { manager.loaded.map { it.name }.toList() }
89-
) { featureName ->
90-
if (manager.reload(manager.getNamed(featureName) ?: fail("Feature $featureName not found"))) {
91-
sender.success("Reloaded feature $featureName")
92-
} else {
93-
sender.error("Failed to reload feature $featureName")
94-
}
95-
}
96-
}
97-
}
98-
}
99-
}
100-
}
101-
}
102-
103-
fun FeatureBuilder.mainCommand(block: context(DICommandContext) IdoRootCommand.() -> Unit) {
104-
onLoad {
105-
instance<MainCommand>().subcommand(name, block)
106-
}
107-
}
42+
//fun MutableDI.commands(block: context(DICommandContext) RootIdoCommands.() -> Unit) = once {
43+
// val context = DICommandContext(get(), get())
44+
// get<Plugin>().commands {
45+
// block(context, this)
46+
// }
47+
//}
10848

109-
data class MainCommand(
110-
val names: List<String>,
111-
val description: String?,
112-
val reloadCommandName: String? = null,
113-
val reloadCommandPermission: String? = null,
114-
val reloadableFeatures: List<Feature<*>>? = null,
115-
val permission: String? = null,
116-
) {
117-
internal val subcommands = mutableListOf<Subcommand>()
118-
fun subcommand(featureName: String, block: context(DICommandContext) IdoRootCommand.() -> Unit) {
119-
subcommands += Subcommand(featureName, block)
49+
inline fun MutableDI.onServerStartup(block: () -> Unit) {
50+
if (Bukkit.getCurrentTick() == 0) {
51+
block()
12052
}
12153
}
12254

123-
data class Subcommand(
124-
val featureName: String,
125-
val create: context(DICommandContext) IdoRootCommand.() -> Unit,
126-
)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.mineinabyss.idofront.features
2+
3+
import com.mineinabyss.dependencies.DI
4+
import com.mineinabyss.dependencies.DIScope
5+
import com.mineinabyss.dependencies.get
6+
import com.mineinabyss.dependencies.module
7+
import com.mineinabyss.idofront.commands.brigadier.Args
8+
import com.mineinabyss.idofront.commands.brigadier.IdoRootCommand
9+
import com.mineinabyss.idofront.commands.brigadier.commands
10+
import com.mineinabyss.idofront.commands.brigadier.context.IdoCommandContext
11+
import com.mineinabyss.idofront.commands.brigadier.oneOf
12+
import com.mineinabyss.idofront.messaging.error
13+
import com.mineinabyss.idofront.messaging.success
14+
15+
data class DICommandContext(val scope: DIScope, val module: DI.Module)
16+
17+
data class MainCommand(
18+
val names: List<String>,
19+
val description: String?,
20+
val reloadCommandName: String? = null,
21+
val reloadCommandPermission: String? = null,
22+
val reloadableFeatures: List<DI.Module>? = null,
23+
val permission: String? = null,
24+
) {
25+
internal val subcommands = mutableListOf<Subcommand>()
26+
fun subcommand(module: DI.Module, block: context(DICommandContext) IdoRootCommand.() -> Unit) {
27+
subcommands += Subcommand(module, block)
28+
}
29+
}
30+
31+
data class Subcommand(
32+
val module: DI.Module,
33+
val create: context(DICommandContext) IdoRootCommand.() -> Unit,
34+
)
35+
36+
context(di: DICommandContext)
37+
inline fun <reified T : Any> IdoCommandContext.get(): T = di
38+
.scope[di.module]
39+
?.get<T>() ?: error("Command tried to get feature config of an unloaded feature: ${di.module.name}.")
40+
41+
val MainCommandFeature = module("Main Command") {
42+
onServerStartup {
43+
plugin.commands {
44+
val main = get<MainCommand>()
45+
val manager = get<DIScope>()
46+
main.names.invoke {
47+
description = main.description
48+
permission = main.permission
49+
main.subcommands.forEach { subcommand ->
50+
// val feature = manager.getModule(subcommand.module) ?: error("Feature name not found: ${subcommand.module}")
51+
val context = DICommandContext(manager, subcommand.module)
52+
subcommand.create(context, this)
53+
}
54+
55+
if (main.reloadCommandName != null) {
56+
main.reloadCommandName {
57+
permission = main.reloadCommandPermission
58+
59+
executes {
60+
if (main.reloadableFeatures == null)
61+
manager.reloadAll()
62+
else manager.reload(*main.reloadableFeatures.toTypedArray())
63+
}
64+
65+
executes.args(
66+
"feature" to Args.string().oneOf {
67+
if (main.reloadableFeatures == null)
68+
manager.loaded.map { it.name }.toList()
69+
else main.reloadableFeatures.map { it.name }
70+
}
71+
) { featureName ->
72+
val feat = manager.loaded.find { it.name == featureName } ?: fail("Feature $featureName not found")
73+
if (runCatching { manager.reload(feat) }.onFailure { it.printStackTrace() }.isSuccess) {
74+
sender.success("Reloaded feature $featureName")
75+
} else {
76+
sender.error("Failed to reload feature $featureName")
77+
}
78+
}
79+
}
80+
}
81+
}
82+
}
83+
}
84+
}
85+
86+
/**
87+
* Registers a subcommand under this plugin's [MainCommand].
88+
*/
89+
fun DI.Module.mainCommand(block: context(DICommandContext) IdoRootCommand.() -> Unit): DI.Module {
90+
return override {
91+
onServerStartup {
92+
get<MainCommand>().subcommand(this@mainCommand, block)
93+
}
94+
}
95+
}
Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.mineinabyss.idofront.features
22

3+
import co.touchlab.kermit.Logger
4+
import com.mineinabyss.dependencies.MutableDI
5+
import com.mineinabyss.dependencies.and
6+
import com.mineinabyss.dependencies.get
7+
import com.mineinabyss.dependencies.single
38
import com.mineinabyss.idofront.config.ConfigBuilder
49
import com.mineinabyss.idofront.config.config
10+
import com.mineinabyss.idofront.messaging.ComponentLogger
511
import org.bukkit.plugin.Plugin
6-
import org.kodein.di.DI
7-
import org.kodein.di.DirectDI
8-
import org.kodein.di.bindSingleton
9-
import org.kodein.di.instance
1012
import kotlin.io.path.div
1113

1214
/**
@@ -15,12 +17,12 @@ import kotlin.io.path.div
1517
* For more complicated config use-cases (ex. reading a directory), use [com.mineinabyss.idofront.config.ConfigBuilder] and manually inject via a context class.
1618
*/
1719

18-
inline fun <reified T : Any> DI.Builder.bindConfig(
20+
inline fun <reified T : Any> MutableDI.singleConfig(
1921
path: String,
20-
crossinline configure: context(DirectDI) ConfigBuilder<T>.() -> Unit = {},
21-
) {
22-
bindSingleton {
23-
val plugin = instance<Plugin>()
24-
config<T> { configure() }.single(plugin.dataPath / path).read()
25-
}
26-
}
22+
crossinline configure: ConfigBuilder<T>.() -> Unit = {},
23+
) = single<T> {
24+
val plugin = get<Plugin>()
25+
config<T> { configure() }.single(plugin.dataPath / path).read()
26+
}
27+
28+
fun MutableDI.singlePluginLogger(plugin: Plugin) = single { ComponentLogger.forPlugin(plugin) }.and<Logger>()

0 commit comments

Comments
 (0)