From cd4224f3ae4281f3fe447827894daeebae9a5a90 Mon Sep 17 00:00:00 2001 From: Eclipse-5214 Date: Tue, 4 Aug 2026 22:01:04 -0400 Subject: [PATCH 1/2] feat(compat): stella compatibility --- gradle/fabric/26.1.versions.toml | 4 +- gradle/fabric/26.2.versions.toml | 4 +- .../internal/OneConfigMixinInit.java | 3 + .../mixin/compat/stella/Mixin_Stella.java | 20 ++ .../oneconfig/internal/compat/CompatLoader.kt | 1 + .../oneconfig/internal/compat/StellaCompat.kt | 219 ++++++++++++++++++ minecraft/stonecutter.gradle.kts | 1 + 7 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java create mode 100644 minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt diff --git a/gradle/fabric/26.1.versions.toml b/gradle/fabric/26.1.versions.toml index 966070e2b..ad7101667 100644 --- a/gradle/fabric/26.1.versions.toml +++ b/gradle/fabric/26.1.versions.toml @@ -12,6 +12,7 @@ yacl = "3.9.0+26.1-fabric" moulconfig = "3.11.0" odin = "0.2.2" skyblocker = "7OtCaJGB" +stella = "Ax39gj7z" vulkanmod = "0.6.8+26.1.2" @@ -32,6 +33,7 @@ modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu"} yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" } odin = { module = "maven.modrinth:odin", version.ref = "odin" } skyblocker = { module = "maven.modrinth:skyblocker-liap", version.ref = "skyblocker" } +stella = { module = "maven.modrinth:stella", version.ref = "stella"} moulconfig = { module = "org.notenoughupdates.moulconfig:common", version.ref = "moulconfig" } @@ -42,5 +44,5 @@ meowdding-lib = { module = "me.owdding.meowdding-lib:meowdding-lib", version.ref skyblock-api = { module = "tech.thatgravyboat:skyblock-api", version.ref = "skyblock-api" } [bundles] -compat = ["modmenu", "yacl", "odin", "skyblocker"] +compat = ["modmenu", "yacl", "odin", "skyblocker", "stella"] fabric-api = ["api-base", "lifecycle-events-v1", "transitive-access-wideners-v1", "command-api-v2", "key-mapping-api-v1", "resource-loader-v0", "resource-loader-v1"] diff --git a/gradle/fabric/26.2.versions.toml b/gradle/fabric/26.2.versions.toml index c58108c09..3e09ef612 100644 --- a/gradle/fabric/26.2.versions.toml +++ b/gradle/fabric/26.2.versions.toml @@ -11,6 +11,7 @@ modmenu = "20.0.0-beta.4" yacl = "3.9.4+26.2-fabric" moulconfig = "3.11.0" skyblocker = "PwRyrygz" +stella = "hhLUIC3p" [libraries] api-base = { module = "net.fabricmc.fabric-api:fabric-api-base", version.ref = "api-base" } @@ -24,7 +25,8 @@ modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu"} yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" } moulconfig = { module = "org.notenoughupdates.moulconfig:common", version.ref = "moulconfig" } skyblocker = { module = "maven.modrinth:skyblocker-liap", version.ref = "skyblocker" } +stella = { module = "maven.modrinth:stella", version.ref = "stella"} [bundles] -compat = ["modmenu", "yacl", "skyblocker"] +compat = ["modmenu", "yacl", "skyblocker", "stella"] fabric-api = ["api-base", "lifecycle-events-v1", "transitive-access-wideners-v1", "command-api-v2", "key-mapping-api-v1", "resource-loader-v1"] diff --git a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfigMixinInit.java b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfigMixinInit.java index af7ac1ac5..6cea8ee7c 100644 --- a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfigMixinInit.java +++ b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfigMixinInit.java @@ -116,6 +116,9 @@ public List getMixins() { mixins.add("compat.skyblocker.Mixin_SkyblockerScreenBuilder"); //? } + //? stella_compat + mixins.add("compat.stella.Mixin_Stella"); + //? apec_compat //mixins.add("compat.apec.Mixin_ApecMenu"); diff --git a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java new file mode 100644 index 000000000..6baa344f1 --- /dev/null +++ b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java @@ -0,0 +1,20 @@ +package org.polyfrost.oneconfig.internal.mixin.compat.stella; + +//? stella_compat { +import co.stellarskys.stella.Stella; +import org.polyfrost.oneconfig.internal.compat.StellaCompat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Pseudo +@Mixin(Stella.class) +public class Mixin_Stella { + @Inject(method = "onInitializeClient", at = @At("TAIL"), require = 0) + private void oneconfig$registerStella(CallbackInfo ci) { + StellaCompat.ensureRegistered(); + } +} +//? } \ No newline at end of file diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/CompatLoader.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/CompatLoader.kt index 3b49b3795..e6000b254 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/CompatLoader.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/CompatLoader.kt @@ -29,6 +29,7 @@ object CompatLoader { "net.azureaaron.dandelion", "com.odtheking.odin", "de.hysky.skyblocker", + "co.stellarskys.stella", "uk.co.hexeption.apec", "moe.nea.firmament.deps.moulconfig", "dev.tr7zw.trender", diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt new file mode 100644 index 000000000..0d2e0fc07 --- /dev/null +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt @@ -0,0 +1,219 @@ +package org.polyfrost.oneconfig.internal.compat + +//? stella_compat { +import co.stellarskys.stella.Stella +import co.stellarskys.stella.api.config.core.* +import co.stellarskys.stella.hud.HUDElement +import co.stellarskys.stella.hud.HUDManager +import co.stellarskys.stella.hud.HUDManager.customRenderers +import co.stellarskys.stella.utils.config +import co.stellarskys.stella.utils.render.Render2D +import co.stellarskys.stella.utils.render.Render2D.height +import co.stellarskys.stella.utils.render.Render2D.width +import net.minecraft.client.gui.GuiGraphicsExtractor +import org.apache.logging.log4j.LogManager +import org.polyfrost.oneconfig.api.config.v1.* +import org.polyfrost.oneconfig.api.config.v1.dsl.category +import org.polyfrost.oneconfig.api.config.v1.dsl.subcategory +import org.polyfrost.oneconfig.api.config.v1.dsl.visualizer +import org.polyfrost.oneconfig.api.hud.v1.OneConfigHudWrapper +import org.polyfrost.oneconfig.api.platform.v1.ModInfo +import org.polyfrost.oneconfig.internal.ui.hud.CompatOverlayRenderer +import java.awt.Color + +object StellaCompat { + private val LOGGER = LogManager.getLogger("OneConfig/Stella-Compat") + private val tree = Tree.tree() + + @JvmStatic + fun ensureRegistered() { + addConfigTree() + addHuds() + + config.registerListener { _, _ -> + for (node in tree.map.values) { + (node as? Property<*>)?.revaluateDisplay() + } + } + } + + // Settings + private fun addConfigTree() { + val info = ModInfo.loadedMods.firstOrNull { it.id == "stella" } + + tree.id = Stella.NAMESPACE + tree.title = "Stella" + info?.extractIconFile()?.let { tree.addMetadata("icon_path", it) } + + for ((catName, category) in config.categories) { + for (subcategory in category.subcategories.values) { + buildProperty(subcategory.configName, subcategory)?.let { property -> + property.category = catName + property.subcategory = subcategory.subName + hookShouldShow(property, subcategory) + tree.put(property) + } + + for ((key, element) in subcategory.elements) { + val property = buildProperty(key, element) ?: continue + property.category = catName + property.subcategory = subcategory.subName + hookShouldShow(property, element) + tree.put(property) + } + } + } + + CompatSnapshots.register(tree) + } + + private fun buildProperty(key: String, element: ConfigElement): Property<*>? { + val name = element.name + val desc = element.description + + return when (element) { + is Toggle -> Properties.functional( + getter = { element.value as Boolean }, + setter = { element.value = it }, + id = key, name = name, description = desc, type = Boolean::class.javaPrimitiveType + ).apply { visualizer = Visualizer.SwitchVisualizer::class.java } + + is ConfigSubcategory -> { + if (element.configName.isNotBlank()) { + Properties.functional( + getter = { element.value as Boolean }, + setter = { element.value = it }, + id = key, name = "Enable", description = desc, type = Boolean::class.javaPrimitiveType + ).apply { visualizer = Visualizer.SwitchVisualizer::class.java } + } else null + } + + is StepSlider -> Properties.functional( + getter = { element.value as Int }, + setter = { element.value = it }, + id = key, name = name, description = desc, type = Int::class.javaPrimitiveType, + ).apply { + visualizer = Visualizer.SliderVisualizer::class.java + addMetadata("min", element.min.toFloat()) + addMetadata("max", element.max.toFloat()) + addMetadata("step", element.step.toFloat()) + } + + is Slider -> Properties.functional( + getter = { element.value as Float }, + setter = { element.value = it }, + id = key, name = name, description = desc, type = Float::class.javaPrimitiveType, + ).apply { + visualizer = Visualizer.SliderVisualizer::class.java + addMetadata("min", element.min) + addMetadata("max", element.max) + } + + is Dropdown -> Properties.functional( + getter = { element.value as Int }, + setter = { element.value = it }, + id = key, name = name, description = desc, type = Int::class.javaPrimitiveType, + ).apply { + visualizer = Visualizer.DropdownVisualizer::class.java + addMetadata("options", element.options) + } + + is ColorPicker -> Properties.functional( + getter = { element.value as Color }, + setter = { element.value = it }, + id = key, name = name, description = desc, type = Color::class.java, + ).apply { visualizer = Visualizer.ColorVisualizer::class.java } + + is TextInput -> Properties.functional( + getter = { element.value as String }, + setter = { element.value = it }, + id = key, name = name, description = desc, type = String::class.java, + ).apply { visualizer = Visualizer.TextVisualizer::class.java } + + is Button -> Properties.dummy(id = key, name = name, description = desc).apply { + visualizer = Visualizer.ButtonVisualizer::class.java + addMetadata("runnable", Runnable { element.onClick?.invoke() }) + } + + is TextParagraph -> Properties.dummy(id = key, name = name, description = desc) + .apply { visualizer = Visualizer.InfoVisualizer::class.java } + + is Keybind -> null + else -> null + } + } + + private fun hookShouldShow (property: Property<*>, element: ConfigElement) { + val shouldShow = element.showIf ?: return + property.addDisplayCondition { + if (shouldShow(config)) Property.Display.SHOWN else Property.Display.HIDDEN + } + } + + // Hud + private class StellaHudWrapper(private val element: HUDElement): OneConfigHudWrapper { + override var id: String = element.id + override var name: String = element.id + override var modId: String = Stella.NAMESPACE + + override var x: Float + get() = element.x + set(value) { element.x = value } + + override var y: Float + get() = element.y + set(value) { element.y = value } + + override var scale: Float + get() = element.scale + set(value) { element.scale = value } + + override var hidden: Boolean + get() = !element.isEnabled() + set(value) { + val key = element.configKey ?: return + config.elementMap[key]?.value = !value + } + + override var scaledWidth: Float + get() = element.width * element.scale + set(_) {} + + override var scaledHeight: Float + get() = element.height * element.scale + set(_) {} + } + + private fun addHuds() { + for (element in HUDManager.elements.values) { + runCatching { StellaHudWrapper(element).register() } + .onFailure { LOGGER.error("Failed to register Stella HUD '${element.id}'", it) } + } + + CompatOverlayRenderer.register(::renderExamples) + } + + private fun renderExamples(ctx: GuiGraphicsExtractor) { + HUDManager.elements.values.forEach { element -> + if (!element.isEnabled()) return@forEach + + ctx.pose().pushMatrix() + ctx.pose().translate(element.x, element.y) + ctx.pose().scale(element.scale, element.scale) + + val custom = customRenderers[element.id] + if (custom != null) custom(ctx) + else { + if (element.width == 0 && element.height == 0) { + element.width = element.text.width() + 4 + element.height = element.text.height() + 6 + } + + Render2D.drawString(ctx, element.text, 2, 3, shadow = false) + } + + ctx.pose().popMatrix() + } + } +} +//? } diff --git a/minecraft/stonecutter.gradle.kts b/minecraft/stonecutter.gradle.kts index 0c277e754..93024397d 100644 --- a/minecraft/stonecutter.gradle.kts +++ b/minecraft/stonecutter.gradle.kts @@ -26,6 +26,7 @@ stonecutter { this["odin_compat"] = current.project.endsWith("-fabric") && catalogue.has("odin") this["skycubed_compat"] = current.project.endsWith("-fabric") && catalogue.has("skycubed") this["skyblocker_compat"] = current.project.endsWith("-fabric") && catalogue.has("skyblocker") + this["stella_compat"] = current.project.endsWith("-fabric") && catalogue.has("stella") this["apec_compat"] = current.project.endsWith("-fabric") && catalogue.has("apec") this["tr7zw_compat"] = true this["wwaypoints_compat"] = true From 824cafc76dbbc4a569a7bf6eac4969389fd8533e Mon Sep 17 00:00:00 2001 From: Eclipse-5214 Date: Thu, 6 Aug 2026 16:32:08 -0400 Subject: [PATCH 2/2] fix(compat): stella hud settings. fix cash on old versions. basically everthing else wyvest wanted --- gradle/fabric/26.1.versions.toml | 5 +- gradle/fabric/26.2.versions.toml | 5 +- .../mixin/compat/stella/Mixin_Stella.java | 2 +- .../oneconfig/internal/compat/StellaCompat.kt | 112 +++++++++++++++--- 4 files changed, 100 insertions(+), 24 deletions(-) diff --git a/gradle/fabric/26.1.versions.toml b/gradle/fabric/26.1.versions.toml index ad7101667..c9374e1f8 100644 --- a/gradle/fabric/26.1.versions.toml +++ b/gradle/fabric/26.1.versions.toml @@ -12,7 +12,7 @@ yacl = "3.9.0+26.1-fabric" moulconfig = "3.11.0" odin = "0.2.2" skyblocker = "7OtCaJGB" -stella = "Ax39gj7z" +stella = "d12aec9c69" vulkanmod = "0.6.8+26.1.2" @@ -33,7 +33,8 @@ modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu"} yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" } odin = { module = "maven.modrinth:odin", version.ref = "odin" } skyblocker = { module = "maven.modrinth:skyblocker-liap", version.ref = "skyblocker" } -stella = { module = "maven.modrinth:stella", version.ref = "stella"} +#stella = { module = "maven.modrinth:stella", version.ref = "stella"} I prefer modrinth but needed this to work befor I release +stella = { module = "com.github.Eclipse-5214.stella:stella-26.1", version.ref = "stella" } moulconfig = { module = "org.notenoughupdates.moulconfig:common", version.ref = "moulconfig" } diff --git a/gradle/fabric/26.2.versions.toml b/gradle/fabric/26.2.versions.toml index 3e09ef612..d16763d11 100644 --- a/gradle/fabric/26.2.versions.toml +++ b/gradle/fabric/26.2.versions.toml @@ -11,7 +11,7 @@ modmenu = "20.0.0-beta.4" yacl = "3.9.4+26.2-fabric" moulconfig = "3.11.0" skyblocker = "PwRyrygz" -stella = "hhLUIC3p" +stella = "d12aec9c69" [libraries] api-base = { module = "net.fabricmc.fabric-api:fabric-api-base", version.ref = "api-base" } @@ -25,7 +25,8 @@ modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu"} yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" } moulconfig = { module = "org.notenoughupdates.moulconfig:common", version.ref = "moulconfig" } skyblocker = { module = "maven.modrinth:skyblocker-liap", version.ref = "skyblocker" } -stella = { module = "maven.modrinth:stella", version.ref = "stella"} +#stella = { module = "maven.modrinth:stella", version.ref = "stella"} I prefer modrinth but needed this to work befor I release +stella = { module = "com.github.Eclipse-5214.stella:stella-26.1", version.ref = "stella" } [bundles] compat = ["modmenu", "yacl", "skyblocker", "stella"] diff --git a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java index 6baa344f1..2c86d1574 100644 --- a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java +++ b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/compat/stella/Mixin_Stella.java @@ -14,7 +14,7 @@ public class Mixin_Stella { @Inject(method = "onInitializeClient", at = @At("TAIL"), require = 0) private void oneconfig$registerStella(CallbackInfo ci) { - StellaCompat.ensureRegistered(); + StellaCompat.initialize(); } } //? } \ No newline at end of file diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt index 0d2e0fc07..2e529d1d5 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/compat/StellaCompat.kt @@ -12,29 +12,66 @@ import co.stellarskys.stella.utils.render.Render2D.height import co.stellarskys.stella.utils.render.Render2D.width import net.minecraft.client.gui.GuiGraphicsExtractor import org.apache.logging.log4j.LogManager -import org.polyfrost.oneconfig.api.config.v1.* +import org.polyfrost.oneconfig.api.config.v1.CompatSnapshots +import org.polyfrost.oneconfig.api.config.v1.ConfigManager +import org.polyfrost.oneconfig.api.config.v1.Properties +import org.polyfrost.oneconfig.api.config.v1.Property +import org.polyfrost.oneconfig.api.config.v1.Tree +import org.polyfrost.oneconfig.api.config.v1.Visualizer +import org.polyfrost.oneconfig.api.config.v1.backend.Backend import org.polyfrost.oneconfig.api.config.v1.dsl.category +import org.polyfrost.oneconfig.api.config.v1.dsl.saveFunction import org.polyfrost.oneconfig.api.config.v1.dsl.subcategory import org.polyfrost.oneconfig.api.config.v1.dsl.visualizer +import org.polyfrost.oneconfig.api.event.v1.EventManager import org.polyfrost.oneconfig.api.hud.v1.OneConfigHudWrapper +import org.polyfrost.oneconfig.api.hud.v1.events.HudEditorToggleEvent import org.polyfrost.oneconfig.api.platform.v1.ModInfo +import org.polyfrost.oneconfig.api.ui.v1.keybind.KeyModifiers +import org.polyfrost.oneconfig.api.ui.v1.keybind.OneConfigKeybind import org.polyfrost.oneconfig.internal.ui.hud.CompatOverlayRenderer import java.awt.Color +import java.util.function.Consumer object StellaCompat { private val LOGGER = LogManager.getLogger("OneConfig/Stella-Compat") + private val hudProperties = mutableMapOf>() private val tree = Tree.tree() + private var initialized = false @JvmStatic + fun initialize() { + CompatLoader.requireTranslations(skip = true) { + ensureRegistered() + } + } + fun ensureRegistered() { - addConfigTree() - addHuds() + if (initialized) return + initialized = true + + try { + addConfigTree() + addHuds() + } catch (_: Throwable) { + fallbackTree() + return + } config.registerListener { _, _ -> for (node in tree.map.values) { (node as? Property<*>)?.revaluateDisplay() } + for (property in hudProperties.values) { + property.revaluateDisplay() + } } + + EventManager.register(HudEditorToggleEvent::class.java, Consumer { event -> + HUDManager.shouldRenderHuds = !event.open + if (!event.open) runCatching { HUDManager.saveAllLayouts() } + .onFailure { LOGGER.warn("Failed to save Stella HUD layouts", it) } + }) } // Settings @@ -43,6 +80,7 @@ object StellaCompat { tree.id = Stella.NAMESPACE tree.title = "Stella" + tree.saveFunction = { config.save() } info?.extractIconFile()?.let { tree.addMetadata("icon_path", it) } for ((catName, category) in config.categories) { @@ -67,7 +105,20 @@ object StellaCompat { CompatSnapshots.register(tree) } + fun fallbackTree() { + val fallback = Tree.tree() + fallback.id = Stella.NAMESPACE + fallback.title = "Stella" + ModInfo.loadedMods.firstOrNull { it.id == "stella" }?.extractIconFile()?.let { fallback.addMetadata("icon_path", it) } + fallback.addMetadata("on_click") { runCatching { config.open() } } + fallback.addMetadata(Backend.UI_ONLY_METADATA, true) + fallback.addMetadata(Backend.UI_PLACEHOLDER_METADATA, true) + ConfigManager.active().register(fallback) + } + private fun buildProperty(key: String, element: ConfigElement): Property<*>? { + if (element.configName.isBlank()) return null + val name = element.name val desc = element.description @@ -78,15 +129,11 @@ object StellaCompat { id = key, name = name, description = desc, type = Boolean::class.javaPrimitiveType ).apply { visualizer = Visualizer.SwitchVisualizer::class.java } - is ConfigSubcategory -> { - if (element.configName.isNotBlank()) { - Properties.functional( - getter = { element.value as Boolean }, - setter = { element.value = it }, - id = key, name = "Enable", description = desc, type = Boolean::class.javaPrimitiveType - ).apply { visualizer = Visualizer.SwitchVisualizer::class.java } - } else null - } + is ConfigSubcategory -> Properties.functional( + getter = { element.value as Boolean }, + setter = { element.value = it }, + id = key, name = "Enable", description = desc, type = Boolean::class.javaPrimitiveType + ).apply { visualizer = Visualizer.SwitchVisualizer::class.java } is StepSlider -> Properties.functional( getter = { element.value as Int }, @@ -138,7 +185,17 @@ object StellaCompat { is TextParagraph -> Properties.dummy(id = key, name = name, description = desc) .apply { visualizer = Visualizer.InfoVisualizer::class.java } - is Keybind -> null + is Keybind -> { + val handler = element.value as Keybind.Handler + Properties.functional( + getter = { + val code = handler.keyCode() + OneConfigKeybind(if (code > 0) intArrayOf(code) else null, null, KeyModifiers.NONE, 0L) { false } + }, + setter = { kb -> handler.setCode(kb.keyCodes?.firstOrNull() ?: 0) }, + id = key, name = name, description = desc, type = OneConfigKeybind::class.java, + ).apply { visualizer = Visualizer.KeybindVisualizer::class.java } + } else -> null } } @@ -152,8 +209,10 @@ object StellaCompat { // Hud private class StellaHudWrapper(private val element: HUDElement): OneConfigHudWrapper { - override var id: String = element.id - override var name: String = element.id + private val confElement: ConfigElement? get() = config.elementMap[element.configKey] + + override var id: String = "stella/${element.id}" + override var name: String = confElement?.name ?: element.id override var modId: String = Stella.NAMESPACE override var x: Float @@ -170,10 +229,7 @@ object StellaCompat { override var hidden: Boolean get() = !element.isEnabled() - set(value) { - val key = element.configKey ?: return - config.elementMap[key]?.value = !value - } + set(value) { confElement?.value = !value } override var scaledWidth: Float get() = element.width * element.scale @@ -182,6 +238,8 @@ object StellaCompat { override var scaledHeight: Float get() = element.height * element.scale set(_) {} + + override fun linkedProperties(): List> = buildHudProperties(element) } private fun addHuds() { @@ -215,5 +273,21 @@ object StellaCompat { ctx.pose().popMatrix() } } + + private fun buildHudProperties(element: HUDElement): List> { + val dynamic = element.dynamicVisibility + val toggle = element.configKey?.let { buildOrGetProp(it, dynamic) } + val related = element.related.mapNotNull { buildOrGetProp(it, dynamic) } + return listOfNotNull(toggle) + related + } + + private fun buildOrGetProp(key: String, dynamic: Boolean): Property<*>? { + hudProperties[key]?.let { return it } + val element = config.elementMap[key] ?: return null + val property = buildProperty(key, element) ?: return null + if (dynamic) hookShouldShow(property, element) + hudProperties[key] = property + return property + } } //? }