mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-03 00:38:21 +00:00
Refactor map loading code
Refactors the map file loading code by importing existing code from the Vicis cache editor project. Adds classes for decoding objects and tiles for a given map file index. Only the new MapIndex decoder code is used when loading GameObjects at the moment , which will later be updated.
This commit is contained in:
@@ -1,135 +0,0 @@
|
|||||||
package org.apollo.cache.decoder;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apollo.cache.IndexedFileSystem;
|
|
||||||
import org.apollo.cache.archive.Archive;
|
|
||||||
import org.apollo.cache.archive.ArchiveEntry;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes {@link MapDefinition}s from the {@link IndexedFileSystem}.
|
|
||||||
*
|
|
||||||
* @author Ryley
|
|
||||||
* @author Major
|
|
||||||
*/
|
|
||||||
public final class MapFileDecoder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A definition for a region.
|
|
||||||
*/
|
|
||||||
public static final class MapDefinition {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether or not this map is members-only.
|
|
||||||
*/
|
|
||||||
private final boolean members;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The object file id.
|
|
||||||
*/
|
|
||||||
private final int objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The packed coordinates.
|
|
||||||
*/
|
|
||||||
private final int packedCoordinates;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The terrain file id.
|
|
||||||
*/
|
|
||||||
private final int terrain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the {@link MapDefinition}.
|
|
||||||
*
|
|
||||||
* @param packedCoordinates The packed coordinates.
|
|
||||||
* @param terrain The terrain file id.
|
|
||||||
* @param objects The object file id.
|
|
||||||
* @param members Indicates whether or not this map is members-only.
|
|
||||||
*/
|
|
||||||
public MapDefinition(int packedCoordinates, int terrain, int objects, boolean members) {
|
|
||||||
this.packedCoordinates = packedCoordinates;
|
|
||||||
this.terrain = terrain;
|
|
||||||
this.objects = objects;
|
|
||||||
this.members = members;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the id of the file containing the object data.
|
|
||||||
*
|
|
||||||
* @return The file id.
|
|
||||||
*/
|
|
||||||
public int getObjectFile() {
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the packed coordinates.
|
|
||||||
*
|
|
||||||
* @return The packed coordinates.
|
|
||||||
*/
|
|
||||||
public int getPackedCoordinates() {
|
|
||||||
return packedCoordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the id of the file containing the terrain data.
|
|
||||||
*
|
|
||||||
* @return The file id.
|
|
||||||
*/
|
|
||||||
public int getTerrainFile() {
|
|
||||||
return terrain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not this MapDefinition is for a members-only area of the world.
|
|
||||||
*
|
|
||||||
* @return {@code true} if this MapDefinition is for a members-only area, {@code false} if not.
|
|
||||||
*/
|
|
||||||
public boolean isMembersOnly() {
|
|
||||||
return members;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The width (and length) of a map file, in tiles.
|
|
||||||
*/
|
|
||||||
public static final int MAP_FILE_WIDTH = 64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The file id of the versions archive.
|
|
||||||
*/
|
|
||||||
private static final int VERSIONS_ARCHIVE_FILE_ID = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes {@link MapDefinition}s from the specified {@link IndexedFileSystem}.
|
|
||||||
*
|
|
||||||
* @param fs The IndexedFileSystem.
|
|
||||||
* @return A {@link Map} of packed coordinates to their MapDefinitions.
|
|
||||||
* @throws IOException If there is an error reading or decoding the Archive.
|
|
||||||
*/
|
|
||||||
public static Map<Integer, MapDefinition> decode(IndexedFileSystem fs) throws IOException {
|
|
||||||
Archive archive = fs.getArchive(0, VERSIONS_ARCHIVE_FILE_ID);
|
|
||||||
ArchiveEntry entry = archive.getEntry("map_index");
|
|
||||||
Map<Integer, MapDefinition> definitions = new HashMap<>();
|
|
||||||
|
|
||||||
ByteBuffer buffer = entry.getBuffer();
|
|
||||||
int count = buffer.capacity() / (3 * Short.BYTES + Byte.BYTES);
|
|
||||||
|
|
||||||
for (int times = 0; times < count; times++) {
|
|
||||||
int id = buffer.getShort() & 0xFFFF;
|
|
||||||
int terrain = buffer.getShort() & 0xFFFF;
|
|
||||||
int objects = buffer.getShort() & 0xFFFF;
|
|
||||||
boolean members = buffer.get() == 1;
|
|
||||||
|
|
||||||
definitions.put(id, new MapDefinition(id, terrain, objects, members));
|
|
||||||
}
|
|
||||||
|
|
||||||
return definitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains {@link MapFile}-related constants.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class MapConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index containing the map files.
|
||||||
|
*/
|
||||||
|
public static final int MAP_INDEX = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width (and length) of a {@link MapFile} in {@link Tile}s.
|
||||||
|
*/
|
||||||
|
public static final int MAP_WIDTH = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of planes in a MapFile.
|
||||||
|
*/
|
||||||
|
public static final int MAP_PLANES = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The multiplicand for height values.
|
||||||
|
*/
|
||||||
|
static final int HEIGHT_MULTIPLICAND = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lowest type value that will result in the decoding of a Tile being continued.
|
||||||
|
*/
|
||||||
|
static final int LOWEST_CONTINUED_TYPE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum type that specifies the Tile attributes.
|
||||||
|
*/
|
||||||
|
static final int MINIMUM_ATTRIBUTES_TYPE = 81;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum type that specifies the Tile underlay id.
|
||||||
|
*/
|
||||||
|
static final int MINIMUM_OVERLAY_TYPE = 49;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of possible overlay orientations.
|
||||||
|
*/
|
||||||
|
static final int ORIENTATION_COUNT = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height difference between two planes.
|
||||||
|
*/
|
||||||
|
static final int PLANE_HEIGHT_DIFFERENCE = 240;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sole private constructor to prevent instantiation.
|
||||||
|
*/
|
||||||
|
private MapConstants() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 3-dimensional 64x64 area of the map.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class MapFile {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array of MapPlanes.
|
||||||
|
*/
|
||||||
|
private final MapPlane[] planes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the MapFile.
|
||||||
|
*
|
||||||
|
* @param planes The {@link MapPlane}s.
|
||||||
|
*/
|
||||||
|
public MapFile(MapPlane[] planes) {
|
||||||
|
this.planes = planes.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link MapPlane} with the specified level.
|
||||||
|
*
|
||||||
|
* @param plane The plane.
|
||||||
|
* @return The MapPlane.
|
||||||
|
* @throws ArrayIndexOutOfBoundsException If {@code plane} is out of bounds.
|
||||||
|
*/
|
||||||
|
public MapPlane getPlane(int plane) {
|
||||||
|
int length = planes.length;
|
||||||
|
Preconditions.checkElementIndex(plane, length, "Plane index out of bounds, must be [0, " + length + ").");
|
||||||
|
return planes[plane];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all of the {@link MapPlane}s in this MapFile.
|
||||||
|
*
|
||||||
|
* @return The MapPlanes.
|
||||||
|
*/
|
||||||
|
public MapPlane[] getPlanes() {
|
||||||
|
return planes.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
import org.apollo.cache.IndexedFileSystem;
|
||||||
|
import org.apollo.util.CompressionUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A decoder for the terrain data stored in {@link MapFile}s.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public class MapFileDecoder {
|
||||||
|
/**
|
||||||
|
* Creates a MapFileDecoder for the specified map file.
|
||||||
|
*
|
||||||
|
* @param fs The {@link IndexedFileSystem} to get the file from.
|
||||||
|
* @param index The {@link MapIndex} to get the file index from.
|
||||||
|
* @return The MapFileDecoder.
|
||||||
|
* @throws IOException If there is an error reading or decompressing the file.
|
||||||
|
*/
|
||||||
|
public static MapFileDecoder create(IndexedFileSystem fs, MapIndex index) throws IOException {
|
||||||
|
ByteBuffer compressed = fs.getFile(MapConstants.MAP_INDEX, index.getMapFile());
|
||||||
|
ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed));
|
||||||
|
|
||||||
|
return new MapFileDecoder(decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DataBuffer containing the MapFile data.
|
||||||
|
*/
|
||||||
|
private final ByteBuffer buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the MapIndexDecoder.
|
||||||
|
* <p>
|
||||||
|
* This constructor expects the {@link ByteBuffer} to <strong>not</strong> be compressed.
|
||||||
|
*
|
||||||
|
* @param buffer The DataBuffer containing the MapFile data.
|
||||||
|
*/
|
||||||
|
public MapFileDecoder(ByteBuffer buffer) {
|
||||||
|
this.buffer = buffer.asReadOnlyBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the data into a {@link MapFile}.
|
||||||
|
*
|
||||||
|
* @return The MapFile.
|
||||||
|
*/
|
||||||
|
public MapFile decode() {
|
||||||
|
MapPlane[] planes = new MapPlane[MapConstants.MAP_PLANES];
|
||||||
|
|
||||||
|
for (int level = 0; level < MapConstants.MAP_PLANES; level++) {
|
||||||
|
planes[level] = decodePlane(planes, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MapFile(planes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a {@link MapPlane} with the specified level.
|
||||||
|
*
|
||||||
|
* @param planes The previously-decoded {@link MapPlane}s, for calculating the height of the tiles.
|
||||||
|
* @param level The level.
|
||||||
|
* @return The MapPlane.
|
||||||
|
*/
|
||||||
|
private MapPlane decodePlane(MapPlane[] planes, int level) {
|
||||||
|
Tile[][] tiles = new Tile[MapConstants.MAP_WIDTH][MapConstants.MAP_WIDTH];
|
||||||
|
|
||||||
|
for (int x = 0; x < MapConstants.MAP_WIDTH; x++) {
|
||||||
|
for (int z = 0; z < MapConstants.MAP_WIDTH; z++) {
|
||||||
|
tiles[x][z] = decodeTile(planes, level, x, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MapPlane(level, tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the data into a {@link Tile}.
|
||||||
|
*
|
||||||
|
* @param planes The previously-decoded {@link MapPlane}s, for calculating the height of the Tile.
|
||||||
|
* @param level The level the Tile is on.
|
||||||
|
* @param x The x coordinate of the Tile.
|
||||||
|
* @param z The z coordinate of the Tile.
|
||||||
|
* @return The MapFile.
|
||||||
|
*/
|
||||||
|
private Tile decodeTile(MapPlane[] planes, int level, int x, int z) {
|
||||||
|
Tile.Builder builder = Tile.builder(x, z, level);
|
||||||
|
|
||||||
|
int type;
|
||||||
|
do {
|
||||||
|
type = buffer.get() & 0xFF;
|
||||||
|
|
||||||
|
if (type == 0) {
|
||||||
|
if (level == 0) {
|
||||||
|
builder.setHeight(TileUtils.calculateHeight(x, z));
|
||||||
|
} else {
|
||||||
|
Tile below = planes[level - 1].getTile(x, z);
|
||||||
|
builder.setHeight(below.getHeight() + MapConstants.PLANE_HEIGHT_DIFFERENCE);
|
||||||
|
}
|
||||||
|
} else if (type == 1) {
|
||||||
|
int height = buffer.get();
|
||||||
|
int below = (level == 0) ? 0 : planes[level - 1].getTile(x, z).getHeight();
|
||||||
|
|
||||||
|
builder.setHeight((height == 1 ? 0 : height) * MapConstants.HEIGHT_MULTIPLICAND + below);
|
||||||
|
} else if (type <= MapConstants.MINIMUM_OVERLAY_TYPE) {
|
||||||
|
builder.setOverlay(buffer.get());
|
||||||
|
builder.setOverlayType((type - MapConstants.LOWEST_CONTINUED_TYPE)
|
||||||
|
/ MapConstants.ORIENTATION_COUNT);
|
||||||
|
builder.setOverlayOrientation(type - MapConstants.LOWEST_CONTINUED_TYPE
|
||||||
|
% MapConstants.ORIENTATION_COUNT);
|
||||||
|
} else if (type <= MapConstants.MINIMUM_ATTRIBUTES_TYPE) {
|
||||||
|
builder.setAttributes(type - MapConstants.MINIMUM_OVERLAY_TYPE);
|
||||||
|
} else {
|
||||||
|
builder.setUnderlay(type - MapConstants.MINIMUM_ATTRIBUTES_TYPE);
|
||||||
|
}
|
||||||
|
} while (type >= MapConstants.LOWEST_CONTINUED_TYPE);
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
import org.apollo.cache.def.ItemDefinition;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A definition for a map.
|
||||||
|
*/
|
||||||
|
public final class MapIndex {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not this map is members-only.
|
||||||
|
*/
|
||||||
|
private final boolean members;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object file id.
|
||||||
|
*/
|
||||||
|
private final int objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The packed coordinates.
|
||||||
|
*/
|
||||||
|
private final int packedCoordinates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The terrain file id.
|
||||||
|
*/
|
||||||
|
private final int terrain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping of region ids to {@link MapIndex}es.
|
||||||
|
*/
|
||||||
|
private static Map<Integer, MapIndex> indices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the class with the specified set of indices.
|
||||||
|
*/
|
||||||
|
public static void init(Map<Integer, MapIndex> indices) {
|
||||||
|
MapIndex.indices = Collections.unmodifiableMap(indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@code Map} of {@link MapIndex} instances.
|
||||||
|
*
|
||||||
|
* @return The map of {@link MapIndex} instances.
|
||||||
|
*/
|
||||||
|
public static Map<Integer, MapIndex> getIndices() {
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the {@link MapIndex}.
|
||||||
|
*
|
||||||
|
* @param packedCoordinates The packed coordinates.
|
||||||
|
* @param terrain The terrain file id.
|
||||||
|
* @param objects The object file id.
|
||||||
|
* @param members Indicates whether or not this map is members-only.
|
||||||
|
*/
|
||||||
|
public MapIndex(int packedCoordinates, int terrain, int objects, boolean members) {
|
||||||
|
this.packedCoordinates = packedCoordinates;
|
||||||
|
this.terrain = terrain;
|
||||||
|
this.objects = objects;
|
||||||
|
this.members = members;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the id of the file containing the object data.
|
||||||
|
*
|
||||||
|
* @return The file id.
|
||||||
|
*/
|
||||||
|
public int getObjectFile() {
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the packed coordinates.
|
||||||
|
*
|
||||||
|
* @return The packed coordinates.
|
||||||
|
*/
|
||||||
|
public int getPackedCoordinates() {
|
||||||
|
return packedCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the id of the file containing the terrain data.
|
||||||
|
*
|
||||||
|
* @return The file id.
|
||||||
|
*/
|
||||||
|
public int getMapFile() {
|
||||||
|
return terrain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the X coordinate of this map.
|
||||||
|
*
|
||||||
|
* @return The X coordinate of this map.
|
||||||
|
*/
|
||||||
|
public int getX() {
|
||||||
|
return (packedCoordinates >> 8 & 0xFF) * MapConstants.MAP_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Y coordinate of this map.
|
||||||
|
*
|
||||||
|
* @return The y coordinate of this map.
|
||||||
|
*/
|
||||||
|
public int getY() {
|
||||||
|
return (packedCoordinates & 0xFF) * MapConstants.MAP_WIDTH;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not this MapIndex is for a members-only area of the world.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this MapIndex is for a members-only area, {@code false} if not.
|
||||||
|
*/
|
||||||
|
public boolean isMembersOnly() {
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apollo.cache.IndexedFileSystem;
|
||||||
|
import org.apollo.cache.archive.Archive;
|
||||||
|
import org.apollo.cache.archive.ArchiveEntry;
|
||||||
|
import org.apollo.cache.map.MapIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes {@link MapIndex}s from the {@link IndexedFileSystem}.
|
||||||
|
*
|
||||||
|
* @author Ryley
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class MapIndexDecoder implements Runnable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file id of the versions archive.
|
||||||
|
*/
|
||||||
|
private static final int VERSIONS_ARCHIVE_FILE_ID = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IndexedFileSystem.
|
||||||
|
*/
|
||||||
|
private final IndexedFileSystem fs;
|
||||||
|
|
||||||
|
public MapIndexDecoder(IndexedFileSystem fs) {
|
||||||
|
this.fs = fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes {@link MapIndex}s from the specified {@link IndexedFileSystem}.
|
||||||
|
*
|
||||||
|
* @return A {@link Map} of packed coordinates to their MapDefinitions.
|
||||||
|
* @throws IOException If there is an error reading or decoding the Archive.
|
||||||
|
*/
|
||||||
|
public Map<Integer, MapIndex> decode() throws IOException {
|
||||||
|
Archive archive = fs.getArchive(0, VERSIONS_ARCHIVE_FILE_ID);
|
||||||
|
ArchiveEntry entry = archive.getEntry("map_index");
|
||||||
|
Map<Integer, MapIndex> definitions = new HashMap<>();
|
||||||
|
|
||||||
|
ByteBuffer buffer = entry.getBuffer();
|
||||||
|
int count = buffer.capacity() / (3 * Short.BYTES + Byte.BYTES);
|
||||||
|
|
||||||
|
for (int times = 0; times < count; times++) {
|
||||||
|
int id = buffer.getShort() & 0xFFFF;
|
||||||
|
int terrain = buffer.getShort() & 0xFFFF;
|
||||||
|
int objects = buffer.getShort() & 0xFFFF;
|
||||||
|
boolean members = buffer.get() == 1;
|
||||||
|
|
||||||
|
definitions.put(id, new MapIndex(id, terrain, objects, members));
|
||||||
|
}
|
||||||
|
|
||||||
|
return definitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
MapIndex.init(decode());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a static world object in a map file.
|
||||||
|
*/
|
||||||
|
public final class MapObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object definition id of this {@code MapObject}.
|
||||||
|
*/
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The packed coordinates (local XY and height) for this object.
|
||||||
|
*/
|
||||||
|
private int packedCoordinates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this object.
|
||||||
|
*/
|
||||||
|
private final int type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The orientation of this object.
|
||||||
|
*/
|
||||||
|
private final int orientation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@code MapObject}.
|
||||||
|
*
|
||||||
|
* @param id The object ID of this map object.
|
||||||
|
* @param packedCoordinates A packed integer containing the coordinates of this map object.
|
||||||
|
* @param type The type of object.
|
||||||
|
* @param orientation The object facing direction.
|
||||||
|
*/
|
||||||
|
public MapObject(int id, int packedCoordinates, int type, int orientation) {
|
||||||
|
this.id = id;
|
||||||
|
this.packedCoordinates = packedCoordinates;
|
||||||
|
this.type = type;
|
||||||
|
this.orientation = orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the object ID of this map object.
|
||||||
|
*
|
||||||
|
* @return The object ID for {@link org.apollo.cache.def.ObjectDefinition} lookups.
|
||||||
|
*/
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the plane this map object exists on.
|
||||||
|
*
|
||||||
|
* @return The plane this map object is on.
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return packedCoordinates >> 12 & 0x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the X coordinate of this object relative to the map position.
|
||||||
|
*
|
||||||
|
* @return The local X coordinate.
|
||||||
|
*/
|
||||||
|
public int getLocalX() {
|
||||||
|
return packedCoordinates >> 6 & 0x3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Y coordinate of this object relative to the map position.
|
||||||
|
*
|
||||||
|
* @return The local Y coordinate.
|
||||||
|
*/
|
||||||
|
public int getLocalY() {
|
||||||
|
return packedCoordinates & 0x3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the integer representation of this objects orientation (0 indexed, starting West-North-East-South).
|
||||||
|
*
|
||||||
|
* @return The orientation of this object.
|
||||||
|
*/
|
||||||
|
public int getOrientation() {
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a packed integer containing the x/y coordinates and height for this object.
|
||||||
|
*
|
||||||
|
* @return The packed coordinates.
|
||||||
|
*/
|
||||||
|
public int getPackedCoordinates() {
|
||||||
|
return packedCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of this object.
|
||||||
|
*
|
||||||
|
* @return The type of this object.
|
||||||
|
*/
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
import org.apollo.cache.IndexedFileSystem;
|
||||||
|
import org.apollo.cache.map.MapIndex;
|
||||||
|
import org.apollo.cache.map.MapConstants;
|
||||||
|
import org.apollo.cache.map.MapObject;
|
||||||
|
import org.apollo.util.BufferUtil;
|
||||||
|
import org.apollo.util.CompressionUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A decoder for reading the map objects for a given map.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class MapObjectsDecoder {
|
||||||
|
/**
|
||||||
|
* Creates a MapObjectsDecoder for the specified map file.
|
||||||
|
*
|
||||||
|
* @param fs The {@link IndexedFileSystem} to get the file from.
|
||||||
|
* @param index The map index to decode objects for.
|
||||||
|
* @return The MapObjectsDecoder.
|
||||||
|
* @throws IOException If there is an error reading or decompressing the file.
|
||||||
|
*/
|
||||||
|
public static MapObjectsDecoder create(IndexedFileSystem fs, MapIndex index) throws IOException {
|
||||||
|
ByteBuffer compressed = fs.getFile(MapConstants.MAP_INDEX, index.getObjectFile());
|
||||||
|
ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed));
|
||||||
|
|
||||||
|
return new MapObjectsDecoder(decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer to decode {@link MapObject}s from.
|
||||||
|
*/
|
||||||
|
private final ByteBuffer buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link MapObjectsDecoder} from the given buffer and map coordinates.
|
||||||
|
*
|
||||||
|
* @param buffer The decompressed object file buffer.
|
||||||
|
*/
|
||||||
|
public MapObjectsDecoder(ByteBuffer buffer) {
|
||||||
|
this.buffer = buffer.asReadOnlyBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the data in the {@code buffer} to a list of {@link MapObject}s.
|
||||||
|
*
|
||||||
|
* @return A list of decoded {@link MapObject}s.
|
||||||
|
*/
|
||||||
|
public List<MapObject> decode() {
|
||||||
|
List<MapObject> objects = new ArrayList<>();
|
||||||
|
|
||||||
|
int id = -1;
|
||||||
|
int idOffset = BufferUtil.readSmart(buffer);
|
||||||
|
|
||||||
|
while (idOffset != 0) {
|
||||||
|
id += idOffset;
|
||||||
|
|
||||||
|
int packed = 0;
|
||||||
|
int positionOffset = BufferUtil.readSmart(buffer);
|
||||||
|
|
||||||
|
while (positionOffset != 0) {
|
||||||
|
packed += positionOffset - 1;
|
||||||
|
|
||||||
|
int attributes = buffer.get() & 0xFF;
|
||||||
|
int type = attributes >> 2;
|
||||||
|
int orientation = attributes & 0x3;
|
||||||
|
objects.add(new MapObject(id, packed, type, orientation));
|
||||||
|
|
||||||
|
positionOffset = BufferUtil.readSmart(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
idOffset = BufferUtil.readSmart(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plane of a map, which is a distinct height level.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class MapPlane {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a shallow copy of the specified 2-dimensional array.
|
||||||
|
*
|
||||||
|
* @param array The array to copy. Must not be {@code null}.
|
||||||
|
* @return The copy.
|
||||||
|
*/
|
||||||
|
private static <T> T[][] clone(T[][] array) {
|
||||||
|
T[][] copy = array.clone();
|
||||||
|
for (int index = 0; index < copy.length; index++) {
|
||||||
|
copy[index] = array[index].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level of this MapPlane.
|
||||||
|
*/
|
||||||
|
private final int level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 2-dimensional array of Tiles.
|
||||||
|
*/
|
||||||
|
private final Tile[][] tiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the MapPlane.
|
||||||
|
*
|
||||||
|
* @param level The level of the MapPlane.
|
||||||
|
* @param tiles The 2D array of {@link Tile}s. Must not be {@code null}. Must be square.
|
||||||
|
*/
|
||||||
|
public MapPlane(int level, Tile[][] tiles) {
|
||||||
|
this.level = level;
|
||||||
|
this.tiles = clone(tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the level of this MapPlane.
|
||||||
|
*
|
||||||
|
* @return The level.
|
||||||
|
*/
|
||||||
|
public int getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the amount of tiles in this MapPlane.
|
||||||
|
*
|
||||||
|
* @return The amount of tiles.
|
||||||
|
*/
|
||||||
|
public int getSize() {
|
||||||
|
return tiles.length * tiles[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Tile} at the specified (x, z) coordinate.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate.
|
||||||
|
* @param z The z coordinate.
|
||||||
|
* @return The Tile.
|
||||||
|
*/
|
||||||
|
public Tile getTile(int x, int z) {
|
||||||
|
return tiles[x][z];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Tile}s in this MapPlane.
|
||||||
|
* <p>
|
||||||
|
* This method returns the Tiles according on a column-based ordering: for a 2x2 tile set, the order will be
|
||||||
|
* {@code (0, 0), (0, 1), (1, 0), (1, 1)}.
|
||||||
|
*
|
||||||
|
* @return The Tiles.
|
||||||
|
*/
|
||||||
|
public Stream<Tile> getTiles() {
|
||||||
|
return Arrays.stream(tiles).flatMap(Arrays::stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+295
@@ -0,0 +1,295 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single tile on the map.
|
||||||
|
*
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class Tile {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder class for a Tile.
|
||||||
|
*/
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes of the Tile.
|
||||||
|
*/
|
||||||
|
private int attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of the Tile.
|
||||||
|
*/
|
||||||
|
private int height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The overlay id of the Tile.
|
||||||
|
*/
|
||||||
|
private int overlay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The overlay orientation of the Tile.
|
||||||
|
*/
|
||||||
|
private int overlayOrientation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The overlay type of the Tile.
|
||||||
|
*/
|
||||||
|
private int overlayType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x coordinate of the Tile.
|
||||||
|
*/
|
||||||
|
private int x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y coordinate of the Tile.
|
||||||
|
*/
|
||||||
|
private int y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlay id of the Tile.
|
||||||
|
*/
|
||||||
|
private int underlay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the Builder.
|
||||||
|
*
|
||||||
|
* @param x The x position of the Tile.
|
||||||
|
* @param y The y position of the Tile.
|
||||||
|
* @param height The height level of the Tile.
|
||||||
|
*/
|
||||||
|
public Builder(int x, int y, int height) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the contents of this Builder into a Tile.
|
||||||
|
*
|
||||||
|
* @return The Tile.
|
||||||
|
*/
|
||||||
|
public Tile build() {
|
||||||
|
return new Tile(x, y, attributes, height, overlay, overlayType, overlayOrientation, underlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the attributes of the Tile.
|
||||||
|
*
|
||||||
|
* @param attributes The attributes.
|
||||||
|
*/
|
||||||
|
public void setAttributes(int attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the height of the Tile.
|
||||||
|
*
|
||||||
|
* @param height The height.
|
||||||
|
*/
|
||||||
|
public void setHeight(int height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the overlay id of the Tile.
|
||||||
|
*
|
||||||
|
* @param overlay The overlay id.
|
||||||
|
*/
|
||||||
|
public void setOverlay(int overlay) {
|
||||||
|
this.overlay = overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the overlay orientation of the Tile.
|
||||||
|
*
|
||||||
|
* @param orientation The overlay orientation.
|
||||||
|
*/
|
||||||
|
public void setOverlayOrientation(int orientation) {
|
||||||
|
this.overlayOrientation = orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the overlay type of the Tile.
|
||||||
|
*
|
||||||
|
* @param type The overlay type.
|
||||||
|
*/
|
||||||
|
public void setOverlayType(int type) {
|
||||||
|
this.overlayType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the position of the Tile.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the Tile.
|
||||||
|
* @param y the y coordinate of the Tile
|
||||||
|
* @param height The height level of the Tile.
|
||||||
|
*/
|
||||||
|
public void setPosition(int x, int y, int height) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the underlay id of the Tile.
|
||||||
|
*
|
||||||
|
* @param underlay The underlay.
|
||||||
|
*/
|
||||||
|
public void setUnderlay(int underlay) {
|
||||||
|
this.underlay = underlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link Builder} for a Tile.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the Tile.
|
||||||
|
* @param y the y coordinate of the Tile.
|
||||||
|
* @param height The height level of the Tile.
|
||||||
|
* @return The Builder.
|
||||||
|
*/
|
||||||
|
public static Builder builder(int x, int y, int height) {
|
||||||
|
return new Builder(x, y, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes of this Tile.
|
||||||
|
*/
|
||||||
|
private final int attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of this Tile.
|
||||||
|
*/
|
||||||
|
private final int height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The overlay id of this Tile.
|
||||||
|
*/
|
||||||
|
private final int overlay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The overlay orientation of this Tile.
|
||||||
|
*/
|
||||||
|
private final int overlayOrientation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The overlay type of this Tile.
|
||||||
|
*/
|
||||||
|
private final int overlayType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x coordinate of this Tile.
|
||||||
|
*/
|
||||||
|
private final int x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y coordinate of this Tile.
|
||||||
|
*/
|
||||||
|
private final int y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlay id of this Tile.
|
||||||
|
*/
|
||||||
|
private final int underlay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the Tile.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the Tile.
|
||||||
|
* @param y The y coordinate of the Tile.
|
||||||
|
* @param attributes The attributes.
|
||||||
|
* @param height The height.
|
||||||
|
* @param overlay The overlay id.
|
||||||
|
* @param overlayType The overlay type.
|
||||||
|
* @param overlayOrientation The overlay orientation.
|
||||||
|
* @param underlay The underlay id.
|
||||||
|
*/
|
||||||
|
public Tile(int x, int y, int attributes, int height, int overlay, int overlayType, int overlayOrientation,
|
||||||
|
int underlay) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.attributes = attributes;
|
||||||
|
this.height = height;
|
||||||
|
this.overlay = overlay;
|
||||||
|
this.overlayType = overlayType;
|
||||||
|
this.overlayOrientation = overlayOrientation;
|
||||||
|
this.underlay = underlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the attributes of this Tile.
|
||||||
|
*
|
||||||
|
* @return The attributes.
|
||||||
|
*/
|
||||||
|
public int getAttributes() {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the height of this Tile.
|
||||||
|
*
|
||||||
|
* @return The height.
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the overlay id of this Tile.
|
||||||
|
*
|
||||||
|
* @return The overlay id.
|
||||||
|
*/
|
||||||
|
public int getOverlay() {
|
||||||
|
return overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the overlay orientation of this Tile.
|
||||||
|
*
|
||||||
|
* @return The overlay orientation.
|
||||||
|
*/
|
||||||
|
public int getOverlayOrientation() {
|
||||||
|
return overlayOrientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the overlay type of this Tile.
|
||||||
|
*
|
||||||
|
* @return The overlay types.
|
||||||
|
*/
|
||||||
|
public int getOverlayType() {
|
||||||
|
return overlayType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlay id of this Tile.
|
||||||
|
*
|
||||||
|
* @return The underlay id.
|
||||||
|
*/
|
||||||
|
public int getUnderlay() {
|
||||||
|
return underlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the x coordinate of this Tile.
|
||||||
|
*
|
||||||
|
* @return The x coordinate.
|
||||||
|
*/
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the y coordinate of this Tile.
|
||||||
|
*
|
||||||
|
* @return The y coordinate.
|
||||||
|
*/
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
package org.apollo.cache.map;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2013 Jonathan Edgecombe <jonathanedgecombe@gmail.com>
|
||||||
|
* Copyright (c) 2015 Major
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains tile-related utility methods.
|
||||||
|
*
|
||||||
|
* @author Johnny
|
||||||
|
* @author Major
|
||||||
|
*/
|
||||||
|
public final class TileUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x coordinate offset, used for computing the Tile height.
|
||||||
|
*/
|
||||||
|
static final int TILE_HEIGHT_X_OFFSET = 0xe3b7b;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The z coordinate offset, used for computing the Tile height.
|
||||||
|
*/
|
||||||
|
static final int TILE_HEIGHT_Z_OFFSET = 0x87cce;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cosine table used for interpolation.
|
||||||
|
*/
|
||||||
|
private static final int[] COSINE = new int[2048];
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (int index = 0; index < COSINE.length; index++) {
|
||||||
|
COSINE[index] = (int) (65536 * Math.cos(2 * Math.PI * index / COSINE.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the height offset for the specified coordinate pair.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the Tile.
|
||||||
|
* @param z The z coordinate of the Tile.
|
||||||
|
* @return The height offset.
|
||||||
|
*/
|
||||||
|
public static int calculateHeight(int x, int z) {
|
||||||
|
int regionSize = 8;
|
||||||
|
int regionOffset = 6;
|
||||||
|
int offset = regionOffset * regionSize;
|
||||||
|
|
||||||
|
int baseX = x - offset;
|
||||||
|
int baseZ = z - offset;
|
||||||
|
|
||||||
|
return computeHeight(x + TILE_HEIGHT_X_OFFSET - baseX, z + TILE_HEIGHT_Z_OFFSET - baseZ)
|
||||||
|
* MapConstants.HEIGHT_MULTIPLICAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the height offset for the specified coordinate pair.
|
||||||
|
*
|
||||||
|
* @param x The offset-x coordinate of the tile.
|
||||||
|
* @param z The offset-z coordinate of the tile.
|
||||||
|
* @return The tile height offset.
|
||||||
|
*/
|
||||||
|
private static int computeHeight(int x, int z) {
|
||||||
|
int total = interpolatedNoise(x + 45365, z + 91923, 4) - 128;
|
||||||
|
|
||||||
|
total += (interpolatedNoise(x + 10294, z + 37821, 2) - 128) / 2;
|
||||||
|
total += (interpolatedNoise(x, z, 1) - 128) / 4;
|
||||||
|
|
||||||
|
total = (int) Math.max(total * 0.3 + 35, 10);
|
||||||
|
return Math.min(total, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolates two smooth noise values.
|
||||||
|
*
|
||||||
|
* @param a The first smooth noise value.
|
||||||
|
* @param b The second smooth noise value.
|
||||||
|
* @param theta The angle.
|
||||||
|
* @param reciprocal The frequency reciprocal.
|
||||||
|
* @return The interpolated value.
|
||||||
|
*/
|
||||||
|
private static int interpolate(int a, int b, int theta, int reciprocal) {
|
||||||
|
int cosine = 65536 - COSINE[theta * COSINE.length / (2 * reciprocal)] / 2;
|
||||||
|
return (a * (65536 - cosine)) / 65536 + (b * cosine) / 65536;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets interpolated noise for the specified coordinate pair, using the specified frequency reciprocal.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate.
|
||||||
|
* @param z The z coordinate.
|
||||||
|
* @param reciprocal The frequency reciprocal.
|
||||||
|
* @return The interpolated noise.
|
||||||
|
*/
|
||||||
|
private static int interpolatedNoise(int x, int z, int reciprocal) {
|
||||||
|
int xt = x % reciprocal;
|
||||||
|
int zt = z % reciprocal;
|
||||||
|
|
||||||
|
x /= reciprocal;
|
||||||
|
z /= reciprocal;
|
||||||
|
|
||||||
|
int c = smoothNoise(x, z);
|
||||||
|
int e = smoothNoise(x + 1, z);
|
||||||
|
int ce = interpolate(c, e, xt, reciprocal);
|
||||||
|
|
||||||
|
int n = smoothNoise(x, z + 1);
|
||||||
|
int ne = smoothNoise(x + 1, z + 1);
|
||||||
|
int u = interpolate(n, ne, xt, reciprocal);
|
||||||
|
|
||||||
|
return interpolate(ce, u, zt, reciprocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes noise for the specified coordinate pair.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate.
|
||||||
|
* @param z The z coordinate.
|
||||||
|
* @return The noise.
|
||||||
|
*/
|
||||||
|
private static int noise(int x, int z) {
|
||||||
|
int n = x + z * 57;
|
||||||
|
n = (n << 13) ^ n;
|
||||||
|
n = (n * (n * n * 15731 + 789221) + 1376312589) & Integer.MAX_VALUE;
|
||||||
|
return (n >> 19) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes smooth noise for the specified coordinate pair.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate.
|
||||||
|
* @param z The z coordinate.
|
||||||
|
* @return The smooth noise.
|
||||||
|
*/
|
||||||
|
private static int smoothNoise(int x, int z) {
|
||||||
|
int corners = noise(x - 1, z - 1) + noise(x + 1, z - 1) + noise(x - 1, z + 1) + noise(x + 1, z + 1);
|
||||||
|
int sides = noise(x - 1, z) + noise(x + 1, z) + noise(x, z - 1) + noise(x, z + 1);
|
||||||
|
int center = noise(x, z);
|
||||||
|
|
||||||
|
return corners / 16 + sides / 8 + center / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sole private constructor to prevent instantiation.
|
||||||
|
*/
|
||||||
|
private TileUtils() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,10 +8,10 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apollo.cache.IndexedFileSystem;
|
import org.apollo.cache.IndexedFileSystem;
|
||||||
import org.apollo.cache.decoder.MapFileDecoder;
|
|
||||||
import org.apollo.cache.decoder.MapFileDecoder.MapDefinition;
|
|
||||||
import org.apollo.cache.decoder.ObjectDefinitionDecoder;
|
import org.apollo.cache.decoder.ObjectDefinitionDecoder;
|
||||||
import org.apollo.cache.def.ObjectDefinition;
|
import org.apollo.cache.def.ObjectDefinition;
|
||||||
|
import org.apollo.cache.map.MapIndex;
|
||||||
|
import org.apollo.cache.map.MapIndexDecoder;
|
||||||
import org.apollo.game.io.player.PlayerSerializer;
|
import org.apollo.game.io.player.PlayerSerializer;
|
||||||
import org.apollo.game.model.Position;
|
import org.apollo.game.model.Position;
|
||||||
import org.apollo.game.model.World;
|
import org.apollo.game.model.World;
|
||||||
@@ -85,10 +85,13 @@ public final class GameObjectDecoder implements Runnable {
|
|||||||
ObjectDefinitionDecoder decoder = new ObjectDefinitionDecoder(fs);
|
ObjectDefinitionDecoder decoder = new ObjectDefinitionDecoder(fs);
|
||||||
decoder.run();
|
decoder.run();
|
||||||
|
|
||||||
try {
|
MapIndexDecoder mapIndexDecoder = new MapIndexDecoder(fs);
|
||||||
Map<Integer, MapDefinition> definitions = MapFileDecoder.decode(fs);
|
mapIndexDecoder.run();
|
||||||
|
|
||||||
for (MapDefinition definition : definitions.values()) {
|
try {
|
||||||
|
Map<Integer, MapIndex> indices = MapIndex.getIndices();
|
||||||
|
|
||||||
|
for (MapIndex definition : indices.values()) {
|
||||||
int packed = definition.getPackedCoordinates();
|
int packed = definition.getPackedCoordinates();
|
||||||
int x = (packed >> 8 & 0xFF) * (Region.SIZE * Region.SIZE);
|
int x = (packed >> 8 & 0xFF) * (Region.SIZE * Region.SIZE);
|
||||||
int y = (packed & 0xFF) * (Region.SIZE * Region.SIZE);
|
int y = (packed & 0xFF) * (Region.SIZE * Region.SIZE);
|
||||||
@@ -97,7 +100,7 @@ public final class GameObjectDecoder implements Runnable {
|
|||||||
ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(objects));
|
ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(objects));
|
||||||
decodeObjects(decompressed, x, y);
|
decodeObjects(decompressed, x, y);
|
||||||
|
|
||||||
ByteBuffer terrain = fs.getFile(4, definition.getTerrainFile());
|
ByteBuffer terrain = fs.getFile(4, definition.getMapFile());
|
||||||
decompressed = ByteBuffer.wrap(CompressionUtil.degzip(terrain));
|
decompressed = ByteBuffer.wrap(CompressionUtil.degzip(terrain));
|
||||||
decodeTerrain(decompressed, x, y);
|
decodeTerrain(decompressed, x, y);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user