diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 69e654b618..3a5779a05e 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -381,4 +381,6 @@ public interface Client extends GameEngine boolean isInterpolateObjectAnimations(); void setInterpolateObjectAnimations(boolean interpolate); + + boolean isInInstancedRegion(); } diff --git a/runelite-api/src/main/java/net/runelite/api/coords/LocalPoint.java b/runelite-api/src/main/java/net/runelite/api/coords/LocalPoint.java index 147dda469d..2765572c14 100644 --- a/runelite-api/src/main/java/net/runelite/api/coords/LocalPoint.java +++ b/runelite-api/src/main/java/net/runelite/api/coords/LocalPoint.java @@ -95,7 +95,7 @@ public class LocalPoint } /** - * Returns the X coordinate in Region space (tiles) + * Returns the X coordinate in Scene space (tiles) */ public int getRegionX() { @@ -104,7 +104,7 @@ public class LocalPoint /** - * Returns the Y coordinate in Region space (tiles) + * Returns the Y coordinate in Scene space (tiles) */ public int getRegionY() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java new file mode 100644 index 0000000000..468dc20372 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerConfig.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, 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.groundmarkers; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +import java.awt.Color; + +@ConfigGroup( + keyName = "groundMarker", + name = "Ground Marker", + description = "Mark ground tiles" +) +public interface GroundMarkerConfig extends Config +{ + @ConfigItem( + keyName = "markerColor", + name = "Color of the tile", + description = "Configures the color of marked tile" + ) + default Color markerColor() + { + return Color.YELLOW; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java new file mode 100644 index 0000000000..7f800bfdb5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerInputListener.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, 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.groundmarkers; + +import java.awt.event.KeyEvent; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.client.input.KeyListener; + +public class GroundMarkerInputListener implements KeyListener +{ + private static final int HOTKEY = KeyEvent.VK_SHIFT; + + private final Client client; + private final GroundMarkerPlugin plugin; + + @Inject + private GroundMarkerInputListener(Client client, GroundMarkerPlugin plugin) + { + this.client = client; + this.plugin = plugin; + } + + @Override + public void keyTyped(KeyEvent e) + { + + } + + @Override + public void keyPressed(KeyEvent e) + { + if (e.getKeyCode() == HOTKEY) + { + plugin.setHotKeyPressed(true); + } + } + + @Override + public void keyReleased(KeyEvent e) + { + if (e.getKeyCode() == HOTKEY) + { + plugin.setHotKeyPressed(false); + } + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java new file mode 100644 index 0000000000..f06ae2b145 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerOverlay.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, 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.groundmarkers; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.util.List; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +public class GroundMarkerOverlay extends Overlay +{ + private final Client client; + private final GroundMarkerConfig config; + private final GroundMarkerPlugin plugin; + + @Inject + private GroundMarkerOverlay(Client client, GroundMarkerConfig config, GroundMarkerPlugin plugin) + { + this.client = client; + this.config = config; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + setLayer(OverlayLayer.UNDER_WIDGETS); + } + + @Override + public Dimension render(Graphics2D graphics) + { + List points = plugin.getPoints(); + for (WorldPoint point : points) + { + if (point.getPlane() != client.getPlane()) + { + continue; + } + + drawTile(graphics, point); + } + + return null; + } + + private void drawTile(Graphics2D graphics, WorldPoint point) + { + WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); + + if (point.distanceTo(playerLocation) >= 32) + { + return; + } + + Polygon poly = Perspective.getCanvasTilePoly(client, LocalPoint.fromWorld(client, point)); + + if (poly == null) + { + return; + } + + OverlayUtil.renderPolygon(graphics, poly, config.markerColor()); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java new file mode 100644 index 0000000000..801fcc3046 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, 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.groundmarkers; + +import com.google.common.base.Strings; +import com.google.common.eventbus.Subscribe; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.inject.Provides; +import java.awt.Polygon; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import static net.runelite.api.Constants.CHUNK_SIZE; +import static net.runelite.api.Constants.REGION_SIZE; +import net.runelite.api.GameState; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.Region; +import net.runelite.api.Tile; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; + +@Slf4j +@PluginDescriptor( + name = "Ground Markers" +) +public class GroundMarkerPlugin extends Plugin +{ + private static final String CONFIG_GROUP = "groundMarker"; + private static final String MARK = "Mark tile"; + private static final String WALK_HERE = "Walk here"; + + private static final Gson gson = new Gson(); + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean hotKeyPressed; + + @Getter(AccessLevel.PACKAGE) + private final List points = new ArrayList<>(); + + @Inject + private Client client; + + @Inject + private GroundMarkerInputListener inputListener; + + @Inject + private ConfigManager configManager; + + @Inject + private GroundMarkerOverlay overlay; + + @Inject + private KeyManager keyManager; + + private void savePoints(int regionId, Collection points) + { + if (points == null || points.isEmpty()) + { + configManager.unsetConfiguration(CONFIG_GROUP, "region_" + regionId); + return; + } + + String json = gson.toJson(points); + configManager.setConfiguration(CONFIG_GROUP, "region_" + regionId, json); + } + + private Collection getPoints(int regionId) + { + String json = configManager.getConfiguration(CONFIG_GROUP, "region_" + regionId); + if (Strings.isNullOrEmpty(json)) + { + return Collections.EMPTY_LIST; + } + return gson.fromJson(json, new TypeToken>() + { + }.getType()); + } + + @Provides + GroundMarkerConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(GroundMarkerConfig.class); + } + + private void loadPoints() + { + points.clear(); + + int[] regions = client.getMapRegions(); + for (int regionId : regions) + { + // load points for region + log.debug("Loading points for region {}", regionId); + Collection regionPoints = getPoints(regionId); + Collection worldPoints = translateToWorld(regionPoints); + points.addAll(worldPoints); + } + } + + /** + * Translate a collection of ground marker points to world points, accounting for instances + * + * @param points + * @return + */ + private Collection translateToWorld(Collection points) + { + if (points.isEmpty()) + { + return Collections.EMPTY_LIST; + } + + List worldPoints = new ArrayList<>(); + for (GroundMarkerPoint point : points) + { + int regionId = point.getRegionId(); + int regionX = point.getRegionX(); + int regionY = point.getRegionY(); + int z = point.getZ(); + + // world point of the tile marker + WorldPoint worldPoint = new WorldPoint( + ((regionId >>> 8) << 6) + regionX, + ((regionId & 0xff) << 6) + regionY, + z + ); + + if (!client.isInInstancedRegion()) + { + worldPoints.add(worldPoint); + continue; + } + + // find instance chunks using the template point. there might be more than one. + int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks(); + for (int x = 0; x < instanceTemplateChunks[z].length; ++x) + { + for (int y = 0; y < instanceTemplateChunks[z][x].length; ++y) + { + int chunkData = instanceTemplateChunks[z][x][y]; + int rotation = chunkData >> 1 & 0x3; + int templateChunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE; + int templateChunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE; + if (worldPoint.getX() >= templateChunkX && worldPoint.getX() < templateChunkX + CHUNK_SIZE + && worldPoint.getY() >= templateChunkY && worldPoint.getY() < templateChunkY + CHUNK_SIZE) + { + WorldPoint p = new WorldPoint(client.getBaseX() + x * CHUNK_SIZE + (worldPoint.getX() & (CHUNK_SIZE - 1)), + client.getBaseY() + y * CHUNK_SIZE + (worldPoint.getY() & (CHUNK_SIZE - 1)), + worldPoint.getPlane()); + p = rotateChunk(p, rotation); + worldPoints.add(p); + } + } + } + } + return worldPoints; + } + + /** + * Rotate the coordinates in the chunk according to chunk rotation + * + * @param point + * @param rotation + * @return + */ + private static WorldPoint rotateChunk(WorldPoint point, int rotation) + { + int chunkX = point.getX() & ~(CHUNK_SIZE - 1); + int chunkY = point.getY() & ~(CHUNK_SIZE - 1); + int x = point.getX() & (CHUNK_SIZE - 1); + int y = point.getY() & (CHUNK_SIZE - 1); + switch (rotation) + { + case 1: + return new WorldPoint(chunkX + y, chunkY + (CHUNK_SIZE - 1 - x), point.getPlane()); + case 2: + return new WorldPoint(chunkX + (CHUNK_SIZE - 1 - x), chunkY + (CHUNK_SIZE - 1 - y), point.getPlane()); + case 3: + return new WorldPoint(chunkX + (CHUNK_SIZE - 1 - y), chunkY + x, point.getPlane()); + } + return point; + } + + @Subscribe + public void onGameStateChange(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() != GameState.LOGGED_IN) + { + return; + } + + // map region has just been updated + loadPoints(); + } + + @Subscribe + public void onFocusChanged(FocusChanged focusChanged) + { + if (!focusChanged.isFocused()) + { + hotKeyPressed = false; + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (hotKeyPressed && event.getOption().equals(WALK_HERE)) + { + MenuEntry[] menuEntries = client.getMenuEntries(); + menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); + + MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); + + menuEntry.setOption(MARK); + menuEntry.setTarget(event.getTarget()); + menuEntry.setType(MenuAction.CANCEL.getId()); + + client.setMenuEntries(menuEntries); + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + if (!event.getMenuOption().equals(MARK)) + { + return; + } + + MenuEntry[] menuEntries = client.getMenuEntries(); + + // get tile coordinates off of walk here entry + for (int i = 0; i < menuEntries.length; i++) + { + MenuEntry menuEntry = menuEntries[i]; + if (menuEntry.getOption().equals(WALK_HERE)) + { + Point target = new Point(menuEntry.getParam0(), menuEntry.getParam1()); + markTile(target); + break; + } + } + } + + @Override + protected void startUp() + { + keyManager.registerKeyListener(inputListener); + } + + @Override + protected void shutDown() + { + keyManager.unregisterKeyListener(inputListener); + } + + @Override + public GroundMarkerOverlay getOverlay() + { + return overlay; + } + + protected void markTile(Point ptMouse) + { + LocalPoint localPoint = getTile(ptMouse); + + if (localPoint == null) + { + return; + } + + WorldPoint worldPoint; + + if (client.isInInstancedRegion()) + { + // get position in the scene + int sceneX = localPoint.getRegionX(); + int sceneY = localPoint.getRegionY(); + + // get chunk from scene + int chunkX = sceneX / CHUNK_SIZE; + int chunkY = sceneY / CHUNK_SIZE; + + // get the template chunk for the chunk + int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks(); + int templateChunk = instanceTemplateChunks[client.getPlane()][chunkX][chunkY]; + + int rotation = templateChunk >> 1 & 0x3; + int templateChunkY = (templateChunk >> 3 & 0x7FF) * CHUNK_SIZE; + int templateChunkX = (templateChunk >> 14 & 0x3FF) * CHUNK_SIZE; + int plane = templateChunk >> 24 & 0x3; + + // calculate world point of the template + int x = templateChunkX + (sceneX & (CHUNK_SIZE - 1)); + int y = templateChunkY + (sceneY & (CHUNK_SIZE - 1)); + + worldPoint = new WorldPoint(x, y, plane); + // rotate point back to 0, to match with template + worldPoint = rotate(worldPoint, rotation); + } + else + { + worldPoint = WorldPoint.fromLocal(client, localPoint); + } + + int regionX = worldPoint.getX() >> 6; + int regionY = worldPoint.getY() >> 6; + int regionId = regionX << 8 | regionY; + GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getX() & 0x3f, worldPoint.getY() & 0x3f, client.getPlane()); + log.debug("Updating point: {} - {}", point, worldPoint); + + List points = new ArrayList<>(getPoints(regionId)); + if (points.contains(point)) + { + points.remove(point); + } + else + { + points.add(point); + } + + savePoints(regionId, points); + + loadPoints(); + } + + /** + * Rotate the chunk containing the given point to rotation 0 + * + * @param point + * @param rotation + * @return + */ + private WorldPoint rotate(WorldPoint point, int rotation) + { + int chunkX = point.getX() & ~(CHUNK_SIZE - 1); + int chunkY = point.getY() & ~(CHUNK_SIZE - 1); + int x = point.getX() & (CHUNK_SIZE - 1); + int y = point.getY() & (CHUNK_SIZE - 1); + switch (rotation) + { + case 1: + return new WorldPoint(chunkX + ((CHUNK_SIZE - 1) - y), chunkY + x, point.getPlane()); + case 2: + return new WorldPoint(chunkX + ((CHUNK_SIZE - 1) - x), chunkY + ((CHUNK_SIZE - 1) - y), point.getPlane()); + case 3: + return new WorldPoint(chunkX + y, chunkY + ((CHUNK_SIZE - 1) - x), point.getPlane()); + } + return point; + } + + /** + * Find the tile which the given mouse point is in + * @param mouse + * @return + */ + private LocalPoint getTile(Point mouse) + { + Region region = client.getRegion(); + Tile[][][] tiles = region.getTiles(); + int z = client.getPlane(); + + java.awt.Point gameMouse = new java.awt.Point(mouse.getX(), mouse.getY()); + + for (int x = 0; x < REGION_SIZE; ++x) + { + for (int y = 0; y < REGION_SIZE; ++y) + { + Tile tile = tiles[z][x][y]; + + if (tile == null) + { + continue; + } + + LocalPoint local = tile.getLocalLocation(); + Polygon poly = Perspective.getCanvasTilePoly(client, local); + + if (poly == null) + { + continue; + } + + if (Perspective.getCanvasTilePoly(client, local).contains(gameMouse)) + { + return local; + } + } + } + + return null; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java new file mode 100644 index 0000000000..b31db32222 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, 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.groundmarkers; + +import lombok.Value; + +@Value +public class GroundMarkerPoint +{ + private int regionId; + private int regionX; + private int regionY; + private int z; +} \ No newline at end of file diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index 98d522d22b..574cae7adc 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -612,4 +612,8 @@ public interface RSClient extends RSGameEngine, Client @Import("hintArrowPlayerTargetIdx") int getHintArrowPlayerTargetIdx(); + + @Import("isDynamicRegion") + @Override + boolean isInInstancedRegion(); }