mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-05 08:40:08 +00:00
Start on collision matrix.
This commit is contained in:
@@ -3,28 +3,55 @@ package org.apollo.fs.decoder;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.apollo.fs.IndexedFileSystem;
|
import org.apollo.fs.IndexedFileSystem;
|
||||||
import org.apollo.fs.archive.Archive;
|
import org.apollo.fs.decoder.MapFileDecoder.MapDefinition;
|
||||||
import org.apollo.game.model.Position;
|
import org.apollo.game.model.Position;
|
||||||
|
import org.apollo.game.model.World;
|
||||||
|
import org.apollo.game.model.area.Sector;
|
||||||
|
import org.apollo.game.model.area.SectorRepository;
|
||||||
|
import org.apollo.game.model.area.collision.CollisionMatrix;
|
||||||
import org.apollo.game.model.entity.GameObject;
|
import org.apollo.game.model.entity.GameObject;
|
||||||
import org.apollo.util.BufferUtil;
|
import org.apollo.util.BufferUtil;
|
||||||
import org.apollo.util.CompressionUtil;
|
import org.apollo.util.CompressionUtil;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes map object data from the {@code map_index.dat} file into {@link GameObject}s.
|
* Parses static object definitions, which include map tiles and landscapes.
|
||||||
*
|
*
|
||||||
* @author Chris Fletcher
|
* @author Ryley
|
||||||
*/
|
*/
|
||||||
public final class GameObjectDecoder {
|
public final class GameObjectDecoder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bit flag which denotes that a specified Position is blocked.
|
||||||
|
*/
|
||||||
|
private static final int FLAG_BLOCKED = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bit flag which denotes that a specified Position is a bridge.
|
||||||
|
*/
|
||||||
|
private static final int FLAG_BRIDGE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sector repository.
|
||||||
|
*/
|
||||||
|
private static final SectorRepository sectors = World.getWorld().getSectorRepository();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link IndexedFileSystem}.
|
* The {@link IndexedFileSystem}.
|
||||||
*/
|
*/
|
||||||
private final IndexedFileSystem fs;
|
private final IndexedFileSystem fs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link List} of decoded game objects.
|
||||||
|
*/
|
||||||
|
private final List<GameObject> objects = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the decoder.
|
* Creates the decoder.
|
||||||
*
|
*
|
||||||
@@ -41,80 +68,87 @@ public final class GameObjectDecoder {
|
|||||||
* @throws IOException If an I/O error occurs.
|
* @throws IOException If an I/O error occurs.
|
||||||
*/
|
*/
|
||||||
public GameObject[] decode() throws IOException {
|
public GameObject[] decode() throws IOException {
|
||||||
Archive versionList = Archive.decode(fs.getFile(0, 5));
|
Map<Integer, MapDefinition> definitions = MapFileDecoder.parse(fs);
|
||||||
ByteBuffer buffer = versionList.getEntry("map_index").getBuffer();
|
|
||||||
|
|
||||||
int indices = buffer.remaining() / 7;
|
for (Entry<Integer, MapDefinition> entry : definitions.entrySet()) {
|
||||||
int[] areas = new int[indices];
|
MapDefinition def = entry.getValue();
|
||||||
int[] landscapes = new int[indices];
|
|
||||||
|
|
||||||
for (int i = 0; i < indices; i++) {
|
int hash = def.getHash();
|
||||||
areas[i] = buffer.getShort() & 0xFFFF;
|
int x = (hash >> 8 & 0xFF) * 64;
|
||||||
|
int y = (hash & 0xFF) * 64;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
ByteBuffer gameObjectData = fs.getFile(4, def.getObjectFile());
|
||||||
int mapFile = buffer.getShort() & 0xFFFF;
|
ByteBuffer gameObjectBuffer = ByteBuffer.wrap(CompressionUtil.degzip(gameObjectData));
|
||||||
|
parseGameObject(gameObjectBuffer, x, y);
|
||||||
|
|
||||||
landscapes[i] = buffer.getShort() & 0xFFFF;
|
ByteBuffer terrainData = fs.getFile(4, def.getTerrainFile());
|
||||||
|
ByteBuffer terrainBuffer = ByteBuffer.wrap(CompressionUtil.degzip(terrainData));
|
||||||
@SuppressWarnings("unused")
|
parseTerrain(terrainBuffer, x, y);
|
||||||
boolean members = (buffer.get() & 0xFF) == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GameObject> objects = new ArrayList<>();
|
return Iterables.toArray(objects, GameObject.class);
|
||||||
|
|
||||||
for (int i = 0; i < indices; i++) {
|
|
||||||
ByteBuffer compressed = fs.getFile(4, landscapes[i]);
|
|
||||||
ByteBuffer uncompressed = ByteBuffer.wrap(CompressionUtil.degzip(compressed));
|
|
||||||
|
|
||||||
Collection<GameObject> areaObjects = parseArea(areas[i], uncompressed);
|
|
||||||
objects.addAll(areaObjects);
|
|
||||||
}
|
|
||||||
|
|
||||||
return objects.toArray(new GameObject[objects.size()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void parseGameObject(ByteBuffer buffer, int x, int y) {
|
||||||
* Parses a single area from the specified buffer.
|
for (int deltaId, id = -1; (deltaId = BufferUtil.readSmart(buffer)) != 0;) {
|
||||||
*
|
id += deltaId;
|
||||||
* @param area The identifier of that area.
|
|
||||||
* @param buffer The buffer which holds the area's data.
|
|
||||||
* @return A collection of all parsed objects.
|
|
||||||
*/
|
|
||||||
private static Collection<GameObject> parseArea(int area, ByteBuffer buffer) {
|
|
||||||
List<GameObject> objects = new ArrayList<>();
|
|
||||||
|
|
||||||
int x = (area >> 8 & 0xFF) * 64;
|
for (int deltaPos, hash = 0; (deltaPos = BufferUtil.readSmart(buffer)) != 0;) {
|
||||||
int y = (area & 0xFF) * 64;
|
hash += deltaPos - 1;
|
||||||
|
|
||||||
int id = -1;
|
int localX = hash >> 6 & 0x3F;
|
||||||
int idOffset;
|
int localY = hash & 0x3F;
|
||||||
|
int height = hash >> 12 & 0x3;
|
||||||
|
|
||||||
while ((idOffset = BufferUtil.readSmart(buffer)) != 0) {
|
int attributes = buffer.get() & 0xFF;
|
||||||
id += idOffset;
|
int type = attributes >> 2;
|
||||||
|
int orientation = attributes & 0x3;
|
||||||
|
Position position = new Position(x + localX, y + localY, height);
|
||||||
|
|
||||||
int position = 0;
|
gameObjectDecoded(id, orientation, type, position);
|
||||||
int positionOffset;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while ((positionOffset = BufferUtil.readSmart(buffer)) != 0) {
|
private void gameObjectDecoded(int id, int orientation, int type, Position position) {
|
||||||
position += positionOffset - 1;
|
|
||||||
|
|
||||||
int localX = position >> 6 & 0x3F;
|
}
|
||||||
int localY = position & 0x3F;
|
|
||||||
int height = position >> 12;
|
|
||||||
|
|
||||||
int info = buffer.get() & 0xFF;
|
private void parseTerrain(ByteBuffer buffer, int x, int y) {
|
||||||
int type = info >> 2;
|
for (int height = 0; height < 4; height++) {
|
||||||
int rotation = info & 3;
|
for (int localX = 0; localX < 64; localX++) {
|
||||||
if (type >= 0 && type <= 3 || type >= 9 && type <= 21) {
|
for (int localY = 0; localY < 64; localY++) {
|
||||||
Position pos = new Position(x + localX, y + localY, height);
|
Position position = new Position(x + localX, y + localY, height);
|
||||||
|
|
||||||
GameObject object = new GameObject(id, pos, type, rotation);
|
int flags = 0;
|
||||||
objects.add(object);
|
for (;;) {
|
||||||
|
int attributeId = buffer.get() & 0xFF;
|
||||||
|
if (attributeId == 0) {
|
||||||
|
terrainDecoded(flags, position);
|
||||||
|
break;
|
||||||
|
} else if (attributeId == 1) {
|
||||||
|
buffer.get();
|
||||||
|
terrainDecoded(flags, position);
|
||||||
|
break;
|
||||||
|
} else if (attributeId <= 49) {
|
||||||
|
buffer.get();
|
||||||
|
} else if (attributeId <= 81) {
|
||||||
|
flags = attributeId - 49;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return objects;
|
private void terrainDecoded(int flags, Position position) {
|
||||||
|
Sector sector = sectors.fromPosition(position);
|
||||||
|
|
||||||
|
if ((flags & FLAG_BLOCKED) != 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if((flags & FLAG_BRIDGE) != 0) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package org.apollo.fs.decoder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apollo.fs.IndexedFileSystem;
|
||||||
|
import org.apollo.fs.archive.Archive;
|
||||||
|
import org.apollo.fs.archive.ArchiveEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses {@link MapDefinition map definitions} from the {@link IndexedFileSystem}.
|
||||||
|
*
|
||||||
|
* @author Ryley
|
||||||
|
*/
|
||||||
|
public final class MapFileDecoder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses {@link MapDefinition}s from the specified {@link IndexedFileSystem}.
|
||||||
|
*
|
||||||
|
* @param fs The file system.
|
||||||
|
* @return A {@link Map} of parsed map definitions.
|
||||||
|
* @throws IOException If some I/O error occurs.
|
||||||
|
*/
|
||||||
|
protected static Map<Integer, MapDefinition> parse(IndexedFileSystem fs) throws IOException {
|
||||||
|
Archive archive = Archive.decode(fs.getFile(0, 5));
|
||||||
|
ArchiveEntry entry = archive.getEntry("map_index");
|
||||||
|
ByteBuffer buffer = entry.getBuffer();
|
||||||
|
Map<Integer, MapDefinition> defs = new HashMap<>();
|
||||||
|
|
||||||
|
int count = buffer.capacity() / 7;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int hash = buffer.getShort() & 0xFFFF;
|
||||||
|
int terrainFile = buffer.getShort() & 0xFFFF;
|
||||||
|
int objectFile = buffer.getShort() & 0xFFFF;
|
||||||
|
boolean preload = buffer.get() == 1;
|
||||||
|
|
||||||
|
defs.put(hash, new MapDefinition(hash, terrainFile, objectFile, preload));
|
||||||
|
}
|
||||||
|
|
||||||
|
return defs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single map definition.
|
||||||
|
*
|
||||||
|
* @author Ryley
|
||||||
|
*/
|
||||||
|
public static final class MapDefinition {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hash of the region coordinates.
|
||||||
|
*/
|
||||||
|
private final int hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The terrain file id.
|
||||||
|
*/
|
||||||
|
private final int terrainFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object file id.
|
||||||
|
*/
|
||||||
|
private final int objectFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this map is preloaded.
|
||||||
|
*/
|
||||||
|
private final boolean preload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link MapDefinition} with the specified hash, terrain file id, object file id and preload
|
||||||
|
* state.
|
||||||
|
*
|
||||||
|
* @param hash The hash of the region coordinates.
|
||||||
|
* @param terrainFile The terrain file id.
|
||||||
|
* @param objectFile The object file id.
|
||||||
|
* @param preload Whether or not this map is preloaded.
|
||||||
|
*/
|
||||||
|
public MapDefinition(int hash, int terrainFile, int objectFile, boolean preload) {
|
||||||
|
this.hash = hash;
|
||||||
|
this.terrainFile = terrainFile;
|
||||||
|
this.objectFile = objectFile;
|
||||||
|
this.preload = preload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the coordinate hash.
|
||||||
|
*/
|
||||||
|
public int getHash() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the terrain file id.
|
||||||
|
*/
|
||||||
|
public int getTerrainFile() {
|
||||||
|
return terrainFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the object file id.
|
||||||
|
*/
|
||||||
|
public int getObjectFile() {
|
||||||
|
return objectFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not this map is preloaded.
|
||||||
|
*/
|
||||||
|
public boolean isPreload() {
|
||||||
|
return preload;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user