diff options
author | hannibal2 <24389977+hannibal002@users.noreply.github.com> | 2024-09-13 20:23:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-13 20:23:57 +0200 |
commit | 5e01624dcc315a2bf7665fc808b1113fa4c9e0d8 (patch) | |
tree | 6a97c6970fecd2d517eac80c1aa391eee42addd2 /src/main/java/at | |
parent | 691d2551cf722b76c1894c814d1f6c2e98fe17d6 (diff) | |
download | skyhanni-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/main/java/at')
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 } |