aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorThunderblade73 <85900443+Thunderblade73@users.noreply.github.com>2024-09-05 10:34:44 +0200
committerGitHub <noreply@github.com>2024-09-05 10:34:44 +0200
commit81aebf952893555a48441c4ac5516ac869741bb0 (patch)
treeb0fd7bd1ee9116f6472ea48b6e7695e82b1f4b72 /src/main
parent6dae2df502995679bbd7742ac919d9ee467db9d8 (diff)
downloadskyhanni-81aebf952893555a48441c4ac5516ac869741bb0.tar.gz
skyhanni-81aebf952893555a48441c4ac5516ac869741bb0.tar.bz2
skyhanni-81aebf952893555a48441c4ac5516ac869741bb0.zip
Backend: Graph Editor Split & Dissolve (#2466)
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java10
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt17
-rw-r--r--src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt77
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt4
4 files changed, 95 insertions, 13 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java
index bbc6caf7d..9a2806f64 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java
@@ -82,6 +82,16 @@ public class GraphConfig {
public int tutorialKey = Keyboard.KEY_K;
@Expose
+ @ConfigOption(name = "Split Key", desc = "Key for splitting an edge that is between the active and the closed node.")
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
+ public int splitKey = Keyboard.KEY_NONE;
+
+ @Expose
+ @ConfigOption(name = "Dissolve Key", desc = "Dissolve the active node into one edge if it only has two edges.")
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
+ public int dissolveKey = Keyboard.KEY_NONE;
+
+ @Expose
@ConfigLink(owner = GraphConfig.class, field = "enabled")
public Position infoDisplay = new Position(20, 20);
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 89fd413f5..21440197d 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt
@@ -7,12 +7,12 @@ import at.hannibal2.skyhanni.utils.json.fromJson
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.google.gson.annotations.Expose
+import com.google.gson.stream.JsonToken
import java.util.PriorityQueue
@JvmInline
value class Graph(
- @Expose
- val graph: List<GraphNode>,
+ @Expose val graph: List<GraphNode>,
) : List<GraphNode> {
override val size
get() = graph.size
@@ -82,6 +82,10 @@ value class Graph(
var tags: List<String>? = null
var neighbors = mutableListOf<Pair<Int, Double>>()
while (reader.hasNext()) {
+ if (reader.peek() != JsonToken.NAME) {
+ reader.skipValue()
+ continue
+ }
when (reader.nextName()) {
"Position" -> {
position = reader.nextString().split(":").let { parts ->
@@ -157,8 +161,7 @@ class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null,
}
}
-fun Graph.findShortestPathAsGraph(start: GraphNode, end: GraphNode): Graph =
- this.findShortestPathAsGraphWithDistance(start, end).first
+fun Graph.findShortestPathAsGraph(start: GraphNode, end: GraphNode): Graph = this.findShortestPathAsGraphWithDistance(start, end).first
fun Graph.findShortestPathAsGraphWithDistance(start: GraphNode, end: GraphNode): Pair<Graph, Double> {
val distances = mutableMapOf<GraphNode, Double>()
@@ -199,11 +202,9 @@ fun Graph.findShortestPathAsGraphWithDistance(start: GraphNode, end: GraphNode):
) to distances[end]!!
}
-fun Graph.findShortestPath(start: GraphNode, end: GraphNode): List<LorenzVec> =
- this.findShortestPathAsGraph(start, end).toPositionsList()
+fun Graph.findShortestPath(start: GraphNode, end: GraphNode): List<LorenzVec> = this.findShortestPathAsGraph(start, end).toPositionsList()
-fun Graph.findShortestDistance(start: GraphNode, end: GraphNode): Double =
- this.findShortestPathAsGraphWithDistance(start, end).second
+fun Graph.findShortestDistance(start: GraphNode, end: GraphNode): Double = this.findShortestPathAsGraphWithDistance(start, end).second
fun Graph.toPositionsList() = this.map { it.position }
diff --git a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt
index f5acf90fb..8757f19bf 100644
--- a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt
+++ b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt
@@ -55,7 +55,18 @@ object GraphEditor {
private val edges = mutableListOf<GraphingEdge>()
private var activeNode: GraphingNode? = null
+ set(value) {
+ field = value
+ selectedEdge = findEdgeBetweenActiveAndClosed()
+ checkDissolve()
+ }
private var closedNode: GraphingNode? = null
+ set(value) {
+ field = value
+ selectedEdge = findEdgeBetweenActiveAndClosed()
+ }
+
+ private var selectedEdge: GraphingEdge? = null
private var ghostPosition: LorenzVec? = null
private var seeThroughBlocks = true
@@ -86,6 +97,7 @@ object GraphEditor {
private val edgeColor = LorenzColor.GOLD.addOpacity(150)
private val edgeDijkstraColor = LorenzColor.DARK_BLUE.addOpacity(150)
+ private val edgeSelectedColor = LorenzColor.DARK_RED.addOpacity(150)
val scrollValue = ScrollValue()
var nodesDisplay = emptyList<Renderable>()
@@ -127,7 +139,11 @@ object GraphEditor {
add("§eTutorial: §6${KeyboardManager.getKeyName(config.tutorialKey)}")
add("§eToggle Ghost Position: §6${KeyboardManager.getKeyName(config.toggleGhostPosition)}")
add(" ")
- if (activeNode != null) add("§eText: §6${KeyboardManager.getKeyName(config.textKey)}")
+ if (activeNode != null) {
+ add("§eText: §6${KeyboardManager.getKeyName(config.textKey)}")
+ if (dissolvePossible) add("§eDissolve: §6${KeyboardManager.getKeyName(config.dissolveKey)}")
+ if (selectedEdge != null) add("§eSplit: §6${KeyboardManager.getKeyName(config.splitKey)}")
+ }
}
if (!inTextMode) {
@@ -152,6 +168,18 @@ object GraphEditor {
}
}
+ private var dissolvePossible = false
+
+ private fun findEdgeBetweenActiveAndClosed(): GraphingEdge? = getEdgeIndex(activeNode, closedNode)?.let { edges[it] }
+
+ private fun checkDissolve() {
+ if (activeNode == null) {
+ dissolvePossible = false
+ return
+ }
+ dissolvePossible = edges.count { it.isInEdge(activeNode) } == 2
+ }
+
@SubscribeEvent
fun onGuiRender(event: GuiRenderEvent) {
if (!isEnabled()) return
@@ -207,7 +235,7 @@ object GraphEditor {
)
}
- private fun createTagName(
+private fun createTagName(
name: String,
tag: GraphNodeTag,
node: GraphingNode,
@@ -333,7 +361,11 @@ object GraphEditor {
private fun LorenzRenderWorldEvent.drawEdge(edge: GraphingEdge) = this.draw3DLine_nea(
edge.node1.position.add(0.5, 0.5, 0.5),
edge.node2.position.add(0.5, 0.5, 0.5),
- if (edge !in highlightedEdges) edgeColor else edgeDijkstraColor,
+ when {
+ selectedEdge == edge -> edgeSelectedColor
+ edge in highlightedEdges -> edgeDijkstraColor
+ else -> edgeColor
+ },
7,
!seeThroughBlocks,
)
@@ -449,6 +481,8 @@ object GraphEditor {
feedBackInTutorial("Added new edge.")
} else {
this.edges.removeAt(edge)
+ checkDissolve()
+ selectedEdge = findEdgeBetweenActiveAndClosed()
feedBackInTutorial("Removed edge.")
}
}
@@ -466,6 +500,29 @@ object GraphEditor {
inTutorialMode = !inTutorialMode
ChatUtils.chat("Tutorial mode is now ${if (inTutorialMode) "active" else "inactive"}.")
}
+ if (selectedEdge != null && config.splitKey.isKeyClicked()) {
+ val edge = selectedEdge ?: return
+ feedBackInTutorial("Split Edge into a Node and two edges.")
+ val middle = edge.node1.position.middle(edge.node2.position).roundLocationToBlock()
+ val node = GraphingNode(id++, middle)
+ nodes.add(node)
+ edges.remove(edge)
+ addEdge(node, edge.node1)
+ addEdge(node, edge.node2)
+ activeNode = node
+ }
+ if (dissolvePossible && config.dissolveKey.isKeyClicked()) {
+ feedBackInTutorial("Dissolved the node, now it is gone.")
+ val edgePair = edges.filter { it.isInEdge(activeNode) }
+ val edge1 = edgePair[0]
+ val edge2 = edgePair[1]
+ val neighbors1 = if (edge1.node1 == activeNode) edge1.node2 else edge1.node1
+ val neighbors2 = if (edge2.node1 == activeNode) edge2.node2 else edge2.node1
+ edges.removeAll(edgePair)
+ nodes.remove(activeNode)
+ activeNode = null
+ addEdge(neighbors1, neighbors2)
+ }
}
private fun save() {
@@ -561,7 +618,14 @@ object GraphEditor {
else null
private fun addEdge(node1: GraphingNode?, node2: GraphingNode?) =
- if (node1 != null && node2 != null && node1 != node2) edges.add(GraphingEdge(node1, node2)) else false
+ if (node1 != null && node2 != null && node1 != node2) {
+ val edge = GraphingEdge(node1, node2)
+ if (edge.isInEdge(activeNode)) {
+ checkDissolve()
+ selectedEdge = findEdgeBetweenActiveAndClosed()
+ }
+ edges.add(edge)
+ } else false
/** Has a side effect on the graphing graph, since it runs [prune] on the graphing graph*/
private fun compileGraph(): Graph {
@@ -597,6 +661,8 @@ object GraphEditor {
}.flatten().distinct(),
)
id = nodes.lastOrNull()?.id?.plus(1) ?: 0
+ checkDissolve()
+ selectedEdge = findEdgeBetweenActiveAndClosed()
}
private val highlightedNodes = mutableSetOf<GraphingNode>()
@@ -630,6 +696,7 @@ object GraphEditor {
edges.clear()
activeNode = null
closedNode = null
+ dissolvePossible = false
ghostPosition = null
}
@@ -671,7 +738,7 @@ private class GraphingNode(
private class GraphingEdge(val node1: GraphingNode, val node2: GraphingNode) {
- fun isInEdge(node: GraphingNode) = node1 == node || node2 == node
+ fun isInEdge(node: GraphingNode?) = node1 == node || node2 == node
override fun equals(other: Any?): Boolean {
if (this === other) return true
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
index 474d6dee5..4a50d79f3 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
@@ -215,6 +215,10 @@ data class LorenzVec(
return (nearestPointOnLine(startPos, endPos) - this).lengthSquared()
}
+ fun middle(other: LorenzVec): LorenzVec = this.plus(other.minus(this) / 2)
+
+ private operator fun div(i: Number): LorenzVec = LorenzVec(x / i.toDouble(), y / i.toDouble(), z / i.toDouble())
+
companion object {
fun getFromYawPitch(yaw: Double, pitch: Double): LorenzVec {