diff options
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament/features')
-rw-r--r-- | src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt | 5 | ||||
-rw-r--r-- | src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt | 172 |
2 files changed, 165 insertions, 12 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt index cd399b3..b9c83e6 100644 --- a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt +++ b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt @@ -6,7 +6,6 @@ package moe.nea.firmament.features.diana -import org.joml.Vector3f import kotlin.time.Duration.Companion.seconds import net.minecraft.particle.ParticleTypes import net.minecraft.sound.SoundEvents @@ -33,6 +32,7 @@ object AncestralSpadeSolver { fun isEnabled() = DianaWaypoints.TConfig.ancestralSpadeSolver && SBData.skyblockLocation == "hub" + fun onKeyBind(event: WorldKeyboardEvent) { if (!isEnabled()) return if (!event.matches(DianaWaypoints.TConfig.ancestralSpadeTeleport)) return @@ -99,8 +99,7 @@ object AncestralSpadeSolver { color(1f, 1f, 0f, 0.5f) tinyBlock(it, 1f) color(1f, 1f, 0f, 1f) - val cameraForward = Vector3f(0f, 0f, 1f).rotate(event.camera.rotation) - line(event.camera.pos.add(Vec3d(cameraForward)), it, lineWidth = 3f) + tracer(it, lineWidth = 3f) } if (particlePositions.size > 2 && lastDing.passedTime() < 10.seconds && nextGuess != null) { color(0f, 1f, 0f, 0.7f) diff --git a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt index 05b1ba5..279be6f 100644 --- a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt +++ b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt @@ -1,20 +1,38 @@ /* * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> * * SPDX-License-Identifier: GPL-3.0-or-later */ package moe.nea.firmament.features.world +import me.shedaniel.math.Color +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.seconds +import net.minecraft.command.argument.BlockPosArgumentType +import net.minecraft.server.command.ServerCommandSource import net.minecraft.text.Text import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import moe.nea.firmament.Firmament +import moe.nea.firmament.commands.thenArgument +import moe.nea.firmament.commands.thenExecute +import moe.nea.firmament.commands.thenLiteral +import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.ProcessChatEvent +import moe.nea.firmament.events.TickEvent 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.ClipboardUtils import moe.nea.firmament.util.MC import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.render.RenderInWorldContext @@ -34,19 +52,34 @@ object Waypoints : FirmamentFeature { override val config get() = TConfig - val temporaryWaypointList = mutableMapOf<String, TemporaryWaypoint>() - val temporaryWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() + val temporaryPlayerWaypointList = mutableMapOf<String, TemporaryWaypoint>() + val temporaryPlayerWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() + + val waypoints = mutableListOf<BlockPos>() + var ordered = false + var orderedIndex = 0 + + @Serializable + data class ColeWeightWaypoint( + val x: Int, + val y: Int, + val z: Int, + val r: Int = 0, + val g: Int = 0, + val b: Int = 0, + ) + override fun onLoad() { WorldRenderLastEvent.subscribe { event -> - temporaryWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } - if (temporaryWaypointList.isNotEmpty()) + temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } + if (temporaryPlayerWaypointList.isNotEmpty()) RenderInWorldContext.renderInWorld(event) { color(1f, 1f, 0f, 1f) - temporaryWaypointList.forEach { (player, waypoint) -> + temporaryPlayerWaypointList.forEach { (player, waypoint) -> block(waypoint.pos) } color(1f, 1f, 1f, 1f) - temporaryWaypointList.forEach { (player, waypoint) -> + temporaryPlayerWaypointList.forEach { (player, waypoint) -> val skin = MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } ?.skinTextures @@ -73,12 +106,106 @@ object Waypoints : FirmamentFeature { } } WorldReadyEvent.subscribe { - temporaryWaypointList.clear() + temporaryPlayerWaypointList.clear() + } + CommandEvent.SubCommand.subscribe { event -> + event.subcommand("waypoint") { + thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> + thenExecute { + val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) + waypoints.add(position) + source.sendFeedback( + Text.stringifiedTranslatable( + "firmament.command.waypoint.added", + position.x, + position.y, + position.z + ) + ) + } + } + } + event.subcommand("waypoints") { + thenLiteral("clear") { + thenExecute { + waypoints.clear() + source.sendFeedback(Text.translatable("firmament.command.waypoint.clear")) + } + } + thenLiteral("toggleordered") { + thenExecute { + ordered = !ordered + if (ordered) { + val p = MC.player?.pos ?: Vec3d.ZERO + orderedIndex = + waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0 + } + source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered")) + } + } + thenLiteral("import") { + thenExecute { + val contents = ClipboardUtils.getTextContents() + val data = try { + Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents) + } catch (ex: Exception) { + Firmament.logger.error("Could not load waypoints from clipboard", ex) + source.sendError(Text.translatable("firmament.command.waypoint.import.error")) + return@thenExecute + } + waypoints.clear() + data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) } + source.sendFeedback( + Text.stringifiedTranslatable( + "firmament.command.waypoint.import", + data.size + ) + ) + } + } + } + } + WorldRenderLastEvent.subscribe { event -> + if (waypoints.isEmpty()) return@subscribe + RenderInWorldContext.renderInWorld(event) { + if (!ordered) { + color(0f, 0.3f, 0.7f, 0.5f) + waypoints.forEach { + block(it) + } + } else { + orderedIndex %= waypoints.size + val firstColor = Color.ofRGBA(0, 200, 40, 180) + color(firstColor) + tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f) + waypoints.wrappingWindow(orderedIndex, 3) + .zip( + listOf( + firstColor, + Color.ofRGBA(180, 200, 40, 150), + Color.ofRGBA(180, 80, 20, 140), + ) + ) + .reversed() + .forEach { (pos, col) -> + color(col) + block(pos) + } + } + } + } + TickEvent.subscribe { + if (waypoints.isEmpty() || !ordered) return@subscribe + orderedIndex %= waypoints.size + val p = MC.player?.pos ?: return@subscribe + if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) { + orderedIndex = (orderedIndex + 1) % waypoints.size + } } ProcessChatEvent.subscribe { - val matcher = temporaryWaypointMatcher.matcher(it.unformattedString) + val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString) if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { - temporaryWaypointList[it.nameHeuristic] = TemporaryWaypoint( + temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint( BlockPos( matcher.group(1).toInt(), matcher.group(2).toInt(), @@ -90,3 +217,30 @@ object Waypoints : FirmamentFeature { } } } + +fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> { + val result = ArrayList<E>(windowSize) + if (startIndex + windowSize < size) { + result.addAll(subList(startIndex, startIndex + windowSize)) + } else { + result.addAll(subList(startIndex, size)) + result.addAll(subList(0, minOf(size - startIndex - windowSize, startIndex))) + } + return result +} + + +fun FabricClientCommandSource.asFakeServer(): ServerCommandSource { + val source = this + return ServerCommandSource( + source.player, + source.position, + source.rotation, + null, + 0, + "FakeServerCommandSource", + Text.literal("FakeServerCommandSource"), + null, + source.player + ) +} |