Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
414 changes: 219 additions & 195 deletions src/main/java/shortestpath/PathMapOverlay.java

Large diffs are not rendered by default.

80 changes: 72 additions & 8 deletions src/main/java/shortestpath/PathMapTooltipOverlay.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package shortestpath;

import com.google.inject.Inject;

import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
Expand All @@ -9,7 +10,9 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

import net.runelite.api.Client;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.widgets.ComponentID;
import net.runelite.api.widgets.InterfaceID;
Expand Down Expand Up @@ -48,51 +51,87 @@ public Dimension render(Graphics2D graphics) {
if (plugin.getPathfinder() != null) {
List<Integer> path = plugin.getPathfinder().getPath();
Point cursorPos = client.getMouseCanvasPosition();
int finalDestination = path.size() > 0 ? path.get(path.size() - 1) : WorldPointUtil.UNDEFINED;
for (int i = 0; i < path.size(); i++) {
int nextPoint = WorldPointUtil.UNDEFINED;
if (path.size() > i + 1) {
nextPoint = path.get(i + 1);
}
if (drawTooltip(graphics, cursorPos, path.get(i), nextPoint, i + 1)) {
if (drawTooltip(graphics, cursorPos, path.get(i), nextPoint, i + 1, finalDestination)) {
return null;
}
}
for (int target : plugin.getPathfinder().getTargets()) {
if (path.size() > 0 && target != path.get(path.size() - 1)) {
drawTooltip(graphics, cursorPos, target, WorldPointUtil.UNDEFINED, -1);
drawTooltip(graphics, cursorPos, target, WorldPointUtil.UNDEFINED, -1, finalDestination);
}
}
}

return null;
}

private boolean drawTooltip(Graphics2D graphics, Point cursorPos, int point, int nextPoint, int n) {
private boolean drawTooltip(Graphics2D graphics, Point cursorPos, int point, int nextPoint, int n, int finalDestination) {
int offsetPoint = WorldPointUtil.dxdy(point, 1, -1);
int startX = plugin.mapWorldPointToGraphicsPointX(point);
int startY = plugin.mapWorldPointToGraphicsPointY(point);
int endX = plugin.mapWorldPointToGraphicsPointX(offsetPoint);
int endY = plugin.mapWorldPointToGraphicsPointY(offsetPoint);

if (startX == Integer.MIN_VALUE || startY == Integer.MIN_VALUE ||
endX == Integer.MIN_VALUE || endY == Integer.MIN_VALUE) {
endX == Integer.MIN_VALUE || endY == Integer.MIN_VALUE) {
return false;
}

int width = endX - startX;

if (cursorPos.getX() < (startX - width / 2) || cursorPos.getX() > (endX - width / 2) ||
cursorPos.getY() < (startY - width / 2) || cursorPos.getY() > (endY - width / 2)) {
cursorPos.getY() < (startY - width / 2) || cursorPos.getY() > (endY - width / 2)) {
return false;
}

List<String> rows = new ArrayList<>(Arrays.asList("Shortest path:",
n < 0 ? "Unused target" : ("Step " + n + " of " + plugin.getPathfinder().getPath().size())));
n < 0 ? "Unused target" : ("Step " + n + " of " + plugin.getPathfinder().getPath().size())));
if (nextPoint != WorldPointUtil.UNDEFINED) {
for (Transport transport : plugin.getTransports().getOrDefault(point, new HashSet<>())) {
if (nextPoint == transport.getDestination()
&& transport.getDisplayInfo() != null && !transport.getDisplayInfo().isEmpty()) {
rows.add(transport.getDisplayInfo());
&& transport.getDisplayInfo() != null && !transport.getDisplayInfo().isEmpty()) {
String transportText = transport.getDisplayInfo();


if (plugin.showTilesSaved && TransportType.isResourceMovement(transport.getType())) {
Player localPlayer = client.getLocalPlayer();
if (localPlayer != null) {
int currentLocation = WorldPointUtil.fromLocalInstance(client, localPlayer.getLocalLocation());
List<Integer> path = plugin.getPathfinder().getPath();

int remainingPathDistance = calculatePathDistance(path, transport.getDestination(), finalDestination);

int walkingDistance;
if (plugin.showBothPaths && plugin.getWalkingPathfinder() != null &&
plugin.getWalkingPathfinder().isDone() && plugin.getWalkingPathfinder().getPath() != null) {
// Use actual walking path distance
List<Integer> walkingPath = plugin.getWalkingPathfinder().getPath();
walkingDistance = calculatePathDistance(walkingPath, currentLocation, finalDestination);
if (walkingDistance == -1) {
// Fallback to straight-line if point not found in walking path
walkingDistance = WorldPointUtil.distanceBetween(currentLocation, finalDestination);
}
} else {
// Use straight-line distance as approximation
walkingDistance = WorldPointUtil.distanceBetween(currentLocation, finalDestination);
}

if (remainingPathDistance != -1 && walkingDistance > remainingPathDistance) {
int tilesSaved = walkingDistance - remainingPathDistance;
if (tilesSaved > 0) {
transportText += " (" + tilesSaved + " tiles saved)";
}
}
}
}

rows.add(transportText);
break;
}
}
Expand Down Expand Up @@ -136,4 +175,29 @@ private boolean drawTooltip(Graphics2D graphics, Point cursorPos, int point, int

return true;
}

private int calculatePathDistance(List<Integer> path, int startPoint, int endPoint) {
int startIndex = -1;
int endIndex = -1;

for (int i = 0; i < path.size(); i++) {
if (path.get(i) == startPoint) {
startIndex = i;
}
if (path.get(i) == endPoint) {
endIndex = i;
}
}

if (startIndex == -1 || endIndex == -1 || startIndex >= endIndex) {
return -1;
}

int totalDistance = 0;
for (int i = startIndex + 1; i <= endIndex; i++) {
totalDistance += WorldPointUtil.distanceBetween(path.get(i - 1), path.get(i));
}

return totalDistance;
}
}
208 changes: 115 additions & 93 deletions src/main/java/shortestpath/PathMinimapOverlay.java
Original file line number Diff line number Diff line change
@@ -1,93 +1,115 @@
package shortestpath;

import com.google.inject.Inject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.util.List;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;

public class PathMinimapOverlay extends Overlay {
private final Client client;
private final ShortestPathPlugin plugin;

@Inject
private PathMinimapOverlay(Client client, ShortestPathPlugin plugin) {
this.client = client;
this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setPriority(Overlay.PRIORITY_LOW);
setLayer(OverlayLayer.ABOVE_WIDGETS);
}

@Override
public Dimension render(Graphics2D graphics) {
if (!plugin.drawMinimap || plugin.getPathfinder() == null) {
return null;
}

Shape minimapClipArea = plugin.getMinimapClipArea();
if (minimapClipArea == null) {
return null;
} else {
graphics.setClip(plugin.getMinimapClipArea());
}
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);

List<Integer> pathPoints = plugin.getPathfinder().getPath();
Color pathColor = plugin.getPathfinder().isDone() ? plugin.colourPath : plugin.colourPathCalculating;
for (int pathPoint : pathPoints) {
if (WorldPointUtil.unpackWorldPlane(pathPoint) != client.getPlane()) {
continue;
}

drawOnMinimap(graphics, pathPoint, pathColor);
}
for (int target : plugin.getPathfinder().getTargets()) {
if (pathPoints.size() > 0 && target != pathPoints.get(pathPoints.size() - 1)) {
drawOnMinimap(graphics, target, plugin.colourPathCalculating);
}
}

return null;
}

private void drawOnMinimap(Graphics2D graphics, int location, Color color) {
for (int point : WorldPointUtil.toLocalInstance(client, location)) {
LocalPoint lp = WorldPointUtil.toLocalPoint(client, point);

if (lp == null) {
continue;
}

Point posOnMinimap = Perspective.localToMinimap(client, lp);

if (posOnMinimap == null) {
continue;
}

renderMinimapRect(client, graphics, posOnMinimap, color);
}
}

public static void renderMinimapRect(Client client, Graphics2D graphics, Point center, Color color) {
double angle = client.getCameraYawTarget() * Perspective.UNIT;
double tileSize = client.getMinimapZoom();
int x = (int) Math.round(center.getX() - tileSize / 2);
int y = (int) Math.round(center.getY() - tileSize / 2);
int width = (int) Math.round(tileSize);
int height = (int) Math.round(tileSize);
graphics.setColor(color);
graphics.rotate(angle, center.getX(), center.getY());
graphics.fillRect(x, y, width, height);
graphics.rotate(-angle, center.getX(), center.getY());
}
}
package shortestpath;

import com.google.inject.Inject;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.util.List;

import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;

public class PathMinimapOverlay extends Overlay {
private final Client client;
private final ShortestPathPlugin plugin;

@Inject
private PathMinimapOverlay(Client client, ShortestPathPlugin plugin) {
this.client = client;
this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setPriority(Overlay.PRIORITY_LOW);
setLayer(OverlayLayer.ABOVE_WIDGETS);
}

@Override
public Dimension render(Graphics2D graphics) {
if (!plugin.drawMinimap) {
return null;
}

Shape minimapClipArea = plugin.getMinimapClipArea();
if (minimapClipArea == null) {
return null;
} else {
graphics.setClip(plugin.getMinimapClipArea());
}
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);


if (plugin.showBothPaths && plugin.getWalkingPathfinder() != null && plugin.getWalkingPathfinder().getPath() != null) {
List<Integer> walkingPathPoints = plugin.getWalkingPathfinder().getPath();
Color walkingPathColor = plugin.getWalkingPathfinder().isDone()
? new Color(plugin.colourWalkingPath.getRed(), plugin.colourWalkingPath.getGreen(),
plugin.colourWalkingPath.getBlue(), plugin.colourWalkingPath.getAlpha() / 2)
: new Color(plugin.colourPathCalculating.getRed(), plugin.colourPathCalculating.getGreen(),
plugin.colourPathCalculating.getBlue(), plugin.colourPathCalculating.getAlpha() / 2);

for (int pathPoint : walkingPathPoints) {
if (WorldPointUtil.unpackWorldPlane(pathPoint) != client.getPlane()) {
continue;
}
drawOnMinimap(graphics, pathPoint, walkingPathColor);
}
}

// Draw main path
if (plugin.getPathfinder() != null && plugin.getPathfinder().getPath() != null) {
List<Integer> pathPoints = plugin.getPathfinder().getPath();
Color pathColor = plugin.getPathfinder().isDone() ? plugin.colourPath : plugin.colourPathCalculating;
for (int pathPoint : pathPoints) {
if (WorldPointUtil.unpackWorldPlane(pathPoint) != client.getPlane()) {
continue;
}

drawOnMinimap(graphics, pathPoint, pathColor);
}
for (int target : plugin.getPathfinder().getTargets()) {
if (pathPoints.size() > 0 && target != pathPoints.get(pathPoints.size() - 1)) {
drawOnMinimap(graphics, target, plugin.colourPathCalculating);
}
}
}

return null;
}

private void drawOnMinimap(Graphics2D graphics, int location, Color color) {
for (int point : WorldPointUtil.toLocalInstance(client, location)) {
LocalPoint lp = WorldPointUtil.toLocalPoint(client, point);

if (lp == null) {
continue;
}

Point posOnMinimap = Perspective.localToMinimap(client, lp);

if (posOnMinimap == null) {
continue;
}

renderMinimapRect(client, graphics, posOnMinimap, color);
}
}

public static void renderMinimapRect(Client client, Graphics2D graphics, Point center, Color color) {
double angle = client.getCameraYawTarget() * Perspective.UNIT;
double tileSize = client.getMinimapZoom();
int x = (int) Math.round(center.getX() - tileSize / 2);
int y = (int) Math.round(center.getY() - tileSize / 2);
int width = (int) Math.round(tileSize);
int height = (int) Math.round(tileSize);
graphics.setColor(color);
graphics.rotate(angle, center.getX(), center.getY());
graphics.fillRect(x, y, width, height);
graphics.rotate(-angle, center.getX(), center.getY());
}
}
Loading