From d86a3b27c1bb6003c06000a17ea3d5841f7a4306 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 24 Mar 2025 11:26:04 +0100 Subject: [PATCH 1/2] Build: Add support for Minecraft 1.21.5 --- api/Elementa.api | 1 + gradle/libs.versions.toml | 2 +- .../elementa/components/GradientComponent.kt | 30 ++++++++++- .../elementa/components/SVGComponent.kt | 1 + .../elementa/components/TreeGraphComponent.kt | 1 + .../essential/elementa/components/UIBlock.kt | 53 +++++++++++++++---- .../essential/elementa/components/UICircle.kt | 41 ++++++++++++++ .../elementa/components/UIRoundedRectangle.kt | 33 ++++++++++++ .../essential/elementa/components/UIShape.kt | 33 +++++++++++- .../essential/elementa/components/UIText.kt | 6 ++- .../elementa/components/UIWrappedText.kt | 6 ++- .../components/image/MSDFComponent.kt | 2 + .../components/inspector/Inspector.kt | 48 +++++++++++++---- .../gg/essential/elementa/dsl/utilities.kt | 13 +++-- .../elementa/effects/ScissorEffect.kt | 12 ++--- .../elementa/font/BasicFontRenderer.kt | 41 ++++++++++++-- .../essential/elementa/font/FontRenderer.kt | 5 ++ .../gg/essential/elementa/utils/LineUtils.kt | 28 ++++++++-- .../gg/essential/elementa/utils/extensions.kt | 8 ++- .../gg/essential/elementa/utils/image.kt | 45 ++++++++++++---- 20 files changed, 350 insertions(+), 59 deletions(-) diff --git a/api/Elementa.api b/api/Elementa.api index 087b0adb..e6bce3f1 100644 --- a/api/Elementa.api +++ b/api/Elementa.api @@ -554,6 +554,7 @@ public class gg/essential/elementa/components/UIBlock : gg/essential/elementa/UI public final class gg/essential/elementa/components/UIBlock$Companion { public final fun drawBlock (Lgg/essential/universal/UMatrixStack;Ljava/awt/Color;DDDD)V + public final fun drawBlock (Lgg/essential/universal/vertex/UVertexConsumer;Lgg/essential/universal/UMatrixStack;Ljava/awt/Color;DDDD)V public final fun drawBlock (Ljava/awt/Color;DDDD)V public final fun drawBlockSized (Lgg/essential/universal/UMatrixStack;Ljava/awt/Color;DDDD)V public final fun drawBlockSized (Ljava/awt/Color;DDDD)V diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 613b9391..017535fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ kotlin = "1.5.10" kotlinx-coroutines = "1.5.2" jetbrains-annotations = "23.0.0" -universalcraft = "363" +universalcraft = "388+feature-fabric-1.21.5" commonmark = "0.17.1" dom4j = "2.1.1" diff --git a/src/main/kotlin/gg/essential/elementa/components/GradientComponent.kt b/src/main/kotlin/gg/essential/elementa/components/GradientComponent.kt index 6e409228..2e1eb450 100644 --- a/src/main/kotlin/gg/essential/elementa/components/GradientComponent.kt +++ b/src/main/kotlin/gg/essential/elementa/components/GradientComponent.kt @@ -5,6 +5,9 @@ import gg.essential.elementa.state.MappedState import gg.essential.elementa.state.State import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState +import gg.essential.universal.vertex.UBufferBuilder import org.lwjgl.opengl.GL11 import java.awt.Color @@ -86,6 +89,7 @@ open class GradientComponent constructor( "This method does not allow for gradients to be rendered at sub-pixel positions. Use the Double variant instead and do not cast to Int.", ReplaceWith("drawGradientBlock(x1.toDouble(), y1.toDouble(), x2.toDouble(), y2.toDouble(), startColor, endColor, direction)") ) + @Suppress("DEPRECATION") fun drawGradientBlock( x1: Int, y1: Int, @@ -123,7 +127,27 @@ open class GradientComponent constructor( endColor: Color, direction: GradientDirection ) { - UGraphics.enableBlend() + if (!URenderPipeline.isRequired) { + @Suppress("DEPRECATION") + return drawGradientBlockLegacy(matrixStack, x1, y1, x2, y2, startColor, endColor, direction) + } + + val colors = direction.getGradientColors(startColor, endColor) + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR) + bufferBuilder.pos(matrixStack, x2, y1, 0.0).color(colors.topRight).endVertex() + bufferBuilder.pos(matrixStack, x1, y1, 0.0).color(colors.topLeft).endVertex() + bufferBuilder.pos(matrixStack, x1, y2, 0.0).color(colors.bottomLeft).endVertex() + bufferBuilder.pos(matrixStack, x2, y2, 0.0).color(colors.bottomRight).endVertex() + bufferBuilder.build()?.drawAndClose(PIPELINE) + } + + @Deprecated("Stops working in 1.21.5") + @Suppress("DEPRECATION") + private fun drawGradientBlockLegacy( + matrixStack: UMatrixStack, + x1: Double, y1: Double, x2: Double, y2: Double, + startColor: Color, endColor: Color, direction: GradientDirection + ) { UGraphics.disableAlpha() UGraphics.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO) UGraphics.shadeModel(GL11.GL_SMOOTH) @@ -141,5 +165,9 @@ open class GradientComponent constructor( UGraphics.disableBlend() UGraphics.enableAlpha() } + + private val PIPELINE = URenderPipeline.builderWithDefaultShader("elementa:gradient_block", UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR).apply { + blendState = BlendState.NORMAL.copy(srcAlpha = BlendState.Param.ONE, dstAlpha = BlendState.Param.ZERO) + }.build() } } \ No newline at end of file diff --git a/src/main/kotlin/gg/essential/elementa/components/SVGComponent.kt b/src/main/kotlin/gg/essential/elementa/components/SVGComponent.kt index 112b38a9..b0511b7b 100644 --- a/src/main/kotlin/gg/essential/elementa/components/SVGComponent.kt +++ b/src/main/kotlin/gg/essential/elementa/components/SVGComponent.kt @@ -48,6 +48,7 @@ class SVGComponent(private var svg: SVG) : UIComponent(), ImageProvider { matrixStack.push() + @Suppress("DEPRECATION") UGraphics.enableBlend() @Suppress("DEPRECATION") UGraphics.disableTexture2D() diff --git a/src/main/kotlin/gg/essential/elementa/components/TreeGraphComponent.kt b/src/main/kotlin/gg/essential/elementa/components/TreeGraphComponent.kt index a453c79b..74092867 100644 --- a/src/main/kotlin/gg/essential/elementa/components/TreeGraphComponent.kt +++ b/src/main/kotlin/gg/essential/elementa/components/TreeGraphComponent.kt @@ -17,6 +17,7 @@ data class TreeGraphStyle( val lineWidth: Float = 2f, val isHorizontal: Boolean = false, val lineDrawer: (UIPoint, UIPoint) -> Unit = { p0, p1 -> + @Suppress("DEPRECATION") // impossible to fix because TreeGraphStyle is public API LineUtils.drawLine(p0, p1, lineColor, lineWidth) } ) diff --git a/src/main/kotlin/gg/essential/elementa/components/UIBlock.kt b/src/main/kotlin/gg/essential/elementa/components/UIBlock.kt index cfc112e3..f76c385b 100644 --- a/src/main/kotlin/gg/essential/elementa/components/UIBlock.kt +++ b/src/main/kotlin/gg/essential/elementa/components/UIBlock.kt @@ -8,6 +8,10 @@ import gg.essential.elementa.state.State import gg.essential.elementa.state.toConstraint import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState +import gg.essential.universal.vertex.UBufferBuilder +import gg.essential.universal.vertex.UVertexConsumer import org.lwjgl.opengl.GL11 import java.awt.Color @@ -53,6 +57,19 @@ open class UIBlock(colorConstraint: ColorConstraint = Color.WHITE.toConstraint() drawBlock(UMatrixStack(), color, x1, y1, x2, y2) fun drawBlock(matrixStack: UMatrixStack, color: Color, x1: Double, y1: Double, x2: Double, y2: Double) { + if (!URenderPipeline.isRequired) { + @Suppress("DEPRECATION") + return drawBlockLegacy(matrixStack, color, x1, y1, x2, y2) + } + + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR) + drawBlock(bufferBuilder, matrixStack, color, x1, y1, x2, y2) + bufferBuilder.build()?.drawAndClose(PIPELINE) + } + + @Deprecated("Stops working in 1.21.5, see UGraphics.Globals") + @Suppress("DEPRECATION") + private fun drawBlockLegacy(matrixStack: UMatrixStack, color: Color, x1: Double, y1: Double, x2: Double, y2: Double) { UGraphics.enableBlend() UGraphics.tryBlendFuncSeparate(770, 771, 1, 0) @@ -63,22 +80,18 @@ open class UIBlock(colorConstraint: ColorConstraint = Color.WHITE.toConstraint() UGraphics.disableBlend() } + @Deprecated("Stops working in 1.21.5, use URenderPipeline via UBufferBuilder with drawBlock(UVertexConsumer, ...) instead.") + @Suppress("DEPRECATION") fun drawBlockWithActiveShader(matrixStack: UMatrixStack, color: Color, x1: Double, y1: Double, x2: Double, y2: Double) { val buffer = UGraphics.getFromTessellator() buffer.beginWithActiveShader(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR) drawBlock(buffer, matrixStack, color, x1, y1, x2, y2) } + @Deprecated("Stops working in 1.21.5, see UGraphics.Globals") + @Suppress("DEPRECATION") private fun drawBlock(worldRenderer: UGraphics, matrixStack: UMatrixStack, color: Color, x1: Double, y1: Double, x2: Double, y2: Double) { - val red = color.red.toFloat() / 255f - val green = color.green.toFloat() / 255f - val blue = color.blue.toFloat() / 255f - val alpha = color.alpha.toFloat() / 255f - - worldRenderer.pos(matrixStack, x1, y2, 0.0).color(red, green, blue, alpha).endVertex() - worldRenderer.pos(matrixStack, x2, y2, 0.0).color(red, green, blue, alpha).endVertex() - worldRenderer.pos(matrixStack, x2, y1, 0.0).color(red, green, blue, alpha).endVertex() - worldRenderer.pos(matrixStack, x1, y1, 0.0).color(red, green, blue, alpha).endVertex() + drawBlock(worldRenderer.asUVertexConsumer(), matrixStack, color, x1, y1, x2, y2) if (ElementaVersion.active >= ElementaVersion.v1) { // At some point MC started enabling its depth test during font rendering but all GUI code is @@ -96,6 +109,18 @@ open class UIBlock(colorConstraint: ColorConstraint = Color.WHITE.toConstraint() } } + fun drawBlock(vertexConsumer: UVertexConsumer, matrixStack: UMatrixStack, color: Color, x1: Double, y1: Double, x2: Double, y2: Double) { + val red = color.red.toFloat() / 255f + val green = color.green.toFloat() / 255f + val blue = color.blue.toFloat() / 255f + val alpha = color.alpha.toFloat() / 255f + + vertexConsumer.pos(matrixStack, x1, y2, 0.0).color(red, green, blue, alpha).endVertex() + vertexConsumer.pos(matrixStack, x2, y2, 0.0).color(red, green, blue, alpha).endVertex() + vertexConsumer.pos(matrixStack, x2, y1, 0.0).color(red, green, blue, alpha).endVertex() + vertexConsumer.pos(matrixStack, x1, y1, 0.0).color(red, green, blue, alpha).endVertex() + } + @Deprecated( "Pass UMatrixStack as first argument, required for 1.17", ReplaceWith("drawBlock(matrixStack, color, x1, y1, x2, y2)") @@ -106,5 +131,15 @@ open class UIBlock(colorConstraint: ColorConstraint = Color.WHITE.toConstraint() fun drawBlockSized(matrixStack: UMatrixStack, color: Color, x: Double, y: Double, width: Double, height: Double) { drawBlock(matrixStack, color, x, y, x + width, y + height) } + + private val PIPELINE = URenderPipeline.builderWithDefaultShader("elementa:block", UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR).apply { + blendState = BlendState.NORMAL.copy(srcAlpha = BlendState.Param.ONE, dstAlpha = BlendState.Param.ZERO) + // At some point MC started enabling its depth test during font rendering but all GUI code is + // essentially flat and has depth tests disabled. This can cause stuff rendered in the background of the + // GUI to interfere with text rendered in the foreground because none of the blocks rendered in between + // will actually write to the depth buffer. + // To work around this, we'll write depth buffer unconditionally in the area where we draw the block. + depthTest = URenderPipeline.DepthTest.Always + }.build() } } diff --git a/src/main/kotlin/gg/essential/elementa/components/UICircle.kt b/src/main/kotlin/gg/essential/elementa/components/UICircle.kt index 8a7f5872..38660601 100644 --- a/src/main/kotlin/gg/essential/elementa/components/UICircle.kt +++ b/src/main/kotlin/gg/essential/elementa/components/UICircle.kt @@ -3,12 +3,16 @@ package gg.essential.elementa.components import gg.essential.elementa.UIComponent import gg.essential.elementa.dsl.toConstraint import gg.essential.elementa.dsl.pixels +import gg.essential.elementa.utils.readElementaShaderSource import gg.essential.elementa.utils.readFromLegacyShader +import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline import gg.essential.universal.shader.BlendState import gg.essential.universal.shader.Float2Uniform import gg.essential.universal.shader.FloatUniform import gg.essential.universal.shader.UShader +import gg.essential.universal.vertex.UBufferBuilder import java.awt.Color /** @@ -66,10 +70,23 @@ class UICircle @JvmOverloads constructor(radius: Float = 0f, color: Color = Colo private lateinit var shaderRadiusUniform: FloatUniform private lateinit var shaderCenterPositionUniform: Float2Uniform + private val PIPELINE = URenderPipeline.builderWithLegacyShader( + "elementa:circle", + UGraphics.DrawMode.QUADS, + UGraphics.CommonVertexFormats.POSITION_COLOR, + readElementaShaderSource("rect", "vsh"), + readElementaShaderSource("circle", "fsh"), + ).apply { + blendState = BlendState.NORMAL + depthTest = URenderPipeline.DepthTest.Always // see UIBlock.PIPELINE + }.build() + fun initShaders() { + if (URenderPipeline.isRequired) return if (::shader.isInitialized) return + @Suppress("DEPRECATION") shader = UShader.readFromLegacyShader("rect", "circle", BlendState.NORMAL) if (!shader.usable) { println("Failed to load Elementa UICircle shader") @@ -87,6 +104,30 @@ class UICircle @JvmOverloads constructor(radius: Float = 0f, color: Color = Colo drawCircle(UMatrixStack(), centerX, centerY, radius, color) fun drawCircle(matrixStack: UMatrixStack, centerX: Float, centerY: Float, radius: Float, color: Color) { + if (!URenderPipeline.isRequired) { + @Suppress("DEPRECATION") + return drawCircleLegacy(matrixStack, centerX, centerY, radius, color) + } + + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR) + UIBlock.drawBlock( + bufferBuilder, + matrixStack, + color, + (centerX - radius).toDouble(), + (centerY - radius).toDouble(), + (centerX + radius).toDouble(), + (centerY + radius).toDouble() + ) + bufferBuilder.build()?.drawAndClose(PIPELINE) { + uniform("u_Radius", radius) + uniform("u_CenterPos", centerX, centerY) + } + } + + @Deprecated("Stops working in 1.21.5") + @Suppress("DEPRECATION") + private fun drawCircleLegacy(matrixStack: UMatrixStack, centerX: Float, centerY: Float, radius: Float, color: Color) { if (!::shader.isInitialized || !shader.usable) return diff --git a/src/main/kotlin/gg/essential/elementa/components/UIRoundedRectangle.kt b/src/main/kotlin/gg/essential/elementa/components/UIRoundedRectangle.kt index d28f07a0..7a9503b0 100644 --- a/src/main/kotlin/gg/essential/elementa/components/UIRoundedRectangle.kt +++ b/src/main/kotlin/gg/essential/elementa/components/UIRoundedRectangle.kt @@ -2,12 +2,16 @@ package gg.essential.elementa.components import gg.essential.elementa.UIComponent import gg.essential.elementa.dsl.pixels +import gg.essential.elementa.utils.readElementaShaderSource import gg.essential.elementa.utils.readFromLegacyShader +import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline import gg.essential.universal.shader.BlendState import gg.essential.universal.shader.Float4Uniform import gg.essential.universal.shader.FloatUniform import gg.essential.universal.shader.UShader +import gg.essential.universal.vertex.UBufferBuilder import java.awt.Color /** @@ -37,10 +41,23 @@ open class UIRoundedRectangle(radius: Float) : UIComponent() { private lateinit var shaderRadiusUniform: FloatUniform private lateinit var shaderInnerRectUniform: Float4Uniform + private val PIPELINE = URenderPipeline.builderWithLegacyShader( + "elementa:rounded_rectangle", + UGraphics.DrawMode.QUADS, + UGraphics.CommonVertexFormats.POSITION_COLOR, + readElementaShaderSource("rect", "vsh"), + readElementaShaderSource("rounded_rect", "fsh"), + ).apply { + blendState = BlendState.NORMAL + depthTest = URenderPipeline.DepthTest.Always // see UIBlock.PIPELINE + }.build() + fun initShaders() { + if (URenderPipeline.isRequired) return if (::shader.isInitialized) return + @Suppress("DEPRECATION") shader = UShader.readFromLegacyShader("rect", "rounded_rect", BlendState.NORMAL) if (!shader.usable) { println("Failed to load Elementa UIRoundedRectangle shader") @@ -61,6 +78,22 @@ open class UIRoundedRectangle(radius: Float) : UIComponent() { * Draws a rounded rectangle */ fun drawRoundedRectangle(matrixStack: UMatrixStack, left: Float, top: Float, right: Float, bottom: Float, radius: Float, color: Color) { + if (!URenderPipeline.isRequired) { + @Suppress("DEPRECATION") + return drawRoundedRectangleLegacy(matrixStack, left, top, right, bottom, radius, color) + } + + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR) + UIBlock.drawBlock(bufferBuilder, matrixStack, color, left.toDouble(), top.toDouble(), right.toDouble(), bottom.toDouble()) + bufferBuilder.build()?.drawAndClose(PIPELINE) { + uniform("u_Radius", radius) + uniform("u_InnerRect", left + radius, top + radius, right - radius, bottom - radius) + } + } + + @Deprecated("Stops working in 1.21.5") + @Suppress("DEPRECATION") + private fun drawRoundedRectangleLegacy(matrixStack: UMatrixStack, left: Float, top: Float, right: Float, bottom: Float, radius: Float, color: Color) { if (!::shader.isInitialized || !shader.usable) return diff --git a/src/main/kotlin/gg/essential/elementa/components/UIShape.kt b/src/main/kotlin/gg/essential/elementa/components/UIShape.kt index f71a69cc..c3d1f1f2 100644 --- a/src/main/kotlin/gg/essential/elementa/components/UIShape.kt +++ b/src/main/kotlin/gg/essential/elementa/components/UIShape.kt @@ -4,6 +4,9 @@ import gg.essential.elementa.UIComponent import gg.essential.elementa.dsl.toConstraint import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState +import gg.essential.universal.vertex.UBufferBuilder import org.lwjgl.opengl.GL11 import java.awt.Color @@ -41,6 +44,30 @@ open class UIShape @JvmOverloads constructor(color: Color = Color.WHITE) : UICom val color = this.getColor() if (color.alpha == 0) return super.draw(matrixStack) + if (URenderPipeline.isRequired) { + draw(matrixStack, color) + } else { + @Suppress("DEPRECATION") + drawLegacy(matrixStack, color) + } + + super.draw(matrixStack) + } + + private fun draw(matrixStack: UMatrixStack, color: Color) { + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.TRIANGLE_FAN, UGraphics.CommonVertexFormats.POSITION_COLOR) + vertices.forEach { + bufferBuilder + .pos(matrixStack, it.absoluteX.toDouble(), it.absoluteY.toDouble(), 0.0) + .color(color.red, color.green, color.blue, color.alpha) + .endVertex() + } + bufferBuilder.build()?.drawAndClose(PIPELINE) + } + + @Deprecated("Stops working in 1.21.5, see UGraphics.Globals") + @Suppress("DEPRECATION") + private fun drawLegacy(matrixStack: UMatrixStack, color: Color) { UGraphics.enableBlend() UGraphics.disableTexture2D() val red = color.red.toFloat() / 255f @@ -66,7 +93,11 @@ open class UIShape @JvmOverloads constructor(color: Color = Color.WHITE) : UICom UGraphics.enableTexture2D() UGraphics.disableBlend() + } - super.draw(matrixStack) + private companion object { + private val PIPELINE = URenderPipeline.builderWithDefaultShader("elementa:shape", UGraphics.DrawMode.TRIANGLE_FAN, UGraphics.CommonVertexFormats.POSITION_COLOR).apply { + blendState = BlendState.NORMAL.copy(srcAlpha = BlendState.Param.ONE, dstAlpha = BlendState.Param.ZERO) + }.build() } } diff --git a/src/main/kotlin/gg/essential/elementa/components/UIText.kt b/src/main/kotlin/gg/essential/elementa/components/UIText.kt index 7030c4b2..f04049f5 100644 --- a/src/main/kotlin/gg/essential/elementa/components/UIText.kt +++ b/src/main/kotlin/gg/essential/elementa/components/UIText.kt @@ -10,6 +10,7 @@ import gg.essential.elementa.state.State import gg.essential.elementa.state.pixels import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline import java.awt.Color /** @@ -117,7 +118,10 @@ constructor( return super.draw(matrixStack) } - UGraphics.enableBlend() + if (!URenderPipeline.isRequired) { + @Suppress("DEPRECATION") + UGraphics.enableBlend() + } val shadow = shadowState.get() val shadowColor = shadowColorState.get() diff --git a/src/main/kotlin/gg/essential/elementa/components/UIWrappedText.kt b/src/main/kotlin/gg/essential/elementa/components/UIWrappedText.kt index 3e88e4ab..1165cab5 100644 --- a/src/main/kotlin/gg/essential/elementa/components/UIWrappedText.kt +++ b/src/main/kotlin/gg/essential/elementa/components/UIWrappedText.kt @@ -13,6 +13,7 @@ import gg.essential.elementa.utils.getStringSplitToWidth import gg.essential.elementa.utils.splitStringToWidthTruncated import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline import java.awt.Color /** @@ -151,7 +152,10 @@ open class UIWrappedText @JvmOverloads constructor( return super.draw(matrixStack) } - UGraphics.enableBlend() + if (!URenderPipeline.isRequired) { + @Suppress("DEPRECATION") + UGraphics.enableBlend() + } val lines = if (trimText) { splitStringToWidthTruncated( diff --git a/src/main/kotlin/gg/essential/elementa/components/image/MSDFComponent.kt b/src/main/kotlin/gg/essential/elementa/components/image/MSDFComponent.kt index 6c736456..19bf6949 100644 --- a/src/main/kotlin/gg/essential/elementa/components/image/MSDFComponent.kt +++ b/src/main/kotlin/gg/essential/elementa/components/image/MSDFComponent.kt @@ -1,3 +1,4 @@ +@file:Suppress("DEPRECATION") package gg.essential.elementa.components.image import gg.essential.elementa.UIComponent @@ -22,6 +23,7 @@ import java.util.concurrent.CompletableFuture import java.util.concurrent.ConcurrentLinkedQueue import javax.imageio.ImageIO +@Deprecated("Not well maintained. Does not currently support 1.21.5+ at all.") open class MSDFComponent constructor( private val imageFuture: CompletableFuture ) : UIComponent(), CacheableImage { diff --git a/src/main/kotlin/gg/essential/elementa/components/inspector/Inspector.kt b/src/main/kotlin/gg/essential/elementa/components/inspector/Inspector.kt index f0cea0ca..d53eabf5 100644 --- a/src/main/kotlin/gg/essential/elementa/components/inspector/Inspector.kt +++ b/src/main/kotlin/gg/essential/elementa/components/inspector/Inspector.kt @@ -1,6 +1,5 @@ package gg.essential.elementa.components.inspector -import gg.essential.elementa.ElementaVersion import gg.essential.elementa.UIComponent import gg.essential.elementa.components.* import gg.essential.elementa.constraints.* @@ -14,7 +13,10 @@ import gg.essential.elementa.utils.devPropSet import gg.essential.elementa.utils.elementaDebug import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack -import org.lwjgl.opengl.GL11 +import gg.essential.universal.render.DrawCallBuilder +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState +import gg.essential.universal.vertex.UBufferBuilder import java.awt.Color import java.io.FileNotFoundException import java.net.ConnectException @@ -309,24 +311,32 @@ class Inspector @JvmOverloads constructor( val x2 = component.getRight().toDouble() val y2 = component.getBottom().toDouble() + fun drawQuad(pipeline: URenderPipeline, color: Color, configure: DrawCallBuilder.() -> Unit = {}) { + val builder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR) + UIBlock.drawBlock(builder, matrixStack, color, x1, y1, x2, y2) + builder.build()?.drawAndClose(pipeline, configure) + } + // Clear the depth buffer cause we will be using it to draw our outside-of-scissor-bounds block - UGraphics.glClear(GL11.GL_DEPTH_BUFFER_BIT) + // Note that we cannot just use glClear because MC 1.21.5+ no longer has any framebuffer bound by default. + matrixStack.push() + matrixStack.translate(0f, 0f, -100f) + drawQuad(CLEAR_DEPTH_PIPELINE, Color.WHITE) { + noScissor() + } + matrixStack.pop() // Draw a highlight on the element respecting its scissor effects scissors.forEach { it.beforeDraw(matrixStack) } - UIBlock.drawBlock(matrixStack, Color(129, 212, 250, 100), x1, y1, x2, y2) + drawQuad(HIGHLIGHT_PIPELINE, Color(129, 212, 250, 100)) scissors.asReversed().forEach { it.afterDraw(matrixStack) } // Then draw another highlight (with depth testing such that we do not overwrite the previous one) // which does not respect the scissor effects and thereby indicates where the element is drawn outside of // its scissor bounds. - UGraphics.enableDepth() - UGraphics.depthFunc(GL11.GL_LESS) - ElementaVersion.v0.enableFor { // need the custom depth testing - UIBlock.drawBlock(matrixStack, Color(255, 100, 100, 100), x1, y1, x2, y2) + drawQuad(HIGHLIGHT_PIPELINE, Color(255, 100, 100, 100)) { + noScissor() } - UGraphics.depthFunc(GL11.GL_LEQUAL) - UGraphics.disableDepth() } val debugState = elementaDebug @@ -357,5 +367,23 @@ class Inspector @JvmOverloads constructor( .drop(2) // this method + caller of this method .first() .className + + private val CLEAR_DEPTH_PIPELINE = URenderPipeline.builderWithDefaultShader( + "elementa:inspector_clear_depth", + UGraphics.DrawMode.QUADS, + UGraphics.CommonVertexFormats.POSITION_COLOR, + ).apply { + colorMask = Pair(false, false) + depthTest = URenderPipeline.DepthTest.Always + }.build() + + private val HIGHLIGHT_PIPELINE = URenderPipeline.builderWithDefaultShader( + "elementa:inspector_highlight", + UGraphics.DrawMode.QUADS, + UGraphics.CommonVertexFormats.POSITION_COLOR, + ).apply { + blendState = BlendState.NORMAL + depthTest = URenderPipeline.DepthTest.Less + }.build() } } diff --git a/src/main/kotlin/gg/essential/elementa/dsl/utilities.kt b/src/main/kotlin/gg/essential/elementa/dsl/utilities.kt index 43536fdb..b99d9f65 100644 --- a/src/main/kotlin/gg/essential/elementa/dsl/utilities.kt +++ b/src/main/kotlin/gg/essential/elementa/dsl/utilities.kt @@ -4,7 +4,6 @@ import gg.essential.elementa.constraints.* import gg.essential.elementa.font.DefaultFonts import gg.essential.elementa.font.FontProvider import gg.essential.universal.UGraphics -import gg.essential.universal.wrappers.message.UTextComponent import java.awt.Color fun Char.width(textScale: Float = 1f) = UGraphics.getCharWidth(this) * textScale @@ -48,17 +47,21 @@ operator fun Color.component4() = alpha // Fabric @Deprecated("Direct Minecraft dependency", level = DeprecationLevel.HIDDEN) +@Suppress("DEPRECATION") fun net.minecraft.class_2561.width(textScale: Float = 1f, fontProvider: FontProvider = DefaultFonts.VANILLA_FONT_RENDERER) = - UTextComponent.from(this)!!.text.width(textScale, fontProvider) + gg.essential.universal.wrappers.message.UTextComponent.from(this)!!.text.width(textScale, fontProvider) // Forge 1.8 @Deprecated("Direct Minecraft dependency", level = DeprecationLevel.HIDDEN) +@Suppress("DEPRECATION") fun net.minecraft.util.IChatComponent.width(textScale: Float = 1f, fontProvider: FontProvider = DefaultFonts.VANILLA_FONT_RENDERER) = - UTextComponent.from(this)!!.text.width(textScale, fontProvider) + gg.essential.universal.wrappers.message.UTextComponent.from(this)!!.text.width(textScale, fontProvider) // Forge 1.12-1.16 @Deprecated("Direct Minecraft dependency", level = DeprecationLevel.HIDDEN) +@Suppress("DEPRECATION") fun net.minecraft.util.text.ITextComponent.width(textScale: Float = 1f, fontProvider: FontProvider = DefaultFonts.VANILLA_FONT_RENDERER) = - UTextComponent.from(this)!!.text.width(textScale, fontProvider) + gg.essential.universal.wrappers.message.UTextComponent.from(this)!!.text.width(textScale, fontProvider) // Forge 1.17+ @Deprecated("Direct Minecraft dependency", level = DeprecationLevel.HIDDEN) +@Suppress("DEPRECATION") fun net.minecraft.network.chat.Component.width(textScale: Float = 1f, fontProvider: FontProvider = DefaultFonts.VANILLA_FONT_RENDERER) = - UTextComponent.from(this)!!.text.width(textScale, fontProvider) + gg.essential.universal.wrappers.message.UTextComponent.from(this)!!.text.width(textScale, fontProvider) diff --git a/src/main/kotlin/gg/essential/elementa/effects/ScissorEffect.kt b/src/main/kotlin/gg/essential/elementa/effects/ScissorEffect.kt index 4e89efb6..5d6b8f74 100644 --- a/src/main/kotlin/gg/essential/elementa/effects/ScissorEffect.kt +++ b/src/main/kotlin/gg/essential/elementa/effects/ScissorEffect.kt @@ -2,9 +2,9 @@ package gg.essential.elementa.effects import gg.essential.elementa.UIComponent import gg.essential.elementa.utils.roundToRealPixels +import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack import gg.essential.universal.UResolution -import org.lwjgl.opengl.GL11.* import kotlin.math.max import kotlin.math.min import kotlin.math.roundToInt @@ -47,10 +47,6 @@ class ScissorEffect @JvmOverloads constructor( val bounds = customBoundingBox?.getScissorBounds() ?: scissorBounds ?: boundComponent.getScissorBounds() val scaleFactor = UResolution.scaleFactor.toInt() - if (currentScissorState == null) { - glEnable(GL_SCISSOR_TEST) - } - oldState = currentScissorState val state = oldState @@ -76,7 +72,7 @@ class ScissorEffect @JvmOverloads constructor( height = min(y2, oldY2) - y } - glScissor(x, y, width.coerceAtLeast(0), height.coerceAtLeast(0)) + UGraphics.enableScissor(x, y, width.coerceAtLeast(0), height.coerceAtLeast(0)) currentScissorState = ScissorState(x, y, width.coerceAtLeast(0), height.coerceAtLeast(0)) } @@ -85,11 +81,11 @@ class ScissorEffect @JvmOverloads constructor( val state = oldState if (state != null) { - glScissor(state.x, state.y, state.width, state.height) + UGraphics.enableScissor(state.x, state.y, state.width, state.height) oldState = null } else { - glDisable(GL_SCISSOR_TEST) + UGraphics.disableScissor() } currentScissorState = state diff --git a/src/main/kotlin/gg/essential/elementa/font/BasicFontRenderer.kt b/src/main/kotlin/gg/essential/elementa/font/BasicFontRenderer.kt index f9c5a1c2..aeb87647 100644 --- a/src/main/kotlin/gg/essential/elementa/font/BasicFontRenderer.kt +++ b/src/main/kotlin/gg/essential/elementa/font/BasicFontRenderer.kt @@ -7,6 +7,10 @@ import gg.essential.elementa.font.data.Font import gg.essential.elementa.font.data.Glyph import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState +import gg.essential.universal.vertex.UBufferBuilder +import gg.essential.universal.vertex.UVertexConsumer import java.awt.Color import kotlin.math.max @@ -144,8 +148,31 @@ class BasicFontRenderer( y: Float, originalPointSize: Float ) { - UGraphics.bindTexture(0, regularFont.getTexture().dynamicGlId) + if (URenderPipeline.isRequired) { + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR) + drawStringNow(bufferBuilder, matrixStack, string, color, x, y, originalPointSize) + bufferBuilder.build()?.drawAndClose(PIPELINE) { + texture(0, regularFont.getTexture().dynamicGlId) + } + } else { + UGraphics.bindTexture(0, regularFont.getTexture().dynamicGlId) + val bufferBuilder = UGraphics.getFromTessellator() + @Suppress("DEPRECATION") + bufferBuilder.beginWithDefaultShader(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR) + drawStringNow(bufferBuilder.asUVertexConsumer(), matrixStack, string, color, x, y, originalPointSize) + bufferBuilder.drawDirect() + } + } + private fun drawStringNow( + vertexConsumer: UVertexConsumer, + matrixStack: UMatrixStack, + string: String, + color: Color, + x: Float, + y: Float, + originalPointSize: Float + ) { var currentX = x var i = 0 while (i < string.length) { @@ -171,6 +198,7 @@ class BasicFontRenderer( val height = (planeBounds.top - planeBounds.bottom) * originalPointSize drawGlyph( + vertexConsumer, matrixStack, glyph, color, @@ -196,6 +224,7 @@ class BasicFontRenderer( private fun drawGlyph( + worldRenderer: UVertexConsumer, matrixStack: UMatrixStack, glyph: Glyph, color: Color, @@ -211,8 +240,6 @@ class BasicFontRenderer( val textureLeft = (atlasBounds.left / atlas.width).toDouble() val textureRight = (atlasBounds.right / atlas.width).toDouble() - val worldRenderer = UGraphics.getFromTessellator() - worldRenderer.beginWithDefaultShader(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR) val doubleX = x.toDouble() val doubleY = y.toDouble() worldRenderer.pos(matrixStack, doubleX, doubleY + height, 0.0).tex(textureLeft, textureBottom).color( @@ -239,11 +266,15 @@ class BasicFontRenderer( color.blue, 255 ).endVertex() - worldRenderer.drawDirect() - } override fun visitImpl(visitor: ConstraintVisitor, type: ConstraintType) { } + + private companion object { + private val PIPELINE = URenderPipeline.builderWithDefaultShader("elementa:basic_font", UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_COLOR).apply { + blendState = BlendState.NORMAL.copy(srcAlpha = BlendState.Param.ONE, dstAlpha = BlendState.Param.ZERO) + }.build() + } } \ No newline at end of file diff --git a/src/main/kotlin/gg/essential/elementa/font/FontRenderer.kt b/src/main/kotlin/gg/essential/elementa/font/FontRenderer.kt index a2dcf772..d75ca304 100644 --- a/src/main/kotlin/gg/essential/elementa/font/FontRenderer.kt +++ b/src/main/kotlin/gg/essential/elementa/font/FontRenderer.kt @@ -9,6 +9,7 @@ import gg.essential.elementa.utils.readFromLegacyShader import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack import gg.essential.universal.UResolution +import gg.essential.universal.render.URenderPipeline import gg.essential.universal.shader.BlendState import gg.essential.universal.shader.Float2Uniform import gg.essential.universal.shader.Float4Uniform @@ -24,6 +25,8 @@ import kotlin.math.max /** * [MSDF](https://github.com/Chlumsky/msdfgen) Font Renderer */ +@Deprecated("Not well maintained. Does not currently support 1.21.5+ at all.") +@Suppress("DEPRECATION") class FontRenderer( private val regularFont: Font, private val boldFont: Font = regularFont @@ -406,9 +409,11 @@ class FontRenderer( fun areShadersInitialized() = ::shader.isInitialized fun initShaders() { + if (URenderPipeline.isRequired) return if (areShadersInitialized()) return + @Suppress("DEPRECATION") shader = UShader.readFromLegacyShader("font", "font", BlendState.NORMAL) if (!shader.usable) { println("Failed to load Elementa font shader") diff --git a/src/main/kotlin/gg/essential/elementa/utils/LineUtils.kt b/src/main/kotlin/gg/essential/elementa/utils/LineUtils.kt index 3815cefe..87d0b50a 100644 --- a/src/main/kotlin/gg/essential/elementa/utils/LineUtils.kt +++ b/src/main/kotlin/gg/essential/elementa/utils/LineUtils.kt @@ -3,11 +3,18 @@ package gg.essential.elementa.utils import gg.essential.elementa.components.UIPoint import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack -import org.lwjgl.opengl.GL11 +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState +import gg.essential.universal.vertex.UBufferBuilder +import gg.essential.universal.vertex.UVertexConsumer import java.awt.Color import kotlin.math.sqrt object LineUtils { + private val PIPELINE = URenderPipeline.builderWithDefaultShader("elementa:line_strip", UGraphics.DrawMode.TRIANGLE_STRIP, UGraphics.CommonVertexFormats.POSITION_COLOR).apply { + blendState = BlendState.NORMAL + }.build() + @Deprecated(UMatrixStack.Compat.DEPRECATED, ReplaceWith("drawLine(UMatrixStack(), x1, y1, x2, y2, color, width)")) @JvmStatic fun drawLine(x1: Number, y1: Number, x2: Number, y2: Number, color: Color, width: Float) = @@ -20,10 +27,22 @@ object LineUtils { @JvmStatic fun drawLineStrip(matrixStack: UMatrixStack, points: List>, color: Color, width: Float) { - UGraphics.enableBlend() + if (URenderPipeline.isRequired) { + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.TRIANGLE_STRIP, UGraphics.CommonVertexFormats.POSITION_COLOR) + drawLineStrip(bufferBuilder, matrixStack, points, color, width) + bufferBuilder.build()?.drawAndClose(PIPELINE) + } else { + @Suppress("DEPRECATION") + UGraphics.enableBlend() + val buffer = UGraphics.getFromTessellator() + @Suppress("DEPRECATION") + buffer.beginWithDefaultShader(UGraphics.DrawMode.TRIANGLE_STRIP, UGraphics.CommonVertexFormats.POSITION_COLOR); + drawLineStrip(buffer.asUVertexConsumer(), matrixStack, points, color, width) + buffer.drawDirect() + } + } - val buffer = UGraphics.getFromTessellator() - buffer.beginWithDefaultShader(UGraphics.DrawMode.TRIANGLE_STRIP, UGraphics.CommonVertexFormats.POSITION_COLOR); + private fun drawLineStrip(buffer: UVertexConsumer, matrixStack: UMatrixStack, points: List>, color: Color, width: Float) { points.forEachIndexed { index, curr -> val (x, y) = curr val prev = points.getOrNull(index - 1) @@ -43,7 +62,6 @@ object LineUtils { .color(color.red, color.green, color.blue, color.alpha) .endVertex() } - buffer.drawDirect() } private fun Pair.sub(other: Pair): Pair { diff --git a/src/main/kotlin/gg/essential/elementa/utils/extensions.kt b/src/main/kotlin/gg/essential/elementa/utils/extensions.kt index c30c8869..b8a8d67c 100644 --- a/src/main/kotlin/gg/essential/elementa/utils/extensions.kt +++ b/src/main/kotlin/gg/essential/elementa/utils/extensions.kt @@ -2,6 +2,7 @@ package gg.essential.elementa.utils import gg.essential.elementa.UIComponent import gg.essential.elementa.components.Window +import gg.essential.universal.UGraphics.CommonVertexFormats import gg.essential.universal.UResolution import gg.essential.universal.shader.BlendState import gg.essential.universal.shader.UShader @@ -31,7 +32,10 @@ operator fun Color.component2() = this.green operator fun Color.component3() = this.blue operator fun Color.component4() = this.alpha +@Deprecated("Stops working in 1.21.5, see UGraphics.Globals") +@Suppress("DEPRECATION") internal fun UShader.Companion.readFromLegacyShader(vertName: String, fragName: String, blendState: BlendState) = - fromLegacyShader(readShader(vertName, "vsh"), readShader(fragName, "fsh"), blendState) -private fun readShader(name: String, ext: String) = + fromLegacyShader(readElementaShaderSource(vertName, "vsh"), readElementaShaderSource(fragName, "fsh"), blendState) + +internal fun readElementaShaderSource(name: String, ext: String) = Window::class.java.getResource("/shaders/$name.$ext").readText() diff --git a/src/main/kotlin/gg/essential/elementa/utils/image.kt b/src/main/kotlin/gg/essential/elementa/utils/image.kt index cc3fbcc6..8642792a 100644 --- a/src/main/kotlin/gg/essential/elementa/utils/image.kt +++ b/src/main/kotlin/gg/essential/elementa/utils/image.kt @@ -2,7 +2,11 @@ package gg.essential.elementa.utils import gg.essential.universal.UGraphics import gg.essential.universal.UMatrixStack +import gg.essential.universal.render.URenderPipeline +import gg.essential.universal.shader.BlendState import gg.essential.universal.utils.ReleasedDynamicTexture +import gg.essential.universal.vertex.UBufferBuilder +import gg.essential.universal.vertex.UVertexConsumer import org.lwjgl.opengl.GL11 import java.awt.Color import java.awt.image.BufferedImage @@ -24,32 +28,53 @@ internal fun drawTexture( ) { matrixStack.push() - UGraphics.enableBlend() - UGraphics.enableAlpha() matrixStack.scale(1f, 1f, 50f) val glId = texture.dynamicGlId - UGraphics.bindTexture(0, glId) val red = color.red.toFloat() / 255f val green = color.green.toFloat() / 255f val blue = color.blue.toFloat() / 255f val alpha = color.alpha.toFloat() / 255f - val worldRenderer = UGraphics.getFromTessellator() UGraphics.configureTexture(glId) { GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, textureMinFilter) GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, textureMagFilter) } - worldRenderer.beginWithDefaultShader(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR) + fun drawTexturedQuad(vertexConsumer: UVertexConsumer) { + vertexConsumer.pos(matrixStack, x, y + height, 0.0).tex(0.0, 1.0).color(red, green, blue, alpha).endVertex() + vertexConsumer.pos(matrixStack, x + width, y + height, 0.0).tex(1.0, 1.0).color(red, green, blue, alpha).endVertex() + vertexConsumer.pos(matrixStack, x + width, y, 0.0).tex(1.0, 0.0).color(red, green, blue, alpha).endVertex() + vertexConsumer.pos(matrixStack, x, y, 0.0).tex(0.0, 0.0).color(red, green, blue, alpha).endVertex() + } - worldRenderer.pos(matrixStack, x, y + height, 0.0).tex(0.0, 1.0).color(red, green, blue, alpha).endVertex() - worldRenderer.pos(matrixStack, x + width, y + height, 0.0).tex(1.0, 1.0).color(red, green, blue, alpha).endVertex() - worldRenderer.pos(matrixStack, x + width, y, 0.0).tex(1.0, 0.0).color(red, green, blue, alpha).endVertex() - worldRenderer.pos(matrixStack, x, y, 0.0).tex(0.0, 0.0).color(red, green, blue, alpha).endVertex() - worldRenderer.drawDirect() + if (URenderPipeline.isRequired) { + val bufferBuilder = UBufferBuilder.create(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR) + drawTexturedQuad(bufferBuilder) + bufferBuilder.build()?.drawAndClose(TEXTURED_QUAD_PIPELINE) { + texture(0, glId) + } + } else { + @Suppress("DEPRECATION") + UGraphics.enableBlend() + UGraphics.enableAlpha() + UGraphics.bindTexture(0, glId) + val worldRenderer = UGraphics.getFromTessellator() + @Suppress("DEPRECATION") + worldRenderer.beginWithDefaultShader(UGraphics.DrawMode.QUADS, UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR) + drawTexturedQuad(worldRenderer.asUVertexConsumer()) + worldRenderer.drawDirect() + } matrixStack.pop() } +private val TEXTURED_QUAD_PIPELINE = URenderPipeline.builderWithDefaultShader( + "elementa:textured_quad", + UGraphics.DrawMode.QUADS, + UGraphics.CommonVertexFormats.POSITION_TEXTURE_COLOR, +).apply { + blendState = BlendState.NORMAL +}.build() + fun decodeBlurHash(blurHash: String?, width: Int, height: Int, punch: Float = 1f): BufferedImage? { if (blurHash == null || blurHash.length < 6) return null From 0f058f1bc88ccc98588a819750a52100767616f9 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 25 Mar 2025 08:56:10 +0100 Subject: [PATCH 2/2] bump UC --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 017535fc..7b4a8bcc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ kotlin = "1.5.10" kotlinx-coroutines = "1.5.2" jetbrains-annotations = "23.0.0" -universalcraft = "388+feature-fabric-1.21.5" +universalcraft = "389" commonmark = "0.17.1" dom4j = "2.1.1"