From 2c9c38868345d5e133179597936f8e584075b8de Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Sun, 12 Nov 2023 14:45:05 +0100 Subject: Add temporary waypoints and /firm sendcoords --- src/main/kotlin/moe/nea/firmament/commands/rome.kt | 11 +++- .../moe/nea/firmament/events/ProcessChatEvent.kt | 9 ++- .../moe/nea/firmament/features/FeatureManager.kt | 2 + .../moe/nea/firmament/features/world/Waypoints.kt | 72 ++++++++++++++++++++++ .../moe/nea/firmament/util/FirmFormatters.kt | 6 ++ src/main/kotlin/moe/nea/firmament/util/MC.kt | 4 ++ .../firmament/util/render/RenderInWorldContext.kt | 30 ++++++++- 7 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt (limited to 'src/main/kotlin/moe') diff --git a/src/main/kotlin/moe/nea/firmament/commands/rome.kt b/src/main/kotlin/moe/nea/firmament/commands/rome.kt index f4c20bd..b175d4b 100644 --- a/src/main/kotlin/moe/nea/firmament/commands/rome.kt +++ b/src/main/kotlin/moe/nea/firmament/commands/rome.kt @@ -36,8 +36,9 @@ fun firmamentCommand() = literal("firmament") { } thenArgument("property", string()) { property -> suggestsList { - (AllConfigsGui.allConfigs.find { it.name == this[config] }?:return@suggestsList listOf()) - .allOptions.entries.asSequence().filter { it.value.handler is BooleanHandler }.map { it.key } + (AllConfigsGui.allConfigs.find { it.name == this[config] } ?: return@suggestsList listOf()) + .allOptions.entries.asSequence().filter { it.value.handler is BooleanHandler } + .map { it.key } .asIterable() } thenExecute { @@ -89,6 +90,12 @@ fun firmamentCommand() = literal("firmament") { InventoryButtons.openEditor() } } + thenLiteral("sendcoords") { + thenExecute { + val p = MC.player ?: return@thenExecute + MC.sendServerChat("x: ${p.blockX}, y: ${p.blockY}, z: ${p.blockZ}") + } + } thenLiteral("storage") { thenExecute { ScreenUtil.setScreenLater(StorageOverlayScreen()) diff --git a/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt index 413c209..b1b66b0 100644 --- a/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt +++ b/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt @@ -6,8 +6,8 @@ package moe.nea.firmament.events -import moe.nea.firmament.util.unformattedString import net.minecraft.text.Text +import moe.nea.firmament.util.unformattedString /** * Behaves like [AllowChatEvent], but is triggered even when cancelled by other mods. Intended for data collection. @@ -16,6 +16,13 @@ import net.minecraft.text.Text data class ProcessChatEvent(val text: Text, val wasExternallyCancelled: Boolean) : FirmamentEvent.Cancellable() { val unformattedString = text.unformattedString + val nameHeuristic: String? = run { + val firstColon = unformattedString.indexOf(':') + if (firstColon < 0) return@run null + val firstSpace = unformattedString.lastIndexOf(' ', firstColon) + unformattedString.substring(firstSpace + 1 until firstColon).takeIf { it.isNotEmpty() } + } + init { if (wasExternallyCancelled) cancelled = true diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index 4888f54..30036b7 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -27,6 +27,7 @@ import moe.nea.firmament.features.inventory.buttons.InventoryButtons import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlay import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures import moe.nea.firmament.features.world.FairySouls +import moe.nea.firmament.features.world.Waypoints import moe.nea.firmament.util.data.DataHolder object FeatureManager : DataHolder(serializer(), "features", ::Config) { @@ -56,6 +57,7 @@ object FeatureManager : DataHolder(serializer(), "feature loadFeature(StorageOverlay) loadFeature(CraftingOverlay) loadFeature(PowerUserTools) + loadFeature(Waypoints) loadFeature(ChatLinks) loadFeature(InventoryButtons) loadFeature(CompatibliltyFeatures) diff --git a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt new file mode 100644 index 0000000..de25a37 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2023 Linnea Gräf + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.features.world + +import kotlin.time.Duration.Companion.hours +import kotlin.time.Duration.Companion.seconds +import net.minecraft.text.Text +import net.minecraft.util.math.BlockPos +import moe.nea.firmament.events.ProcessChatEvent +import moe.nea.firmament.events.WorldReadyEvent +import moe.nea.firmament.events.WorldRenderLastEvent +import moe.nea.firmament.features.FirmamentFeature +import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.render.RenderInWorldContext + +object Waypoints : FirmamentFeature { + override val identifier: String + get() = "waypoints" + + object TConfig : ManagedConfig(identifier) { + val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds } + } + + data class TemporaryWaypoint( + val pos: BlockPos, + val postedAt: TimeMark, + ) + + override val config get() = TConfig + + val temporaryWaypointList = mutableMapOf() + val temporaryWaypointMatcher = "x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() + override fun onLoad() { + WorldRenderLastEvent.subscribe { + temporaryWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } + if (temporaryWaypointList.isNotEmpty()) + RenderInWorldContext.renderInWorld(it) { + color(1f, 1f, 0f, 1f) + temporaryWaypointList.forEach { (player, waypoint) -> + block(waypoint.pos) + } + color(1f, 1f, 1f, 1f) + temporaryWaypointList.forEach { (player, waypoint) -> + waypoint(waypoint.pos, Text.translatable("firmament.waypoint.temporary", player)) + } + } + } + WorldReadyEvent.subscribe { + temporaryWaypointList.clear() + } + ProcessChatEvent.subscribe { + val matcher = temporaryWaypointMatcher.matcher(it.unformattedString) + if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { + temporaryWaypointList.put( + it.nameHeuristic, TemporaryWaypoint( + BlockPos( + matcher.group(1).toInt(), + matcher.group(2).toInt(), + matcher.group(3).toInt(), + ), + TimeMark.now() + ) + ) + } + } + } +} diff --git a/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt b/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt index 96a4389..c07f53d 100644 --- a/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt +++ b/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt @@ -28,6 +28,12 @@ object FirmFormatters { return formatCurrency(long) + (if (digits.isEmpty()) "" else ".$digits") } + fun formatDistance(distance: Double): String { + if (distance < 10) + return "%.1fm".format(distance) + return "%dm".format(distance.toInt()) + } + fun formatTimespan(duration: Duration): String { return duration.toString() } diff --git a/src/main/kotlin/moe/nea/firmament/util/MC.kt b/src/main/kotlin/moe/nea/firmament/util/MC.kt index 347a15e..f3fc754 100644 --- a/src/main/kotlin/moe/nea/firmament/util/MC.kt +++ b/src/main/kotlin/moe/nea/firmament/util/MC.kt @@ -51,6 +51,10 @@ object MC { ) } + fun sendServerChat(text: String) { + player?.networkHandler?.sendChatMessage(text) + } + fun sendCommand(command: String) { player?.networkHandler?.sendCommand(command) } diff --git a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt index f636529..aa54979 100644 --- a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt @@ -8,8 +8,10 @@ package moe.nea.firmament.util.render import com.mojang.blaze3d.systems.RenderSystem import java.lang.Math.pow +import java.lang.Math.toRadians import org.joml.Matrix4f import org.joml.Vector3f +import kotlin.math.tan import net.minecraft.client.font.TextRenderer import net.minecraft.client.gl.VertexBuffer import net.minecraft.client.render.BufferBuilder @@ -28,6 +30,8 @@ import net.minecraft.text.Text import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Vec3d import moe.nea.firmament.events.WorldRenderLastEvent +import moe.nea.firmament.mixins.accessor.AccessorGameRenderer +import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.MC import moe.nea.firmament.util.assertTrueOr @@ -35,9 +39,12 @@ class RenderInWorldContext private constructor( private val tesselator: Tessellator, private val matrixStack: MatrixStack, private val camera: Camera, + private val tickDelta: Float, private val vertexConsumers: VertexConsumerProvider.Immediate, ) { private val buffer = tesselator.buffer + val effectiveFov = (MC.instance.gameRenderer as AccessorGameRenderer).getFov_firmament(camera, tickDelta, true) + val effectiveFovScaleFactor = 1 / tan(toRadians(effectiveFov) / 2) fun color(red: Float, green: Float, blue: Float, alpha: Float) { RenderSystem.setShaderColor(red, green, blue, alpha) @@ -65,15 +72,24 @@ class RenderInWorldContext private constructor( } fun waypoint(position: BlockPos, label: Text) { - text(position.toCenterPos(), label, Text.literal("§e${MC.player?.pos?.distanceTo(position.toCenterPos())}m")) + text( + position.toCenterPos(), + label, + Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}") + ) } fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER) { assertTrueOr(texts.isNotEmpty()) { return@text } matrixStack.push() matrixStack.translate(position.x, position.y, position.z) + val actualCameraDistance = position.distanceTo(camera.pos) + val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0) + val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance) + matrixStack.translate(vec.x, vec.y, vec.z) matrixStack.multiply(camera.rotation) matrixStack.scale(-0.025F, -0.025F, -1F) + for ((index, text) in texts.withIndex()) { matrixStack.push() val width = MC.font.getWidth(text) @@ -145,7 +161,16 @@ class RenderInWorldContext private constructor( } companion object { - private fun doLine(matrix: Entry, buf: BufferBuilder, i: Number, j: Number, k: Number, x: Number, y: Number, z: Number) { + private fun doLine( + matrix: Entry, + buf: BufferBuilder, + i: Number, + j: Number, + k: Number, + x: Number, + y: Number, + z: Number + ) { val normal = Vector3f(x.toFloat(), y.toFloat(), z.toFloat()) .sub(i.toFloat(), j.toFloat(), k.toFloat()) .mul(-1F) @@ -226,6 +251,7 @@ class RenderInWorldContext private constructor( RenderSystem.renderThreadTesselator(), event.matrices, event.camera, + event.tickDelta, event.vertexConsumers ) -- cgit