aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhannibal2 <24389977+hannibal002@users.noreply.github.com>2024-09-13 20:23:57 +0200
committerGitHub <noreply@github.com>2024-09-13 20:23:57 +0200
commit5e01624dcc315a2bf7665fc808b1113fa4c9e0d8 (patch)
tree6a97c6970fecd2d517eac80c1aa391eee42addd2 /src
parent691d2551cf722b76c1894c814d1f6c2e98fe17d6 (diff)
downloadskyhanni-5e01624dcc315a2bf7665fc808b1113fa4c9e0d8.tar.gz
skyhanni-5e01624dcc315a2bf7665fc808b1113fa4c9e0d8.tar.bz2
skyhanni-5e01624dcc315a2bf7665fc808b1113fa4c9e0d8.zip
Feature: Graphs Pathfinding (#2468)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java32
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java41
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt320
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt28
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt32
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt46
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt290
-rw-r--r--src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt18
-rw-r--r--src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt19
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt10
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt7
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/Searchable.kt5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt4
22 files changed, 820 insertions, 67 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
index 7a17c1462..d0f58f082 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
@@ -33,6 +33,7 @@ import at.hannibal2.skyhanni.features.event.diana.InquisitorWaypointShare
import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker
import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats
import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggLocations
+import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggLocator
import at.hannibal2.skyhanni.features.event.hoppity.HoppityEventSummary
import at.hannibal2.skyhanni.features.event.jerry.frozentreasure.FrozenTreasureTracker
import at.hannibal2.skyhanni.features.fishing.tracker.FishingProfitTracker
@@ -58,8 +59,8 @@ import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker
import at.hannibal2.skyhanni.features.mining.KingTalismanHelper
import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay
-import at.hannibal2.skyhanni.features.mining.glacitemineshaft.CorpseTracker
import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker
+import at.hannibal2.skyhanni.features.mining.glacitemineshaft.CorpseTracker
import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker
import at.hannibal2.skyhanni.features.minion.MinionFeatures
import at.hannibal2.skyhanni.features.misc.CollectionTracker
@@ -495,6 +496,7 @@ object Commands {
private fun developersCodingHelp() {
registerCommand("shrepopatterns", "See where regexes are loaded from") { RepoPatternGui.open() }
registerCommand("shtest", "Unused test command.") { SkyHanniDebugsAndTests.testCommand(it) }
+ registerCommand("shtestrabbitpaths", "Tests pathfinding to rabbit eggs. Use a number 0-14.") { HoppityEggLocator.testPathfind(it) }
registerCommand(
"shtestitem",
"test item internal name resolving",
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 9a2806f64..9eed8233c 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
@@ -103,4 +103,9 @@ public class GraphConfig {
@ConfigOption(name = "Shows Stats", desc = "Show funny extra statistics on save. May lag the game a bit.")
@ConfigEditorBoolean
public boolean showsStats = true;
+
+ @Expose
+ @ConfigOption(name = "Use as Island Area", desc = "When saving, use the current edited graph as temporary island area for the current island.")
+ @ConfigEditorBoolean
+ public boolean useAsIslandArea = false;
}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java
index c270dae8b..b438d83f5 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java
@@ -51,6 +51,12 @@ public class HoppityEggsConfig {
public boolean showLine = false;
@Expose
+ @ConfigOption(name = "Show Path Finder", desc = "Show a pathfind to the next hoppity egg.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean showPathFinder = false;
+
+ @Expose
@ConfigOption(name = "Show All Waypoints", desc = "Show all possible egg waypoints for the current lobby. §e" +
"Only works when you don't have an Egglocator in your inventory.")
@ConfigEditorBoolean
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java
new file mode 100644
index 000000000..38a399ed4
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaNavigationConfig.java
@@ -0,0 +1,32 @@
+package at.hannibal2.skyhanni.config.features.misc;
+
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.Accordion;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+public class AreaNavigationConfig {
+
+ @Expose
+ @ConfigOption(name = "Area Path Finder", desc = "")
+ @Accordion
+ public AreaPathfinderConfig pathfinder = new AreaPathfinderConfig();
+
+ @Expose
+ @ConfigOption(name = "In World", desc = "Shows the area names in world")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean inWorld = false;
+
+ @Expose
+ @ConfigOption(name = "Small Areas", desc = "Include small areas.")
+ @ConfigEditorBoolean
+ public boolean includeSmallAreas = false;
+
+ @Expose
+ @ConfigOption(name = "Title on Enter", desc = "Sends a titles on screen when entering an area.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean enterTitle = false;
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java
new file mode 100644
index 000000000..af9b1de64
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/AreaPathfinderConfig.java
@@ -0,0 +1,41 @@
+package at.hannibal2.skyhanni.config.features.misc;
+
+import at.hannibal2.skyhanni.config.FeatureToggle;
+import at.hannibal2.skyhanni.config.core.config.Position;
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigLink;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+import io.github.notenoughupdates.moulconfig.observer.Property;
+
+public class AreaPathfinderConfig {
+
+ @Expose
+ @ConfigOption(name = "Enabled", desc = "While in your invenotry, show all areas of the island. Click on an area to display the path to this area.")
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean enabled = false;
+
+ @Expose
+ @ConfigOption(name = "Show Always", desc = "Show the list always, not only while inside the inventory.")
+ @ConfigEditorBoolean
+ public boolean showAlways = false;
+
+ @Expose
+ @ConfigOption(name = "Current Area", desc = "Show the name of the current area at the top of the list")
+ @ConfigEditorBoolean
+ public Property<Boolean> includeCurrentArea = Property.of(false);
+
+ @Expose
+ @ConfigOption(
+ name = "Path Color",
+ desc = "Change the color of the path."
+ )
+ @ConfigEditorColour
+ public Property<String> color = Property.of("0:245:85:255:85");
+
+ @Expose
+ @ConfigLink(owner = AreaPathfinderConfig.class, field = "enabled")
+ public Position position = new Position(20, 20);
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java
index f3b9ab16e..03b0bf779 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java
@@ -42,6 +42,10 @@ public class MiscConfig {
@Category(name = "Stranded", desc = "Features for the Stranded game mode.")
public StrandedConfig stranded = new StrandedConfig();
+ @Expose
+ @Category(name = "Area Navigation", desc = "Helps navigate to different areas on the current island.")
+ public AreaNavigationConfig areaNavigation = new AreaNavigationConfig();
+
@ConfigOption(name = "Hide Armor", desc = "")
@Accordion
@Expose
diff --git a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt
new file mode 100644
index 000000000..02a065abe
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt
@@ -0,0 +1,320 @@
+package at.hannibal2.skyhanni.data
+
+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.findShortestPathAsGraphWithDistance
+import at.hannibal2.skyhanni.data.repo.RepoUtils
+import at.hannibal2.skyhanni.events.IslandChangeEvent
+import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
+import at.hannibal2.skyhanni.events.LorenzTickEvent
+import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
+import at.hannibal2.skyhanni.events.RepositoryReloadEvent
+import at.hannibal2.skyhanni.features.misc.IslandAreas
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.test.SkyHanniDebugsAndTests
+import at.hannibal2.skyhanni.utils.LocationUtils
+import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen
+import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer
+import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine
+import at.hannibal2.skyhanni.utils.RenderUtils.draw3DPathWithWaypoint
+import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.awt.Color
+import java.io.File
+import kotlin.math.abs
+
+/**
+ * TODO
+ * benefits of every island graphs:
+ * global:
+ * NEU's fairy souls
+ * point of interest
+ * slayer area
+ * NEU's NPC's
+ * races (end, park, winter, dungeon hub)
+ * jump pads between servers
+ * ring of love/romeo juliet quest
+ * death location
+ * hub:
+ * 12 starter NPC's
+ * diana
+ * farming:
+ * pelt farming
+ * rift:
+ * enigma souls
+ * eyes
+ * big quests
+ * spider:
+ * relicts + throw spot
+ * dwarven mines:
+ * emissary
+ * commssion areas
+ * events: raffle, goblin slayer, donpieresso
+ * deep
+ * path to the bottom
+ * end
+ * golem spawn
+ * dragon death spot
+ * crimson
+ * vanquisher path
+ * area mini bosses
+ * daily quests
+ * intro tutorials with elle
+ *
+ * graph todo:
+ * fix rename not using tick but input event we have (+ create the input event in the first place)
+ * toggle distance to node by node path lengh, instead of eye of sight lenght
+ * press test button again to enable "true test mode", with graph math and hiding other stuff
+ * option to compare two graphs, and store multiple graphs in the edit mode in paralell
+ */
+
+@SkyHanniModule
+object IslandGraphs {
+ var currentIslandGraph: Graph? = null
+
+ val existsForThisIsland get() = currentIslandGraph != null
+
+ var closedNote: GraphNode? = null
+
+ private var currentTarget: LorenzVec? = null
+ private var color = Color.WHITE
+ private var showGoalExact = false
+ private var onFound: () -> Unit = {}
+ private var goal: GraphNode? = null
+ set(value) {
+ prevGoal = field
+ field = value
+ }
+ private var prevGoal: GraphNode? = null
+
+ private var fastestPath: Graph? = null
+ private var condition: () -> Boolean = { true }
+
+ @SubscribeEvent
+ fun onRepoReload(event: RepositoryReloadEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+
+ reloadFromJson(LorenzUtils.skyBlockIsland)
+ }
+
+ @SubscribeEvent
+ fun onIslandChange(event: IslandChangeEvent) {
+ reloadFromJson(event.newIsland)
+ }
+
+ @SubscribeEvent
+ fun onWorldChange(event: LorenzWorldChangeEvent) {
+ reset()
+ }
+
+ private fun reloadFromJson(newIsland: IslandType) {
+ val islandName = newIsland.name
+ val constant = "island_graphs/$islandName"
+ val name = "constants/$constant.json"
+ val jsonFile = File(SkyHanniMod.repo.repoLocation, name)
+ if (!jsonFile.isFile) {
+ currentIslandGraph = null
+ return
+ }
+
+ val graph = RepoUtils.getConstant(SkyHanniMod.repo.repoLocation, constant, Graph.gson, Graph::class.java)
+ setNewGraph(graph)
+ }
+
+ fun setNewGraph(graph: Graph) {
+ reset()
+ currentIslandGraph = graph
+ }
+
+ private fun reset() {
+ closedNote = null
+ currentTarget = null
+ goal = null
+ fastestPath = null
+ }
+
+ @SubscribeEvent
+ fun onTick(event: LorenzTickEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ val prevClosed = closedNote
+
+ val graph = currentIslandGraph ?: return
+
+ currentTarget?.let {
+ if (it.distanceToPlayer() < 3) {
+ onFound()
+ reset()
+ }
+ if (!condition()) {
+ reset()
+ }
+ }
+
+ val newClosest = if (SkyHanniDebugsAndTests.c == 0.0) {
+ graph.minBy { it.position.distanceSqToPlayer() }
+ } else null
+ if (closedNote == newClosest) return
+ closedNote = newClosest
+ onNewNote()
+ val closest = closedNote ?: return
+ val goal = goal ?: return
+ if (closest == prevClosed) return
+
+ val (path, distance) = graph.findShortestPathAsGraphWithDistance(closest, goal)
+ val first = path.firstOrNull()
+ val second = path.getOrNull(1)
+
+ val playerPosition = LocationUtils.playerLocation()
+ val nodeDistance = first?.let { playerPosition.distance(it.position) } ?: 0.0
+ if (first != null && second != null) {
+ val direct = playerPosition.distance(second.position)
+ val firstPath = first.neighbours[second] ?: 0.0
+ val around = nodeDistance + firstPath
+ if (direct < around) {
+ setFastestPath(Graph(path.drop(1)) to (distance - firstPath + direct))
+ return
+ }
+ }
+ setFastestPath(path to (distance + nodeDistance))
+ }
+
+ private fun setFastestPath(path: Pair<Graph, Double>) {
+ fastestPath = path.takeIf { it.first.isNotEmpty() }?.first
+
+ fastestPath?.let {
+ fastestPath = Graph(cutByMaxDistance(it.nodes, 3.0))
+ }
+ }
+
+ private fun onNewNote() {
+ // TODO create an event
+ IslandAreas.noteMoved()
+ }
+
+ fun stop() {
+ currentTarget = null
+ goal = null
+ fastestPath = null
+ }
+
+ fun pathFind(
+ location: LorenzVec,
+ color: Color = LorenzColor.WHITE.toColor(),
+ onFound: () -> Unit = {},
+ showGoalExact: Boolean = false,
+ condition: () -> Boolean = { true },
+ ) {
+ reset()
+ currentTarget = location
+ this.color = color
+ this.onFound = onFound
+ this.showGoalExact = showGoalExact
+ this.condition = condition
+ val graph = currentIslandGraph ?: return
+ goal = graph.minBy { it.position.distance(currentTarget!!) }
+ }
+
+ @SubscribeEvent
+ fun onRenderWorld(event: LorenzRenderWorldEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ val path = fastestPath ?: return
+
+ var graph = path
+ graph = skipNodes(graph) ?: graph
+
+ event.draw3DPathWithWaypoint(
+ graph,
+ color,
+ 6,
+ true,
+ bezierPoint = 2.0,
+ textSize = 1.0,
+ )
+ val lastNode = graph.nodes.last().position
+ val targetLocation = currentTarget ?: return
+ event.draw3DLine(lastNode.add(0.5, 0.5, 0.5), targetLocation.add(0.5, 0.5, 0.5), color, 4, true)
+
+ if (showGoalExact) {
+ event.drawWaypointFilled(targetLocation, color)
+ }
+ }
+
+ // TODO move into new utils class
+ private fun cutByMaxDistance(nodes: List<GraphNode>, maxDistance: Double): List<GraphNode> {
+ var index = nodes.size * 10
+ val locations = mutableListOf<LorenzVec>()
+ var first = true
+ for (node in nodes) {
+ if (first) {
+ first = false
+ } else {
+ var lastPosition = locations.last()
+ val currentPosition = node.position
+ val vector = (currentPosition - lastPosition).normalize()
+ var distance = lastPosition.distance(currentPosition)
+ while (distance > maxDistance) {
+ distance -= maxDistance
+ val nextStepDistance = if (distance < maxDistance / 2) {
+ (maxDistance + distance) / 2
+ break
+ } else maxDistance
+ val newPosition = lastPosition + (vector * (nextStepDistance))
+ locations.add(newPosition)
+ lastPosition = newPosition
+ }
+ }
+ locations.add(node.position)
+ }
+
+ return locations.map { GraphNode(index++, it) }
+ }
+
+ // trying to find a faster node-path, if the future nodes are in line of sight and gratly beneift the current path
+ private fun skipNodes(graph: Graph): Graph? {
+ val closedNode = closedNote ?: return null
+
+ val playerEyeLocation = LocationUtils.playerEyeLocation()
+ val playerY = playerEyeLocation.y - 1
+
+ val distanceToPlayer = closedNode.position.distanceToPlayer()
+ val skipNodeDistance = distanceToPlayer > 8
+ val maxSkipDistance = if (skipNodeDistance) 50.0 else 20.0
+
+ val nodes = graph.nodes
+ val potentialSkip =
+ nodes.lastOrNull { it.position.canBeSeen(maxSkipDistance, -1.0) && abs(it.position.y - playerY) <= 2 }
+ ?: return null
+
+ val angleSkip = if (potentialSkip == nodes.first()) {
+ false
+ } else {
+ val v1 = potentialSkip.position - playerEyeLocation
+ val v2 = nodes.first().position - playerEyeLocation
+ val v = v1.angleInRad(v2)
+ v > 1
+ }
+
+ if (!skipNodeDistance && !angleSkip) return null
+
+ val list = mutableListOf<GraphNode>()
+ list.add(potentialSkip)
+
+ var passed = false
+ for (node in nodes) {
+ if (passed) {
+ list.add(node)
+ } else {
+ if (node == potentialSkip) {
+ passed = true
+ }
+ }
+ }
+
+ return Graph(list)
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt
index a5a8eb184..0f029a1f2 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt
@@ -19,11 +19,11 @@ object PurseAPI {
private val patternGroup = RepoPattern.group("data.purse")
val coinsPattern by patternGroup.pattern(
"coins",
- "(§.)*(Piggy|Purse): §6(?<coins>[\\d,.]+)( ?(§.)*\\([+-](?<earned>[\\d,.]+)\\)?|.*)?$"
+ "(§.)*(Piggy|Purse): §6(?<coins>[\\d,.]+)( ?(§.)*\\([+-](?<earned>[\\d,.]+)\\)?|.*)?$",
)
val piggyPattern by patternGroup.pattern(
"piggy",
- "Piggy: (?<coins>.*)"
+ "Piggy: (?<coins>.*)",
)
private var inventoryCloseTime = SimpleTimeMark.farPast()
@@ -54,6 +54,7 @@ object PurseAPI {
return PurseChangeCause.GAIN_TALISMAN_OF_COINS
}
+ // TODO relic of coins support
if (diff == 15.million || diff == 100.million) {
return PurseChangeCause.GAIN_DICE_ROLL
}
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 21440197d..8c63be891 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt
@@ -12,29 +12,29 @@ import java.util.PriorityQueue
@JvmInline
value class Graph(
- @Expose val graph: List<GraphNode>,
+ @Expose val nodes: List<GraphNode>,
) : List<GraphNode> {
override val size
- get() = graph.size
+ get() = nodes.size
- override fun contains(element: GraphNode) = graph.contains(element)
+ override fun contains(element: GraphNode) = nodes.contains(element)
- override fun containsAll(elements: Collection<GraphNode>) = graph.containsAll(elements)
+ override fun containsAll(elements: Collection<GraphNode>) = nodes.containsAll(elements)
- override fun get(index: Int) = graph.get(index)
+ override fun get(index: Int) = nodes.get(index)
- override fun isEmpty() = graph.isEmpty()
+ override fun isEmpty() = nodes.isEmpty()
- override fun indexOf(element: GraphNode) = graph.indexOf(element)
+ override fun indexOf(element: GraphNode) = nodes.indexOf(element)
- override fun iterator(): Iterator<GraphNode> = graph.iterator()
- override fun listIterator() = graph.listIterator()
+ override fun iterator(): Iterator<GraphNode> = nodes.iterator()
+ override fun listIterator() = nodes.listIterator()
- override fun listIterator(index: Int) = graph.listIterator(index)
+ override fun listIterator(index: Int) = nodes.listIterator(index)
- override fun subList(fromIndex: Int, toIndex: Int) = graph.subList(fromIndex, toIndex)
+ override fun subList(fromIndex: Int, toIndex: Int) = nodes.subList(fromIndex, toIndex)
- override fun lastIndexOf(element: GraphNode) = graph.lastIndexOf(element)
+ override fun lastIndexOf(element: GraphNode) = nodes.lastIndexOf(element)
companion object {
val gson = GsonBuilder().setPrettyPrinting().registerTypeAdapter<Graph>(
@@ -142,6 +142,10 @@ value class Graph(
// 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) {
+ val tags: List<GraphNodeTag> by lazy {
+ tagNames?.mapNotNull { GraphNodeTag.byId(it) } ?: emptyList()
+ }
+
/** 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/repo/RepoManager.kt b/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt
index 551f44699..ec6f0cbd9 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/repo/RepoManager.kt
@@ -34,7 +34,7 @@ class RepoManager(private val configLocation: File) {
private val gson get() = ConfigManager.gson
private var latestRepoCommit: String? = null
- private val repoLocation: File = File(configLocation, "repo")
+ val repoLocation: File = File(configLocation, "repo")
private var error = false
private var lastRepoUpdate = SimpleTimeMark.farPast()
diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt
index 35a783f7d..aa58c3c0f 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt
@@ -49,17 +49,16 @@ object GriffinBurrowHelper {
private val config get() = SkyHanniMod.feature.event.diana
- private val allowedBlocksAboveGround =
- listOf(
- Blocks.air,
- Blocks.leaves,
- Blocks.leaves2,
- Blocks.tallgrass,
- Blocks.double_plant,
- Blocks.red_flower,
- Blocks.yellow_flower,
- Blocks.spruce_fence
- )
+ private val allowedBlocksAboveGround = listOf(
+ Blocks.air,
+ Blocks.leaves,
+ Blocks.leaves2,
+ Blocks.tallgrass,
+ Blocks.double_plant,
+ Blocks.red_flower,
+ Blocks.yellow_flower,
+ Blocks.spruce_fence,
+ )
var targetLocation: LorenzVec? = null
private var guessLocation: LorenzVec? = null
@@ -134,7 +133,14 @@ object GriffinBurrowHelper {
}
locations.addAll(InquisitorWaypointShare.waypoints.values.map { it.location })
}
- targetLocation = locations.minByOrNull { it.distanceToPlayer() }
+ val newLocation = locations.minByOrNull { it.distanceToPlayer() }
+ if (targetLocation != newLocation) {
+ targetLocation = newLocation
+ // add island graphs here some day when the hub is fully added in the graph
+// newLocation?.let {
+// IslandGraphs.find(it)
+// }
+ }
if (config.burrowNearestWarp) {
targetLocation?.let {
@@ -401,7 +407,7 @@ object GriffinBurrowHelper {
if (currentMayor != Mayor.DIANA) {
ChatUtils.chatAndOpenConfig(
"§cSelect Diana as mayor overwrite!",
- SkyHanniMod.feature.dev.debug::assumeMayor
+ SkyHanniMod.feature.dev.debug::assumeMayor,
)
} else {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt
index cce0aef79..896220842 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt
@@ -30,7 +30,7 @@ object HoppityEggLocations {
ChocolateFactoryAPI.profileStorage?.collectedEggLocations = value
}
- private var apiEggLocations: Map<IslandType, Map<String, LorenzVec>> = mapOf()
+ var apiEggLocations: Map<IslandType, Map<String, LorenzVec>> = mapOf()
val islandLocations
get() = apiEggLocations[LorenzUtils.skyBlockIsland]?.values?.toSet() ?: emptySet()
diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt
index d15d43d81..0d5bfefa8 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.features.event.hoppity
import at.hannibal2.skyhanni.data.ClickType
+import at.hannibal2.skyhanni.data.IslandGraphs
import at.hannibal2.skyhanni.events.DebugDataCollectEvent
import at.hannibal2.skyhanni.events.ItemClickEvent
import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
@@ -19,6 +20,7 @@ import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzUtils.round
import at.hannibal2.skyhanni.utils.LorenzVec
import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName
+import at.hannibal2.skyhanni.utils.NumberUtil.formatInt
import at.hannibal2.skyhanni.utils.RecalculatingValue
import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine
import at.hannibal2.skyhanni.utils.RenderUtils.drawColor
@@ -154,8 +156,7 @@ object HoppityEggLocator {
}
private fun LorenzRenderWorldEvent.drawEggWaypoint(location: LorenzVec, label: String) {
- val shouldMarkDuplicate = config.highlightDuplicateEggLocations
- && HoppityEggLocations.hasCollectedEgg(location)
+ val shouldMarkDuplicate = config.highlightDuplicateEggLocations && HoppityEggLocations.hasCollectedEgg(location)
val possibleDuplicateLabel = if (shouldMarkDuplicate) "$label §c(Duplicate Location)" else label
if (!shouldMarkDuplicate) {
drawWaypointFilled(location, config.waypointColor.toChromaColor(), seeThroughBlocks = true)
@@ -165,8 +166,7 @@ object HoppityEggLocator {
drawDynamicText(location.add(y = 1), possibleDuplicateLabel, 1.5)
}
- private fun shouldShowAllEggs() =
- config.showAllWaypoints && !locatorInHotbar && HoppityEggType.eggsRemaining()
+ private fun shouldShowAllEggs() = config.showAllWaypoints && !locatorInHotbar && HoppityEggType.eggsRemaining()
fun eggFound() {
resetData()
@@ -214,6 +214,7 @@ object HoppityEggLocator {
if (event.clickType == ClickType.RIGHT_CLICK && item.isLocatorItem) {
lastClick = SimpleTimeMark.now()
MythicRabbitPetWarning.check()
+ trySendingGraph()
}
}
@@ -264,20 +265,29 @@ object HoppityEggLocator {
possibleEggLocations = filteredEggs
+ if (drawLocations) return
drawLocations = true
+
+ trySendingGraph()
+ }
+
+ private fun trySendingGraph() {
+ if (!config.showPathFinder) return
+ val location = possibleEggLocations.firstOrNull() ?: return
+
+ val color = config.waypointColor.toChromaColor()
+
+ IslandGraphs.pathFind(location, color, condition = { config.showPathFinder })
}
- fun isValidEggLocation(location: LorenzVec): Boolean =
- HoppityEggLocations.islandLocations.any { it.distance(location) < 5.0 }
+ fun isValidEggLocation(location: LorenzVec): Boolean = HoppityEggLocations.islandLocations.any { it.distance(location) < 5.0 }
- private fun ReceiveParticleEvent.isVillagerParticle() =
- type == EnumParticleTypes.VILLAGER_HAPPY && speed == 0.0f && count == 1
+ private fun ReceiveParticleEvent.isVillagerParticle() = type == EnumParticleTypes.VILLAGER_HAPPY && speed == 0.0f && count == 1
- private fun ReceiveParticleEvent.isEnchantmentParticle() =
- type == EnumParticleTypes.ENCHANTMENT_TABLE && speed == -2.0f && count == 10
+ private fun ReceiveParticleEvent.isEnchantmentParticle() = type == EnumParticleTypes.ENCHANTMENT_TABLE && speed == -2.0f && count == 10
- fun isEnabled() = LorenzUtils.inSkyBlock && config.waypoints && !GardenAPI.inGarden() &&
- !ReminderUtils.isBusy(true) && HoppityAPI.isHoppityEvent()
+ fun isEnabled() =
+ LorenzUtils.inSkyBlock && config.waypoints && !GardenAPI.inGarden() && !ReminderUtils.isBusy(true) && HoppityAPI.isHoppityEvent()
private val ItemStack.isLocatorItem get() = getInternalName() == locatorItem
@@ -314,4 +324,16 @@ object HoppityEggLocator {
add("Current Egg Note: ${currentEggNote ?: "None"}")
}
}
+
+ fun testPathfind(args: Array<String>) {
+ val target = args[0].formatInt()
+ HoppityEggLocations.apiEggLocations[LorenzUtils.skyBlockIsland]?.let {
+ for ((i, location) in it.values.withIndex()) {
+ if (i == target) {
+ IslandGraphs.pathFind(location)
+ return
+ }
+ }
+ }
+ }
}
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 afe5694b1..8d7f771b7 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt
@@ -447,6 +447,7 @@ object TunnelsMaps {
true,
bezierPoint = 2.0,
textSize = config.textSize.toDouble(),
+ showNoteNames = true,
)
event.drawDynamicText(
if (config.distanceFirst) {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt
new file mode 100644
index 000000000..c5c0071f9
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt
@@ -0,0 +1,290 @@
+package at.hannibal2.skyhanni.features.misc
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.IslandGraphs
+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.findShortestPathAsGraphWithDistance
+import at.hannibal2.skyhanni.events.ConfigLoadEvent
+import at.hannibal2.skyhanni.events.EntityMoveEvent
+import at.hannibal2.skyhanni.events.GuiRenderEvent
+import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent
+import at.hannibal2.skyhanni.events.LorenzTickEvent
+import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.ChatUtils
+import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString
+import at.hannibal2.skyhanni.utils.CollectionUtils.sorted
+import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor
+import at.hannibal2.skyhanni.utils.ConditionalUtils
+import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen
+import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer
+import at.hannibal2.skyhanni.utils.LorenzColor
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.round
+import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText
+import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.renderables.Searchable
+import at.hannibal2.skyhanni.utils.renderables.buildSearchBox
+import at.hannibal2.skyhanni.utils.renderables.toSearchable
+import net.minecraft.client.Minecraft
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import kotlin.time.Duration.Companion.seconds
+
+@SkyHanniModule
+object IslandAreas {
+ private val config get() = SkyHanniMod.feature.misc.areaNavigation
+
+ private var nodes = mapOf<GraphNode, Double>()
+ private var paths = mapOf<GraphNode, Graph>()
+ private var display: Renderable? = null
+ private var targetNode: GraphNode? = null
+ private var currentAreaName = ""
+ private val textInput = TextInput()
+
+ @SubscribeEvent
+ fun onWorldChange(event: LorenzWorldChangeEvent) {
+ nodes = emptyMap()
+ display = null
+ targetNode = null
+ hasMoved = true
+ }
+
+ fun noteMoved() {
+ updateNodes()
+ }
+
+ private fun updateNodes() {
+ if (!isEnabled()) return
+ val graph = IslandGraphs.currentIslandGraph ?: return
+ val closedNote = IslandGraphs.closedNote ?: return
+
+ val paths = mutableMapOf<GraphNode, Graph>()
+
+ val map = mutableMapOf<GraphNode, Double>()
+ for (graphNode in graph.nodes) {
+ if (graphNode.getAreaTag() == null) continue
+ val (path, distance) = graph.findShortestPathAsGraphWithDistance(closedNote, graphNode)
+ paths[graphNode] = path
+ map[graphNode] = distance
+ }
+ this.paths = paths
+
+ val finalNodes = mutableMapOf<GraphNode, Double>()
+
+ val alreadyFoundAreas = mutableListOf<String>()
+ for ((node, distance) in map.sorted()) {
+ val areaName = node.name ?: continue
+ if (areaName in alreadyFoundAreas) continue
+ alreadyFoundAreas.add(areaName)
+
+ finalNodes[node] = distance
+ }
+
+ nodes = finalNodes
+ }
+
+ var hasMoved = false
+
+ @SubscribeEvent
+ fun onTick(event: LorenzTickEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ if (!IslandGraphs.existsForThisIsland) return
+
+ if (event.isMod(2) && hasMoved) {
+ hasMoved = false
+ updatePosition()
+ }
+ }
+
+ @SubscribeEvent
+ fun onPlayerMove(event: EntityMoveEvent) {
+ if (isEnabled()) {
+ if (event.entity == Minecraft.getMinecraft().thePlayer) {
+ hasMoved = true
+ }
+ }
+ }
+
+ private fun updatePosition() {
+ display = buildDisplay().buildSearchBox(textInput)
+ }
+
+ @SubscribeEvent
+ fun onOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
+ if (!isEnabled()) return
+ if (!config.pathfinder.enabled) return
+ if (!config.pathfinder.showAlways) return
+
+ display?.let {
+ config.pathfinder.position.renderRenderable(it, posLabel = "Island Areas")
+ }
+ }
+
+ @SubscribeEvent
+ fun onOverlay(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
+ if (!isEnabled()) return
+ if (!config.pathfinder.enabled) return
+
+ display?.let {
+ config.pathfinder.position.renderRenderable(it, posLabel = "Island Areas")
+ }
+ }
+
+ private fun buildDisplay() = buildList<Searchable> {
+ val closedNote = IslandGraphs.closedNote ?: return@buildList
+ val playerDiff = closedNote.position.distanceToPlayer()
+
+ var foundCurrentArea = false
+ var foundAreas = 0
+
+ for ((node, diff) in nodes) {
+ val difference = diff + playerDiff
+ val tag = node.getAreaTag() ?: continue
+
+ val name = node.name ?: continue
+ // can not compare nodes directly. By using names, we also accept other nodes
+ val isTarget = node.name == targetNode?.name
+ val color = if (isTarget) LorenzColor.GOLD else tag.color
+
+ // trying to find a faster path to the existing target
+ if (isTarget && node != targetNode) {
+ ChatUtils.debug("Found a faster node, rerouting...")
+ setTarget(node)
+ }
+ val coloredName = "${color.getChatColor()}${name}"
+
+ var suffix = ""
+ paths[node]?.let { path ->
+ val passedAreas = path.nodes.filter { it.getAreaTag() != null }.map { it.name }.distinct().toMutableList()
+ passedAreas.remove(name)
+ passedAreas.remove(null)
+ passedAreas.remove("null")
+ passedAreas.remove(currentAreaName)
+ // so show areas needed to pass thorough
+ if (passedAreas.isNotEmpty()) {
+// suffix = " §7${passedAreas.joinToString(", ")}"
+ }
+ }
+
+ val distance = difference.round(1)
+ val text = "${coloredName}§7: §e$distance$suffix"
+
+ if (!foundCurrentArea) {
+ foundCurrentArea = true
+
+ val inAnArea = name != "no_area"
+ if (config.pathfinder.includeCurrentArea.get()) {
+ if (inAnArea) {
+ addSearchString("§eCurrent area: $coloredName")
+ } else {
+ addSearchString("§7Not in an area.")
+ }
+ }
+ if (name != currentAreaName) {
+ if (inAnArea && config.enterTitle) {
+ LorenzUtils.sendTitle("§aEntered $name!", 3.seconds)
+ }
+ currentAreaName = name
+ }
+
+ addSearchString("§eAreas nearby:")
+ continue
+ }
+
+ if (name == "no_area") continue
+ foundAreas++
+
+ add(
+ Renderable.clickAndHover(
+ text,
+ tips = buildList {
+ add(tag.color.getChatColor() + node.name)
+ add("§7Type: ${tag.displayName}")
+ add("§7Distance: §e$distance blocks")
+ add("")
+ if (node == targetNode) {
+ add("§aPath Finder points to this!")
+ add("")
+ add("§eClick to disable!")
+ } else {
+ add("§eClick to find a path!")
+ }
+ },
+ onClick = {
+ if (node == targetNode) {
+ targetNode = null
+ IslandGraphs.stop()
+ updatePosition()
+ } else {
+ setTarget(node)
+ }
+ },
+ ).toSearchable(name),
+ )
+ }
+ if (foundAreas == 0) {
+ val islandName = LorenzUtils.skyBlockIsland.displayName
+ if (foundCurrentArea) {
+ addSearchString("§cThere is only one area in $islandName,")
+ addSearchString("§cnothing else to navigate to!")
+ } else {
+ addSearchString("§cThere is no $islandName area data avaliable yet!")
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onRenderWorld(event: LorenzRenderWorldEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ if (!config.inWorld) return
+ for ((node, distance) in nodes) {
+ val name = node.name ?: continue
+ if (name == currentAreaName) continue
+ if (name == "no_area") continue
+ val position = node.position
+ val color = node.getAreaTag()?.color?.getChatColor() ?: ""
+ if (!position.canBeSeen(40.0)) return
+ event.drawDynamicText(position, color + name, 1.5)
+ }
+ }
+
+ @SubscribeEvent
+ fun onConfigLoad(event: ConfigLoadEvent) {
+ ConditionalUtils.onToggle(config.pathfinder.color) {
+ targetNode?.let {
+ setTarget(it)
+ }
+ }
+ ConditionalUtils.onToggle(config.pathfinder.color, config.pathfinder.includeCurrentArea) {
+ updateNodes()
+ updatePosition()
+ }
+ }
+
+ private val allAreas = listOf(GraphNodeTag.AREA, GraphNodeTag.SMALL_AREA)
+ private val onlyLargeAreas = listOf(GraphNodeTag.AREA)
+
+ private fun GraphNode.getAreaTag(): GraphNodeTag? = tags.firstOrNull {
+ it in (if (config.includeSmallAreas) allAreas else onlyLargeAreas)
+ }
+
+ private fun setTarget(node: GraphNode) {
+ targetNode = node
+ val color = config.pathfinder.color.get().toChromaColor()
+ IslandGraphs.pathFind(
+ node.position, color,
+ onFound = {
+ targetNode = null
+ updatePosition()
+ },
+ condition = { config.pathfinder.enabled },
+ )
+ hasMoved = true
+ }
+
+ fun isEnabled() = LorenzUtils.inSkyBlock && config.let { it.pathfinder.enabled || it.enterTitle || it.inWorld }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt
index e720b57ca..81a85283e 100644
--- a/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt
+++ b/src/main/java/at/hannibal2/skyhanni/test/GraphEditor.kt
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.test
import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.IslandGraphs
import at.hannibal2.skyhanni.data.model.Graph
import at.hannibal2.skyhanni.data.model.GraphNode
import at.hannibal2.skyhanni.data.model.GraphNodeTag
@@ -39,6 +40,7 @@ import at.hannibal2.skyhanni.utils.renderables.buildSearchableScrollable
import at.hannibal2.skyhanni.utils.renderables.toSearchable
import kotlinx.coroutines.runBlocking
import net.minecraft.client.settings.KeyBinding
+import net.minecraftforge.fml.common.eventhandler.EventPriority
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
import java.awt.Color
@@ -104,12 +106,12 @@ object GraphEditor {
private val edgeDijkstraColor = LorenzColor.DARK_BLUE.addOpacity(150)
private val edgeSelectedColor = LorenzColor.DARK_RED.addOpacity(150)
- val scrollValue = ScrollValue()
- val textInput = TextInput()
- var nodesDisplay = emptyList<Searchable>()
+ private val scrollValue = ScrollValue()
+ private val textInput = TextInput()
+ private var nodesDisplay = emptyList<Searchable>()
var lastUpdate = SimpleTimeMark.farPast()
- @SubscribeEvent
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
fun onRender(event: LorenzRenderWorldEvent) {
if (!isEnabled()) return
nodes.forEach { event.drawNode(it) }
@@ -196,7 +198,7 @@ object GraphEditor {
val list = getNodeNames()
val size = list.size
addString("§eGraph Nodes: $size")
- val height = (size * 10).coerceAtMost(150)
+ val height = (size * 10).coerceAtMost(250)
if (list.isNotEmpty()) {
add(list.buildSearchableScrollable(height, textInput, scrollValue, velocity = 10.0))
}
@@ -537,7 +539,11 @@ object GraphEditor {
ChatUtils.chat("Copied nothing since the graph is empty.")
return
}
- val json = compileGraph().toJson()
+ val compileGraph = compileGraph()
+ if (config.useAsIslandArea) {
+ IslandGraphs.setNewGraph(compileGraph)
+ }
+ val json = compileGraph.toJson()
OSUtils.copyToClipboard(json)
ChatUtils.chat("Copied Graph to Clipboard.")
if (config.showsStats) {
diff --git a/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt b/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt
index d3a5e0bce..9e95df881 100644
--- a/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt
+++ b/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt
@@ -8,6 +8,7 @@ import at.hannibal2.skyhanni.config.ConfigManager
import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator
import at.hannibal2.skyhanni.config.core.config.Position
import at.hannibal2.skyhanni.data.HypixelData
+import at.hannibal2.skyhanni.data.IslandGraphs
import at.hannibal2.skyhanni.events.GuiKeyPressEvent
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.LorenzChatEvent
@@ -120,12 +121,17 @@ object SkyHanniDebugsAndTests {
val x = args[0].toDouble()
val y = args[1].toDouble()
val z = args[2].toDouble()
- testLocation = LorenzVec(x, y, z)
+ val location = LorenzVec(x, y, z)
+ testLocation = location
+ if (args.getOrNull(3) == "pathfind") {
+ IslandGraphs.pathFind(location)
+ }
ChatUtils.chat("set test waypoint")
}
fun testCommand(args: Array<String>) {
- SoundUtils.playBeepSound()
+
+
// val a = Thread { OSUtils.copyToClipboard("123") }
// val b = Thread { OSUtils.copyToClipboard("456") }
// a.start()
@@ -509,8 +515,7 @@ object SkyHanniDebugsAndTests {
fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) {
if (!LorenzUtils.inSkyBlock) return
- @Suppress("ConstantConditionIf")
- if (false) {
+ @Suppress("ConstantConditionIf") if (false) {
itemRenderDebug()
}
@@ -545,8 +550,7 @@ object SkyHanniDebugsAndTests {
@SubscribeEvent
fun onGuiRenderChestGuiOverlayRender(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) {
- @Suppress("ConstantConditionIf")
- if (false) {
+ @Suppress("ConstantConditionIf") if (false) {
dragAbleTest()
}
}
@@ -594,8 +598,7 @@ object SkyHanniDebugsAndTests {
}.editCopy {
this.add(
0,
- generateSequence(scale) { it + 0.1 }.take(25).map { Renderable.string(it.round(1).toString()) }
- .toList(),
+ generateSequence(scale) { it + 0.1 }.take(25).map { Renderable.string(it.round(1).toString()) }.toList(),
)
}
config.debugItemPos.renderRenderables(
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt
index ba82321f2..34aa3f22f 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt
@@ -8,7 +8,11 @@ import kotlin.math.min
object LocationUtils {
- fun canSee(a: LorenzVec, b: LorenzVec) =
+ fun canSee(a: LorenzVec, b: LorenzVec, offset: Double? = null): Boolean {
+ return canSee0(a, b) && offset?.let { canSee0(a.add(y = it), b.add(y = it)) } ?: true
+ }
+
+ private fun canSee0(a: LorenzVec, b: LorenzVec) =
Minecraft.getMinecraft().theWorld.rayTraceBlocks(a.toVec3(), b.toVec3(), false, true, false) == null
fun playerLocation() = Minecraft.getMinecraft().thePlayer.getLorenzVec()
@@ -38,10 +42,10 @@ object LocationUtils {
fun AxisAlignedBB.isPlayerInside() = isInside(playerLocation())
- fun LorenzVec.canBeSeen(radius: Double = 150.0): Boolean {
+ fun LorenzVec.canBeSeen(radius: Double = 150.0, offset: Double? = null): Boolean {
val a = playerEyeLocation()
val b = this
- val noBlocks = canSee(a, b)
+ val noBlocks = canSee(a, b, offset)
val notTooFar = a.distance(b) < radius
val inFov = true // TODO add Frustum "Frustum().isBoundingBoxInFrustum(entity.entityBoundingBox)"
return noBlocks && notTooFar && inFov
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
index 4a50d79f3..51bb8b72c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
@@ -74,13 +74,13 @@ data class LorenzVec(
override fun toString() = "LorenzVec{x=$x, y=$y, z=$z}"
- @Deprecated("Use operator fun times instead", ReplaceWith("this * LorenzVec(x, y, z)"))
+ @Deprecated("Use operator fun times instead", ReplaceWith("this * d"))
fun multiply(d: Double): LorenzVec = LorenzVec(x * d, y * d, z * d)
- @Deprecated("Use operator fun times instead", ReplaceWith("this * LorenzVec(x, y, z)"))
+ @Deprecated("Use operator fun times instead", ReplaceWith("this * d"))
fun multiply(d: Int): LorenzVec = LorenzVec(x * d, y * d, z * d)
- @Deprecated("Use operator fun times instead", ReplaceWith("this * LorenzVec(x, y, z)"))
+ @Deprecated("Use operator fun times instead", ReplaceWith("this * v"))
fun multiply(v: LorenzVec) = LorenzVec(x * v.x, y * v.y, z * v.z)
fun dotProduct(other: LorenzVec): Double = (x * other.x) + (y * other.y) + (z * other.z)
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
index 3442032e6..08532e0c4 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt
@@ -1269,6 +1269,7 @@ object RenderUtils {
waypointColor: Color =
(path.lastOrNull()?.name?.getFirstColorCode()?.toLorenzColor() ?: LorenzColor.WHITE).toColor(),
bezierPoint: Double = 1.0,
+ showNoteNames: Boolean = false
) {
if (path.isEmpty()) return
val points = if (startAtEye) {
@@ -1290,8 +1291,10 @@ object RenderUtils {
bezierPoint,
)
}
- path.filter { it.name?.isNotEmpty() == true }.forEach {
- this.drawDynamicText(it.position, it.name!!, textSize)
+ if (showNoteNames) {
+ path.filter { it.name?.isNotEmpty() == true }.forEach {
+ this.drawDynamicText(it.position, it.name!!, textSize)
+ }
}
val last = path.last()
drawWaypointFilled(last.position, waypointColor, seeThroughBlocks = true)
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Searchable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Searchable.kt
index 8ce7c5ec2..4a81830a8 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Searchable.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Searchable.kt
@@ -10,8 +10,9 @@ fun Searchable.toRenderable() = renderable
fun List<Searchable>.toRenderable() = map { it.toRenderable() }
fun List<Searchable>.toMap() = associate { it.renderable to it.string }
val searchPrefix = "§eSearch: §7"
-fun List<Searchable>.buildSearchBox(): Renderable {
- val textInput = TextInput()
+fun List<Searchable>.buildSearchBox(
+ textInput: TextInput,
+): Renderable {
val key = 0
return Renderable.searchBox(
Renderable.verticalSearchableContainer(toMap(), textInput = textInput, key = key + 1),
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt b/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt
index 7810c1ee6..a6d42839c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt
@@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.config.core.config.Position
import at.hannibal2.skyhanni.config.storage.ProfileSpecificStorage
import at.hannibal2.skyhanni.data.ProfileStorageData
import at.hannibal2.skyhanni.data.TrackerManager
+import at.hannibal2.skyhanni.data.model.TextInput
import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValue
import at.hannibal2.skyhanni.test.command.ErrorManager
import at.hannibal2.skyhanni.utils.ChatUtils
@@ -36,6 +37,7 @@ open class SkyHanniTracker<Data : TrackerData>(
private var display = emptyList<Renderable>()
private var sessionResetTime = SimpleTimeMark.farPast()
private var dirty = false
+ private val textInput = TextInput()
companion object {
@@ -85,7 +87,7 @@ open class SkyHanniTracker<Data : TrackerData>(
display = getSharedTracker()?.let {
val data = it.get(getDisplayMode())
val searchables = drawDisplay(data)
- buildFinalDisplay(searchables.buildSearchBox())
+ buildFinalDisplay(searchables.buildSearchBox(textInput))
} ?: emptyList()
dirty = false
}