From 5984383d2c48b4ae84bac1827bc6ca1891af8cf0 Mon Sep 17 00:00:00 2001 From: nea Date: Wed, 24 May 2023 02:29:20 +0200 Subject: Common config gui --- src/main/kotlin/moe/nea/firmament/commands/rome.kt | 12 +- .../moe/nea/firmament/features/FeatureManager.kt | 2 + .../moe/nea/firmament/features/FirmamentFeature.kt | 2 +- .../firmament/features/fishing/FishingWarning.kt | 2 +- .../moe/nea/firmament/features/world/FairySouls.kt | 2 +- src/main/kotlin/moe/nea/firmament/gui/ConfigGui.kt | 94 ---------- .../moe/nea/firmament/gui/WGridPanelWithPadding.kt | 33 ---- .../moe/nea/firmament/gui/config/AllConfigsGui.kt | 42 +++++ .../moe/nea/firmament/gui/config/BooleanHandler.kt | 33 ++++ .../moe/nea/firmament/gui/config/ClickHandler.kt | 25 +++ .../moe/nea/firmament/gui/config/GuiAppender.kt | 44 +++++ .../moe/nea/firmament/gui/config/ManagedConfig.kt | 153 ++++++++++++++++ .../moe/nea/firmament/gui/config/StringHandler.kt | 32 ++++ src/main/kotlin/moe/nea/firmament/gui/repogui.kt | 36 ---- .../moe/nea/firmament/repo/RepoDownloadManager.kt | 4 +- .../kotlin/moe/nea/firmament/repo/RepoManager.kt | 29 +-- src/main/kotlin/moe/nea/firmament/util/MC.kt | 5 +- .../moe/nea/firmament/util/config/ManagedConfig.kt | 204 --------------------- .../resources/assets/firmament/lang/en_us.json | 22 ++- 19 files changed, 373 insertions(+), 403 deletions(-) delete mode 100644 src/main/kotlin/moe/nea/firmament/gui/ConfigGui.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/gui/WGridPanelWithPadding.kt create mode 100644 src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt create mode 100644 src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt create mode 100644 src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt create mode 100644 src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt create mode 100644 src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt create mode 100644 src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/gui/repogui.kt delete mode 100644 src/main/kotlin/moe/nea/firmament/util/config/ManagedConfig.kt (limited to 'src') diff --git a/src/main/kotlin/moe/nea/firmament/commands/rome.kt b/src/main/kotlin/moe/nea/firmament/commands/rome.kt index bdbaa3f..4fde10e 100644 --- a/src/main/kotlin/moe/nea/firmament/commands/rome.kt +++ b/src/main/kotlin/moe/nea/firmament/commands/rome.kt @@ -1,17 +1,20 @@ package moe.nea.firmament.commands import com.mojang.brigadier.CommandDispatcher -import io.github.cottonmc.cotton.gui.client.CottonClientScreen import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource import net.minecraft.text.Text import moe.nea.firmament.features.world.FairySouls -import moe.nea.firmament.gui.repoGui +import moe.nea.firmament.gui.config.AllConfigsGui import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.ScreenUtil.setScreenLater fun firmamentCommand() = literal("firmament") { + thenLiteral("config") { + thenExecute { + AllConfigsGui.showAllGuis() + } + } thenLiteral("repo") { thenLiteral("reload") { thenLiteral("fetch") { @@ -25,9 +28,6 @@ fun firmamentCommand() = literal("firmament") { RepoManager.reload() } } - thenExecute { - setScreenLater(CottonClientScreen(repoGui())) - } } thenLiteral("dev") { thenLiteral("config") { diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index 580d745..a8d9722 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -16,6 +16,8 @@ object FeatureManager : DataHolder(serializer(), "feature private val features = mutableMapOf() + val allFeatures: Collection get() = features.values + private var hasAutoloaded = false init { diff --git a/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt b/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt index c9cb8f0..3d2fc86 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt @@ -1,6 +1,6 @@ package moe.nea.firmament.features -import moe.nea.firmament.util.config.ManagedConfig +import moe.nea.firmament.gui.config.ManagedConfig interface FirmamentFeature { val name: String diff --git a/src/main/kotlin/moe/nea/firmament/features/fishing/FishingWarning.kt b/src/main/kotlin/moe/nea/firmament/features/fishing/FishingWarning.kt index ab8ebf4..cb87d54 100644 --- a/src/main/kotlin/moe/nea/firmament/features/fishing/FishingWarning.kt +++ b/src/main/kotlin/moe/nea/firmament/features/fishing/FishingWarning.kt @@ -16,7 +16,7 @@ import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.config.ManagedConfig +import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.util.render.RenderBlockContext.Companion.renderBlocks object FishingWarning : FirmamentFeature { diff --git a/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt b/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt index ffde0b9..7a25799 100644 --- a/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt +++ b/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt @@ -11,7 +11,7 @@ import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData import moe.nea.firmament.util.blockPos -import moe.nea.firmament.util.config.ManagedConfig +import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.render.RenderBlockContext.Companion.renderBlocks import moe.nea.firmament.util.unformattedString diff --git a/src/main/kotlin/moe/nea/firmament/gui/ConfigGui.kt b/src/main/kotlin/moe/nea/firmament/gui/ConfigGui.kt deleted file mode 100644 index 6acf68a..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/ConfigGui.kt +++ /dev/null @@ -1,94 +0,0 @@ -package moe.nea.firmament.gui - -import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription -import io.github.cottonmc.cotton.gui.widget.WButton -import io.github.cottonmc.cotton.gui.widget.WLabel -import io.github.cottonmc.cotton.gui.widget.WTextField -import io.github.cottonmc.cotton.gui.widget.WToggleButton -import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment -import io.github.cottonmc.cotton.gui.widget.data.Insets -import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.data.DataHolder -import net.minecraft.text.Text -import kotlin.reflect.KMutableProperty1 - -class ConfigGui(val holder: DataHolder, val build: ConfigGui.() -> Unit) : LightweightGuiDescription() { - private val root = WGridPanelWithPadding(verticalPadding = 4) - private val reloadables = mutableListOf<(() -> Unit)>() - - init { - setRootPanel(root) - root.insets = Insets.ROOT_PANEL - build() - reload() - } - - fun title(text: Text) { - if (col != 0) { - Firmament.logger.warn("Set title not at the top of the ConfigGui") - } - val label = WLabel(text) - label.verticalAlignment = VerticalAlignment.TOP - label.horizontalAlignment = HorizontalAlignment.CENTER - root.add(label, 0, col, 11, 1) - col++ - } - - private fun label(text: Text) { - val label = WLabel(text) - label.verticalAlignment = VerticalAlignment.CENTER - root.add(label, 0, col, 5, 1) - } - - fun toggle(text: Text, prop: KMutableProperty1) { - val toggle = WToggleButton(text) - reloadables.add { toggle.toggle = prop.get(holder.data) } - toggle.setOnToggle { - prop.set(holder.data, true) - holder.markDirty() - } - root.add(toggle, 5, col, 6, 1) - label(text) - col++ - } - - fun button(text: Text, buttonText: Text, runnable: () -> Unit) { - val button = WButton(buttonText) - button.setOnClick { - runnable.invoke() - } - root.add(button, 5, col, 6, 1) - label(text) - col++ - } - - fun textfield( - text: Text, - background: Text, - prop: KMutableProperty1, - maxLength: Int = 255 - ) { - val textfield = WTextField(background) - textfield.isEditable = true - reloadables.add { - textfield.text = prop.get(holder.data) - } - textfield.maxLength = maxLength - textfield.setChangedListener { - prop.set(holder.data, it) - holder.markDirty() - } - root.add(textfield, 5, col, 6, 11) - label(text) - col++ - } - - fun reload() { - reloadables.forEach { it.invoke() } - } - - private var col = 0 - - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/WGridPanelWithPadding.kt b/src/main/kotlin/moe/nea/firmament/gui/WGridPanelWithPadding.kt deleted file mode 100644 index 255b80d..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/WGridPanelWithPadding.kt +++ /dev/null @@ -1,33 +0,0 @@ -package moe.nea.firmament.gui - -import io.github.cottonmc.cotton.gui.widget.WPanelWithInsets -import io.github.cottonmc.cotton.gui.widget.WWidget -import io.github.cottonmc.cotton.gui.widget.data.Insets - -class WGridPanelWithPadding( - val grid: Int = 18, - val verticalPadding: Int = 0, - val horizontalPadding: Int = 0, -) : WPanelWithInsets() { - - private inline val vertOffset get() = grid + verticalPadding - private inline val horiOffset get() = grid + horizontalPadding - - fun add(w: WWidget, x: Int, y: Int, width: Int = 1, height: Int = 1) { - children.add(w) - w.parent = this - w.setLocation(x * horiOffset + insets.left, y * vertOffset + insets.top) - if (w.canResize()) - w.setSize( - grid + (horiOffset * (width - 1)), - grid + (vertOffset * (height - 1)), - ) - expandToFit(w, insets) - } - - override fun setInsets(insets: Insets): WGridPanelWithPadding { - super.setInsets(insets) - return this - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt b/src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt new file mode 100644 index 0000000..687959d --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt @@ -0,0 +1,42 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.client.BackgroundPainter +import io.github.cottonmc.cotton.gui.client.CottonClientScreen +import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription +import io.github.cottonmc.cotton.gui.widget.WButton +import io.github.cottonmc.cotton.gui.widget.WGridPanel +import io.github.cottonmc.cotton.gui.widget.WLabel +import io.github.cottonmc.cotton.gui.widget.WListPanel +import io.github.cottonmc.cotton.gui.widget.data.Insets +import net.minecraft.text.Text +import moe.nea.firmament.features.FeatureManager +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.util.ScreenUtil.setScreenLater + +object AllConfigsGui { + + fun showAllGuis() { + val lwgd = LightweightGuiDescription() + var screen: CottonClientScreen? = null + lwgd.setRootPanel(WListPanel( + listOf( + RepoManager.Config + ) + FeatureManager.allFeatures.mapNotNull { it.config }, ::WGridPanel + ) { config, panel -> + panel.insets = Insets.ROOT_PANEL + panel.backgroundPainter = BackgroundPainter.VANILLA + panel.add(WLabel(Text.translatable("firmament.config.${config.name}")), 0, 0, 10, 1) + panel.add(WButton(Text.translatable("firmanent.config.edit")).also { + it.setOnClick { + config.showConfigEditor(screen) + } + }, 0, 1, 10, 1) + println("Panel size: ${panel.width} ${panel.height}") + }.also { + it.setListItemHeight(52) + it.setSize(10 * 18 + 14 + 16, 300) + }) + screen = CottonClientScreen(lwgd) + setScreenLater(screen) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt new file mode 100644 index 0000000..fa56901 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt @@ -0,0 +1,33 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.widget.WLabel +import io.github.cottonmc.cotton.gui.widget.WToggleButton +import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.jsonPrimitive +import net.minecraft.text.Text + +class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler { + override fun toJson(element: Boolean): JsonElement? { + return JsonPrimitive(element) + } + + override fun fromJson(element: JsonElement): Boolean { + return element.jsonPrimitive.boolean + } + + override fun emitGuiElements(opt: ManagedConfig.Option, guiAppender: GuiAppender) { + guiAppender.appendLabeledRow( + opt.labelText, + WToggleButton(opt.labelText).apply { + guiAppender.onReload { toggle = opt.value } + setOnToggle { + opt.value = it + config.save() + } + } + ) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt new file mode 100644 index 0000000..4948ade --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt @@ -0,0 +1,25 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.widget.WButton +import io.github.cottonmc.cotton.gui.widget.WLabel +import kotlinx.serialization.json.JsonElement +import net.minecraft.text.Text + +class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : ManagedConfig.OptionHandler { + override fun toJson(element: Unit): JsonElement? { + return null + } + + override fun fromJson(element: JsonElement) {} + + override fun emitGuiElements(opt: ManagedConfig.Option, guiAppender: GuiAppender) { + guiAppender.appendLabeledRow( + Text.translatable("firmament.config.${config.name}.${opt.propertyName}"), + WButton(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")).apply { + setOnClick { + runnable() + } + }, + ) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt b/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt new file mode 100644 index 0000000..fb0fb1d --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt @@ -0,0 +1,44 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.widget.WGridPanel +import io.github.cottonmc.cotton.gui.widget.WLabel +import io.github.cottonmc.cotton.gui.widget.WWidget +import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment +import net.minecraft.text.Text + +class GuiAppender(val width: Int) { + private var row = 0 + internal val panel = WGridPanel().also { it.setGaps(4, 4) } + internal val reloadables = mutableListOf<(() -> Unit)>() + fun set(x: Int, y: Int, w: Int, h: Int, widget: WWidget) { + panel.add(widget, x, y, w, h) + } + + + fun onReload(reloadable: () -> Unit) { + reloadables.add(reloadable) + } + + fun skipRows(r: Int) { + row += r + } + + fun appendLabeledRow(label: Text, right: WWidget) { + appendSplitRow( + WLabel(label).setVerticalAlignment(VerticalAlignment.CENTER), + right + ) + } + + fun appendSplitRow(left: WWidget, right: WWidget) { + val lw = width / 2 + set(0, row, lw, 1, left) + set(lw, row, width - lw, 1, right) + skipRows(1) + } + + fun appendFullRow(widget: WWidget) { + set(0, row, width, 1, widget) + skipRows(1) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt new file mode 100644 index 0000000..b268be9 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt @@ -0,0 +1,153 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.client.CottonClientScreen +import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription +import io.github.cottonmc.cotton.gui.widget.data.Insets +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlin.io.path.createDirectories +import kotlin.io.path.readText +import kotlin.io.path.writeText +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty +import net.minecraft.client.gui.screen.Screen +import net.minecraft.text.Text +import moe.nea.firmament.Firmament +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.ScreenUtil.setScreenLater + +abstract class ManagedConfig(val name: String) { + + interface OptionHandler { + fun toJson(element: T): JsonElement? + fun fromJson(element: JsonElement): T + fun emitGuiElements(opt: Option, guiAppender: GuiAppender) + } + + inner class Option internal constructor( + val config: ManagedConfig, + val propertyName: String, + val default: () -> T, + val handler: OptionHandler + ) : ReadWriteProperty { + + 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 + ) + } + } + 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 data: JsonObject by lazy { + try { + Firmament.json.decodeFromString( + file.readText() + ) + } catch (e: Exception) { + Firmament.logger.info("Could not read config $name. Loading empty config.") + JsonObject(mutableMapOf()) + } + } + + fun save() { + val data = JsonObject(allOptions.mapNotNull { (key, value) -> + value.toJson()?.let { + key to it + } + }.toMap()) + file.parent.createDirectories() + file.writeText(Firmament.json.encodeToString(data)) + } + + + val allOptions = mutableMapOf>() + val sortedOptions = mutableListOf>() + + private var latestGuiAppender: GuiAppender? = null + + protected fun option(propertyName: String, default: () -> T, handler: OptionHandler): Option { + if (propertyName in allOptions) error("Cannot register the same name twice") + return Option(this, propertyName, default, handler).also { + allOptions[propertyName] = it + sortedOptions.add(it) + } + } + + protected fun toggle(propertyName: String, default: () -> Boolean): Option { + return option(propertyName, default, BooleanHandler(this)) + } + + protected fun button(propertyName: String, runnable: () -> Unit): Option { + return option(propertyName, { }, ClickHandler(this, runnable)) + } + + protected fun string(propertyName: String, default: () -> String): Option { + return option(propertyName, default, StringHandler(this)) + } + + + + fun reloadGui() { + latestGuiAppender?.reloadables?.forEach {it() } + } + + fun showConfigEditor(parent: Screen? = null) { + val lwgd = LightweightGuiDescription() + val guiapp = GuiAppender(20) + latestGuiAppender = guiapp + guiapp.panel.insets = Insets.ROOT_PANEL + sortedOptions.forEach { it.appendToGui(guiapp) } + guiapp.reloadables.forEach { it() } + lwgd.setRootPanel(guiapp.panel) + setScreenLater(object : CottonClientScreen(lwgd) { + override fun close() { + latestGuiAppender = null + MC.screen = parent + } + }) + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt new file mode 100644 index 0000000..b883e21 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt @@ -0,0 +1,32 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.widget.WLabel +import io.github.cottonmc.cotton.gui.widget.WTextField +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.jsonPrimitive +import net.minecraft.text.Text + +class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler { + override fun toJson(element: String): JsonElement? { + return JsonPrimitive(element) + } + + override fun fromJson(element: JsonElement): String { + return element.jsonPrimitive.toString() + } + + override fun emitGuiElements(opt: ManagedConfig.Option, guiAppender: GuiAppender) { + guiAppender.appendLabeledRow( + opt.labelText, + WTextField(opt.labelText).apply { + suggestion = Text.translatableWithFallback(opt.rawLabelText + ".hint", "") + guiAppender.onReload { text = opt.value } + setChangedListener { + opt.value = it + config.save() + } + } + ) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/repogui.kt b/src/main/kotlin/moe/nea/firmament/gui/repogui.kt deleted file mode 100644 index da681e4..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/repogui.kt +++ /dev/null @@ -1,36 +0,0 @@ -package moe.nea.firmament.gui - -import net.minecraft.text.Text -import moe.nea.firmament.repo.RepoManager - -fun repoGui(): ConfigGui { - return ConfigGui(RepoManager) { - title(Text.translatable("firmament.gui.repo.title")) - toggle(Text.translatable("firmament.gui.repo.autoupdate"), RepoManager.Config::autoUpdate) - textfield( - Text.translatable("firmament.gui.repo.username"), - Text.translatable("firmament.gui.repo.hint.username"), - RepoManager.Config::user, - maxLength = 255 - ) - textfield( - Text.translatable("firmament.gui.repo.reponame"), - Text.translatable("firmament.gui.repo.hint.reponame"), - RepoManager.Config::repo - ) - textfield( - Text.translatable("firmament.gui.repo.branch"), - Text.translatable("firmament.gui.repo.hint.branch"), - RepoManager.Config::branch - ) - button( - Text.translatable("firmament.gui.repo.reset.label"), - Text.translatable("firmament.gui.repo.reset"), - ) { - RepoManager.data.user = "NotEnoughUpdates" - RepoManager.data.repo = "NotEnoughUpdates-REPO" - RepoManager.data.branch = "dangerous" - reload() - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt index 09b246a..611a4e1 100644 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt +++ b/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt @@ -50,7 +50,7 @@ object RepoDownloadManager { private suspend fun requestLatestGithubSha(): String? { val response = - Firmament.httpClient.get("https://api.github.com/repos/${RepoManager.data.user}/${RepoManager.data.repo}/commits/${RepoManager.data.branch}") + Firmament.httpClient.get("https://api.github.com/repos/${RepoManager.Config.username}/${RepoManager.Config.reponame}/commits/${RepoManager.Config.branch}") if (response.status.value != 200) { return null } @@ -77,7 +77,7 @@ object RepoDownloadManager { } val currentSha = loadSavedVersionHash() if (latestSha != currentSha || force) { - val requestUrl = "https://github.com/${RepoManager.data.user}/${RepoManager.data.repo}/archive/$latestSha.zip" + val requestUrl = "https://github.com/${RepoManager.Config.username}/${RepoManager.Config.reponame}/archive/$latestSha.zip" logger.info("Planning to upgrade repository from $currentSha to $latestSha from $requestUrl") val zipFile = downloadGithubArchive(requestUrl) logger.info("Download repository zip file to $zipFile. Deleting old repository") diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt index b1091fc..ea77fc1 100644 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt +++ b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt @@ -8,8 +8,6 @@ import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.NEURecipe import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import kotlinx.coroutines.launch -import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer import net.minecraft.client.MinecraftClient import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket import net.minecraft.text.Text @@ -17,16 +15,21 @@ import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament.logger import moe.nea.firmament.hud.ProgressBar import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.data.DataHolder - -object RepoManager : DataHolder(serializer(), "repo", ::Config) { - @Serializable - data class Config( - var user: String = "NotEnoughUpdates", - var repo: String = "NotEnoughUpdates-REPO", - var autoUpdate: Boolean = true, - var branch: String = "dangerous", - ) +import moe.nea.firmament.gui.config.ManagedConfig + +object RepoManager { + object Config : ManagedConfig("repo") { + var username by string("username") { "NotEnoughUpdates" } + var reponame by string("reponame") { "NotEnoughUpdates-REPO" } + var branch by string("branch") { "prerelease" } + val autoUpdate by toggle("autoUpdate") { true } + val reset by button("reset") { + username = "NotEnoughUpdates" + reponame = "NotEnoughUpdates-REPO" + branch = "prerelease" + save() + } + } val currentDownloadedSha by RepoDownloadManager::latestSavedVersionHash @@ -93,7 +96,7 @@ object RepoManager : DataHolder(serializer(), "repo", ::Conf } fun initialize() { - if (data.autoUpdate) { + if (Config.autoUpdate) { launchAsyncUpdate() } else { reload() diff --git a/src/main/kotlin/moe/nea/firmament/util/MC.kt b/src/main/kotlin/moe/nea/firmament/util/MC.kt index 8fc15b5..ae5f9a6 100644 --- a/src/main/kotlin/moe/nea/firmament/util/MC.kt +++ b/src/main/kotlin/moe/nea/firmament/util/MC.kt @@ -4,13 +4,14 @@ import io.github.moulberry.repo.data.Coordinate import net.minecraft.client.MinecraftClient import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.util.math.BlockPos -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen object MC { inline val soundManager get() = MinecraftClient.getInstance().soundManager inline val player get() = MinecraftClient.getInstance().player inline val world get() = MinecraftClient.getInstance().world - inline val screen get() = MinecraftClient.getInstance().currentScreen + inline var screen + get() = MinecraftClient.getInstance().currentScreen + set(value) = MinecraftClient.getInstance().setScreen(value) inline val handledScreen: HandledScreen<*>? get() = MinecraftClient.getInstance().currentScreen as? HandledScreen<*> } diff --git a/src/main/kotlin/moe/nea/firmament/util/config/ManagedConfig.kt b/src/main/kotlin/moe/nea/firmament/util/config/ManagedConfig.kt deleted file mode 100644 index bc06064..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/config/ManagedConfig.kt +++ /dev/null @@ -1,204 +0,0 @@ -package moe.nea.firmament.util.config - -import io.github.cottonmc.cotton.gui.client.CottonClientScreen -import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription -import io.github.cottonmc.cotton.gui.widget.WButton -import io.github.cottonmc.cotton.gui.widget.WLabel -import io.github.cottonmc.cotton.gui.widget.WToggleButton -import io.github.cottonmc.cotton.gui.widget.WWidget -import io.github.cottonmc.cotton.gui.widget.data.Insets -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.boolean -import kotlinx.serialization.json.jsonPrimitive -import kotlin.io.path.createDirectories -import kotlin.io.path.readText -import kotlin.io.path.writeText -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.gui.WGridPanelWithPadding -import moe.nea.firmament.util.ScreenUtil.setScreenLater - -abstract class ManagedConfig(val name: String) { - - class GuiAppender(val width: Int) { - private var row = 0 - internal val panel = WGridPanelWithPadding(verticalPadding = 4, horizontalPadding = 4) - internal val reloadables = mutableListOf<(() -> Unit)>() - fun set(x: Int, y: Int, w: Int, h: Int, widget: WWidget) { - panel.add(widget, x, y, w, h) - } - - - fun onReload(reloadable: () -> Unit) { - reloadables.add(reloadable) - } - - fun skipRows(r: Int) { - row += r - } - - fun appendSplitRow(left: WWidget, right: WWidget) { - val lw = width / 2 - set(0, row, lw, 1, left) - set(lw, row, width - lw, 1, right) - skipRows(1) - } - - fun appendFullRow(widget: WWidget) { - set(0, row, width, 1, widget) - skipRows(1) - } - } - - interface OptionHandler { - fun toJson(element: T): JsonElement? - fun fromJson(element: JsonElement): T - fun emitGuiElements(opt: Option, guiAppender: GuiAppender) - } - - inner class Option internal constructor( - val propertyName: String, - val default: () -> T, - val handler: OptionHandler - ) : ReadOnlyProperty { - - 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 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 - ) - } - } - 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 data: JsonObject by lazy { - try { - Firmament.json.decodeFromString( - file.readText() - ) - } catch (e: Exception) { - Firmament.logger.info("Could not read config $name. Loading empty config.") - JsonObject(mutableMapOf()) - } - } - - fun save() { - val data = JsonObject(allOptions.mapNotNull { (key, value) -> - value.toJson()?.let { - key to it - } - }.toMap()) - file.parent.createDirectories() - file.writeText(Firmament.json.encodeToString(data)) - } - - - val allOptions = mutableMapOf>() - val sortedOptions = mutableListOf>() - - protected fun option(propertyName: String, default: () -> T, handler: OptionHandler): Option { - if (propertyName in allOptions) error("Cannot register the same name twice") - return Option(propertyName, default, handler).also { - allOptions[propertyName] = it - sortedOptions.add(it) - } - } - - class BooleanHandler(val config: ManagedConfig) : OptionHandler { - override fun toJson(element: Boolean): JsonElement? { - return JsonPrimitive(element) - } - - override fun fromJson(element: JsonElement): Boolean { - return element.jsonPrimitive.boolean - } - - override fun emitGuiElements(opt: Option, guiAppender: GuiAppender) { - guiAppender.appendFullRow( - WToggleButton(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")).apply { - guiAppender.onReload { toggle = opt.value } - setOnToggle { - opt.value = it - config.save() - } - } - ) - } - } - - class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : OptionHandler { - override fun toJson(element: Unit): JsonElement? { - return null - } - - override fun fromJson(element: JsonElement) {} - - override fun emitGuiElements(opt: Option, guiAppender: GuiAppender) { - guiAppender.appendSplitRow( - WLabel(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")), - WButton(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")).apply { - setOnClick { - runnable() - } - }, - ) - } - } - - protected fun toggle(propertyName: String, default: () -> Boolean): Option { - return option(propertyName, default, BooleanHandler(this)) - } - - fun showConfigEditor() { - val lwgd = LightweightGuiDescription() - val guiapp = GuiAppender(20) - guiapp.panel.insets = Insets.ROOT_PANEL - sortedOptions.forEach { it.appendToGui(guiapp) } - guiapp.reloadables.forEach { it() } - lwgd.setRootPanel(guiapp.panel) - setScreenLater(CottonClientScreen(lwgd)) - } - - protected fun button(propertyName: String, runnable: () -> Unit): Option { - return option(propertyName, { }, ClickHandler(this, runnable)) - } - -} diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index ca50bb1..9243c28 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -3,24 +3,26 @@ "firmament.repo.reload.disk": "Reloading repository from disk. This may lag a bit.", "firmament.repo.cache": "Recaching items", "firmament.repo.brokenitem": "Failed to render item: %s", - "firmament.gui.repo.title": "firmament Repo Settings", - "firmament.gui.repo.autoupdate": "Auto Update", - "firmament.gui.repo.username": "Repo Username", - "firmament.gui.repo.hint.username": "NotEnoughUpdates", - "firmament.gui.repo.reponame": "Repo Name", - "firmament.gui.repo.hint.reponame": "NotEnoughUpdates-REPO", - "firmament.gui.repo.branch": "Repo Branch", - "firmament.gui.repo.hint.branch": "dangerous", - "firmament.gui.repo.reset": "Reset", - "firmament.gui.repo.reset.label": "Reset to Defaults", + "firmanent.config.edit": "Edit", + "firmament.config.repo": "Firmament Repo Settings", + "firmament.config.repo.autoUpdate": "Auto Update", + "firmament.config.repo.username": "Repo Username", + "firmament.config.repo.username.hint": "NotEnoughUpdates", + "firmament.config.repo.reponame": "Repo Name", + "firmament.config.repo.reponame.hint": "NotEnoughUpdates-REPO", + "firmament.config.repo.branch": "Repo Branch", + "firmament.config.repo.branch.hint": "dangerous", + "firmament.config.repo.reset": "Reset", "firmament.sbinfo.nolocraw": "No locraw data available", "firmament.sbinfo.profile": "Current profile cutename: %s", "firmament.sbinfo.server": "Locraw Server: %s", "firmament.sbinfo.gametype": "Locraw Gametype: %s", "firmament.sbinfo.mode": "Locraw Mode: %s", "firmament.sbinfo.map": "Locraw Map: %s", + "firmament.config.fairy-souls": "Fairy Souls", "firmament.config.fairy-souls.show": "Show Fairy Soul Waypoints", "firmament.config.fairy-souls.reset": "Reset Collected Fairy Souls", + "firmament.config.fishing-warning": "Fishing Warning", "firmament.config.fishing-warning.display-warning": "Display a warning when you are about to hook a fish", "firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles", "firmament.key.slotlocking": "Lock Slot / Slot Binding", -- cgit