Merge remote-tracking branch 'runelite/master'
This commit is contained in:
@@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import net.runelite.cache.fs.Store;
|
||||
import net.runelite.cache.region.Region;
|
||||
import net.runelite.cache.region.RegionLoader;
|
||||
import net.runelite.cache.util.KeyProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -48,9 +49,9 @@ public class HeightMapDumper
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public void load() throws IOException
|
||||
public void load(KeyProvider keyProvider) throws IOException
|
||||
{
|
||||
regionLoader = new RegionLoader(store);
|
||||
regionLoader = new RegionLoader(store, keyProvider);
|
||||
regionLoader.loadRegions();
|
||||
regionLoader.calculateBounds();
|
||||
}
|
||||
|
||||
@@ -27,23 +27,26 @@ package net.runelite.cache;
|
||||
|
||||
public enum IndexType
|
||||
{
|
||||
FRAMES(0),
|
||||
FRAMEMAPS(1),
|
||||
ANIMATIONS(0),
|
||||
SKELETONS(1),
|
||||
CONFIGS(2),
|
||||
INTERFACES(3),
|
||||
SOUNDEFFECTS(4),
|
||||
MAPS(5),
|
||||
TRACK1(6),
|
||||
MUSIC_TRACKS(6),
|
||||
MODELS(7),
|
||||
SPRITES(8),
|
||||
TEXTURES(9),
|
||||
BINARY(10),
|
||||
TRACK2(11),
|
||||
MUSIC_JINGLES(11),
|
||||
CLIENTSCRIPT(12),
|
||||
FONTS(13),
|
||||
VORBIS(14),
|
||||
INSTRUMENTS(15),
|
||||
WORLDMAP(16);
|
||||
MUSIC_SAMPLES(14),
|
||||
MUSIC_PATCHES(15),
|
||||
WORLDMAP_OLD(16), // looks unused
|
||||
WORLDMAP_GEOGRAPHY(18),
|
||||
WORLDMAP(19),
|
||||
WORLDMAP_GROUND(20);
|
||||
|
||||
private int id;
|
||||
|
||||
|
||||
@@ -26,13 +26,20 @@ package net.runelite.cache;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.imageio.ImageIO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.cache.definitions.AreaDefinition;
|
||||
import net.runelite.cache.definitions.ObjectDefinition;
|
||||
import net.runelite.cache.definitions.OverlayDefinition;
|
||||
@@ -47,39 +54,44 @@ 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.models.JagexColor;
|
||||
import net.runelite.cache.region.Location;
|
||||
import net.runelite.cache.region.Position;
|
||||
import net.runelite.cache.region.Region;
|
||||
import net.runelite.cache.region.RegionLoader;
|
||||
import net.runelite.cache.util.Djb2;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import net.runelite.cache.util.BigBufferedImage;
|
||||
import net.runelite.cache.util.KeyProvider;
|
||||
import net.runelite.cache.util.XteaKeyManager;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
|
||||
@Slf4j
|
||||
@Accessors(chain = true)
|
||||
public class MapImageDumper
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(MapImageDumper.class);
|
||||
|
||||
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[] colorPalette = JagexColor.createPalette(JagexColor.BRIGHTNESS_MIN);
|
||||
|
||||
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 int wallColor = (238 + (int) (random() * 20.0D) - 10 << 16) + (238 + (int) (random() * 20.0D) - 10 << 8) + (238 + (int) (random() * 20.0D) - 10);
|
||||
private final int doorColor = 238 + (int) (random() * 20.0D) - 10 << 16;
|
||||
|
||||
private final Store store;
|
||||
|
||||
private final Map<Integer, UnderlayDefinition> underlays = new HashMap<>();
|
||||
private final Map<Integer, OverlayDefinition> overlays = new HashMap<>();
|
||||
private final Map<Integer, Image> scaledMapIcons = new HashMap<>();
|
||||
private SpriteDefinition[] mapDecorations;
|
||||
|
||||
private RegionLoader regionLoader;
|
||||
private final RegionLoader regionLoader;
|
||||
private final AreaManager areas;
|
||||
private final SpriteManager sprites;
|
||||
private RSTextureProvider rsTextureProvider;
|
||||
@@ -93,15 +105,106 @@ public class MapImageDumper
|
||||
@Setter
|
||||
private boolean outlineRegions;
|
||||
|
||||
public MapImageDumper(Store store)
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean renderMap = true;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean renderObjects = true;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean renderIcons = true;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean transparency = false;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean lowMemory = true;
|
||||
|
||||
public MapImageDumper(Store store, KeyProvider keyProvider)
|
||||
{
|
||||
this.store = store;
|
||||
this.areas = new AreaManager(store);
|
||||
this.sprites = new SpriteManager(store);
|
||||
objectManager = new ObjectManager(store);
|
||||
this(store, new RegionLoader(store, keyProvider));
|
||||
}
|
||||
|
||||
public void load() throws IOException
|
||||
public MapImageDumper(Store store, RegionLoader regionLoader)
|
||||
{
|
||||
this.store = store;
|
||||
this.regionLoader = regionLoader;
|
||||
this.areas = new AreaManager(store);
|
||||
this.sprites = new SpriteManager(store);
|
||||
this.objectManager = new ObjectManager(store);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
Options options = new Options();
|
||||
options.addOption(Option.builder().longOpt("cachedir").hasArg().required().build());
|
||||
options.addOption(Option.builder().longOpt("xteapath").hasArg().required().build());
|
||||
options.addOption(Option.builder().longOpt("outputdir").hasArg().required().build());
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
CommandLine cmd;
|
||||
try
|
||||
{
|
||||
cmd = parser.parse(options, args);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
System.err.println("Error parsing command line options: " + ex.getMessage());
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final String cacheDirectory = cmd.getOptionValue("cachedir");
|
||||
final String xteaJSONPath = cmd.getOptionValue("xteapath");
|
||||
final String outputDirectory = cmd.getOptionValue("outputdir");
|
||||
|
||||
XteaKeyManager xteaKeyManager = new XteaKeyManager();
|
||||
try (FileInputStream fin = new FileInputStream(xteaJSONPath))
|
||||
{
|
||||
xteaKeyManager.loadKeys(fin);
|
||||
}
|
||||
|
||||
File base = new File(cacheDirectory);
|
||||
File outDir = new File(outputDirectory);
|
||||
outDir.mkdirs();
|
||||
|
||||
try (Store store = new Store(base))
|
||||
{
|
||||
store.load();
|
||||
|
||||
MapImageDumper dumper = new MapImageDumper(store, xteaKeyManager);
|
||||
dumper.load();
|
||||
|
||||
for (int i = 0; i < Region.Z; ++i)
|
||||
{
|
||||
BufferedImage image = dumper.drawMap(i);
|
||||
|
||||
File imageFile = new File(outDir, "img-" + i + ".png");
|
||||
|
||||
ImageIO.write(image, "png", imageFile);
|
||||
log.info("Wrote image {}", imageFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected double random()
|
||||
{
|
||||
// the client would use a random value here, but we prefer determinism
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public MapImageDumper setBrightness(double brightness)
|
||||
{
|
||||
colorPalette = JagexColor.createPalette(brightness);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MapImageDumper load() throws IOException
|
||||
{
|
||||
loadUnderlays(store);
|
||||
loadOverlays(store);
|
||||
@@ -111,10 +214,12 @@ public class MapImageDumper
|
||||
textureManager.load();
|
||||
rsTextureProvider = new RSTextureProvider(textureManager, sprites);
|
||||
|
||||
loadRegions(store);
|
||||
loadRegions();
|
||||
areas.load();
|
||||
sprites.load();
|
||||
loadSprites();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public BufferedImage drawMap(int z)
|
||||
@@ -131,11 +236,19 @@ public class MapImageDumper
|
||||
int pixelsX = dimX * MAP_SCALE;
|
||||
int pixelsY = dimY * MAP_SCALE;
|
||||
|
||||
logger.info("Map image dimensions: {}px x {}px, {}px per map square ({} MB). Max memory: {}mb", pixelsX, pixelsY,
|
||||
log.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(pixelsX, pixelsY, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage image;
|
||||
if (lowMemory)
|
||||
{
|
||||
image = BigBufferedImage.create(pixelsX, pixelsY, transparency ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = new BufferedImage(pixelsX, pixelsY, transparency ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
|
||||
}
|
||||
|
||||
drawMap(image, z);
|
||||
drawObjects(image, z);
|
||||
@@ -144,15 +257,35 @@ public class MapImageDumper
|
||||
return image;
|
||||
}
|
||||
|
||||
private void drawNeighborObjects(BufferedImage image, int rx, int ry, int dx, int dy, int z)
|
||||
{
|
||||
Region neighbor = regionLoader.findRegionForRegionCoordinates(rx + dx, ry + dy);
|
||||
if (neighbor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
drawObjects(image, Region.X * dx, Region.Y * -dy, neighbor, z);
|
||||
}
|
||||
|
||||
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);
|
||||
BufferedImage image = new BufferedImage(pixelsX, pixelsY, transparency ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
drawMap(image, 0, 0, z, region);
|
||||
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), -1, -1, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), -1, 0, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), -1, 1, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), 0, -1, z);
|
||||
drawObjects(image, 0, 0, region, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), 0, 1, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), 1, -1, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), 1, 0, z);
|
||||
drawNeighborObjects(image, region.getRegionX(), region.getRegionY(), 1, 1, z);
|
||||
drawMapIcons(image, 0, 0, region, z);
|
||||
|
||||
return image;
|
||||
@@ -160,31 +293,41 @@ public class MapImageDumper
|
||||
|
||||
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)
|
||||
if (!renderMap)
|
||||
{
|
||||
above = new int[Region.X * MAP_SCALE][Region.Y * MAP_SCALE];
|
||||
drawMap(above, region, z + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
int[][][] map = new int[4][][];
|
||||
|
||||
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))
|
||||
int tileZ = z + (isBridge ? 1 : 0);
|
||||
if (tileZ >= Region.Z)
|
||||
{
|
||||
drawTile(image, map, drawBaseX, drawBaseY, x, y);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z < 3 && isBridge) // client also has a check for &8 != 0 here
|
||||
int tileSetting = region.getTileSetting(z, x, Region.Y - y - 1);
|
||||
if ((tileSetting & 24) == 0)
|
||||
{
|
||||
drawTile(image, above, drawBaseX, drawBaseY, x, y);
|
||||
if (z == 0 && isBridge)
|
||||
{
|
||||
drawTile(image, map, region, drawBaseX, drawBaseY, 0, x, y);
|
||||
}
|
||||
drawTile(image, map, region, drawBaseX, drawBaseY, tileZ, x, y);
|
||||
}
|
||||
|
||||
if (tileZ < 3)
|
||||
{
|
||||
int upTileSetting = region.getTileSetting(z + 1, x, Region.Y - y - 1);
|
||||
if ((upTileSetting & 8) != 0)
|
||||
{
|
||||
drawTile(image, map, region, drawBaseX, drawBaseY, tileZ + 1, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,15 +351,27 @@ public class MapImageDumper
|
||||
}
|
||||
}
|
||||
|
||||
private void drawTile(BufferedImage to, int[][] pixels, int drawBaseX, int drawBaseY, int x, int y)
|
||||
private void drawTile(BufferedImage to, int[][][] planes, Region region, int drawBaseX, int drawBaseY, int z, int x, int y)
|
||||
{
|
||||
int[][] pixels = planes[z];
|
||||
|
||||
if (pixels == null)
|
||||
{
|
||||
pixels = planes[z] = new int[Region.X * MAP_SCALE][Region.Y * MAP_SCALE];
|
||||
drawMap(pixels, region, z);
|
||||
}
|
||||
|
||||
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]);
|
||||
int argb = pixels[x * MAP_SCALE + i][y * MAP_SCALE + j];
|
||||
if (argb != 0)
|
||||
{
|
||||
to.setRGB(drawBaseX * MAP_SCALE + x * MAP_SCALE + i,
|
||||
drawBaseY * MAP_SCALE + y * MAP_SCALE + j,
|
||||
argb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,11 +500,11 @@ public class MapImageDumper
|
||||
if (underlayHsl != -1)
|
||||
{
|
||||
int var0 = method1792(underlayHsl, 96);
|
||||
underlayRgb = colorPalette[var0];
|
||||
underlayRgb = colorPalette[var0] | 0xFF000000;
|
||||
}
|
||||
|
||||
int shape, rotation;
|
||||
Integer overlayRgb = null;
|
||||
int overlayRgb = 0;
|
||||
if (overlayId == 0)
|
||||
{
|
||||
shape = rotation = 0;
|
||||
@@ -361,28 +516,27 @@ public class MapImageDumper
|
||||
|
||||
OverlayDefinition overlayDefinition = findOverlay(overlayId - 1);
|
||||
int overlayTexture = overlayDefinition.getTexture();
|
||||
int rgb;
|
||||
int hsl;
|
||||
|
||||
if (overlayTexture >= 0)
|
||||
{
|
||||
rgb = rsTextureProvider.getAverageTextureRGB(overlayTexture);
|
||||
hsl = rsTextureProvider.getAverageTextureRGB(overlayTexture);
|
||||
}
|
||||
else if (overlayDefinition.getRgbColor() == 0xFF_00FF)
|
||||
{
|
||||
rgb = -2;
|
||||
hsl = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// randomness added here
|
||||
int overlayHsl = packHsl(overlayDefinition.getHue(), overlayDefinition.getSaturation(), overlayDefinition.getLightness());
|
||||
rgb = overlayHsl;
|
||||
hsl = overlayHsl;
|
||||
}
|
||||
|
||||
overlayRgb = 0;
|
||||
if (rgb != -2)
|
||||
if (hsl != -2)
|
||||
{
|
||||
int var0 = adjustHSLListness0(rgb, 96);
|
||||
overlayRgb = colorPalette[var0];
|
||||
int var0 = adjustHSLListness0(hsl, 96);
|
||||
overlayRgb = colorPalette[var0] | 0xFF000000;
|
||||
}
|
||||
|
||||
if (overlayDefinition.getSecondaryRgbColor() != -1)
|
||||
@@ -390,9 +544,9 @@ public class MapImageDumper
|
||||
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];
|
||||
hsl = packHsl(hue, sat, olight);
|
||||
int var0 = adjustHSLListness0(hsl, 96);
|
||||
overlayRgb = colorPalette[var0] | 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,208 +640,221 @@ public class MapImageDumper
|
||||
|
||||
private void drawObjects(BufferedImage image, int drawBaseX, int drawBaseY, Region region, int z)
|
||||
{
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
|
||||
for (Location location : region.getLocations())
|
||||
if (!renderObjects)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
List<Location> planeLocs = new ArrayList<>();
|
||||
List<Location> pushDownLocs = new ArrayList<>();
|
||||
List<List<Location>> layers = Arrays.asList(planeLocs, pushDownLocs);
|
||||
for (int localX = 0; localX < Region.X; localX++)
|
||||
{
|
||||
int regionX = localX + region.getBaseX();
|
||||
for (int localY = 0; localY < Region.Y; localY++)
|
||||
{
|
||||
if (!isBridge)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (location.getPosition().getZ() == z)
|
||||
{
|
||||
if (isBridge)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int regionY = localY + region.getBaseY();
|
||||
|
||||
if ((region.getTileSetting(z, localX, localY) & 24) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
planeLocs.clear();
|
||||
pushDownLocs.clear();
|
||||
boolean isBridge = (region.getTileSetting(1, localX, localY) & 2) != 0;
|
||||
int tileZ = z + (isBridge ? 1 : 0);
|
||||
|
||||
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.getWallOrDoor() == 0)
|
||||
for (Location loc : region.getLocations())
|
||||
{
|
||||
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)
|
||||
Position pos = loc.getPosition();
|
||||
if (pos.getX() != regionX || pos.getY() != regionY)
|
||||
{
|
||||
if (rotation == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pos.getZ() == tileZ && (region.getTileSetting(z, localX, localY) & 24) == 0)
|
||||
{
|
||||
planeLocs.add(loc);
|
||||
}
|
||||
else if (z < 3 && pos.getZ() == tileZ + 1 && (region.getTileSetting(z + 1, localX, localY) & 8) != 0)
|
||||
{
|
||||
pushDownLocs.add(loc);
|
||||
}
|
||||
}
|
||||
|
||||
for (List<Location> locs : layers)
|
||||
{
|
||||
for (Location location : locs)
|
||||
{
|
||||
int type = location.getType();
|
||||
if (type >= 0 && type <= 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 == 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);
|
||||
int rotation = location.getOrientation();
|
||||
|
||||
ObjectDefinition object = findObject(location.getId());
|
||||
|
||||
int drawX = (drawBaseX + localX) * MAP_SCALE;
|
||||
int drawY = (drawBaseY + (Region.Y - object.getSizeY() - localY)) * MAP_SCALE;
|
||||
|
||||
int rgb = wallColor;
|
||||
if (object.getWallOrDoor() != 0)
|
||||
{
|
||||
rgb = doorColor;
|
||||
}
|
||||
rgb |= 0xFF000000;
|
||||
|
||||
if (object.getMapSceneID() != -1)
|
||||
{
|
||||
blitMapDecoration(image, drawX, drawY, object);
|
||||
}
|
||||
else if (drawX >= 0 && drawY >= 0 && drawX < image.getWidth() && drawY < image.getHeight())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 3)
|
||||
for (Location location : locs)
|
||||
{
|
||||
if (rotation == 0)
|
||||
int type = location.getType();
|
||||
if (type == 9)
|
||||
{
|
||||
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);
|
||||
int rotation = location.getOrientation();
|
||||
|
||||
ObjectDefinition object = findObject(location.getId());
|
||||
|
||||
int drawX = (drawBaseX + localX) * MAP_SCALE;
|
||||
int drawY = (drawBaseY + (Region.Y - object.getSizeY() - localY)) * MAP_SCALE;
|
||||
|
||||
if (object.getMapSceneID() != -1)
|
||||
{
|
||||
blitMapDecoration(image, drawX, drawY, object);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drawX >= 0 && drawY >= 0 && drawX < image.getWidth() && drawY < image.getHeight())
|
||||
{
|
||||
int rgb = 0xFFEE_EEEE;
|
||||
if (object.getWallOrDoor() != 0)
|
||||
{
|
||||
rgb = 0xFFEE_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 2)
|
||||
for (Location location : locs)
|
||||
{
|
||||
if (rotation == 3)
|
||||
int type = location.getType();
|
||||
if (type == 22 || (type >= 9 && type <= 11))
|
||||
{
|
||||
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);
|
||||
ObjectDefinition object = findObject(location.getId());
|
||||
|
||||
int drawX = (drawBaseX + localX) * MAP_SCALE;
|
||||
int drawY = (drawBaseY + (Region.Y - object.getSizeY() - localY)) * MAP_SCALE;
|
||||
|
||||
if (object.getMapSceneID() != -1)
|
||||
{
|
||||
blitMapDecoration(image, drawX, drawY, object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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.getWallOrDoor() == 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)
|
||||
@@ -715,7 +882,7 @@ public class MapImageDumper
|
||||
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
|
||||
drawMapIcons(graphics, region, z, drawBaseX, drawBaseY);
|
||||
drawMapIcons(image, region, z, drawBaseX, drawBaseY);
|
||||
|
||||
if (labelRegions)
|
||||
{
|
||||
@@ -854,12 +1021,22 @@ public class MapImageDumper
|
||||
}
|
||||
}
|
||||
|
||||
private void drawMapIcons(Graphics2D graphics, Region region, int z, int drawBaseX, int drawBaseY)
|
||||
private void drawMapIcons(BufferedImage img, Region region, int z, int drawBaseX, int drawBaseY)
|
||||
{
|
||||
if (!renderIcons)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Location location : region.getLocations())
|
||||
{
|
||||
int localX = location.getPosition().getX() - region.getBaseX();
|
||||
int localY = location.getPosition().getY() - region.getBaseY();
|
||||
boolean isBridge = (region.getTileSetting(1, localX, localY) & 2) != 0;
|
||||
|
||||
int tileZ = z + (isBridge ? 1 : 0);
|
||||
int localZ = location.getPosition().getZ();
|
||||
if (z != 0 && localZ != z)
|
||||
if (z != 0 && localZ != tileZ)
|
||||
{
|
||||
// draw all icons on z=0
|
||||
continue;
|
||||
@@ -869,9 +1046,6 @@ public class MapImageDumper
|
||||
|
||||
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);
|
||||
|
||||
@@ -880,27 +1054,26 @@ public class MapImageDumper
|
||||
AreaDefinition area = areas.getArea(od.getMapAreaId());
|
||||
assert area != null;
|
||||
|
||||
int spriteId = area.spriteId;
|
||||
|
||||
SpriteDefinition sprite = sprites.findSprite(spriteId, 0);
|
||||
SpriteDefinition sprite = sprites.findSprite(area.spriteId, 0);
|
||||
assert sprite != null;
|
||||
|
||||
BufferedImage iconImage = sprites.getSpriteImage(sprite);
|
||||
graphics.drawImage(iconImage, drawX * MAP_SCALE, drawY * MAP_SCALE, null);
|
||||
blitIcon(img,
|
||||
2 + (drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
|
||||
2 + (drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
|
||||
sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadRegions(Store store) throws IOException
|
||||
private void loadRegions() throws IOException
|
||||
{
|
||||
regionLoader = new RegionLoader(store);
|
||||
regionLoader.loadRegions();
|
||||
regionLoader.calculateBounds();
|
||||
|
||||
logger.info("North most region: {}", regionLoader.getLowestY().getBaseY());
|
||||
logger.info("South most region: {}", regionLoader.getHighestY().getBaseY());
|
||||
logger.info("West most region: {}", regionLoader.getLowestX().getBaseX());
|
||||
logger.info("East most region: {}", regionLoader.getHighestX().getBaseX());
|
||||
log.debug("North most region: {}", regionLoader.getLowestY().getBaseY());
|
||||
log.debug("South most region: {}", regionLoader.getHighestY().getBaseY());
|
||||
log.debug("West most region: {}", regionLoader.getLowestX().getBaseX());
|
||||
log.debug("East most region: {}", regionLoader.getHighestX().getBaseX());
|
||||
}
|
||||
|
||||
private void loadUnderlays(Store store) throws IOException
|
||||
@@ -953,35 +1126,42 @@ public class MapImageDumper
|
||||
{
|
||||
Storage storage = store.getStorage();
|
||||
Index index = store.getIndex(IndexType.SPRITES);
|
||||
final int mapsceneHash = Djb2.hash("mapscene");
|
||||
Archive a = index.findArchiveByName("mapscene");
|
||||
byte[] contents = a.decompress(storage.loadArchive(a));
|
||||
|
||||
for (Archive a : index.getArchives())
|
||||
SpriteLoader loader = new SpriteLoader();
|
||||
mapDecorations = loader.load(a.getArchiveId(), contents);
|
||||
}
|
||||
|
||||
private void blitMapDecoration(BufferedImage dst, int x, int y, ObjectDefinition object)
|
||||
{
|
||||
SpriteDefinition sprite = mapDecorations[object.getMapSceneID()];
|
||||
int ox = (object.getSizeX() * MAP_SCALE - sprite.getWidth()) / 2;
|
||||
int oy = (object.getSizeY() * MAP_SCALE - sprite.getHeight()) / 2;
|
||||
blitIcon(dst, x + ox, y + oy, sprite);
|
||||
}
|
||||
|
||||
private void blitIcon(BufferedImage dst, int x, int y, SpriteDefinition sprite)
|
||||
{
|
||||
x += sprite.getOffsetX();
|
||||
y += sprite.getOffsetY();
|
||||
|
||||
int ymin = Math.max(0, -y);
|
||||
int ymax = Math.min(sprite.getHeight(), dst.getHeight() - y);
|
||||
|
||||
int xmin = Math.max(0, -x);
|
||||
int xmax = Math.min(sprite.getWidth(), dst.getWidth() - x);
|
||||
|
||||
for (int yo = ymin; yo < ymax; yo++)
|
||||
{
|
||||
byte[] contents = a.decompress(storage.loadArchive(a));
|
||||
|
||||
SpriteLoader loader = new SpriteLoader();
|
||||
SpriteDefinition[] sprites = loader.load(a.getArchiveId(), contents);
|
||||
|
||||
for (SpriteDefinition sprite : sprites)
|
||||
for (int xo = xmin; xo < xmax; xo++)
|
||||
{
|
||||
if (sprite.getHeight() <= 0 || sprite.getWidth() <= 0)
|
||||
int rgb = sprite.getPixels()[xo + (yo * sprite.getWidth())];
|
||||
if (rgb != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a.getNameHash() == mapsceneHash)
|
||||
{
|
||||
BufferedImage spriteImage = new BufferedImage(sprite.getWidth(), sprite.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
spriteImage.setRGB(0, 0, sprite.getWidth(), sprite.getHeight(), sprite.getPixels(), 0, sprite.getWidth());
|
||||
|
||||
// scale image down so it fits
|
||||
Image scaledImage = spriteImage.getScaledInstance(MAPICON_MAX_WIDTH, MAPICON_MAX_HEIGHT, 0);
|
||||
|
||||
assert scaledMapIcons.containsKey(sprite.getFrame()) == false;
|
||||
scaledMapIcons.put(sprite.getFrame(), scaledImage);
|
||||
dst.setRGB(x + xo, y + yo, rgb | 0xFF000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
package net.runelite.cache.item;
|
||||
|
||||
import net.runelite.cache.models.JagexColor;
|
||||
|
||||
class Graphics3D extends Rasterizer2D
|
||||
{
|
||||
private static final double UNIT = Math.PI / 1024d; // How much of the circle each unit of SINE/COSINE is
|
||||
@@ -132,9 +134,9 @@ class Graphics3D extends Rasterizer2D
|
||||
Rasterizer3D_clipMidY2 = Rasterizer3D_clipHeight - centerY;
|
||||
}
|
||||
|
||||
public final void setBrightness(double var0)
|
||||
public final void setBrightness(double brightness)
|
||||
{
|
||||
colorPalette = new ColorPalette(var0, 0, 512).getColorPalette();
|
||||
colorPalette = JagexColor.createPalette(brightness);
|
||||
}
|
||||
|
||||
final void rasterGouraud(int var0, int var1, int var2, int var3, int var4, int var5, int var6, int var7, int var8)
|
||||
|
||||
@@ -33,6 +33,7 @@ import net.runelite.cache.definitions.providers.ModelProvider;
|
||||
import net.runelite.cache.definitions.providers.SpriteProvider;
|
||||
import net.runelite.cache.definitions.providers.TextureProvider;
|
||||
import net.runelite.cache.models.FaceNormal;
|
||||
import net.runelite.cache.models.JagexColor;
|
||||
import net.runelite.cache.models.VertexNormal;
|
||||
|
||||
public class ItemSpriteFactory
|
||||
@@ -111,7 +112,7 @@ public class ItemSpriteFactory
|
||||
|
||||
Sprite spritePixels = new Sprite(36, 32);
|
||||
Graphics3D graphics = new Graphics3D(rsTextureProvider);
|
||||
graphics.setBrightness(0.6d);
|
||||
graphics.setBrightness(JagexColor.BRIGHTNESS_MAX);
|
||||
graphics.setRasterBuffer(spritePixels.pixels, 36, 32);
|
||||
graphics.reset();
|
||||
graphics.setRasterClipping();
|
||||
|
||||
@@ -29,7 +29,7 @@ public final class JagexColor
|
||||
public static final double BRIGHTNESS_MAX = .6;
|
||||
public static final double BRIGHTNESS_HIGH = .7;
|
||||
public static final double BRIGHTNESS_LOW = .8;
|
||||
public static final double BRIGTHNESS_MIN = .9;
|
||||
public static final double BRIGHTNESS_MIN = .9;
|
||||
|
||||
private static final double HUE_OFFSET = (.5 / 64.D);
|
||||
private static final double SATURATION_OFFSET = (.5 / 8.D);
|
||||
@@ -133,4 +133,14 @@ public final class JagexColor
|
||||
| ((int) (g * 256.0D) << 8)
|
||||
| (int) (b * 256.0D);
|
||||
}
|
||||
|
||||
public static int[] createPalette(double brightness)
|
||||
{
|
||||
int[] colorPalette = new int[65536];
|
||||
for (int i = 0; i < colorPalette.length; i++)
|
||||
{
|
||||
colorPalette[i] = HSLtoRGB((short) i, brightness);
|
||||
}
|
||||
return colorPalette;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import net.runelite.cache.definitions.TextureDefinition;
|
||||
|
||||
public class ObjExporter
|
||||
{
|
||||
private static final double BRIGHTNESS = JagexColor.BRIGTHNESS_MIN;
|
||||
private static final double BRIGHTNESS = JagexColor.BRIGHTNESS_MIN;
|
||||
|
||||
private final TextureManager textureManager;
|
||||
private final ModelDefinition model;
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.cache.IndexType;
|
||||
import net.runelite.cache.definitions.LocationsDefinition;
|
||||
import net.runelite.cache.definitions.MapDefinition;
|
||||
@@ -37,39 +38,44 @@ import net.runelite.cache.fs.Archive;
|
||||
import net.runelite.cache.fs.Index;
|
||||
import net.runelite.cache.fs.Storage;
|
||||
import net.runelite.cache.fs.Store;
|
||||
import net.runelite.cache.util.XteaKeyManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import net.runelite.cache.util.KeyProvider;
|
||||
|
||||
@Slf4j
|
||||
public class RegionLoader
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(RegionLoader.class);
|
||||
|
||||
private static final int MAX_REGION = 32768;
|
||||
|
||||
private final Store store;
|
||||
private final Index index;
|
||||
private final XteaKeyManager keyManager;
|
||||
private final KeyProvider keyProvider;
|
||||
|
||||
private final Map<Integer, Region> regions = new HashMap<>();
|
||||
private Region lowestX = null, lowestY = null;
|
||||
private Region highestX = null, highestY = null;
|
||||
|
||||
public RegionLoader(Store store)
|
||||
public RegionLoader(Store store, KeyProvider keyProvider)
|
||||
{
|
||||
this.store = store;
|
||||
index = store.getIndex(IndexType.MAPS);
|
||||
keyManager = new XteaKeyManager();
|
||||
this.keyProvider = keyProvider;
|
||||
}
|
||||
|
||||
public void loadRegions() throws IOException
|
||||
{
|
||||
if (!this.regions.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_REGION; ++i)
|
||||
{
|
||||
Region region = this.loadRegionFromArchive(i);
|
||||
if (region != null)
|
||||
try
|
||||
{
|
||||
regions.put(i, region);
|
||||
this.loadRegionFromArchive(i);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.debug("Can't decrypt region " + i, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,25 +103,31 @@ public class RegionLoader
|
||||
Region region = new Region(i);
|
||||
region.loadTerrain(mapDef);
|
||||
|
||||
Integer[] keysTmp = keyManager.getKeys(i);
|
||||
if (keysTmp != null)
|
||||
int[] keys = keyProvider.getKey(i);
|
||||
if (keys != null)
|
||||
{
|
||||
int[] keys = {keysTmp[0], keysTmp[1], keysTmp[2], keysTmp[3]};
|
||||
try
|
||||
{
|
||||
data = land.decompress(storage.loadArchive(land), keys);
|
||||
LocationsDefinition locDef = new LocationsLoader().load(x, y, data);
|
||||
region.loadLocations(locDef);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.debug("Can't decrypt region " + i, ex);
|
||||
}
|
||||
data = land.decompress(storage.loadArchive(land), keys);
|
||||
LocationsDefinition locDef = new LocationsLoader().load(x, y, data);
|
||||
region.loadLocations(locDef);
|
||||
}
|
||||
|
||||
regions.put(i, region);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
public Region loadRegion(int id, MapDefinition map, LocationsDefinition locs)
|
||||
{
|
||||
Region r = new Region(id);
|
||||
r.loadTerrain(map);
|
||||
if (locs != null)
|
||||
{
|
||||
r.loadLocations(locs);
|
||||
}
|
||||
regions.put(id, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public void calculateBounds()
|
||||
{
|
||||
for (Region region : regions.values())
|
||||
@@ -154,6 +166,11 @@ public class RegionLoader
|
||||
return regions.get((x << 8) | y);
|
||||
}
|
||||
|
||||
public Region findRegionForRegionCoordinates(int x, int y)
|
||||
{
|
||||
return regions.get((x << 8) | y);
|
||||
}
|
||||
|
||||
public Region getLowestX()
|
||||
{
|
||||
return lowestX;
|
||||
@@ -173,4 +190,4 @@ public class RegionLoader
|
||||
{
|
||||
return highestY;
|
||||
}
|
||||
}
|
||||
}
|
||||
346
cache/src/main/java/net/runelite/cache/util/BigBufferedImage.java
vendored
Normal file
346
cache/src/main/java/net/runelite/cache/util/BigBufferedImage.java
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
package net.runelite.cache.util;
|
||||
|
||||
/*
|
||||
* This class is part of MCFS (Mission Control - Flight Software) a development
|
||||
* of Team Puli Space, official Google Lunar XPRIZE contestant.
|
||||
* This class is released under Creative Commons CC0.
|
||||
* @author Zsolt Pocze, Dimitry Polivaev
|
||||
* Please like us on facebook, and/or join our Small Step Club.
|
||||
* http://www.pulispace.com
|
||||
* https://www.facebook.com/pulispace
|
||||
* http://nyomdmegteis.hu/en/
|
||||
*/
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BandedSampleModel;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class BigBufferedImage extends BufferedImage
|
||||
{
|
||||
private static final String TMP_DIR = System.getProperty("java.io.tmpdir");
|
||||
private static final int MAX_PIXELS_IN_MEMORY = 1024 * 1024;
|
||||
|
||||
public static BufferedImage create(int width, int height, int imageType)
|
||||
{
|
||||
if (width * height > MAX_PIXELS_IN_MEMORY)
|
||||
{
|
||||
try
|
||||
{
|
||||
final File tempDir = new File(TMP_DIR);
|
||||
return createBigBufferedImage(tempDir, width, height, imageType);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BufferedImage(width, height, imageType);
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage create(File inputFile, int imageType) throws IOException
|
||||
{
|
||||
try (ImageInputStream stream = ImageIO.createImageInputStream(inputFile))
|
||||
{
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
|
||||
if (readers.hasNext())
|
||||
{
|
||||
try
|
||||
{
|
||||
ImageReader reader = readers.next();
|
||||
reader.setInput(stream, true, true);
|
||||
int width = reader.getWidth(reader.getMinIndex());
|
||||
int height = reader.getHeight(reader.getMinIndex());
|
||||
BufferedImage image = create(width, height, imageType);
|
||||
int cores = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
|
||||
int block = Math.min(MAX_PIXELS_IN_MEMORY / cores / width, (int) (Math.ceil(height / (double) cores)));
|
||||
ExecutorService generalExecutor = Executors.newFixedThreadPool(cores);
|
||||
List<Callable<ImagePartLoader>> partLoaders = new ArrayList<>();
|
||||
for (int y = 0; y < height; y += block)
|
||||
{
|
||||
partLoaders.add(new ImagePartLoader(
|
||||
y, width, Math.min(block, height - y), inputFile, image));
|
||||
}
|
||||
generalExecutor.invokeAll(partLoaders);
|
||||
generalExecutor.shutdown();
|
||||
return image;
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
log.error(null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static BufferedImage createBigBufferedImage(File tempDir, int width, int height, int imageType)
|
||||
throws IOException
|
||||
{
|
||||
FileDataBuffer buffer = new FileDataBuffer(tempDir, width * height, 4);
|
||||
ColorModel colorModel;
|
||||
BandedSampleModel sampleModel;
|
||||
switch (imageType)
|
||||
{
|
||||
case TYPE_INT_RGB:
|
||||
colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
new int[]{8, 8, 8, 0},
|
||||
false,
|
||||
false,
|
||||
ComponentColorModel.TRANSLUCENT,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
sampleModel = new BandedSampleModel(DataBuffer.TYPE_BYTE, width, height, 3);
|
||||
break;
|
||||
case TYPE_INT_ARGB:
|
||||
colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
new int[]{8, 8, 8, 8},
|
||||
true,
|
||||
false,
|
||||
ComponentColorModel.TRANSLUCENT,
|
||||
DataBuffer.TYPE_BYTE);
|
||||
sampleModel = new BandedSampleModel(DataBuffer.TYPE_BYTE, width, height, 4);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported image type: " + imageType);
|
||||
}
|
||||
SimpleRaster raster = new SimpleRaster(sampleModel, buffer, new Point(0, 0));
|
||||
BigBufferedImage image = new BigBufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
|
||||
return image;
|
||||
}
|
||||
|
||||
private static class ImagePartLoader implements Callable<ImagePartLoader>
|
||||
{
|
||||
private final int y;
|
||||
private final BufferedImage image;
|
||||
private final Rectangle region;
|
||||
private final File file;
|
||||
|
||||
public ImagePartLoader(int y, int width, int height, File file, BufferedImage image)
|
||||
{
|
||||
this.y = y;
|
||||
this.image = image;
|
||||
this.file = file;
|
||||
region = new Rectangle(0, y, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImagePartLoader call() throws Exception
|
||||
{
|
||||
Thread.currentThread().setPriority((Thread.MIN_PRIORITY + Thread.NORM_PRIORITY) / 2);
|
||||
try (ImageInputStream stream = ImageIO.createImageInputStream(file);)
|
||||
{
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
|
||||
if (readers.hasNext())
|
||||
{
|
||||
ImageReader reader = readers.next();
|
||||
reader.setInput(stream, true, true);
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setSourceRegion(region);
|
||||
BufferedImage part = reader.read(0, param);
|
||||
Raster source = part.getRaster();
|
||||
WritableRaster target = image.getRaster();
|
||||
target.setRect(0, y, source);
|
||||
}
|
||||
}
|
||||
return ImagePartLoader.this;
|
||||
}
|
||||
}
|
||||
|
||||
private BigBufferedImage(ColorModel cm, SimpleRaster raster, boolean isRasterPremultiplied, Hashtable<?, ?> properties)
|
||||
{
|
||||
super(cm, raster, isRasterPremultiplied, properties);
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
((SimpleRaster) getRaster()).dispose();
|
||||
}
|
||||
|
||||
public static void dispose(RenderedImage image)
|
||||
{
|
||||
if (image instanceof BigBufferedImage)
|
||||
{
|
||||
((BigBufferedImage) image).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimpleRaster extends WritableRaster
|
||||
{
|
||||
public SimpleRaster(SampleModel sampleModel, FileDataBuffer dataBuffer, Point origin)
|
||||
{
|
||||
super(sampleModel, dataBuffer, origin);
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
((FileDataBuffer) getDataBuffer()).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FileDataBufferDeleterHook extends Thread
|
||||
{
|
||||
static
|
||||
{
|
||||
Runtime.getRuntime().addShutdownHook(new FileDataBufferDeleterHook());
|
||||
}
|
||||
|
||||
private static final HashSet<FileDataBuffer> undisposedBuffers = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final FileDataBuffer[] buffers = undisposedBuffers.toArray(new FileDataBuffer[0]);
|
||||
for (FileDataBuffer b : buffers)
|
||||
{
|
||||
b.disposeNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileDataBuffer extends DataBuffer
|
||||
{
|
||||
private final String id = "buffer-" + System.currentTimeMillis() + "-" + ((int) (Math.random() * 1000));
|
||||
private File dir;
|
||||
private String path;
|
||||
private File[] files;
|
||||
private RandomAccessFile[] accessFiles;
|
||||
private MappedByteBuffer[] buffer;
|
||||
|
||||
public FileDataBuffer(File dir, int size) throws IOException
|
||||
{
|
||||
super(TYPE_BYTE, size);
|
||||
this.dir = dir;
|
||||
init();
|
||||
}
|
||||
|
||||
public FileDataBuffer(File dir, int size, int numBanks) throws IOException
|
||||
{
|
||||
super(TYPE_BYTE, size, numBanks);
|
||||
this.dir = dir;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() throws IOException
|
||||
{
|
||||
FileDataBufferDeleterHook.undisposedBuffers.add(this);
|
||||
if (dir == null)
|
||||
{
|
||||
dir = new File(".");
|
||||
}
|
||||
if (!dir.exists())
|
||||
{
|
||||
throw new RuntimeException("FileDataBuffer constructor parameter dir does not exist: " + dir);
|
||||
}
|
||||
if (!dir.isDirectory())
|
||||
{
|
||||
throw new RuntimeException("FileDataBuffer constructor parameter dir is not a directory: " + dir);
|
||||
}
|
||||
path = dir.getPath() + "/" + id;
|
||||
File subDir = new File(path);
|
||||
subDir.mkdir();
|
||||
buffer = new MappedByteBuffer[banks];
|
||||
accessFiles = new RandomAccessFile[banks];
|
||||
files = new File[banks];
|
||||
for (int i = 0; i < banks; i++)
|
||||
{
|
||||
File file = files[i] = new File(path + "/bank" + i + ".dat");
|
||||
final RandomAccessFile randomAccessFile = accessFiles[i] = new RandomAccessFile(file, "rw");
|
||||
buffer[i] = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, getSize());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getElem(int bank, int i)
|
||||
{
|
||||
return buffer[bank].get(i) & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setElem(int bank, int i, int val)
|
||||
{
|
||||
buffer[bank].put(i, (byte) val);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
disposeNow();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void disposeNow()
|
||||
{
|
||||
this.buffer = null;
|
||||
if (accessFiles != null)
|
||||
{
|
||||
for (RandomAccessFile file : accessFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
file.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
accessFiles = null;
|
||||
}
|
||||
if (files != null)
|
||||
{
|
||||
for (File file : files)
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
files = null;
|
||||
}
|
||||
if (path != null)
|
||||
{
|
||||
new File(path).delete();
|
||||
path = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
30
cache/src/main/java/net/runelite/cache/util/KeyProvider.java
vendored
Normal file
30
cache/src/main/java/net/runelite/cache/util/KeyProvider.java
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Abex
|
||||
* 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.util;
|
||||
|
||||
public interface KeyProvider
|
||||
{
|
||||
int[] getKey(int region);
|
||||
}
|
||||
34
cache/src/main/java/net/runelite/cache/util/XteaKey.java
vendored
Normal file
34
cache/src/main/java/net/runelite/cache/util/XteaKey.java
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Adam <Adam@sigterm.info>
|
||||
* 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.util;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XteaKey
|
||||
{
|
||||
private int region;
|
||||
private int keys[];
|
||||
}
|
||||
@@ -24,25 +24,40 @@
|
||||
*/
|
||||
package net.runelite.cache.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class XteaKeyManager
|
||||
public class XteaKeyManager implements KeyProvider
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(XteaKeyManager.class);
|
||||
|
||||
private Map<Integer, Integer[]> keys = new HashMap<>();
|
||||
private final Map<Integer, int[]> keys = new HashMap<>();
|
||||
|
||||
public void loadKeys()
|
||||
public void loadKeys(InputStream in)
|
||||
{
|
||||
keys = null;
|
||||
// CHECKSTYLE:OFF
|
||||
List<XteaKey> k = new Gson()
|
||||
.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), new TypeToken<List<XteaKey>>() { }.getType());
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
for (XteaKey key : k)
|
||||
{
|
||||
keys.put(key.getRegion(), key.getKeys());
|
||||
}
|
||||
|
||||
logger.info("Loaded {} keys", keys.size());
|
||||
}
|
||||
|
||||
public Integer[] getKeys(int region)
|
||||
@Override
|
||||
public int[] getKey(int region)
|
||||
{
|
||||
return keys.get(region);
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ public class FrameDumper
|
||||
store.load();
|
||||
|
||||
Storage storage = store.getStorage();
|
||||
Index frameIndex = store.getIndex(IndexType.FRAMES);
|
||||
Index framemapIndex = store.getIndex(IndexType.FRAMEMAPS);
|
||||
Index frameIndex = store.getIndex(IndexType.ANIMATIONS);
|
||||
Index framemapIndex = store.getIndex(IndexType.SKELETONS);
|
||||
|
||||
for (Archive archive : frameIndex.getArchives())
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ public class FramemapDumper
|
||||
store.load();
|
||||
|
||||
Storage storage = store.getStorage();
|
||||
Index index = store.getIndex(IndexType.FRAMEMAPS);
|
||||
Index index = store.getIndex(IndexType.SKELETONS);
|
||||
|
||||
for (Archive archive : index.getArchives())
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ public class HeightMapDumperTest
|
||||
store.load();
|
||||
|
||||
HeightMapDumper dumper = new HeightMapDumper(store);
|
||||
dumper.load();
|
||||
dumper.load(null);
|
||||
|
||||
BufferedImage image = dumper.drawHeightMap(0);
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ public class MapDumperTest
|
||||
File base = StoreLocation.LOCATION,
|
||||
outDir = folder.newFolder();
|
||||
XteaKeyManager keyManager = new XteaKeyManager();
|
||||
keyManager.loadKeys();
|
||||
|
||||
try (Store store = new Store(base))
|
||||
{
|
||||
@@ -76,7 +75,7 @@ public class MapDumperTest
|
||||
|
||||
for (int i = 0; i < MAX_REGIONS; i++)
|
||||
{
|
||||
Integer[] keysTmp = keyManager.getKeys(i);
|
||||
int[] keys = keyManager.getKey(i);
|
||||
|
||||
int x = i >> 8;
|
||||
int y = i & 0xFF;
|
||||
@@ -95,9 +94,8 @@ public class MapDumperTest
|
||||
|
||||
Files.write(data, new File(outDir, "m" + x + "_" + y + ".dat"));
|
||||
|
||||
if (keysTmp != null)
|
||||
if (keys != null)
|
||||
{
|
||||
int[] keys = {keysTmp[0], keysTmp[1], keysTmp[2], keysTmp[3]};
|
||||
try
|
||||
{
|
||||
data = land.decompress(storage.loadArchive(land), keys);
|
||||
@@ -122,7 +120,6 @@ public class MapDumperTest
|
||||
Storage storage = store.getStorage();
|
||||
Index index = store.getIndex(IndexType.MAPS);
|
||||
XteaKeyManager keyManager = new XteaKeyManager();
|
||||
keyManager.loadKeys();
|
||||
|
||||
for (int i = 0; i < MAX_REGIONS; ++i)
|
||||
{
|
||||
@@ -143,10 +140,9 @@ public class MapDumperTest
|
||||
MapDefinition mapDef = new MapLoader().load(x, y, data);
|
||||
LocationsDefinition locDef = null;
|
||||
|
||||
Integer[] keysTmp = keyManager.getKeys(i);
|
||||
if (keysTmp != null)
|
||||
int[] keys = keyManager.getKey(i);
|
||||
if (keys != null)
|
||||
{
|
||||
int[] keys = {keysTmp[0], keysTmp[1], keysTmp[2], keysTmp[3]};
|
||||
try
|
||||
{
|
||||
data = land.decompress(storage.loadArchive(land), keys);
|
||||
|
||||
@@ -31,6 +31,7 @@ import javax.imageio.ImageIO;
|
||||
import net.runelite.cache.fs.Store;
|
||||
import net.runelite.cache.region.Region;
|
||||
import net.runelite.cache.region.RegionLoader;
|
||||
import net.runelite.cache.util.XteaKeyManager;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -56,7 +57,10 @@ public class MapImageDumperTest
|
||||
{
|
||||
store.load();
|
||||
|
||||
MapImageDumper dumper = new MapImageDumper(store);
|
||||
XteaKeyManager keyManager = new XteaKeyManager();
|
||||
keyManager.loadKeys(null);
|
||||
|
||||
MapImageDumper dumper = new MapImageDumper(store, keyManager);
|
||||
dumper.load();
|
||||
|
||||
for (int i = 0; i < Region.Z; ++i)
|
||||
@@ -82,10 +86,13 @@ public class MapImageDumperTest
|
||||
{
|
||||
store.load();
|
||||
|
||||
RegionLoader regionLoader = new RegionLoader(store);
|
||||
XteaKeyManager keyManager = new XteaKeyManager();
|
||||
keyManager.loadKeys(null);
|
||||
|
||||
RegionLoader regionLoader = new RegionLoader(store, keyManager);
|
||||
regionLoader.loadRegions();
|
||||
|
||||
MapImageDumper dumper = new MapImageDumper(store);
|
||||
MapImageDumper dumper = new MapImageDumper(store, regionLoader);
|
||||
dumper.load();
|
||||
|
||||
int z = 0;
|
||||
|
||||
@@ -67,8 +67,8 @@ public class TrackDumperTest
|
||||
store.load();
|
||||
|
||||
Storage storage = store.getStorage();
|
||||
Index index = store.getIndex(IndexType.TRACK1);
|
||||
Index index2 = store.getIndex(IndexType.TRACK2);
|
||||
Index index = store.getIndex(IndexType.MUSIC_TRACKS);
|
||||
Index index2 = store.getIndex(IndexType.MUSIC_JINGLES);
|
||||
|
||||
for (Archive archive : index.getArchives())
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ public class WorldMapDumperTest
|
||||
store.load();
|
||||
|
||||
Storage storage = store.getStorage();
|
||||
Index index = store.getIndex(IndexType.WORLDMAP);
|
||||
Index index = store.getIndex(IndexType.WORLDMAP_OLD);
|
||||
Archive archive = index.getArchive(0); // there is also archive 1/2, but their data format is not this
|
||||
|
||||
byte[] archiveData = storage.loadArchive(archive);
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.junit.Test;
|
||||
public class JagexColorTest
|
||||
{
|
||||
private static final double[] BRIGHTNESS_LEVELS = {
|
||||
JagexColor.BRIGTHNESS_MIN,
|
||||
JagexColor.BRIGHTNESS_MIN,
|
||||
JagexColor.BRIGHTNESS_LOW,
|
||||
JagexColor.BRIGHTNESS_HIGH,
|
||||
JagexColor.BRIGHTNESS_MAX,
|
||||
|
||||
Reference in New Issue
Block a user