From 6e6c59dc5b9468fc654c45d80e90bee0c67b8c32 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 20 Aug 2016 15:47:58 -0400 Subject: [PATCH] Add map image dumper, mostly from @im-frizzy, but with some improvements --- .../net/runelite/cache/MapImageDumper.java | 416 ++++++++++++++++++ .../cache/definitions/OverlayDefinition.java | 90 ++++ .../cache/definitions/SpriteDefinition.java | 60 ++- .../cache/definitions/TextureDefinition.java | 57 +++ .../cache/definitions/UnderlayDefinition.java | 56 +++ .../definitions/loaders/OverlayLoader.java | 79 ++++ .../definitions/loaders/SpriteLoader.java | 4 +- .../definitions/loaders/TextureLoader.java | 59 +++ .../definitions/loaders/UnderlayLoader.java | 65 +++ .../net/runelite/cache/region/HeightCalc.java | 102 +++++ .../net/runelite/cache/region/Region.java | 165 +++++++ .../runelite/cache/MapImageDumperTest.java | 75 ++++ .../net/runelite/cache/SpriteDumperTest.java | 7 +- .../net/runelite/cache/TextureDumper.java | 85 ++++ .../java/net/runelite/cache/TitleDumper.java | 2 - .../net/runelite/cache/UnderlayDumper.java | 85 ++++ 16 files changed, 1397 insertions(+), 10 deletions(-) create mode 100644 cache/src/main/java/net/runelite/cache/MapImageDumper.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/TextureDefinition.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/loaders/OverlayLoader.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/loaders/TextureLoader.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/loaders/UnderlayLoader.java create mode 100644 cache/src/main/java/net/runelite/cache/region/HeightCalc.java create mode 100644 cache/src/main/java/net/runelite/cache/region/Region.java create mode 100644 cache/src/test/java/net/runelite/cache/MapImageDumperTest.java create mode 100644 cache/src/test/java/net/runelite/cache/TextureDumper.java create mode 100644 cache/src/test/java/net/runelite/cache/UnderlayDumper.java diff --git a/cache/src/main/java/net/runelite/cache/MapImageDumper.java b/cache/src/main/java/net/runelite/cache/MapImageDumper.java new file mode 100644 index 0000000000..c209838dff --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/MapImageDumper.java @@ -0,0 +1,416 @@ +/* + * 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; + +import java.awt.Color; +import java.awt.Graphics2D; +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.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.OverlayLoader; +import net.runelite.cache.definitions.loaders.SpriteLoader; +import net.runelite.cache.definitions.loaders.TextureLoader; +import net.runelite.cache.definitions.loaders.UnderlayLoader; +import net.runelite.cache.fs.Archive; +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.Region; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MapImageDumper +{ + private static final Logger logger = LoggerFactory.getLogger(MapImageDumper.class); + + private static final int MAX_REGION = 32768; + + 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 Map averageColors = new HashMap<>(); + + private final List regions = new ArrayList<>(); + private Region lowestX = null, lowestY = null; + private Region highestX = null, highestY = null; + + private boolean labelRegions; + private boolean outlineRegions; + + public MapImageDumper(Store store) + { + this.store = store; + } + + public BufferedImage[] buildImages() throws IOException + { + BufferedImage[] images = new BufferedImage[Region.Z]; + + loadUnderlays(store); + loadOverlays(store); + loadTextures(store); + loadSprites(store); + + loadRegions(store); + + int minX = lowestX.getBaseX(); + int minY = lowestY.getBaseY(); + + int maxX = highestX.getBaseX() + Region.X; + int maxY = highestY.getBaseY() + Region.Y; + + int dimX = maxX - minX; + int dimY = maxY - minY; + + logger.info("Map image dimensions: {}px x {}px", dimX, dimY); + + for (int i = 0; i < images.length; ++i) + { + images[i] = new BufferedImage(dimX, dimY, BufferedImage.TYPE_INT_RGB); + } + + for (Region region : regions) + { + int baseX = region.getBaseX(); + int baseY = region.getBaseY(); + + // to pixel X + int drawBaseX = baseX - lowestX.getBaseX(); + + // to pixel Y. top most y is 0, but the top most + // region has the greaters y, so invert + int drawBaseY = highestY.getBaseY() - baseY; + + for (int z = 0; z < Region.Z; ++z) + { + BufferedImage image = images[z]; + Graphics2D graphics = image.createGraphics(); + + for (int x = 0; x < Region.X; ++x) + { + int drawX = drawBaseX + x; + + for (int y = 0; y < Region.Y; ++y) + { + 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) + { + UnderlayDefinition underlay = findUnderlay(underlayId); + rgb = underlay.getColor(); + } + + image.setRGB(drawX, drawY, rgb); + } + } + + if (labelRegions) + { + graphics.setColor(Color.WHITE); + graphics.drawString(baseX + "," + baseY, drawBaseX, drawBaseY + graphics.getFontMetrics().getHeight()); + } + + if (outlineRegions) + { + graphics.setColor(Color.WHITE); + graphics.drawRect(drawBaseX, drawBaseY, Region.X, Region.Y); + } + + graphics.dispose(); + } + } + + return images; + } + + private void loadRegions(Store store) throws IOException + { + Index index = store.getIndex(IndexType.MAPS); + + for (int i = 0; i < MAX_REGION; ++i) + { + Region region = new Region(i); + + Archive map = index.findArchiveByName("m" + (i >> 8) + "_" + (i & 0xFF)); + if (map == null) + { + continue; + } + + assert map.getFiles().size() == 1; + + map.decompressAndLoad(null); + + byte[] data = map.getFiles().get(0).getContents(); + region.loadTerrain(data); + + regions.add(region); + + if (lowestX == null || region.getBaseX() < lowestX.getBaseX()) + { + lowestX = region; + } + + if (highestX == null || region.getBaseX() > highestX.getBaseX()) + { + highestX = region; + } + + if (lowestY == null || region.getBaseY() < lowestY.getBaseY()) + { + lowestY = region; + } + + if (highestY == null || region.getBaseY() > highestY.getBaseY()) + { + highestY = region; + } + } + + assert lowestX != null; + assert lowestY != null; + + assert highestX != null; + assert highestY != null; + + logger.info("North most region: {}", lowestY.getBaseY()); + logger.info("South most region: {}", highestY.getBaseY()); + logger.info("West most region: {}", lowestX.getBaseX()); + logger.info("East most region: {}", highestX.getBaseX()); + } + + private void loadUnderlays(Store store) + { + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.UNDERLAY.getId()); + + for (File file : archive.getFiles()) + { + UnderlayLoader loader = new UnderlayLoader(); + UnderlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); + + underlays.add(underlay); + } + } + + private UnderlayDefinition findUnderlay(int id) + { + for (UnderlayDefinition u : underlays) + { + if (u.getId() == id) + { + return u; + } + } + return null; + } + + private void loadOverlays(Store store) + { + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.OVERLAY.getId()); + + for (File file : archive.getFiles()) + { + OverlayLoader loader = new OverlayLoader(); + OverlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); + + overlays.add(underlay); + } + } + + private OverlayDefinition findOverlay(int id) + { + for (OverlayDefinition u : overlays) + { + if (u.getId() == id) + { + return u; + } + } + return null; + } + + private void loadTextures(Store store) + { + Index index = store.getIndex(IndexType.TEXTURES); + Archive archive = index.getArchive(0); + + for (File file : archive.getFiles()) + { + TextureLoader loader = new TextureLoader(); + TextureDefinition texture = loader.load(file.getFileId(), file.getContents()); + + textures.add(texture); + } + } + + private TextureDefinition findTexture(int id) + { + for (TextureDefinition t : textures) + { + if (t.getId() == id) + { + return t; + } + } + + return null; + } + + private void loadSprites(Store store) + { + Index index = store.getIndex(IndexType.SPRITES); + + for (Archive a : index.getArchives()) + { + List files = a.getFiles(); + + assert files.size() == 1; + + File file = files.get(0); + byte[] contents = file.getContents(); + + SpriteLoader loader = new SpriteLoader(); + SpriteDefinition[] sprites = loader.load(a.getArchiveId(), new InputStream(contents)); + + for (SpriteDefinition sprite : sprites) + { + this.sprites.add(sprite); + + averageColors.put(sprite, getAverageColor(sprite.getPixels())); + } + } + } + + private SpriteDefinition findSprite(int id, int frame) + { + for (SpriteDefinition def : sprites) + { + if (def.getId() == id && def.getFrame() == frame) + { + return def; + } + } + return null; + } + + private int getAverageColor(int[] pixels) + { + int redTotal = 0; + int greenTotal = 0; + int blueTotal = 0; + + if (pixels.length == 0) + { + return 0; + } + + for (int pixel : pixels) + { + Color color = new Color(pixel); + + redTotal += color.getRed(); + greenTotal += color.getGreen(); + blueTotal += color.getBlue(); + } + + int averageRed = redTotal / pixels.length; + int averageGreen = greenTotal / pixels.length; + int averageBlue = blueTotal / pixels.length; + + Color color = new Color(averageRed, averageGreen, averageBlue); + return color.getRGB(); + } + + public boolean isLabelRegions() + { + return labelRegions; + } + + public void setLabelRegions(boolean labelRegions) + { + this.labelRegions = labelRegions; + } + + public boolean isOutlineRegions() + { + return outlineRegions; + } + + public void setOutlineRegions(boolean outlineRegions) + { + this.outlineRegions = outlineRegions; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java new file mode 100644 index 0000000000..f00c6c3aed --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java @@ -0,0 +1,90 @@ +/* + * 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.definitions; + +public class OverlayDefinition +{ + private int id; + private int rgbColor = 0; + private int texture = -1; + private int secondaryRgbColor = -1; + private boolean hideUnderlay = true; + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public int getRgbColor() + { + return rgbColor; + } + + public void setRgbColor(int rgbColor) + { + this.rgbColor = rgbColor; + } + + public int getTexture() + { + return texture; + } + + public void setTexture(int texture) + { + this.texture = texture; + } + + public int getSecondaryRgbColor() + { + return secondaryRgbColor; + } + + public void setSecondaryRgbColor(int secondaryRgbColor) + { + this.secondaryRgbColor = secondaryRgbColor; + } + + public boolean isHideUnderlay() + { + return hideUnderlay; + } + + public void setHideUnderlay(boolean hideUnderlay) + { + this.hideUnderlay = hideUnderlay; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java index 458cbb37ff..efd0f6c275 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/SpriteDefinition.java @@ -32,6 +32,8 @@ package net.runelite.cache.definitions; public class SpriteDefinition { + private int id; + private int frame; private int offsetX; private int offsetY; private int width; @@ -40,6 +42,62 @@ public class SpriteDefinition private int maxWidth; private int maxHeight; + @Override + public int hashCode() + { + int hash = 7; + hash = 89 * hash + this.id; + hash = 89 * hash + this.frame; + 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 SpriteDefinition other = (SpriteDefinition) obj; + if (this.id != other.id) + { + return false; + } + if (this.frame != other.frame) + { + return false; + } + return true; + } + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public int getFrame() + { + return frame; + } + + public void setFrame(int frame) + { + this.frame = frame; + } + public int getOffsetX() { return offsetX; @@ -109,6 +167,4 @@ public class SpriteDefinition { this.maxHeight = maxHeight; } - - } diff --git a/cache/src/main/java/net/runelite/cache/definitions/TextureDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/TextureDefinition.java new file mode 100644 index 0000000000..3cbd41dd5b --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/TextureDefinition.java @@ -0,0 +1,57 @@ +/* + * 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.definitions; + +public class TextureDefinition +{ + private int id; + private int[] fileIds; + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public int[] getFileIds() + { + return fileIds; + } + + public void setFileIds(int[] fileIds) + { + this.fileIds = fileIds; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java new file mode 100644 index 0000000000..e8b728d664 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java @@ -0,0 +1,56 @@ +/* + * 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.definitions; + +public class UnderlayDefinition +{ + private int id; + private int color; + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public int getColor() + { + return color; + } + + public void setColor(int color) + { + this.color = color; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/OverlayLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/OverlayLoader.java new file mode 100644 index 0000000000..73b0c7e95f --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/OverlayLoader.java @@ -0,0 +1,79 @@ +/* + * 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.definitions.loaders; + +import net.runelite.cache.definitions.OverlayDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OverlayLoader +{ + private static final Logger logger = LoggerFactory.getLogger(OverlayLoader.class); + + public OverlayDefinition load(int id, byte[] b) + { + OverlayDefinition def = new OverlayDefinition(); + InputStream is = new InputStream(b); + + def.setId(id); + + for (;;) + { + int opcode = is.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + if (opcode == 1) + { + int color = is.read24BitInt(); + def.setRgbColor(color); + } + else if (opcode == 2) + { + int texture = is.readUnsignedByte(); + def.setTexture(texture); + } + else if (opcode == 5) + { + def.setHideUnderlay(false); + } + else if (opcode == 7) + { + int secondaryColor = is.read24BitInt(); + def.setSecondaryRgbColor(secondaryColor); + } + } + + return def; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java index 29a66f7b38..556222f7a3 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/SpriteLoader.java @@ -38,7 +38,7 @@ public class SpriteLoader public static final int FLAG_VERTICAL = 0b01; public static final int FLAG_ALPHA = 0b10; - public SpriteDefinition[] load(InputStream stream) + public SpriteDefinition[] load(int id, InputStream stream) { stream.setOffset(stream.getLength() - 2); int spriteCount = stream.readUnsignedShort(); @@ -58,6 +58,8 @@ public class SpriteLoader for (int i = 0; i < spriteCount; ++i) { sprites[i] = new SpriteDefinition(); + sprites[i].setId(id); + sprites[i].setFrame(i); sprites[i].setMaxWidth(width); sprites[i].setMaxHeight(height); } diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/TextureLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/TextureLoader.java new file mode 100644 index 0000000000..e967b06bf4 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/TextureLoader.java @@ -0,0 +1,59 @@ +/* + * 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.definitions.loaders; + +import net.runelite.cache.definitions.TextureDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TextureLoader +{ + private static final Logger logger = LoggerFactory.getLogger(TextureLoader.class); + + public TextureDefinition load(int id, byte[] b) + { + TextureDefinition def = new TextureDefinition(); + InputStream is = new InputStream(b); + + is.skip(3); + def.setId(id); + + int count = is.readUnsignedByte(); + int[] files = new int[count]; + + for (int i = 0; i < count; ++i) + files[i] = is.readUnsignedShort(); + + def.setFileIds(files); + + return def; + } +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/UnderlayLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/UnderlayLoader.java new file mode 100644 index 0000000000..881a4ad976 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/UnderlayLoader.java @@ -0,0 +1,65 @@ +/* + * 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.definitions.loaders; + +import net.runelite.cache.definitions.UnderlayDefinition; +import net.runelite.cache.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UnderlayLoader +{ + private static final Logger logger = LoggerFactory.getLogger(UnderlayLoader.class); + + public UnderlayDefinition load(int id, byte[] b) + { + UnderlayDefinition def = new UnderlayDefinition(); + InputStream is = new InputStream(b); + + def.setId(id); + + for (;;) + { + int opcode = is.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + if (opcode == 1) + { + int color = is.read24BitInt(); + def.setColor(color); + } + } + + return def; + } +} diff --git a/cache/src/main/java/net/runelite/cache/region/HeightCalc.java b/cache/src/main/java/net/runelite/cache/region/HeightCalc.java new file mode 100644 index 0000000000..d30abbee53 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/region/HeightCalc.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2015 Kyle Friz + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.runelite.cache.region; + +/** + * @author Kyle Friz + * @since Feb 20, 2016 + */ +public class HeightCalc +{ + private static final int JAGEX_CIRCULAR_ANGLE = 2048; + private static final double ANGULAR_RATIO = 360D / JAGEX_CIRCULAR_ANGLE; + private static final double JAGEX_RADIAN = Math.toRadians(ANGULAR_RATIO); + + private static final int[] SIN = new int[JAGEX_CIRCULAR_ANGLE]; + private static final int[] COS = new int[JAGEX_CIRCULAR_ANGLE]; + + static + { + for (int i = 0; i < JAGEX_CIRCULAR_ANGLE; i++) + { + SIN[i] = (int) (65536.0D * Math.sin((double) i * JAGEX_RADIAN)); + COS[i] = (int) (65536.0D * Math.cos((double) i * JAGEX_RADIAN)); + } + } + + public static int calculate(int baseX, int baseY, int x, int y) + { + int xc = (baseX >> 3) + 932731 + x; + int yc = (baseY >> 3) + 556238 + y; + int n = interpolateNoise(xc + 45365, yc + 91923, 4) - 128 + + (interpolateNoise(10294 + xc, yc + 37821, 2) - 128 >> 1) + + (interpolateNoise(xc, yc, 1) - 128 >> 2); + n = 35 + (int) ((double) n * 0.3D); + if (n < 10) + { + n = 10; + } + else if (n > 60) + { + n = 60; + } + + return n; + } + + public static int interpolateNoise(int x, int y, int frequency) + { + int intX = x / frequency; + int fracX = x & frequency - 1; + int intY = y / frequency; + int fracY = y & frequency - 1; + int v1 = smoothedNoise1(intX, intY); + int v2 = smoothedNoise1(intX + 1, intY); + int v3 = smoothedNoise1(intX, intY + 1); + int v4 = smoothedNoise1(1 + intX, 1 + intY); + int i1 = interpolate(v1, v2, fracX, frequency); + int i2 = interpolate(v3, v4, fracX, frequency); + return interpolate(i1, i2, fracY, frequency); + } + + public static int smoothedNoise1(int x, int y) + { + int corners = noise(x - 1, y - 1) + noise(x + 1, y - 1) + noise(x - 1, 1 + y) + noise(x + 1, y + 1); + int sides = noise(x - 1, y) + noise(1 + x, y) + noise(x, y - 1) + noise(x, 1 + y); + int center = noise(x, y); + return center / 4 + sides / 8 + corners / 16; + } + + public static int noise(int x, int y) + { + int n = x + y * 57; + n ^= n << 13; + return ((n * (n * n * 15731 + 789221) + 1376312589) & Integer.MAX_VALUE) >> 19 & 255; + } + + public static int interpolate(int a, int b, int x, int y) + { + int f = 65536 - COS[1024 * x / y] >> 1; + return (f * b >> 16) + (a * (65536 - f) >> 16); + } + +} diff --git a/cache/src/main/java/net/runelite/cache/region/Region.java b/cache/src/main/java/net/runelite/cache/region/Region.java new file mode 100644 index 0000000000..e6c2600073 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/region/Region.java @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2015 Kyle Friz + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.runelite.cache.region; + +import net.runelite.cache.io.InputStream; + +/** + * + * @author Kyle Friz + * @since Jun 30, 2015 + */ +public class Region +{ + + public static final int X = 64; + public static final int Y = 64; + public static final int Z = 4; + + private final int regionID; + private final int baseX; + private final int baseY; + + private final int[][][] tileHeights = new int[Z][X][Y]; + private final byte[][][] renderRules = new byte[Z][X][Y]; + private final byte[][][] overlayIds = new byte[Z][X][Y]; + private final byte[][][] overlayPaths = new byte[Z][X][Y]; + private final byte[][][] overlayRotations = new byte[Z][X][Y]; + private final byte[][][] underlayIds = new byte[Z][X][Y]; + + public Region(int id) + { + this.regionID = id; + this.baseX = ((id >> 8) & 0xFF) << 6; + this.baseY = (id & 0xFF) << 6; + } + + public void loadTerrain(byte[] buf) + { + InputStream in = new InputStream(buf); + + for (int z = 0; z < Z; z++) + { + for (int x = 0; x < X; x++) + { + for (int y = 0; y < Y; y++) + { + while (true) + { + int attribute = in.readUnsignedByte(); + if (attribute == 0) + { + if (z == 0) + { + tileHeights[0][x][y] = -HeightCalc.calculate(baseX, baseY, x, y) * 8; + } + else + { + tileHeights[z][x][y] = tileHeights[z - 1][x][y] - 240; + } + + break; + } + else if (attribute == 1) + { + int height = in.readUnsignedByte(); + if (height == 1) + { + height = 0; + } + + if (z == 0) + { + tileHeights[0][x][y] = -height * 8; + } + else + { + tileHeights[z][x][y] = tileHeights[z - 1][x][y] - height * 8; + } + + break; + } + else if (attribute <= 49) + { + overlayIds[z][x][y] = in.readByte(); + overlayPaths[z][x][y] = (byte) ((attribute - 2) / 4); + overlayRotations[z][x][y] = (byte) (attribute - 2 & 3); + } + else if (attribute <= 81) + { + renderRules[z][x][y] = (byte) (attribute - 49); + } + else + { + underlayIds[z][x][y] = (byte) (attribute - 81); + } + } + } + } + } + } + + public int getRegionID() + { + return regionID; + } + + public int getBaseX() + { + return baseX; + } + + public int getBaseY() + { + return baseY; + } + + public int getTileHeight(int z, int x, int y) + { + return tileHeights[z][x][y]; + } + + public byte getRenderRule(int z, int x, int y) + { + return renderRules[z][x][y]; + } + + public int getOverlayId(int z, int x, int y) + { + return overlayIds[z][x][y] & 0xFF; + } + + public byte getOverlayPath(int z, int x, int y) + { + return overlayPaths[z][x][y]; + } + + public byte getOverlayRotation(int z, int x, int y) + { + return overlayRotations[z][x][y]; + } + + public int getUnderlayId(int z, int x, int y) + { + return underlayIds[z][x][y] & 0xFF; + } +} diff --git a/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java b/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java new file mode 100644 index 0000000000..14b4cbb07c --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java @@ -0,0 +1,75 @@ +/* + * 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; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MapImageDumperTest +{ + private static final Logger logger = LoggerFactory.getLogger(MapImageDumperTest.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + public void extract() throws IOException + { + File base = StoreLocation.LOCATION, + outFile = folder.newFile(); + + BufferedImage[] images; + + try (Store store = new Store(base)) + { + store.load(); + + MapImageDumper dumper = new MapImageDumper(store); + images = dumper.buildImages(); + } + + int i = 0; + for (BufferedImage image : images) + { + File imageFile = new File(outFile, "img-" + i++ + ".png"); + + ImageIO.write(image, "png", imageFile); + logger.info("Wrote image {}", imageFile); + } + } +} diff --git a/cache/src/test/java/net/runelite/cache/SpriteDumperTest.java b/cache/src/test/java/net/runelite/cache/SpriteDumperTest.java index 70ce0e9835..314c832cea 100644 --- a/cache/src/test/java/net/runelite/cache/SpriteDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/SpriteDumperTest.java @@ -79,9 +79,7 @@ public class SpriteDumperTest byte[] contents = file.getContents(); SpriteLoader loader = new SpriteLoader(); - SpriteDefinition[] sprites = loader.load(new InputStream(contents)); - - int frame = 0; + SpriteDefinition[] sprites = loader.load(a.getArchiveId(), new InputStream(contents)); for (SpriteDefinition def : sprites) { @@ -90,12 +88,11 @@ public class SpriteDumperTest continue; BufferedImage image = getBufferedImage(def); - java.io.File targ = new java.io.File(outDir, a.getArchiveId() + "-" + frame + ".png"); + java.io.File targ = new java.io.File(outDir, def.getId() + "-" + def.getFrame() + ".png"); targ.mkdirs(); ImageIO.write(image, "png", targ); ++count; - ++frame; } } } diff --git a/cache/src/test/java/net/runelite/cache/TextureDumper.java b/cache/src/test/java/net/runelite/cache/TextureDumper.java new file mode 100644 index 0000000000..73f052877f --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/TextureDumper.java @@ -0,0 +1,85 @@ +/* + * 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; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.IOException; +import java.nio.charset.Charset; +import net.runelite.cache.definitions.TextureDefinition; +import net.runelite.cache.definitions.loaders.TextureLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TextureDumper +{ + private static final Logger logger = LoggerFactory.getLogger(TextureDumper.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Test + public void extract() throws IOException + { + java.io.File base = StoreLocation.LOCATION, + outDir = folder.newFile(); + + int count = 0; + + try (Store store = new Store(base)) + { + store.load(); + + Index index = store.getIndex(IndexType.TEXTURES); + Archive archive = index.getArchive(0); + + for (File file : archive.getFiles()) + { + TextureLoader loader = new TextureLoader(); + TextureDefinition texture = loader.load(file.getFileId(), file.getContents()); + + Files.write(gson.toJson(texture), new java.io.File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + ++count; + } + } + + logger.info("Dumped {} textures to {}", count, outDir); + } +} diff --git a/cache/src/test/java/net/runelite/cache/TitleDumper.java b/cache/src/test/java/net/runelite/cache/TitleDumper.java index 9f21585aed..efeae930b7 100644 --- a/cache/src/test/java/net/runelite/cache/TitleDumper.java +++ b/cache/src/test/java/net/runelite/cache/TitleDumper.java @@ -32,8 +32,6 @@ package net.runelite.cache; import java.io.IOException; import java.nio.file.Files; -import net.runelite.cache.IndexType; -import net.runelite.cache.StoreLocation; import net.runelite.cache.fs.Archive; import net.runelite.cache.fs.File; import net.runelite.cache.fs.Index; diff --git a/cache/src/test/java/net/runelite/cache/UnderlayDumper.java b/cache/src/test/java/net/runelite/cache/UnderlayDumper.java new file mode 100644 index 0000000000..6b365f5b47 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/UnderlayDumper.java @@ -0,0 +1,85 @@ +/* + * 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; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.IOException; +import java.nio.charset.Charset; +import net.runelite.cache.definitions.UnderlayDefinition; +import net.runelite.cache.definitions.loaders.UnderlayLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UnderlayDumper +{ + private static final Logger logger = LoggerFactory.getLogger(UnderlayDumper.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Test + public void extract() throws IOException + { + java.io.File base = StoreLocation.LOCATION, + outDir = folder.newFile(); + + int count = 0; + + try (Store store = new Store(base)) + { + store.load(); + + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.UNDERLAY.getId()); + + for (File file : archive.getFiles()) + { + UnderlayLoader loader = new UnderlayLoader(); + UnderlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); + + Files.write(gson.toJson(underlay), new java.io.File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + ++count; + } + } + + logger.info("Dumped {} underlays to {}", count, outDir); + } +}