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