Add ordered waypoints (ColeWeight compat)
This commit is contained in:
@@ -13,6 +13,7 @@ import io.ktor.client.statement.*
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.apis.UrsaManager
|
||||
import moe.nea.firmament.events.CommandEvent
|
||||
import moe.nea.firmament.features.inventory.buttons.InventoryButtons
|
||||
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
|
||||
import moe.nea.firmament.features.world.FairySouls
|
||||
@@ -218,6 +219,7 @@ fun firmamentCommand() = literal("firmament") {
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandEvent.SubCommand.publish(CommandEvent.SubCommand(this@literal))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@@ -12,6 +13,7 @@ import net.minecraft.command.CommandRegistryAccess
|
||||
import moe.nea.firmament.commands.CaseInsensitiveLiteralCommandNode
|
||||
import moe.nea.firmament.commands.DefaultSource
|
||||
import moe.nea.firmament.commands.literal
|
||||
import moe.nea.firmament.commands.thenLiteral
|
||||
|
||||
data class CommandEvent(
|
||||
val dispatcher: CommandDispatcher<DefaultSource>,
|
||||
@@ -20,6 +22,20 @@ data class CommandEvent(
|
||||
) : FirmamentEvent() {
|
||||
companion object : FirmamentEventBus<CommandEvent>()
|
||||
|
||||
/**
|
||||
* Register subcommands to `/firm`. For new top level commands use [CommandEvent]. Cannot be used to register
|
||||
* subcommands to other commands.
|
||||
*/
|
||||
data class SubCommand(
|
||||
val builder: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>,
|
||||
) : FirmamentEvent() {
|
||||
companion object : FirmamentEventBus<SubCommand>()
|
||||
|
||||
fun subcommand(name: String, block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit) {
|
||||
builder.thenLiteral(name, block)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCommand(name: String) {
|
||||
dispatcher.root.children.removeIf { it.name.equals(name, ignoreCase = false) }
|
||||
serverCommands?.root?.children?.removeIf { it.name.equals(name, ignoreCase = false) }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@@ -44,6 +45,10 @@ class RenderInWorldContext private constructor(
|
||||
val effectiveFov = (MC.instance.gameRenderer as AccessorGameRenderer).getFov_firmament(camera, tickDelta, true)
|
||||
val effectiveFovScaleFactor = 1 / tan(toRadians(effectiveFov) / 2)
|
||||
|
||||
fun color(color: me.shedaniel.math.Color) {
|
||||
color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f)
|
||||
}
|
||||
|
||||
fun color(red: Float, green: Float, blue: Float, alpha: Float) {
|
||||
RenderSystem.setShaderColor(red, green, blue, alpha)
|
||||
}
|
||||
@@ -140,6 +145,11 @@ class RenderInWorldContext private constructor(
|
||||
line(points.toList(), lineWidth)
|
||||
}
|
||||
|
||||
fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) {
|
||||
val cameraForward = Vector3f(0f, 0f, 1f).rotate(camera.rotation)
|
||||
line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth)
|
||||
}
|
||||
|
||||
fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
|
||||
RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram)
|
||||
RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(points.first()), 0.25).toFloat())
|
||||
|
||||
Reference in New Issue
Block a user