diff options
9 files changed, 158 insertions, 23 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e8ff4ab..a7d1f84 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ fabric_loader = "0.14.21" fabric_api = "0.83.0+1.20" fabric_kotlin = "1.9.4+kotlin.1.8.21" yarn = "1.20+build.1" -libgui = "8.0.0+1.20" +libgui = "8.0.1+1.20" rei = "12.0.622" devauth = "1.0.0" modmenu = "7.0.0" diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/ImagePreview.kt b/src/main/kotlin/moe/nea/firmament/features/chat/ImagePreview.kt index 5dcacc3..90edac3 100644 --- a/src/main/kotlin/moe/nea/firmament/features/chat/ImagePreview.kt +++ b/src/main/kotlin/moe/nea/firmament/features/chat/ImagePreview.kt @@ -5,8 +5,11 @@ import io.ktor.client.statement.* import io.ktor.utils.io.jvm.javaio.* import java.net.URL import java.util.* +import moe.nea.jarvis.api.Point import kotlinx.coroutines.Deferred +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.async +import kotlin.math.max import kotlin.math.min import net.minecraft.client.gui.screen.ChatScreen import net.minecraft.client.texture.NativeImage @@ -35,12 +38,13 @@ object ImagePreview : FirmamentFeature { val allowedHosts by string("allowed-hosts") { "cdn.discordapp.com,media.discordapp.com,media.discordapp.net,i.imgur.com" } val actualAllowedHosts get() = allowedHosts.split(",").map { it.trim() } val screenPercentage by integer("percentage", 10, 100) { 50 } + val position by position("position", 16 * 20, 9 * 20) { Point(0.0, 0.0) } } - fun isHostAllowed(host: String) = + private fun isHostAllowed(host: String) = TConfig.allowAllHosts || TConfig.actualAllowedHosts.any { it.equals(host, ignoreCase = true) } - fun isUrlAllowed(url: String) = isHostAllowed(url.removePrefix("https://").substringBefore("/")) + private fun isUrlAllowed(url: String) = isHostAllowed(url.removePrefix("https://").substringBefore("/")) override val config get() = TConfig val urlRegex = "https://[^. ]+\\.[^ ]+(\\.(png|gif|jpe?g))(\\?[^ ]*)?( |$)".toRegex() @@ -54,7 +58,7 @@ object ImagePreview : FirmamentFeature { val imageCache: MutableMap<String, Deferred<Image?>> = Collections.synchronizedMap(mutableMapOf<String, Deferred<Image?>>()) - fun tryCacheUrl(url: String) { + private fun tryCacheUrl(url: String) { if (!isUrlAllowed(url)) { return } @@ -81,6 +85,7 @@ object ImagePreview : FirmamentFeature { } } + @OptIn(ExperimentalCoroutinesApi::class) override fun onLoad() { ClientChatLineReceivedEvent.subscribe { it.replaceWith = it.text.transformEachRecursively { child -> @@ -122,16 +127,10 @@ object ImagePreview : FirmamentFeature { val imageFuture = imageCache[url] ?: return@subscribe if (!imageFuture.isCompleted) return@subscribe val image = imageFuture.getCompleted() ?: return@subscribe - val screen = MC.screen!! - val scale = - min( - 1F, - min( - (TConfig.screenPercentage / 100F * screen.width.toFloat()) / image.width, - screen.height.toFloat() / image.height - ) - ) it.drawContext.matrices.push() + val pos = TConfig.position + pos.applyTransformations(it.drawContext.matrices) + val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width)) it.drawContext.matrices.scale(scale, scale, 1F) it.drawContext.drawTexture( image.texture, diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt b/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt index f298c76..af83aee 100644 --- a/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt +++ b/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt @@ -22,10 +22,14 @@ 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.client.gui.screen.Screen import net.minecraft.text.Text -class GuiAppender(val width: Int) { +class GuiAppender(val width: Int, val screenAccessor: () -> Screen) { 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) { diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/HudMetaHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/HudMetaHandler.kt new file mode 100644 index 0000000..f8d2c3e --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/HudMetaHandler.kt @@ -0,0 +1,34 @@ +package moe.nea.firmament.gui.config + +import io.github.cottonmc.cotton.gui.widget.WButton +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.decodeFromJsonElement +import kotlinx.serialization.json.encodeToJsonElement +import net.minecraft.text.MutableText +import net.minecraft.text.Text +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) + } + + override fun fromJson(element: JsonElement): HudMeta { + return HudMeta(Json.decodeFromJsonElement(element), label, width, height) + } + + override fun emitGuiElements(opt: ManagedConfig.Option<HudMeta>, guiAppender: GuiAppender) { + guiAppender.appendLabeledRow(opt.labelText, WButton(Text.translatable("firmament.hud.edit", label)) + .also { + it.setOnClick { + MC.screen = JarvisIntegration.jarvis.getHudEditor( + guiAppender.screenAccessor.invoke(), + listOf(opt.value) + ) + } + }) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/JAnyHud.kt b/src/main/kotlin/moe/nea/firmament/gui/config/JAnyHud.kt new file mode 100644 index 0000000..5470f9b --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/config/JAnyHud.kt @@ -0,0 +1,46 @@ +package moe.nea.firmament.gui.config + +import moe.nea.jarvis.api.JarvisHud +import moe.nea.jarvis.api.JarvisScalable +import kotlinx.serialization.Serializable +import net.minecraft.text.Text + +@Serializable +data class HudPosition( + var x: Double, + var y: Double, + var scale: Float, +) + + +data class HudMeta( + val position: HudPosition, + private val label: Text, + private val width: Int, + private val height: Int, +) : JarvisScalable, JarvisHud { + override fun getX(): Double = position.x + + override fun setX(newX: Double) { + position.x = newX + } + + override fun getY(): Double = position.y + + override fun setY(newY: Double) { + position.y = newY + } + + override fun getLabel(): Text = label + + override fun getWidth(): Int = width + + override fun getHeight(): Int = height + + override fun getScale(): Float = position.scale + + override fun setScale(newScale: Float) { + position.scale = newScale + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt index 0204448..83d95ca 100644 --- a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt +++ b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt @@ -21,6 +21,7 @@ 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 moe.nea.jarvis.api.Point import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.JsonElement @@ -150,6 +151,19 @@ abstract class ManagedConfig(val name: String) { } + protected fun position( + propertyName: String, + width: Int, + height: Int, + default: () -> Point, + ): Option<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 integer( propertyName: String, min: Int, @@ -175,18 +189,26 @@ abstract class ManagedConfig(val name: String) { fun getConfigEditor(parent: Screen? = null): CottonClientScreen { val lwgd = LightweightGuiDescription() - val guiapp = GuiAppender(20) + var screen: Screen? = null + val guiapp = GuiAppender(20, { requireNotNull(screen) { "Screen Accessor called too early" } }) latestGuiAppender = guiapp guiapp.panel.insets = Insets.ROOT_PANEL sortedOptions.forEach { it.appendToGui(guiapp) } guiapp.reloadables.forEach { it() } lwgd.setRootPanel(guiapp.panel) - return object : CottonClientScreen(lwgd) { - override fun close() { - latestGuiAppender = null - MC.screen = parent + screen = + object : CottonClientScreen(lwgd) { + override fun init() { + latestGuiAppender = guiapp + super.init() + } + + override fun close() { + latestGuiAppender = null + MC.screen = parent + } } - } + return screen } fun showConfigEditor(parent: Screen? = null) { diff --git a/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt b/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt index 3dfb7d0..f691dba 100644 --- a/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt +++ b/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt @@ -1,21 +1,42 @@ package moe.nea.firmament.jarvis +import moe.nea.jarvis.api.Jarvis import moe.nea.jarvis.api.JarvisConfigOption +import moe.nea.jarvis.api.JarvisHud import moe.nea.jarvis.api.JarvisPlugin import net.minecraft.client.gui.screen.Screen import net.minecraft.text.Text import moe.nea.firmament.Firmament import moe.nea.firmament.features.FeatureManager +import moe.nea.firmament.gui.config.HudMeta +import moe.nea.firmament.gui.config.HudMetaHandler import moe.nea.firmament.repo.RepoManager class JarvisIntegration : JarvisPlugin { override fun getModId(): String = Firmament.MOD_ID - override fun getAllConfigOptions(): List<JarvisConfigOption> { - val configs = listOf( + companion object { + lateinit var jarvis: Jarvis + } + + override fun onInitialize(jarvis: Jarvis) { + Companion.jarvis = jarvis + } + + val configs + get() = listOf( RepoManager.Config ) + FeatureManager.allFeatures.mapNotNull { it.config } + + + override fun getAllHuds(): List<JarvisHud> { + return configs.flatMap { config -> + config.sortedOptions.mapNotNull { if (it.handler is HudMetaHandler) it.value as HudMeta else null } + } + } + + override fun getAllConfigOptions(): List<JarvisConfigOption> { return configs.flatMap { config -> config.sortedOptions.map { object : JarvisConfigOption { diff --git a/src/main/kotlin/moe/nea/firmament/util/propertyutil.kt b/src/main/kotlin/moe/nea/firmament/util/propertyutil.kt new file mode 100644 index 0000000..89b8251 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/util/propertyutil.kt @@ -0,0 +1,7 @@ +package moe.nea.firmament.util + +import kotlin.properties.ReadOnlyProperty + +fun <T, V, M> ReadOnlyProperty<T, V>.map(mapper: (V) -> M): ReadOnlyProperty<T, M> { + return ReadOnlyProperty { thisRef, property -> mapper(this@map.getValue(thisRef, property)) } +} diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index dfd2fa3..ca12967 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -71,5 +71,7 @@ "firmament.config.image-preview.enabled": "Enable Image Preview", "firmament.config.image-preview.allow-all-hosts": "Allow all Image Hosts", "firmament.config.image-preview.allowed-hosts": "Allowed Image Hosts", - "firmament.config.image-preview.percentage": "Image Width (Percentage of screen)" + "firmament.config.image-preview.percentage": "Image Width (Percentage of screen)", + "firmament.config.image-preview.position": "Chat Image Preview", + "firmament.hud.edit": "Edit %s" } |