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:
Gary Tierney
2016-12-30 23:42:48 +00:00
parent b7a57fa973
commit 6a4625cb32
12 changed files with 1171 additions and 141 deletions
@@ -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;
}
}
+62
View File
@@ -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() {
}
}
+48
View File
@@ -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();
}
}
+123
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+90
View File
@@ -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
View File
@@ -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
View File
@@ -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() {
}
}