feat: add colour config options

This commit is contained in:
Linnea Gräf
2025-07-04 19:30:31 +02:00
parent 89642c2443
commit 918ee6ab5b
6 changed files with 190 additions and 18 deletions

View File

@@ -1,6 +1,7 @@
package moe.nea.firmament.compat.moulconfig
import com.google.auto.service.AutoService
import io.github.notenoughupdates.moulconfig.ChromaColour
import io.github.notenoughupdates.moulconfig.Config
import io.github.notenoughupdates.moulconfig.DescriptionRendereringBehaviour
import io.github.notenoughupdates.moulconfig.Social
@@ -20,6 +21,7 @@ import io.github.notenoughupdates.moulconfig.gui.editors.ComponentEditor
import io.github.notenoughupdates.moulconfig.gui.editors.GuiOptionEditorAccordion
import io.github.notenoughupdates.moulconfig.gui.editors.GuiOptionEditorBoolean
import io.github.notenoughupdates.moulconfig.gui.editors.GuiOptionEditorButton
import io.github.notenoughupdates.moulconfig.gui.editors.GuiOptionEditorColour
import io.github.notenoughupdates.moulconfig.gui.editors.GuiOptionEditorDropdown
import io.github.notenoughupdates.moulconfig.gui.editors.GuiOptionEditorText
import io.github.notenoughupdates.moulconfig.observer.GetSetter
@@ -39,6 +41,7 @@ import moe.nea.firmament.gui.config.AllConfigsGui
import moe.nea.firmament.gui.config.BooleanHandler
import moe.nea.firmament.gui.config.ChoiceHandler
import moe.nea.firmament.gui.config.ClickHandler
import moe.nea.firmament.gui.config.ColourHandler
import moe.nea.firmament.gui.config.DurationHandler
import moe.nea.firmament.gui.config.FirmamentConfigScreenProvider
import moe.nea.firmament.gui.config.HudMeta
@@ -186,6 +189,26 @@ class MCConfigEditorIntegration : FirmamentConfigScreenProvider {
}
}
}
register(ColourHandler::class.java) { handler, option, accordionId, configObject ->
object : ProcessedEditableOptionFirm<ChromaColour>(option, accordionId, configObject) {
override fun fromT(t: ChromaColour): Any {
return t
}
override fun toT(any: Any?): ChromaColour? {
return any as ChromaColour?
}
override fun createEditor(): GuiOptionEditor {
return GuiOptionEditorColour(this)
}
override fun getType(): Type? {
return ChromaColour::class.java
}
}
}
register(ClickHandler::class.java) { handler, option, categoryAccordionId, configObject ->
object : ProcessedEditableOptionFirm<Unit>(option, categoryAccordionId, configObject) {
override fun createEditor(): GuiOptionEditor {

View File

@@ -9,6 +9,7 @@ import dev.isxander.yacl3.api.Option
import dev.isxander.yacl3.api.OptionDescription
import dev.isxander.yacl3.api.OptionGroup
import dev.isxander.yacl3.api.YetAnotherConfigLib
import dev.isxander.yacl3.api.controller.ColorControllerBuilder
import dev.isxander.yacl3.api.controller.ControllerBuilder
import dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder
import dev.isxander.yacl3.api.controller.EnumControllerBuilder
@@ -18,6 +19,8 @@ import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder
import dev.isxander.yacl3.api.controller.ValueFormatter
import dev.isxander.yacl3.gui.YACLScreen
import dev.isxander.yacl3.gui.tab.ListHolderWidget
import io.github.notenoughupdates.moulconfig.ChromaColour
import java.awt.Color
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
@@ -27,6 +30,7 @@ import net.minecraft.text.Text
import moe.nea.firmament.gui.config.BooleanHandler
import moe.nea.firmament.gui.config.ChoiceHandler
import moe.nea.firmament.gui.config.ClickHandler
import moe.nea.firmament.gui.config.ColourHandler
import moe.nea.firmament.gui.config.DurationHandler
import moe.nea.firmament.gui.config.EnumRenderer
import moe.nea.firmament.gui.config.FirmamentConfigScreenProvider
@@ -39,6 +43,8 @@ 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
import moe.nea.firmament.util.getRGBAWithoutAnimation
import moe.nea.firmament.util.toChromaWithoutAnimation
@AutoService(FirmamentConfigScreenProvider::class)
@@ -56,20 +62,22 @@ class YaclIntegration : FirmamentConfigScreenProvider {
OptionGroup.createBuilder()
.name(it.labelText)
.options(buildOptions(it.sortedOptions))
.build())
.build()
)
}
}
.build()
}
fun buildOptions(options: List<ManagedOption<*>>): Collection<Option<*>> =
options.map { buildOption(it) }
options.flatMap { buildOption(it) }
private fun <T : Any> buildOption(managedOption: ManagedOption<T>): Option<*> {
private fun <T : Any> buildOption(managedOption: ManagedOption<T>): Collection<Option<*>> {
val handler = managedOption.handler
val binding = Binding.generic(managedOption.default(),
managedOption::value,
{ managedOption.value = it; managedOption.element.save() })
val binding = Binding.generic(
managedOption.default(),
managedOption::value,
{ managedOption.value = it; managedOption.element.save() })
fun <T> createDefaultBinding(function: (Option<T>) -> ControllerBuilder<T>): Option.Builder<T> {
return Option.createBuilder<T>()
@@ -78,30 +86,72 @@ class YaclIntegration : FirmamentConfigScreenProvider {
.binding(binding as Binding<T>)
.controller { function(it) }
}
fun Option<out Any>.single() = listOf(this)
fun ButtonOption.Builder.single() = build().single()
fun Option.Builder<out Any>.single() = build().single()
when (handler) {
is ClickHandler -> return ButtonOption.createBuilder()
.name(managedOption.labelText)
.action { t, u ->
handler.runnable()
}
.build()
.single()
is HudMetaHandler -> return ButtonOption.createBuilder()
.name(managedOption.labelText)
.action { t, u ->
handler.openEditor(managedOption as ManagedOption<HudMeta>, t)
}
.build()
.single()
is ChoiceHandler<*> -> return createDefaultBinding {
createChoiceBinding(handler as ChoiceHandler<*>, managedOption as ManagedOption<*>, it as Option<*>)
}.build()
}.single()
is BooleanHandler -> return createDefaultBinding(TickBoxControllerBuilder::create).build()
is StringHandler -> return createDefaultBinding(StringControllerBuilder::create).build()
is ColourHandler -> {
managedOption as ManagedOption<ChromaColour>
val colorBinding =
Binding.generic(
managedOption.default().getRGBAWithoutAnimation(),
{ managedOption.value.getRGBAWithoutAnimation() },
{
managedOption.value =
it.toChromaWithoutAnimation(managedOption.value.timeForFullRotationInMillis)
managedOption.element.save()
})
val speedBinding =
Binding.generic(
managedOption.default().timeForFullRotationInMillis,
{ managedOption.value.timeForFullRotationInMillis },
{
managedOption.value = managedOption.value.copy(timeForFullRotationInMillis = it)
managedOption.element.save()
}
)
return listOf(
Option.createBuilder<Color>()
.name(managedOption.labelText)
.binding(colorBinding)
.controller {
ColorControllerBuilder.create(it)
.allowAlpha(true)
}
.build(),
Option.createBuilder<Int>()
.name(managedOption.labelText)
.binding(speedBinding)
.controller { IntegerSliderControllerBuilder.create(it).range(0, 60_000).step(10) }
.build(),
)
}
is BooleanHandler -> return createDefaultBinding(TickBoxControllerBuilder::create).single()
is StringHandler -> return createDefaultBinding(StringControllerBuilder::create).single()
is IntegerHandler -> return createDefaultBinding {
IntegerSliderControllerBuilder.create(it).range(handler.min, handler.max).step(1)
}.build()
}.single()
is DurationHandler -> return Option.createBuilder<Double>()
.name(managedOption.labelText)
@@ -112,13 +162,13 @@ class YaclIntegration : FirmamentConfigScreenProvider {
.step(0.1)
.range(handler.min.toDouble(DurationUnit.SECONDS), handler.max.toDouble(DurationUnit.SECONDS))
}
.build()
.single()
is KeyBindingHandler -> return createDefaultBinding {
KeybindingBuilder(it, managedOption as ManagedOption<SavedKeyBinding>)
}.build()
}.single()
else -> return LabelOption.create(Text.literal("This option is currently unhandled for this config menu. Please report this as a bug."))
else -> return listOf(LabelOption.create(Text.literal("This option is currently unhandled for this config menu. Please report this as a bug.")))
}
}

View File

@@ -1,12 +1,13 @@
package moe.nea.firmament.features.items
import io.github.notenoughupdates.moulconfig.ChromaColour
import me.shedaniel.math.Color
import net.minecraft.util.hit.BlockHitResult
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC
import net.minecraft.util.hit.BlockHitResult
import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.util.extraAttributes
import moe.nea.firmament.util.render.RenderInWorldContext
import moe.nea.firmament.util.skyBlockId
@@ -19,6 +20,7 @@ object EtherwarpOverlay : FirmamentFeature {
object TConfig : ManagedConfig(identifier, Category.ITEMS) {
var etherwarpOverlay by toggle("etherwarp-overlay") { false }
var cube by toggle("cube") { true }
val cubeColour by colour("cube-colour") { ChromaColour.fromStaticRGB(172, 0, 255, 60) }
var wireframe by toggle("wireframe") { false }
}
@@ -44,7 +46,7 @@ object EtherwarpOverlay : FirmamentFeature {
if (!world.getBlockState(blockPos.up()).isAir) return
if (!world.getBlockState(blockPos.up(2)).isAir) return
RenderInWorldContext.renderInWorld(event) {
if (TConfig.cube) block(blockPos, Color.ofRGBA(172, 0, 255, 60).color)
if (TConfig.cube) block(blockPos, TConfig.cubeColour.getEffectiveColourRGB())
if (TConfig.wireframe) wireframeCube(blockPos, 10f)
}
}

View File

@@ -0,0 +1,82 @@
package moe.nea.firmament.gui.config
import io.github.notenoughupdates.moulconfig.ChromaColour
import io.github.notenoughupdates.moulconfig.gui.component.ColorSelectComponent
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
class ColourHandler(val config: ManagedConfig) :
ManagedConfig.OptionHandler<ChromaColour> {
@Serializable
data class ChromaDelegate(
@SerialName("h")
val hue: Float,
@SerialName("s")
val saturation: Float,
@SerialName("b")
val brightness: Float,
@SerialName("a")
val alpha: Int,
@SerialName("c")
val timeForFullRotationInMillis: Int,
) {
constructor(delegate: ChromaColour) : this(
delegate.hue,
delegate.saturation,
delegate.brightness,
delegate.alpha,
delegate.timeForFullRotationInMillis
)
fun into(): ChromaColour = ChromaColour(hue, saturation, brightness, alpha, timeForFullRotationInMillis)
}
object ChromaSerializer : KSerializer<ChromaColour> {
override val descriptor: SerialDescriptor
get() = SerialDescriptor("FirmChromaColour", ChromaDelegate.serializer().descriptor)
override fun serialize(
encoder: Encoder,
value: ChromaColour
) {
encoder.encodeSerializableValue(ChromaDelegate.serializer(), ChromaDelegate(value))
}
override fun deserialize(decoder: Decoder): ChromaColour {
return decoder.decodeSerializableValue(ChromaDelegate.serializer()).into()
}
}
override fun toJson(element: ChromaColour): JsonElement? {
return Json.encodeToJsonElement(ChromaSerializer, element)
}
override fun fromJson(element: JsonElement): ChromaColour {
return Json.decodeFromJsonElement(ChromaSerializer, element)
}
override fun emitGuiElements(
opt: ManagedOption<ChromaColour>,
guiAppender: GuiAppender
) {
guiAppender.appendLabeledRow(
opt.labelText,
ColorSelectComponent(
0,
0,
opt.value.toLegacyString(),
{
opt.value = ChromaColour.forLegacyString(it)
config.save()
},
{ }
)
)
}
}

View File

@@ -1,6 +1,7 @@
package moe.nea.firmament.gui.config
import com.mojang.serialization.Codec
import io.github.notenoughupdates.moulconfig.ChromaColour
import io.github.notenoughupdates.moulconfig.gui.CloseEventListener
import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper
import io.github.notenoughupdates.moulconfig.gui.GuiContext
@@ -118,6 +119,10 @@ abstract class ManagedConfig(
return option(propertyName, default, BooleanHandler(this))
}
protected fun colour(propertyName: String, default: ()-> ChromaColour) : ManagedOption<ChromaColour> {
return option(propertyName, default, ColourHandler(this))
}
protected fun <E> choice(
propertyName: String,
enumClass: Class<E>,

View File

@@ -0,0 +1,10 @@
package moe.nea.firmament.util
import io.github.notenoughupdates.moulconfig.ChromaColour
import java.awt.Color
fun ChromaColour.getRGBAWithoutAnimation() =
Color(ChromaColour.specialToSimpleRGB(toLegacyString()), true)
fun Color.toChromaWithoutAnimation(timeForFullRotationInMillis: Int = 0) =
ChromaColour.fromRGB(red, green, blue, timeForFullRotationInMillis, alpha)