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."])
|
@Subcommand(helpText = ["Enable component", "Temporarily or permanently enables a component."])
|
||||||
fun enable(sender: CommandSender, plugin: Plugin, component: String, @OptionalArg permanent: Boolean): Boolean {
|
fun enable(sender: CommandSender, plugin: Plugin, component: String, @OptionalArg permanent: Boolean): Boolean {
|
||||||
if (plugin is ButtonPlugin) {
|
if (plugin is ButtonPlugin) {
|
||||||
if (!plugin.justReload()) {
|
if (!plugin.tryReloadConfig()) {
|
||||||
sender.sendMessage("${ChatColor.RED}Couldn't reload config, check console.")
|
sender.sendMessage("${ChatColor.RED}Couldn't reload config, check console.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,14 @@ import java.util.function.Consumer
|
||||||
|
|
||||||
@HasConfig(global = true)
|
@HasConfig(global = true)
|
||||||
abstract class ButtonPlugin : JavaPlugin() {
|
abstract class ButtonPlugin : JavaPlugin() {
|
||||||
protected var iConfig = getIConfigInstance()
|
protected val iConfig = IHaveConfig(::saveConfig, section)
|
||||||
private set
|
|
||||||
private var yaml: YamlConfiguration? = null
|
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
|
protected val data //TODO
|
||||||
: IHaveConfig? = null
|
: IHaveConfig? = null
|
||||||
|
|
||||||
|
@ -39,7 +43,7 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
*/
|
*/
|
||||||
protected open fun pluginPreDisable() {}
|
protected open fun pluginPreDisable() {}
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
if (!reloadIConfig()) {
|
if (!tryReloadConfig()) {
|
||||||
logger.warning("Please fix the issues and restart the server to load the plugin.")
|
logger.warning("Please fix the issues and restart the server to load the plugin.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -52,18 +56,6 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
IHaveConfig.pregenConfig(this, null)
|
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() {
|
override fun onDisable() {
|
||||||
try {
|
try {
|
||||||
pluginPreDisable()
|
pluginPreDisable()
|
||||||
|
@ -81,14 +73,17 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryReloadConfig(): Boolean {
|
fun tryReloadConfig(): Boolean {
|
||||||
if (!justReload()) return false
|
if (!saveAndReloadYaml()) return false
|
||||||
reloadIConfig()
|
iConfig.reload(section)
|
||||||
componentStack.forEach(Consumer { c -> c.updateConfig() })
|
componentStack.forEach(Consumer { c -> c.updateConfig() })
|
||||||
return true
|
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.")
|
logger.warning("Saved pending configuration changes to the file, didn't reload. Apply your changes again.")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -106,10 +101,8 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
this.yaml = yaml
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
this.yaml = yaml
|
||||||
val res = getTextResource("configHelp.yml") ?: return true
|
val res = getTextResource("configHelp.yml") ?: return true
|
||||||
val yc = YamlConfiguration.loadConfiguration(res)
|
val yc = YamlConfiguration.loadConfiguration(res)
|
||||||
for ((key, value) in yc.getValues(true))
|
for ((key, value) in yc.getValues(true))
|
||||||
|
@ -121,7 +114,7 @@ abstract class ButtonPlugin : JavaPlugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getConfig(): FileConfiguration {
|
override fun getConfig(): FileConfiguration {
|
||||||
if (yaml == null) justReload()
|
if (!isConfigLoaded) saveAndReloadYaml()
|
||||||
return yaml ?: YamlConfiguration() //Return a temporary instance
|
return yaml ?: YamlConfiguration() //Return a temporary instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,10 +121,11 @@ abstract class Component<TP : JavaPlugin> {
|
||||||
private val className: String get() = javaClass.simpleName
|
private val className: String get() = javaClass.simpleName
|
||||||
|
|
||||||
internal fun updateConfig() {
|
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")
|
var compconf = plugin.config.getConfigurationSection("components")
|
||||||
if (compconf == null) compconf = plugin.config.createSection("components")
|
if (compconf == null) compconf = plugin.config.createSection("components")
|
||||||
var configSect = compconf.getConfigurationSection(className)
|
var configSect = compconf.getConfigurationSection(className)
|
||||||
|
@ -261,7 +262,7 @@ abstract class Component<TP : JavaPlugin> {
|
||||||
if (component.isEnabled == enabled) return //Don't do anything
|
if (component.isEnabled == enabled) return //Don't do anything
|
||||||
if (enabled.also { component.isEnabled = it }) {
|
if (enabled.also { component.isEnabled = it }) {
|
||||||
try {
|
try {
|
||||||
component.getConfigSection(component.plugin)
|
component.updateConfig()
|
||||||
component.enable()
|
component.enable()
|
||||||
if (ButtonPlugin.configGenAllowed(component)) {
|
if (ButtonPlugin.configGenAllowed(component)) {
|
||||||
IHaveConfig.pregenConfig(component, null)
|
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
|
* @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(
|
class ConfigData<T : Any?> internal constructor(
|
||||||
val config: IHaveConfig?,
|
var config: IHaveConfig?,
|
||||||
override val path: String,
|
override val path: String,
|
||||||
private val primitiveDef: Any,
|
private val primitiveDef: Any,
|
||||||
private val getter: Function<Any, T>,
|
private val getter: Function<Any, T>,
|
||||||
|
@ -52,6 +52,10 @@ class ConfigData<T : Any?> internal constructor(
|
||||||
return getter.apply(convertPrimitiveType(freshValue)).also { value = it }
|
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].
|
* 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?) {
|
private fun setInternal(`val`: Any?) {
|
||||||
if (config == null) return
|
val conf = config ?: return
|
||||||
config.config.set(path, `val`)
|
conf.config.set(path, `val`)
|
||||||
signalChange(config)
|
signalChange(conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package buttondevteam.lib.architecture
|
package buttondevteam.lib.architecture
|
||||||
|
|
||||||
import buttondevteam.lib.architecture.config.ConfigDataDelegate
|
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.IConfigData
|
||||||
|
import buttondevteam.lib.architecture.config.ListConfigDataDelegate
|
||||||
|
import buttondevteam.lib.architecture.config.delegate
|
||||||
import org.bukkit.configuration.ConfigurationSection
|
import org.bukkit.configuration.ConfigurationSection
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ class IHaveConfig(
|
||||||
/**
|
/**
|
||||||
* Returns the Bukkit ConfigurationSection. Use [.signalChange] after changing it.
|
* Returns the Bukkit ConfigurationSection. Use [.signalChange] after changing it.
|
||||||
*/
|
*/
|
||||||
val config: ConfigurationSection
|
var config: ConfigurationSection
|
||||||
) {
|
) {
|
||||||
private val datamap = HashMap<String, IConfigData<*>>()
|
private val datamap = HashMap<String, IConfigData<*>>()
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ class IHaveConfig(
|
||||||
elementGetter: Function<Any?, T>? = null,
|
elementGetter: Function<Any?, T>? = null,
|
||||||
elementSetter: Function<T, Any?>? = null,
|
elementSetter: Function<T, Any?>? = null,
|
||||||
readOnly: Boolean = false
|
readOnly: Boolean = false
|
||||||
): ConfigDataDelegate<ListConfigData<T>.List> {
|
): ListConfigDataDelegate<T> {
|
||||||
var data = datamap[path]
|
var data = datamap[path]
|
||||||
if (data == null) datamap[path] = ListConfigData(
|
if (data == null) datamap[path] = ListConfigData(
|
||||||
this,
|
this,
|
||||||
|
@ -109,6 +110,11 @@ class IHaveConfig(
|
||||||
ConfigData.signalChange(this)
|
ConfigData.signalChange(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun reload(section: ConfigurationSection) {
|
||||||
|
config = section
|
||||||
|
datamap.forEach { it.value.reload() }
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Generates the config YAML.
|
* Generates the config YAML.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package buttondevteam.lib.architecture
|
package buttondevteam.lib.architecture
|
||||||
|
|
||||||
import buttondevteam.lib.architecture.config.IConfigData
|
import buttondevteam.lib.architecture.config.IConfigData
|
||||||
|
import buttondevteam.lib.architecture.config.IListConfigData
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import java.util.function.UnaryOperator
|
import java.util.function.UnaryOperator
|
||||||
|
@ -12,19 +13,14 @@ class ListConfigData<T> internal constructor(
|
||||||
private val elementGetter: Function<Any?, T>,
|
private val elementGetter: Function<Any?, T>,
|
||||||
private val elementSetter: Function<T, Any?>,
|
private val elementSetter: Function<T, Any?>,
|
||||||
readOnly: Boolean
|
readOnly: Boolean
|
||||||
) : IConfigData<ListConfigData<T>.List> {
|
) : IConfigData<ListConfigData<T>.List>, IListConfigData<T> {
|
||||||
val listConfig: ConfigData<List> =
|
val listConfig: ConfigData<List> =
|
||||||
ConfigData(config, path, primitiveDef, { List((it as ArrayList<*>).toMutableList()) }, { it }, readOnly)
|
ConfigData(config, path, primitiveDef, { List((it as ArrayList<*>).toMutableList()) }, { it }, readOnly)
|
||||||
|
|
||||||
override val path: String get() = listConfig.path
|
override val path get() = listConfig.path
|
||||||
|
override fun get() = listConfig.get()
|
||||||
override fun get(): List {
|
override fun set(value: List) = listConfig.set(value)
|
||||||
return listConfig.get()
|
override fun reload() = listConfig.reload()
|
||||||
}
|
|
||||||
|
|
||||||
override fun set(value: List) {
|
|
||||||
listConfig.set(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class List(backingList: MutableList<Any?>) : MutableList<T> {
|
inner class List(backingList: MutableList<Any?>) : MutableList<T> {
|
||||||
private val primitiveList = backingList
|
private val primitiveList = backingList
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package buttondevteam.lib.architecture.config
|
package buttondevteam.lib.architecture.config
|
||||||
|
|
||||||
|
import buttondevteam.lib.architecture.ListConfigData
|
||||||
import kotlin.reflect.KProperty
|
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 getValue(thisRef: Any?, property: KProperty<*>): T = data.get()
|
||||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = data.set(value)
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = data.set(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListConfigDataDelegate<T>(data: IConfigData<ListConfigData<T>.List>) : ConfigDataDelegate<ListConfigData<T>.List>(data), IListConfigData<T>
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun <T> IConfigData<T>.delegate() = ConfigDataDelegate(this)
|
fun <T> IConfigData<T>.delegate() = ConfigDataDelegate(this)
|
||||||
}
|
fun <T> IListConfigData<T>.delegate() = ListConfigDataDelegate(this)
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package buttondevteam.lib.architecture.config
|
package buttondevteam.lib.architecture.config
|
||||||
|
|
||||||
|
import buttondevteam.lib.architecture.ListConfigData
|
||||||
|
|
||||||
interface IConfigData<T> {
|
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.
|
* 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)
|
fun set(value: T)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload the config from the file.
|
||||||
|
*/
|
||||||
|
fun reload()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path to the config value.
|
* The path to the config value.
|
||||||
*/
|
*/
|
||||||
val path: String
|
val path: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IListConfigData<T> : IConfigData<ListConfigData<T>.List>
|
||||||
|
|
Loading…
Reference in a new issue