From 7de0e8e7e09e3428c17ca9717c21c02469c31b76 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Wed, 16 Oct 2024 19:24:24 +0200 Subject: Add edit backpacks button to /firm storage --- src/main/kotlin/util/MoulConfigUtils.kt | 443 ++++++++++++++------------ src/main/kotlin/util/assertions.kt | 12 +- src/main/kotlin/util/render/DrawContextExt.kt | 8 + src/main/kotlin/util/uuid.kt | 8 +- 4 files changed, 270 insertions(+), 201 deletions(-) create mode 100644 src/main/kotlin/util/render/DrawContextExt.kt (limited to 'src/main/kotlin/util') diff --git a/src/main/kotlin/util/MoulConfigUtils.kt b/src/main/kotlin/util/MoulConfigUtils.kt index 00561d1..54528dd 100644 --- a/src/main/kotlin/util/MoulConfigUtils.kt +++ b/src/main/kotlin/util/MoulConfigUtils.kt @@ -1,12 +1,15 @@ - - package moe.nea.firmament.util +import io.github.notenoughupdates.moulconfig.common.IMinecraft import io.github.notenoughupdates.moulconfig.common.MyResourceLocation import io.github.notenoughupdates.moulconfig.gui.CloseEventListener +import io.github.notenoughupdates.moulconfig.gui.GuiComponent import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper import io.github.notenoughupdates.moulconfig.gui.GuiContext +import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext +import io.github.notenoughupdates.moulconfig.gui.MouseEvent import io.github.notenoughupdates.moulconfig.observer.GetSetter +import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext import io.github.notenoughupdates.moulconfig.xml.ChildCount import io.github.notenoughupdates.moulconfig.xml.XMLContext import io.github.notenoughupdates.moulconfig.xml.XMLGuiLoader @@ -19,6 +22,7 @@ import me.shedaniel.math.Color import org.w3c.dom.Element import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds +import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.screen.Screen import moe.nea.firmament.gui.BarComponent import moe.nea.firmament.gui.FirmButtonComponent @@ -26,205 +30,254 @@ import moe.nea.firmament.gui.FirmHoverComponent import moe.nea.firmament.gui.FixedComponent import moe.nea.firmament.gui.ImageComponent import moe.nea.firmament.gui.TickComponent +import moe.nea.firmament.util.render.isUntranslatedGuiDrawContext object MoulConfigUtils { - val firmUrl = "http://firmament.nea.moe/moulconfig" - val universe = XMLUniverse.getDefaultUniverse().also { uni -> - uni.registerMapper(java.awt.Color::class.java) { - if (it.startsWith("#")) { - val hexString = it.substring(1) - val hex = hexString.toInt(16) - if (hexString.length == 6) { - return@registerMapper java.awt.Color(hex) - } - if (hexString.length == 8) { - return@registerMapper java.awt.Color(hex, true) - } - error("Hexcolor $it needs to be exactly 6 or 8 hex digits long") - } - return@registerMapper java.awt.Color(it.toInt(), true) - } - uni.registerMapper(Color::class.java) { - val color = uni.mapXMLObject(it, java.awt.Color::class.java) - Color.ofRGBA(color.red, color.green, color.blue, color.alpha) - } - uni.registerLoader(object : XMLGuiLoader.Basic { - override fun getName(): QName { - return QName(firmUrl, "Bar") - } - - override fun createInstance(context: XMLContext<*>, element: Element): BarComponent { - return BarComponent( - context.getPropertyFromAttribute(element, QName("progress"), Double::class.java)!!, - context.getPropertyFromAttribute(element, QName("total"), Double::class.java)!!, - context.getPropertyFromAttribute(element, QName("fillColor"), Color::class.java)!!.get(), - context.getPropertyFromAttribute(element, QName("emptyColor"), Color::class.java)!!.get(), - ) - } - - override fun getChildCount(): ChildCount { - return ChildCount.NONE - } - - override fun getAttributeNames(): Map { - return mapOf("progress" to true, "total" to true, "emptyColor" to true, "fillColor" to true) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic { - override fun createInstance(context: XMLContext<*>, element: Element): FirmHoverComponent { - return FirmHoverComponent( - context.getChildFragment(element), - context.getPropertyFromAttribute(element, QName("lines"), List::class.java) as Supplier>, - context.getPropertyFromAttribute(element, QName("delay"), Duration::class.java, 0.6.seconds), - ) - } - - override fun getName(): QName { - return QName(firmUrl, "Hover") - } - - override fun getChildCount(): ChildCount { - return ChildCount.ONE - } - - override fun getAttributeNames(): Map { - return mapOf( - "lines" to true, - "delay" to false, - ) - } - - }) - uni.registerLoader(object : XMLGuiLoader.Basic { - override fun getName(): QName { - return QName(firmUrl, "Button") - } - - override fun createInstance(context: XMLContext<*>, element: Element): FirmButtonComponent { - return FirmButtonComponent( - context.getChildFragment(element), - context.getPropertyFromAttribute(element, QName("enabled"), Boolean::class.java) - ?: GetSetter.constant(true), - context.getPropertyFromAttribute(element, QName("noBackground"), Boolean::class.java, false), - context.getMethodFromAttribute(element, QName("onClick")), - ) - } - - override fun getChildCount(): ChildCount { - return ChildCount.ONE - } - - override fun getAttributeNames(): Map { - return mapOf("onClick" to true, "enabled" to false, "noBackground" to false) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic { - override fun createInstance(context: XMLContext<*>, element: Element): ImageComponent { - return ImageComponent( - context.getPropertyFromAttribute(element, QName("width"), Int::class.java)!!.get(), - context.getPropertyFromAttribute(element, QName("height"), Int::class.java)!!.get(), - context.getPropertyFromAttribute(element, QName("resource"), MyResourceLocation::class.java)!!, - context.getPropertyFromAttribute(element, QName("u1"), Float::class.java, 0f), - context.getPropertyFromAttribute(element, QName("u2"), Float::class.java, 1f), - context.getPropertyFromAttribute(element, QName("v1"), Float::class.java, 0f), - context.getPropertyFromAttribute(element, QName("v2"), Float::class.java, 1f), - ) - } - - override fun getName(): QName { - return QName(firmUrl, "Image") - } - - override fun getChildCount(): ChildCount { - return ChildCount.NONE - } - - override fun getAttributeNames(): Map { - return mapOf( - "width" to true, "height" to true, - "resource" to true, - "u1" to false, - "u2" to false, - "v1" to false, - "v2" to false, - ) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic { - override fun createInstance(context: XMLContext<*>, element: Element): TickComponent { - return TickComponent(context.getMethodFromAttribute(element, QName("tick"))) - } - - override fun getName(): QName { - return QName(firmUrl, "Tick") - } - - override fun getChildCount(): ChildCount { - return ChildCount.NONE - } - - override fun getAttributeNames(): Map { - return mapOf("tick" to true) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic { - override fun createInstance(context: XMLContext<*>, element: Element): FixedComponent { - return FixedComponent( - context.getPropertyFromAttribute(element, QName("width"), Int::class.java) - ?: error("Requires width specified"), - context.getPropertyFromAttribute(element, QName("height"), Int::class.java) - ?: error("Requires height specified"), - context.getChildFragment(element) - ) - } - - override fun getName(): QName { - return QName(firmUrl, "Fixed") - } - - override fun getChildCount(): ChildCount { - return ChildCount.ONE - } - - override fun getAttributeNames(): Map { - return mapOf("width" to true, "height" to true) - } - }) - } - - fun generateXSD( - file: File, - namespace: String - ) { - val generator = XSDGenerator(universe, namespace) - generator.writeAll() - generator.dumpToFile(file) - } - - @JvmStatic - fun main(args: Array) { - generateXSD(File("MoulConfig.xsd"), XMLUniverse.MOULCONFIG_XML_NS) - generateXSD(File("MoulConfig.Firmament.xsd"), firmUrl) - File("wrapper.xsd").writeText(""" + val firmUrl = "http://firmament.nea.moe/moulconfig" + val universe = XMLUniverse.getDefaultUniverse().also { uni -> + uni.registerMapper(java.awt.Color::class.java) { + if (it.startsWith("#")) { + val hexString = it.substring(1) + val hex = hexString.toInt(16) + if (hexString.length == 6) { + return@registerMapper java.awt.Color(hex) + } + if (hexString.length == 8) { + return@registerMapper java.awt.Color(hex, true) + } + error("Hexcolor $it needs to be exactly 6 or 8 hex digits long") + } + return@registerMapper java.awt.Color(it.toInt(), true) + } + uni.registerMapper(Color::class.java) { + val color = uni.mapXMLObject(it, java.awt.Color::class.java) + Color.ofRGBA(color.red, color.green, color.blue, color.alpha) + } + uni.registerLoader(object : XMLGuiLoader.Basic { + override fun getName(): QName { + return QName(firmUrl, "Bar") + } + + override fun createInstance(context: XMLContext<*>, element: Element): BarComponent { + return BarComponent( + context.getPropertyFromAttribute(element, QName("progress"), Double::class.java)!!, + context.getPropertyFromAttribute(element, QName("total"), Double::class.java)!!, + context.getPropertyFromAttribute(element, QName("fillColor"), Color::class.java)!!.get(), + context.getPropertyFromAttribute(element, QName("emptyColor"), Color::class.java)!!.get(), + ) + } + + override fun getChildCount(): ChildCount { + return ChildCount.NONE + } + + override fun getAttributeNames(): Map { + return mapOf("progress" to true, "total" to true, "emptyColor" to true, "fillColor" to true) + } + }) + uni.registerLoader(object : XMLGuiLoader.Basic { + override fun createInstance(context: XMLContext<*>, element: Element): FirmHoverComponent { + return FirmHoverComponent( + context.getChildFragment(element), + context.getPropertyFromAttribute(element, + QName("lines"), + List::class.java) as Supplier>, + context.getPropertyFromAttribute(element, QName("delay"), Duration::class.java, 0.6.seconds), + ) + } + + override fun getName(): QName { + return QName(firmUrl, "Hover") + } + + override fun getChildCount(): ChildCount { + return ChildCount.ONE + } + + override fun getAttributeNames(): Map { + return mapOf( + "lines" to true, + "delay" to false, + ) + } + + }) + uni.registerLoader(object : XMLGuiLoader.Basic { + override fun getName(): QName { + return QName(firmUrl, "Button") + } + + override fun createInstance(context: XMLContext<*>, element: Element): FirmButtonComponent { + return FirmButtonComponent( + context.getChildFragment(element), + context.getPropertyFromAttribute(element, QName("enabled"), Boolean::class.java) + ?: GetSetter.constant(true), + context.getPropertyFromAttribute(element, QName("noBackground"), Boolean::class.java, false), + context.getMethodFromAttribute(element, QName("onClick")), + ) + } + + override fun getChildCount(): ChildCount { + return ChildCount.ONE + } + + override fun getAttributeNames(): Map { + return mapOf("onClick" to true, "enabled" to false, "noBackground" to false) + } + }) + uni.registerLoader(object : XMLGuiLoader.Basic { + override fun createInstance(context: XMLContext<*>, element: Element): ImageComponent { + return ImageComponent( + context.getPropertyFromAttribute(element, QName("width"), Int::class.java)!!.get(), + context.getPropertyFromAttribute(element, QName("height"), Int::class.java)!!.get(), + context.getPropertyFromAttribute(element, QName("resource"), MyResourceLocation::class.java)!!, + context.getPropertyFromAttribute(element, QName("u1"), Float::class.java, 0f), + context.getPropertyFromAttribute(element, QName("u2"), Float::class.java, 1f), + context.getPropertyFromAttribute(element, QName("v1"), Float::class.java, 0f), + context.getPropertyFromAttribute(element, QName("v2"), Float::class.java, 1f), + ) + } + + override fun getName(): QName { + return QName(firmUrl, "Image") + } + + override fun getChildCount(): ChildCount { + return ChildCount.NONE + } + + override fun getAttributeNames(): Map { + return mapOf( + "width" to true, "height" to true, + "resource" to true, + "u1" to false, + "u2" to false, + "v1" to false, + "v2" to false, + ) + } + }) + uni.registerLoader(object : XMLGuiLoader.Basic { + override fun createInstance(context: XMLContext<*>, element: Element): TickComponent { + return TickComponent(context.getMethodFromAttribute(element, QName("tick"))) + } + + override fun getName(): QName { + return QName(firmUrl, "Tick") + } + + override fun getChildCount(): ChildCount { + return ChildCount.NONE + } + + override fun getAttributeNames(): Map { + return mapOf("tick" to true) + } + }) + uni.registerLoader(object : XMLGuiLoader.Basic { + override fun createInstance(context: XMLContext<*>, element: Element): FixedComponent { + return FixedComponent( + context.getPropertyFromAttribute(element, QName("width"), Int::class.java) + ?: error("Requires width specified"), + context.getPropertyFromAttribute(element, QName("height"), Int::class.java) + ?: error("Requires height specified"), + context.getChildFragment(element) + ) + } + + override fun getName(): QName { + return QName(firmUrl, "Fixed") + } + + override fun getChildCount(): ChildCount { + return ChildCount.ONE + } + + override fun getAttributeNames(): Map { + return mapOf("width" to true, "height" to true) + } + }) + } + + fun generateXSD( + file: File, + namespace: String + ) { + val generator = XSDGenerator(universe, namespace) + generator.writeAll() + generator.dumpToFile(file) + } + + @JvmStatic + fun main(args: Array) { + generateXSD(File("MoulConfig.xsd"), XMLUniverse.MOULCONFIG_XML_NS) + generateXSD(File("MoulConfig.Firmament.xsd"), firmUrl) + File("wrapper.xsd").writeText(""" """.trimIndent()) - } - - fun loadScreen(name: String, bindTo: Any, parent: Screen?): Screen { - return object : GuiComponentWrapper(loadGui(name, bindTo)) { - override fun close() { - if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) { - client!!.setScreen(parent) - } - } - } - } - - fun loadGui(name: String, bindTo: Any): GuiContext { - return GuiContext(universe.load(bindTo, MyResourceLocation("firmament", "gui/$name.xml"))) - } + } + + fun loadScreen(name: String, bindTo: Any, parent: Screen?): Screen { + return object : GuiComponentWrapper(loadGui(name, bindTo)) { + override fun close() { + if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) { + client!!.setScreen(parent) + } + } + } + } + + // TODO: move this utility into moulconfig (also rework guicontext into an interface so i can make this mesh better into vanilla) + fun GuiContext.adopt(element: GuiComponent) = element.foldRecursive(Unit, { comp, unit -> comp.context = this }) + + fun clickMCComponentInPlace( + component: GuiComponent, + x: Int, + y: Int, + w: Int, + h: Int, + mouseX: Int, mouseY: Int, + mouseEvent: MouseEvent + ): Boolean { + val immContext = createInPlaceFullContext(null, mouseX, mouseY) + return component.mouseEvent(mouseEvent, immContext.translated(x, y, w, h)) + } + + fun createInPlaceFullContext(drawContext: DrawContext?, mouseX: Int, mouseY: Int): GuiImmediateContext { + assert(drawContext?.isUntranslatedGuiDrawContext() != false) + val context = drawContext?.let(::ModernRenderContext) + ?: IMinecraft.instance.provideTopLevelRenderContext() + val immContext = GuiImmediateContext(context, + 0, 0, 0, 0, + mouseX, mouseY, + mouseX, mouseY, + mouseX.toFloat(), + mouseY.toFloat()) + return immContext + } + + fun DrawContext.drawMCComponentInPlace( + component: GuiComponent, + x: Int, + y: Int, + w: Int, + h: Int, + mouseX: Int, + mouseY: Int + ) { + val immContext = createInPlaceFullContext(this, mouseX, mouseY) + matrices.push() + matrices.translate(x.toFloat(), y.toFloat(), 0F) + component.render(immContext.translated(x, y, w, h)) + matrices.pop() + } + + + fun loadGui(name: String, bindTo: Any): GuiContext { + return GuiContext(universe.load(bindTo, MyResourceLocation("firmament", "gui/$name.xml"))) + } } diff --git a/src/main/kotlin/util/assertions.kt b/src/main/kotlin/util/assertions.kt index 6f2ed19..86982be 100644 --- a/src/main/kotlin/util/assertions.kt +++ b/src/main/kotlin/util/assertions.kt @@ -1,11 +1,18 @@ - +@file:OptIn(ExperimentalContracts::class) package moe.nea.firmament.util +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + /** * Less aggressive version of `require(obj != null)`, which fails in devenv but continues at runtime. */ inline fun assertNotNullOr(obj: T?, message: String? = null, block: () -> T): T { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } if (message == null) assert(obj != null) else @@ -18,6 +25,9 @@ inline fun assertNotNullOr(obj: T?, message: String? = null, block: () * Less aggressive version of `require(condition)`, which fails in devenv but continues at runtime. */ inline fun assertTrueOr(condition: Boolean, block: () -> Unit) { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } assert(condition) if (!condition) block() } diff --git a/src/main/kotlin/util/render/DrawContextExt.kt b/src/main/kotlin/util/render/DrawContextExt.kt new file mode 100644 index 0000000..48698b4 --- /dev/null +++ b/src/main/kotlin/util/render/DrawContextExt.kt @@ -0,0 +1,8 @@ +package moe.nea.firmament.util.render + +import org.joml.Matrix4f +import net.minecraft.client.gui.DrawContext + +fun DrawContext.isUntranslatedGuiDrawContext(): Boolean { + return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0 +} diff --git a/src/main/kotlin/util/uuid.kt b/src/main/kotlin/util/uuid.kt index 4aa0749..cccfdd2 100644 --- a/src/main/kotlin/util/uuid.kt +++ b/src/main/kotlin/util/uuid.kt @@ -1,12 +1,10 @@ - - package moe.nea.firmament.util import java.math.BigInteger import java.util.UUID fun parseDashlessUUID(dashlessUuid: String): UUID { - val most = BigInteger(dashlessUuid.substring(0, 16), 16) - val least = BigInteger(dashlessUuid.substring(16, 32), 16) - return UUID(most.toLong(), least.toLong()) + val most = BigInteger(dashlessUuid.substring(0, 16), 16) + val least = BigInteger(dashlessUuid.substring(16, 32), 16) + return UUID(most.toLong(), least.toLong()) } -- cgit