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
This commit is contained in:
parent
a26c16565f
commit
58729ab885
8 changed files with 61 additions and 50 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -121,10 +121,11 @@ abstract class Component<TP : JavaPlugin> {
|
|||
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<TP : JavaPlugin> {
|
|||
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)
|
||||
|
|
|
@ -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<T : Any?> internal constructor(
|
||||
val config: IHaveConfig?,
|
||||
var config: IHaveConfig?,
|
||||
override val path: String,
|
||||
private val primitiveDef: Any,
|
||||
private val getter: Function<Any, T>,
|
||||
|
@ -52,6 +52,10 @@ class ConfigData<T : Any?> 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<T : Any?> 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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<String, IConfigData<*>>()
|
||||
|
||||
|
@ -88,7 +89,7 @@ class IHaveConfig(
|
|||
elementGetter: Function<Any?, T>? = null,
|
||||
elementSetter: Function<T, Any?>? = null,
|
||||
readOnly: Boolean = false
|
||||
): ConfigDataDelegate<ListConfigData<T>.List> {
|
||||
): ListConfigDataDelegate<T> {
|
||||
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.
|
||||
|
|
|
@ -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<T> internal constructor(
|
|||
private val elementGetter: Function<Any?, T>,
|
||||
private val elementSetter: Function<T, Any?>,
|
||||
readOnly: Boolean
|
||||
) : IConfigData<ListConfigData<T>.List> {
|
||||
) : IConfigData<ListConfigData<T>.List>, IListConfigData<T> {
|
||||
val listConfig: ConfigData<List> =
|
||||
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<Any?>) : MutableList<T> {
|
||||
private val primitiveList = backingList
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package buttondevteam.lib.architecture.config
|
||||
|
||||
import buttondevteam.lib.architecture.ListConfigData
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class ConfigDataDelegate<T>(val data: IConfigData<T>) : IConfigData<T> by data {
|
||||
open class ConfigDataDelegate<T>(private val data: IConfigData<T>) : IConfigData<T> 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 <T> IConfigData<T>.delegate() = ConfigDataDelegate(this)
|
||||
}
|
||||
}
|
||||
|
||||
class ListConfigDataDelegate<T>(data: IConfigData<ListConfigData<T>.List>) : ConfigDataDelegate<ListConfigData<T>.List>(data), IListConfigData<T>
|
||||
|
||||
fun <T> IConfigData<T>.delegate() = ConfigDataDelegate(this)
|
||||
fun <T> IListConfigData<T>.delegate() = ListConfigDataDelegate(this)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package buttondevteam.lib.architecture.config
|
||||
|
||||
import buttondevteam.lib.architecture.ListConfigData
|
||||
|
||||
interface IConfigData<T> {
|
||||
/**
|
||||
* 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<T> {
|
|||
*/
|
||||
fun set(value: T)
|
||||
|
||||
/**
|
||||
* Reload the config from the file.
|
||||
*/
|
||||
fun reload()
|
||||
|
||||
/**
|
||||
* The path to the config value.
|
||||
*/
|
||||
val path: String
|
||||
}
|
||||
}
|
||||
|
||||
interface IListConfigData<T> : IConfigData<ListConfigData<T>.List>
|
||||
|
|
Loading…
Reference in a new issue