Replace clipping files with loading straight from the cache. (#540)

* Archive decompression from apollo

* Removed unused object definition fields

* Add more options to IndexedFileSystem

New methods are to read directly to a bytearray rather than allocating a large number of ByteBuffers on server startup for map loading. decompress is from client and will be depre

* Fix opcode 19 of object defs

* Initial commit of loading maps from cache

* Removed deprecated methods

Methods were in IndexedFileSystem for testing to ensure the getFileBytes method worked correctly.

* Some code cleanup to fix packaging.

#TODO review methods in CompressionUtil to use the best Gzip decompression

* map_index loading from cache

* Update pom.xml

Added commons compress dependency from maven for bzip2 decompression

* Renaming some object definition values.

* Update ObjectDefinition.java

Removed rest of unused variables

* Update ObjectDefinition.java

* Object Definitions loading from cache

* Remove dead code

* Remove unneeded files

Maps/Definitions now load from in the cache.

* Firemaking clipping
This commit is contained in:
MatthewBishop
2023-01-25 14:15:31 -05:00
committed by GitHub
parent f56402845b
commit 1ad531d244
1353 changed files with 551 additions and 475 deletions
@@ -213,7 +213,6 @@ public class GameEngine {
/**
* Initialise Handlers
*/
ObjectDefinition.loadConfig();
RegionFactory.load();
Doors.getSingleton().load();
DoubleDoors.getSingleton().load();
@@ -81,14 +81,24 @@ public class Firemaking {
GameEngine.itemHandler.createGroundItem(c, logId, c.absX, c.absY, 1, c.playerId);
}
}
final boolean walk;
int[] dir = { 0, 0 };
if (Region.getClipping(x - 1, y, c.heightLevel, -1, 0)) {
walk = true;
} else {
walk = false;
dir[0] = -1;
dir[1] = 0;
} else if (Region.getClipping(x + 1, y, c.heightLevel, 1, 0)) {
dir[0] = 1;
dir[1] = 0;
} else if (Region.getClipping(x, y - 1, c.heightLevel, 0, -1)) {
dir[0] = 0;
dir[1] = -1;
} else if (Region.getClipping(x, y + 1, c.heightLevel, 0, 1)) {
dir[0] = 0;
dir[1] = 1;
}
c.startAnimation(733);
c.getPlayerAssistant().walkTo(walk ? -1 : 1, 0);
c.getPlayerAssistant().walkTo(dir[0], dir[1]);
c.stopFiremaking = false;
CycleEventHandler.getSingleton().addEvent(c, new CycleEvent() {
@@ -121,7 +131,7 @@ public class Firemaking {
@Override
public void execute(CycleEventContainer container) {
c.turnPlayerTo(walk ? x + 1 : x - 1, y);
c.turnPlayerTo(x - dir[0], y - dir[1]);
c.logLit = true;
stopFiremaking(c);
container.stop();
@@ -164,4 +174,5 @@ public class Firemaking {
}
}
}
}
@@ -14,49 +14,14 @@ public class ByteStream {
offset += length;
}
public void setOffset(int position) {
offset = position;
}
public void setOffset(long position) {
offset = (int) position;
}
public int length() {
return buffer.length;
}
public byte getByte() {
return buffer[offset++];
}
public int getUByte() {
return buffer[offset++] & 0xff;
}
public int getShort() {
int val = (getByte() << 8) + getByte();
if (val > 32767) {
val -= 0x10000;
}
return val;
}
public int getUShort() {
return (getUByte() << 8) + getUByte();
}
public int getInt() {
return (getUByte() << 24) + (getUByte() << 16) + (getUByte() << 8)
+ getUByte();
}
public long getLong() {
return (getUByte() << 56) + (getUByte() << 48) + (getUByte() << 40)
+ (getUByte() << 32) + (getUByte() << 24) + (getUByte() << 16)
+ (getUByte() << 8) + getUByte();
}
public int getUSmart() {
int i = buffer[offset] & 0xff;
if (i < 128) {
@@ -65,31 +30,4 @@ public class ByteStream {
return getUShort() - 32768;
}
}
public String getNString() {
int i = offset;
while (buffer[offset++] != 0) {
;
}
return new String(buffer, i, offset - i - 1);
}
public byte[] getBytes() {
int i = offset;
while (buffer[offset++] != 10) {
;
}
byte abyte0[] = new byte[offset - i - 1];
System.arraycopy(buffer, i, abyte0, i - i, offset - 1 - i);
return abyte0;
}
public byte[] read(int length) {
byte[] b = new byte[length];
for (int i = 0; i < length; i++) {
b[i] = buffer[offset++];
}
return b;
}
}
@@ -1,102 +0,0 @@
package com.rs2.world.clip;
public final class ByteStreamExt {
public void skip(int length) {
currentOffset += length;
}
public ByteStreamExt(byte abyte0[]) {
buffer = abyte0;
currentOffset = 0;
}
public int readUnsignedByte() {
return buffer[currentOffset++] & 0xff;
}
public byte readSignedByte() {
return buffer[currentOffset++];
}
public int readUnsignedWord() {
currentOffset += 2;
return ((buffer[currentOffset - 2] & 0xff) << 8)
+ (buffer[currentOffset - 1] & 0xff);
}
public int readSignedWord() {
currentOffset += 2;
int i = ((buffer[currentOffset - 2] & 0xff) << 8)
+ (buffer[currentOffset - 1] & 0xff);
if (i > 32767) {
i -= 0x10000;
}
return i;
}
public int read3Bytes() {
currentOffset += 3;
return ((buffer[currentOffset - 3] & 0xff) << 16)
+ ((buffer[currentOffset - 2] & 0xff) << 8)
+ (buffer[currentOffset - 1] & 0xff);
}
public int readR3Bytes() {
currentOffset += 3;
return ((buffer[currentOffset - 1] & 0xff) << 16)
+ ((buffer[currentOffset - 2] & 0xff) << 8)
+ (buffer[currentOffset - 3] & 0xff);
}
public int readDWord() {
currentOffset += 4;
return ((buffer[currentOffset - 4] & 0xff) << 24)
+ ((buffer[currentOffset - 3] & 0xff) << 16)
+ ((buffer[currentOffset - 2] & 0xff) << 8)
+ (buffer[currentOffset - 1] & 0xff);
}
public long readQWord() {
long l = readDWord() & 0xffffffffL;
long l1 = readDWord() & 0xffffffffL;
return (l << 32) + l1;
}
public String readString() {
int i = currentOffset;
while (buffer[currentOffset++] != 10) {
;
}
return new String(buffer, i, currentOffset - i - 1);
}
public String readNewString() {
int i = currentOffset;
while (buffer[currentOffset++] != 0) {
;
}
return new String(buffer, i, currentOffset - i - 1);
}
public byte[] readBytes() {
int i = currentOffset;
while (buffer[currentOffset++] != 10) {
;
}
byte abyte0[] = new byte[currentOffset - i - 1];
System.arraycopy(buffer, i, abyte0, i - i, currentOffset - 1 - i);
return abyte0;
}
public void readBytes(int i, int j, byte abyte0[]) {
for (int l = j; l < j + i; l++) {
abyte0[l] = buffer[currentOffset++];
}
}
public byte buffer[];
public int currentOffset;
// removed useless static initializer
}
@@ -1,35 +0,0 @@
package com.rs2.world.clip;
public class MemoryArchive {
private final ByteStream cache;
private final ByteStream index;
private static final int INDEX_DATA_CHUNK_SIZE = 12;
public MemoryArchive(ByteStream cache, ByteStream index) {
this.cache = cache;
this.index = index;
}
public byte[] get(int dataIndex) {
try {
if (index.length() < dataIndex * INDEX_DATA_CHUNK_SIZE) {
return null;
}
index.setOffset(dataIndex * INDEX_DATA_CHUNK_SIZE);
long fileOffset = index.getLong();
int fileSize = index.getInt();
cache.setOffset(fileOffset);
byte[] buffer = cache.read(fileSize);
return buffer;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public int contentSize() {
return index.length() / 12;
}
}
@@ -1,260 +1,191 @@
package com.rs2.world.clip;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apollo.archive.Archive;
import org.apollo.jagcached.fs.IndexedFileSystem;
public final class ObjectDefinition {
private static ObjectDefinition[] definitions;
public static ObjectDefinition getObjectDef(int i) {
for (int j = 0; j < 20; j++) {
if (cache[j].type == i) {
return cache[j];
}
}
cacheIndex = (cacheIndex + 1) % 20;
ObjectDefinition class46 = cache[cacheIndex];
class46.type = i;
class46.setDefaults();
byte[] buffer = archive.get(i);
if (buffer != null && buffer.length > 0) {
class46.readValues(new ByteStreamExt(buffer));
}
return class46;
return definitions[i];
}
private void setDefaults() {
anIntArray773 = null;
anIntArray776 = null;
name = null;
description = null;
modifiedModelColors = null;
originalModelColors = null;
anInt744 = 1;
anInt761 = 1;
aBoolean767 = true;
aBoolean757 = true;
hasActions = false;
aBoolean762 = false;
aBoolean764 = false;
anInt781 = -1;
anInt775 = 16;
actions = null;
anInt746 = -1;
anInt758 = -1;
aBoolean779 = true;
anInt768 = 0;
aBoolean736 = false;
anInt774 = -1;
anInt749 = -1;
childrenIDs = null;
}
public static void loadConfig() {
archive = new MemoryArchive(new ByteStream(getBuffer("loc.dat")),
new ByteStream(getBuffer("loc.idx")));
cache = new ObjectDefinition[20];
for (int k = 0; k < 20; k++) {
cache[k] = new ObjectDefinition();
public static void loadConfig(IndexedFileSystem fs) throws IOException {
Archive config = Archive.decode(fs.getFile(0, 2));
ByteBuffer data = config.getEntry("loc.dat").getBuffer();
ByteBuffer idx = config.getEntry("loc.idx").getBuffer();
int count = idx.getShort(), index = 2;
int[] indices = new int[count];
for (int i = 0; i < count; i++) {
indices[i] = index;
index += idx.getShort();
}
definitions = new ObjectDefinition[count];
for (int i = 0; i < count; i++) {
data.position(indices[i]);
definitions[i] = readValues(i, data);
}
System.out.println("[ObjectDef] DONE LOADING OBJECT CONFIGURATION");
}
public static byte[] getBuffer(String s) {
try {
java.io.File f = new java.io.File("./data/world/object/" + s);
if (!f.exists()) {
return null;
}
byte[] buffer = new byte[(int) f.length()];
java.io.DataInputStream dis = new java.io.DataInputStream(
new java.io.FileInputStream(f));
dis.readFully(buffer);
dis.close();
return buffer;
} catch (Exception e) {
}
return null;
}
private static ObjectDefinition readValues(int id, ByteBuffer data) {
ObjectDefinition def = new ObjectDefinition();
def.type = id;
int[] modelId = null;
int[] modelType = null;
private void readValues(ByteStreamExt stream) {
int flag = -1;
boolean actions = false;
do {
int type = stream.readUnsignedByte();
int type = data.get() & 0xFF;
if (type == 0) {
break;
}
if (type == 1) {
int len = stream.readUnsignedByte();
int len = data.get() & 0xFF;
if (len > 0) {
if (anIntArray773 == null || lowMem) {
anIntArray776 = new int[len];
anIntArray773 = new int[len];
if (modelId == null) {
modelType = new int[len];
modelId = new int[len];
for (int k1 = 0; k1 < len; k1++) {
anIntArray773[k1] = stream.readUnsignedWord();
anIntArray776[k1] = stream.readUnsignedByte();
modelId[k1] = data.getShort() & 0xFFFF;
modelType[k1] = data.get() & 0xFF;
}
} else {
stream.currentOffset += len * 3;
for (int i = 0; i < len; i++) {
data.getShort();
data.get();
}
}
}
} else if (type == 2) {
name = stream.readNewString();
def.name = readString(data);
} else if (type == 3) {
readString(data);
} else if (type == 5) {
int len = stream.readUnsignedByte();
int len = data.get() & 0xFF;
if (len > 0) {
if (anIntArray773 == null || lowMem) {
anIntArray776 = null;
anIntArray773 = new int[len];
if (modelId == null) {
modelType = null;
modelId = new int[len];
for (int l1 = 0; l1 < len; l1++) {
anIntArray773[l1] = stream.readUnsignedWord();
modelId[l1] = data.getShort() & 0xFFFF;
}
} else {
stream.currentOffset += len * 2;
for (int i = 0; i < len; i++) {
data.getShort();
}
}
}
} else if (type == 14) {
anInt744 = stream.readUnsignedByte();
def.width = data.get() & 0xFF;
} else if (type == 15) {
anInt761 = stream.readUnsignedByte();
def.length = data.get() & 0xFF;
} else if (type == 17) {
aBoolean767 = false;
def.solid = false;
} else if (type == 18) {
aBoolean757 = false;
def.impenetrable = false;
} else if (type == 19) {
hasActions = stream.readUnsignedByte() == 1;
flag = data.get() & 0xFF;
def.hasActions = flag == 1;
} else if (type == 21) {
aBoolean762 = true;
// aBoolean762 = true;
} else if (type == 22) {
} else if (type == 23) {
aBoolean764 = true;
// aBoolean764 = true;
} else if (type == 24) {
anInt781 = stream.readUnsignedWord();
if (anInt781 == 65535) {
anInt781 = -1;
}
data.getShort();
} else if (type == 27) {
continue;
} else if (type == 28) {
anInt775 = stream.readUnsignedByte();
data.get();
} else if (type == 29) {
stream.readSignedByte();
data.get();
} else if (type == 39) {
stream.readSignedByte();
data.get();
} else if (type >= 30 && type < 39) {
if (actions == null) {
actions = new String[5];
}
actions[type - 30] = stream.readNewString();
hasActions = true;
if (actions[type - 30].equalsIgnoreCase("hidden")) {
actions[type - 30] = null;
}
actions = true;
readString(data);
def.hasActions = true;
} else if (type == 40) {
int i1 = stream.readUnsignedByte();
modifiedModelColors = new int[i1];
originalModelColors = new int[i1];
for (int i2 = 0; i2 < i1; i2++) {
modifiedModelColors[i2] = stream.readUnsignedWord();
originalModelColors[i2] = stream.readUnsignedWord();
int amount = data.get() & 0xFF;
for (int i = 0; i < amount; i++) {
data.getShort();
data.getShort();
}
} else if (type == 41) {
int l = stream.readUnsignedByte();
stream.skip(l * 4);
} else if (type == 42) {
int l = stream.readUnsignedByte();
stream.skip(l);
} else if (type == 60) {
anInt746 = stream.readUnsignedWord();
data.getShort();
} else if (type == 62) {
} else if (type == 64) {
aBoolean779 = false;
def.clipped = false;
} else if (type == 65) {
stream.readUnsignedWord();
data.getShort();
} else if (type == 66) {
stream.readUnsignedWord();
data.getShort();
} else if (type == 67) {
stream.readUnsignedWord();
data.getShort();
} else if (type == 68) {
anInt758 = stream.readUnsignedWord();
data.getShort();
} else if (type == 69) {
anInt768 = stream.readUnsignedByte();
data.get();
} else if (type == 70) {
stream.readSignedWord();
data.getShort();
} else if (type == 71) {
stream.readSignedWord();
data.getShort();
} else if (type == 72) {
stream.readSignedWord();
data.getShort();
} else if (type == 73) {
aBoolean736 = true;
// #TODO obstructive = true;
} else if (type == 74) {
} else if (type == 75) {
stream.readUnsignedByte();
} else if (type == 77 || type == 92) {
anInt774 = stream.readUnsignedWord();
if (anInt774 == 65535) {
anInt774 = -1;
}
anInt749 = stream.readUnsignedWord();
if (anInt749 == 65535) {
anInt749 = -1;
}
int endChild = -1;
if (type == 92) {
endChild = stream.readUnsignedWord();
if (endChild == 65535) {
endChild = -1;
}
}
int j1 = stream.readUnsignedByte();
childrenIDs = new int[j1 + 2];
for (int j2 = 0; j2 <= j1; j2++) {
childrenIDs[j2] = stream.readUnsignedWord();
if (childrenIDs[j2] == 65535) {
childrenIDs[j2] = -1;
}
}
childrenIDs[j1 + 1] = endChild;
} else if (type == 78) {
stream.skip(3);
} else if (type == 79) {
stream.skip(5);
int l = stream.readUnsignedByte();
stream.skip(l * 2);
} else if (type == 81) {
stream.skip(1);
} else if (type == 82 || type == 88 || type == 89 || type == 90
|| type == 91 || type == 94 || type == 95 || type == 96
|| type == 97) {
continue;
} else if (type == 93) {
stream.skip(2);
} else if (type == 249) {
int l = stream.readUnsignedByte();
for (int ii = 0; ii < l; ii++) {
boolean b = stream.readUnsignedByte() == 1;
stream.skip(3);
if (b) {
stream.readNewString();
} else {
stream.skip(4);
}
data.get();
} else if (type == 77) {
data.getShort();
data.getShort();
int count = data.get() & 0xFF;
for (int i = 0; i <= count; i++) {
data.getShort();
}
} else {
System.out.println("Unknown config: " + type);
System.out.println("Unknown config: " + type);
System.exit(0);
}
} while (true);
if (flag == -1) {
hasActions = anIntArray773 != null
&& (anIntArray776 == null || anIntArray776[0] == 10);
if (actions != null) {
hasActions = true;
def.hasActions = modelId != null && (modelType == null || modelType[0] == 10);
if (actions) {
def.hasActions = true;
}
}
return def;
}
/**
* Reads a string from the specified {@link ByteBuffer}.
*
* @param buffer The buffer.
* @return The string.
*/
public static String readString(ByteBuffer buffer) {
StringBuilder bldr = new StringBuilder();
char character;
while ((character = (char) buffer.get()) != 10) {
bldr.append(character);
}
return bldr.toString();
}
private ObjectDefinition() {
type = -1;
}
/*
* TODO is this needed? Only called by type 22 objects (ground decorations/map signs).
*/
public boolean hasActions() {
return hasActions;
}
@@ -264,53 +195,32 @@ public final class ObjectDefinition {
}
public boolean solid() {
return aBoolean779;
return clipped;
}
public int xLength() {
return anInt744;
return width;
}
public int yLength() {
return anInt761;
return length;
}
public boolean aBoolean767() {
return aBoolean767;
return solid;
}
public boolean isUnshootable() {
return aBoolean757;
return impenetrable;
}
public boolean aBoolean736;
public String name;
public int anInt744;
public int anInt746;
private int[] originalModelColors;
public int anInt749;
public static boolean lowMem;
public int type;
public boolean aBoolean757;
public int anInt758;
public int childrenIDs[];
public int anInt761;
public boolean aBoolean762;
public boolean aBoolean764;
public boolean aBoolean767;
public int anInt768;
private static int cacheIndex;
private int[] anIntArray773;
public int anInt774;
public int anInt775;
private int[] anIntArray776;
public byte description[];
public boolean hasActions;
public boolean aBoolean779;
public int anInt781;
private static ObjectDefinition[] cache;
private int[] modifiedModelColors;
public String actions[];
private static MemoryArchive archive;
public String name = null;
private int width = 1;
@SuppressWarnings("unused")
private int type;
private boolean impenetrable = true;
private int length = 1;
private boolean solid = true;
private boolean hasActions = false;
private boolean clipped = true;
}
@@ -1,10 +1,15 @@
package com.rs2.world.clip;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.zip.GZIPInputStream;
import java.nio.ByteBuffer;
import org.apollo.archive.Archive;
import org.apollo.archive.ArchiveEntry;
import org.apollo.archive.CompressionUtil;
import org.apollo.jagcached.Constants;
import org.apollo.jagcached.fs.IndexedFileSystem;
public class RegionFactory {
@@ -17,13 +22,14 @@ public class RegionFactory {
public static void load() {
//GameEngine.getLogger(Region.class).info("Loading region configurations...");
try {
File f = new File("./data/world/map_index");
byte[] buffer = new byte[(int) f.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(f));
dis.readFully(buffer);
dis.close();
ByteStream in = new ByteStream(buffer);
int size = in.length() / 7;
IndexedFileSystem fs = new IndexedFileSystem(new File(Constants.FILE_SYSTEM_DIR), true);
ObjectDefinition.loadConfig(fs);
Archive archive = Archive.decode(fs.getFile(0, 5));
ArchiveEntry entry = archive.getEntry("map_index");
ByteBuffer buffer = entry.getBuffer();
int size = buffer.capacity() / 7;
regions = new Region[size];
int[] regionIds = new int[size];
int[] mapGroundFileIds = new int[size];
@@ -37,10 +43,10 @@ public class RegionFactory {
* isMembers (8 bits)
*/
for (int i = 0; i < size; i++) {
regionIds[i] = in.getUShort();
mapGroundFileIds[i] = in.getUShort();
mapObjectsFileIds[i] = in.getUShort();
isMembers[i] = in.getUByte() == 0;
regionIds[i] = buffer.getShort() & 0xFFFF;
mapGroundFileIds[i] = buffer.getShort() & 0xFFFF;
mapObjectsFileIds[i] = buffer.getShort() & 0xFFFF;
isMembers[i] = buffer.get() == 0;
}
for (int i = 0; i < size; i++) {
regions[i] = new Region(regionIds[i], isMembers[i]);
@@ -49,11 +55,9 @@ public class RegionFactory {
//GameEngine.getLogger(Region.class).info("Populating regions...");
for (int i = 0; i < size; i++) {
//GameEngine.getLogger(Region.class).info("Region: " + i + " RegionId: " + regionIds[i] + " ObjectsId: " + mapObjectsFileIds[i]
// + " ClippingsId: " + mapGroundFileIds[i]);
byte[] file1 = getBuffer(new File("./data/world/map/"
+ mapObjectsFileIds[i] + ".gz"));
byte[] file2 = getBuffer(new File("./data/world/map/"
+ mapGroundFileIds[i] + ".gz"));
// + " ClippingsId: " + mapGroundFileIds[i]);
byte[] file1 = CompressionUtil.degzip(fs.getFileBytes(4, mapObjectsFileIds[i]));
byte[] file2 = CompressionUtil.degzip(fs.getFileBytes(4, mapGroundFileIds[i]));
if (file1 == null || file2 == null) {
continue;
}
@@ -158,39 +162,4 @@ public class RegionFactory {
}
}
}
public static byte[] getBuffer(File f) throws Exception {
if (!f.exists()) {
return null;
}
byte[] buffer = new byte[(int) f.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(f));
dis.readFully(buffer);
dis.close();
byte[] gzipInputBuffer = new byte[999999];
int bufferlength = 0;
GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(
buffer));
do {
if (bufferlength == gzipInputBuffer.length) {
System.out
.println("Error inflating data.\nGZIP buffer overflow.");
break;
}
int readByte = gzip.read(gzipInputBuffer, bufferlength,
gzipInputBuffer.length - bufferlength);
if (readByte == -1) {
break;
}
bufferlength += readByte;
} while (true);
byte[] inflated = new byte[bufferlength];
System.arraycopy(gzipInputBuffer, 0, inflated, 0, bufferlength);
buffer = inflated;
if (buffer.length < 10) {
return null;
}
return buffer;
}
}