diff options
author | hannibal2 <24389977+hannibal002@users.noreply.github.com> | 2024-09-05 00:51:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-05 00:51:21 +0200 |
commit | 59eef491fef0d7dd7f4018febe4d91de01369cbe (patch) | |
tree | db9a99de84cc96198db95047eda524737f6a5db1 /src/main/java | |
parent | bf152b4376c453f9eee76a6521377cc4062e9838 (diff) | |
download | skyhanni-59eef491fef0d7dd7f4018febe4d91de01369cbe.tar.gz skyhanni-59eef491fef0d7dd7f4018febe4d91de01369cbe.tar.bz2 skyhanni-59eef491fef0d7dd7f4018febe4d91de01369cbe.zip |
Backend: Added Tags to Graph Editor (#2464)
Co-authored-by: Thunderblade73 <85900443+thunderblade73@users.noreply.github.com>
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java')
6 files changed, 221 insertions, 36 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt index ab5d1ca2d..89fd413f5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt @@ -42,17 +42,30 @@ value class Graph( out.beginObject() value.forEach { out.name(it.id.toString()).beginObject() + out.name("Position").value(with(it.position) { "$x:$y:$z" }) - if (it.name != null) { - out.name("Name").value(it.name) + + it.name?.let { + out.name("Name").value(it) + } + + it.tagNames?.takeIf { it.isNotEmpty() }?.let { + out.name("Tags") + out.beginArray() + for (tagName in it) { + out.value(tagName) + } + out.endArray() } + out.name("Neighbours") out.beginObject() - it.neighbours.forEach { (node, weight) -> + for ((node, weight) in it.neighbours) { val id = node.id.toString() out.name(id).value(weight.round(2)) } out.endObject() + out.endObject() } out.endObject() @@ -66,6 +79,7 @@ value class Graph( reader.beginObject() var position: LorenzVec? = null var name: String? = null + var tags: List<String>? = null var neighbors = mutableListOf<Pair<Int, Double>>() while (reader.hasNext()) { when (reader.nextName()) { @@ -89,9 +103,19 @@ value class Graph( name = reader.nextString() } + "Tags" -> { + tags = mutableListOf() + reader.beginArray() + while (reader.hasNext()) { + val tagName = reader.nextString() + tags.add(tagName) + } + reader.endArray() + } + } } - val node = GraphNode(id, position!!, name) + val node = GraphNode(id, position!!, name, tags) list.add(node) neighbourMap[node] = neighbors reader.endObject() @@ -111,7 +135,8 @@ value class Graph( } } -class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null) { +// The node object that gets parsed from/to json +class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, val tagNames: List<String>? = null) { /** Keys are the neighbours and value the edge weight (e.g. Distance) */ lateinit var neighbours: Map<GraphNode, Double> diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt b/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt new file mode 100644 index 000000000..6cfac664b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt @@ -0,0 +1,41 @@ +package at.hannibal2.skyhanni.data.model + +enum class GraphNodeTag(val internalName: String?, val displayName: String, val description: String) { + DEV("dev", "Dev", "Intentionally marked as dev."), // E.g. Spawn points, todos, etc + + // Everywhere + NPC("npc", "§eNPC", "A NPC entity."), // also take from neu repo + AREA("area", "§aArea", "A SkyBlock Area."), + POI("poi", "PoI", "Point of interest."), + LAUNCH_PAD("launch", "Launch Pad", "Slime blocks sending you to another server."), + + // on multiple islands + ROMEO("romeo", "Romeo & Juliette Quest", "Blocks related to the Romeo and Juliette/Ring of Love quest line."), + RACE("race", "Race Start/Stop", "A race start or stop point."), + SLAYER("slayer", "Slayer", "A Slayer area"), + // hoppity + + // Hub + HUB_12_STARTER("starter_npc", "Starter NPC", "One of the 12 starter NPC's you need to talk to."), + // diana + + // Farming Islands: Pelts + FARMING_CROP("farming_crop", "Farming Crop", "A spot where you can break crops on farming islands."), + + // Rift + RIFT_ENIGMA("rift_enigma", "§5Enigma Soul", "Enigma Souls in the rift."), + RIFT_EYE("rift_eye", "§4Eye", "An Eye in the rift to teleport to."), + + // Spider's Den + SPIDER_RELIC("SPIDER_RELIC", "§5Relic", "An relic in the Spider's Den."), + + // Dwarven Mines + MINES_EMISSARY("mines_emissary", "§6Emissary", "A Emissary from the king."), + // commission areas + + ; + + companion object { + fun byId(internalName: String?): GraphNodeTag? = values().firstOrNull { it.internalName == internalName } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt index f1a5001ad..d7e6ff8e1 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.data.model import at.hannibal2.skyhanni.utils.KeyboardManager import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked +import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.OSUtils import at.hannibal2.skyhanni.utils.StringUtils.insert import kotlinx.coroutines.runBlocking @@ -14,12 +15,12 @@ class TextInput { var textBox: String = "" private var carriage: Int? = null - fun editText() = textBox.let { + fun editText(textColor: LorenzColor = LorenzColor.WHITE, carriageColor: LorenzColor = LorenzColor.GREEN) = textBox.let { with(carriage) { if (this == null) it - else it.insert(this, '|') + else it.insert(this, "${carriageColor.getChatColor()}|${textColor.getChatColor()}") } - }.replace("§", "&&") + }.replace("(?<!§.\\|)§(?!.\\|§.)".toRegex(), "&&") fun finalText() = textBox.replace("&&", "§") diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt index f4d98e782..a06b3dcbc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt @@ -9,6 +9,7 @@ import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.addString import at.hannibal2.skyhanni.utils.CollectionUtils.collectWhile import at.hannibal2.skyhanni.utils.CollectionUtils.consumeWhile import at.hannibal2.skyhanni.utils.DisplayTableEntry @@ -220,7 +221,7 @@ object HoppityCollectionStats { val foundRabbitCount = getFoundRabbitsFromHypixel(event) if (loggedRabbitCount < foundRabbitCount) { - newList.add(Renderable.string("")) + newList.addString("") newList.add( Renderable.wrappedString( "§cPlease Scroll through \n" + "§call pages!", diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt index d2d351878..b6c1c81d0 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt @@ -21,6 +21,7 @@ import at.hannibal2.skyhanni.events.LorenzWarpEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.CollectionUtils.addString import at.hannibal2.skyhanni.utils.CollectionUtils.filterNotNullKeys import at.hannibal2.skyhanni.utils.ColorUtils.getFirstColorCode import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor @@ -284,12 +285,12 @@ object TunnelsMaps { ), ) } else { - add(Renderable.string("")) + addString("") } } } else { - add(Renderable.string("")) - add(Renderable.string("")) + addString("") + addString("") } addAll(locationDisplay) } diff --git a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt index ababb9b65..ece6d16cb 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt @@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.test import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.data.model.Graph import at.hannibal2.skyhanni.data.model.GraphNode +import at.hannibal2.skyhanni.data.model.GraphNodeTag import at.hannibal2.skyhanni.data.model.TextInput import at.hannibal2.skyhanni.data.model.findShortestPathAsGraph import at.hannibal2.skyhanni.data.model.toJson @@ -38,6 +39,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable import kotlin.math.sqrt import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @SkyHanniModule object GraphEditor { @@ -84,7 +86,7 @@ object GraphEditor { private val edgeDijkstraColor = LorenzColor.DARK_BLUE.addOpacity(150) val scrollValue = ScrollValue() - var namedNodeList: List<Renderable> = emptyList() + var nodesDisplay = emptyList<Renderable>() var lastUpdate = SimpleTimeMark.farPast() @SubscribeEvent @@ -128,7 +130,7 @@ object GraphEditor { } if (inTextMode) { add("§eFormat: ${textBox.finalText()}") - add("§eRaw: ${textBox.editText()}") + add("§eRaw: ${textBox.editText(textColor = LorenzColor.YELLOW)}") } } @@ -137,7 +139,7 @@ object GraphEditor { if (!isEnabled()) return config.namedNodesList.renderRenderables( buildList { - val list = getNamedNodes() + val list = getNodeNames() val size = list.size addString("§eGraph Nodes: $size") val height = (size * 10).coerceAtMost(150) @@ -149,34 +151,117 @@ object GraphEditor { ) } - private fun getNamedNodes(): List<Renderable> { + private fun getNodeNames(): List<Renderable> { if (lastUpdate.passedSince() > 250.milliseconds) { - lastUpdate = SimpleTimeMark.now() - namedNodeList = calculateNamedNodes() + updateNodeNames() } - return namedNodeList + return nodesDisplay } + private fun updateNodeNames() { + lastUpdate = SimpleTimeMark.now() + nodesDisplay = drawNodeNames() + } + + private fun updateTagView(node: GraphingNode) { + lastUpdate = SimpleTimeMark.now() + 60.seconds + nodesDisplay = drawTagNames(node) + } + + private fun drawTagNames(node: GraphingNode): List<Renderable> = buildList { + addString("§eChange tag for node '${node.name}§e'") + addString("") + + for (tag in GraphNodeTag.entries) { + val state = if (tag in node.tags) "§aYES" else "§cNO" + val name = state + " §r" + tag.displayName + add(createTagName(name, tag, node)) + } + addString("") + add( + Renderable.clickAndHover( + "§cGo Back!", + tips = listOf("§eClick to go back to the node list!"), + onClick = { + updateNodeNames() + }, + ), + ) + } + + private fun createTagName( + name: String, + tag: GraphNodeTag, + node: GraphingNode, + ) = Renderable.clickAndHover( + name, + tips = listOf( + "Tag ${tag.name}", + "§7${tag.description}", + "", + "§eClick to set tag for ${node.name} to ${tag.name}!", + ), + onClick = { + if (tag in node.tags) { + node.tags.remove(tag) + } else { + node.tags.add(tag) + } + updateTagView(node) + }, + ) - private fun calculateNamedNodes(): List<Renderable> = buildList { + private fun drawNodeNames(): List<Renderable> = buildList { for ((node, distance: Double) in nodes.map { it to it.position.distanceSqToPlayer() }.sortedBy { it.second }) { val name = node.name?.takeIf { !it.isBlank() } ?: continue val color = if (node == activeNode) "§a" else "§7" val distanceFormat = sqrt(distance).toInt().addSeparators() - val text = "${color}Node §r$name §f($distanceFormat)" - add( - Renderable.clickAndHover( - text, - emptyList(), - onClick = { - activeNode = node - lastUpdate = SimpleTimeMark.farPast() - }, - ), - ) + val tagText = node.tags.let { + if (it.isEmpty()) { + " §cNo tag§r" + } else { + val text = node.tags.map { it.internalName }.joinToString(", ") + " §f($text)" + } + } + + val text = "${color}Node §r$name$tagText §7[$distanceFormat]" + add(createNodeTextLine(text, name, node)) } } + private fun MutableList<Renderable>.createNodeTextLine( + text: String, + name: String, + node: GraphingNode, + ): Renderable = Renderable.clickAndHover( + text, + tips = buildList { + add("Node '$name'") + add("") + + if (node.tags.isNotEmpty()) { + add("Tags: ") + for (tag in node.tags) { + add(" §8- §r${tag.displayName}") + } + add("") + } + + add("§eClick to select/deselect this node!") + add("§eControl-Click to edit the tags for this node!") + + }, + onClick = { + if (KeyboardManager.isModifierKeyDown()) { + updateTagView(node) + } else { + activeNode = node + updateNodeNames() + } + }, + ) + private fun feedBackInTutorial(text: String) { if (inTutorialMode) { ChatUtils.chat(text) @@ -199,10 +284,11 @@ object GraphEditor { minimumAlpha = 0.2f, inverseAlphaScale = true, ) - if (node.name == null) return + + val nodeName = node.name ?: return this.drawDynamicText( node.position, - node.name!!, + nodeName, 0.8, ignoreBlocks = seeThroughBlocks || node.position.distanceSqToPlayer() < 100, smallestDistanceVew = 12.0, @@ -210,6 +296,20 @@ object GraphEditor { yOff = -15f, maxDistance = 80, ) + + val tags = node.tags + if (tags.isEmpty()) return + val tagText = tags.map { it.displayName }.joinToString(" §f+ ") + this.drawDynamicText( + node.position, + tagText, + 0.8, + ignoreBlocks = seeThroughBlocks || node.position.distanceSqToPlayer() < 100, + smallestDistanceVew = 12.0, + ignoreY = true, + yOff = 0f, + maxDistance = 80, + ) } private fun LorenzRenderWorldEvent.drawEdge(edge: GraphingEdge) = this.draw3DLine_nea( @@ -359,6 +459,7 @@ object GraphEditor { val length = edges.sumOf { it.node1.position.distance(it.node2.position) }.toInt().addSeparators() ChatUtils.chat( "§lStats\n" + + "§eNamed Nodes: ${nodes.count { it.name != null }.addSeparators()}\n" + "§eNodes: ${nodes.size.addSeparators()}\n" + "§eEdges: ${edges.size.addSeparators()}\n" + "§eLength: $length", @@ -428,7 +529,7 @@ object GraphEditor { private fun compileGraph(): Graph { prune() val indexedTable = nodes.mapIndexed { index, node -> node.id to index }.toMap() - val nodes = nodes.mapIndexed { index, it -> GraphNode(index, it.position, it.name) } + val nodes = nodes.mapIndexed { index, it -> GraphNode(index, it.position, it.name, it.tags.mapNotNull { it.internalName }) } val neighbours = this.nodes.map { node -> edges.filter { it.isInEdge(node) }.map { edge -> val otherNode = if (node == edge.node1) edge.node2 else edge.node1 @@ -441,7 +542,16 @@ object GraphEditor { fun import(graph: Graph) { clear() - nodes.addAll(graph.map { GraphingNode(it.id, it.position, it.name) }) + nodes.addAll( + graph.map { + GraphingNode( + it.id, + it.position, + it.name, + it.tagNames?.mapNotNull { GraphNodeTag.byId(it) }?.toMutableList() ?: mutableListOf(), + ) + }, + ) val translation = graph.mapIndexed { index, it -> it to nodes[index] }.toMap() edges.addAll( graph.map { node -> @@ -494,7 +604,13 @@ object GraphEditor { } } -private class GraphingNode(val id: Int, var position: LorenzVec, var name: String? = null) { +// The node object the graph editor is working with +private class GraphingNode( + val id: Int, + var position: LorenzVec, + var name: String? = null, + var tags: MutableList<GraphNodeTag> = mutableListOf(), +) { override fun hashCode(): Int { return id |