I wrote this compressor and loader which uses RandomAccessFile so that people were not releasing client's with map folders bigger than the actual cache.
This compressor will pack your maps into 3 files;
MAP_CACHE.DAT - Contains the raw map bytes.
MAP_CACHE.IDX - Contains the offset, length compressed and decompressed.
MAP_CACHE.IDX2 - Contains the index table, for the map id's.
The total file size is smaller than rarring the files in a rar archive, 23mb of maps went into a 2.7mb raw data file and 2 indexes around 20kb in size.
Basically, in your client if you load 317 map's or whatever you can use this tool to compress and load with ease.
The map's are stored in a HashMap and only loaded when required, then they are stored for future reference.
So anyway;
Compressor download link: Map compressor.rar
Loader class;
Code:
/*
* @ Author: Zee best
*/
import java.io.RandomAccessFile;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.zip.GZIPInputStream;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
public class MapDecompressor {
public static List<Integer> mapIndices = null;
public static Map<Integer, byte[]> mapBuffer = new HashMap<Integer, byte[]>();
public static byte[] grabMap(int id) throws IOException
{
if(mapIndices == null)
loadIndex2();
if(mapBuffer.get(id) == null)
{
RandomAccessFile raf_cache = new RandomAccessFile("./MAP_CACHE.dat", "rw");
RandomAccessFile raf_index = new RandomAccessFile("./MAP_CACHE.idx", "rw");
int pos = getIndexPosition(id);
if(pos == -1)
return null;
raf_index.seek(pos * 12);
raf_cache.seek(raf_index.readInt());
byte[] b = new byte[raf_index.readInt()];
raf_cache.readFully(b);
b = inflate(b, raf_index.readInt());
mapBuffer.put(id, b);
return mapBuffer.get(id);
}
return mapBuffer.get(id);
}
public static void loadIndex2() throws IOException
{
mapIndices = new ArrayList<Integer>();
DataInputStream dis = new DataInputStream(new FileInputStream("./MAP_CACHE.idx2"));
for (int i = 0; i < (int) new File("./MAP_CACHE.idx2").length() / 2; i++)
mapIndices.add((int) dis.readShort());
}
public static int getIndexPosition(int id) throws IOException
{
if(mapIndices.contains(id))
for (int i = 0; i < mapIndices.size(); i++)
if(mapIndices.get(i) == id)
return i;
return -1;
}
public static byte[] inflate(byte[] b, int l) throws IOException
{
byte[] buf = new byte[l];
ByteArrayInputStream bais = new ByteArrayInputStream(b);
DataInputStream dis = new DataInputStream(new GZIPInputStream(bais));
dis.readFully(buf, 0, buf.length);
dis.close();
return buf;
}
}
Now, basically to get a map in the cache use it like this;
Code:
MapDecompressor.grabMap(id);
That would replace any other loading method you have installed into your client.
Feel free to use this for your client.
Method summary:
grabMap(Integer),
This method attempts to get the map byte array from the HashTable, if it's not already loaded then it will read the index and cache and load it.
loadIndex2()
This method loads the idx2 index file which contains the index map id's, so that they can be found easy instead of searching a file for names.
getIndexPosition(Integer)
Checks the index array list for a match of map id, if it gets the map it returns
the position / 12 of the index file.
inflate(byte[], Integer)
This method is used to un-gzip the compressed byte array, integer l is the uncompressed length.