From eecf1837006cba79e043da838fad13c8a5118b1d Mon Sep 17 00:00:00 2001 From: Toocanzs Date: Sat, 18 Nov 2017 02:31:59 -0500 Subject: [PATCH] instance map: add complex tile rendering --- .../src/main/java/net/runelite/api/Actor.java | 2 + .../java/net/runelite/api/Perspective.java | 2 +- .../main/java/net/runelite/api/Region.java | 4 + .../java/net/runelite/api/SceneTileModel.java | 36 ++ .../src/main/java/net/runelite/api/Tile.java | 6 + .../java/net/runelite/api/WallObject.java | 3 + .../instancemap/InstanceMapOverlay.java | 419 +++++++++++++++++- .../plugins/instancemap/IntanceMapPlugin.java | 65 ++- .../client/plugins/instancemap/PixelMaps.java | 207 +++++++++ .../plugins/instancemap/WallOffset.java | 47 ++ .../client/plugins/instancemap/WallShape.java | 51 +++ .../net/runelite/mixins/RSActorMixin.java | 8 + .../java/net/runelite/mixins/RSTileMixin.java | 49 ++ .../java/net/runelite/rs/api/RSRegion.java | 9 + .../net/runelite/rs/api/RSSceneTileModel.java | 47 ++ .../main/java/net/runelite/rs/api/RSTile.java | 5 + .../net/runelite/rs/api/RSWallObject.java | 8 + 17 files changed, 940 insertions(+), 28 deletions(-) create mode 100644 runelite-api/src/main/java/net/runelite/api/SceneTileModel.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/instancemap/PixelMaps.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallOffset.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallShape.java create mode 100644 runelite-mixins/src/main/java/net/runelite/mixins/RSTileMixin.java create mode 100644 runescape-api/src/main/java/net/runelite/rs/api/RSSceneTileModel.java 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 301ffb97dc..af3b61d30c 100644 --- a/runelite-api/src/main/java/net/runelite/api/Actor.java +++ b/runelite-api/src/main/java/net/runelite/api/Actor.java @@ -61,4 +61,6 @@ public interface Actor extends Renderable Point getCanvasSpriteLocation(Graphics2D graphics, SpritePixels sprite, int zOffset); Point getMinimapLocation(); + + Point getRegionLocation(); } 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 47aa5f07b5..5fa47381fd 100644 --- a/runelite-api/src/main/java/net/runelite/api/Perspective.java +++ b/runelite-api/src/main/java/net/runelite/api/Perspective.java @@ -34,7 +34,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; + public static final int LOCAL_COORD_BITS = 7; 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 diff --git a/runelite-api/src/main/java/net/runelite/api/Region.java b/runelite-api/src/main/java/net/runelite/api/Region.java index 95fd4148eb..c095406d39 100644 --- a/runelite-api/src/main/java/net/runelite/api/Region.java +++ b/runelite-api/src/main/java/net/runelite/api/Region.java @@ -27,4 +27,8 @@ package net.runelite.api; public interface Region { Tile[][][] getTiles(); + + int[][] getTileMask2d(); + + int[][] getTileRotation2d(); } diff --git a/runelite-api/src/main/java/net/runelite/api/SceneTileModel.java b/runelite-api/src/main/java/net/runelite/api/SceneTileModel.java new file mode 100644 index 0000000000..31cfc08100 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/SceneTileModel.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Adam + * 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.api; + +public interface SceneTileModel +{ + int getModelUnderlay(); + + int getModelOverlay(); + + int getShape(); + + int getRotation(); +} diff --git a/runelite-api/src/main/java/net/runelite/api/Tile.java b/runelite-api/src/main/java/net/runelite/api/Tile.java index bc82e97274..58954c405a 100644 --- a/runelite-api/src/main/java/net/runelite/api/Tile.java +++ b/runelite-api/src/main/java/net/runelite/api/Tile.java @@ -42,4 +42,10 @@ public interface Tile WallObject getWallObject(); SceneTilePaint getSceneTilePaint(); + + SceneTileModel getSceneTileModel(); + + Point getWorldLocation(); + + Point getLocalLocation(); } diff --git a/runelite-api/src/main/java/net/runelite/api/WallObject.java b/runelite-api/src/main/java/net/runelite/api/WallObject.java index e5510d05e6..a16216a8c2 100644 --- a/runelite-api/src/main/java/net/runelite/api/WallObject.java +++ b/runelite-api/src/main/java/net/runelite/api/WallObject.java @@ -31,4 +31,7 @@ package net.runelite.api; */ public interface WallObject extends TileObject { + int getOrientationA(); + + int getOrientationB(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java index 27d2167e1a..568fb9b099 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java @@ -27,29 +27,77 @@ package net.runelite.client.plugins.instancemap; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import javax.annotation.Nullable; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.Region; +import net.runelite.api.SceneTileModel; +import net.runelite.api.SceneTilePaint; import net.runelite.api.Tile; +import net.runelite.api.WallObject; +import net.runelite.client.events.GameStateChanged; +import net.runelite.client.events.MapRegionChanged; +import static net.runelite.client.plugins.instancemap.PixelMaps.ALL; +import static net.runelite.client.plugins.instancemap.PixelMaps.BOTTOM; +import static net.runelite.client.plugins.instancemap.PixelMaps.BOTTOM_LEFT_CORNER; +import static net.runelite.client.plugins.instancemap.PixelMaps.BOTTOM_LEFT_TO_TOP_RIGHT; +import static net.runelite.client.plugins.instancemap.PixelMaps.BOTTOM_RIGHT_CORNER; +import static net.runelite.client.plugins.instancemap.PixelMaps.LEFT; +import static net.runelite.client.plugins.instancemap.PixelMaps.RIGHT; +import static net.runelite.client.plugins.instancemap.PixelMaps.TOP; +import static net.runelite.client.plugins.instancemap.PixelMaps.TOP_LEFT_CORNER; +import static net.runelite.client.plugins.instancemap.PixelMaps.TOP_RIGHT_CORNER; +import static net.runelite.client.plugins.instancemap.PixelMaps.TOP_RIGHT_TO_BOTTOM_LEFT; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; class InstanceMapOverlay extends Overlay { /** - * Size of the drawn tile in the instance map. + * The size of tiles on the map. The way the client renders requires + * this value to be 4. Changing this will break the method for rendering + * complex tiles */ - private static final int tileSize = 3; + static final int TILE_SIZE = 4; + + /** + * The multiplier to scale the map size by. This is just for rendering + * mapImage. mapImage is scaled by this value + */ + private static final double MAP_SCALING = 1; + + /** + * The size of the player's position marker on the map + */ + private static final int PLAYER_MARKER_SIZE = 4; + + private static final int MAX_PLANE = 3; + private static final int MIN_PLANE = 0; + + /** + * The plane to render on the instance map. When the map is opened this + * defaults to the current plane. The ascend and descend buttons raise + * and lower this This is used to render parts of an instance below or + * above the local player's current plane. + */ + private int viewedPlane = 0; private final Client client; private final InstanceMapConfig config; + /** + * Saved image of the region, no reason to draw the whole thing every + * frame. This is redrawn in the drawToBufferedImage method + */ + private BufferedImage mapImage; private boolean showMap = false; @Inject - InstanceMapOverlay(@Nullable Client client, - InstanceMapConfig config) + InstanceMapOverlay(@Nullable Client client, InstanceMapConfig config) { super(OverlayPosition.DYNAMIC); this.client = client; @@ -61,9 +109,48 @@ class InstanceMapOverlay extends Overlay return showMap; } + /** + * Setter for showing the map. When the map is set to show, the map is + * re-rendered + * + * @param show Whether or not the map should be shown. + */ public void setShowMap(boolean show) { showMap = show; + if (showMap) + { + viewedPlane = client.getPlane();//When we open the map show the current plane + mapImage = drawMapImage(getTiles()); + } + } + + /** + * Increases the viewed plane. The maximum viewedPlane is 3 + */ + public void onAscend() + { + if (viewedPlane >= MAX_PLANE) + { + return; + } + + viewedPlane++;//Increment plane + mapImage = drawMapImage(getTiles()); + } + + /** + * Decreases the viewed plane. The minimum viewedPlane is 0 + */ + public void onDescend() + { + if (viewedPlane <= MIN_PLANE) + { + return; + } + + viewedPlane--; + mapImage = drawMapImage(getTiles()); } @Override @@ -74,7 +161,86 @@ class InstanceMapOverlay extends Overlay return null; } - return drawInstanceMap(graphics); + if (mapImage == null) + { + mapImage = drawMapImage(getTiles()); + } + + //Scale mapImage by the mapScaling to display a larger map. + graphics.drawImage(mapImage, 0, 0, (int) (mapImage.getWidth() * MAP_SCALING), (int) (mapImage.getHeight() * MAP_SCALING), 0, 0, mapImage.getWidth(), mapImage.getHeight(), null); + + if (client.getPlane() == viewedPlane)//If we are not viewing the plane we are on, don't show player's position + { + drawPlayerDot(graphics, client.getLocalPlayer(), Color.white, Color.black); + } + + Tile[][] tiles = getTiles(); + Dimension mapOverlaySize = new Dimension(tiles.length * TILE_SIZE, tiles[0].length * TILE_SIZE); + + return mapOverlaySize; + } + + /** + * Draws the players position as a dot on the map. + * + * @param graphics graphics to be drawn to + */ + private void drawPlayerDot(Graphics2D graphics, Player player, Color dotColor, Color outlineColor) + { + Point playerLocation = player.getRegionLocation(); + + Tile[][] tiles = getTiles(); + Point localPlayerPoint = new Point(playerLocation.getX(), (tiles[0].length - 1) - playerLocation.getY()); // flip the y value + + graphics.setColor(dotColor); + graphics.fillRect((int) (localPlayerPoint.getX() * TILE_SIZE * MAP_SCALING), (int) (localPlayerPoint.getY() * TILE_SIZE * MAP_SCALING), PLAYER_MARKER_SIZE, PLAYER_MARKER_SIZE);//draw the players point on the map + graphics.setColor(outlineColor); + graphics.drawRect((int) (localPlayerPoint.getX() * TILE_SIZE * MAP_SCALING), (int) (localPlayerPoint.getY() * TILE_SIZE * MAP_SCALING), PLAYER_MARKER_SIZE, PLAYER_MARKER_SIZE);//outline + } + + /** + * Handles region changes and re-draws the map + * + * @param event The region change event + */ + public void onRegionChange(MapRegionChanged event) + { + mapImage = drawMapImage(getTiles()); + } + + /** + * Handles game state changes and re-draws the map + * + * @param event The game state change event + */ + public void onGameStateChange(GameStateChanged event) + { + mapImage = drawMapImage(getTiles()); + } + + /** + * Get the files for the current viewed plane + * + * @return + */ + private Tile[][] getTiles() + { + Tile[][][] regionTiles = client.getRegion().getTiles(); + return regionTiles[viewedPlane]; + } + + /** + * Draws the map to the the buffered image mapImage + * + * @param tiles The tiles to draw to the map + */ + private BufferedImage drawMapImage(Tile[][] tiles) + { + BufferedImage image = new BufferedImage(tiles.length * TILE_SIZE, tiles[0].length * TILE_SIZE, BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + drawInstanceMap(g); + g.dispose(); + return image; } /** @@ -84,31 +250,246 @@ class InstanceMapOverlay extends Overlay * @param graphics graphics to draw to * @return The dimensions of the map */ - private Dimension drawInstanceMap(Graphics2D graphics) + private void drawInstanceMap(Graphics2D graphics) { - Tile[][][] regionTiles = client.getRegion().getTiles(); + Region region = client.getRegion(); + Tile[][] tiles = getTiles(); - int plane = client.getPlane(); - Tile[][] tiles = regionTiles[plane]; + Dimension mapOverlaySize = new Dimension(tiles.length * TILE_SIZE, tiles[0].length * TILE_SIZE); - Dimension mapOverlaySize = new Dimension(tiles.length * tileSize, tiles[0].length * tileSize); - - graphics.setColor(Color.BLACK); - graphics.fillRect(0, 0, mapOverlaySize.width, mapOverlaySize.height); + graphics.setColor(Color.black); + graphics.fillRect(0, 0, mapOverlaySize.width, mapOverlaySize.height);//draw background + graphics.setColor(Color.white); + graphics.drawRect(0, 0, mapOverlaySize.width - 1, mapOverlaySize.height - 1);//draw outline + //Draw the base colors first for (int x = 0; x < tiles.length; x++) { - for (int y = 0; y < tiles[x].length; y++) + for (int y = tiles[x].length - 1; y >= 0; y--)//flip y value { - Tile curTile = tiles[x][(tiles[x].length - 1) - y]; // flip the y value - if (curTile != null && curTile.getSceneTilePaint() != null) + drawTileColor(graphics, region, tiles[x][(tiles[x].length - 1) - y], x, y); + } + } + + //Draw walls on top + for (int x = 0; x < tiles.length; x++) + { + for (int y = tiles[x].length - 1; y >= 0; y--)//Flip y value + { + drawTileWalls(graphics, tiles[x][(tiles[x].length - 1) - y], x, y); + } + } + + } + + private void drawTileWalls(Graphics2D graphics, Tile curTile, int x, int y) + { + if (curTile != null) + { + WallObject wallObject = curTile.getWallObject(); + if (wallObject != null) + { + drawWallObject(graphics, wallObject, curTile, x * TILE_SIZE, y * TILE_SIZE); + } + } + } + + private void drawTileColor(Graphics2D graphics, Region region, Tile curTile, int x, int y) + { + if (curTile != null) + { + SceneTilePaint sceneTilePaint = curTile.getSceneTilePaint(); + SceneTileModel sceneTileModel = curTile.getSceneTileModel(); + + if (sceneTilePaint != null) + { + drawMapPixel(graphics, sceneTilePaint, x * TILE_SIZE, y * TILE_SIZE); + } + else if (sceneTileModel != null) + { + drawComplexMapPixel(graphics, sceneTileModel, region, x * TILE_SIZE, y * TILE_SIZE); + } + } + } + + /** + * Draws a tile as 4x4 pixels on the map. This tile will be drawn as a + * set of 4x4 pixels + * + * @param graphics graphics to be drawn to + * @param sceneTilePaint the tiles sceneTilePaint used to get the RGB + * value of that tile + * @param startX the top left point at which the 4x4 is drawn + * @param startY the top left point at which the 4x4 is drawn + */ + private void drawMapPixel(Graphics2D graphics, SceneTilePaint sceneTilePaint, int startX, int startY) + { + Color c = new Color(sceneTilePaint.getRBG());//Normal map pixels have only 1 solid color + graphics.setColor(c); + graphics.fillRect(startX, startY, TILE_SIZE, TILE_SIZE); + } + + /** + * Gets the walls shape from the orientation + * + * @param orientationA the wall object's orientationA + * @param orientationB the wall object's orientationB + * @return A WallShape representing the wall as a 4x4 set of pixels with + * an offset + */ + private WallShape getWallShape(int orientationA, int orientationB) + { + int[][] pixels = ALL; + WallOffset wallOffset = WallOffset.NONE; + + switch (orientationA) + { + case 16: + //Diagonal / + pixels = BOTTOM_LEFT_TO_TOP_RIGHT; + wallOffset = WallOffset.TOP_LEFT; + break; + case 32: + //Diagonal \ + pixels = TOP_RIGHT_TO_BOTTOM_LEFT; + wallOffset = WallOffset.TOP_RIGHT; + break; + case 64: + //Diagonal / + pixels = BOTTOM_LEFT_TO_TOP_RIGHT; + wallOffset = WallOffset.BOTTOM_RIGHT; + break; + case 1: + //Left wall + pixels = LEFT; + break; + case 2: + //Top wall + pixels = TOP; + break; + case 4: + //Right wall + pixels = RIGHT; + break; + case 8: + //Bottom wall + pixels = BOTTOM; + break; + case 128: + //Diagonal \ + pixels = TOP_RIGHT_TO_BOTTOM_LEFT; + wallOffset = WallOffset.BOTTOM_LEFT; + break; + } + + switch (orientationB) + { + case 2: + //top left corner + pixels = TOP_LEFT_CORNER; + break; + case 4: + //top right corner + pixels = TOP_RIGHT_CORNER; + break; + case 8: + //bottom right corner + pixels = BOTTOM_RIGHT_CORNER; + break; + case 1: + //Bottom left corner + pixels = BOTTOM_LEFT_CORNER; + break; + } + + return new WallShape(pixels, wallOffset); + } + + /** + * Draws a wall on the map using a tiles WallObject. This wall will be + * drawn as a set of 4x4 pixels + * + * @param graphics graphics to be drawn to + * @param wallObject the wall object of the tile + * @param startX the top left point at which the 4x4 is drawn + * @param startY the top left point at which the 4x4 is drawn + */ + private void drawWallObject(Graphics2D graphics, WallObject wallObject, Tile tile, int startX, int startY) + { + graphics.setColor(Color.white); + + int orientationA = wallObject.getOrientationA();//Orientation is a set of flags stored as an int + int orientationB = wallObject.getOrientationB(); + + WallShape wallShape = getWallShape(orientationA, orientationB); + int[][] pixels = wallShape.getPixels(); + + for (int i = 0; i < pixels.length; i++) + { + for (int j = 0; j < pixels.length; j++) + { + if (pixels[i][j] == 1) { - graphics.setColor(new Color(curTile.getSceneTilePaint().getRBG())); - graphics.fillRect(x * tileSize, y * tileSize, tileSize, tileSize); + //Draw the 4x4 and offset accordingly + drawPoint(graphics, startX + wallShape.getOffset().xOffset + j, startY + wallShape.getOffset().yOffset + i); } } } - return mapOverlaySize; } + + /** + * Draws just one pixel to the screen + * + * @param graphics Graphics to be drawn to + * @param x x position of the pixel + * @param y y position of the pixel + */ + private void drawPoint(Graphics2D graphics, int x, int y) + { + graphics.drawLine(x, y, x, y); + } + + /** + * Draws tiles which have more than one color to them. For example a + * tile that falls on the edge of a river will have one part that is + * grass, and the other part will be water. To draw these tiles we need + * to use two colors. This tile will be drawn as a 4x4 set of pixels + * + * @param graphics the graphics to be drawn to + * @param sceneTileModel The SceneTileModel of the complex tile + * @param region The current region + * @param startX the top left point at which the 4x4 is drawn + * @param startY the top left point at which the 4x4 is drawn + */ + private void drawComplexMapPixel(Graphics2D graphics, SceneTileModel sceneTileModel, Region region, int startX, int startY) + { + //Most of this code is directly from the client from minimap rendering + int[][] TILE_MASK_2D = region.getTileMask2d(); + int[][] TILE_ROTATION_2D = region.getTileRotation2d(); + + int shape = sceneTileModel.getShape(); + int rotation = sceneTileModel.getRotation(); + + int overlay = sceneTileModel.getModelOverlay();//SceneTileModels have only two colors, and overlay and underlay. + int underlay = sceneTileModel.getModelUnderlay(); + + int[] shapes = TILE_MASK_2D[shape]; + int[] rotations = TILE_ROTATION_2D[rotation]; + + int rotationIndex = 0; + + for (int i = 0; i < TILE_SIZE; i++) + { + for (int j = 0; j < TILE_SIZE; j++) + { + int intColor = (shapes[rotations[rotationIndex++]] == 0) ? underlay : overlay; + Color c = new Color(intColor); + graphics.setColor(c); + graphics.fillRect(startX + j, startY + i, 1, 1); + } + } + + } + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java index b8083d1adb..00ad626fa4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java @@ -29,11 +29,14 @@ import com.google.inject.Binder; import com.google.inject.Provides; import javax.inject.Inject; import net.runelite.api.widgets.WidgetInfo; +import static net.runelite.api.widgets.WidgetInfo.WORLD_MAP; import net.runelite.client.config.ConfigManager; import net.runelite.client.events.ConfigChanged; +import net.runelite.client.events.GameStateChanged; +import net.runelite.client.events.MapRegionChanged; import net.runelite.client.events.WidgetMenuOptionClicked; -import net.runelite.client.menus.WidgetMenuOption; import net.runelite.client.menus.MenuManager; +import net.runelite.client.menus.WidgetMenuOption; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.Overlay; @@ -44,6 +47,8 @@ import net.runelite.client.ui.overlay.Overlay; public class IntanceMapPlugin extends Plugin { private final WidgetMenuOption openMapOption = new WidgetMenuOption("Show", "Instance Map", WidgetInfo.WORLD_MAP); + private final WidgetMenuOption ascendOption = new WidgetMenuOption("Ascend", "Instance Map", WidgetInfo.WORLD_MAP); + private final WidgetMenuOption descendOption = new WidgetMenuOption("Descend", "Instance Map", WidgetInfo.WORLD_MAP); @Inject InstanceMapConfig config; @@ -66,41 +71,77 @@ public class IntanceMapPlugin extends Plugin return configManager.getConfig(InstanceMapConfig.class); } + private void addCustomOptions() + { + menuManager.addManagedCustomMenu(openMapOption); + menuManager.addManagedCustomMenu(descendOption); + menuManager.addManagedCustomMenu(ascendOption); + } + + private void removeCustomOptions() + { + menuManager.removeManagedCustomMenu(openMapOption); + menuManager.removeManagedCustomMenu(descendOption); + menuManager.removeManagedCustomMenu(ascendOption); + } + @Override protected void startUp() throws Exception { if (config.enabled()) { - menuManager.addManagedCustomMenu(openMapOption); + addCustomOptions(); } } + @Override + protected void shutDown() throws Exception + { + removeCustomOptions(); + } + @Subscribe public void onConfigChanged(ConfigChanged event) { if (config.enabled()) { - menuManager.addManagedCustomMenu(openMapOption); + addCustomOptions(); } else { - menuManager.removeManagedCustomMenu(openMapOption); + removeCustomOptions(); } } + @Subscribe + public void regionChange(MapRegionChanged event) + { + overlay.onRegionChange(event); + } + + @Subscribe + public void gameStateChange(GameStateChanged event) + { + overlay.onGameStateChange(event); + } + + private boolean clickedOptionEquals(WidgetMenuOptionClicked event, WidgetMenuOption widgetMenuOption) + { + return event.getMenuOption().equals(widgetMenuOption.getMenuOption()) && event.getMenuTarget().equals(widgetMenuOption.getMenuTarget()); + } + @Subscribe public void onWidgetMenuOptionClicked(WidgetMenuOptionClicked event) { - if (!config.enabled()) + if (!config.enabled() || event.getWidget() != WORLD_MAP) { return; } - if (event.getMenuOption().equals(openMapOption.getMenuOption()) - && event.getMenuTarget().equals(openMapOption.getMenuTarget()) - && event.getWidget() == WidgetInfo.WORLD_MAP) + if (clickedOptionEquals(event, openMapOption)) { overlay.setShowMap(!overlay.isMapShown()); + if (overlay.isMapShown()) { openMapOption.setMenuOption("Hide"); @@ -110,6 +151,14 @@ public class IntanceMapPlugin extends Plugin openMapOption.setMenuOption("Show"); } } + else if (clickedOptionEquals(event, ascendOption)) + { + overlay.onAscend(); + } + else if (clickedOptionEquals(event, descendOption)) + { + overlay.onDescend(); + } } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/PixelMaps.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/PixelMaps.java new file mode 100644 index 0000000000..052436bf23 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/PixelMaps.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2017, Adam + * 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.instancemap; + +class PixelMaps +{ + static final int[][] ALL = new int[][] + { + { + 1, 1, 1, 1 + }, + { + 1, 1, 1, 1 + }, + { + 1, 1, 1, 1 + }, + { + 1, 1, 1, 1 + } + }; + + //Diagonal / + static final int[][] BOTTOM_LEFT_TO_TOP_RIGHT = new int[][] + { + { + 0, 0, 0, 1 + }, + { + 0, 0, 1, 0 + }, + { + 0, 1, 0, 0 + }, + { + 1, 0, 0, 0 + } + }; + + //Diagonal \ + static final int[][] TOP_RIGHT_TO_BOTTOM_LEFT = new int[][] + { + { + 1, 0, 0, 0 + }, + { + 0, 1, 0, 0 + }, + { + 0, 0, 1, 0 + }, + { + 0, 0, 0, 1 + } + }; + + //Left + static final int[][] LEFT = new int[][] + { + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + } + }; + + static final int[][] TOP = new int[][] + { + { + 1, 1, 1, 1 + }, + { + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0 + } + }; + + static final int[][] RIGHT = new int[][] + { + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + } + }; + + static final int BOTTOM[][] = new int[][] + { + { + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0 + }, + { + 1, 1, 1, 1 + } + }; + + static final int[][] TOP_LEFT_CORNER = new int[][] + { + { + 1, 1, 1, 1 + }, + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + } + }; + + static final int[][] TOP_RIGHT_CORNER = new int[][] + { + { + 1, 1, 1, 1 + }, + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + } + }; + + static final int[][] BOTTOM_RIGHT_CORNER = new int[][] + { + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1 + }, + { + 1, 1, 1, 1 + } + }; + + static final int[][] BOTTOM_LEFT_CORNER = new int[][] + { + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + }, + { + 1, 0, 0, 0 + }, + { + 1, 1, 1, 1 + } + }; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallOffset.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallOffset.java new file mode 100644 index 0000000000..8d4f868c2d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallOffset.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, Adam + * 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.instancemap; + +import static net.runelite.client.plugins.instancemap.InstanceMapOverlay.TILE_SIZE; + +enum WallOffset +{ + TOP_LEFT(-TILE_SIZE / 2, -TILE_SIZE / 2), + TOP_RIGHT(TILE_SIZE / 2, -TILE_SIZE / 2), + BOTTOM_LEFT(-TILE_SIZE / 2, TILE_SIZE / 2), + BOTTOM_RIGHT(TILE_SIZE / 2, TILE_SIZE / 2), + RIGHT(TILE_SIZE / 2, 0), + LEFT(-TILE_SIZE / 2, 0), + NONE(0, 0); + + public final int xOffset; + public final int yOffset; + + WallOffset(int xOffset, int yOffset) + { + this.xOffset = xOffset; + this.yOffset = yOffset; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallShape.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallShape.java new file mode 100644 index 0000000000..ac2702effe --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/WallShape.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017, Adam + * 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.instancemap; + +/** + * Used to represent the wall as a 4x4 set of pixels with an offset + */ +class WallShape +{ + private final int[][] pixels; + private final WallOffset offset; + + public WallShape(int[][] pixels, WallOffset offset) + { + this.pixels = pixels; + this.offset = offset; + } + + public int[][] getPixels() + { + return pixels; + } + + public WallOffset getOffset() + { + return offset; + } + +} diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSActorMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSActorMixin.java index 361f91ff19..698476fc48 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSActorMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSActorMixin.java @@ -30,6 +30,7 @@ import java.awt.image.BufferedImage; import net.runelite.api.Actor; import net.runelite.api.NPC; import net.runelite.api.Perspective; +import static net.runelite.api.Perspective.LOCAL_COORD_BITS; import net.runelite.api.Player; import net.runelite.api.Point; import net.runelite.api.SpritePixels; @@ -124,6 +125,13 @@ public abstract class RSActorMixin implements RSActor return Perspective.localToWorld(client, localLocation); } + @Inject + @Override + public Point getRegionLocation() + { + return new Point(getX() >>> LOCAL_COORD_BITS, getY() >>> LOCAL_COORD_BITS);// divided by 128 + } + @Inject @Override public Point getLocalLocation() diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSTileMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSTileMixin.java new file mode 100644 index 0000000000..68d8e88990 --- /dev/null +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSTileMixin.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016-2017, Adam + * 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.mixins; + +import static net.runelite.api.Perspective.LOCAL_COORD_BITS; +import net.runelite.api.Point; +import net.runelite.api.mixins.Inject; +import net.runelite.api.mixins.Mixin; +import net.runelite.rs.api.RSTile; + +@Mixin(RSTile.class) +public abstract class RSTileMixin implements RSTile +{ + @Inject + @Override + public Point getWorldLocation() + { + return new Point(getLocalLocation().getX() << LOCAL_COORD_BITS, getLocalLocation().getX() << LOCAL_COORD_BITS); + } + + @Inject + @Override + public Point getLocalLocation() + { + return new Point(getX(), getY()); + } +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSRegion.java b/runescape-api/src/main/java/net/runelite/rs/api/RSRegion.java index a217075d8b..41b417ba79 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSRegion.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSRegion.java @@ -36,4 +36,13 @@ public interface RSRegion extends Region @Import("tiles") @Override Tile[][][] getTiles(); + + @Import("TILE_MASK_2D") + @Override + int[][] getTileMask2d(); + + @Import("TILE_ROTATION_2D") + @Override + int[][] getTileRotation2d(); + } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSSceneTileModel.java b/runescape-api/src/main/java/net/runelite/rs/api/RSSceneTileModel.java new file mode 100644 index 0000000000..dcec5d5f5c --- /dev/null +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSSceneTileModel.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016-2017, Adam + * 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.rs.api; + +import net.runelite.api.SceneTileModel; +import net.runelite.mapping.Import; + +public interface RSSceneTileModel extends SceneTileModel +{ + @Import("underlay") + @Override + int getModelUnderlay(); + + @Import("overlay") + @Override + int getModelOverlay(); + + @Import("shape") + @Override + int getShape(); + + @Import("rotation") + @Override + int getRotation(); +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java b/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java index a4c58722f2..2491175148 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java @@ -28,6 +28,7 @@ import net.runelite.api.DecorativeObject; import net.runelite.api.GameObject; import net.runelite.api.GroundObject; import net.runelite.api.ItemLayer; +import net.runelite.api.SceneTileModel; import net.runelite.api.SceneTilePaint; import net.runelite.api.Tile; import net.runelite.api.WallObject; @@ -59,6 +60,10 @@ public interface RSTile extends Tile @Override SceneTilePaint getSceneTilePaint(); + @Import("overlay") + @Override + SceneTileModel getSceneTileModel(); + @Import("x") int getX(); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWallObject.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWallObject.java index 2880895b09..9c7cd76eff 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWallObject.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWallObject.java @@ -40,4 +40,12 @@ public interface RSWallObject extends WallObject @Import("y") @Override int getY(); + + @Import("orientationA") + @Override + int getOrientationA(); + + @Import("orientationB") + @Override + int getOrientationB(); }