diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/Font.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/Font.kt index e9f195566..f7c052f97 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/Font.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/Font.kt @@ -38,6 +38,7 @@ class Font( const val CHAR_MARGIN = 1 // used for background const val TOTAL_CHAR_HEIGHT = CHAR_HEIGHT + 2 * CHAR_MARGIN // top and bottom const val HORIZONTAL_SPACING = 1 + const val HORIZONTAL_SPACING_SHADOW = 0 const val VERTICAL_SPACING = 3 } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextComponentRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextComponentRenderer.kt index dfe36b2a2..41c7bec70 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextComponentRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextComponentRenderer.kt @@ -22,21 +22,35 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments.Companion.getOffset import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer +import de.bixilon.minosoft.util.KUtil.decide import de.bixilon.minosoft.util.MMath.ceil import glm_.vec2.Vec2i object TextComponentRenderer : ChatComponentRenderer { override fun render(initialOffset: Vec2i, offset: Vec2i, size: Vec2i, z: Int, element: Element, fontAlignment: ElementAlignments, renderWindow: RenderWindow, consumer: GUIVertexConsumer?, renderInfo: TextRenderInfo, text: TextComponent): Boolean { + if (text.message.isEmpty()) { + return false + } val elementMaxSize = element.maxSize + val shadow = text.formatting.contains(PreChatFormattingCodes.SHADOWED) // ToDo: Only 1 quad for the underline and the strikethrough var alignmentXOffset = 0 - if (size.x >= elementMaxSize.x || size.y >= elementMaxSize.y) { + if (size.x > elementMaxSize.x || size.y > elementMaxSize.y) { // The size is already bigger/equals the maximum size return true } + fun applyOffset() { + if (consumer == null) { + // preparing phase + renderInfo.lines += TextLineInfo() + } else { + alignmentXOffset = fontAlignment.getOffset(element.size.x, renderInfo.currentLine.width) + } + } + fun addY(height: Int): Boolean { val nextY = offset.y + height val nextSizeY = nextY - initialOffset.y + Font.TOTAL_CHAR_HEIGHT // add initial height for chars + end margin @@ -54,14 +68,9 @@ object TextComponentRenderer : ChatComponentRenderer { if (addY(Font.TOTAL_CHAR_HEIGHT)) { return true } - renderInfo.currentLine++ + renderInfo.currentLineNumber++ offset.x = initialOffset.x + Font.CHAR_MARGIN - if (consumer == null) { - // preparing phase - renderInfo.lines += TextLineInfo() - } else { - alignmentXOffset = fontAlignment.getOffset(element.size.x, renderInfo.lines[renderInfo.currentLine].width) - } + applyOffset() return false } @@ -78,7 +87,7 @@ object TextComponentRenderer : ChatComponentRenderer { return addX(width, false) } if (consumer == null) { - renderInfo.lines[renderInfo.currentLine].width += width + renderInfo.currentLine.width += width } offset.x = nextX if (nextSizeX > size.x) { @@ -94,15 +103,11 @@ object TextComponentRenderer : ChatComponentRenderer { if (nextSizeY > elementMaxSize.y) { return true } - if (consumer != null) { - alignmentXOffset = fontAlignment.getOffset(element.size.x, renderInfo.lines[renderInfo.currentLine].width) - } else { - renderInfo.lines += TextLineInfo() // add line 0 - } size.y = nextSizeY size.x += Font.CHAR_MARGIN * 2 offset += Font.CHAR_MARGIN } + applyOffset() for (charCode in text.message.codePoints().toArray()) { @@ -126,7 +131,7 @@ object TextComponentRenderer : ChatComponentRenderer { if (offset.x != initialOffset.x + Font.CHAR_MARGIN) { // add spacing between letters - width += Font.HORIZONTAL_SPACING + width += shadow.decide(Font.HORIZONTAL_SPACING_SHADOW, Font.HORIZONTAL_SPACING) } val previousY = offset.y @@ -147,7 +152,7 @@ object TextComponentRenderer : ChatComponentRenderer { consumer?.let { charData.render(letterOffset, z, text, it) } if (consumer == null) { - renderInfo.lines[renderInfo.currentLine].chars += char + renderInfo.currentLine.chars += char } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextRenderInfo.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextRenderInfo.kt index c4185f40b..c0e1b8499 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextRenderInfo.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/TextRenderInfo.kt @@ -15,5 +15,8 @@ package de.bixilon.minosoft.gui.rendering.font.renderer class TextRenderInfo( val lines: MutableList = mutableListOf(), - var currentLine: Int = 0, -) + var currentLineNumber: Int = 0, +) { + val currentLine: TextLineInfo + get() = lines[currentLineNumber] +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/AutoTextElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/AutoTextElement.kt index a29933093..c212b9f4a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/AutoTextElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/AutoTextElement.kt @@ -13,13 +13,15 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.text +import de.bixilon.minosoft.gui.rendering.gui.elements.ElementAlignments import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer class AutoTextElement( hudRenderer: HUDRenderer, var interval: Int, + alignment: ElementAlignments = ElementAlignments.LEFT, private val updater: () -> Any, -) : TextElement(hudRenderer, "") { +) : TextElement(hudRenderer, "", alignment) { private var remainingTicks = 0 init { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt index 38b05ed1d..200224f33 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextElement.kt @@ -46,11 +46,16 @@ open class TextElement( prepared = false } + private var emptyMessage: Boolean = true + final override var textComponent: ChatComponent = ChatComponent.of("") protected set(value) { field = value + emptyMessage = value.message.isEmpty() val prefSize = Vec2i.EMPTY - ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, prefSize, 0, InfiniteSizeElement(hudRenderer), fontAlignment, renderWindow, null, TextRenderInfo(), value) + if (!emptyMessage) { + ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, prefSize, 0, InfiniteSizeElement(hudRenderer), fontAlignment, renderWindow, null, TextRenderInfo(), value) + } this.prefSize = prefSize apply() } @@ -62,17 +67,16 @@ open class TextElement( } override fun silentApply() { - size = Vec2i.EMPTY - if (textComponent.message.isNotEmpty()) { - val size = Vec2i.EMPTY + val size = Vec2i.EMPTY + if (!emptyMessage) { val renderInfo = TextRenderInfo() ChatComponentRenderer.render(Vec2i.EMPTY, Vec2i.EMPTY, size, 0, this, fontAlignment, renderWindow, null, renderInfo, textComponent) - - renderInfo.currentLine = 0 + renderInfo.currentLineNumber = 0 this.renderInfo = renderInfo - this.size = size - preparedSize = size } + + this.size = size + preparedSize = size } override fun apply() { @@ -96,10 +100,13 @@ open class TextElement( override fun render(offset: Vec2i, z: Int, consumer: GUIVertexConsumer): Int { + if (emptyMessage) { + return 0 + } val initialOffset = offset + margin.offset ChatComponentRenderer.render(initialOffset, Vec2i(initialOffset), Vec2i.EMPTY, z + 1, this, fontAlignment, renderWindow, consumer, renderInfo, textComponent) - renderInfo.currentLine = 0 + renderInfo.currentLineNumber = 0 prepared = true if (background) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/hud/DebugHUD.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/hud/DebugHUD.kt index 7b0289083..acd5416e2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/hud/DebugHUD.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/hud/DebugHUD.kt @@ -63,7 +63,7 @@ class DebugHUD(val hudRenderer: HUDRenderer) : HUD { private fun initLeft(): Element { val layout = RowLayout(hudRenderer) - layout.margin = Vec4i(5) + layout.margin = Vec4i(2) layout += TextElement(hudRenderer, TextComponent(RunConfiguration.VERSION_STRING, ChatColors.RED)) layout += AutoTextElement(hudRenderer, 1) { "FPS ${renderWindow.renderStats.smoothAvgFPS.round10}" } renderWindow[WorldRenderer]?.apply { @@ -93,7 +93,7 @@ class DebugHUD(val hudRenderer: HUDRenderer) : HUD { layout += LineSpacerElement(hudRenderer) - layout += TextElement(hudRenderer, "Difficulty ${connection.world.difficulty.format()}, ${connection.world.difficultyLocked.decide("locked", "unlocked")}", ElementAlignments.RIGHT).apply { + layout += TextElement(hudRenderer, "Difficulty ${connection.world.difficulty.format()}, ${connection.world.difficultyLocked.decide("locked", "unlocked")}").apply { connection.registerEvent(CallbackEventInvoker.of { text = "Difficulty ${it.difficulty.format()}, ${it.locked.decide("locked", "unlocked")}" }) @@ -104,7 +104,7 @@ class DebugHUD(val hudRenderer: HUDRenderer) : HUD { private fun initRight(): Element { val layout = RowLayout(hudRenderer, ElementAlignments.RIGHT) - layout.margin = Vec4i(5) + layout.margin = Vec4i(2) layout += TextElement(hudRenderer, "Java ${Runtime.version()} ${System.getProperty("sun.arch.data.model")}bit", ElementAlignments.RIGHT) layout += LineSpacerElement(hudRenderer) @@ -137,6 +137,14 @@ class DebugHUD(val hudRenderer: HUDRenderer) : HUD { layout += TextElement(hudRenderer, "Mods ${ModLoader.MOD_MAP.size}x loaded, ${connection.size}x listeners", ElementAlignments.RIGHT) + layout += LineSpacerElement(hudRenderer) + + renderWindow.inputHandler.camera.apply { + layout += AutoTextElement(hudRenderer, 1, ElementAlignments.RIGHT) { + // ToDo: Tags + target ?: return@AutoTextElement "" + } + } return layout } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt index 609de231c..c09183e97 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt @@ -69,6 +69,7 @@ class Camera( var cameraRight = Vec3d(0.0, 0.0, -1.0) private var cameraUp = Vec3d(0.0, 1.0, 0.0) + // ToDo: They should also be available in headless mode var target: RaycastHit? = null private set var blockTarget: BlockRaycastHit? = null // Block target or if blocked by entity null diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt index 579c5d7fc..1fdebc111 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/BlockRaycastHit.kt @@ -15,7 +15,9 @@ package de.bixilon.minosoft.gui.rendering.input.camera.hit import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.BlockState -import de.bixilon.minosoft.util.KUtil.format +import de.bixilon.minosoft.data.text.BaseComponent +import de.bixilon.minosoft.data.text.ChatComponent +import de.bixilon.minosoft.data.text.TextFormattable import glm_.vec3.Vec3d import glm_.vec3.Vec3i @@ -25,23 +27,29 @@ open class BlockRaycastHit( hitDirection: Directions, val blockState: BlockState, val blockPosition: Vec3i, -) : RaycastHit(position, distance, hitDirection) { +) : RaycastHit(position, distance, hitDirection), TextFormattable { val hitPosition = position - blockPosition override fun toString(): String { - val ret = StringBuilder() - ret.append(blockPosition) - ret.append(": ") - ret.append(blockState.block.resourceLocation) + return toText().legacyText + } - for ((key, value) in blockState.properties) { - ret.append('\n') - ret.append(' ') - ret.append(key.group) - ret.append(": ") - ret.append(value.format()) + override fun toText(): ChatComponent { + val text = BaseComponent() + + text += "Block target " + text += blockPosition + text += ": " + text += blockState.block.resourceLocation + + for ((property, value) in blockState.properties) { + text += "\n" + text += property + text += ": " + text += value } - return ret.toString() + return text } + } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt index f2b164fc6..35d586fa3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/EntityRaycastHit.kt @@ -34,20 +34,25 @@ class EntityRaycastHit( override fun toText(): ChatComponent { val text = BaseComponent() + text += "Entity target " text += position - text += (": ") + text += ": " text += entity.entityType.resourceLocation - text += "\n Id: " - text += entity.id - - text += "\n UUID: " - text += entity.uuid text += "\n" + text += "Id: ${entity.id}" + text += "\n" + text += "UUID: ${entity.uuid}" - for ((key, value) in entity.entityMetaDataFormatted) { - text += "\n " - text += key + + val metaData = entity.entityMetaDataFormatted + if (metaData.isNotEmpty()) { + text += "\n" + } + + for ((property, value) in metaData) { + text += "\n" + text += property text += ": " text += value } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt index 2ceee71ab..7de134c9a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/hit/FluidRaycastHit.kt @@ -15,8 +15,10 @@ package de.bixilon.minosoft.gui.rendering.input.camera.hit import de.bixilon.minosoft.data.direction.Directions import de.bixilon.minosoft.data.registries.blocks.BlockState -import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties import de.bixilon.minosoft.data.registries.fluid.Fluid +import de.bixilon.minosoft.data.text.BaseComponent +import de.bixilon.minosoft.data.text.ChatComponent +import de.bixilon.minosoft.data.text.TextFormattable import glm_.vec3.Vec3d import glm_.vec3.Vec3i @@ -27,9 +29,27 @@ class FluidRaycastHit( val blockState: BlockState, val blockPosition: Vec3i, val fluid: Fluid, -) : RaycastHit(position, distance, hitDirection) { +) : RaycastHit(position, distance, hitDirection), TextFormattable { override fun toString(): String { - return "$blockPosition: ${fluid.resourceLocation}\n Height: ${fluid.getHeight(blockState)}\n Level: ${blockState.properties[BlockProperties.FLUID_LEVEL]}" + return toText().legacyText + } + + override fun toText(): ChatComponent { + val text = BaseComponent() + + text += "Fluid target " + text += blockPosition + text += ": " + text += fluid.resourceLocation + + for ((property, value) in blockState.properties) { + text += "\n" + text += property + text += ": " + text += value + } + + return text } } diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index 3f9aca0a3..8b46b4dd4 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -29,6 +29,7 @@ import de.bixilon.minosoft.util.enum.AliasableEnum import de.bixilon.minosoft.util.json.JSONSerializer import glm_.vec2.Vec2t import glm_.vec3.Vec3t +import glm_.vec4.Vec4t import okio.Buffer import sun.misc.Unsafe import java.io.PrintWriter @@ -255,6 +256,8 @@ object KUtil { is Float -> "§d%.3f".format(this) is Double -> "§d%.4f".format(this) is Number -> TextComponent(this).color(ChatColors.LIGHT_PURPLE) + is ResourceLocation -> TextComponent(this.toString()).color(ChatColors.GOLD) + is Vec4t<*> -> "(${this.x.format()} ${this.y.format()} ${this.z.format()} ${this.w.format()})" is Vec3t<*> -> "(${this.x.format()} ${this.y.format()} ${this.z.format()})" is Vec2t<*> -> "(${this.x.format()} ${this.y.format()})" else -> this.toString()