From f3b9548c848b65a6c105ac3d035549e1be1b72d6 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 30 Mar 2018 12:22:35 -0400 Subject: [PATCH 1/5] cache: split color palette code into its own class --- .../net/runelite/cache/item/ColorPalette.java | 161 ++++++++++++++++++ .../net/runelite/cache/item/Graphics3D.java | 126 +------------- 2 files changed, 163 insertions(+), 124 deletions(-) create mode 100644 cache/src/main/java/net/runelite/cache/item/ColorPalette.java diff --git a/cache/src/main/java/net/runelite/cache/item/ColorPalette.java b/cache/src/main/java/net/runelite/cache/item/ColorPalette.java new file mode 100644 index 0000000000..6486afe2fb --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/item/ColorPalette.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.item; + +import lombok.Getter; + +public class ColorPalette +{ + @Getter + private final int[] colorPalette; + + public ColorPalette(double brightness, int var2, int var3) + { + colorPalette = buildColorPalettee(brightness, var2, var3); + } + + private int[] buildColorPalettee(double brightness, int var2, int var3) + { + int[] colorPalette = new int[65536]; + int var4 = var2 * 128; + + for (int var5 = var2; var5 < var3; ++var5) + { + double var6 = (double) (var5 >> 3) / 64.0D + 0.0078125D; + double var8 = (double) (var5 & 7) / 8.0D + 0.0625D; + + for (int var10 = 0; var10 < 128; ++var10) + { + double var11 = (double) var10 / 128.0D; + double var13 = var11; + double var15 = var11; + double var17 = var11; + if (var8 != 0.0D) + { + double var19; + if (var11 < 0.5D) + { + var19 = var11 * (1.0D + var8); + } + else + { + var19 = var11 + var8 - var11 * var8; + } + + double var21 = 2.0D * var11 - var19; + double var23 = var6 + 0.3333333333333333D; + if (var23 > 1.0D) + { + --var23; + } + + double var27 = var6 - 0.3333333333333333D; + if (var27 < 0.0D) + { + ++var27; + } + + if (6.0D * var23 < 1.0D) + { + var13 = var21 + (var19 - var21) * 6.0D * var23; + } + else if (2.0D * var23 < 1.0D) + { + var13 = var19; + } + else if (3.0D * var23 < 2.0D) + { + var13 = var21 + (var19 - var21) * (0.6666666666666666D - var23) * 6.0D; + } + else + { + var13 = var21; + } + + if (6.0D * var6 < 1.0D) + { + var15 = var21 + (var19 - var21) * 6.0D * var6; + } + else if (2.0D * var6 < 1.0D) + { + var15 = var19; + } + else if (3.0D * var6 < 2.0D) + { + var15 = var21 + (var19 - var21) * (0.6666666666666666D - var6) * 6.0D; + } + else + { + var15 = var21; + } + + if (6.0D * var27 < 1.0D) + { + var17 = var21 + (var19 - var21) * 6.0D * var27; + } + else if (2.0D * var27 < 1.0D) + { + var17 = var19; + } + else if (3.0D * var27 < 2.0D) + { + var17 = var21 + (var19 - var21) * (0.6666666666666666D - var27) * 6.0D; + } + else + { + var17 = var21; + } + } + + int var29 = (int) (var13 * 256.0D); + int var20 = (int) (var15 * 256.0D); + int var30 = (int) (var17 * 256.0D); + int var22 = var30 + (var20 << 8) + (var29 << 16); + var22 = adjustRGB(var22, brightness); + if (var22 == 0) + { + var22 = 1; + } + + colorPalette[var4++] = var22; + } + } + return colorPalette; + } + + private static int adjustRGB(int var0, double var1) + { + double var3 = (double) (var0 >> 16) / 256.0D; + double var5 = (double) (var0 >> 8 & 255) / 256.0D; + double var7 = (double) (var0 & 255) / 256.0D; + var3 = Math.pow(var3, var1); + var5 = Math.pow(var5, var1); + var7 = Math.pow(var7, var1); + int var9 = (int) (var3 * 256.0D); + int var10 = (int) (var5 * 256.0D); + int var11 = (int) (var7 * 256.0D); + return var11 + (var10 << 8) + (var9 << 16); + } +} diff --git a/cache/src/main/java/net/runelite/cache/item/Graphics3D.java b/cache/src/main/java/net/runelite/cache/item/Graphics3D.java index 9312a9f945..248ab6c572 100644 --- a/cache/src/main/java/net/runelite/cache/item/Graphics3D.java +++ b/cache/src/main/java/net/runelite/cache/item/Graphics3D.java @@ -70,7 +70,7 @@ class Graphics3D extends Rasterizer2D int Rasterizer3D_clipNegativeMidY; int Rasterizer3D_clipMidY2; int[] rasterClipY = new int[1024]; - public int[] colorPalette = new int[65536]; + public int[] colorPalette; public Graphics3D(RSTextureProvider textureProvider) { @@ -134,129 +134,7 @@ class Graphics3D extends Rasterizer2D public final void setBrightness(double var0) { - buildColorPalette(var0, 0, 512); - } - - final void buildColorPalette(double var0, int var2, int var3) - { - int var4 = var2 * 128; - - for (int var5 = var2; var5 < var3; ++var5) - { - double var6 = (double) (var5 >> 3) / 64.0D + 0.0078125D; - double var8 = (double) (var5 & 7) / 8.0D + 0.0625D; - - for (int var10 = 0; var10 < 128; ++var10) - { - double var11 = (double) var10 / 128.0D; - double var13 = var11; - double var15 = var11; - double var17 = var11; - if (var8 != 0.0D) - { - double var19; - if (var11 < 0.5D) - { - var19 = var11 * (1.0D + var8); - } - else - { - var19 = var11 + var8 - var11 * var8; - } - - double var21 = 2.0D * var11 - var19; - double var23 = var6 + 0.3333333333333333D; - if (var23 > 1.0D) - { - --var23; - } - - double var27 = var6 - 0.3333333333333333D; - if (var27 < 0.0D) - { - ++var27; - } - - if (6.0D * var23 < 1.0D) - { - var13 = var21 + (var19 - var21) * 6.0D * var23; - } - else if (2.0D * var23 < 1.0D) - { - var13 = var19; - } - else if (3.0D * var23 < 2.0D) - { - var13 = var21 + (var19 - var21) * (0.6666666666666666D - var23) * 6.0D; - } - else - { - var13 = var21; - } - - if (6.0D * var6 < 1.0D) - { - var15 = var21 + (var19 - var21) * 6.0D * var6; - } - else if (2.0D * var6 < 1.0D) - { - var15 = var19; - } - else if (3.0D * var6 < 2.0D) - { - var15 = var21 + (var19 - var21) * (0.6666666666666666D - var6) * 6.0D; - } - else - { - var15 = var21; - } - - if (6.0D * var27 < 1.0D) - { - var17 = var21 + (var19 - var21) * 6.0D * var27; - } - else if (2.0D * var27 < 1.0D) - { - var17 = var19; - } - else if (3.0D * var27 < 2.0D) - { - var17 = var21 + (var19 - var21) * (0.6666666666666666D - var27) * 6.0D; - } - else - { - var17 = var21; - } - } - - int var29 = (int) (var13 * 256.0D); - int var20 = (int) (var15 * 256.0D); - int var30 = (int) (var17 * 256.0D); - int var22 = var30 + (var20 << 8) + (var29 << 16); - var22 = adjustRGB(var22, var0); - if (var22 == 0) - { - var22 = 1; - } - - colorPalette[var4++] = var22; - } - } - - } - - static int adjustRGB(int var0, double var1) - { - double var3 = (double) (var0 >> 16) / 256.0D; - double var5 = (double) (var0 >> 8 & 255) / 256.0D; - double var7 = (double) (var0 & 255) / 256.0D; - var3 = Math.pow(var3, var1); - var5 = Math.pow(var5, var1); - var7 = Math.pow(var7, var1); - int var9 = (int) (var3 * 256.0D); - int var10 = (int) (var5 * 256.0D); - int var11 = (int) (var7 * 256.0D); - return var11 + (var10 << 8) + (var9 << 16); + colorPalette = new ColorPalette(var0, 0, 512).getColorPalette(); } final void rasterGouraud(int var0, int var1, int var2, int var3, int var4, int var5, int var6, int var7, int var8) From d3c4c9551f80e1cc5f14cd6e979de73c89fec90d Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 30 Mar 2018 12:23:38 -0400 Subject: [PATCH 2/5] cache: add and compute hsl in underlay --- .../cache/definitions/UnderlayDefinition.java | 100 ++++++++++++++++++ .../definitions/loaders/UnderlayLoader.java | 2 + 2 files changed, 102 insertions(+) diff --git a/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java index ff3d6046f3..7d3d8c2a47 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/UnderlayDefinition.java @@ -31,4 +31,104 @@ public class UnderlayDefinition { private int id; private int color; + + private transient int hue; + private transient int saturation; + private transient int lightness; + private transient int hueMultiplier; + + public void calculateHsl() + { + int var1 = color; + double var2 = (double) (var1 >> 16 & 255) / 256.0D; + double var4 = (double) (var1 >> 8 & 255) / 256.0D; + double var6 = (double) (var1 & 255) / 256.0D; + double var8 = var2; + if (var4 < var2) + { + var8 = var4; + } + + if (var6 < var8) + { + var8 = var6; + } + + double var10 = var2; + if (var4 > var2) + { + var10 = var4; + } + + if (var6 > var10) + { + var10 = var6; + } + + double var12 = 0.0D; + double var14 = 0.0D; + double var16 = (var10 + var8) / 2.0D; + if (var8 != var10) + { + if (var16 < 0.5D) + { + var14 = (var10 - var8) / (var8 + var10); + } + + if (var16 >= 0.5D) + { + var14 = (var10 - var8) / (2.0D - var10 - var8); + } + + if (var2 == var10) + { + var12 = (var4 - var6) / (var10 - var8); + } + else if (var10 == var4) + { + var12 = 2.0D + (var6 - var2) / (var10 - var8); + } + else if (var10 == var6) + { + var12 = 4.0D + (var2 - var4) / (var10 - var8); + } + } + + var12 /= 6.0D; + this.saturation = (int) (var14 * 256.0D); + this.lightness = (int) (var16 * 256.0D); + if (this.saturation < 0) + { + this.saturation = 0; + } + else if (this.saturation > 255) + { + this.saturation = 255; + } + + if (this.lightness < 0) + { + this.lightness = 0; + } + else if (this.lightness > 255) + { + this.lightness = 255; + } + + if (var16 > 0.5D) + { + this.hueMultiplier = (int) (var14 * (1.0D - var16) * 512.0D); + } + else + { + this.hueMultiplier = (int) (var14 * var16 * 512.0D); + } + + if (this.hueMultiplier < 1) + { + this.hueMultiplier = 1; + } + + this.hue = (int) ((double) this.hueMultiplier * var12); + } } 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 index cec9e5e148..5c4c10f09d 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/UnderlayLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/UnderlayLoader.java @@ -55,6 +55,8 @@ public class UnderlayLoader } } + def.calculateHsl(); + return def; } } From f50760c8b2c91b0b100858287ba6c82f46513318 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 30 Mar 2018 12:28:13 -0400 Subject: [PATCH 3/5] cache: add and compute hsl in overlay --- .../cache/definitions/OverlayDefinition.java | 101 ++++++++++++++++++ .../definitions/loaders/OverlayLoader.java | 2 + 2 files changed, 103 insertions(+) diff --git a/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java index 02be73a73d..3846e99364 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/OverlayDefinition.java @@ -35,4 +35,105 @@ public class OverlayDefinition private int texture = -1; private int secondaryRgbColor = -1; private boolean hideUnderlay = true; + + private transient int hue; + private transient int saturation; + private transient int lightness; + + private transient int otherHue; + private transient int otherSaturation; + private transient int otherLightness; + + public void calculateHsl() + { + if (secondaryRgbColor != -1) + { + calculateHsl(secondaryRgbColor); + otherHue = hue; + otherSaturation = saturation; + otherLightness = lightness; + } + + calculateHsl(rgbColor); + } + + private void calculateHsl(int var1) + { + double var2 = (double) (var1 >> 16 & 255) / 256.0D; + double var4 = (double) (var1 >> 8 & 255) / 256.0D; + double var6 = (double) (var1 & 255) / 256.0D; + double var8 = var2; + if (var4 < var2) + { + var8 = var4; + } + + if (var6 < var8) + { + var8 = var6; + } + + double var10 = var2; + if (var4 > var2) + { + var10 = var4; + } + + if (var6 > var10) + { + var10 = var6; + } + + double var12 = 0.0D; + double var14 = 0.0D; + double var16 = (var8 + var10) / 2.0D; + if (var10 != var8) + { + if (var16 < 0.5D) + { + var14 = (var10 - var8) / (var10 + var8); + } + + if (var16 >= 0.5D) + { + var14 = (var10 - var8) / (2.0D - var10 - var8); + } + + if (var2 == var10) + { + var12 = (var4 - var6) / (var10 - var8); + } + else if (var4 == var10) + { + var12 = 2.0D + (var6 - var2) / (var10 - var8); + } + else if (var10 == var6) + { + var12 = 4.0D + (var2 - var4) / (var10 - var8); + } + } + + var12 /= 6.0D; + this.hue = (int) (256.0D * var12); + this.saturation = (int) (var14 * 256.0D); + this.lightness = (int) (var16 * 256.0D); + if (this.saturation < 0) + { + this.saturation = 0; + } + else if (this.saturation > 255) + { + this.saturation = 255; + } + + if (this.lightness < 0) + { + this.lightness = 0; + } + else if (this.lightness > 255) + { + this.lightness = 255; + } + + } } 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 index d420c50616..1b01c07c87 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/OverlayLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/OverlayLoader.java @@ -69,6 +69,8 @@ public class OverlayLoader } } + def.calculateHsl(); + return def; } } From 769ce714e48af4f6caa2d5321e986e65a6dcb536 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 30 Mar 2018 12:29:14 -0400 Subject: [PATCH 4/5] cache: add post to object loader --- .../definitions/loaders/ObjectLoader.java | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java index bdcf503ceb..2f8972287e 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java @@ -24,14 +24,13 @@ */ package net.runelite.cache.definitions.loaders; +import java.util.HashMap; +import java.util.Map; import net.runelite.cache.definitions.ObjectDefinition; import net.runelite.cache.io.InputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; - public class ObjectLoader { private static final Logger logger = LoggerFactory.getLogger(ObjectLoader.class); @@ -54,6 +53,8 @@ public class ObjectLoader processOp(opcode, def, is); } + post(def); + return def; } @@ -375,4 +376,30 @@ public class ObjectLoader logger.warn("Unrecognized opcode {}", opcode); } } + + + private void post(ObjectDefinition def) + { + if (def.getAnInt2088() == -1) + { + def.setAnInt2088(0); + if (def.getObjectModels() != null && (def.getObjectTypes() == null || def.getObjectTypes()[0] == 10)) + { + def.setAnInt2088(1); + } + + for (int var1 = 0; var1 < 5; ++var1) + { + if (def.getActions()[var1] != null) + { + def.setAnInt2088(1); + } + } + } + + if (def.getAnInt2106() == -1) + { + def.setAnInt2106(def.getInteractType() != 0 ? 1 : 0); + } + } } From 9f943832eade7131735648fffadf4b763e63fe0d Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 30 Mar 2018 12:35:20 -0400 Subject: [PATCH 5/5] cache: rewrite map image dumper with logic from client --- .../net/runelite/cache/MapImageDumper.java | 986 +++++++++++++----- .../net/runelite/cache/ObjectManager.java | 22 +- .../cache/item/RSTextureProvider.java | 2 +- .../runelite/cache/region/RegionLoader.java | 22 +- .../runelite/cache/MapImageDumperTest.java | 30 +- 5 files changed, 765 insertions(+), 297 deletions(-) diff --git a/cache/src/main/java/net/runelite/cache/MapImageDumper.java b/cache/src/main/java/net/runelite/cache/MapImageDumper.java index 089ec5e062..5235d97fb6 100644 --- a/cache/src/main/java/net/runelite/cache/MapImageDumper.java +++ b/cache/src/main/java/net/runelite/cache/MapImageDumper.java @@ -29,19 +29,17 @@ 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 lombok.Getter; +import lombok.Setter; import net.runelite.cache.definitions.AreaDefinition; 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.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.ArchiveFiles; @@ -49,6 +47,8 @@ import net.runelite.cache.fs.FSFile; import net.runelite.cache.fs.Index; import net.runelite.cache.fs.Storage; import net.runelite.cache.fs.Store; +import net.runelite.cache.item.ColorPalette; +import net.runelite.cache.item.RSTextureProvider; import net.runelite.cache.region.Location; import net.runelite.cache.region.Region; import net.runelite.cache.region.RegionLoader; @@ -60,24 +60,37 @@ public class MapImageDumper { private static final Logger logger = LoggerFactory.getLogger(MapImageDumper.class); - private static final int MAP_SCALE = 2; // this squared is the number of pixels per map square + private static final int MAP_SCALE = 4; // 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 static final int BLEND = 5; // number of surrounding tiles for ground blending + + private static int[] colorPalette = new ColorPalette(0.9d, 0, 512).getColorPalette(); + + private static int[][] TILE_SHAPE_2D = new int[][]{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1}, {1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1}, {0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1}, {1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1}}; + private static int[][] TILE_ROTATION_2D = new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {12, 8, 4, 0, 13, 9, 5, 1, 14, 10, 6, 2, 15, 11, 7, 3}, {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, {3, 7, 11, 15, 2, 6, 10, 14, 1, 5, 9, 13, 0, 4, 8, 12}}; + + private final int wallColor = (238 + (int) (Math.random() * 20.0D) - 10 << 16) + (238 + (int) (Math.random() * 20.0D) - 10 << 8) + (238 + (int) (Math.random() * 20.0D) - 10); + private final int doorColor = 238 + (int) (Math.random() * 20.0D) - 10 << 16; private final Store store; - private final List underlays = new ArrayList<>(); - private final List overlays = new ArrayList<>(); - private final List textures = new ArrayList<>(); - private final Map averageColors = new HashMap<>(); + private final Map underlays = new HashMap<>(); + private final Map overlays = new HashMap<>(); private final Map scaledMapIcons = new HashMap<>(); - private final Map objects = new HashMap<>(); private RegionLoader regionLoader; private final AreaManager areas; private final SpriteManager sprites; + private RSTextureProvider rsTextureProvider; + private final ObjectManager objectManager; + @Getter + @Setter private boolean labelRegions; + + @Getter + @Setter private boolean outlineRegions; public MapImageDumper(Store store) @@ -85,14 +98,18 @@ public class MapImageDumper this.store = store; this.areas = new AreaManager(store); this.sprites = new SpriteManager(store); + objectManager = new ObjectManager(store); } public void load() throws IOException { loadUnderlays(store); loadOverlays(store); - loadTextures(store); - loadObjects(store); + objectManager.load(); + + TextureManager textureManager = new TextureManager(store); + textureManager.load(); + rsTextureProvider = new RSTextureProvider(textureManager, sprites); loadRegions(store); areas.load(); @@ -100,7 +117,7 @@ public class MapImageDumper loadSprites(); } - public BufferedImage drawMap(int z) throws IOException + public BufferedImage drawMap(int z) { int minX = regionLoader.getLowestX().getBaseX(); int minY = regionLoader.getLowestY().getBaseY(); @@ -111,17 +128,70 @@ public class MapImageDumper int dimX = maxX - minX; int dimY = maxY - minY; - dimX *= MAP_SCALE; - dimY *= MAP_SCALE; + int pixelsX = dimX * MAP_SCALE; + int pixelsY = dimY * MAP_SCALE; - logger.info("Map image dimensions: {}px x {}px, {}px per map square ({} MB)", dimX, dimY, MAP_SCALE, (dimX * dimY / 1024 / 1024)); + logger.info("Map image dimensions: {}px x {}px, {}px per map square ({} MB). Max memory: {}mb", pixelsX, pixelsY, + MAP_SCALE, (pixelsX * pixelsY * 3 / 1024 / 1024), + Runtime.getRuntime().maxMemory() / 1024L / 1024L); - BufferedImage image = new BufferedImage(dimX, dimY, BufferedImage.TYPE_INT_RGB); + BufferedImage image = new BufferedImage(pixelsX, pixelsY, BufferedImage.TYPE_INT_RGB); - drawUnderlay(image, z); - drawOverlay(image, z); + drawMap(image, z); + drawObjects(image, z); + drawMapIcons(image, z); - // objects + return image; + } + + public BufferedImage drawRegion(Region region, int z) + { + int pixelsX = Region.X * MAP_SCALE; + int pixelsY = Region.Y * MAP_SCALE; + + BufferedImage image = new BufferedImage(pixelsX, pixelsY, BufferedImage.TYPE_INT_RGB); + + drawMap(image, 0, 0, z, region); + drawObjects(image, 0, 0, region, z); + drawMapIcons(image, 0, 0, region, z); + + return image; + } + + private void drawMap(BufferedImage image, int drawBaseX, int drawBaseY, int z, Region region) + { + int[][] map = new int[Region.X * MAP_SCALE][Region.Y * MAP_SCALE]; + drawMap(map, region, z); + + int[][] above = null; + if (z < 3) + { + above = new int[Region.X * MAP_SCALE][Region.Y * MAP_SCALE]; + drawMap(above, region, z + 1); + } + + for (int x = 0; x < Region.X; ++x) + { + for (int y = 0; y < Region.Y; ++y) + { + boolean isBridge = (region.getTileSetting(1, x, Region.Y - y - 1) & 2) != 0; + + int tileSetting = region.getTileSetting(z, x, Region.Y - y - 1); + if (!isBridge && ((tileSetting & 24) == 0)) + { + drawTile(image, map, drawBaseX, drawBaseY, x, y); + } + + if (z < 3 && isBridge) // client also has a check for &8 != 0 here + { + drawTile(image, above, drawBaseX, drawBaseY, x, y); + } + } + } + } + + private void drawMap(BufferedImage image, int z) + { for (Region region : regionLoader.getRegions()) { int baseX = region.getBaseX(); @@ -134,13 +204,537 @@ public class MapImageDumper // region has the greatest y, so invert int drawBaseY = regionLoader.getHighestY().getBaseY() - baseY; - Graphics2D graphics = image.createGraphics(); + drawMap(image, drawBaseX, drawBaseY, z, region); + } + } - drawObjects(graphics, region, z, drawBaseX, drawBaseY); + private void drawTile(BufferedImage to, int[][] pixels, int drawBaseX, int drawBaseY, int x, int y) + { + for (int i = 0; i < MAP_SCALE; ++i) + { + for (int j = 0; j < MAP_SCALE; ++j) + { + to.setRGB(drawBaseX * MAP_SCALE + x * MAP_SCALE + i, + drawBaseY * MAP_SCALE + y * MAP_SCALE + j, + pixels[x * MAP_SCALE + i][y * MAP_SCALE + j]); + } + } + } - graphics.dispose(); + private void drawMap(int[][] pixels, Region region, int z) + { + int baseX = region.getBaseX(); + int baseY = region.getBaseY(); + + int len = Region.X + BLEND * 2; + int[] hues = new int[len]; + int[] sats = new int[len]; + int[] light = new int[len]; + int[] mul = new int[len]; + int[] num = new int[len]; + + boolean hasLeftRegion = regionLoader.findRegionForWorldCoordinates(baseX - 1, baseY) != null; + boolean hasRightRegion = regionLoader.findRegionForWorldCoordinates(baseX + Region.X, baseY) != null; + boolean hasUpRegion = regionLoader.findRegionForWorldCoordinates(baseX, baseY + Region.Y) != null; + boolean hasDownRegion = regionLoader.findRegionForWorldCoordinates(baseX, baseY - 1) != null; + + for (int xi = (hasLeftRegion ? -BLEND * 2 : -BLEND); xi < Region.X + (hasRightRegion ? BLEND * 2 : BLEND); ++xi) + { + for (int yi = (hasDownRegion ? -BLEND : 0); yi < Region.Y + (hasUpRegion ? BLEND : 0); ++yi) + { + int xr = xi + BLEND; + if (xr >= (hasLeftRegion ? -BLEND : 0) && xr < Region.X + (hasRightRegion ? BLEND : 0)) + { + Region r = regionLoader.findRegionForWorldCoordinates(baseX + xr, baseY + yi); + if (r != null) + { + int underlayId = r.getUnderlayId(z, convert(xr), convert(yi)); + if (underlayId > 0) + { + UnderlayDefinition underlay = findUnderlay(underlayId - 1); + hues[yi + BLEND] += underlay.getHue(); + sats[yi + BLEND] += underlay.getSaturation(); + light[yi + BLEND] += underlay.getLightness(); + mul[yi + BLEND] += underlay.getHueMultiplier(); + num[yi + BLEND]++; + } + } + } + + int xl = xi - BLEND; + if (xl >= (hasLeftRegion ? -BLEND : 0) && xl < Region.X + (hasRightRegion ? BLEND : 0)) + { + Region r = regionLoader.findRegionForWorldCoordinates(baseX + xl, baseY + yi); + if (r != null) + { + int underlayId = r.getUnderlayId(z, convert(xl), convert(yi)); + if (underlayId > 0) + { + UnderlayDefinition underlay = findUnderlay(underlayId - 1); + hues[yi + BLEND] -= underlay.getHue(); + sats[yi + BLEND] -= underlay.getSaturation(); + light[yi + BLEND] -= underlay.getLightness(); + mul[yi + BLEND] -= underlay.getHueMultiplier(); + num[yi + BLEND]--; + } + } + } + } + + if (xi >= 0 && xi < Region.X) + { + int runningHues = 0; + int runningSat = 0; + int runningLight = 0; + int runningMultiplier = 0; + int runningNumber = 0; + + for (int yi = (hasDownRegion ? -BLEND * 2 : -BLEND); yi < Region.Y + (hasUpRegion ? BLEND * 2 : BLEND); ++yi) + { + int yu = yi + BLEND; + if (yu >= (hasDownRegion ? -BLEND : 0) && yu < Region.Y + (hasUpRegion ? BLEND : 0)) + { + runningHues += hues[yu + BLEND]; + runningSat += sats[yu + BLEND]; + runningLight += light[yu + BLEND]; + runningMultiplier += mul[yu + BLEND]; + runningNumber += num[yu + BLEND]; + } + + int yd = yi - BLEND; + if (yd >= (hasDownRegion ? -BLEND : 0) && yd < Region.Y + (hasUpRegion ? BLEND : 0)) + { + runningHues -= hues[yd + BLEND]; + runningSat -= sats[yd + BLEND]; + runningLight -= light[yd + BLEND]; + runningMultiplier -= mul[yd + BLEND]; + runningNumber -= num[yd + BLEND]; + } + + if (yi >= 0 && yi < Region.Y) + { + Region r = regionLoader.findRegionForWorldCoordinates(baseX + xi, baseY + yi); + if (r != null) + { + int underlayId = r.getUnderlayId(z, convert(xi), convert(yi)); + int overlayId = r.getOverlayId(z, convert(xi), convert(yi)); + + if (underlayId > 0 || overlayId > 0) + { + int underlayHsl = -1; + if (underlayId > 0) + { + int avgHue = runningHues * 256 / runningMultiplier; + int avgSat = runningSat / runningNumber; + int avgLight = runningLight / runningNumber; + // randomness is added to avgHue here + + if (avgLight < 0) + { + avgLight = 0; + } + else if (avgLight > 255) + { + avgLight = 255; + } + + underlayHsl = packHsl(avgHue, avgSat, avgLight); + } + + int underlayRgb = 0; + if (underlayHsl != -1) + { + int var0 = method1792(underlayHsl, 96); + underlayRgb = colorPalette[var0]; + } + + int shape, rotation; + Integer overlayRgb = null; + if (overlayId == 0) + { + shape = rotation = 0; + } + else + { + shape = r.getOverlayPath(z, convert(xi), convert(yi)) + 1; + rotation = r.getOverlayRotation(z, convert(xi), convert(yi)); + + OverlayDefinition overlayDefinition = findOverlay(overlayId - 1); + int overlayTexture = overlayDefinition.getTexture(); + int rgb; + + if (overlayTexture >= 0) + { + rgb = rsTextureProvider.getAverageTextureRGB(overlayTexture); + } + else if (overlayDefinition.getRgbColor() == 0xFF_00FF) + { + rgb = -2; + } + else + { + // randomness added here + int overlayHsl = packHsl(overlayDefinition.getHue(), overlayDefinition.getSaturation(), overlayDefinition.getLightness()); + rgb = overlayHsl; + } + + overlayRgb = 0; + if (rgb != -2) + { + int var0 = adjustHSLListness0(rgb, 96); + overlayRgb = colorPalette[var0]; + } + + if (overlayDefinition.getSecondaryRgbColor() != -1) + { + int hue = overlayDefinition.getOtherHue(); + int sat = overlayDefinition.getOtherSaturation(); + int olight = overlayDefinition.getOtherLightness(); + rgb = packHsl(hue, sat, olight); + int var0 = adjustHSLListness0(rgb, 96); + overlayRgb = colorPalette[var0]; + } + } + + if (shape == 0) + { + int drawX = xi; + int drawY = Region.Y - 1 - yi; + if (underlayRgb != 0) + { + drawMapSquare(pixels, drawX, drawY, underlayRgb); + } + } + else if (shape == 1) + { + int drawX = xi; + int drawY = Region.Y - 1 - yi; + drawMapSquare(pixels, drawX, drawY, overlayRgb); + } + else + { + int drawX = xi * MAP_SCALE; + int drawY = (Region.Y - 1 - yi) * MAP_SCALE; + int[] tileShapes = TILE_SHAPE_2D[shape]; + int[] tileRotations = TILE_ROTATION_2D[rotation]; + if (underlayRgb != 0) + { + int rotIdx = 0; + for (int i = 0; i < Region.Z; ++i) + { + int p1 = tileShapes[tileRotations[rotIdx++]] == 0 ? underlayRgb : overlayRgb; + int p2 = tileShapes[tileRotations[rotIdx++]] == 0 ? underlayRgb : overlayRgb; + int p3 = tileShapes[tileRotations[rotIdx++]] == 0 ? underlayRgb : overlayRgb; + int p4 = tileShapes[tileRotations[rotIdx++]] == 0 ? underlayRgb : overlayRgb; + pixels[drawX + 0][drawY + i] = p1; + pixels[drawX + 1][drawY + i] = p2; + pixels[drawX + 2][drawY + i] = p3; + pixels[drawX + 3][drawY + i] = p4; + } + } + else + { + int rotIdx = 0; + for (int i = 0; i < Region.Z; ++i) + { + int p1 = tileShapes[tileRotations[rotIdx++]]; + int p2 = tileShapes[tileRotations[rotIdx++]]; + int p3 = tileShapes[tileRotations[rotIdx++]]; + int p4 = tileShapes[tileRotations[rotIdx++]]; + + if (p1 != 0) + { + pixels[drawX + 0][drawY + i] = overlayRgb; + } + + if (p2 != 0) + { + pixels[drawX + 1][drawY + i] = overlayRgb; + } + + if (p3 != 0) + { + pixels[drawX + 2][drawY + i] = overlayRgb; + } + + if (p4 != 0) + { + pixels[drawX + 3][drawY + i] = overlayRgb; + } + } + } + } + } + } + } + } + } + } + } + + private static int convert(int d) + { + if (d >= 0) + { + return d % 64; + } + else + { + return 64 - -(d % 64) - 1; + } + } + + private void drawObjects(BufferedImage image, int drawBaseX, int drawBaseY, Region region, int z) + { + Graphics2D graphics = image.createGraphics(); + + for (Location location : region.getLocations()) + { + + int rotation = location.getOrientation(); + int type = location.getType(); + + int localX = location.getPosition().getX() - region.getBaseX(); + int localY = location.getPosition().getY() - region.getBaseY(); + + boolean isBridge = (region.getTileSetting(1, localX, localY) & 2) != 0; + + if (location.getPosition().getZ() == z + 1) + { + if (!isBridge) + { + continue; + } + } + else if (location.getPosition().getZ() == z) + { + if (isBridge) + { + continue; + } + + if ((region.getTileSetting(z, localX, localY) & 24) != 0) + { + continue; + } + } + else + { + continue; + } + + ObjectDefinition object = findObject(location.getId()); + + int drawX = (drawBaseX + localX) * MAP_SCALE; + int drawY = (drawBaseY + (Region.Y - 1 - localY)) * MAP_SCALE; + + if (type >= 0 && type <= 3) + { + // this is a wall + int hash = (localY << 7) + localX + (location.getId() << 14) + 0x4000_0000; + if (object.getAnInt2088() == 0) + { + hash -= Integer.MIN_VALUE; + } + + int rgb = wallColor; + if (hash > 0) + { + rgb = doorColor; + } + + if (object.getMapSceneID() != -1) + { + Image spriteImage = scaledMapIcons.get(object.getMapSceneID()); + graphics.drawImage(spriteImage, drawX * MAP_SCALE, drawY * MAP_SCALE, null); + } + else + { + if (type == 0 || type == 2) + { + if (rotation == 0) + { + image.setRGB(drawX + 0, drawY + 0, rgb); + image.setRGB(drawX + 0, drawY + 1, rgb); + image.setRGB(drawX + 0, drawY + 2, rgb); + image.setRGB(drawX + 0, drawY + 3, rgb); + } + else if (rotation == 1) + { + image.setRGB(drawX + 0, drawY + 0, rgb); + image.setRGB(drawX + 1, drawY + 0, rgb); + image.setRGB(drawX + 2, drawY + 0, rgb); + image.setRGB(drawX + 3, drawY + 0, rgb); + } + else if (rotation == 2) + { + image.setRGB(drawX + 3, drawY + 0, rgb); + image.setRGB(drawX + 3, drawY + 1, rgb); + image.setRGB(drawX + 3, drawY + 2, rgb); + image.setRGB(drawX + 3, drawY + 3, rgb); + } + else if (rotation == 3) + { + image.setRGB(drawX + 0, drawY + 3, rgb); + image.setRGB(drawX + 1, drawY + 3, rgb); + image.setRGB(drawX + 2, drawY + 3, rgb); + image.setRGB(drawX + 3, drawY + 3, rgb); + } + } + + if (type == 3) + { + if (rotation == 0) + { + image.setRGB(drawX + 0, drawY + 0, rgb); + } + else if (rotation == 1) + { + image.setRGB(drawX + 3, drawY + 0, rgb); + } + else if (rotation == 2) + { + image.setRGB(drawX + 3, drawY + 3, rgb); + } + else if (rotation == 3) + { + image.setRGB(drawX + 0, drawY + 3, rgb); + } + } + + if (type == 2) + { + if (rotation == 3) + { + image.setRGB(drawX + 0, drawY + 0, rgb); + image.setRGB(drawX + 0, drawY + 1, rgb); + image.setRGB(drawX + 0, drawY + 2, rgb); + image.setRGB(drawX + 0, drawY + 3, rgb); + } + else if (rotation == 0) + { + image.setRGB(drawX + 0, drawY + 0, rgb); + image.setRGB(drawX + 1, drawY + 0, rgb); + image.setRGB(drawX + 2, drawY + 0, rgb); + image.setRGB(drawX + 3, drawY + 0, rgb); + } + else if (rotation == 1) + { + image.setRGB(drawX + 3, drawY + 0, rgb); + image.setRGB(drawX + 3, drawY + 1, rgb); + image.setRGB(drawX + 3, drawY + 2, rgb); + image.setRGB(drawX + 3, drawY + 3, rgb); + } + else if (rotation == 2) + { + image.setRGB(drawX + 0, drawY + 3, rgb); + image.setRGB(drawX + 1, drawY + 3, rgb); + image.setRGB(drawX + 2, drawY + 3, rgb); + image.setRGB(drawX + 3, drawY + 3, rgb); + } + } + } + } + else if (type == 9) + { + if (object.getMapSceneID() != -1) + { + Image spriteImage = scaledMapIcons.get(object.getMapSceneID()); + graphics.drawImage(spriteImage, drawX, drawY, null); + continue; + } + + int hash = (localY << 7) + localX + (location.getId() << 14) + 0x4000_0000; + if (object.getAnInt2088() == 0) + { + hash -= Integer.MIN_VALUE; + } + + if ((hash >> 29 & 3) != 2) + { + continue; + } + + int rgb = 0xEE_EEEE; + if (hash > 0) + { + rgb = 0xEE_0000; + } + + if (rotation != 0 && rotation != 2) + { + image.setRGB(drawX + 0, drawY + 0, rgb); + image.setRGB(drawX + 1, drawY + 1, rgb); + image.setRGB(drawX + 2, drawY + 2, rgb); + image.setRGB(drawX + 3, drawY + 3, rgb); + } + else + { + image.setRGB(drawX + 0, drawY + 3, rgb); + image.setRGB(drawX + 1, drawY + 2, rgb); + image.setRGB(drawX + 2, drawY + 1, rgb); + image.setRGB(drawX + 3, drawY + 0, rgb); + } + } + else if (type == 22 || (type >= 9 && type <= 11)) + { + // ground object + if (object.getMapSceneID() != -1) + { + Image spriteImage = scaledMapIcons.get(object.getMapSceneID()); + graphics.drawImage(spriteImage, drawX, drawY, null); + } + } } + graphics.dispose(); + } + + private void drawObjects(BufferedImage image, int z) + { + for (Region region : regionLoader.getRegions()) + { + int baseX = region.getBaseX(); + int baseY = region.getBaseY(); + + // to pixel X + int drawBaseX = baseX - regionLoader.getLowestX().getBaseX(); + + // to pixel Y. top most y is 0, but the top most + // region has the greatest y, so invert + int drawBaseY = regionLoader.getHighestY().getBaseY() - baseY; + + drawObjects(image, drawBaseX, drawBaseY, region, z); + } + } + + private void drawMapIcons(BufferedImage image, int drawBaseX, int drawBaseY, Region region, int z) + { + int baseX = region.getBaseX(); + int baseY = region.getBaseY(); + + Graphics2D graphics = image.createGraphics(); + + drawMapIcons(graphics, region, z, drawBaseX, drawBaseY); + + if (labelRegions) + { + graphics.setColor(Color.WHITE); + String str = baseX + "," + baseY + " (" + region.getRegionX() + "," + region.getRegionY() + ")"; + graphics.drawString(str, 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(); + } + + private void drawMapIcons(BufferedImage image, int z) + { // map icons for (Region region : regionLoader.getRegions()) { @@ -154,135 +748,99 @@ public class MapImageDumper // region has the greatest y, so invert int drawBaseY = regionLoader.getHighestY().getBaseY() - baseY; - Graphics2D graphics = image.createGraphics(); - - drawMapIcons(graphics, region, z, drawBaseX, drawBaseY); - - if (labelRegions) - { - graphics.setColor(Color.WHITE); - String str = baseX + "," + baseY + " (" + region.getRegionX() + "," + region.getRegionY() + ")"; - graphics.drawString(str, 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(); + drawMapIcons(image, drawBaseX, drawBaseY, region, z); } - - return image; } - private void drawUnderlay(BufferedImage image, int z) + private ObjectDefinition findObject(int id) { - // pass 1 - for (Region region : regionLoader.getRegions()) - { - int baseX = region.getBaseX(); - int baseY = region.getBaseY(); - - // to pixel X - int drawBaseX = baseX - regionLoader.getLowestX().getBaseX(); - - // to pixel Y. top most y is 0, but the top most - // region has the greatest y, so invert - int drawBaseY = regionLoader.getHighestY().getBaseY() - baseY; - - 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 if (underlayId > -1) - { - UnderlayDefinition underlay = findUnderlay(underlayId); - rgb = underlay.getColor(); - } - - drawMapSquare(image, drawX, drawY, rgb); - } - } - } + return objectManager.getObject(id); } - private void drawOverlay(BufferedImage image, int z) + private int packHsl(int var0, int var1, int var2) { - for (Region region : regionLoader.getRegions()) + if (var2 > 179) { - int baseX = region.getBaseX(); - int baseY = region.getBaseY(); + var1 /= 2; + } - // to pixel X - int drawBaseX = baseX - regionLoader.getLowestX().getBaseX(); + if (var2 > 192) + { + var1 /= 2; + } - // to pixel Y. top most y is 0, but the top most - // region has the greatest y, so invert - int drawBaseY = regionLoader.getHighestY().getBaseY() - baseY; + if (var2 > 217) + { + var1 /= 2; + } - for (int x = 0; x < Region.X; ++x) + if (var2 > 243) + { + var1 /= 2; + } + + int var3 = (var1 / 32 << 7) + (var0 / 4 << 10) + var2 / 2; + return var3; + } + + static int method1792(int var0, int var1) + { + if (var0 == -1) + { + return 12345678; + } + else + { + var1 = (var0 & 127) * var1 / 128; + if (var1 < 2) { - 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; - - if (overlayId > -1) - { - OverlayDefinition overlay = findOverlay(overlayId); - - int rgb = 0; - if (overlay.isHideUnderlay()) - { - 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 = sprites.findSprite(texture.getFileIds()[0], 0); - assert sprite != null; - - rgb = averageColors.get(sprite); - } - - drawMapSquare(image, drawX, drawY, rgb); - } - } + var1 = 2; } + else if (var1 > 126) + { + var1 = 126; + } + + return (var0 & 65408) + var1; } } - private void drawMapSquare(BufferedImage image, int x, int y, int rgb) + static final int adjustHSLListness0(int var0, int var1) + { + if (var0 == -2) + { + return 12345678; + } + else if (var0 == -1) + { + if (var1 < 2) + { + var1 = 2; + } + else if (var1 > 126) + { + var1 = 126; + } + + return var1; + } + else + { + var1 = (var0 & 127) * var1 / 128; + if (var1 < 2) + { + var1 = 2; + } + else if (var1 > 126) + { + var1 = 126; + } + + return (var0 & 65408) + var1; + } + } + + private void drawMapSquare(int[][] pixels, int x, int y, int rgb) { x *= MAP_SCALE; y *= MAP_SCALE; @@ -291,35 +849,7 @@ public class MapImageDumper { for (int j = 0; j < MAP_SCALE; ++j) { - image.setRGB(x + i, y + j, rgb); - } - } - } - - private void drawObjects(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) - { - Image spriteImage = scaledMapIcons.get(od.getMapSceneID()); - graphics.drawImage(spriteImage, drawX * MAP_SCALE, drawY * MAP_SCALE, null); + pixels[x + i][y + j] = rgb; } } } @@ -328,7 +858,12 @@ public class MapImageDumper { for (Location location : region.getLocations()) { - // draw map icons from all planes + int localZ = location.getPosition().getZ(); + if (z != 0 && localZ != z) + { + // draw all icons on z=0 + continue; + } ObjectDefinition od = findObject(location.getId()); @@ -382,20 +917,13 @@ public class MapImageDumper UnderlayLoader loader = new UnderlayLoader(); UnderlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); - underlays.add(underlay); + underlays.put(underlay.getId(), underlay); } } private UnderlayDefinition findUnderlay(int id) { - for (UnderlayDefinition u : underlays) - { - if (u.getId() == id) - { - return u; - } - } - return null; + return underlays.get(id); } private void loadOverlays(Store store) throws IOException @@ -410,53 +938,15 @@ public class MapImageDumper for (FSFile file : files.getFiles()) { OverlayLoader loader = new OverlayLoader(); - OverlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); + OverlayDefinition overlay = loader.load(file.getFileId(), file.getContents()); - overlays.add(underlay); + overlays.put(overlay.getId(), overlay); } } private OverlayDefinition findOverlay(int id) { - for (OverlayDefinition u : overlays) - { - if (u.getId() == id) - { - return u; - } - } - return null; - } - - private void loadTextures(Store store) throws IOException - { - Storage storage = store.getStorage(); - Index index = store.getIndex(IndexType.TEXTURES); - Archive archive = index.getArchive(0); - - byte[] archiveData = storage.loadArchive(archive); - ArchiveFiles files = archive.getFiles(archiveData); - - for (FSFile file : files.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; + return overlays.get(id); } private void loadSprites() throws IOException @@ -479,8 +969,6 @@ public class MapImageDumper continue; } - averageColors.put(sprite, getAverageColor(sprite.getPixels())); - if (a.getNameHash() == mapsceneHash) { BufferedImage spriteImage = new BufferedImage(sprite.getWidth(), sprite.getHeight(), BufferedImage.TYPE_INT_ARGB); @@ -496,66 +984,4 @@ public class MapImageDumper } } - 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(); - } - - private void loadObjects(Store store) throws IOException - { - ObjectManager manager = new ObjectManager(store); - manager.load(); - for (ObjectDefinition def : manager.getObjects()) - { - objects.put(def.getId(), def); - } - } - - private ObjectDefinition findObject(int id) - { - return objects.get(id); - } - - 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/ObjectManager.java b/cache/src/main/java/net/runelite/cache/ObjectManager.java index a00177d9ae..95bf1cfdca 100644 --- a/cache/src/main/java/net/runelite/cache/ObjectManager.java +++ b/cache/src/main/java/net/runelite/cache/ObjectManager.java @@ -27,9 +27,10 @@ package net.runelite.cache; import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import net.runelite.cache.definitions.ObjectDefinition; import net.runelite.cache.definitions.exporters.ObjectExporter; import net.runelite.cache.definitions.loaders.ObjectLoader; @@ -44,7 +45,7 @@ import net.runelite.cache.util.Namer; public class ObjectManager { private final Store store; - private final List objects = new ArrayList<>(); + private final Map objects = new HashMap<>(); private final Namer namer = new Namer(); public ObjectManager(Store store) @@ -66,20 +67,25 @@ public class ObjectManager for (FSFile f : files.getFiles()) { ObjectDefinition def = loader.load(f.getFileId(), f.getContents()); - objects.add(def); + objects.put(f.getFileId(), def); } } - public List getObjects() + public Collection getObjects() { - return Collections.unmodifiableList(objects); + return Collections.unmodifiableCollection(objects.values()); + } + + public ObjectDefinition getObject(int id) + { + return objects.get(id); } public void dump(File out) throws IOException { out.mkdirs(); - for (ObjectDefinition def : objects) + for (ObjectDefinition def : objects.values()) { ObjectExporter exporter = new ObjectExporter(def); @@ -100,7 +106,7 @@ public class ObjectManager fw.println(""); fw.println("public final class ObjectID"); fw.println("{"); - for (ObjectDefinition def : objects) + for (ObjectDefinition def : objects.values()) { String name; if (def.getName().equalsIgnoreCase("NULL")) diff --git a/cache/src/main/java/net/runelite/cache/item/RSTextureProvider.java b/cache/src/main/java/net/runelite/cache/item/RSTextureProvider.java index 90296dfa70..a38f14dce3 100644 --- a/cache/src/main/java/net/runelite/cache/item/RSTextureProvider.java +++ b/cache/src/main/java/net/runelite/cache/item/RSTextureProvider.java @@ -28,7 +28,7 @@ import net.runelite.cache.definitions.TextureDefinition; import net.runelite.cache.definitions.providers.SpriteProvider; import net.runelite.cache.definitions.providers.TextureProvider; -class RSTextureProvider +public class RSTextureProvider { private final SpriteProvider spriteProvider; TextureDefinition[] textures; diff --git a/cache/src/main/java/net/runelite/cache/region/RegionLoader.java b/cache/src/main/java/net/runelite/cache/region/RegionLoader.java index cc346a9265..a15e25a868 100644 --- a/cache/src/main/java/net/runelite/cache/region/RegionLoader.java +++ b/cache/src/main/java/net/runelite/cache/region/RegionLoader.java @@ -25,8 +25,9 @@ package net.runelite.cache.region; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import net.runelite.cache.IndexType; import net.runelite.cache.definitions.LocationsDefinition; import net.runelite.cache.definitions.MapDefinition; @@ -50,7 +51,7 @@ public class RegionLoader private final Index index; private final XteaKeyManager keyManager; - private final List regions = new ArrayList<>(); + private final Map regions = new HashMap<>(); private Region lowestX = null, lowestY = null; private Region highestX = null, highestY = null; @@ -69,7 +70,7 @@ public class RegionLoader Region region = this.loadRegionFromArchive(i); if (region != null) { - regions.add(region); + regions.put(i, region); } } } @@ -117,7 +118,7 @@ public class RegionLoader public void calculateBounds() { - for (Region region : regions) + for (Region region : regions.values()) { if (lowestX == null || region.getBaseX() < lowestX.getBaseX()) { @@ -141,9 +142,16 @@ public class RegionLoader } } - public List getRegions() + public Collection getRegions() { - return regions; + return regions.values(); + } + + public Region findRegionForWorldCoordinates(int x, int y) + { + x >>>= 6; + y >>>= 6; + return regions.get((x << 8) | y); } public Region getLowestX() diff --git a/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java b/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java index b932dd3ddf..7491e54b58 100644 --- a/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/MapImageDumperTest.java @@ -30,6 +30,7 @@ import java.io.IOException; import javax.imageio.ImageIO; import net.runelite.cache.fs.Store; import net.runelite.cache.region.Region; +import net.runelite.cache.region.RegionLoader; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -46,7 +47,7 @@ public class MapImageDumperTest @Test @Ignore - public void extract() throws IOException + public void dumpMap() throws IOException { File base = StoreLocation.LOCATION, outDir = folder.newFolder(); @@ -69,4 +70,31 @@ public class MapImageDumperTest } } } + + @Test + @Ignore + public void dumpRegions() throws Exception + { + File base = StoreLocation.LOCATION, + outDir = folder.newFolder(); + + try (Store store = new Store(base)) + { + store.load(); + + RegionLoader regionLoader = new RegionLoader(store); + regionLoader.loadRegions(); + + MapImageDumper dumper = new MapImageDumper(store); + dumper.load(); + + int z = 0; + for (Region region : regionLoader.getRegions()) + { + File imageFile = new File(outDir, "img-" + z + "-" + region.getRegionID() + ".png"); + BufferedImage image = dumper.drawRegion(region, z); + ImageIO.write(image, "png", imageFile); + } + } + } }