Skip to content

Instantly share code, notes, and snippets.

@ekmillard
Created December 7, 2023 22:31
Show Gist options
  • Save ekmillard/e8400a2ed2b8f0dc0c24586e529ace30 to your computer and use it in GitHub Desktop.
Save ekmillard/e8400a2ed2b8f0dc0c24586e529ace30 to your computer and use it in GitHub Desktop.
package ps.eden.server.cache.editor.emperor.wm;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import ps.eden.server.ServerConstants;
import ps.eden.server.cache.editor.dragonkk.store.Store;
import ps.eden.server.cache.editor.dragonkk.tools.clientCacheUpdater.RSXteas;
import ps.eden.server.cache.editor.dragonkk.utils.ByteBufferUtils;
import ps.eden.server.cache.editor.mgi.tools.rseditor.core.cache.Cache;
import ps.eden.server.cache.editor.mgi.tools.rseditor.core.cache.File;
import ps.eden.server.cache.editor.mgi.tools.rseditor.core.cache.Folder;
import static ps.eden.server.ServerConstants.CUSTOM_ISLAND_NAME;
/**
* Used for packing new regions on the world map (not "game map").
*
* @author Emperor - mostly everything
* @author Clayton Williams - just finishing up some wall icons and piers //TODO pier walls
*/
public final class WorldMapPacker {
/**
* The cache index.
*/
private static final int INDEX = 23;
/**
* The world map planes available.
*/
private static List<WorldMapPlane> planes = new ArrayList<>();
/**
* The main method, sets things going.
*
* @param args The arguments cast on runtime.
*/
public static void main(String[] args) {
long time = System.currentTimeMillis();
Cache cache = Cache.openCache(ServerConstants.CACHE_530_DIR);
if (false) {
parseWorldMap(cache);
System.out.println("Took = "+(System.currentTimeMillis() - time));
return;
}
//RSXteas.loadUnpackedXteas(store.getRevision());
//store.getIndexes()[23].packIndex(new Store("./old530/", 530));
//if (true)
// return;
//parseWorldMap(new Store("./530/", 530));
//parseDetails(cache);
//planes.get(0).setName(ServerConstants.GAME_NAME + " surface");
//3968, 3521
//planes.clear();
cache.getFilesSystem(INDEX).deleteAllFolders();
WorldMapPlane plane = new WorldMapPlane(ServerConstants.GAME_NAME + " surface", "main");
//3087, 3502
plane.setCenterX(3087 >> 6);
plane.setCenterY(3502 >> 6);
plane.setVisible(true);
/*plane.addBoundaries(new ZoneBorders(2800, 2900, 4000, 3932));
plane.addBoundaries(new ZoneBorders(2100, 2500, 3428, 4132));
plane.addBoundaries(new ZoneBorders(3428, 2500, 4031, 3642));
plane.addBoundaries(new ZoneBorders(1799, 2463, 2268, 4885));*/
// below is the ENTIRE visible map region on world map - will take longest but the BEST results! :)
//plane.addBoundaries(new ZoneBorders(1158, 2111, 4857, 5654));
plane.addBoundaries(new ZoneBorders(2800, 2900, 4000, 3932));
plane.setDefault(cache);
/*plane.getDetails().add(new RegionDetails(CUSTOM_ISLAND_NAME, (byte) 8, 3968, 3518, -1));
plane.getDetails().add(new RegionDetails("Donator Islands", (byte) 8, 3918, 3585, -1));
plane.getDetails().add(new RegionDetails("Deadman Island", (byte) 8, 2962, 2787, -1));
plane.getDetails().add(new RegionDetails("Resource Area", (byte) 8, 3188, 3934, -1));
plane.getDetails().add(new RegionDetails("Wilderness Hub", (byte) 8, 3043, 3768, -1));*/
planes.add(plane);
packWMPlane(planes.get(0), cache);
packDetails(cache);
System.out.println("Took = "+(System.currentTimeMillis() - time));
try {
cache.close();
} catch (Throwable t) {
System.err.println("Failed 2 complete write");
t.printStackTrace();
}
}
/**
* Parses all world map information.
*
* @param cache The store.
*/
private static void parseWorldMap(Cache cache) {
parseDetails(cache);
for (WorldMapPlane plane : planes) {
parseWMPlane(cache, plane);
}
}
/**
* Parses the world map details.
*
* @param cache The store.
*/
private static void parseDetails(Cache cache) {
if (cache.getIndicesCount() <= INDEX) {
throw new IllegalStateException("No world map cache file found! Amount of files: " + cache.getIndicesCount());
}
Folder archiveId = cache.getFilesSystem(INDEX).findFolderByName("details");
if (archiveId == null) {
System.err.println("No world map details found!");
return;
}
int length = archiveId.filesCount();
for (int i = 0; i < length; i++) {
File file = archiveId.findFileByID(i);
if (file == null) {
System.err.println("World map plane " + i + " is invalid!");
continue;
}
ByteBuffer buffer = ByteBuffer.wrap(file.getData().getBuffer());
String archive = ByteBufferUtils.getString(buffer);
String name = ByteBufferUtils.getString(buffer);
int regionX = buffer.getShort();
int regionY = buffer.getShort();
int value = buffer.getInt(); //?
boolean visible = buffer.get() == 1; //?
int type = buffer.get(); //?
WorldMapPlane plane = new WorldMapPlane(name, archive);
plane.setCenterX(regionX);
plane.setCenterY(regionY);
plane.setVisible(visible);
plane.setType(type);
plane.setValue(value);
planes.add(plane);
int amount = buffer.get() & 0xFF;
for (int j = 0; j < amount; j++) {
plane.addBoundaries(new ZoneBorders(buffer.getShort(), buffer.getShort(), buffer.getShort(), buffer.getShort()));
}
System.out.println("Found plane id: " + i + ", name: " + name + ", archive: " + archive + ", center loc: [" + regionX + "," + regionY + "], zones (" + amount + "): " + plane.getBoundaries() + ".");
}
}
/**
* Parses the world map details.
*
* @param cache The store.
*/
private static void packDetails(Cache cache) {
if (cache.getIndicesCount() <= INDEX) {
throw new IllegalStateException("No world map cache file found! Amount of files: " + cache.getIndicesCount());
}
Folder archiveId = cache.getFilesSystem(INDEX).findFolderByName("details");
if (archiveId == null) {
archiveId = new Folder("details", new File[] {});
}
archiveId.deleteAllFiles();
for (int i = 0; i < planes.size(); i++) {
WorldMapPlane plane = planes.get(i);
if (plane == null) {
System.err.println("World map plane " + i + " is invalid.");
continue;
}
ByteBuffer buffer = ByteBuffer.allocate(65535);
ByteBufferUtils.putString(plane.getArchive(), buffer);
ByteBufferUtils.putString(plane.getName(), buffer);
buffer.putShort((short) plane.getCenterX());
buffer.putShort((short) plane.getCenterY());
buffer.putInt(plane.getValue());
buffer.put((byte) (plane.isVisible() ? 1 : 0));
buffer.put((byte) plane.getType());
buffer.put((byte) plane.getBoundaries().size());
for (ZoneBorders z : plane.getBoundaries()) {
buffer.putShort((short) z.getSouthWestX());
buffer.putShort((short) z.getSouthWestY());
buffer.putShort((short) z.getNorthEastX());
buffer.putShort((short) z.getNorthEastY());
}
buffer.flip();
byte[] bs = new byte[buffer.remaining()];
buffer.get(bs);
archiveId.addFile(new File(new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs)));
System.out.println("Packed world map details for plane " + plane.getName() + "!");
}
cache.getFilesSystem(INDEX).addFolder(archiveId);
}
/**
* Parses all data for a world map plane.
*
* @param cache The store to get the data from.
* @param plane The plane we're parsing.
*/
private static void parseWMPlane(Cache cache, WorldMapPlane plane) {
parseUnderlay(cache, plane);
parseOverlay(cache, plane);
parseOverlay2(cache, plane); //Overlays above overlays, used for platforms you can walk on etc.
parseObjects(cache, plane);
parseLabels(cache, plane);
}
/**
* Packs data for a world map plane on the cache store.
*
* @param cache The store to pack on.
* @param plane The plane we're packing.
*/
private static void packWMPlane(WorldMapPlane plane, Cache cache) {
try {
packUnderlay(cache, plane);
} catch (Throwable t) {
System.err.println("Failed 2 pack underlay");
t.printStackTrace();
}
try {
packOverlay(cache, plane);
} catch (Throwable t) {
System.err.println("Failed 2 pack overlay");
t.printStackTrace();
}
try {
packOverlay2(cache, plane);
} catch (Throwable t) {
System.err.println("Failed 2 pack overlay2");
t.printStackTrace();
}
try {
packObjects(cache, plane);
} catch (Throwable t) {
System.err.println("Failed 2 pack objects");
t.printStackTrace();
}
try {
packLabels(cache, plane);
} catch (Throwable t) {
System.err.println("Failed 2 pack labels");
t.printStackTrace();
}
}
/**
* Parses the underlays for the given world map plane.
*
* @param cache The cache store.
* @param plane The world map plane.
*/
private static void parseUnderlay(Cache cache, WorldMapPlane plane) {
File file = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive()).findFileByName("underlay");
if (file == null) {
System.err.println("Underlays for world map plane " + plane.getName() + " (archive " + plane.getArchive() + ") not found!");
return;
}
ByteBuffer buffer = ByteBuffer.wrap(file.getData().getBuffer());
byte[][][] data = plane.getUnderlay();
if (data == null) {
plane.setUnderlay(data = new byte[plane.getSizeX()][plane.getSizeY()][]);
}
int count = 0;
while (buffer.hasRemaining()) {
boolean chunk = buffer.get() == 1;
int chunkX = 0; //Chunk x-coordinate
int chunkY = 0; //Chunk y-coordinate
if (chunk) { //Not used in 530 so far.
chunkX = buffer.get() & 0xFF;
chunkY = buffer.get() & 0xFF;
System.out.println("Parsing chunk instead of region!");
}
int regionX = buffer.get() & 0xFF;
int regionY = buffer.get() & 0xFF;
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
if (data[offsetX][offsetY] == null) {
data[offsetX][offsetY] = new byte[4096];
}
if (offsetX >= 0 && offsetY >= 0 && offsetX < data.length && offsetY < data[offsetX].length) {
for (int x = 0; x < 64; ++x) {
for (int y = 0; y < 64; ++y) {
if (!chunk || x >= 8 * chunkX && 8 + 8 * chunkX > x && y >= chunkY * 8 && y < 8 + 8 * chunkY) {
data[offsetX][offsetY][x + (63 - y << 6)] = buffer.get();
count++;
}
}
}
} else if (!chunk) {
buffer.position(buffer.position() + 4096); //64x64=4096
} else {
buffer.position(buffer.position() + 64); //8x8=64
}
}
System.out.println("Parsed " + count + " underlays for plane " + plane.getName() + "!");
}
/**
* Packs underlays for a map plane on the cache store.
*
* @param cache The store to pack on.
* @param plane The world map plane to pack.
*/
private static void packUnderlay(Cache cache, WorldMapPlane plane) {
if (plane.getUnderlay() == null) {
System.err.println("Underlay is null for world map plane " + plane.getName() + "!");
return;
}
int count = 0;
ByteBuffer buffer = ByteBuffer.allocate(4099 * 5000); //Currently supports up to 5000 regions
for (ZoneBorders z : plane.getBoundaries()) {
for (int regionX = z.getSouthWestX() >> 6; regionX < (z.getNorthEastX() >> 6) + 1; regionX++) {
for (int regionY = z.getSouthWestY() >> 6; regionY < (z.getNorthEastY() >> 6) + 1; regionY++) {
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
buffer.put((byte) 0); //No support for chunk based packing yet!
buffer.put((byte) regionX);
buffer.put((byte) regionY);
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
byte[] data = plane.getUnderlay()[offsetX][offsetY];
if (data != null && offsetX >= 0 && offsetY >= 0 && offsetX < plane.getUnderlay().length && offsetY < plane.getUnderlay()[offsetX].length) {
buffer.put((byte) (plane.getUnderlay()[offsetX][offsetY][x + (63 - y << 6)]));
count++;
} else {
// System.out.println("Array " + arrX + "," + arrY);
buffer.put((byte) 0);
}
}
}
}
}
}
buffer.flip();
byte[] bs = new byte[buffer.remaining()];
buffer.get(bs);
Folder folder = null;
try {
folder = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive());
} catch (Exception e) {
e.printStackTrace();
}
String fileName = "underlay";
if (folder == null) {
folder = new Folder(plane.getArchive(), new File[] {new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs))});
} else {
File file = folder.findFileByName(fileName);
if (file != null) {
file.setData(new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
} else {
file = new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
folder.addFile(file);
}
}
folder.finish();
cache.getFilesSystem(INDEX).addFolder(folder);
cache.getFilesSystem(INDEX).finish();
System.out.println("Packed " + count + " underlays for plane " + plane.getName() + "!");
}
/**
* Parses the overlays for the given world map plane.
*
* @param cache The cache store.
* @param plane The world map plane.
*/
private static void parseOverlay(Cache cache, WorldMapPlane plane) {
File file = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive()).findFileByName("overlay");
if (file == null) {
System.err.println("Overlays for world map plane " + plane.getName() + " (archive " + plane.getArchive() + ") not found!");
return;
}
ByteBuffer buffer = ByteBuffer.wrap(file.getData().getBuffer());
byte[][][] data = plane.getOverlay();
if (data == null) {
plane.setOverlay(data = new byte[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
byte[][][] shapes = plane.getOverlayShapes();
if (shapes == null) {
plane.setOverlayShapes(shapes = new byte[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
int count = 0;
while (buffer.hasRemaining()) {
boolean chunk = buffer.get() == 1;
int chunkX = 0; //Chunk x-coordinate
int chunkY = 0; //Chunk y-coordinate
if (chunk) { //Not used in 530 so far.
chunkX = buffer.get() & 0xFF;
chunkY = buffer.get() & 0xFF;
System.out.println("Parsing chunk instead of region!");
}
int regionX = buffer.get() & 0xFF;
int regionY = buffer.get() & 0xFF;
// System.out.println("Parsing region " + regionX + "," + regionY + " (" + (regionX << 6) + "," + (regionY << 6) + ").");
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
if (offsetX >= 0 && offsetY >= 0 && offsetX < data.length && offsetY < data[offsetX].length) {
for (int x = 0; x < 64; ++x) {
for (int y = 0; y < 64; ++y) {
if (!chunk || x >= 8 * chunkX && 8 + 8 * chunkX > x && y >= chunkY * 8 && y < 8 + 8 * chunkY) {
int overlayId = buffer.get() & 0xFF;
if (overlayId != 0) {
if (data[offsetX][offsetY] == null) {
data[offsetX][offsetY] = new byte[4096];
}
data[offsetX][offsetY][x + (63 - y << 6)] = (byte) overlayId;
if (shapes[offsetX][offsetY] == null) {
shapes[offsetX][offsetY] = new byte[4096];
}
shapes[offsetX][offsetY][x + (63 - y << 6)] = buffer.get();
count++;
}
}
}
}
} else {
for (int i = 0; i < (chunk ? 64 : 4096); ++i) {
int b = buffer.get();
if (b != 0) {
buffer.position(buffer.position() + 1);
}
}
}
}
System.out.println("Parsed " + count + " overlay for plane " + plane.getName() + "!");
}
/**
* Packs the overlay data.
*
* @param cache The store.
* @param plane The world map plane to pack.
*/
private static void packOverlay(Cache cache, WorldMapPlane plane) {
if (plane.getOverlay() == null) {
System.err.println("Overlay is null for world map plane " + plane.getName() + "!");
return;
}
int count = 0;
ByteBuffer buffer = ByteBuffer.allocate(8195 * 5000); //Currently supports up to 5000 regions
for (ZoneBorders z : plane.getBoundaries()) {
for (int regionX = z.getSouthWestX() >> 6; regionX < (z.getNorthEastX() >> 6) + 1; regionX++) {
for (int regionY = z.getSouthWestY() >> 6; regionY < (z.getNorthEastY() >> 6) + 1; regionY++) {
int offX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offY = ((regionY << 6) - plane.getBaseY()) >> 6;
buffer.put((byte) 0); //No support for chunk based packing yet!
buffer.put((byte) regionX);
buffer.put((byte) regionY);
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
if (offX >= 0 && offY >= 0 && offX < plane.getOverlay().length && offY < plane.getOverlay()[offX].length) {
byte[] data = plane.getOverlay()[offX][offY];
int overlayId = data == null ? 0 : data[x + (63 - y << 6)] & 0xFF;
buffer.put((byte) overlayId);
if (overlayId != 0) {
count++;
buffer.put((byte) plane.getOverlayShapes()[offX][offY][x + (63 - y << 6)]);
}
} else {
buffer.put((byte) 0);
}
}
}
}
}
}
buffer.flip();
byte[] bs = new byte[buffer.remaining()];
buffer.get(bs);
Folder folder = null;
try {
folder = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive());
} catch (Exception e) {
e.printStackTrace();
}
String fileName = "overlay";
if (folder == null) {
folder = new Folder(plane.getArchive(), new File[] {new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs))});
} else {
File file = folder.findFileByName(fileName);
if (file != null) {
file.setData(new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
} else {
file = new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
folder.addFile(file);
}
}
cache.getFilesSystem(INDEX).addFolder(folder);
System.out.println("Packed " + count + " overlays for plane " + plane.getName() + "!");
}
/**
* Parses the overlay2 for the given world map plane.
*
* @param cache The cache store.
* @param plane The world map plane.
*/
private static void parseOverlay2(Cache cache, WorldMapPlane plane) {
File file = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive()).findFileByName("overlay2");
if (file == null) {
System.err.println("Overlay2 for world map plane " + plane.getName() + " (archive " + plane.getArchive() + ") not found!");
return;
}
ByteBuffer buffer = ByteBuffer.wrap(file.getData().getBuffer());
byte[][][] data = plane.getOverlay2();
if (data == null) {
plane.setOverlay2(data = new byte[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
byte[][][] shapes = plane.getOverlay2Shapes();
if (shapes == null) {
plane.setOverlay2Shapes(shapes = new byte[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
int count = 0;
while (buffer.hasRemaining()) {
boolean chunk = buffer.get() == 1;
int chunkX = 0; //Chunk x-coordinate
int chunkY = 0; //Chunk y-coordinate
if (chunk) { //Not used in 530 so far.
chunkX = buffer.get() & 0xFF;
chunkY = buffer.get() & 0xFF;
System.out.println("Parsing chunk instead of region!");
}
int regionX = buffer.get() & 0xFF;
int regionY = buffer.get() & 0xFF;
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
if (offsetX >= 0 && offsetY >= 0 && offsetX < data.length && offsetY < data[offsetX].length) {
for (int i = 0; i < 64; ++i) {
for (int j = 0; j < 64; ++j) {
if (!chunk || i >= 8 * chunkX && 8 + 8 * chunkX > i && j >= chunkY * 8 && j < 8 + 8 * chunkY) {
int overlayId = buffer.get() & 0xFF;
if (overlayId != 0) {
if (data[offsetX][offsetY] == null) {
data[offsetX][offsetY] = new byte[4096];
}
data[offsetX][offsetY][i + (63 - j << 6)] = (byte) overlayId;
if (shapes[offsetX][offsetY] == null) {
shapes[offsetX][offsetY] = new byte[4096];
}
shapes[offsetX][offsetY][i + (63 - j << 6)] = buffer.get();
count++;
}
}
}
}
} else {
for (int i = 0; i < (chunk ? 64 : 4096); ++i) {
int b = buffer.get();
if (b != 0) {
buffer.position(buffer.position() + 1);
}
}
}
}
System.out.println("Parsed " + count + " overlay2 for plane " + plane.getName() + "!");
}
/**
* Packs the overlay2 data.
*
* @param cache The store.
* @param plane The world map plane to pack.
*/
private static void packOverlay2(Cache cache, WorldMapPlane plane) {
if (plane.getOverlay2() == null) {
System.err.println("Overlay is null for world map plane " + plane.getName() + "!");
return;
}
int count = 0;
ByteBuffer buffer = ByteBuffer.allocate(8195 * 5000); //Currently supports up to 5000 regions
for (ZoneBorders z : plane.getBoundaries()) {
for (int regionX = z.getSouthWestX() >> 6; regionX < (z.getNorthEastX() >> 6) + 1; regionX++) {
for (int regionY = z.getSouthWestY() >> 6; regionY < (z.getNorthEastY() >> 6) + 1; regionY++) {
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
buffer.put((byte) 0); //No support for chunk based packing yet!
buffer.put((byte) regionX);
buffer.put((byte) regionY);
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
if (offsetX >= 0 && offsetY >= 0 && offsetX < plane.getOverlay().length && offsetY < plane.getOverlay()[offsetX].length) {
byte[] data = plane.getOverlay2()[offsetX][offsetY];
int overlayId = data == null ? 0 : data[x + (63 - y << 6)] & 0xFF;
buffer.put((byte) overlayId);
if (overlayId != 0) {
count++;
buffer.put((byte) plane.getOverlay2Shapes()[offsetX][offsetY][x + (63 - y << 6)]);
}
} else {
buffer.put((byte) 0);
}
}
}
}
}
}
buffer.flip();
byte[] bs = new byte[buffer.remaining()];
buffer.get(bs);
Folder folder = null;
try {
folder = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive());
} catch (Exception e) {
e.printStackTrace();
}
String fileName = "overlay2";
if (folder == null) {
folder = new Folder(plane.getArchive(), new File[] {new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs))});
} else {
File file = folder.findFileByName(fileName);
if (file != null) {
file.setData(new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
} else {
file = new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
folder.addFile(file);
}
}
cache.getFilesSystem(INDEX).addFolder(folder);
System.out.println("Packed " + count + " overlay2 for plane " + plane.getName() + " (" + bs.length + " bytes packed)!");
}
/**
* Parses the object information for the given world map plane.
*
* @param cache The store.
* @param plane The plane.
*/
private static void parseObjects(Cache cache, WorldMapPlane plane) {
File file = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive()).findFileByName("loc");
if (file == null) {
System.err.println("Object locations for world map plane " + plane.getName() + " (archive " + plane.getArchive() + ") not found!");
return;
}
byte[][][] walls = plane.getWalls();
if (walls == null) {
plane.setWalls(walls = new byte[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
int[][][] objects = plane.getObjectIcons();
if (objects == null) {
plane.setObjectIcons(objects = new int[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
int[][][] icons = plane.getMapIcons();
if (icons == null) {
plane.setMapIcons(icons = new int[plane.getSizeX() >> 6][plane.getSizeY() >> 6][]);
}
ByteBuffer buffer = ByteBuffer.wrap(file.getData().getBuffer());
int[] debug = new int[3];
roar:
while (true) {
if (buffer.hasRemaining()) {
boolean chunk = buffer.get() == 1;
int chunkX = 0; //Chunk x-coordinate
int chunkY = 0; //Chunk y-coordinate
if (chunk) { //Not used in 530 so far.
chunkX = buffer.get() & 0xFF;
chunkY = buffer.get() & 0xFF;
System.out.println("Parsing chunk instead of region!");
}
int regionX = buffer.get() & 0xFF;
int regionY = buffer.get() & 0xFF;
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
if (offsetX >= 0 && offsetY >= 0 && offsetX < plane.getSizeX() >> 6 && offsetY < plane.getSizeY() >> 6) {
int objX = 0;
while (true) {
if (objX >= 64) {
continue roar;
}
for (int objY = 0; objY < 64; objY++) {
if (!chunk || objX >= 8 * chunkX && 8 + 8 * chunkX > objX && objY >= chunkY * 8 && objY < 8 + 8 * chunkY) {
int flag = buffer.get();
if (flag == 0) {
continue;
}
if ((flag & 1) == 1) {
if (walls[offsetX][offsetY] == null) {
walls[offsetX][offsetY] = new byte[4096];
}
walls[offsetX][offsetY][objX + (63 - objY << 6)] = buffer.get();
debug[0]++;
}
if ((flag & 2) == 2) {
if (objects[offsetX][offsetY] == null) {
objects[offsetX][offsetY] = new int[4096];
}
objects[offsetX][offsetY][objX + (63 - objY << 6)] = ByteBufferUtils.getTriByte(buffer);
debug[1]++;
}
if ((flag & 4) == 4) {
if (icons[offsetX][offsetY] == null) {
icons[offsetX][offsetY] = new int[4096];
}
//object id = value - 1
icons[offsetX][offsetY][objX + (63 - objY << 6)] = ByteBufferUtils.getTriByte(buffer);
debug[2]++;
}
}
}
++objX;
}
}
int count = 0;
while (true) {
if (count >= (chunk ? 64 : 4096)) {
continue roar;
}
int flag = buffer.get();
if (flag != 0) {
if ((flag & 1) == 1) {
buffer.position(buffer.position() + 1);
}
if ((flag & 2) == 2) {
buffer.position(buffer.position() + 3);
}
if ((flag & 4) == 4) {
buffer.position(buffer.position() + 3);
}
}
++count;
}
}
System.out.println("Parsed " + debug[0] + " walls, " + debug[1] + " object drawings and " + debug[2] + " map icons for plane " + plane.getName() + "!");
return;
}
}
/**
* Packs the object information for the given world map plane.
*
* @param cache The store.
* @param plane The plane.
*/
private static void packObjects(Cache cache, WorldMapPlane plane) {
if (plane.getObjectIcons() == null) {
System.err.println("Object icons is null for world map plane " + plane.getName() + "!");
return;
}
int count = 0;
ByteBuffer buffer = ByteBuffer.allocate(8199 * 5000); //Currently supports up to 5000 regions
for (ZoneBorders z : plane.getBoundaries()) {
for (int regionX = z.getSouthWestX() >> 6; regionX < (z.getNorthEastX() >> 6) + 1; regionX++) {
for (int regionY = z.getSouthWestY() >> 6; regionY < (z.getNorthEastY() >> 6) + 1; regionY++) {
int offsetX = ((regionX << 6) - plane.getBaseX()) >> 6;
int offsetY = ((regionY << 6) - plane.getBaseY()) >> 6;
buffer.put((byte) 0); //No support for chunk based packing yet!
buffer.put((byte) regionX);
buffer.put((byte) regionY);
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
int wall = plane.getWalls()[offsetX][offsetY] == null ? 0 : plane.getWalls()[offsetX][offsetY][x + (63 - y << 6)];
int object = plane.getObjectIcons()[offsetX][offsetY] == null ? 0 : plane.getObjectIcons()[offsetX][offsetY][x + (63 - y << 6)];
int icon = plane.getMapIcons()[offsetX][offsetY] == null ? 0 : plane.getMapIcons()[offsetX][offsetY][x + (63 - y << 6)];
int index = buffer.position();
int flag = 0;
buffer.put((byte) flag);
if (wall != 0) {
flag |= 1;
buffer.put((byte) wall);
}
if (object > 0) {
flag |= 2;
ByteBufferUtils.putTriByte(object, buffer);
}
if (icon > 0) {
flag |= 4;
ByteBufferUtils.putTriByte(icon, buffer);
}
if (flag != 0) {
int pos = buffer.position();
buffer.position(index);
buffer.put((byte) flag);
buffer.position(pos);
count++;
}
}
}
}
}
}
buffer.flip();
byte[] bs = new byte[buffer.remaining()];
buffer.get(bs);
Folder folder = null;
try {
folder = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive());
} catch (Exception e) {
e.printStackTrace();
}
String fileName = "loc";
if (folder == null) {
folder = new Folder(plane.getArchive(), new File[] {new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs))});
} else {
File file = folder.findFileByName(fileName);
if (file != null) {
file.setData(new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
} else {
file = new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
folder.addFile(file);
}
}
cache.getFilesSystem(INDEX).addFolder(folder);
System.out.println("Packed " + count + " objects for plane " + plane.getName() + "!");
}
/**
* Parses the name labels for a world map plane.
*
* @param cache The cache store.
* @param plane The world map plane.
*/
private static void parseLabels(Cache cache, WorldMapPlane plane) {
Folder archiveId = cache.getFilesSystem(INDEX).findFolderByName(plane.getArchive() + "_labels");
if (archiveId == null) {
System.out.println("Could not find labels for plane " + plane.getName() + "!");
return;
}
int count = 0;
for (int i = 0; i < archiveId.filesCount(); i++) {
byte[] data = archiveId.findFileByID(i).getData().getBuffer();
if (data == null || data.length < 2) {
System.err.println("Invalid label file for plane " + plane.getName() + "!");
continue;
}
ByteBuffer buffer = ByteBuffer.wrap(data);
String name = ByteBufferUtils.getString(buffer);
byte flag = buffer.get();
int x = buffer.getShort();
int y = buffer.getShort();
int hash = buffer.getInt(); //Always seems to be -1
plane.getDetails().add(new RegionDetails(name, flag, x, y, hash));
System.out.println("Parsing label " + name + ", " + x + ", " + y + ", " + flag);
count++;
}
System.out.println("Parsed " + count + " region details for plane " + plane.getName() + "!");
}
/**
* Parses the name labels for a world map plane.
*
* @param cache The cache store.
* @param plane The world map plane.
*/
private static void packLabels(Cache cache, WorldMapPlane plane) {
int count = 0;
for (RegionDetails r : plane.getDetails()) {
ByteBuffer buffer = ByteBuffer.allocate(256 + 9);
ByteBufferUtils.putString(r.getName(), buffer);
buffer.put((byte) r.getFlag());
buffer.putShort((short) r.getX());
buffer.putShort((short) r.getY());
buffer.putInt(r.getData());
buffer.flip();
byte[] bs = new byte[buffer.remaining()];
buffer.get(bs);
String groupname = plane.getArchive() + "_labels";
Folder folder = null;
try {
folder = cache.getFilesSystem(INDEX).findFolderByName(groupname);
} catch (Exception e) {
e.printStackTrace();
}
int fileName = count++;
if (folder == null) {
folder = new Folder(groupname, new File[] {new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs))});
} else {
File file = folder.findFileByName(fileName);
if (file != null) {
file.setData(new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
} else {
file = new File(fileName, new ps.eden.server.cache.editor.mgi.tools.rseditor.core.utilities.ByteBuffer(bs));
folder.addFile(file);
}
}
cache.getFilesSystem(INDEX).addFolder(folder);
}
System.out.println("Packed " + count + " region details for plane " + plane.getName() + "!");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment