Add slightly more modular options

This commit is contained in:
nea
2023-08-11 22:42:01 +02:00
parent 2b33dd1b11
commit b32f5da88c
9 changed files with 93 additions and 81 deletions

View File

@@ -21,7 +21,7 @@ class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Bo
return element.jsonPrimitive.boolean return element.jsonPrimitive.boolean
} }
override fun emitGuiElements(opt: ManagedConfig.Option<Boolean>, guiAppender: GuiAppender) { override fun emitGuiElements(opt: ManagedOption<Boolean>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow( guiAppender.appendLabeledRow(
opt.labelText, opt.labelText,
WToggleButton(opt.labelText).apply { WToggleButton(opt.labelText).apply {

View File

@@ -7,7 +7,6 @@
package moe.nea.firmament.gui.config package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WButton import io.github.cottonmc.cotton.gui.widget.WButton
import io.github.cottonmc.cotton.gui.widget.WLabel
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import net.minecraft.text.Text import net.minecraft.text.Text
@@ -18,7 +17,7 @@ class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : Manage
override fun fromJson(element: JsonElement) {} override fun fromJson(element: JsonElement) {}
override fun emitGuiElements(opt: ManagedConfig.Option<Unit>, guiAppender: GuiAppender) { override fun emitGuiElements(opt: ManagedOption<Unit>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow( guiAppender.appendLabeledRow(
Text.translatable("firmament.config.${config.name}.${opt.propertyName}"), Text.translatable("firmament.config.${config.name}.${opt.propertyName}"),
WButton(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")).apply { WButton(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")).apply {

View File

@@ -33,7 +33,7 @@ class DurationHandler(val config: ManagedConfig, val min: Duration, val max: Dur
return element.jsonPrimitive.long.toDuration(DurationUnit.MILLISECONDS) return element.jsonPrimitive.long.toDuration(DurationUnit.MILLISECONDS)
} }
override fun emitGuiElements(opt: ManagedConfig.Option<Duration>, guiAppender: GuiAppender) { override fun emitGuiElements(opt: ManagedOption<Duration>, guiAppender: GuiAppender) {
val label = val label =
WLabel(Text.literal(FirmFormatters.formatTimespan(opt.value))).setVerticalAlignment(VerticalAlignment.CENTER) WLabel(Text.literal(FirmFormatters.formatTimespan(opt.value))).setVerticalAlignment(VerticalAlignment.CENTER)
guiAppender.appendLabeledRow(opt.labelText, WBox(Axis.HORIZONTAL).also { guiAppender.appendLabeledRow(opt.labelText, WBox(Axis.HORIZONTAL).also {

View File

@@ -26,7 +26,7 @@ class HudMetaHandler(val config: ManagedConfig, val label: MutableText, val widt
return HudMeta(Json.decodeFromJsonElement(element), label, width, height) return HudMeta(Json.decodeFromJsonElement(element), label, width, height)
} }
override fun emitGuiElements(opt: ManagedConfig.Option<HudMeta>, guiAppender: GuiAppender) { override fun emitGuiElements(opt: ManagedOption<HudMeta>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow(opt.labelText, WButton(Text.translatable("firmament.hud.edit", label)) guiAppender.appendLabeledRow(opt.labelText, WButton(Text.translatable("firmament.hud.edit", label))
.also { .also {
it.setOnClick { it.setOnClick {

View File

@@ -16,9 +16,7 @@ import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.int import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import kotlin.time.Duration.Companion.milliseconds
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.util.FirmFormatters
class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : ManagedConfig.OptionHandler<Int> { class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : ManagedConfig.OptionHandler<Int> {
override fun toJson(element: Int): JsonElement? { override fun toJson(element: Int): JsonElement? {
@@ -29,7 +27,7 @@ class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : Ma
return element.jsonPrimitive.int return element.jsonPrimitive.int
} }
override fun emitGuiElements(opt: ManagedConfig.Option<Int>, guiAppender: GuiAppender) { override fun emitGuiElements(opt: ManagedOption<Int>, guiAppender: GuiAppender) {
val label = val label =
WLabel(Text.literal(opt.value.toString())).setVerticalAlignment(VerticalAlignment.CENTER) WLabel(Text.literal(opt.value.toString())).setVerticalAlignment(VerticalAlignment.CENTER)
guiAppender.appendLabeledRow(opt.labelText, WBox(Axis.HORIZONTAL).also { guiAppender.appendLabeledRow(opt.labelText, WBox(Axis.HORIZONTAL).also {

View File

@@ -11,7 +11,6 @@ import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription
import io.github.cottonmc.cotton.gui.widget.WBox import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WButton import io.github.cottonmc.cotton.gui.widget.WButton
import io.github.cottonmc.cotton.gui.widget.WLabel import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.WScrollPanel
import io.github.cottonmc.cotton.gui.widget.data.Axis import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.Insets import io.github.cottonmc.cotton.gui.widget.data.Insets
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
@@ -23,8 +22,6 @@ import kotlinx.serialization.json.JsonObject
import kotlin.io.path.createDirectories import kotlin.io.path.createDirectories
import kotlin.io.path.readText import kotlin.io.path.readText
import kotlin.io.path.writeText import kotlin.io.path.writeText
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import kotlin.time.Duration import kotlin.time.Duration
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import net.minecraft.text.Text import net.minecraft.text.Text
@@ -33,67 +30,12 @@ import moe.nea.firmament.gui.WTightScrollPanel
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil.setScreenLater import moe.nea.firmament.util.ScreenUtil.setScreenLater
abstract class ManagedConfig(val name: String) { abstract class ManagedConfig(override val name: String) : ManagedConfigElement() {
interface OptionHandler<T : Any> { interface OptionHandler<T : Any> {
fun toJson(element: T): JsonElement? fun toJson(element: T): JsonElement?
fun fromJson(element: JsonElement): T fun fromJson(element: JsonElement): T
fun emitGuiElements(opt: Option<T>, guiAppender: GuiAppender) fun emitGuiElements(opt: ManagedOption<T>, guiAppender: GuiAppender)
}
inner class Option<T : Any> internal constructor(
val config: ManagedConfig,
val propertyName: String,
val default: () -> T,
val handler: OptionHandler<T>
) : ReadWriteProperty<Any?, T> {
val rawLabelText = "firmament.config.${config.name}.${propertyName}"
val labelText = Text.translatable(rawLabelText)
private lateinit var _value: T
private var loaded = false
var value: T
get() {
if (!loaded)
load()
return _value
}
set(value) {
loaded = true
_value = value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
private fun load() {
if (data.containsKey(propertyName)) {
try {
value = handler.fromJson(data[propertyName]!!)
} catch (e: Exception) {
Firmament.logger.error(
"Exception during loading of config file $name. This will reset this config.",
e
)
}
} else {
value = default()
}
}
internal fun toJson(): JsonElement? {
return handler.toJson(value)
}
fun appendToGui(guiapp: GuiAppender) {
handler.emitGuiElements(this, guiapp)
}
} }
val file = Firmament.CONFIG_DIR.resolve("$name.json") val file = Firmament.CONFIG_DIR.resolve("$name.json")
@@ -119,20 +61,25 @@ abstract class ManagedConfig(val name: String) {
} }
val allOptions = mutableMapOf<String, Option<*>>() val allOptions = mutableMapOf<String, ManagedOption<*>>()
val sortedOptions = mutableListOf<Option<*>>() val sortedOptions = mutableListOf<ManagedOption<*>>()
private var latestGuiAppender: GuiAppender? = null private var latestGuiAppender: GuiAppender? = null
protected fun <T : Any> option(propertyName: String, default: () -> T, handler: OptionHandler<T>): Option<T> { protected fun <T : Any> option(
propertyName: String,
default: () -> T,
handler: OptionHandler<T>
): ManagedOption<T> {
if (propertyName in allOptions) error("Cannot register the same name twice") if (propertyName in allOptions) error("Cannot register the same name twice")
return Option(this, propertyName, default, handler).also { return ManagedOption(this, propertyName, default, handler).also {
it.load(data)
allOptions[propertyName] = it allOptions[propertyName] = it
sortedOptions.add(it) sortedOptions.add(it)
} }
} }
protected fun toggle(propertyName: String, default: () -> Boolean): Option<Boolean> { protected fun toggle(propertyName: String, default: () -> Boolean): ManagedOption<Boolean> {
return option(propertyName, default, BooleanHandler(this)) return option(propertyName, default, BooleanHandler(this))
} }
@@ -141,7 +88,7 @@ abstract class ManagedConfig(val name: String) {
min: Duration, min: Duration,
max: Duration, max: Duration,
default: () -> Duration, default: () -> Duration,
): Option<Duration> { ): ManagedOption<Duration> {
return option(propertyName, default, DurationHandler(this, min, max)) return option(propertyName, default, DurationHandler(this, min, max))
} }
@@ -151,7 +98,7 @@ abstract class ManagedConfig(val name: String) {
width: Int, width: Int,
height: Int, height: Int,
default: () -> Point, default: () -> Point,
): Option<HudMeta> { ): ManagedOption<HudMeta> {
val label = Text.translatable("firmament.config.${name}.${propertyName}") val label = Text.translatable("firmament.config.${name}.${propertyName}")
return option(propertyName, { return option(propertyName, {
val p = default() val p = default()
@@ -164,20 +111,19 @@ abstract class ManagedConfig(val name: String) {
min: Int, min: Int,
max: Int, max: Int,
default: () -> Int, default: () -> Int,
): Option<Int> { ): ManagedOption<Int> {
return option(propertyName, default, IntegerHandler(this, min, max)) return option(propertyName, default, IntegerHandler(this, min, max))
} }
protected fun button(propertyName: String, runnable: () -> Unit): Option<Unit> { protected fun button(propertyName: String, runnable: () -> Unit): ManagedOption<Unit> {
return option(propertyName, { }, ClickHandler(this, runnable)) return option(propertyName, { }, ClickHandler(this, runnable))
} }
protected fun string(propertyName: String, default: () -> String): Option<String> { protected fun string(propertyName: String, default: () -> String): ManagedOption<String> {
return option(propertyName, default, StringHandler(this)) return option(propertyName, default, StringHandler(this))
} }
fun reloadGui() { fun reloadGui() {
latestGuiAppender?.reloadables?.forEach {it() } latestGuiAppender?.reloadables?.forEach {it() }
} }

View File

@@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.config
abstract class ManagedConfigElement {
abstract val name: String
}

View File

@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.config
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
class ManagedOption<T : Any>(
val element: ManagedConfigElement,
val propertyName: String,
val default: () -> T,
val handler: ManagedConfig.OptionHandler<T>
) : ReadWriteProperty<Any?, T> {
val rawLabelText = "firmament.config.${element.name}.${propertyName}"
val labelText = Text.translatable(rawLabelText)
lateinit var value: T
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
fun load(root: JsonElement) {
if (root is JsonObject && root.containsKey(propertyName)) {
try {
value = handler.fromJson(root[propertyName]!!)
return
} catch (e: Exception) {
Firmament.logger.error(
"Exception during loading of config file ${element.name}. This will reset this config.",
e
)
}
}
value = default()
}
fun toJson(): JsonElement? {
return handler.toJson(value)
}
fun appendToGui(guiapp: GuiAppender) {
handler.emitGuiElements(this, guiapp)
}
}

View File

@@ -6,7 +6,6 @@
package moe.nea.firmament.gui.config package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.WTextField import io.github.cottonmc.cotton.gui.widget.WTextField
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonPrimitive
@@ -22,7 +21,7 @@ class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Str
return element.jsonPrimitive.content return element.jsonPrimitive.content
} }
override fun emitGuiElements(opt: ManagedConfig.Option<String>, guiAppender: GuiAppender) { override fun emitGuiElements(opt: ManagedOption<String>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow( guiAppender.appendLabeledRow(
opt.labelText, opt.labelText,
WTextField(opt.labelText).apply { WTextField(opt.labelText).apply {