Skip to content

Commit e9002ff

Browse files
committed
fix: Include kodein in idofront
feat: Reimplement main command logic as a feature
1 parent 803342c commit e9002ff

9 files changed

Lines changed: 98 additions & 20 deletions

File tree

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ platform = [
115115
"creative-server",
116116
"kermit",
117117
"koin-core",
118+
"kodein-di",
118119
"kotlin-reflect",
119120
"kotlin-stdlib",
120121
"kotlinx-coroutines",

gradle/wrapper/gradle-wrapper.jar

5.38 KB
Binary file not shown.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
#Sun Mar 29 15:31:26 EDT 2026
21
distributionBase=GRADLE_USER_HOME
32
distributionPath=wrapper/dists
43
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
4+
networkTimeout=10000
5+
validateDistributionUrl=true
56
zipStoreBase=GRADLE_USER_HOME
67
zipStorePath=wrapper/dists
Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
package com.mineinabyss.idofront
22

3-
import com.mineinabyss.idofront.di.DI
43
import com.mineinabyss.idofront.messaging.ComponentLogger
54
import com.mineinabyss.idofront.plugin.Services
65
import com.mineinabyss.idofront.plugin.listeners
76
import com.mineinabyss.idofront.serialization.recipes.options.IngredientOptionsListener
87
import com.mineinabyss.idofront.services.SerializableItemStackService
98
import com.mineinabyss.idofront.services.impl.SerializableItemStackServiceImpl
109
import org.bukkit.plugin.java.JavaPlugin
10+
import org.kodein.di.*
11+
12+
class IdofrontPlugin : JavaPlugin(), DIAware {
13+
override val di = DI {
14+
bindSingleton { ComponentLogger.forPlugin(this@IdofrontPlugin) }
15+
bindSingleton { IngredientOptionsListener(this@IdofrontPlugin) }
16+
bindSingleton { SerializableItemStackServiceImpl() }
17+
}
18+
19+
val direct = di.direct
1120

12-
class IdofrontPlugin : JavaPlugin() {
1321
override fun onLoad() {
14-
DI.scoped("Idofront").add<ComponentLogger>(ComponentLogger.forPlugin(this))
15-
Services.register<SerializableItemStackService>(this, SerializableItemStackServiceImpl())
22+
Services.register<SerializableItemStackService>(this, direct.instance())
1623
}
1724

1825
override fun onEnable() {
19-
val recipeOptionsListener = IngredientOptionsListener(this)
20-
DI.add(recipeOptionsListener)
21-
listeners(recipeOptionsListener)
26+
listeners(direct.instance<IngredientOptionsListener>())
2227
}
2328
}

idofront-features/src/main/kotlin/com/mineinabyss/idofront/features/FeatureDSL.kt

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package com.mineinabyss.idofront.features
22

33
import com.github.shynixn.mccoroutine.bukkit.registerSuspendingEvents
44
import com.mineinabyss.features.*
5-
import com.mineinabyss.idofront.commands.brigadier.IdoRootCommand
6-
import com.mineinabyss.idofront.commands.brigadier.RootIdoCommands
7-
import com.mineinabyss.idofront.commands.brigadier.commands
5+
import com.mineinabyss.idofront.commands.brigadier.*
86
import com.mineinabyss.idofront.commands.brigadier.context.IdoCommandContext
7+
import com.mineinabyss.idofront.messaging.error
8+
import com.mineinabyss.idofront.messaging.success
9+
import com.mineinabyss.idofront.plugin.Plugins
910
import com.mineinabyss.idofront.plugin.unregisterListeners
1011
import kotlinx.coroutines.CoroutineScope
1112
import kotlinx.coroutines.Job
@@ -34,6 +35,14 @@ fun FeatureDI.listeners(vararg listeners: Listener) {
3435
}
3536
}
3637

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+
}
44+
}
45+
3746
fun FeatureDI.task(job: Job) {
3847
val scope = instance<CoroutineScope>()
3948
scope.launch { job.join() }
@@ -53,9 +62,47 @@ fun FeatureBuilder.commands(block: context(DICommandContext) RootIdoCommands.()
5362
}
5463
}
5564

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+
56103
fun FeatureBuilder.mainCommand(block: context(DICommandContext) IdoRootCommand.() -> Unit) {
57104
onLoad {
58-
instance<MainCommand>().subcommand(block)
105+
instance<MainCommand>().subcommand(name, block)
59106
}
60107
}
61108

@@ -64,10 +111,16 @@ data class MainCommand(
64111
val description: String?,
65112
val reloadCommandName: String? = null,
66113
val reloadCommandPermission: String? = null,
114+
val reloadableFeatures: List<Feature<*>>? = null,
67115
val permission: String? = null,
68116
) {
69-
internal val subcommands = mutableListOf<context(DICommandContext) IdoRootCommand.() -> Unit>()
70-
fun subcommand(block: context(DICommandContext) IdoRootCommand.() -> Unit) {
71-
subcommands += block
117+
internal val subcommands = mutableListOf<Subcommand>()
118+
fun subcommand(featureName: String, block: context(DICommandContext) IdoRootCommand.() -> Unit) {
119+
subcommands += Subcommand(featureName, block)
72120
}
73121
}
122+
123+
data class Subcommand(
124+
val featureName: String,
125+
val create: context(DICommandContext) IdoRootCommand.() -> Unit,
126+
)
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
package com.mineinabyss.idofront.messaging
22

3-
import com.mineinabyss.idofront.di.DI
4-
5-
val idofrontLogger by DI.scoped("Idofront").observeLogger()
3+
val idofrontLogger = ComponentLogger.fallback(tag = "Idofront")

idofront-serializers/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ plugins {
99

1010
dependencies {
1111
compileOnly(libs.kotlin.reflect)
12+
compileOnly(libs.kodein.di)
1213
compileOnly(libs.kotlinx.serialization.json)
1314
compileOnly(libs.kotlinx.serialization.kaml)
1415
compileOnly(libs.minecraft.plugin.mythic.dist)

idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/recipes/options/IngredientOptionsListener.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package com.mineinabyss.idofront.serialization.recipes.options
22

3-
import com.mineinabyss.idofront.di.DI
3+
import com.mineinabyss.idofront.plugin.Plugins
44
import org.bukkit.Bukkit
55
import org.bukkit.Keyed
66
import org.bukkit.event.EventHandler
77
import org.bukkit.event.Listener
88
import org.bukkit.event.inventory.CraftItemEvent
99
import org.bukkit.plugin.Plugin
10+
import org.kodein.di.DIAware
11+
import org.kodein.di.instance
1012

11-
val ingredientOptionsListener by DI.observe<IngredientOptionsListener>()
13+
val ingredientOptionsListener by Plugins.get<DIAware>("Idofront").instance<IngredientOptionsListener>()
1214

1315
class IngredientOptionsListener(
1416
val plugin: Plugin,

idofront-util/src/main/kotlin/com/mineinabyss/idofront/plugin/Plugins.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.mineinabyss.idofront.plugin
22

3+
import com.mineinabyss.idofront.plugin.Plugins.getOrNull
34
import org.bukkit.Bukkit
45
import org.bukkit.plugin.Plugin
56

@@ -11,12 +12,28 @@ object Plugins {
1112
inline fun <reified T : Plugin> get(): T =
1213
getOrNull() ?: error("Could not find plugin ${T::class.simpleName}")
1314

15+
/**
16+
* Gets a plugin by name, ensuring it's of type [T], throws an error if not found or class isn't loaded.
17+
*/
18+
inline fun <reified T> get(name: String): T =
19+
getOrNull(name) ?: error("Could not find plugin ${T::class.simpleName}")
20+
1421
/** Gets a plugin registered with Bukkit with main class [T] or null if not found. */
1522
inline fun <reified T : Plugin> getOrNull(): T? {
1623
if (runCatching { T::class }.isFailure) return null
1724
return Bukkit.getPluginManager().plugins.find { it::class == T::class } as? T
1825
}
1926

27+
/**
28+
* Gets a plugin by name, ensuring it's of type [T].
29+
*
30+
* If the class [T] is not loaded, returns `null`.
31+
*/
32+
inline fun <reified T> getOrNull(name: String): T? {
33+
if (runCatching { T::class }.isFailure) return null
34+
return Bukkit.getPluginManager().getPlugin(name) as? T
35+
}
36+
2037
/** Checks if a plugin with main class [T] exists and is enabled. */
2138
inline fun <reified T : Plugin> isEnabled(): Boolean =
2239
getOrNull<T>()?.let { isEnabled(it) } ?: false

0 commit comments

Comments
 (0)