From 915f61c6f24a9895a49e1c4afa9a9c43bdd36e35 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Fri, 15 Mar 2024 14:46:05 -0400 Subject: [PATCH] Feat: Allow defaults for DI observers Feat: Scoped DI This is pretty much multi-context support but every context is tied to the root DI so clearing is still easy! Feat: Integrate logging with DI system, tries to create reasonable defaults when a logger isn't registered, deprecate old logging functions. Deps: Kotlin 1.9.23, compose 1.6.1 --- gradle.properties | 2 +- gradle/libs.versions.toml | 5 +- .../com/mineinabyss/idofront/di/DIContext.kt | 19 ++++ .../idofront/di/DefaultingModuleObserver.kt | 21 ++++ .../idofront/di/ScopedDIContext.kt | 8 ++ .../idofront/features/FeatureManager.kt | 15 ++- idofront-logging/build.gradle.kts | 2 + .../idofront/messaging/ComponentLogger.kt | 91 +++++++++++++++ .../idofront/messaging/IdoLogging.kt | 106 ++++++++++++++++++ .../idofront/messaging/IdofrontLogger.kt | 5 + .../idofront/messaging/KermitPaperWriter.kt | 36 ++++++ .../mineinabyss/idofront/messaging/Logging.kt | 104 ----------------- .../idofront/messaging/LoggingDI.kt | 22 ++++ idofront-plugin-loader/build.gradle.kts | 7 -- .../loading/IdofrontPluginLoader.java | 53 --------- .../idofront/serialization/ColorSerializer.kt | 1 + .../serialization/SerializableItemStack.kt | 13 ++- .../SerializableItemStackSerializer.kt | 27 ++--- idofront-util/build.gradle.kts | 1 + 19 files changed, 342 insertions(+), 196 deletions(-) create mode 100644 idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DefaultingModuleObserver.kt create mode 100644 idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/ScopedDIContext.kt create mode 100644 idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/ComponentLogger.kt create mode 100644 idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdoLogging.kt create mode 100644 idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdofrontLogger.kt create mode 100644 idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/KermitPaperWriter.kt delete mode 100644 idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/Logging.kt create mode 100644 idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/LoggingDI.kt delete mode 100644 idofront-plugin-loader/build.gradle.kts delete mode 100644 idofront-plugin-loader/src/main/java/com/mineinabyss/idofront/loading/IdofrontPluginLoader.java diff --git a/gradle.properties b/gradle.properties index 984f65cf..e7a9188f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=com.mineinabyss -version=0.22 +version=0.23 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1adc2cb7..1bf71429 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,11 @@ [versions] minecraft = "1.20.4-R0.1-SNAPSHOT" -kotlin = "1.9.20" +kotlin = "1.9.23" jvm = "17" anvilgui = "1.9.2-SNAPSHOT" coroutines = "1.7.3" -compose = "1.5.11" +compose = "1.6.1" exposed = "0.46.0" fastutil = "8.2.2" fawe = "2.8.4" @@ -153,6 +153,7 @@ platform = [ "ktor-client-cio", "ktor-client-logging", "ktor-client-content-negotiation", + "kermit", "logback-classic", "kmongo-coroutine-serialization", "creative-api", diff --git a/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DIContext.kt b/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DIContext.kt index 2e9f5185..88043d16 100644 --- a/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DIContext.kt +++ b/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DIContext.kt @@ -11,6 +11,24 @@ open class DIContext { @PublishedApi internal val moduleObservers = mutableMapOf, ModuleObserver>() + @PublishedApi + internal val keyScopes = mutableMapOf() + internal val kClassScopes = mutableMapOf, ScopedDIContext>() + + inline fun scoped(): ScopedDIContext = scoped(T::class) + + fun scoped(kClass: KClass<*>): ScopedDIContext { + val simpleName = kClass.simpleName ?: error("Class $kClass has no simple name") + return kClassScopes.getOrPut(kClass) { + ScopedDIContext(simpleName = simpleName, byClass = kClass) + } + + } + + fun scoped(key: String, simpleName: String = key): ScopedDIContext { + return keyScopes.getOrPut(key) { ScopedDIContext(simpleName = simpleName) } + } + /** * Gets an observer for a module of type [T]. * @@ -62,6 +80,7 @@ open class DIContext { fun clear() { moduleObservers.forEach { it.value.module = null } + (keyScopes + kClassScopes).forEach { it.value.clear() } } @Suppress("UNCHECKED_CAST") // Logic ensures safety diff --git a/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DefaultingModuleObserver.kt b/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DefaultingModuleObserver.kt new file mode 100644 index 00000000..c0de4696 --- /dev/null +++ b/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/DefaultingModuleObserver.kt @@ -0,0 +1,21 @@ +package com.mineinabyss.idofront.di + +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +class DefaultingModuleObserver( + val observer: ModuleObserver, + val defaultProvider: () -> T, +) : ReadOnlyProperty { + val default by lazy { defaultProvider() } + + fun get(): T = observer.getOrNull() ?: default + + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + return get() + } +} + +fun ModuleObserver.default(provider: () -> T): DefaultingModuleObserver { + return DefaultingModuleObserver(this, provider) +} diff --git a/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/ScopedDIContext.kt b/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/ScopedDIContext.kt new file mode 100644 index 00000000..af32a664 --- /dev/null +++ b/idofront-di/src/commonMain/kotlin/com/mineinabyss/idofront/di/ScopedDIContext.kt @@ -0,0 +1,8 @@ +package com.mineinabyss.idofront.di + +import kotlin.reflect.KClass + +class ScopedDIContext( + val simpleName: String, + val byClass: KClass<*>? = null, +) : DIContext() diff --git a/idofront-features/src/main/kotlin/com/mineinabyss/idofront/features/FeatureManager.kt b/idofront-features/src/main/kotlin/com/mineinabyss/idofront/features/FeatureManager.kt index ffcd7ac2..fd9e1964 100644 --- a/idofront-features/src/main/kotlin/com/mineinabyss/idofront/features/FeatureManager.kt +++ b/idofront-features/src/main/kotlin/com/mineinabyss/idofront/features/FeatureManager.kt @@ -2,10 +2,7 @@ package com.mineinabyss.idofront.features import com.mineinabyss.idofront.commands.arguments.optionArg import com.mineinabyss.idofront.commands.execution.IdofrontCommandExecutor -import com.mineinabyss.idofront.messaging.error -import com.mineinabyss.idofront.messaging.logError -import com.mineinabyss.idofront.messaging.logSuccess -import com.mineinabyss.idofront.messaging.success +import com.mineinabyss.idofront.messaging.* import com.mineinabyss.idofront.plugin.Plugins import com.mineinabyss.idofront.plugin.actions import org.bukkit.command.CommandSender @@ -14,6 +11,8 @@ import org.bukkit.command.TabCompleter abstract class FeatureManager( createContext: () -> T, ) : FeatureWithContext(createContext) { + val logger: ComponentLogger get() = context.plugin.injectedLogger() + val commandExecutor: IdofrontCommandExecutor by lazy { object : IdofrontCommandExecutor(), TabCompleter { override val commands = commands(context.plugin) { @@ -54,7 +53,7 @@ abstract class FeatureManager( val featuresWithMetDeps = context.features.filter { feature -> feature.dependsOn.all { Plugins.isEnabled(it) } } (context.features - featuresWithMetDeps.toSet()).forEach { feature -> val featureName = feature::class.simpleName - logError("Could not enable $featureName, missing dependencies: ${feature.dependsOn.filterNot(Plugins::isEnabled)}") + logger.iFail("Could not enable $featureName, missing dependencies: ${feature.dependsOn.filterNot(Plugins::isEnabled)}") } "Registering feature contexts" { featuresWithMetDeps @@ -62,7 +61,7 @@ abstract class FeatureManager( .forEach { runCatching { it.createAndInjectContext() - }.onFailure { e -> logError("Failed to create context for ${it::class.simpleName}: $e") } + }.onFailure { error -> logger.iFail("Failed to create context for ${it::class.simpleName}: $error") } } } @@ -110,8 +109,8 @@ abstract class FeatureManager( "Disabling features" { context.features.forEach { feature -> runCatching { feature.disable(context) } - .onSuccess { logSuccess("Disabled ${feature::class.simpleName}") } - .onFailure { e -> logError("Failed to disable ${feature::class.simpleName}: $e") } + .onSuccess { logger.iSuccess("Disabled ${feature::class.simpleName}") } + .onFailure { e -> logger.iFail("Failed to disable ${feature::class.simpleName}: $e") } } } removeContext() diff --git a/idofront-logging/build.gradle.kts b/idofront-logging/build.gradle.kts index 8e45b816..815837f7 100644 --- a/idofront-logging/build.gradle.kts +++ b/idofront-logging/build.gradle.kts @@ -6,4 +6,6 @@ plugins { dependencies { implementation(project(":idofront-text-components")) + implementation(project(":idofront-di")) + api(libs.kermit) } diff --git a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/ComponentLogger.kt b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/ComponentLogger.kt new file mode 100644 index 00000000..f1759304 --- /dev/null +++ b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/ComponentLogger.kt @@ -0,0 +1,91 @@ +package com.mineinabyss.idofront.messaging + +import co.touchlab.kermit.Logger +import co.touchlab.kermit.Severity +import co.touchlab.kermit.StaticConfig +import com.mineinabyss.idofront.messaging.IdoLogging.errorComp +import com.mineinabyss.idofront.messaging.IdoLogging.successComp +import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.idofront.textcomponents.toPlainText +import net.kyori.adventure.text.ComponentLike +import org.bukkit.plugin.Plugin + +open class ComponentLogger( + staticConfig: StaticConfig, + tag: String, +) : Logger(staticConfig, tag) { + + fun i(message: ComponentLike) { + if (config.minSeverity <= Severity.Info) + logComponent(Severity.Info, message) + } + + fun iMM(message: String) { + i(message.miniMsg()) + } + + fun iSuccess(message: String) { + i(successComp.append(message.miniMsg())) + } + + fun iSuccess(message: ComponentLike) { + i(successComp.append(message)) + } + + fun iFail(message: String) { + i(errorComp.append(message.miniMsg())) + } + + fun iFail(message: ComponentLike) { + i(errorComp.append(message)) + } + + fun v(message: ComponentLike) { + if (config.minSeverity <= Severity.Verbose) + logComponent(Severity.Verbose, message) + } + + fun d(message: ComponentLike) { + if (config.minSeverity <= Severity.Debug) + logComponent(Severity.Debug, message) + } + + fun w(message: ComponentLike) { + if (config.minSeverity <= Severity.Warn) + logComponent(Severity.Warn, message) + } + + fun e(message: ComponentLike) { + if (config.minSeverity <= Severity.Error) + logComponent(Severity.Error, message) + } + + fun a(message: ComponentLike) { + if (config.minSeverity <= Severity.Assert) + logComponent(Severity.Assert, message) + } + + fun logComponent(severity: Severity, message: ComponentLike) { + config.logWriterList.forEach { + if (!it.isLoggable(severity)) return@forEach + if (it is KermitPaperWriter) it.log(severity, message) + else it.log(severity, message.asComponent().toPlainText(), tag, null) + } + } + + companion object { + fun forPlugin(plugin: Plugin, minSeverity: Severity = Severity.Info): ComponentLogger { + return ComponentLogger( + StaticConfig(minSeverity = minSeverity, logWriterList = listOf(KermitPaperWriter(plugin))), + plugin.name + ) + } + + fun fallback( + minSeverity: Severity = Severity.Info, + tag: String = "Idofront" + ): ComponentLogger { + return ComponentLogger(StaticConfig(minSeverity = minSeverity), tag) + } + } +} diff --git a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdoLogging.kt b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdoLogging.kt new file mode 100644 index 00000000..b20e5ec3 --- /dev/null +++ b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdoLogging.kt @@ -0,0 +1,106 @@ +package com.mineinabyss.idofront.messaging + +import com.mineinabyss.idofront.messaging.IdoLogging.ERROR_PREFIX +import com.mineinabyss.idofront.messaging.IdoLogging.SUCCESS_PREFIX +import com.mineinabyss.idofront.messaging.IdoLogging.WARN_PREFIX +import com.mineinabyss.idofront.messaging.IdoLogging.logWithFallback +import com.mineinabyss.idofront.textcomponents.miniMsg +import com.mineinabyss.idofront.textcomponents.toPlainText +import net.kyori.adventure.text.Component +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.command.ConsoleCommandSender + +object IdoLogging { + const val ERROR_PREFIX = "\u274C" + const val SUCCESS_PREFIX = "\u2714" + const val WARN_PREFIX = "\u26A0" + + val successComp = SUCCESS_PREFIX.miniMsg() + val errorComp = ERROR_PREFIX.miniMsg() + val warnComp = WARN_PREFIX.miniMsg() + + @PublishedApi + internal val BUKKIT_LOADED = runCatching { + Bukkit.getConsoleSender() + }.isSuccess + + @PublishedApi + internal val ADVENTURE_LOADED = runCatching { + "Test".miniMsg() + }.isSuccess + + inline fun logWithFallback(message: Any?, printBukkit: (Component) -> Unit) { + if (ADVENTURE_LOADED) { + val messageComponent = message as? Component ?: message.toString().miniMsg() + if (BUKKIT_LOADED) printBukkit(messageComponent) + else println(messageComponent.toPlainText()) + } else { + println(message) + } + } +} + +@Deprecated("Use Plugin.logger().i(...)") +fun logInfo(message: Any?) = + logWithFallback(message) { Bukkit.getConsoleSender().sendMessage(it) } + +@Deprecated("Use Plugin.logger().i(...)") +fun logSuccess(message: Any?) = + logWithFallback("$message") { Bukkit.getConsoleSender().sendMessage(it) } + +@Deprecated("Use Plugin.logger().e(...)") +fun logError(message: Any?) = + logWithFallback(message) { Bukkit.getLogger().severe(it.toPlainText()) } + +@Deprecated("Use Plugin.logger().w(...)") +fun logWarn(message: Any?) = + logWithFallback(message) { Bukkit.getLogger().warning(it.toPlainText()) } + +/** Broadcasts a message to the entire server. */ +fun broadcast(message: Any?) = logWithFallback(message) { Bukkit.getServer().broadcast(it) } + +fun CommandSender.info(message: Any?) = logWithFallback(message, printBukkit = ::sendMessage) + +fun CommandSender.error(message: Any?) { + if (this is ConsoleCommandSender) + logWithFallback(message) { Bukkit.getLogger().severe(it.toPlainText()) } + else info("$ERROR_PREFIX $message") +} + +fun CommandSender.success(message: Any?) { + if (this is ConsoleCommandSender) + logWithFallback("$message") { Bukkit.getConsoleSender().sendMessage(it) } + else info("$SUCCESS_PREFIX $message") +} + +fun CommandSender.warn(message: Any?) { + if (this is ConsoleCommandSender) + logWithFallback(message) { Bukkit.getLogger().warning(it.toPlainText()) } + else info("$WARN_PREFIX $message") +} + +/** + * (Kotlin) Logs a value with an optional string in front of it e.x. + * + * ``` + * val length: Int = "A String".logVal("Name").length.logVal("Its length") + * ``` + * Will print: + * ``` + * Name: A String + * Its length: 8 + * ``` + * + * @param message A string to be placed in front of this value. + * @return Itself. + */ +fun T.logVal(message: String = ""): T = logWithFallback( + "${if (message == "") "" else "$message: "}$this", + printBukkit = Bukkit.getConsoleSender()::sendMessage +).let { this } + +/** + * Same as [logVal] but uses [broadcast] instead + */ +fun T.broadcastVal(message: String = ""): T = broadcast("$message$this").let { this } diff --git a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdofrontLogger.kt b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdofrontLogger.kt new file mode 100644 index 00000000..91b25ec0 --- /dev/null +++ b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/IdofrontLogger.kt @@ -0,0 +1,5 @@ +package com.mineinabyss.idofront.messaging + +import com.mineinabyss.idofront.di.DI + +val idofrontLogger by DI.scoped("Idofront").observeLogger() diff --git a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/KermitPaperWriter.kt b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/KermitPaperWriter.kt new file mode 100644 index 00000000..02f839e6 --- /dev/null +++ b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/KermitPaperWriter.kt @@ -0,0 +1,36 @@ +package com.mineinabyss.idofront.messaging + +import co.touchlab.kermit.LogWriter +import co.touchlab.kermit.Severity +import com.mineinabyss.idofront.textcomponents.toPlainText +import net.kyori.adventure.text.ComponentLike +import org.bukkit.Bukkit +import org.bukkit.plugin.Plugin +import java.util.logging.Level + +class KermitPaperWriter(private val plugin: Plugin) : LogWriter() { + override fun log(severity: Severity, message: String, tag: String, throwable: Throwable?) { + plugin.logger.log(severityToLogLevel(severity), message) + throwable?.printStackTrace() + } + + fun log(severity: Severity, message: ComponentLike) { + if (severity >= Severity.Warn) + log(severity, message.asComponent().toPlainText(), "", null) + else + Bukkit.getConsoleSender().sendMessage(message) + } + + companion object { + // Spigot passes the java log level into log4j that's harder to configure, we'll just stick to info level + // and filter on our end + fun severityToLogLevel(severity: Severity): Level = when (severity) { + Severity.Verbose -> Level.INFO + Severity.Debug -> Level.INFO + Severity.Info -> Level.INFO + Severity.Warn -> Level.WARNING + Severity.Error -> Level.SEVERE + Severity.Assert -> Level.SEVERE + } + } +} diff --git a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/Logging.kt b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/Logging.kt deleted file mode 100644 index f5cb5964..00000000 --- a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/Logging.kt +++ /dev/null @@ -1,104 +0,0 @@ -package com.mineinabyss.idofront.messaging - -import com.mineinabyss.idofront.textcomponents.miniMsg -import com.mineinabyss.idofront.textcomponents.toPlainText -import net.kyori.adventure.text.Component -import org.bukkit.Bukkit -import org.bukkit.command.CommandSender -import org.bukkit.command.ConsoleCommandSender -import org.bukkit.plugin.java.PluginClassLoader - -@PublishedApi -internal object Logging { - // Get plugin via classloader - val pluginPrefix by lazy { - (Logging::class.java.classLoader as? PluginClassLoader)?.plugin?.name?.let { "[$it] ".miniMsg() } - ?: Component.empty() - } -} - -private const val ERROR_PREFIX = "\u274C" -private const val SUCCESS_PREFIX = "\u2714" -private const val WARN_PREFIX = "\u26A0" - -@PublishedApi -internal val BUKKIT_LOADED = runCatching { - Bukkit.getConsoleSender() -}.isSuccess - -@PublishedApi -internal val ADVENTURE_LOADED = runCatching { - "Test".miniMsg() -}.isSuccess - -//private val BUKKIT_OR_DEFAULT_LOGGER: (Any?) -> Unit = { -// if (BUKKIT_LOADED) Bukkit.getConsoleSender().sendMessage(it) -//} - -/** Broadcasts a message to the entire server. */ -fun broadcast(message: Any?) = logTo(message) { Bukkit.getServer().broadcast(it) } - -inline fun logTo(message: Any?, addPrefix: Boolean = true, printBukkit: (Component) -> Unit) { - if (ADVENTURE_LOADED) { - val messageComponent = message as? Component ?: message.toString().miniMsg() - val fullMessage = if (addPrefix && BUKKIT_LOADED) - Logging.pluginPrefix.append(messageComponent) - else messageComponent - - if (BUKKIT_LOADED) printBukkit(fullMessage) - else println(fullMessage.toPlainText()) - } else { - println(message) - } -} - -fun logInfo(message: Any?) = - logTo(message) { Bukkit.getConsoleSender().sendMessage(it) } - -fun logSuccess(message: Any?) = - logTo("$message") { Bukkit.getConsoleSender().sendMessage(it) } - -fun logError(message: Any?) = - logTo(message) { Bukkit.getLogger().severe(it.toPlainText()) } - -fun logWarn(message: Any?) = - logTo(message) { Bukkit.getLogger().warning(it.toPlainText()) } - -fun CommandSender.info(message: Any?) = logTo(message, addPrefix = false, printBukkit = ::sendMessage) - -fun CommandSender.error(message: Any?) { - if (this is ConsoleCommandSender) logError(message) - else info("$ERROR_PREFIX $message") -} - -fun CommandSender.success(message: Any?) { - if (this is ConsoleCommandSender) logSuccess(message) - else info("$SUCCESS_PREFIX $message") -} - -fun CommandSender.warn(message: Any?) { - if (this is ConsoleCommandSender) logWarn(message) - else info("$WARN_PREFIX $message") -} - -/** - * (Kotlin) Logs a value with an optional string in front of it e.x. - * - * ``` - * val length: Int = "A String".logVal("Name").length.logVal("Its length") - * ``` - * Will print: - * ``` - * Name: A String - * Its length: 8 - * ``` - * - * @param message A string to be placed in front of this value. - * @return Itself. - */ -fun T.logVal(message: String = ""): T = logInfo("${if (message == "") "" else "$message: "}$this").let { this } - -/** - * Same as [logVal] but uses [broadcast] instead - */ -fun T.broadcastVal(message: String = ""): T = broadcast("$message$this").let { this } diff --git a/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/LoggingDI.kt b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/LoggingDI.kt new file mode 100644 index 00000000..b54e34c7 --- /dev/null +++ b/idofront-logging/src/main/kotlin/com/mineinabyss/idofront/messaging/LoggingDI.kt @@ -0,0 +1,22 @@ +package com.mineinabyss.idofront.messaging + +import com.mineinabyss.idofront.di.* +import org.bukkit.Bukkit +import org.bukkit.plugin.Plugin + +fun DIContext.observeLogger() = observe() + .default { + if (this is ScopedDIContext) { + if (byClass != null && IdoLogging.BUKKIT_LOADED) { + val matchedPlugin = Bukkit.getPluginManager().plugins.find { it::class == byClass } + if (matchedPlugin != null) return@default ComponentLogger.forPlugin(matchedPlugin) + } + return@default ComponentLogger.fallback(tag = simpleName) + } + ComponentLogger.fallback() + } + +fun Plugin.injectedLogger(): ComponentLogger = observeLogger().get() +fun Plugin.observeLogger(): DefaultingModuleObserver = DI.scoped(this::class).observeLogger() +fun Plugin.injectLogger(logger: ComponentLogger): Unit = DI.scoped(this::class) + .add(logger) diff --git a/idofront-plugin-loader/build.gradle.kts b/idofront-plugin-loader/build.gradle.kts deleted file mode 100644 index 3f33f5db..00000000 --- a/idofront-plugin-loader/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - id("com.mineinabyss.conventions.kotlin.jvm") - id("com.mineinabyss.conventions.papermc") -} - -dependencies { -} diff --git a/idofront-plugin-loader/src/main/java/com/mineinabyss/idofront/loading/IdofrontPluginLoader.java b/idofront-plugin-loader/src/main/java/com/mineinabyss/idofront/loading/IdofrontPluginLoader.java deleted file mode 100644 index ca6b6be2..00000000 --- a/idofront-plugin-loader/src/main/java/com/mineinabyss/idofront/loading/IdofrontPluginLoader.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.mineinabyss.idofront.loading; - -import io.papermc.paper.plugin.loader.PluginClasspathBuilder; -import io.papermc.paper.plugin.loader.PluginLoader; -import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.repository.RemoteRepository; -import org.jetbrains.annotations.NotNull; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; - -public class IdofrontPluginLoader implements PluginLoader { - @Override - public void classloader(@NotNull PluginClasspathBuilder classpathBuilder) { - var logger = classpathBuilder.getContext().getLogger(); - var plugin = classpathBuilder.getContext().getConfiguration().getName(); - logger.info("Loading idofront dependencies"); - InputStream resource; - - try (var stream = Files.find(classpathBuilder.getContext().getDataDirectory().getParent(), 1, (path, attr) -> - path.getFileName().toString().startsWith("idofront"))) { - var first = stream.findFirst(); - if (first.isEmpty()) { - logger.error("This plugin requires idofront to be installed. Please install it from https://github.com/MineInAbyss/Idofront/releases/"); - return; - } - resource = new URLClassLoader(new URL[]{first.get().toUri().toURL()}) - .getResourceAsStream("maven-deps.txt"); - } catch (IOException e) { - throw new RuntimeException(e); - } - - if (resource == null) { - logger.error("Could not find maven-deps.txt in idofront jar, not including them in classpath"); - return; - } - var resolver = new MavenLibraryResolver(); - try (var reader = new BufferedReader(new InputStreamReader(resource)).lines()) { - reader.forEach(line -> resolver.addDependency(new Dependency(new DefaultArtifact(line), null))); - } - - resolver.addRepository(new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2").build()); - - classpathBuilder.addLibrary(resolver); - } -} diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/ColorSerializer.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/ColorSerializer.kt index 8d27c882..241db789 100644 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/ColorSerializer.kt +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/ColorSerializer.kt @@ -36,6 +36,7 @@ private value class ColorSurrogate(val color: String) { object ColorSerializer : KSerializer { override val descriptor: SerialDescriptor = ColorSurrogate.serializer().descriptor + @OptIn(ExperimentalStdlibApi::class) override fun serialize(encoder: Encoder, value: Color) { val hex = value.asARGB().toHexString(ColorHelpers.hexFormat) val hexColor = if (value.alpha == 255 && hex.length > 7) hex.substring(2) else hex diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt index 7dd779ef..ba07a546 100644 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt @@ -4,6 +4,7 @@ package com.mineinabyss.idofront.serialization import com.google.common.collect.HashMultimap import com.mineinabyss.idofront.di.DI +import com.mineinabyss.idofront.messaging.idofrontLogger import com.mineinabyss.idofront.messaging.logWarn import com.mineinabyss.idofront.plugin.Plugins import dev.lone.itemsadder.api.CustomStack @@ -77,9 +78,9 @@ data class BaseSerializableItemStack( MythicCrucible.core().itemManager.getItemStack(id)?.let { applyTo.type = it.type applyTo.itemMeta = it.itemMeta - } ?: logWarn("No Crucible item found with id $id") + } ?: idofrontLogger.w("No Crucible item found with id $id") } else { - logWarn("Tried to import Crucible item, but MythicCrucible was not enabled") + idofrontLogger.w("Tried to import Crucible item, but MythicCrucible was not enabled") } } @@ -89,9 +90,9 @@ data class BaseSerializableItemStack( OraxenItems.getItemById(id)?.build()?.let { applyTo.type = it.type applyTo.itemMeta = it.itemMeta - } ?: logWarn("No Oraxen item found with id $id") + } ?: idofrontLogger.w("No Oraxen item found with id $id") } else { - logWarn("Tried to import Oraxen item, but Oraxen was not enabled") + idofrontLogger.w("Tried to import Oraxen item, but Oraxen was not enabled") } } @@ -101,9 +102,9 @@ data class BaseSerializableItemStack( CustomStack.getInstance(id)?.itemStack?.let { applyTo.type = it.type applyTo.itemMeta = it.itemMeta - } ?: logWarn("No ItemsAdder item found with id $id") + } ?: idofrontLogger.w("No ItemsAdder item found with id $id") } else { - logWarn("Tried to import ItemsAdder item, but ItemsAdder was not enabled") + idofrontLogger.w("Tried to import ItemsAdder item, but ItemsAdder was not enabled") } } diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStackSerializer.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStackSerializer.kt index 71fad796..a4ca287e 100644 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStackSerializer.kt +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStackSerializer.kt @@ -14,7 +14,6 @@ import org.bukkit.Material class SerializableItemStackSerializer : KSerializer { // override val descriptor: SerialDescriptor = BaseSerializableItemStack.serializer().descriptor - @OptIn(InternalSerializationApi::class) override val descriptor: SerialDescriptor = ContextualSerializer(BaseSerializableItemStack::class).descriptor @@ -33,24 +32,22 @@ class SerializableItemStackSerializer : KSerializer { } - fun decodeFromShorthand(stringShorthand: String): BaseSerializableItemStack { - return when { - stringShorthand.startsWith("minecraft:") -> return BaseSerializableItemStack( - type = Material.matchMaterial( - stringShorthand - ) + fun decodeFromShorthand(stringShorthand: String) = when { + stringShorthand.startsWith("minecraft:") -> BaseSerializableItemStack( + type = Material.matchMaterial( + stringShorthand ) + ) - stringShorthand.startsWith("crucible ") -> return BaseSerializableItemStack( - crucibleItem = stringShorthand.removePrefix("crucible ") - ) + stringShorthand.startsWith("crucible ") -> BaseSerializableItemStack( + crucibleItem = stringShorthand.removePrefix("crucible ") + ) - stringShorthand.startsWith("oraxen ") -> return BaseSerializableItemStack( - oraxenItem = stringShorthand.removePrefix("oraxen ") - ) + stringShorthand.startsWith("oraxen ") -> BaseSerializableItemStack( + oraxenItem = stringShorthand.removePrefix("oraxen ") + ) - else -> return BaseSerializableItemStack(prefab = stringShorthand) - } + else -> BaseSerializableItemStack(prefab = stringShorthand) } override fun serialize(encoder: Encoder, value: SerializableItemStack) { diff --git a/idofront-util/build.gradle.kts b/idofront-util/build.gradle.kts index ac777c5a..7ce63225 100644 --- a/idofront-util/build.gradle.kts +++ b/idofront-util/build.gradle.kts @@ -9,4 +9,5 @@ plugins { dependencies { compileOnly(libs.kotlinx.serialization.json) implementation(project(":idofront-logging")) + implementation(project(":idofront-di")) }