Add player icon to temporary waypoints

This commit is contained in:
Linnea Gräf
2024-01-27 18:16:11 +01:00
parent 9b0e966d66
commit 0cb6e308ac
5 changed files with 153 additions and 76 deletions

View File

@@ -154,7 +154,7 @@ git push "$REMOTE" "$BRANCH" "$newversion"
if command -v gh; then if command -v gh; then
echo Creating github release echo Creating github release
(set -x; gh release create "$newversion" -F "$releasenotes" "$basedir/build/libs/Firmament-$newversion.jar") (set -x; gh release create -t "Firmament $newversion" "$newversion" -F "$releasenotes" "$basedir/build/libs/Firmament-$newversion.jar")
else else
echo Could not find github command utility. Opening github releases echo Could not find github command utility. Opening github releases
xdg-open "https://github.com/nea89o/firmament/releases/new" xdg-open "https://github.com/nea89o/firmament/releases/new"

View File

@@ -9,7 +9,6 @@ package moe.nea.firmament.features.world
import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.events.WorldReadyEvent
@@ -36,19 +35,40 @@ object Waypoints : FirmamentFeature {
override val config get() = TConfig override val config get() = TConfig
val temporaryWaypointList = mutableMapOf<String, TemporaryWaypoint>() val temporaryWaypointList = mutableMapOf<String, TemporaryWaypoint>()
val temporaryWaypointMatcher = "x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() val temporaryWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern()
override fun onLoad() { override fun onLoad() {
WorldRenderLastEvent.subscribe { WorldRenderLastEvent.subscribe { event ->
temporaryWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } temporaryWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
if (temporaryWaypointList.isNotEmpty()) if (temporaryWaypointList.isNotEmpty())
RenderInWorldContext.renderInWorld(it) { RenderInWorldContext.renderInWorld(event) {
color(1f, 1f, 0f, 1f) color(1f, 1f, 0f, 1f)
temporaryWaypointList.forEach { (player, waypoint) -> temporaryWaypointList.forEach { (player, waypoint) ->
block(waypoint.pos) block(waypoint.pos)
} }
color(1f, 1f, 1f, 1f) color(1f, 1f, 1f, 1f)
temporaryWaypointList.forEach { (player, waypoint) -> temporaryWaypointList.forEach { (player, waypoint) ->
val skin =
MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
?.skinTextures
?.texture
withFacingThePlayer(waypoint.pos.toCenterPos()) {
waypoint(waypoint.pos, Text.translatable("firmament.waypoint.temporary", player)) waypoint(waypoint.pos, Text.translatable("firmament.waypoint.temporary", player))
if (skin != null) {
matrixStack.translate(0F, -20F, 0F)
// Head front
texture(
skin, 16, 16,
1 / 8f, 1 / 8f,
2 / 8f, 2 / 8f,
)
// Head overlay
texture(
skin, 16, 16,
5 / 8f, 1 / 8f,
6 / 8f, 2 / 8f,
)
}
}
} }
} }
} }
@@ -58,8 +78,7 @@ object Waypoints : FirmamentFeature {
ProcessChatEvent.subscribe { ProcessChatEvent.subscribe {
val matcher = temporaryWaypointMatcher.matcher(it.unformattedString) val matcher = temporaryWaypointMatcher.matcher(it.unformattedString)
if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) {
temporaryWaypointList.put( temporaryWaypointList[it.nameHeuristic] = TemporaryWaypoint(
it.nameHeuristic, TemporaryWaypoint(
BlockPos( BlockPos(
matcher.group(1).toInt(), matcher.group(1).toInt(),
matcher.group(2).toInt(), matcher.group(2).toInt(),
@@ -67,7 +86,6 @@ object Waypoints : FirmamentFeature {
), ),
TimeMark.now() TimeMark.now()
) )
)
} }
} }
} }

View File

@@ -0,0 +1,102 @@
/*
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem
import org.joml.Matrix4f
import net.minecraft.client.font.TextRenderer
import net.minecraft.client.render.BufferRenderer
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.assertTrueOr
@RenderContextDSL
class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
val matrixStack by worldContext::matrixStack
fun waypoint(position: BlockPos, label: Text) {
text(
label,
Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}")
)
}
fun text(
vararg texts: Text,
verticalAlign: RenderInWorldContext.VerticalAlign = RenderInWorldContext.VerticalAlign.CENTER
) {
assertTrueOr(texts.isNotEmpty()) { return@text }
for ((index, text) in texts.withIndex()) {
worldContext.matrixStack.push()
val width = MC.font.getWidth(text)
worldContext.matrixStack.translate(-width / 2F, verticalAlign.align(index, texts.size), 0F)
val vertexConsumer: VertexConsumer =
worldContext.vertexConsumers.getBuffer(RenderLayer.getTextBackgroundSeeThrough())
val matrix4f = worldContext.matrixStack.peek().positionMatrix
vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
vertexConsumer.vertex(matrix4f, width.toFloat(), MC.font.fontHeight.toFloat(), 0.0f)
.color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
worldContext.matrixStack.translate(0F, 0F, 0.01F)
MC.font.draw(
text,
0F,
0F,
-1,
false,
worldContext.matrixStack.peek().positionMatrix,
worldContext.vertexConsumers,
TextRenderer.TextLayerType.SEE_THROUGH,
0,
LightmapTextureManager.MAX_LIGHT_COORDINATE
)
worldContext.matrixStack.pop()
}
}
fun texture(
texture: Identifier, width: Int, height: Int,
u1: Float, v1: Float,
u2: Float, v2: Float,
) {
RenderSystem.setShaderTexture(0, texture)
RenderSystem.setShader(GameRenderer::getPositionColorTexProgram)
val hw = width / 2F
val hh = height / 2F
val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix
val buf = Tessellator.getInstance().buffer
buf.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE)
buf.fixedColor(255, 255, 255, 255)
buf.vertex(matrix4f, -hw, -hh, 0F)
.texture(u1, v1).next()
buf.vertex(matrix4f, -hw, +hh, 0F)
.texture(u1, v2).next()
buf.vertex(matrix4f, +hw, +hh, 0F)
.texture(u2, v2).next()
buf.vertex(matrix4f, +hw, -hh, 0F)
.texture(u2, v1).next()
buf.unfixColor()
BufferRenderer.drawWithGlobalProgram(buf.end())
}
}

View File

@@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.util.render
@DslMarker
annotation class RenderContextDSL {
}

View File

@@ -12,16 +12,11 @@ import java.lang.Math.toRadians
import org.joml.Matrix4f import org.joml.Matrix4f
import org.joml.Vector3f import org.joml.Vector3f
import kotlin.math.tan import kotlin.math.tan
import net.minecraft.client.font.TextRenderer
import net.minecraft.client.gl.VertexBuffer import net.minecraft.client.gl.VertexBuffer
import net.minecraft.client.render.BufferBuilder import net.minecraft.client.render.BufferBuilder
import net.minecraft.client.render.BufferRenderer
import net.minecraft.client.render.Camera import net.minecraft.client.render.Camera
import net.minecraft.client.render.GameRenderer import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.Tessellator import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.VertexFormat import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats import net.minecraft.client.render.VertexFormats
@@ -36,14 +31,14 @@ import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.mixins.accessor.AccessorGameRenderer import moe.nea.firmament.mixins.accessor.AccessorGameRenderer
import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.assertTrueOr
@RenderContextDSL
class RenderInWorldContext private constructor( class RenderInWorldContext private constructor(
private val tesselator: Tessellator, private val tesselator: Tessellator,
private val matrixStack: MatrixStack, val matrixStack: MatrixStack,
private val camera: Camera, private val camera: Camera,
private val tickDelta: Float, private val tickDelta: Float,
private val vertexConsumers: VertexConsumerProvider.Immediate, val vertexConsumers: VertexConsumerProvider.Immediate,
) { ) {
private val buffer = tesselator.buffer private val buffer = tesselator.buffer
val effectiveFov = (MC.instance.gameRenderer as AccessorGameRenderer).getFov_firmament(camera, tickDelta, true) val effectiveFov = (MC.instance.gameRenderer as AccessorGameRenderer).getFov_firmament(camera, tickDelta, true)
@@ -82,7 +77,7 @@ class RenderInWorldContext private constructor(
) )
} }
fun withFacingThePlayer(position: Vec3d, block: () -> Unit) { fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) {
matrixStack.push() matrixStack.push()
matrixStack.translate(position.x, position.y, position.z) matrixStack.translate(position.x, position.y, position.z)
val actualCameraDistance = position.distanceTo(camera.pos) val actualCameraDistance = position.distanceTo(camera.pos)
@@ -92,7 +87,7 @@ class RenderInWorldContext private constructor(
matrixStack.multiply(camera.rotation) matrixStack.multiply(camera.rotation)
matrixStack.scale(-0.025F, -0.025F, -1F) matrixStack.scale(-0.025F, -0.025F, -1F)
block() FacingThePlayerContext(this).run(block)
matrixStack.pop() matrixStack.pop()
vertexConsumers.drawCurrentLayer() vertexConsumers.drawCurrentLayer()
@@ -110,62 +105,13 @@ class RenderInWorldContext private constructor(
u2: Float, v2: Float, u2: Float, v2: Float,
) { ) {
withFacingThePlayer(position) { withFacingThePlayer(position) {
RenderSystem.setShaderTexture(0, texture) texture(texture, width, height, u1, v1, u2, v2)
RenderSystem.setShader(GameRenderer::getPositionColorTexProgram)
val hw = width / 2F
val hh = height / 2F
val matrix4f: Matrix4f = matrixStack.peek().positionMatrix
val buf = Tessellator.getInstance().buffer
buf.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE)
buf.fixedColor(255, 255, 255, 255)
buf.vertex(matrix4f, -hw, -hh, 0F)
.texture(u1, v1).next()
buf.vertex(matrix4f, -hw, +hh, 0F)
.texture(u1, v2).next()
buf.vertex(matrix4f, +hw, +hh, 0F)
.texture(u2, v2).next()
buf.vertex(matrix4f, +hw, -hh, 0F)
.texture(u2, v1).next()
buf.unfixColor()
BufferRenderer.drawWithGlobalProgram(buf.end())
} }
} }
fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER) { fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER) {
assertTrueOr(texts.isNotEmpty()) { return@text }
withFacingThePlayer(position) { withFacingThePlayer(position) {
for ((index, text) in texts.withIndex()) { text(*texts, verticalAlign = verticalAlign)
matrixStack.push()
val width = MC.font.getWidth(text)
matrixStack.translate(-width / 2F, verticalAlign.align(index, texts.size), 0F)
val vertexConsumer: VertexConsumer =
vertexConsumers.getBuffer(RenderLayer.getTextBackgroundSeeThrough())
val matrix4f = matrixStack.peek().positionMatrix
vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
vertexConsumer.vertex(matrix4f, width.toFloat(), MC.font.fontHeight.toFloat(), 0.0f)
.color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(0x70808080)
.light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next()
matrixStack.translate(0F, 0F, 0.01F)
MC.font.draw(
text,
0F,
0F,
-1,
false,
matrixStack.peek().positionMatrix,
vertexConsumers,
TextRenderer.TextLayerType.SEE_THROUGH,
0,
LightmapTextureManager.MAX_LIGHT_COORDINATE
)
matrixStack.pop()
}
} }
} }