Add support for delegating config properties

- Changed the return value of all getData() methods to allow using the result for property delegation
- This allows using the config properties like any other property in Kotlin
- Also delegating the underlying ConfigData object to the delegate (heh) so that the result can still be used from Java normally
- It does require one notable change though: using the IConfigData interface *everywhere*
- One problematic part for this is ListConfigData, as a much more elaborate IConfigData<ListConfigData<T>.List> needs to be used for list configs
- Also using the display name for MC users heh
This commit is contained in:
Norbi Peti 2023-06-12 22:56:39 +02:00
parent cd108dc787
commit a26c16565f
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
8 changed files with 29 additions and 19 deletions

View file

@ -74,7 +74,7 @@ class ComponentCommand : ICommand2MC() {
val oc = getComponentOrError(plugin, component, sender) val oc = getComponentOrError(plugin, component, sender)
if (!oc.isPresent) return true if (!oc.isPresent) return true
setComponentEnabled(oc.get(), enable) setComponentEnabled(oc.get(), enable)
if (permanent) oc.get().shouldBeEnabled.set(enable) if (permanent) oc.get().shouldBeEnabled = enable
sender.sendMessage("${oc.get().javaClass.simpleName} ${if (enable) "en" else "dis"}abled ${if (permanent) "permanently" else "temporarily"}.") sender.sendMessage("${oc.get().javaClass.simpleName} ${if (enable) "en" else "dis"}abled ${if (permanent) "permanently" else "temporarily"}.")
} catch (e: Exception) { } catch (e: Exception) {
TBMCCoreAPI.SendException( TBMCCoreAPI.SendException(

View file

@ -23,7 +23,7 @@ object ComponentManager {
* Enables components based on a configuration - any component registered afterwards will be also enabled * Enables components based on a configuration - any component registered afterwards will be also enabled
*/ */
fun enableComponents() { fun enableComponents() {
components.values.stream().filter { c: Component<out JavaPlugin> -> c.shouldBeEnabled.get() } components.values.stream().filter { c: Component<out JavaPlugin> -> c.shouldBeEnabled }
.forEach { c -> .forEach { c ->
try { try {
setComponentEnabled(c, true) setComponentEnabled(c, true)

View file

@ -1,9 +1,7 @@
package buttondevteam.core.component.channel package buttondevteam.core.component.channel
import buttondevteam.core.ComponentManager.get import buttondevteam.core.ComponentManager.get
import buttondevteam.lib.architecture.ConfigData
import buttondevteam.lib.architecture.IHaveConfig import buttondevteam.lib.architecture.IHaveConfig
import buttondevteam.lib.architecture.ListConfigData
import buttondevteam.lib.chat.Color import buttondevteam.lib.chat.Color
import buttondevteam.lib.player.ChromaGamerBase import buttondevteam.lib.player.ChromaGamerBase
import org.bukkit.Bukkit import org.bukkit.Bukkit
@ -53,16 +51,16 @@ open class Channel
* Must start with a color code * Must start with a color code
*/ */
@JvmField @JvmField
val displayName: ConfigData<String> = val displayName = component.config.getData("${this.identifier}.displayName", this.defDisplayName)
component.config.getData("${this.identifier}.displayName", this.defDisplayName)
@JvmField @JvmField
val color: ConfigData<Color> = component.config.getData("${this.identifier}.color", val color = component.config.getData(
"${this.identifier}.color",
this.defColor, { c -> Color.valueOf((c as String)) }, Color::toString this.defColor, { c -> Color.valueOf((c as String)) }, Color::toString
) )
@JvmField @JvmField
val extraIdentifiers: ListConfigData<String> = component.config.getListData("${this.identifier}.IDs", listOf()) val extraIdentifiers = component.config.getListData("${this.identifier}.IDs", listOf<String>())
val isGlobal: Boolean val isGlobal: Boolean
get() = filterAndErrorMSG == null get() = filterAndErrorMSG == null

View file

@ -27,8 +27,7 @@ abstract class Component<TP : JavaPlugin> {
private val data //TODO private val data //TODO
: IHaveConfig? = null : IHaveConfig? = null
val shouldBeEnabled: ConfigData<Boolean> var shouldBeEnabled by config.getData("enabled", javaClass.getAnnotation(ComponentMetadata::class.java)?.enabledByDefault ?: true)
get() = config.getData("enabled", javaClass.getAnnotation(ComponentMetadata::class.java)?.enabledByDefault ?: true)
fun log(message: String) { fun log(message: String) {
plugin.logger.info("[$className] $message") plugin.logger.info("[$className] $message")
@ -210,7 +209,7 @@ abstract class Component<TP : JavaPlugin> {
component.updateConfig() component.updateConfig()
_components[component.javaClass] = component _components[component.javaClass] = component
if (plugin is ButtonPlugin) plugin.componentStack.push(component) if (plugin is ButtonPlugin) plugin.componentStack.push(component)
if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled.get()) { if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled) {
return try { //Enable components registered after the previous ones getting enabled return try { //Enable components registered after the previous ones getting enabled
setComponentEnabled(component, true) setComponentEnabled(component, true)
true true

View file

@ -1,5 +1,7 @@
package buttondevteam.lib.architecture 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.IConfigData
import org.bukkit.configuration.ConfigurationSection import org.bukkit.configuration.ConfigurationSection
import java.util.function.Function import java.util.function.Function
@ -41,7 +43,7 @@ class IHaveConfig(
getter: Function<Any, T>? = null, getter: Function<Any, T>? = null,
setter: Function<T, Any>? = null, setter: Function<T, Any>? = null,
readOnly: Boolean = false readOnly: Boolean = false
): ConfigData<T> { ): ConfigDataDelegate<T> {
val safeSetter = setter ?: Function { it ?: throw RuntimeException("No setter specified for nullable config data $path!") } val safeSetter = setter ?: Function { it ?: throw RuntimeException("No setter specified for nullable config data $path!") }
return getData(path, getter ?: Function { it as T }, safeSetter, safeSetter.apply(def), readOnly) return getData(path, getter ?: Function { it as T }, safeSetter, safeSetter.apply(def), readOnly)
} }
@ -65,10 +67,10 @@ class IHaveConfig(
setter: Function<T, Any>, setter: Function<T, Any>,
primitiveDef: Any, primitiveDef: Any,
readOnly: Boolean = false readOnly: Boolean = false
): ConfigData<T> { ): ConfigDataDelegate<T> {
val data = val data =
datamap[path] ?: ConfigData(this, path, primitiveDef, getter, setter, readOnly).also { datamap[path] = it } datamap[path] ?: ConfigData(this, path, primitiveDef, getter, setter, readOnly).also { datamap[path] = it }
return data as ConfigData<T> return (data as ConfigData<T>).delegate()
} }
/** /**
@ -86,7 +88,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
): ListConfigData<T> { ): ConfigDataDelegate<ListConfigData<T>.List> {
var data = datamap[path] var data = datamap[path]
if (data == null) datamap[path] = ListConfigData( if (data == null) datamap[path] = ListConfigData(
this, this,
@ -97,7 +99,7 @@ class IHaveConfig(
readOnly readOnly
).also { data = it } ).also { data = it }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return data as ListConfigData<T> return (data as ListConfigData<T>).delegate()
} }
/** /**

View file

@ -0,0 +1,12 @@
package buttondevteam.lib.architecture.config
import kotlin.reflect.KProperty
class ConfigDataDelegate<T>(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)
}
}

View file

@ -4,7 +4,6 @@ import buttondevteam.core.MainPlugin
import buttondevteam.core.component.channel.Channel import buttondevteam.core.component.channel.Channel
import buttondevteam.core.component.channel.Channel.Companion.getChannels import buttondevteam.core.component.channel.Channel.Companion.getChannels
import buttondevteam.lib.TBMCCoreAPI import buttondevteam.lib.TBMCCoreAPI
import buttondevteam.lib.architecture.ConfigData
import buttondevteam.lib.architecture.ConfigData.Companion.saveNow import buttondevteam.lib.architecture.ConfigData.Companion.saveNow
import buttondevteam.lib.architecture.IHaveConfig import buttondevteam.lib.architecture.IHaveConfig
import buttondevteam.lib.chat.Command2Sender import buttondevteam.lib.chat.Command2Sender
@ -160,7 +159,7 @@ abstract class ChromaGamerBase : Command2Sender {
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
val channel: ConfigData<Channel> val channel
get() = config.getData("channel", Channel.globalChat, get() = config.getData("channel", Channel.globalChat,
{ id -> { id ->
getChannels().filter { it.identifier.equals(id as String, ignoreCase = true) } getChannels().filter { it.identifier.equals(id as String, ignoreCase = true) }

View file

@ -55,7 +55,7 @@ abstract class TBMCPlayerBase : ChromaGamerBase() {
} }
override fun getName(): String { override fun getName(): String {
return playerName.get() return player?.displayName ?: playerName.get()
} }
override fun checkChannelInGroup(group: String?): Channel.RecipientTestResult { override fun checkChannelInGroup(group: String?): Channel.RecipientTestResult {