aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-10-13 19:53:10 +0200
committerLinnea Gräf <nea@nea.moe>2024-10-13 19:53:10 +0200
commit87b851373071490bb371ba1160f85f0341579cb2 (patch)
tree45d267d83baad2e3cb6caad6127f6a4d40e7fcbf
parente6142bb93619dee768fc18b87ffdd28558d4bcab (diff)
downloadFirmament-87b851373071490bb371ba1160f85f0341579cb2.tar.gz
Firmament-87b851373071490bb371ba1160f85f0341579cb2.tar.bz2
Firmament-87b851373071490bb371ba1160f85f0341579cb2.zip
Add YACL config menu
-rw-r--r--build.gradle.kts5
-rw-r--r--gradle/libs.versions.toml26
-rw-r--r--src/compat/yacl/java/KeybindingBuilder.kt16
-rw-r--r--src/compat/yacl/java/KeybindingController.kt71
-rw-r--r--src/compat/yacl/java/YaclIntegration.kt119
-rw-r--r--src/main/kotlin/gui/config/AllConfigsGui.kt71
-rw-r--r--src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt37
-rw-r--r--src/main/kotlin/gui/config/HudMetaHandler.kt47
-rw-r--r--src/main/kotlin/gui/config/KeyBindingHandler.kt168
-rw-r--r--src/main/kotlin/gui/config/KeyBindingStateManager.kt108
-rw-r--r--src/main/kotlin/keybindings/SavedKeyBinding.kt2
-rw-r--r--src/main/kotlin/repo/RepoManager.kt246
-rw-r--r--src/main/resources/assets/firmament/lang/en_us.json1
13 files changed, 589 insertions, 328 deletions
diff --git a/build.gradle.kts b/build.gradle.kts
index bb15a1f..20b077c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -85,6 +85,9 @@ allprojects {
maven("https://maven.azureaaron.net/snapshots")
maven("https://maven.azureaaron.net/releases")
maven("https://www.cursemaven.com")
+ maven("https://maven.isxander.dev/releases") {
+ name = "Xander Maven"
+ }
mavenLocal()
}
}
@@ -154,6 +157,7 @@ val SourceSet.modImplementationConfigurationName
val configuredSourceSet = createIsolatedSourceSet("configured")
val sodiumSourceSet = createIsolatedSourceSet("sodium")
val citResewnSourceSet = createIsolatedSourceSet("citresewn")
+val yaclSourceSet = createIsolatedSourceSet("yacl")
val shadowMe by configurations.creating {
exclude(group = "org.jetbrains.kotlin")
@@ -223,6 +227,7 @@ dependencies {
(citResewnSourceSet.modImplementationConfigurationName)(
innerJarsOf("citresewn", dependencies.create(libs.citresewn.get())).asFileTree)
(citResewnSourceSet.modImplementationConfigurationName)(libs.citresewn)
+ (yaclSourceSet.modImplementationConfigurationName)(libs.yacl)
// Actual dependencies
modCompileOnly(libs.rei.api) {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2f3c7cc..efb7c94 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -76,6 +76,9 @@ hypixelmodapi_fabric = "1.0.1+build.1+mc1.21"
# Update from https://github.com/shedaniel/fabric-asm or https://maven.shedaniel.me/me/shedaniel/mm/
manninghamMills = "2.4.1"
+# Update from https://docs.isxander.dev/yet-another-config-lib/installing-yacl
+yacl = "3.5.0+1.21-fabric"
+
[libraries]
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
fabric_loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric_loader" }
@@ -109,22 +112,23 @@ sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
freecammod = { module = "maven.modrinth:freecam", version.ref = "freecammod" }
citresewn = { module = "maven.modrinth:cit-resewn", version.ref = "citresewn" }
femalegender = { module = "maven.modrinth:female-gender", version.ref = "femalegender" }
+yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" }
[bundles]
runtime_required = [
- "architectury_fabric",
- "rei_fabric",
- "notenoughanimations",
- "femalegender",
- "hypixelmodapi_fabric",
+ "architectury_fabric",
+ "rei_fabric",
+ "notenoughanimations",
+ "femalegender",
+ "hypixelmodapi_fabric",
]
runtime_optional = [
- "devauth",
- "freecammod",
- "sodium",
-# "qolify",
- "ncr",
- "citresewn",
+ "devauth",
+ "freecammod",
+ "sodium",
+ # "qolify",
+ "ncr",
+ "citresewn",
]
[plugins]
diff --git a/src/compat/yacl/java/KeybindingBuilder.kt b/src/compat/yacl/java/KeybindingBuilder.kt
new file mode 100644
index 0000000..322ddff
--- /dev/null
+++ b/src/compat/yacl/java/KeybindingBuilder.kt
@@ -0,0 +1,16 @@
+package moe.nea.firmament.compat.yacl
+
+import dev.isxander.yacl3.api.Controller
+import dev.isxander.yacl3.api.Option
+import dev.isxander.yacl3.api.controller.ControllerBuilder
+import moe.nea.firmament.gui.config.ManagedOption
+import moe.nea.firmament.keybindings.SavedKeyBinding
+
+class KeybindingBuilder(
+ val option: Option<SavedKeyBinding>,
+ val managedOption: ManagedOption<SavedKeyBinding>
+) : ControllerBuilder<SavedKeyBinding> {
+ override fun build(): Controller<SavedKeyBinding> {
+ return KeybindingController(option, managedOption)
+ }
+}
diff --git a/src/compat/yacl/java/KeybindingController.kt b/src/compat/yacl/java/KeybindingController.kt
new file mode 100644
index 0000000..6be9dd1
--- /dev/null
+++ b/src/compat/yacl/java/KeybindingController.kt
@@ -0,0 +1,71 @@
+package moe.nea.firmament.compat.yacl
+
+import dev.isxander.yacl3.api.Controller
+import dev.isxander.yacl3.api.Option
+import dev.isxander.yacl3.api.utils.Dimension
+import dev.isxander.yacl3.gui.AbstractWidget
+import dev.isxander.yacl3.gui.YACLScreen
+import dev.isxander.yacl3.gui.controllers.ControllerWidget
+import net.minecraft.text.Text
+import moe.nea.firmament.gui.config.KeyBindingHandler
+import moe.nea.firmament.gui.config.KeyBindingStateManager
+import moe.nea.firmament.gui.config.ManagedOption
+import moe.nea.firmament.keybindings.SavedKeyBinding
+
+class KeybindingController(
+ val option: Option<SavedKeyBinding>,
+ val managedOption: ManagedOption<SavedKeyBinding>,
+) : Controller<SavedKeyBinding> {
+ val handler = managedOption.handler as KeyBindingHandler
+ override fun option(): Option<SavedKeyBinding> {
+ return option
+ }
+
+ override fun formatValue(): Text {
+ return option.pendingValue().format()
+ }
+
+ override fun provideWidget(screen: YACLScreen, widgetDimension: Dimension<Int>): AbstractWidget {
+ lateinit var button: ControllerWidget<KeybindingController>
+ val sm = KeyBindingStateManager(
+ { option.pendingValue() },
+ { option.requestSet(it) },
+ { screen.focused = null },
+ { screen.focused = button }
+ )
+ button = object : ControllerWidget<KeybindingController>(this, screen, widgetDimension) {
+ override fun getHoveredControlWidth(): Int {
+ return 130
+ }
+
+ override fun getValueText(): Text {
+ return sm.label
+ }
+
+ override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
+ return sm.keyboardEvent(keyCode, true)
+ }
+
+ override fun keyReleased(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
+ return sm.keyboardEvent(keyCode, false)
+ }
+
+ override fun unfocus() {
+ sm.onLostFocus()
+ }
+
+ override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ if (button == 0 && isHovered) {
+ sm.onClick()
+ return true
+ }
+ return super.mouseClicked(mouseX, mouseY, button)
+ }
+ }
+ option.addListener { t, u ->
+ sm.updateLabel()
+ }
+ sm.updateLabel()
+ return button
+ }
+}
diff --git a/src/compat/yacl/java/YaclIntegration.kt b/src/compat/yacl/java/YaclIntegration.kt
new file mode 100644
index 0000000..6c9354a
--- /dev/null
+++ b/src/compat/yacl/java/YaclIntegration.kt
@@ -0,0 +1,119 @@
+package moe.nea.firmament.compat.yacl
+
+import com.google.auto.service.AutoService
+import dev.isxander.yacl3.api.Binding
+import dev.isxander.yacl3.api.ButtonOption
+import dev.isxander.yacl3.api.ConfigCategory
+import dev.isxander.yacl3.api.LabelOption
+import dev.isxander.yacl3.api.Option
+import dev.isxander.yacl3.api.YetAnotherConfigLib
+import dev.isxander.yacl3.api.controller.ControllerBuilder
+import dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder
+import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder
+import dev.isxander.yacl3.api.controller.StringControllerBuilder
+import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+import kotlin.time.DurationUnit
+import net.minecraft.client.gui.screen.Screen
+import net.minecraft.text.Text
+import moe.nea.firmament.gui.config.AllConfigsGui
+import moe.nea.firmament.gui.config.BooleanHandler
+import moe.nea.firmament.gui.config.ClickHandler
+import moe.nea.firmament.gui.config.DurationHandler
+import moe.nea.firmament.gui.config.FirmamentConfigScreenProvider
+import moe.nea.firmament.gui.config.HudMeta
+import moe.nea.firmament.gui.config.HudMetaHandler
+import moe.nea.firmament.gui.config.IntegerHandler
+import moe.nea.firmament.gui.config.KeyBindingHandler
+import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.gui.config.ManagedOption
+import moe.nea.firmament.gui.config.StringHandler
+import moe.nea.firmament.keybindings.SavedKeyBinding
+import moe.nea.firmament.util.FirmFormatters
+
+
+@AutoService(FirmamentConfigScreenProvider::class)
+class YaclIntegration : FirmamentConfigScreenProvider {
+ fun buildCategories() =
+ AllConfigsGui.allConfigs
+ .map(::buildCategory)
+
+ private fun buildCategory(managedConfig: ManagedConfig): ConfigCategory {
+ return ConfigCategory.createBuilder()
+ .name(managedConfig.labelText)
+ .also {
+ it.rootGroupBuilder()
+ .options(buildOptions(managedConfig.sortedOptions))
+ }
+ .build()
+ }
+
+ fun buildOptions(options: List<ManagedOption<*>>): Collection<Option<*>> =
+ options.map { buildOption(it) }
+
+ private fun <T : Any> buildOption(managedOption: ManagedOption<T>): Option<*> {
+ val handler = managedOption.handler
+ val binding = Binding.generic(managedOption.default(), managedOption::value, managedOption::value.setter)
+ fun <T> createDefaultBinding(function: (Option<T>) -> ControllerBuilder<T>): Option.Builder<T> {
+ return Option.createBuilder<T>()
+ .name(managedOption.labelText)
+ .binding(binding as Binding<T>)
+ .controller { function(it) }
+ }
+ when (handler) {
+ is ClickHandler -> return ButtonOption.createBuilder()
+ .name(managedOption.labelText)
+ .action { t, u ->
+ handler.runnable()
+ }
+ .build()
+
+ is HudMetaHandler -> return ButtonOption.createBuilder()
+ .name(managedOption.labelText)
+ .action { t, u ->
+ handler.openEditor(managedOption as ManagedOption<HudMeta>, t)
+ }
+ .build()
+
+ is BooleanHandler -> return createDefaultBinding(TickBoxControllerBuilder::create).build()
+ is StringHandler -> return createDefaultBinding(StringControllerBuilder::create).build()
+ is IntegerHandler -> return createDefaultBinding {
+ IntegerSliderControllerBuilder.create(it).range(handler.min, handler.max).step(1)
+ }.build()
+
+ is DurationHandler -> return Option.createBuilder<Double>()
+ .name(managedOption.labelText)
+ .binding((binding as Binding<Duration>).xmap({ it.toDouble(DurationUnit.SECONDS) }, { it.seconds }))
+ .controller {
+ DoubleSliderControllerBuilder.create(it)
+ .formatValue { Text.literal(FirmFormatters.formatTimespan(it.seconds)) }
+ .step(0.1)
+ .range(handler.min.toDouble(DurationUnit.SECONDS), handler.max.toDouble(DurationUnit.SECONDS))
+ }
+ .build()
+
+ is KeyBindingHandler -> return createDefaultBinding {
+ KeybindingBuilder(it, managedOption as ManagedOption<SavedKeyBinding>)
+ }.build()
+
+ else -> return LabelOption.create(Text.literal("This option is currently unhandled for this config menu. Please report this as a bug."))
+ }
+ }
+
+
+ fun buildConfig(): YetAnotherConfigLib {
+ return YetAnotherConfigLib.createBuilder()
+ .title(Text.literal("Firmament"))
+ .categories(buildCategories())
+ .build()
+ }
+
+ override val key: String
+ get() = "yacl"
+
+ override fun open(parent: Screen?): Screen {
+ return buildConfig().generateScreen(parent)
+ }
+
+}
diff --git a/src/main/kotlin/gui/config/AllConfigsGui.kt b/src/main/kotlin/gui/config/AllConfigsGui.kt
index 3091b2a..c72b8b0 100644
--- a/src/main/kotlin/gui/config/AllConfigsGui.kt
+++ b/src/main/kotlin/gui/config/AllConfigsGui.kt
@@ -12,39 +12,40 @@ import moe.nea.firmament.util.ScreenUtil.setScreenLater
object AllConfigsGui {
- val allConfigs
- get() = listOf(
- RepoManager.Config
- ) + FeatureManager.allFeatures.mapNotNull { it.config }
-
- fun <T> List<T>.toObservableList(): ObservableList<T> = ObservableList(this)
-
- class MainMapping(val allConfigs: List<ManagedConfig>) {
- @get:Bind("configs")
- val configs = allConfigs.map { EntryMapping(it) }.toObservableList()
-
- class EntryMapping(val config: ManagedConfig) {
- @Bind
- fun name() = Text.translatable("firmament.config.${config.name}").string
-
- @Bind
- fun openEditor() {
- config.showConfigEditor(MC.screen)
- }
- }
- }
-
- fun makeBuiltInScreen(parent: Screen? = null): Screen {
- return MoulConfigUtils.loadScreen("config/main", MainMapping(allConfigs), parent)
- }
-
- fun makeScreen(parent: Screen? = null): Screen {
- val provider = FirmamentConfigScreenProvider.providers.find { it.key == "builtin" }
- ?: FirmamentConfigScreenProvider.providers.first()
- return provider.open(parent)
- }
-
- fun showAllGuis() {
- setScreenLater(makeScreen())
- }
+ val allConfigs
+ get() = listOf(
+ RepoManager.Config
+ ) + FeatureManager.allFeatures.mapNotNull { it.config }
+
+ fun <T> List<T>.toObservableList(): ObservableList<T> = ObservableList(this)
+
+ class MainMapping(val allConfigs: List<ManagedConfig>) {
+ @get:Bind("configs")
+ val configs = allConfigs.map { EntryMapping(it) }.toObservableList()
+
+ class EntryMapping(val config: ManagedConfig) {
+ @Bind
+ fun name() = Text.translatable("firmament.config.${config.name}").string
+
+ @Bind
+ fun openEditor() {
+ config.showConfigEditor(MC.screen)
+ }
+ }
+ }
+
+ fun makeBuiltInScreen(parent: Screen? = null): Screen {
+ return MoulConfigUtils.loadScreen("config/main", MainMapping(allConfigs), parent)
+ }
+
+ fun makeScreen(parent: Screen? = null): Screen {
+ val wantedKey = if (RepoManager.Config.enableYacl) "yacl" else "builtin"
+ val provider = FirmamentConfigScreenProvider.providers.find { it.key == wantedKey }
+ ?: FirmamentConfigScreenProvider.providers.first()
+ return provider.open(parent)
+ }
+
+ fun showAllGuis() {
+ setScreenLater(makeScreen())
+ }
}
diff --git a/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt b/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt
index 582f701..82e151e 100644
--- a/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt
+++ b/src/main/kotlin/gui/config/FirmamentConfigScreenProvider.kt
@@ -6,22 +6,29 @@ import net.minecraft.client.gui.screen.Screen
import moe.nea.firmament.Firmament
interface FirmamentConfigScreenProvider {
- val key: String
- val isEnabled: Boolean get() = true
+ val key: String
+ val isEnabled: Boolean get() = true
- fun open(parent: Screen?): Screen
+ fun open(parent: Screen?): Screen
- companion object {
- private val loader = ServiceLoader.load(FirmamentConfigScreenProvider::class.java)
+ companion object {
+ private val loader = ServiceLoader.load(FirmamentConfigScreenProvider::class.java)
- val providers by lazy {
- loader.stream().asSequence().mapNotNull { service ->
- kotlin.runCatching { service.get() }
- .getOrElse {
- Firmament.logger.warn("Could not load config provider ${service.type()}", it)
- null
- }
- }.filter { it.isEnabled }.toList()
- }
- }
+ val providers by lazy {
+ loader.stream().asSequence().mapNotNull { service ->
+ kotlin.runCatching { service.get() }
+ .getOrElse {
+ Firmament.logger.warn("Could not load config provider ${service.type()}", it)
+ null
+ }
+ }.filter { it.isEnabled }
+ .sortedWith(Comparator.comparing(
+ { it.key },
+ Comparator<String> { left, right ->
+ if (left == "builtin") return@Comparator -1
+ if (right == "builtin") return@Comparator 1
+ return@Comparator left.compareTo(right)
+ })).toList()
+ }
+ }
}
diff --git a/src/main/kotlin/gui/config/HudMetaHandler.kt b/src/main/kotlin/gui/config/HudMetaHandler.kt
index 35c9d51..a9659ee 100644
--- a/src/main/kotlin/gui/config/HudMetaHandler.kt
+++ b/src/main/kotlin/gui/config/HudMetaHandler.kt
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.gui.config
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
@@ -7,6 +5,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement
+import net.minecraft.client.gui.screen.Screen
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import moe.nea.firmament.gui.FirmButtonComponent
@@ -14,26 +13,30 @@ import moe.nea.firmament.jarvis.JarvisIntegration
import moe.nea.firmament.util.MC
class HudMetaHandler(val config: ManagedConfig, val label: MutableText, val width: Int, val height: Int) :
- ManagedConfig.OptionHandler<HudMeta> {
- override fun toJson(element: HudMeta): JsonElement? {
- return Json.encodeToJsonElement(element.position)
- }
+ ManagedConfig.OptionHandler<HudMeta> {
+ override fun toJson(element: HudMeta): JsonElement? {
+ return Json.encodeToJsonElement(element.position)
+ }
+
+ override fun fromJson(element: JsonElement): HudMeta {
+ return HudMeta(Json.decodeFromJsonElement(element), label, width, height)
+ }
- override fun fromJson(element: JsonElement): HudMeta {
- return HudMeta(Json.decodeFromJsonElement(element), label, width, height)
- }
+ fun openEditor(option: ManagedOption<HudMeta>, oldScreen: Screen) {
+ MC.screen = JarvisIntegration.jarvis.getHudEditor(
+ oldScreen,
+ listOf(option.value)
+ )
+ }
- override fun emitGuiElements(opt: ManagedOption<HudMeta>, guiAppender: GuiAppender) {
- guiAppender.appendLabeledRow(
- opt.labelText,
- FirmButtonComponent(
- TextComponent(
- Text.stringifiedTranslatable("firmament.hud.edit", label).string),
- ) {
- MC.screen = JarvisIntegration.jarvis.getHudEditor(
- guiAppender.screenAccessor.invoke(),
- listOf(opt.value)
- )
- })
- }
+ override fun emitGuiElements(opt: ManagedOption<HudMeta>, guiAppender: GuiAppender) {
+ guiAppender.appendLabeledRow(
+ opt.labelText,
+ FirmButtonComponent(
+ TextComponent(
+ Text.stringifiedTranslatable("firmament.hud.edit", label).string),
+ ) {
+ openEditor(opt, guiAppender.screenAccessor())
+ })
+ }
}
diff --git a/src/main/kotlin/gui/config/KeyBindingHandler.kt b/src/main/kotlin/gui/config/KeyBindingHandler.kt
index c389cc9..7ec7e81 100644
--- a/src/main/kotlin/gui/config/KeyBindingHandler.kt
+++ b/src/main/kotlin/gui/config/KeyBindingHandler.kt
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.gui.config
import io.github.notenoughupdates.moulconfig.common.IMinecraft
@@ -13,137 +11,63 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement
-import net.minecraft.text.Text
-import net.minecraft.util.Formatting
import moe.nea.firmament.gui.FirmButtonComponent
import moe.nea.firmament.keybindings.FirmamentKeyBindings
import moe.nea.firmament.keybindings.SavedKeyBinding
class KeyBindingHandler(val name: String, val managedConfig: ManagedConfig) :
- ManagedConfig.OptionHandler<SavedKeyBinding> {
-
- override fun initOption(opt: ManagedOption<SavedKeyBinding>) {
- FirmamentKeyBindings.registerKeyBinding(name, opt)
- }
+ ManagedConfig.OptionHandler<SavedKeyBinding> {
- override fun toJson(element: SavedKeyBinding): JsonElement? {
- return Json.encodeToJsonElement(element)
- }
+ override fun initOption(opt: ManagedOption<SavedKeyBinding>) {
+ FirmamentKeyBindings.registerKeyBinding(name, opt)
+ }
- override fun fromJson(element: JsonElement): SavedKeyBinding {
- return Json.decodeFromJsonElement(element)
- }
+ override fun toJson(element: SavedKeyBinding): JsonElement? {
+ return Json.encodeToJsonElement(element)
+ }
- override fun emitGuiElements(opt: ManagedOption<SavedKeyBinding>, guiAppender: GuiAppender) {
- var editing = false
- var lastPressed = 0
- var lastPressedNonModifier = 0
- var label: String = ""
- var button: FirmButtonComponent? = null
- fun updateLabel() {
- var stroke = opt.value.format()
- if (editing) {
- stroke = Text.literal("")
- val (shift, alt, ctrl) = SavedKeyBinding.getMods(SavedKeyBinding.getModInt())
- if (shift) {
- stroke.append("SHIFT + ")
- }
- if (alt) {
- stroke.append("ALT + ")
- }
- if (ctrl) {
- stroke.append("CTRL + ")
- }
- stroke.append("???")
- stroke.styled { it.withColor(Formatting.YELLOW) }
- }
- label = (stroke).string
- managedConfig.save()
- }
- button = object : FirmButtonComponent(
- TextComponent(
- IMinecraft.instance.defaultFontRenderer,
- { label },
- 130,
- TextComponent.TextAlignment.LEFT,
- false,
- false
- ), action = {
- if (editing) {
- button!!.blur()
- } else {
- editing = true
- button!!.requestFocus()
- updateLabel()
- }
- }) {
- override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean {
- if (event is KeyboardEvent.KeyPressed) {
- return if (event.pressed) onKeyPressed(event.keycode, SavedKeyBinding.getModInt())
- else onKeyReleased(event.keycode, SavedKeyBinding.getModInt())
- }
- return super.keyboardEvent(event, context)
- }
+ override fun fromJson(element: JsonElement): SavedKeyBinding {
+ return Json.decodeFromJsonElement(element)
+ }
- override fun getBackground(context: GuiImmediateContext): NinePatch<MyResourceLocation> {
- if (editing) return activeBg
- return super.getBackground(context)
- }
+ override fun emitGuiElements(opt: ManagedOption<SavedKeyBinding>, guiAppender: GuiAppender) {
+ lateinit var button: FirmButtonComponent
+ val sm = KeyBindingStateManager(
+ { opt.value },
+ { opt.value = it },
+ { button.blur() },
+ { button.requestFocus() }
+ )
+ button = object : FirmButtonComponent(
+ TextComponent(
+ IMinecraft.instance.defaultFontRenderer,
+ { sm.label.string },
+ 130,
+ TextComponent.TextAlignment.LEFT,
+ false,
+ false
+ ), action = {
+ sm.onClick()
+ }) {
+ override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean {
+ if (event is KeyboardEvent.KeyPressed) {
+ return sm.keyboardEvent(event.keycode, event.pressed)
+ }
+ return super.keyboardEvent(event, context)
+ }
- fun onKeyPressed(ch: Int, modifiers: Int): Boolean {
- if (!editing) {
- return false
- }
- if (ch == GLFW.GLFW_KEY_ESCAPE) {
- lastPressedNonModifier = 0
- editing = false
- lastPressed = 0
- opt.value = SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN)
- updateLabel()
- blur()
- return true
- }
- if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT
- || ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT
- || ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL
- ) {
- lastPressed = ch
- } else {
- opt.value = SavedKeyBinding(
- ch, modifiers
- )
- editing = false
- blur()
- lastPressed = 0
- lastPressedNonModifier = 0
- }
- updateLabel()
- return true
- }
+ override fun getBackground(context: GuiImmediateContext): NinePatch<MyResourceLocation> {
+ if (sm.editing) return activeBg
+ return super.getBackground(context)
+ }
- override fun onLostFocus() {
- lastPressedNonModifier = 0
- editing = false
- lastPressed = 0
- updateLabel()
- }
- fun onKeyReleased(ch: Int, modifiers: Int): Boolean {
- if (!editing)
- return false
- if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) {
- opt.value = SavedKeyBinding(ch, modifiers)
- editing = false
- blur()
- lastPressed = 0
- lastPressedNonModifier = 0
- }
- updateLabel()
- return true
- }
- }
- updateLabel()
- guiAppender.appendLabeledRow(opt.labelText, button)
- }
+ override fun onLostFocus() {
+ sm.onLostFocus()
+ }
+ }
+ sm.updateLabel()
+ guiAppender.appendLabeledRow(opt.labelText, button)
+ }
}
diff --git a/src/main/kotlin/gui/config/KeyBindingStateManager.kt b/src/main/kotlin/gui/config/KeyBindingStateManager.kt
new file mode 100644
index 0000000..cc8178d
--- /dev/null
+++ b/src/main/kotlin/gui/config/KeyBindingStateManager.kt
@@ -0,0 +1,108 @@
+package moe.nea.firmament.gui.config
+
+import org.lwjgl.glfw.GLFW
+import net.minecraft.text.Text
+import net.minecraft.util.Formatting
+import moe.nea.firmament.keybindings.SavedKeyBinding
+
+class KeyBindingStateManager(
+ val value: () -> SavedKeyBinding,
+ val setValue: (key: SavedKeyBinding) -> Unit,
+ val blur: () -> Unit,
+ val requestFocus: () -> Unit,
+) {
+ var editing = false
+ var lastPressed = 0
+ var lastPressedNonModifier = 0
+ var label: Text = Text.literal("")
+
+ fun onClick() {
+ if (editing) {
+ editing = false
+ blur()
+ } else {
+ editing = true
+ requestFocus()
+ }
+ updateLabel()
+ }
+
+ fun keyboardEvent(keyCode: Int, pressed: Boolean): Boolean {
+ return if (pressed) onKeyPressed(keyCode, SavedKeyBinding.getModInt())
+ else onKeyReleased(keyCode, SavedKeyBinding.getModInt())
+ }
+
+ fun onKeyPressed(ch: Int, modifiers: Int): Boolean {
+ if (!editing) {
+ return false
+ }
+ if (ch == GLFW.GLFW_KEY_ESCAPE) {
+ lastPressedNonModifier = 0
+ editing = false
+ lastPressed = 0
+ setValue(SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN))
+ updateLabel()
+ blur()
+ return true
+ }
+ if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT
+ || ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT
+ || ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL
+ ) {
+ lastPressed = ch
+ } else {
+ setValue(SavedKeyBinding(
+ ch, modifiers
+ ))
+ editing = false
+ blur()
+ lastPressed = 0
+ lastPressedNonModifier = 0
+ }
+ updateLabel()
+ return true
+ }
+
+ fun onLostFocus() {
+ lastPressedNonModifier = 0
+ editing = false
+ lastPressed = 0
+ updateLabel()
+ }
+
+ fun onKeyReleased(ch: Int, modifiers: Int): Boolean {
+ if (!editing)
+ return false
+ if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) {
+ setValue(SavedKeyBinding(ch, modifiers))
+ editing = false
+ blur()
+ lastPressed = 0
+ lastPressedNonModifier = 0
+ }
+ updateLabel()
+ return true
+ }
+
+ fun updateLabel() {
+ var stroke = value().format()
+ if (editing) {
+ stroke = Text.literal("")
+ val (shift, ctrl, alt) = SavedKeyBinding.getMods(SavedKeyBinding.getModInt())
+ if (shift) {
+ stroke.append("SHIFT + ")
+ }
+ if (alt) {
+ stroke.append("ALT + ")
+ }
+ if (ctrl) {
+ stroke.append("CTRL + ")
+ }
+ stroke.append("???")
+ stroke.styled { it.withColor(Formatting.YELLOW) }
+ }
+ label = stroke
+ }
+
+
+}
diff --git a/src/main/kotlin/keybindings/SavedKeyBinding.kt b/src/main/kotlin/keybindings/SavedKeyBinding.kt
index 8607fd0..5bca87e 100644
--- a/src/main/kotlin/keybindings/SavedKeyBinding.kt
+++ b/src/main/kotlin/keybindings/SavedKeyBinding.kt
@@ -32,7 +32,7 @@ data class SavedKeyBinding(
return Triple(
modifiers and GLFW.GLFW_MOD_SHIFT != 0,
modifiers and GLFW.GLFW_MOD_CONTROL != 0,
- modifiers and GLFW.GLFW_MOD_ALT != 0
+ modifiers and GLFW.GLFW_MOD_ALT != 0,
)
}
diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt
index f0da397..4c25daa 100644
--- a/src/main/kotlin/repo/RepoManager.kt
+++ b/src/main/kotlin/repo/RepoManager.kt
@@ -19,127 +19,129 @@ import moe.nea.firmament.util.MinecraftDispatcher
import moe.nea.firmament.util.SkyblockId
object RepoManager {
- object Config : ManagedConfig("repo") {
- var username by string("username") { "NotEnoughUpdates" }
- var reponame by string("reponame") { "NotEnoughUpdates-REPO" }
- var branch by string("branch") { "master" }
- val autoUpdate by toggle("autoUpdate") { true }
- val reset by button("reset") {
- username = "NotEnoughUpdates"
- reponame = "NotEnoughUpdates-REPO"
- branch = "master"
- save()
- }
-
- val disableItemGroups by toggle("disable-item-groups") { true }
- val reload by button("reload") {
- save()
- RepoManager.reload()
- }
- val redownload by button("redownload") {
- save()
- RepoManager.launchAsyncUpdate(true)
- }
- }
-
- val currentDownloadedSha by RepoDownloadManager::latestSavedVersionHash
-
- var recentlyFailedToUpdateItemList = false
-
- val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
- registerReloadListener(ItemCache)
- registerReloadListener(ExpLadders)
- registerReloadListener(ItemNameLookup)
- ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this))
- registerReloadListener {
- Firmament.coroutineScope.launch(MinecraftDispatcher) {
- if (!trySendClientboundUpdateRecipesPacket()) {
- logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
- recentlyFailedToUpdateItemList = true
- }
- }
- }
- }
-
- val essenceRecipeProvider = EssenceRecipeProvider()
- val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider)
-
- init {
- neuRepo.registerReloadListener(essenceRecipeProvider)
- neuRepo.registerReloadListener(recipeCache)
- }
-
- fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes }
-
- fun getRecipesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.recipes[skyblockId] ?: setOf()
- fun getUsagesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.usages[skyblockId] ?: setOf()
-
- private fun trySendClientboundUpdateRecipesPacket(): Boolean {
- return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes(
- SynchronizeRecipesS2CPacket(mutableListOf())
- ) != null
- }
-
- init {
- ClientTickEvents.START_WORLD_TICK.register(ClientTickEvents.StartWorldTick {
- if (recentlyFailedToUpdateItemList && trySendClientboundUpdateRecipesPacket())
- recentlyFailedToUpdateItemList = false
- })
- }
-
- fun getNEUItem(skyblockId: SkyblockId): NEUItem? = neuRepo.items.getItemBySkyblockId(skyblockId.neuItem)
-
- fun launchAsyncUpdate(force: Boolean = false) {
- Firmament.coroutineScope.launch {
- ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar
- ItemCache.ReloadProgressHud.isEnabled = true
- try {
- RepoDownloadManager.downloadUpdate(force)
- ItemCache.ReloadProgressHud.reportProgress("Download complete", 1, 1)
- } finally {
- ItemCache.ReloadProgressHud.isEnabled = false
- }
- reload()
- }
- }
-
- fun reload() {
- try {
- ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk",
- 0,
- -1) // TODO: replace with a proper boundy bar
- ItemCache.ReloadProgressHud.isEnabled = true
- neuRepo.reload()
- } catch (exc: NEURepositoryException) {
- MinecraftClient.getInstance().player?.sendMessage(
- Text.literal("Failed to reload repository. This will result in some mod features not working.")
- )
- ItemCache.ReloadProgressHud.isEnabled = false
- exc.printStackTrace()
- }
- }
-
- fun initialize() {
- if (Config.autoUpdate) {
- launchAsyncUpdate()
- } else {
- reload()
- }
- }
-
- fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? {
- val parts = skyblockId.neuItem.split(";")
- if (parts.size != 2) {
- return null
- }
- val (petId, rarityIndex) = parts
- if (!rarityIndex.all { it.isDigit() }) {
- return null
- }
- val intIndex = rarityIndex.toInt()
- if (intIndex !in Rarity.values().indices) return null
- if (petId !in neuRepo.constants.petNumbers) return null
- return PetData(Rarity.values()[intIndex], petId, 0.0, true)
- }
+ object Config : ManagedConfig("repo") {
+ var username by string("username") { "NotEnoughUpdates" }
+ var reponame by string("reponame") { "NotEnoughUpdates-REPO" }
+ var branch by string("branch") { "master" }
+ val autoUpdate by toggle("autoUpdate") { true }
+ val reset by button("reset") {
+ username = "NotEnoughUpdates"
+ reponame = "NotEnoughUpdates-REPO"
+ branch = "master"
+ save()
+ }
+
+ val enableYacl by toggle("enable-yacl") { false }
+
+ val disableItemGroups by toggle("disable-item-groups") { true }
+ val reload by button("reload") {
+ save()
+ RepoManager.reload()
+ }
+ val redownload by button("redownload") {
+ save()
+ RepoManager.launchAsyncUpdate(true)
+ }
+ }
+
+ val currentDownloadedSha by RepoDownloadManager::latestSavedVersionHash
+
+ var recentlyFailedToUpdateItemList = false
+
+ val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
+ registerReloadListener(ItemCache)
+ registerReloadListener(ExpLadders)
+ registerReloadListener(ItemNameLookup)
+ ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this))
+ registerReloadListener {
+ Firmament.coroutineScope.launch(MinecraftDispatcher) {
+ if (!trySendClientboundUpdateRecipesPacket()) {
+ logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
+ recentlyFailedToUpdateItemList = true
+ }
+ }
+ }
+ }
+
+ val essenceRecipeProvider = EssenceRecipeProvider()
+ val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider)
+
+ init {
+ neuRepo.registerReloadListener(essenceRecipeProvider)
+ neuRepo.registerReloadListener(recipeCache)
+ }
+
+ fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes }
+
+ fun getRecipesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.recipes[skyblockId] ?: setOf()
+ fun getUsagesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.usages[skyblockId] ?: setOf()
+
+ private fun trySendClientboundUpdateRecipesPacket(): Boolean {
+ return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes(
+ SynchronizeRecipesS2CPacket(mutableListOf())
+ ) != null
+ }
+
+ init {
+ ClientTickEvents.START_WORLD_TICK.register(ClientTickEvents.StartWorldTick {
+ if (recentlyFailedToUpdateItemList && trySendClientboundUpdateRecipesPacket())
+ recentlyFailedToUpdateItemList = false
+ })
+ }
+
+ fun getNEUItem(skyblockId: SkyblockId): NEUItem? = neuRepo.items.getItemBySkyblockId(skyblockId.neuItem)
+
+ fun launchAsyncUpdate(force: Boolean = false) {
+ Firmament.coroutineScope.launch {
+ ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar
+ ItemCache.ReloadProgressHud.isEnabled = true
+ try {
+ RepoDownloadManager.downloadUpdate(force)
+ ItemCache.ReloadProgressHud.reportProgress("Download complete", 1, 1)
+ } finally {
+ ItemCache.ReloadProgressHud.isEnabled = false
+ }
+ reload()
+ }
+ }
+
+ fun reload() {
+ try {
+ ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk",
+ 0,
+ -1) // TODO: replace with a proper boundy bar
+ ItemCache.ReloadProgressHud.isEnabled = true
+ neuRepo.reload()
+ } catch (exc: NEURepositoryException) {
+ MinecraftClient.getInstance().player?.sendMessage(
+ Text.literal("Failed to reload repository. This will result in some mod features not working.")
+ )
+ ItemCache.ReloadProgressHud.isEnabled = false
+ exc.printStackTrace()
+ }
+ }
+
+ fun initialize() {
+ if (Config.autoUpdate) {
+ launchAsyncUpdate()
+ } else {
+ reload()
+ }
+ }
+
+ fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? {
+ val parts = skyblockId.neuItem.split(";")
+ if (parts.size != 2) {
+ return null
+ }
+ val (petId, rarityIndex) = parts
+ if (!rarityIndex.all { it.isDigit() }) {
+ return null
+ }
+ val intIndex = rarityIndex.toInt()
+ if (intIndex !in Rarity.values().indices) return null
+ if (petId !in neuRepo.constants.petNumbers) return null
+ return PetData(Rarity.values()[intIndex], petId, 0.0, true)
+ }
}
diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json
index 131eae2..1512b9d 100644
--- a/src/main/resources/assets/firmament/lang/en_us.json
+++ b/src/main/resources/assets/firmament/lang/en_us.json
@@ -73,6 +73,7 @@
"firmament.config.repo.username.hint": "NotEnoughUpdates",
"firmament.config.repo.reponame": "Repo Name",
"firmament.config.repo.reponame.hint": "NotEnoughUpdates-REPO",
+ "firmament.config.repo.enable-yacl": "Use YACL Config",
"firmament.config.repo.branch": "Repo Branch",
"firmament.config.repo.branch.hint": "dangerous",
"firmament.config.repo.reset": "Reset",