Add config categories
This commit is contained in:
@@ -4,24 +4,35 @@ import io.github.notenoughupdates.moulconfig.observer.ObservableList
|
||||
import io.github.notenoughupdates.moulconfig.xml.Bind
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.features.FeatureManager
|
||||
import moe.nea.firmament.repo.RepoManager
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.MoulConfigUtils
|
||||
import moe.nea.firmament.util.ScreenUtil.setScreenLater
|
||||
|
||||
object AllConfigsGui {
|
||||
//
|
||||
// val allConfigs
|
||||
// get() = listOf(
|
||||
// RepoManager.Config
|
||||
// ) + FeatureManager.allFeatures.mapNotNull { it.config }
|
||||
|
||||
val allConfigs
|
||||
get() = listOf(
|
||||
RepoManager.Config
|
||||
) + FeatureManager.allFeatures.mapNotNull { it.config }
|
||||
object ConfigConfig : ManagedConfig("configconfig", Category.META) {
|
||||
val enableYacl by toggle("enable-yacl") { false }
|
||||
}
|
||||
|
||||
fun <T> List<T>.toObservableList(): ObservableList<T> = ObservableList(this)
|
||||
|
||||
class MainMapping(val allConfigs: List<ManagedConfig>) {
|
||||
class CategoryMapping(val category: ManagedConfig.Category) {
|
||||
@get:Bind("configs")
|
||||
val configs = allConfigs.map { EntryMapping(it) }.toObservableList()
|
||||
val configs = category.configs.map { EntryMapping(it) }.toObservableList()
|
||||
|
||||
@Bind
|
||||
fun name() = category.labelText.string
|
||||
|
||||
@Bind
|
||||
fun close() {
|
||||
MC.screen?.close()
|
||||
}
|
||||
|
||||
class EntryMapping(val config: ManagedConfig) {
|
||||
@Bind
|
||||
@@ -34,12 +45,29 @@ object AllConfigsGui {
|
||||
}
|
||||
}
|
||||
|
||||
class CategoryView {
|
||||
@get:Bind("categories")
|
||||
val categories = ManagedConfig.Category.entries
|
||||
.map { CategoryEntry(it) }
|
||||
.toObservableList()
|
||||
|
||||
class CategoryEntry(val category: ManagedConfig.Category) {
|
||||
@Bind
|
||||
fun name() = category.labelText.string
|
||||
|
||||
@Bind
|
||||
fun open() {
|
||||
MC.screen = MoulConfigUtils.loadScreen("config/category", CategoryMapping(category), MC.screen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun makeBuiltInScreen(parent: Screen? = null): Screen {
|
||||
return MoulConfigUtils.loadScreen("config/main", MainMapping(allConfigs), parent)
|
||||
return MoulConfigUtils.loadScreen("config/main", CategoryView(), parent)
|
||||
}
|
||||
|
||||
fun makeScreen(parent: Screen? = null): Screen {
|
||||
val wantedKey = if (RepoManager.Config.enableYacl) "yacl" else "builtin"
|
||||
val wantedKey = if (ConfigConfig.enableYacl) "yacl" else "builtin"
|
||||
val provider = FirmamentConfigScreenProvider.providers.find { it.key == wantedKey }
|
||||
?: FirmamentConfigScreenProvider.providers.first()
|
||||
return provider.open(parent)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
package moe.nea.firmament.gui.config
|
||||
|
||||
import io.github.notenoughupdates.moulconfig.gui.CloseEventListener
|
||||
@@ -26,157 +24,191 @@ import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.gui.FirmButtonComponent
|
||||
import moe.nea.firmament.keybindings.SavedKeyBinding
|
||||
import moe.nea.firmament.util.ScreenUtil.setScreenLater
|
||||
import moe.nea.firmament.util.collections.InstanceList
|
||||
|
||||
abstract class ManagedConfig(override val name: String) : ManagedConfigElement() {
|
||||
abstract class ManagedConfig(
|
||||
override val name: String,
|
||||
val category: Category,
|
||||
// TODO: allow vararg secondaryCategories: Category,
|
||||
) : ManagedConfigElement() {
|
||||
enum class Category {
|
||||
// Böse Kategorie, nicht benutzten lol
|
||||
MISC,
|
||||
CHAT,
|
||||
INVENTORY,
|
||||
MINING,
|
||||
EVENTS,
|
||||
INTEGRATIONS,
|
||||
META,
|
||||
DEV,
|
||||
;
|
||||
|
||||
interface OptionHandler<T : Any> {
|
||||
fun initOption(opt: ManagedOption<T>) {}
|
||||
fun toJson(element: T): JsonElement?
|
||||
fun fromJson(element: JsonElement): T
|
||||
fun emitGuiElements(opt: ManagedOption<T>, guiAppender: GuiAppender)
|
||||
}
|
||||
val labelText: Text = Text.translatable("firmament.config.category.${name.lowercase()}")
|
||||
val configs: MutableList<ManagedConfig> = mutableListOf()
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
val allManagedConfigs = InstanceList<ManagedConfig>("ManagedConfig")
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
interface OptionHandler<T : Any> {
|
||||
fun initOption(opt: ManagedOption<T>) {}
|
||||
fun toJson(element: T): JsonElement?
|
||||
fun fromJson(element: JsonElement): T
|
||||
fun emitGuiElements(opt: ManagedOption<T>, guiAppender: GuiAppender)
|
||||
}
|
||||
|
||||
init {
|
||||
allManagedConfigs.getAll().forEach {
|
||||
require(it.name != name) { "Duplicate name '$name' used for config" }
|
||||
}
|
||||
allManagedConfigs.add(this)
|
||||
category.configs.add(this)
|
||||
}
|
||||
|
||||
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<String, ManagedOption<*>>()
|
||||
val sortedOptions = mutableListOf<ManagedOption<*>>()
|
||||
val allOptions = mutableMapOf<String, ManagedOption<*>>()
|
||||
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>
|
||||
): ManagedOption<T> {
|
||||
if (propertyName in allOptions) error("Cannot register the same name twice")
|
||||
return ManagedOption(this, propertyName, default, handler).also {
|
||||
it.handler.initOption(it)
|
||||
it.load(data)
|
||||
allOptions[propertyName] = it
|
||||
sortedOptions.add(it)
|
||||
}
|
||||
}
|
||||
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")
|
||||
return ManagedOption(this, propertyName, default, handler).also {
|
||||
it.handler.initOption(it)
|
||||
it.load(data)
|
||||
allOptions[propertyName] = it
|
||||
sortedOptions.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun toggle(propertyName: String, default: () -> Boolean): ManagedOption<Boolean> {
|
||||
return option(propertyName, default, BooleanHandler(this))
|
||||
}
|
||||
protected fun toggle(propertyName: String, default: () -> Boolean): ManagedOption<Boolean> {
|
||||
return option(propertyName, default, BooleanHandler(this))
|
||||
}
|
||||
|
||||
protected fun duration(
|
||||
propertyName: String,
|
||||
min: Duration,
|
||||
max: Duration,
|
||||
default: () -> Duration,
|
||||
): ManagedOption<Duration> {
|
||||
return option(propertyName, default, DurationHandler(this, min, max))
|
||||
}
|
||||
protected fun duration(
|
||||
propertyName: String,
|
||||
min: Duration,
|
||||
max: Duration,
|
||||
default: () -> Duration,
|
||||
): ManagedOption<Duration> {
|
||||
return option(propertyName, default, DurationHandler(this, min, max))
|
||||
}
|
||||
|
||||
|
||||
protected fun position(
|
||||
propertyName: String,
|
||||
width: Int,
|
||||
height: Int,
|
||||
default: () -> Point,
|
||||
): ManagedOption<HudMeta> {
|
||||
val label = Text.translatable("firmament.config.${name}.${propertyName}")
|
||||
return option(propertyName, {
|
||||
val p = default()
|
||||
HudMeta(HudPosition(p.x, p.y, 1F), label, width, height)
|
||||
}, HudMetaHandler(this, label, width, height))
|
||||
}
|
||||
protected fun position(
|
||||
propertyName: String,
|
||||
width: Int,
|
||||
height: Int,
|
||||
default: () -> Point,
|
||||
): ManagedOption<HudMeta> {
|
||||
val label = Text.translatable("firmament.config.${name}.${propertyName}")
|
||||
return option(propertyName, {
|
||||
val p = default()
|
||||
HudMeta(HudPosition(p.x, p.y, 1F), label, width, height)
|
||||
}, HudMetaHandler(this, label, width, height))
|
||||
}
|
||||
|
||||
protected fun keyBinding(
|
||||
propertyName: String,
|
||||
default: () -> Int,
|
||||
): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(default()) }
|
||||
protected fun keyBinding(
|
||||
propertyName: String,
|
||||
default: () -> Int,
|
||||
): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(default()) }
|
||||
|
||||
protected fun keyBindingWithOutDefaultModifiers(
|
||||
propertyName: String,
|
||||
default: () -> SavedKeyBinding,
|
||||
): ManagedOption<SavedKeyBinding> {
|
||||
return option(propertyName, default, KeyBindingHandler("firmament.config.${name}.${propertyName}", this))
|
||||
}
|
||||
protected fun keyBindingWithOutDefaultModifiers(
|
||||
propertyName: String,
|
||||
default: () -> SavedKeyBinding,
|
||||
): ManagedOption<SavedKeyBinding> {
|
||||
return option(propertyName, default, KeyBindingHandler("firmament.config.${name}.${propertyName}", this))
|
||||
}
|
||||
|
||||
protected fun keyBindingWithDefaultUnbound(
|
||||
propertyName: String,
|
||||
): ManagedOption<SavedKeyBinding> {
|
||||
return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN) }
|
||||
}
|
||||
protected fun keyBindingWithDefaultUnbound(
|
||||
propertyName: String,
|
||||
): ManagedOption<SavedKeyBinding> {
|
||||
return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN) }
|
||||
}
|
||||
|
||||
protected fun integer(
|
||||
propertyName: String,
|
||||
min: Int,
|
||||
max: Int,
|
||||
default: () -> Int,
|
||||
): ManagedOption<Int> {
|
||||
return option(propertyName, default, IntegerHandler(this, min, max))
|
||||
}
|
||||
protected fun integer(
|
||||
propertyName: String,
|
||||
min: Int,
|
||||
max: Int,
|
||||
default: () -> Int,
|
||||
): ManagedOption<Int> {
|
||||
return option(propertyName, default, IntegerHandler(this, min, max))
|
||||
}
|
||||
|
||||
protected fun button(propertyName: String, runnable: () -> Unit): ManagedOption<Unit> {
|
||||
return option(propertyName, { }, ClickHandler(this, runnable))
|
||||
}
|
||||
protected fun button(propertyName: String, runnable: () -> Unit): ManagedOption<Unit> {
|
||||
return option(propertyName, { }, ClickHandler(this, runnable))
|
||||
}
|
||||
|
||||
protected fun string(propertyName: String, default: () -> String): ManagedOption<String> {
|
||||
return option(propertyName, default, StringHandler(this))
|
||||
}
|
||||
protected fun string(propertyName: String, default: () -> String): ManagedOption<String> {
|
||||
return option(propertyName, default, StringHandler(this))
|
||||
}
|
||||
|
||||
|
||||
fun reloadGui() {
|
||||
latestGuiAppender?.reloadables?.forEach { it() }
|
||||
}
|
||||
fun reloadGui() {
|
||||
latestGuiAppender?.reloadables?.forEach { it() }
|
||||
}
|
||||
|
||||
val translationKey get() = "firmament.config.${name}"
|
||||
val labelText = Text.translatable(translationKey)
|
||||
val translationKey get() = "firmament.config.${name}"
|
||||
val labelText = Text.translatable(translationKey)
|
||||
|
||||
fun getConfigEditor(parent: Screen? = null): Screen {
|
||||
var screen: Screen? = null
|
||||
val guiapp = GuiAppender(400) { requireNotNull(screen) { "Screen Accessor called too early" } }
|
||||
latestGuiAppender = guiapp
|
||||
guiapp.appendFullRow(RowComponent(
|
||||
FirmButtonComponent(TextComponent("←")) {
|
||||
if (parent != null) {
|
||||
save()
|
||||
setScreenLater(parent)
|
||||
} else {
|
||||
AllConfigsGui.showAllGuis()
|
||||
}
|
||||
}
|
||||
))
|
||||
sortedOptions.forEach { it.appendToGui(guiapp) }
|
||||
guiapp.reloadables.forEach { it() }
|
||||
val component = CenterComponent(PanelComponent(ScrollPanelComponent(400, 300, ColumnComponent(guiapp.panel)), 10, PanelComponent.DefaultBackgroundRenderer.VANILLA))
|
||||
screen = object : GuiComponentWrapper(GuiContext(component)) {
|
||||
override fun close() {
|
||||
if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) {
|
||||
client!!.setScreen(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return screen
|
||||
}
|
||||
fun getConfigEditor(parent: Screen? = null): Screen {
|
||||
var screen: Screen? = null
|
||||
val guiapp = GuiAppender(400) { requireNotNull(screen) { "Screen Accessor called too early" } }
|
||||
latestGuiAppender = guiapp
|
||||
guiapp.appendFullRow(RowComponent(
|
||||
FirmButtonComponent(TextComponent("←")) {
|
||||
if (parent != null) {
|
||||
save()
|
||||
setScreenLater(parent)
|
||||
} else {
|
||||
AllConfigsGui.showAllGuis()
|
||||
}
|
||||
}
|
||||
))
|
||||
sortedOptions.forEach { it.appendToGui(guiapp) }
|
||||
guiapp.reloadables.forEach { it() }
|
||||
val component = CenterComponent(PanelComponent(ScrollPanelComponent(400, 300, ColumnComponent(guiapp.panel)),
|
||||
10,
|
||||
PanelComponent.DefaultBackgroundRenderer.VANILLA))
|
||||
screen = object : GuiComponentWrapper(GuiContext(component)) {
|
||||
override fun close() {
|
||||
if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) {
|
||||
client!!.setScreen(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return screen
|
||||
}
|
||||
|
||||
fun showConfigEditor(parent: Screen? = null) {
|
||||
setScreenLater(getConfigEditor(parent))
|
||||
}
|
||||
fun showConfigEditor(parent: Screen? = null) {
|
||||
setScreenLater(getConfigEditor(parent))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import net.minecraft.text.Text
|
||||
import moe.nea.firmament.Firmament
|
||||
|
||||
class ManagedOption<T : Any>(
|
||||
val element: ManagedConfigElement,
|
||||
val element: ManagedConfig,
|
||||
val propertyName: String,
|
||||
val default: () -> T,
|
||||
val handler: ManagedConfig.OptionHandler<T>
|
||||
|
||||
Reference in New Issue
Block a user