diff --git a/cache/pom.xml b/cache/pom.xml index f6cf9583a3..c006a177d9 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -101,7 +101,7 @@ 2.16 true - -Xmx1024m + -Xmx2048m diff --git a/cache/src/main/java/net/runelite/cache/MapImageDumper.java b/cache/src/main/java/net/runelite/cache/MapImageDumper.java index c209838dff..7d6cc6ecbb 100644 --- a/cache/src/main/java/net/runelite/cache/MapImageDumper.java +++ b/cache/src/main/java/net/runelite/cache/MapImageDumper.java @@ -29,18 +29,23 @@ */ package net.runelite.cache; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Image; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import net.runelite.cache.definitions.ObjectDefinition; import net.runelite.cache.definitions.OverlayDefinition; import net.runelite.cache.definitions.SpriteDefinition; import net.runelite.cache.definitions.TextureDefinition; import net.runelite.cache.definitions.UnderlayDefinition; +import net.runelite.cache.definitions.loaders.ObjectLoader; import net.runelite.cache.definitions.loaders.OverlayLoader; import net.runelite.cache.definitions.loaders.SpriteLoader; import net.runelite.cache.definitions.loaders.TextureLoader; @@ -50,7 +55,9 @@ import net.runelite.cache.fs.File; import net.runelite.cache.fs.Index; import net.runelite.cache.fs.Store; import net.runelite.cache.io.InputStream; +import net.runelite.cache.region.Location; import net.runelite.cache.region.Region; +import net.runelite.cache.util.XteaKeyManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,14 +66,20 @@ public class MapImageDumper private static final Logger logger = LoggerFactory.getLogger(MapImageDumper.class); private static final int MAX_REGION = 32768; + private static final int MAP_SCENE_SPRITE_ID = 317; // magic sprite id map icons are in + private static final int MAP_SCALE = 2; // this squared is the number of pixels per map square + private static final int MAPICON_MAX_WIDTH = 5; // scale minimap icons down to this size so they fit.. + private static final int MAPICON_MAX_HEIGHT = 6; private final Store store; private final List underlays = new ArrayList<>(); private final List overlays = new ArrayList<>(); private final List textures = new ArrayList<>(); - private final List sprites = new ArrayList<>(); + private final Multimap sprites = HashMultimap.create(); private final Map averageColors = new HashMap<>(); + private final Map scaledMapIcons = new HashMap<>(); + private final Map objects = new HashMap<>(); private final List regions = new ArrayList<>(); private Region lowestX = null, lowestY = null; @@ -80,17 +93,19 @@ public class MapImageDumper this.store = store; } - public BufferedImage[] buildImages() throws IOException + public void load() throws IOException { - BufferedImage[] images = new BufferedImage[Region.Z]; - loadUnderlays(store); loadOverlays(store); loadTextures(store); loadSprites(store); + loadObjects(store); loadRegions(store); + } + public BufferedImage drawMap(int z) throws IOException + { int minX = lowestX.getBaseX(); int minY = lowestY.getBaseY(); @@ -100,12 +115,12 @@ public class MapImageDumper int dimX = maxX - minX; int dimY = maxY - minY; - logger.info("Map image dimensions: {}px x {}px", dimX, dimY); + dimX *= MAP_SCALE; + dimY *= MAP_SCALE; - for (int i = 0; i < images.length; ++i) - { - images[i] = new BufferedImage(dimX, dimY, BufferedImage.TYPE_INT_RGB); - } + logger.info("Map image dimensions: {}px x {}px, {}px per map square ({} MB)", dimX, dimY, MAP_SCALE, (dimX * dimY / 1024 / 1024)); + + BufferedImage image = new BufferedImage(dimX, dimY, BufferedImage.TYPE_INT_RGB); for (Region region : regions) { @@ -119,102 +134,176 @@ public class MapImageDumper // region has the greaters y, so invert int drawBaseY = highestY.getBaseY() - baseY; - for (int z = 0; z < Region.Z; ++z) + Graphics2D graphics = image.createGraphics(); + + for (int x = 0; x < Region.X; ++x) { - BufferedImage image = images[z]; - Graphics2D graphics = image.createGraphics(); + int drawX = drawBaseX + x; - for (int x = 0; x < Region.X; ++x) + for (int y = 0; y < Region.Y; ++y) { - int drawX = drawBaseX + x; + int drawY = drawBaseY + (Region.Y - 1 - y); - for (int y = 0; y < Region.Y; ++y) + int overlayId = region.getOverlayId(z, x, y) - 1; + int underlayId = region.getUnderlayId(z, x, y) - 1; + int rgb = 0; + + if (overlayId > -1) { - int drawY = drawBaseY + (Region.Y - 1 - y); - - int overlayId = region.getOverlayId(z, x, y) - 1; - int underlayId = region.getUnderlayId(z, x, y) - 1; - int rgb = 0; - - if (overlayId > -1) - { - OverlayDefinition overlay = findOverlay(overlayId); - if (!overlay.isHideUnderlay() && underlayId > -1) - { - UnderlayDefinition underlay = findUnderlay(underlayId); - rgb = underlay.getColor(); - } - else - { - rgb = overlay.getRgbColor(); - } - - if (overlay.getSecondaryRgbColor() > -1) - { - rgb = overlay.getSecondaryRgbColor(); - } - - if (overlay.getTexture() > -1) - { - TextureDefinition texture = findTexture(overlay.getTexture()); - assert texture.getFileIds().length == 1; - - SpriteDefinition sprite = findSprite(texture.getFileIds()[0], 0); - assert sprite != null; - - rgb = averageColors.get(sprite); - } - } - else if (underlayId > -1) + OverlayDefinition overlay = findOverlay(overlayId); + if (!overlay.isHideUnderlay() && underlayId > -1) { UnderlayDefinition underlay = findUnderlay(underlayId); rgb = underlay.getColor(); } + else + { + rgb = overlay.getRgbColor(); + } - image.setRGB(drawX, drawY, rgb); + if (overlay.getSecondaryRgbColor() > -1) + { + rgb = overlay.getSecondaryRgbColor(); + } + + if (overlay.getTexture() > -1) + { + TextureDefinition texture = findTexture(overlay.getTexture()); + assert texture.getFileIds().length == 1; + + SpriteDefinition sprite = findSprite(texture.getFileIds()[0], 0); + assert sprite != null; + + rgb = averageColors.get(sprite); + } + } + else if (underlayId > -1) + { + UnderlayDefinition underlay = findUnderlay(underlayId); + rgb = underlay.getColor(); } - } - if (labelRegions) - { - graphics.setColor(Color.WHITE); - graphics.drawString(baseX + "," + baseY, drawBaseX, drawBaseY + graphics.getFontMetrics().getHeight()); + drawMapSquare(image, drawX, drawY, rgb); } - - if (outlineRegions) - { - graphics.setColor(Color.WHITE); - graphics.drawRect(drawBaseX, drawBaseY, Region.X, Region.Y); - } - - graphics.dispose(); } + + drawLocations(graphics, region, z, drawBaseX, drawBaseY); + + if (labelRegions) + { + graphics.setColor(Color.WHITE); + graphics.drawString(baseX + "," + baseY, drawBaseX * MAP_SCALE, drawBaseY * MAP_SCALE + graphics.getFontMetrics().getHeight()); + } + + if (outlineRegions) + { + graphics.setColor(Color.WHITE); + graphics.drawRect(drawBaseX * MAP_SCALE, drawBaseY * MAP_SCALE, Region.X * MAP_SCALE, Region.Y * MAP_SCALE); + } + + graphics.dispose(); } - return images; + return image; + } + + private void drawMapSquare(BufferedImage image, int x, int y, int rgb) + { + x *= MAP_SCALE; + y *= MAP_SCALE; + + for (int i = 0; i < MAP_SCALE; ++i) + { + for (int j = 0; j < MAP_SCALE; ++j) + { + image.setRGB(x + i, y + j, rgb); + } + } + } + + private void drawLocations(Graphics2D graphics, Region region, int z, int drawBaseX, int drawBaseY) + { + for (Location location : region.getLocations()) + { + // regions include locations on all planes, so check + if (location.getPosition().getZ() != z) + { + continue; + } + + ObjectDefinition od = findObject(location.getId()); + + assert od != null; + + int localX = location.getPosition().getX() - region.getBaseX(); + int localY = location.getPosition().getY() - region.getBaseY(); + + int drawX = drawBaseX + localX; + int drawY = drawBaseY + (Region.Y - 1 - localY); + + if (od.getMapSceneID() != -1) + { + SpriteDefinition sprite = findSprite(MAP_SCENE_SPRITE_ID, od.getMapSceneID()); + + assert sprite != null; + + if (sprite.getHeight() <= 0 || sprite.getWidth() <= 0) + { + continue; + } + + Image spriteImage = scaledMapIcons.get(sprite); + graphics.drawImage(spriteImage, drawX * MAP_SCALE, drawY * MAP_SCALE, null); + } + } } private void loadRegions(Store store) throws IOException { Index index = store.getIndex(IndexType.MAPS); + XteaKeyManager keyManager = index.getXteaManager(); for (int i = 0; i < MAX_REGION; ++i) { - Region region = new Region(i); + int x = i >> 8; + int y = i & 0xFF; - Archive map = index.findArchiveByName("m" + (i >> 8) + "_" + (i & 0xFF)); - if (map == null) + Archive map = index.findArchiveByName("m" + x + "_" + y); + Archive land = index.findArchiveByName("l" + x + "_" + y); + + assert (map == null) == (land == null); + + if (map == null || land == null) { continue; } assert map.getFiles().size() == 1; + assert land.getFiles().size() == 1; map.decompressAndLoad(null); byte[] data = map.getFiles().get(0).getContents(); + + Region region = new Region(i); region.loadTerrain(data); + int[] keys = keyManager.getKeys(i); + if (keys != null) + { + try + { + land.decompressAndLoad(keys); + + data = land.getFiles().get(0).getContents(); + region.loadLocations(data); + } + catch (IOException ex) + { + logger.debug("Can't decrypt region " + i, ex); + } + } + regions.add(region); if (lowestX == null || region.getBaseX() < lowestX.getBaseX()) @@ -347,18 +436,34 @@ public class MapImageDumper for (SpriteDefinition sprite : sprites) { - this.sprites.add(sprite); + this.sprites.put(sprite.getId(), sprite); averageColors.put(sprite, getAverageColor(sprite.getPixels())); + + if (sprite.getId() == MAP_SCENE_SPRITE_ID) + { + if (sprite.getHeight() <= 0 || sprite.getWidth() <= 0) + { + continue; + } + + BufferedImage spriteImage = new BufferedImage(sprite.getWidth(), sprite.getHeight(), BufferedImage.TYPE_INT_ARGB); + spriteImage.setRGB(0, 0, sprite.getWidth(), sprite.getHeight(), sprite.getPixels(), 0, sprite.getWidth()); + + // scale image down so it fits + Image scaledImage = spriteImage.getScaledInstance(MAPICON_MAX_WIDTH, MAPICON_MAX_HEIGHT, 0); + + scaledMapIcons.put(sprite, scaledImage); + } } } } private SpriteDefinition findSprite(int id, int frame) { - for (SpriteDefinition def : sprites) + for (SpriteDefinition def : sprites.get(id)) { - if (def.getId() == id && def.getFrame() == frame) + if (def.getFrame() == frame) { return def; } @@ -394,6 +499,25 @@ public class MapImageDumper return color.getRGB(); } + private void loadObjects(Store store) + { + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.OBJECT.getId()); + + ObjectLoader loader = new ObjectLoader(); + + for (File f : archive.getFiles()) + { + ObjectDefinition def = loader.load(f.getFileId(), f.getContents()); + objects.put(def.getId(), def); + } + } + + private ObjectDefinition findObject(int id) + { + return objects.get(id); + } + public boolean isLabelRegions() { return labelRegions; diff --git a/cache/src/main/java/net/runelite/cache/io/InputStream.java b/cache/src/main/java/net/runelite/cache/io/InputStream.java index e964dce6e2..e2e42321ce 100644 --- a/cache/src/main/java/net/runelite/cache/io/InputStream.java +++ b/cache/src/main/java/net/runelite/cache/io/InputStream.java @@ -126,15 +126,7 @@ public class InputStream extends java.io.InputStream public byte peek() { - int position = buffer.position(); - try - { - return buffer.get(); - } - finally - { - buffer.position(position); - } + return buffer.get(buffer.position()); } public int readBigSmart() @@ -144,8 +136,14 @@ public class InputStream extends java.io.InputStream public int readShortSmart() { - int var2 = this.peek() & 0xFF; - return var2 < 128 ? this.readUnsignedByte() - 64 : this.readUnsignedShort() - 0xc000; + int peek = this.peek() & 0xFF; + return peek < 128 ? this.readUnsignedByte() - 64 : this.readUnsignedShort() - 0xc000; + } + + public int readUnsignedShortSmart() + { + int peek = this.peek() & 0xFF; + return peek < 128 ? this.readUnsignedByte() : this.readUnsignedShort() - 0x8000; } public String readString() diff --git a/cache/src/main/java/net/runelite/cache/region/Location.java b/cache/src/main/java/net/runelite/cache/region/Location.java new file mode 100644 index 0000000000..bc1ce8d3ae --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/region/Location.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''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 Adam 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.cache.region; + +import java.util.Objects; + +public class Location +{ + private final int id; + private final int type; + private final int orientation; + private final Position position; + + public Location(int id, int type, int orientation, Position position) + { + this.id = id; + this.type = type; + this.orientation = orientation; + this.position = position; + } + + @Override + public String toString() + { + return "GamwObject{" + "id=" + id + ", type=" + type + ", orientation=" + orientation + ", position=" + position + '}'; + } + + @Override + public int hashCode() + { + int hash = 5; + hash = 83 * hash + this.id; + hash = 83 * hash + this.type; + hash = 83 * hash + this.orientation; + hash = 83 * hash + Objects.hashCode(this.position); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final Location other = (Location) obj; + if (this.id != other.id) + { + return false; + } + if (this.type != other.type) + { + return false; + } + if (this.orientation != other.orientation) + { + return false; + } + if (!Objects.equals(this.position, other.position)) + { + return false; + } + return true; + } + + public int getId() + { + return id; + } + + public int getType() + { + return type; + } + + public int getOrientation() + { + return orientation; + } + + public Position getPosition() + { + return position; + } +} diff --git a/cache/src/main/java/net/runelite/cache/region/Position.java b/cache/src/main/java/net/runelite/cache/region/Position.java new file mode 100644 index 0000000000..656dc10be7 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/region/Position.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam + * 4. Neither the name of the Adam nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam ''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 Adam 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.cache.region; + +public class Position +{ + private final int x; + private final int y; + private final int z; + + public Position(int x, int y, int z) + { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public String toString() + { + return "Position{" + "x=" + x + ", y=" + y + ", z=" + z + '}'; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 67 * hash + this.x; + hash = 67 * hash + this.y; + hash = 67 * hash + this.z; + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final Position other = (Position) obj; + if (this.x != other.x) + { + return false; + } + if (this.y != other.y) + { + return false; + } + if (this.z != other.z) + { + return false; + } + return true; + } + + public int getX() + { + return x; + } + + public int getY() + { + return y; + } + + public int getZ() + { + return z; + } +} diff --git a/cache/src/main/java/net/runelite/cache/region/Region.java b/cache/src/main/java/net/runelite/cache/region/Region.java index e6c2600073..a77b55f84a 100644 --- a/cache/src/main/java/net/runelite/cache/region/Region.java +++ b/cache/src/main/java/net/runelite/cache/region/Region.java @@ -21,6 +21,8 @@ */ package net.runelite.cache.region; +import java.util.ArrayList; +import java.util.List; import net.runelite.cache.io.InputStream; /** @@ -46,6 +48,8 @@ public class Region private final byte[][][] overlayRotations = new byte[Z][X][Y]; private final byte[][][] underlayIds = new byte[Z][X][Y]; + private final List locations = new ArrayList<>(); + public Region(int id) { this.regionID = id; @@ -118,6 +122,37 @@ public class Region } } + public void loadLocations(byte[] b) + { + InputStream buf = new InputStream(b); + + int id = -1; + int idOffset; + + while ((idOffset = buf.readUnsignedShortSmart()) != 0) + { + id += idOffset; + + int position = 0; + int positionOffset; + + while ((positionOffset = buf.readUnsignedShortSmart()) != 0) + { + position += positionOffset - 1; + + int localY = position & 0x3F; + int localX = position >> 6 & 0x3F; + int height = position >> 12 & 0x3; + + int attributes = buf.readUnsignedByte(); + int type = attributes >> 2; + int orientation = attributes & 0x3; + + locations.add(new Location(id, type, orientation, new Position(getBaseX() + localX, getBaseY() + localY, height))); + } + } + } + public int getRegionID() { return regionID; @@ -162,4 +197,9 @@ public class Region { return underlayIds[z][x][y] & 0xFF; } + + public List getLocations() + { + return locations; + } } diff --git a/cache/src/test/java/net/runelite/cache/MapDumperTest.java b/cache/src/test/java/net/runelite/cache/MapDumperTest.java index b6ede35489..fe888856fd 100644 --- a/cache/src/test/java/net/runelite/cache/MapDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/MapDumperTest.java @@ -27,15 +27,19 @@ * (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.cache; import com.google.common.io.Files; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import net.runelite.cache.fs.Archive; import net.runelite.cache.fs.Index; import net.runelite.cache.fs.Store; +import net.runelite.cache.region.Region; import net.runelite.cache.util.XteaKeyManager; import org.junit.Rule; import org.junit.Test; @@ -48,12 +52,15 @@ public class MapDumperTest private static final Logger logger = LoggerFactory.getLogger(MapDumperTest.class); private static final int MAX_REGIONS = 32768; + private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Rule public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); - @Test - public void dump() throws IOException + private final List regions = new ArrayList<>(); + + //@Test + public void dumpRaw() throws IOException { File base = StoreLocation.LOCATION, outDir = folder.newFolder(); @@ -68,17 +75,19 @@ public class MapDumperTest for (int i = 0; i < MAX_REGIONS; i++) { int[] keys = keyManager.getKeys(i); - + int x = i >> 8; int y = i & 0xFF; Archive map = index.findArchiveByName("m" + x + "_" + y); Archive land = index.findArchiveByName("l" + x + "_" + y); - + assert (map == null) == (land == null); if (map == null || land == null) + { continue; + } assert map.getFiles().size() == 1; assert land.getFiles().size() == 1; @@ -99,10 +108,12 @@ public class MapDumperTest } catch (IOException ex) { - logger.warn("Unable to decompress and load land " + x + "/" + y + " (bad keys?)", ex); + logger.info("Unable to decompress and load land " + x + "," + y + " (bad keys?)", ex); continue; } + logger.info("Decrypted region {} coords {},{}", i, x, y); + data = land.getFiles().get(0).getContents(); Files.write(data, new File(outDir, "l" + x + "_" + y + ".dat")); @@ -111,4 +122,79 @@ public class MapDumperTest } } + private void loadRegions(Store store) throws IOException + { + Index index = store.getIndex(IndexType.MAPS); + XteaKeyManager keyManager = index.getXteaManager(); + + for (int i = 0; i < MAX_REGIONS; ++i) + { + int x = i >> 8; + int y = i & 0xFF; + + Archive map = index.findArchiveByName("m" + x + "_" + y); + Archive land = index.findArchiveByName("l" + x + "_" + y); + + assert (map == null) == (land == null); + + if (map == null || land == null) + { + continue; + } + + assert map.getFiles().size() == 1; + assert land.getFiles().size() == 1; + + map.decompressAndLoad(null); + + byte[] data = map.getFiles().get(0).getContents(); + + Region region = new Region(i); + region.loadTerrain(data); + + int[] keys = keyManager.getKeys(i); + if (keys != null) + { + try + { + land.decompressAndLoad(keys); + } + catch (IOException ex) + { + continue; + } + + data = land.getFiles().get(0).getContents(); + region.loadLocations(data); + } + + regions.add(region); + } + } + + @Test + public void dunpJson() throws IOException + { + File base = StoreLocation.LOCATION, + outDir = folder.newFolder(); + + try (Store store = new Store(base)) + { + store.load(); + + loadRegions(store); + + for (Region region : regions) + { + if (region.getLocations().isEmpty()) + { + continue; + } + + Files.write(gson.toJson(region).getBytes(), new File(outDir, region.getBaseX() + "_" + region.getBaseY() + ".json")); + } + } + + logger.info("Dumped regions to {}", outDir); + } } diff --git a/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java b/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java index 09ad7a727e..6d41218fdd 100644 --- a/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java @@ -34,6 +34,7 @@ import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import net.runelite.cache.fs.Store; +import net.runelite.cache.region.Region; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -51,25 +52,24 @@ public class MapImageDumperTest public void extract() throws IOException { File base = StoreLocation.LOCATION, - outFile = folder.newFolder(); - - BufferedImage[] images; + outDir = folder.newFolder(); try (Store store = new Store(base)) { store.load(); MapImageDumper dumper = new MapImageDumper(store); - images = dumper.buildImages(); - } + dumper.load(); - int i = 0; - for (BufferedImage image : images) - { - File imageFile = new File(outFile, "img-" + i++ + ".png"); + for (int i = 0; i < Region.Z; ++i) + { + BufferedImage image = dumper.drawMap(i); - ImageIO.write(image, "png", imageFile); - logger.info("Wrote image {}", imageFile); + File imageFile = new File(outDir, "img-" + i + ".png"); + + ImageIO.write(image, "png", imageFile); + logger.info("Wrote image {}", imageFile); + } } } } diff --git a/cache/src/test/java/net/runelite/cache/StoreLocation.java b/cache/src/test/java/net/runelite/cache/StoreLocation.java index caf9bf2832..396f73d9c5 100644 --- a/cache/src/test/java/net/runelite/cache/StoreLocation.java +++ b/cache/src/test/java/net/runelite/cache/StoreLocation.java @@ -40,7 +40,10 @@ public class StoreLocation { private static final Logger logger = LoggerFactory.getLogger(StoreLocation.class); + private static final String TMP_DIR = "d:/temp"; + public static File LOCATION; + private static File TMP; static { @@ -53,13 +56,25 @@ public class StoreLocation logger.error(null, ex); } - File tmp = new File("d:/temp"); + File tmp = new File(TMP_DIR); if (tmp.exists() || tmp.mkdir()) - System.setProperty("java.io.tmpdir", "d:/temp"); + { + System.setProperty("java.io.tmpdir", TMP_DIR); + TMP = tmp; + } } public static TemporaryFolder getTemporaryFolder() { - return new TemporaryFolder(); + return new TemporaryFolder() + { + @Override + public void after() + { + // don't cleanup if using local tmpdir + if (TMP == null) + super.after(); + } + }; } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4ee9b59a45..b24a405252 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,7 @@ maven-surefire-plugin 2.19 + true -Xmx512m