diff --git a/runelite-api/src/main/java/net/runelite/api/Actor.java b/runelite-api/src/main/java/net/runelite/api/Actor.java index e3becbf73d..101c9a2c51 100644 --- a/runelite-api/src/main/java/net/runelite/api/Actor.java +++ b/runelite-api/src/main/java/net/runelite/api/Actor.java @@ -22,9 +22,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package net.runelite.api; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.geom.Rectangle2D; import net.runelite.rs.api.CombatInfo1; import net.runelite.rs.api.CombatInfo2; import net.runelite.rs.api.CombatInfoList; @@ -33,6 +36,7 @@ import net.runelite.rs.api.Node; public abstract class Actor extends Renderable { + private Client client; private net.runelite.rs.api.Actor actor; @@ -107,4 +111,71 @@ public abstract class Actor extends Renderable } return -1; } + + public Point getLocalLocation() + { + return new Point(getX(), getY()); + } + + private int getX() + { + return actor.getX(); + } + + private int getY() + { + return actor.getY(); + } + + public int getAnimation() + { + return actor.getAnimation(); + } + + public int getModelHeight() + { + return actor.getModelHeight(); + } + + public Polygon getCanvasTilePoly() + { + int plane = client.getPlane(); + int halfTile = Perspective.LOCAL_TILE_SIZE / 2; + + Point p1 = Perspective.worldToCanvas(client, getX() - halfTile, getY() - halfTile, plane); + Point p2 = Perspective.worldToCanvas(client, getX() - halfTile, getY() + halfTile, plane); + Point p3 = Perspective.worldToCanvas(client, getX() + halfTile, getY() + halfTile, plane); + Point p4 = Perspective.worldToCanvas(client, getX() + halfTile, getY() - halfTile, plane); + + if (p1 == null || p2 == null || p3 == null || p4 == null) + { + return null; + } + + Polygon poly = new Polygon(); + poly.addPoint(p1.getX(), p1.getY()); + poly.addPoint(p2.getX(), p2.getY()); + poly.addPoint(p3.getX(), p3.getY()); + poly.addPoint(p4.getX(), p4.getY()); + + return poly; + } + + public Point getCanvasTextLocation(Graphics2D graphics, String text, int zOffset) + { + int plane = client.getPlane(); + + Point p = Perspective.worldToCanvas(client, getLocalLocation().getX(), getLocalLocation().getY(), plane, zOffset); + + if (p == null) + { + return null; + } + + FontMetrics fm = graphics.getFontMetrics(); + Rectangle2D bounds = fm.getStringBounds(text, graphics); + int xOffset = p.getX() - (int) (bounds.getWidth() / 2); + + return new Point(xOffset, p.getY()); + } } diff --git a/runelite-api/src/main/java/net/runelite/api/Perspective.java b/runelite-api/src/main/java/net/runelite/api/Perspective.java index 78278d7bb0..149ab04d34 100644 --- a/runelite-api/src/main/java/net/runelite/api/Perspective.java +++ b/runelite-api/src/main/java/net/runelite/api/Perspective.java @@ -29,7 +29,7 @@ public class Perspective private static final double UNIT = Math.PI / 1024d; // How much of the circle each unit of SINE/COSINE is private static final int LOCAL_COORD_BITS = 7; - private static final int LOCAL_TILE_SIZE = 1 << LOCAL_COORD_BITS; // 128 - size of a tile in local coordinates + public static final int LOCAL_TILE_SIZE = 1 << LOCAL_COORD_BITS; // 128 - size of a tile in local coordinates public static final int[] SINE = new int[2048]; // sine angles for each of the 2048 units, * 65536 and stored as an int public static final int[] COSINE = new int[2048]; // cosine @@ -50,18 +50,36 @@ public class Perspective * @param client * @param x ground coordinate on the x axis * @param y ground coordinate on the y axis - * @param var2 + * @param plane ground plane on the z axis * @return a {@link Point} on screen corresponding to the position in * 3D-space */ - public static Point worldToCanvas(Client client, int x, int y, int var2) + public static Point worldToCanvas(Client client, int x, int y, int plane) + { + return worldToCanvas(client, x, y, plane, 0); + } + + /** + * Translates two-dimensional ground coordinates within the 3D world to + * their corresponding coordinates on the game screen. + * + * @param client + * @param x ground coordinate on the x axis + * @param y ground coordinate on the y axis + * @param plane ground plane on the z axis + * @param zOffset distance from ground on the z axis + * @return a {@link Point} on screen corresponding to the position in + * 3D-space + */ + public static Point worldToCanvas(Client client, int x, int y, int plane, int zOffset) { if (x >= 128 && y >= 128 && x <= 13056 && y <= 13056) { - int z = getTileHeight(client, x, y, client.getPlane()) - var2; + int z = getTileHeight(client, x, y, client.getPlane()) - plane; x -= client.getCameraX(); - z -= client.getCameraZ(); y -= client.getCameraY(); + z -= client.getCameraZ(); + z -= zOffset; int cameraPitch = client.getCameraPitch(); int cameraYaw = client.getCameraYaw(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index 011443e1f6..dbe5a98a52 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -31,6 +31,7 @@ import net.runelite.client.RuneLite; import net.runelite.client.plugins.boosts.Boosts; import net.runelite.client.plugins.bosstimer.BossTimers; import net.runelite.client.plugins.debug.Debug; +import net.runelite.client.plugins.devtools.DevTools; import net.runelite.client.plugins.fpsinfo.FPS; import net.runelite.client.plugins.gronditems.GroundItems; import net.runelite.client.plugins.hiscore.Hiscore; @@ -64,6 +65,7 @@ public class PluginManager load(new Debug()); load(new GroundItems()); + load(new DevTools()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java new file mode 100644 index 0000000000..73a31996e0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, Kronos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.devtools; + +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.Overlay; + +public class DevTools extends Plugin +{ + private final DevToolsOverlay overlay = new DevToolsOverlay(); + + @Override + public Overlay getOverlay() + { + return overlay; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java new file mode 100644 index 0000000000..e560ecb218 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017, Kronos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.devtools; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.NPC; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.client.RuneLite; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; + +public class DevToolsOverlay extends Overlay +{ + + private static final Client client = RuneLite.getClient(); + + public DevToolsOverlay() + { + super(OverlayPosition.DYNAMIC); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return null; + } + + NPC[] npcs = client.getNpcs(); + if (npcs != null && (npcs.length - 1) > 0) + { + for (NPC npc : npcs) + { + if (npc != null) + { + String text = npc.getName() + " (A: " + npc.getAnimation() + ")"; + if (npc.getCombatLevel() > 1) + { + render(graphics, npc, text, new Color(230, 74, 25)); + } + else + { + render(graphics, npc, text, Color.ORANGE); + } + } + } + } + + Player[] players = client.getPlayers(); + if (players != null && (players.length - 1) > 0) + { + for (Player p : players) + { + if (p != null) + { + if (!p.getName().equals(client.getLocalPlayer().getName())) + { + String text = p.getName() + " (A: " + p.getAnimation() + ")"; + render(graphics, p, text, Color.BLUE); + } + } + } + } + + Player local = client.getLocalPlayer(); + String text = local.getName() + " (A: " + local.getAnimation() + ")"; + render(graphics, local, text, Color.CYAN); + + return null; + } + + private void render(Graphics2D graphics, Actor actor, String text, Color color) + { + Polygon poly = actor.getCanvasTilePoly(); + if (poly == null) + { + return; + } + + Point textLocation = actor.getCanvasTextLocation(graphics, text, actor.getModelHeight()); + + graphics.setColor(color); + graphics.setStroke(new BasicStroke(2)); + graphics.drawPolygon(poly); + graphics.setColor(new Color(0, 0, 0, 50)); + graphics.fillPolygon(poly); + + if (textLocation != null) + { + graphics.setColor(Color.WHITE); + graphics.drawString(text, textLocation.getX(), textLocation.getY()); + } + } + +}