summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/test/GraphNodeEditor.kt
blob: f541b16e307ca9218a52c809aa52ccaf53c3e85c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package at.hannibal2.skyhanni.test

import at.hannibal2.skyhanni.data.model.GraphNodeTag
import at.hannibal2.skyhanni.data.model.TextInput
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.test.GraphEditor.distanceSqToPlayer
import at.hannibal2.skyhanni.utils.CollectionUtils.addString
import at.hannibal2.skyhanni.utils.KeyboardManager
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.renderables.Renderable
import at.hannibal2.skyhanni.utils.renderables.ScrollValue
import at.hannibal2.skyhanni.utils.renderables.Searchable
import at.hannibal2.skyhanni.utils.renderables.buildSearchableScrollable
import at.hannibal2.skyhanni.utils.renderables.toSearchable
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.math.sqrt
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds

@SkyHanniModule
object GraphNodeEditor {

    private val scrollValueNodes = ScrollValue()
    private val scrollValueTags = ScrollValue()
    private val textInput = TextInput()
    private var nodesDisplay = emptyList<Renderable>()
    private var lastUpdate = SimpleTimeMark.farPast()

    @SubscribeEvent
    fun onGuiRender(event: GuiRenderEvent) {
        if (!isEnabled()) return


        config.namedNodesList.renderRenderables(
            getNodeNames(),
            posLabel = "Graph Nodes List",
        )
    }

    private fun getNodeNames(): List<Renderable> {
        if (lastUpdate.passedSince() > 250.milliseconds) {
            updateNodeNames()
        }
        return nodesDisplay
    }

    private fun updateNodeNames() {
        lastUpdate = SimpleTimeMark.now()
        nodesDisplay = buildList {
            val list = drawNodeNames()
            val size = list.size
            addString("§eGraph Nodes: $size")
            val height = (size * 10).coerceAtMost(250)
            if (list.isNotEmpty()) {
                add(list.buildSearchableScrollable(height, textInput, scrollValueNodes, velocity = 10.0))
            }
        }
    }

    private fun updateTagView(node: GraphingNode) {
        lastUpdate = SimpleTimeMark.now() + 60.seconds
        nodesDisplay = buildList {
            val list = drawTagNames(node)
            val size = list.size
            addString("§eGraph Nodes: $size")
            val height = (size * 10).coerceAtMost(250)
            if (list.isNotEmpty()) {
                add(Renderable.scrollList(list, height, scrollValueTags, velocity = 10.0))
            }
        }
    }

    private fun drawTagNames(node: GraphingNode): List<Renderable> = buildList {
        addString("§eChange tag for node '${node.name}§e'")
        addString("")

        for (tag in GraphNodeTag.entries.filter { it in node.tags || checkIsland(it) }) {
            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 checkIsland(tag: GraphNodeTag): Boolean = tag.onlyIsland?.let {
        it == LorenzUtils.skyBlockIsland
    } ?: true

    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 drawNodeNames(): List<Searchable> = buildList {
        for ((node, distance: Double) in GraphEditor.nodes.map { it to it.position.distanceSqToPlayer() }.sortedBy { it.second }) {
            val name = node.name?.takeIf { !it.isBlank() } ?: continue
            val color = if (node == GraphEditor.activeNode) "§a" else "§7"
            val distanceFormat = sqrt(distance).toInt().addSeparators()
            val tagText = node.tags.let { tags ->
                if (tags.isEmpty()) {
                    " §cNo tag§r"
                } else {
                    val text = node.tags.joinToString(", ") { it.internalName }
                    " §f($text)"
                }
            }

            val text = "${color}Node §r$name$tagText §7[$distanceFormat]"
            add(createNodeTextLine(text, name, node))
        }
    }

    private fun createNodeTextLine(
        text: String,
        name: String,
        node: GraphingNode,
    ): Searchable = 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 {
                GraphEditor.activeNode = node
                updateNodeNames()
            }
        },
    ).toSearchable(name)

    fun isEnabled() = GraphEditor.isEnabled()
    private val config get() = GraphEditor.config

}