From 58729ab8852dbab38f5908b5ad84be00ca61b722 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 18 Jun 2023 20:16:12 +0200 Subject: [PATCH] Config delegation & reload improvements - Added a class and an interface to make using list config data easier - Made everything config-related reusable and reloadable because delegated properties don't update automatically when reassigned - This also means that the original ConfigData instance should also properly update now when reloading, although now we return the delegate --- .../buttondevteam/core/ComponentCommand.kt | 2 +- .../lib/architecture/ButtonPlugin.kt | 39 ++++++++----------- .../lib/architecture/Component.kt | 7 ++-- .../lib/architecture/ConfigData.kt | 12 ++++-- .../lib/architecture/IHaveConfig.kt | 12 ++++-- .../lib/architecture/ListConfigData.kt | 16 +++----- .../architecture/config/ConfigDataDelegate.kt | 12 +++--- .../lib/architecture/config/IConfigData.kt | 11 +++++- 8 files changed, 61 insertions(+), 50 deletions(-) diff --git a/Chroma-Core/src/main/java/buttondevteam/core/ComponentCommand.kt b/Chroma-Core/src/main/java/buttondevteam/core/ComponentCommand.kt index eeb3c34..cb313c0 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/ComponentCommand.kt +++ b/Chroma-Core/src/main/java/buttondevteam/core/ComponentCommand.kt @@ -30,7 +30,7 @@ class ComponentCommand : ICommand2MC() { @Subcommand(helpText = ["Enable component", "Temporarily or permanently enables a component."]) fun enable(sender: CommandSender, plugin: Plugin, component: String, @OptionalArg permanent: Boolean): Boolean { if (plugin is ButtonPlugin) { - if (!plugin.justReload()) { + if (!plugin.tryReloadConfig()) { sender.sendMessage("${ChatColor.RED}Couldn't reload config, check console.") return true } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt index 06347a4..5fccf79 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt @@ -16,10 +16,14 @@ import java.util.function.Consumer @HasConfig(global = true) abstract class ButtonPlugin : JavaPlugin() { - protected var iConfig = getIConfigInstance() - private set + protected val iConfig = IHaveConfig(::saveConfig, section) private var yaml: YamlConfiguration? = null + /** + * May change if the config is reloaded + */ + private val section get() = config.getConfigurationSection("global") ?: config.createSection("global") + protected val data //TODO : IHaveConfig? = null @@ -39,7 +43,7 @@ abstract class ButtonPlugin : JavaPlugin() { */ protected open fun pluginPreDisable() {} override fun onEnable() { - if (!reloadIConfig()) { + if (!tryReloadConfig()) { logger.warning("Please fix the issues and restart the server to load the plugin.") return } @@ -52,18 +56,6 @@ abstract class ButtonPlugin : JavaPlugin() { IHaveConfig.pregenConfig(this, null) } - private fun getIConfigInstance(): IHaveConfig { - return IHaveConfig( - ::saveConfig, - this.config.getConfigurationSection("global") ?: this.config.createSection("global") - ) - } - - private fun reloadIConfig(): Boolean { - iConfig = getIConfigInstance() - return isConfigLoaded // If loading fails, getConfig() returns a temporary instance - } - override fun onDisable() { try { pluginPreDisable() @@ -81,14 +73,17 @@ abstract class ButtonPlugin : JavaPlugin() { } fun tryReloadConfig(): Boolean { - if (!justReload()) return false - reloadIConfig() + if (!saveAndReloadYaml()) return false + iConfig.reload(section) componentStack.forEach(Consumer { c -> c.updateConfig() }) return true } - fun justReload(): Boolean { - if (yaml != null && ConfigData.saveNow(config)) { + /** + * Returns whether the config was loaded successfully. Otherwise, an empty config is used. + */ + private fun saveAndReloadYaml(): Boolean { + if (isConfigLoaded && ConfigData.saveNow(config)) { logger.warning("Saved pending configuration changes to the file, didn't reload. Apply your changes again.") return false } @@ -106,10 +101,8 @@ abstract class ButtonPlugin : JavaPlugin() { e.printStackTrace() return false } - this.yaml = yaml - } else { - return false } + this.yaml = yaml val res = getTextResource("configHelp.yml") ?: return true val yc = YamlConfiguration.loadConfiguration(res) for ((key, value) in yc.getValues(true)) @@ -121,7 +114,7 @@ abstract class ButtonPlugin : JavaPlugin() { } override fun getConfig(): FileConfiguration { - if (yaml == null) justReload() + if (!isConfigLoaded) saveAndReloadYaml() return yaml ?: YamlConfiguration() //Return a temporary instance } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt index c103408..bda7290 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt @@ -121,10 +121,11 @@ abstract class Component { private val className: String get() = javaClass.simpleName internal fun updateConfig() { - this.config = IHaveConfig(plugin::saveConfig, getConfigSection(plugin)) + if (!this::config.isInitialized) this.config = IHaveConfig(plugin::saveConfig, getConfigSection()) + else this.config.reload(getConfigSection()) } - private fun getConfigSection(plugin: JavaPlugin): ConfigurationSection { + private fun getConfigSection(): ConfigurationSection { var compconf = plugin.config.getConfigurationSection("components") if (compconf == null) compconf = plugin.config.createSection("components") var configSect = compconf.getConfigurationSection(className) @@ -261,7 +262,7 @@ abstract class Component { if (component.isEnabled == enabled) return //Don't do anything if (enabled.also { component.isEnabled = it }) { try { - component.getConfigSection(component.plugin) + component.updateConfig() component.enable() if (ButtonPlugin.configGenAllowed(component)) { IHaveConfig.pregenConfig(component, null) diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt index a9149d9..a677e79 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt @@ -23,7 +23,7 @@ import java.util.function.Function * @param T The type of the config value. May be nullable if the getter cannot always return a value */ class ConfigData internal constructor( - val config: IHaveConfig?, + var config: IHaveConfig?, override val path: String, private val primitiveDef: Any, private val getter: Function, @@ -52,6 +52,10 @@ class ConfigData internal constructor( return getter.apply(convertPrimitiveType(freshValue)).also { value = it } } + override fun reload() { + value = null + } + /** * Converts a value to [T] from the representation returned by [Configuration.get]. */ @@ -72,9 +76,9 @@ class ConfigData internal constructor( } private fun setInternal(`val`: Any?) { - if (config == null) return - config.config.set(path, `val`) - signalChange(config) + val conf = config ?: return + conf.config.set(path, `val`) + signalChange(conf) } /** diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt index c42185b..0606512 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt @@ -1,8 +1,9 @@ package buttondevteam.lib.architecture import buttondevteam.lib.architecture.config.ConfigDataDelegate -import buttondevteam.lib.architecture.config.ConfigDataDelegate.Companion.delegate import buttondevteam.lib.architecture.config.IConfigData +import buttondevteam.lib.architecture.config.ListConfigDataDelegate +import buttondevteam.lib.architecture.config.delegate import org.bukkit.configuration.ConfigurationSection import java.util.function.Function @@ -18,7 +19,7 @@ class IHaveConfig( /** * Returns the Bukkit ConfigurationSection. Use [.signalChange] after changing it. */ - val config: ConfigurationSection + var config: ConfigurationSection ) { private val datamap = HashMap>() @@ -88,7 +89,7 @@ class IHaveConfig( elementGetter: Function? = null, elementSetter: Function? = null, readOnly: Boolean = false - ): ConfigDataDelegate.List> { + ): ListConfigDataDelegate { var data = datamap[path] if (data == null) datamap[path] = ListConfigData( this, @@ -109,6 +110,11 @@ class IHaveConfig( ConfigData.signalChange(this) } + fun reload(section: ConfigurationSection) { + config = section + datamap.forEach { it.value.reload() } + } + companion object { /** * Generates the config YAML. diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt index d34b45f..15167e2 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt @@ -1,6 +1,7 @@ package buttondevteam.lib.architecture import buttondevteam.lib.architecture.config.IConfigData +import buttondevteam.lib.architecture.config.IListConfigData import java.util.function.Function import java.util.function.Predicate import java.util.function.UnaryOperator @@ -12,19 +13,14 @@ class ListConfigData internal constructor( private val elementGetter: Function, private val elementSetter: Function, readOnly: Boolean -) : IConfigData.List> { +) : IConfigData.List>, IListConfigData { val listConfig: ConfigData = ConfigData(config, path, primitiveDef, { List((it as ArrayList<*>).toMutableList()) }, { it }, readOnly) - override val path: String get() = listConfig.path - - override fun get(): List { - return listConfig.get() - } - - override fun set(value: List) { - listConfig.set(value) - } + override val path get() = listConfig.path + override fun get() = listConfig.get() + override fun set(value: List) = listConfig.set(value) + override fun reload() = listConfig.reload() inner class List(backingList: MutableList) : MutableList { private val primitiveList = backingList diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/ConfigDataDelegate.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/ConfigDataDelegate.kt index 3a866f6..79fc36c 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/ConfigDataDelegate.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/ConfigDataDelegate.kt @@ -1,12 +1,14 @@ package buttondevteam.lib.architecture.config +import buttondevteam.lib.architecture.ListConfigData import kotlin.reflect.KProperty -class ConfigDataDelegate(val data: IConfigData) : IConfigData by data { +open class ConfigDataDelegate(private val data: IConfigData) : IConfigData by data { operator fun getValue(thisRef: Any?, property: KProperty<*>): T = data.get() operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = data.set(value) - - companion object { - fun IConfigData.delegate() = ConfigDataDelegate(this) - } } + +class ListConfigDataDelegate(data: IConfigData.List>) : ConfigDataDelegate.List>(data), IListConfigData + +fun IConfigData.delegate() = ConfigDataDelegate(this) +fun IListConfigData.delegate() = ListConfigDataDelegate(this) diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/IConfigData.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/IConfigData.kt index 8b606f1..9032138 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/IConfigData.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/config/IConfigData.kt @@ -1,5 +1,7 @@ package buttondevteam.lib.architecture.config +import buttondevteam.lib.architecture.ListConfigData + interface IConfigData { /** * Gets the value from the config using the getter specified for the config. If the config is not set, the default value is returned. @@ -11,8 +13,15 @@ interface IConfigData { */ fun set(value: T) + /** + * Reload the config from the file. + */ + fun reload() + /** * The path to the config value. */ val path: String -} \ No newline at end of file +} + +interface IListConfigData : IConfigData.List>