Initial cache library upgrade push old Dragonkk implementation -> Displee's cache library

This commit is contained in:
woahscam 2022-11-28 01:37:41 -05:00
parent 7f9656d40a
commit 679d9e126e
44 changed files with 609 additions and 2154 deletions

View file

@ -90,6 +90,11 @@
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.displee</groupId>
<artifactId>rs-cache-library</artifactId>
<version>6.9-RC2</version>
</dependency>
</dependencies>
<build>

View file

@ -1,238 +0,0 @@
package core.cache;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import rs09.ServerConstants;
import core.cache.def.impl.AnimationDefinition;
import core.cache.def.impl.GraphicDefinition;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.NPCDefinition;
import core.cache.def.impl.SceneryDefinition;
import rs09.game.system.SystemLogger;
/**
* A cache reader.
*
* @author Emperor
* @author Dragonkk
*/
public final class Cache {
/**
* The cache file manager.
*/
private static CacheFileManager[] cacheFileManagers;
/**
* The container cache file informer.
*/
private static CacheFile referenceFile;
/**
* Construct a new instance.
*/
private Cache(String location) {
try {
init(location);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Initialize the cache reader.
*
* @param path The cache path.x
* @throws Throwable When an exception occurs.
*/
public static void init(String path) throws Throwable {
SystemLogger.logInfo(Cache.class, "Initializing cache...");
byte[] cacheFileBuffer = new byte[520];
RandomAccessFile containersInformFile = new RandomAccessFile(path + File.separator + "main_file_cache.idx255", "r");
RandomAccessFile dataFile = new RandomAccessFile(path + File.separator + "main_file_cache.dat2", "r");
referenceFile = new CacheFile(255, containersInformFile, dataFile, 500000, cacheFileBuffer);
int length = (int) (containersInformFile.length() / 6);
cacheFileManagers = new CacheFileManager[length];
for (int i = 0; i < length; i++) {
File f = new File(path + File.separator + "main_file_cache.idx" + i);
if (f.exists() && f.length() > 0) {
CacheFile cacheFile = new CacheFile(i, new RandomAccessFile(f, "r"), dataFile, 1000000, cacheFileBuffer);
cacheFileManagers[i] = new CacheFileManager(cacheFile, true);
if (cacheFileManagers[i].getInformation() == null) {
SystemLogger.logErr(Cache.class, "Error loading cache index " + i + ": no information.");
cacheFileManagers[i] = null;
}
}
}
ItemDefinition.parse();
SceneryDefinition.parse();
}
/**
* Initializes the cache.
*/
public static void init() {
try {
init(ServerConstants.CACHE_PATH);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Gets the archive buffer for the grab requests.
*
* @param index The index id.
* @param archive The archive id.
* @param priority The priority.
* @param encryptionValue The current encryption value.
* @return The byte buffer.
*/
public static ByteBuffer getArchiveData(int index, int archive, boolean priority, int encryptionValue) {
byte[] data = index == 255 ? referenceFile.getContainerData(archive) : cacheFileManagers[index].getCacheFile().getContainerData(archive);
if (data == null || data.length < 1) {
SystemLogger.logErr(Cache.class, "Invalid JS-5 request - " + index + ", " + archive + ", " + priority + ", " + encryptionValue + "!");
return null;
}
int compression = data[0] & 0xff;
int length = ((data[1] & 0xff) << 24) + ((data[2] & 0xff) << 16) + ((data[3] & 0xff) << 8) + (data[4] & 0xff);
int settings = compression;
if (!priority) {
settings |= 0x80;
}
int realLength = compression != 0 ? length + 4 : length;
// TODO There are two archives that lack two bytes at the end (The version, most likely). This causes the client CRC to be miscalculated. To combat this, we simply send two more bytes if the length seems to be off.
realLength += (index != 255 && compression != 0 && data.length - length == 9) ? 2 : 0;
ByteBuffer buffer = ByteBuffer.allocate((realLength + 5) + (realLength / 512) + 10);
buffer.put((byte) index);
buffer.putShort((short) archive);
buffer.put((byte) settings);
buffer.putInt(length);
for (int i = 5; i < realLength + 5; i++) {
if (buffer.position() % 512 == 0) {
buffer.put((byte) 255);
}
if (data.length > i)
buffer.put(data[i]);
else
buffer.put((byte) 0);
}
if (encryptionValue != 0) {
for (int i = 0; i < buffer.position(); i++) {
buffer.put(i, (byte) (buffer.get(i) ^ encryptionValue));
}
}
buffer.flip();
return buffer;
}
/**
* Generate the reference data for the cache files.
*
* @return The reference data byte array.
*/
public static final byte[] generateReferenceData() {
ByteBuffer buffer = ByteBuffer.allocate(cacheFileManagers.length * 8);
for (int index = 0; index < cacheFileManagers.length; index++) {
if (cacheFileManagers[index] == null) {
buffer.putInt(index == 24 ? 609698396 : 0);
buffer.putInt(0);
continue;
}
buffer.putInt(cacheFileManagers[index].getInformation().getInformationContainer().getCrc());
buffer.putInt(cacheFileManagers[index].getInformation().getRevision());
}
return buffer.array();
}
/**
* Get the cache file managers.
*
* @return The cache file managers.
*/
public static final CacheFileManager[] getIndexes() {
return cacheFileManagers;
}
/**
* Get the container cache file informer.
*
* @return The container cache file informer.
*/
public static final CacheFile getReferenceFile() {
return referenceFile;
}
/**
* Method used to return the component size of the interface.
*
* @param interfaceId the interface.
* @return the value.
*/
public static final int getInterfaceDefinitionsComponentsSize(int interfaceId) {
return getIndexes()[3].getFilesSize(interfaceId);
}
/**
* Method used to return the max size of the interface definitions.
*
* @return the size.
*/
public static final int getInterfaceDefinitionsSize() {
return getIndexes()[3].getContainersSize();
}
/**
* Method used to return the {@link NPCDefinition} size.
*
* @return the size.
*/
public static final int getNPCDefinitionsSize() {
int lastContainerId = getIndexes()[18].getContainersSize() - 1;
return lastContainerId * 128 + getIndexes()[18].getFilesSize(lastContainerId);
}
/**
* Method used to return the {@link GraphicDefinition} size.
*
* @return the size.
*/
public static final int getGraphicDefinitionsSize() {
int lastContainerId = getIndexes()[21].getContainersSize() - 1;
return lastContainerId * 256 + getIndexes()[21].getFilesSize(lastContainerId);
}
/**
* Method used to return the {@link AnimationDefinition} size.
*
* @return the size.
*/
public static final int getAnimationDefinitionsSize() {
int lastContainerId = getIndexes()[20].getContainersSize() - 1;
return lastContainerId * 128 + getIndexes()[20].getFilesSize(lastContainerId);
}
/**
* Method used to return the {@link SceneryDefinition} size.
*
* @return the size.
*/
public static final int getObjectDefinitionsSize() {
int lastContainerId = getIndexes()[16].getContainersSize() - 1;
return lastContainerId * 256 + getIndexes()[16].getFilesSize(lastContainerId);
}
/**
* Method used to return the item definition size.
*
* @return the size.
*/
public static final int getItemDefinitionsSize() {
int lastContainerId = getIndexes()[19].getContainersSize() - 1;
return lastContainerId * 256 + getIndexes()[19].getFilesSize(lastContainerId);
}
}

View file

@ -1,148 +0,0 @@
package core.cache;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import core.cache.crypto.XTEACryption;
import core.cache.misc.ContainersInformation;
/**
* A cache file.
* @author Dragonkk
*/
public final class CacheFile {
/**
* The index file id.
*/
private int indexFileId;
/**
* The cache file buffer.
*/
private byte[] cacheFileBuffer;
/**
* The maximum container size.
*/
private int maxContainerSize;
/**
* The index file.
*/
private RandomAccessFile indexFile;
/**
* The data file.
*/
private RandomAccessFile dataFile;
/**
* Construct a new cache file.
* @param indexFileId The index file id.
* @param indexFile The index file.
* @param dataFile The data file.
* @param maxContainerSize The maximum container size.
* @param cacheFileBuffer The cache file buffer.
*/
public CacheFile(int indexFileId, RandomAccessFile indexFile, RandomAccessFile dataFile, int maxContainerSize, byte[] cacheFileBuffer) {
this.cacheFileBuffer = cacheFileBuffer;
this.indexFileId = indexFileId;
this.maxContainerSize = maxContainerSize;
this.indexFile = indexFile;
this.dataFile = dataFile;
}
/**
* Get the unpacked container data.
* @param containerId The container id.
* @param xteaKeys The container keys.
* @return The unpacked container data.
*/
public final byte[] getContainerUnpackedData(int containerId, int[] xteaKeys) {
byte[] packedData = getContainerData(containerId);
if (packedData == null) {
return null;
}
if (xteaKeys != null && (xteaKeys[0] != 0 || xteaKeys[1] != 0 || xteaKeys[2] != 0 || xteaKeys[3] != 0)) {
packedData = XTEACryption.decrypt(xteaKeys, ByteBuffer.wrap(packedData), 5, packedData.length).array();
}
return ContainersInformation.unpackCacheContainer(packedData);
}
/**
* Get the container data for the specified container id.
* @param containerId The container id.
* @return The container data.
*/
public final byte[] getContainerData(int containerId) {
synchronized (dataFile) {
try {
if (indexFile.length() < (6 * containerId + 6)) {
return null;
}
indexFile.seek(6 * containerId);
indexFile.read(cacheFileBuffer, 0, 6);
int containerSize = (cacheFileBuffer[2] & 0xff) + (((0xff & cacheFileBuffer[0]) << 16) + (cacheFileBuffer[1] << 8 & 0xff00));
int sector = ((cacheFileBuffer[3] & 0xff) << 16) - (-(0xff00 & cacheFileBuffer[4] << 8) - (cacheFileBuffer[5] & 0xff));
if (containerSize < 0 || containerSize > maxContainerSize) {
return null;
}
if (sector <= 0 || dataFile.length() / 520L < sector) {
return null;
}
byte data[] = new byte[containerSize];
int dataReadCount = 0;
int part = 0;
while (containerSize > dataReadCount) {
if (sector == 0) {
return null;
}
dataFile.seek(520 * sector);
int dataToReadCount = containerSize - dataReadCount;
if (dataToReadCount > 512) {
dataToReadCount = 512;
}
dataFile.read(cacheFileBuffer, 0, 8 + dataToReadCount);
int currentContainerId = (0xff & cacheFileBuffer[1]) + (0xff00 & cacheFileBuffer[0] << 8);
int currentPart = ((cacheFileBuffer[2] & 0xff) << 8) + (0xff & cacheFileBuffer[3]);
int nextSector = (cacheFileBuffer[6] & 0xff) + (0xff00 & cacheFileBuffer[5] << 8) + ((0xff & cacheFileBuffer[4]) << 16);
int currentIndexFileId = cacheFileBuffer[7] & 0xff;
if (containerId != currentContainerId || currentPart != part || indexFileId != currentIndexFileId) {
return null;
}
if (nextSector < 0 || (dataFile.length() / 520L) < nextSector) {
return null;
}
for (int index = 0; dataToReadCount > index; index++) {
data[dataReadCount++] = cacheFileBuffer[8 + index];
}
part++;
sector = nextSector;
}
return data;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
/**
* Get the index file id.
* @return
*/
public int getIndexFileId() {
return indexFileId;
}
/**
* Get the unpacked container data.
* @param containerId The container id.
* @return The unpacked container data.
*/
public final byte[] getContainerUnpackedData(int containerId) {
return getContainerUnpackedData(containerId, null);
}
}

View file

@ -1,293 +0,0 @@
package core.cache;
import java.nio.ByteBuffer;
import core.cache.misc.ContainersInformation;
import core.tools.StringUtils;
/**
* A cache file manager.
* @author Dragonkk
*/
public final class CacheFileManager {
/**
* The cache file.
*/
private CacheFile cacheFile;
/**
* The containers information.
*/
private ContainersInformation information;
/**
* Discard a files data.
*/
private boolean discardFilesData;
/**
* A array holding file data.
*/
private byte[][][] filesData;
/**
* Construct a new cache file manager.
* @param cacheFile The cache file.
* @param discardFilesData To discard a files data.
*/
public CacheFileManager(CacheFile cacheFile, boolean discardFilesData) {
this.cacheFile = cacheFile;
this.discardFilesData = discardFilesData;
byte[] informContainerPackedData = Cache.getReferenceFile().getContainerData(cacheFile.getIndexFileId());
if (informContainerPackedData == null) {
return;
}
information = new ContainersInformation(informContainerPackedData);
resetFilesData();
}
/**
* Get the cache file.
* @return The cache file.
*/
public CacheFile getCacheFile() {
return cacheFile;
}
/**
* Get the containers size.
* @return The containers size.
*/
public int getContainersSize() {
return information.getContainers().length;
}
/**
* Get the files size.
* @param containerId The container id.
* @return The files size.
*/
public int getFilesSize(int containerId) {
if (!validContainer(containerId)) {
return -1;
}
return information.getContainers()[containerId].getFiles().length;
}
/**
* Reset the file data.
*/
public void resetFilesData() {
filesData = new byte[information.getContainers().length][][];
}
/**
* Check if a file is valid.
* @param containerId The container id.
* @param fileId The file id.
* @return If the file is valid {@code true}.
*/
public boolean validFile(int containerId, int fileId) {
if (!validContainer(containerId)) {
return false;
}
if (fileId < 0 || information.getContainers()[containerId] == null || information.getContainers()[containerId].getFiles().length <= fileId) {
return false;
}
return true;
}
/**
* If a container is valid.
* @param containerId The container id.
* @return If the container is valid {@code true}.
*/
public boolean validContainer(int containerId) {
if (containerId < 0 || information.getContainers().length <= containerId) {
return false;
}
return true;
}
/**
* Get the file ids.
* @param containerId The container id.
* @return The file ids.
*/
public int[] getFileIds(int containerId) {
if (!validContainer(containerId)) {
return null;
}
return information.getContainers()[containerId].getFilesIndexes();
}
/**
* Get the archive id.
* @param name The archive name.
* @return The archive id.
*/
public int getArchiveId(String name) {
if (name == null) {
return -1;
}
int hash = StringUtils.getNameHash(name);
for (int containerIndex = 0; containerIndex < information.getContainersIndexes().length; containerIndex++) {
if (information.getContainers()[information.getContainersIndexes()[containerIndex]].getNameHash() == hash) {
return information.getContainersIndexes()[containerIndex];
}
}
return -1;
}
/**
* Get the file data.
* @param containerId The container id.
* @param fileId The file id.
* @return The get file data.
*/
public byte[] getFileData(int containerId, int fileId) {
return getFileData(containerId, fileId, null);
}
/**
* Load the file data.
* @param archiveId The container id.
* @param keys The container keys.
* @return If the file data is loaded {@code true}.
*/
public boolean loadFilesData(int archiveId, int[] keys) {
byte[] data = cacheFile.getContainerUnpackedData(archiveId, keys);
if (data == null) {
return false;
}
if (filesData[archiveId] == null) {
if (information.getContainers()[archiveId] == null) {
return false; // container inform doesnt exist anymore
}
filesData[archiveId] = new byte[information.getContainers()[archiveId].getFiles().length][];
}
if (information.getContainers()[archiveId].getFilesIndexes().length == 1) {
int fileId = information.getContainers()[archiveId].getFilesIndexes()[0];
filesData[archiveId][fileId] = data;
} else {
int readPosition = data.length;
int amtOfLoops = data[--readPosition] & 0xff;
readPosition -= amtOfLoops * (information.getContainers()[archiveId].getFilesIndexes().length * 4);
ByteBuffer buffer = ByteBuffer.wrap(data);
int filesSize[] = new int[information.getContainers()[archiveId].getFilesIndexes().length];
buffer.position(readPosition);
for (int loop = 0; loop < amtOfLoops; loop++) {
int offset = 0;
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
filesSize[fileIndex] += offset += buffer.getInt();
}
}
byte[][] filesBufferData = new byte[information.getContainers()[archiveId].getFilesIndexes().length][];
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
filesBufferData[fileIndex] = new byte[filesSize[fileIndex]];
filesSize[fileIndex] = 0;
}
buffer.position(readPosition);
int sourceOffset = 0;
for (int loop = 0; loop < amtOfLoops; loop++) {
int dataRead = 0;
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
dataRead += buffer.getInt();
System.arraycopy(data, sourceOffset, filesBufferData[fileIndex], filesSize[fileIndex], dataRead);
sourceOffset += dataRead;
filesSize[fileIndex] += dataRead;
}
}
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
filesData[archiveId][information.getContainers()[archiveId].getFilesIndexes()[fileIndex]] = filesBufferData[fileIndex];
}
}
return true;
}
/**
* Get the file data.
* @param containerId The container id.
* @param fileId The file id.
* @param xteaKeys The container keys.
* @return The file data.
*/
public byte[] getFileData(int containerId, int fileId, int[] xteaKeys) {
if (!validFile(containerId, fileId)) {
return null;
}
if (filesData[containerId] == null || filesData[containerId][fileId] == null) {
if (!loadFilesData(containerId, xteaKeys)) {
return null;
}
}
byte[] data = filesData[containerId][fileId];
if (discardFilesData) {
if (filesData[containerId].length == 1) {
filesData[containerId] = null;
} else {
filesData[containerId][fileId] = null;
}
}
return data;
}
/**
* Get the containers information.
* @return The containers information.
*/
public ContainersInformation getInformation() {
return information;
}
/**
* Gets the discardFilesData.
* @return the discardFilesData.
*/
public boolean isDiscardFilesData() {
return discardFilesData;
}
/**
* Sets the discardFilesData.
* @param discardFilesData the discardFilesData to set
*/
public void setDiscardFilesData(boolean discardFilesData) {
this.discardFilesData = discardFilesData;
}
/**
* Gets the filesData.
* @return the filesData.
*/
public byte[][][] getFilesData() {
return filesData;
}
/**
* Sets the filesData.
* @param filesData the filesData to set
*/
public void setFilesData(byte[][][] filesData) {
this.filesData = filesData;
}
/**
* Sets the cacheFile.
* @param cacheFile the cacheFile to set
*/
public void setCacheFile(CacheFile cacheFile) {
this.cacheFile = cacheFile;
}
/**
* Sets the information.
* @param information the information to set
*/
public void setInformation(ContainersInformation information) {
this.information = information;
}
}

View file

@ -1,72 +0,0 @@
package core.cache;
import java.nio.ByteBuffer;
/**
* Represents a file used in the server store.
* @author Emperor
*/
public final class StoreFile {
/**
* If the data can change during server runtime.
*/
private boolean dynamic;
/**
* The file data.
*/
private byte[] data;
/**
* Constructs a new {@code StoreFile} {@code Object}.
*/
public StoreFile() {
/*
* empty.
*/
}
/**
* Puts the data on the buffer.
* @param buffer The buffer.
*/
public void put(ByteBuffer buffer) {
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
this.data = data;
}
/**
* Creates a byte buffer containing the file data.
* @return The buffer.
*/
public ByteBuffer data() {
return ByteBuffer.wrap(data);
}
/**
* Sets the data.
* @param data The data.
*/
public void setData(byte[] data) {
this.data = data;
}
/**
* Gets the dynamic.
* @return The dynamic.
*/
public boolean isDynamic() {
return dynamic;
}
/**
* Sets the dynamic.
* @param dynamic The dynamic to set.
*/
public void setDynamic(boolean dynamic) {
this.dynamic = dynamic;
}
}

View file

@ -1,56 +0,0 @@
package core.cache.bzip2;
public class BZip2BlockEntry {
boolean aBooleanArray2205[];
boolean aBooleanArray2213[];
byte aByte2201;
byte aByteArray2204[];
byte aByteArray2211[];
byte aByteArray2212[];
byte aByteArray2214[];
byte aByteArray2219[];
byte aByteArray2224[];
byte aByteArrayArray2229[][];
int anInt2202;
int anInt2203;
int anInt2206;
int anInt2207;
int anInt2208;
int anInt2209;
int anInt2215;
int anInt2216;
int anInt2217;
int anInt2221;
int anInt2222;
int anInt2223;
int anInt2225;
int anInt2227;
int anInt2232;
int anIntArray2200[];
int anIntArray2220[];
int anIntArray2226[];
int anIntArray2228[];
int anIntArrayArray2210[][];
int anIntArrayArray2218[][];
int anIntArrayArray2230[][];
public BZip2BlockEntry() {
anIntArray2200 = new int[6];
anInt2203 = 0;
aByteArray2204 = new byte[4096];
aByteArray2211 = new byte[256];
aByteArray2214 = new byte[18002];
aByteArray2219 = new byte[18002];
anIntArray2220 = new int[257];
anIntArrayArray2218 = new int[6][258];
aBooleanArray2205 = new boolean[16];
aBooleanArray2213 = new boolean[256];
anInt2209 = 0;
anIntArray2226 = new int[16];
anIntArrayArray2210 = new int[6][258];
aByteArrayArray2229 = new byte[6][258];
anIntArrayArray2230 = new int[6][258];
anIntArray2228 = new int[256];
}
}

View file

@ -1,532 +0,0 @@
package core.cache.bzip2;
public class BZip2Decompressor {
private static int anIntArray257[];
private static BZip2BlockEntry entryInstance = new BZip2BlockEntry();
public static final void decompress(byte decompressedData[], byte packedData[], int containerSize, int blockSize) {
synchronized (entryInstance) {
entryInstance.aByteArray2224 = packedData;
entryInstance.anInt2209 = blockSize;
entryInstance.aByteArray2212 = decompressedData;
entryInstance.anInt2203 = 0;
entryInstance.anInt2206 = decompressedData.length;
entryInstance.anInt2232 = 0;
entryInstance.anInt2207 = 0;
entryInstance.anInt2217 = 0;
entryInstance.anInt2216 = 0;
method1793(entryInstance);
entryInstance.aByteArray2224 = null;
entryInstance.aByteArray2212 = null;
}
}
private static final void method1785(BZip2BlockEntry entry) {
entry.anInt2215 = 0;
for (int i = 0; i < 256; i++) {
if (entry.aBooleanArray2213[i]) {
entry.aByteArray2211[entry.anInt2215] = (byte) i;
entry.anInt2215++;
}
}
}
private static final void method1786(int ai[], int ai1[], int ai2[], byte abyte0[], int i, int j, int k) {
int l = 0;
for (int i1 = i; i1 <= j; i1++) {
for (int l2 = 0; l2 < k; l2++) {
if (abyte0[l2] == i1) {
ai2[l] = l2;
l++;
}
}
}
for (int j1 = 0; j1 < 23; j1++) {
ai1[j1] = 0;
}
for (int k1 = 0; k1 < k; k1++) {
ai1[abyte0[k1] + 1]++;
}
for (int l1 = 1; l1 < 23; l1++) {
ai1[l1] += ai1[l1 - 1];
}
for (int i2 = 0; i2 < 23; i2++) {
ai[i2] = 0;
}
int i3 = 0;
for (int j2 = i; j2 <= j; j2++) {
i3 += ai1[j2 + 1] - ai1[j2];
ai[j2] = i3 - 1;
i3 <<= 1;
}
for (int k2 = i + 1; k2 <= j; k2++) {
ai1[k2] = (ai[k2 - 1] + 1 << 1) - ai1[k2];
}
}
private static final void method1787(BZip2BlockEntry entry) {
byte byte4 = entry.aByte2201;
int i = entry.anInt2222;
int j = entry.anInt2227;
int k = entry.anInt2221;
int ai[] = anIntArray257;
int l = entry.anInt2208;
byte abyte0[] = entry.aByteArray2212;
int i1 = entry.anInt2203;
int j1 = entry.anInt2206;
int k1 = j1;
int l1 = entry.anInt2225 + 1;
label0: do {
if (i > 0) {
do {
if (j1 == 0) {
break label0;
}
if (i == 1) {
break;
}
abyte0[i1] = byte4;
i--;
i1++;
j1--;
} while (true);
abyte0[i1] = byte4;
i1++;
j1--;
}
boolean flag = true;
while (flag) {
flag = false;
if (j == l1) {
i = 0;
break label0;
}
byte4 = (byte) k;
l = ai[l];
byte byte0 = (byte) (l & 0xff);
l >>= 8;
j++;
if (byte0 != k) {
k = byte0;
if (j1 == 0) {
i = 1;
} else {
abyte0[i1] = byte4;
i1++;
j1--;
flag = true;
continue;
}
break label0;
}
if (j != l1) {
continue;
}
if (j1 == 0) {
i = 1;
break label0;
}
abyte0[i1] = byte4;
i1++;
j1--;
flag = true;
}
i = 2;
l = ai[l];
byte byte1 = (byte) (l & 0xff);
l >>= 8;
if (++j != l1) {
if (byte1 != k) {
k = byte1;
} else {
i = 3;
l = ai[l];
byte byte2 = (byte) (l & 0xff);
l >>= 8;
if (++j != l1) {
if (byte2 != k) {
k = byte2;
} else {
l = ai[l];
byte byte3 = (byte) (l & 0xff);
l >>= 8;
j++;
i = (byte3 & 0xff) + 4;
l = ai[l];
k = (byte) (l & 0xff);
l >>= 8;
j++;
}
}
}
}
} while (true);
entry.anInt2216 += k1 - j1;
entry.aByte2201 = byte4;
entry.anInt2222 = i;
entry.anInt2227 = j;
entry.anInt2221 = k;
anIntArray257 = ai;
entry.anInt2208 = l;
entry.aByteArray2212 = abyte0;
entry.anInt2203 = i1;
entry.anInt2206 = j1;
}
private static final byte method1788(BZip2BlockEntry entry) {
return (byte) method1790(1, entry);
}
private static final byte method1789(BZip2BlockEntry entryInstance2) {
return (byte) method1790(8, entryInstance2);
}
private static final int method1790(int i, BZip2BlockEntry entry) {
int j;
do {
if (entry.anInt2232 >= i) {
int k = entry.anInt2207 >> entry.anInt2232 - i & (1 << i) - 1;
entry.anInt2232 -= i;
j = k;
break;
}
entry.anInt2207 = entry.anInt2207 << 8 | entry.aByteArray2224[entry.anInt2209] & 0xff;
entry.anInt2232 += 8;
entry.anInt2209++;
entry.anInt2217++;
} while (true);
return j;
}
public static void clearBlockEntryInstance() {
entryInstance = null;
}
private static final void method1793(BZip2BlockEntry entryInstance2) {
// unused
/*
* boolean flag = false; boolean flag1 = false; boolean flag2 = false;
* boolean flag3 = false; boolean flag4 = false; boolean flag5 = false;
* boolean flag6 = false; boolean flag7 = false; boolean flag8 = false;
* boolean flag9 = false; boolean flag10 = false; boolean flag11 =
* false; boolean flag12 = false; boolean flag13 = false; boolean flag14
* = false; boolean flag15 = false; boolean flag16 = false; boolean
* flag17 = false;
*/
int j8 = 0;
int ai[] = null;
int ai1[] = null;
int ai2[] = null;
entryInstance2.anInt2202 = 1;
if (anIntArray257 == null) {
anIntArray257 = new int[entryInstance2.anInt2202 * 0x186a0];
}
boolean flag18 = true;
while (flag18) {
byte byte0 = method1789(entryInstance2);
if (byte0 == 23) {
return;
}
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1788(entryInstance2);
entryInstance2.anInt2223 = 0;
byte0 = method1789(entryInstance2);
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
byte0 = method1789(entryInstance2);
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
byte0 = method1789(entryInstance2);
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
for (int j = 0; j < 16; j++) {
byte byte1 = method1788(entryInstance2);
if (byte1 == 1) {
entryInstance2.aBooleanArray2205[j] = true;
} else {
entryInstance2.aBooleanArray2205[j] = false;
}
}
for (int k = 0; k < 256; k++) {
entryInstance2.aBooleanArray2213[k] = false;
}
for (int l = 0; l < 16; l++) {
if (entryInstance2.aBooleanArray2205[l]) {
for (int i3 = 0; i3 < 16; i3++) {
byte byte2 = method1788(entryInstance2);
if (byte2 == 1) {
entryInstance2.aBooleanArray2213[l * 16 + i3] = true;
}
}
}
}
method1785(entryInstance2);
int i4 = entryInstance2.anInt2215 + 2;
int j4 = method1790(3, entryInstance2);
int k4 = method1790(15, entryInstance2);
for (int i1 = 0; i1 < k4; i1++) {
int j3 = 0;
do {
byte byte3 = method1788(entryInstance2);
if (byte3 == 0) {
break;
}
j3++;
} while (true);
entryInstance2.aByteArray2214[i1] = (byte) j3;
}
byte abyte0[] = new byte[6];
for (byte byte16 = 0; byte16 < j4; byte16++) {
abyte0[byte16] = byte16;
}
for (int j1 = 0; j1 < k4; j1++) {
byte byte17 = entryInstance2.aByteArray2214[j1];
byte byte15 = abyte0[byte17];
for (; byte17 > 0; byte17--) {
abyte0[byte17] = abyte0[byte17 - 1];
}
abyte0[0] = byte15;
entryInstance2.aByteArray2219[j1] = byte15;
}
for (int k3 = 0; k3 < j4; k3++) {
int k6 = method1790(5, entryInstance2);
for (int k1 = 0; k1 < i4; k1++) {
do {
byte byte4 = method1788(entryInstance2);
if (byte4 == 0) {
break;
}
byte4 = method1788(entryInstance2);
if (byte4 == 0) {
k6++;
} else {
k6--;
}
} while (true);
entryInstance2.aByteArrayArray2229[k3][k1] = (byte) k6;
}
}
for (int l3 = 0; l3 < j4; l3++) {
byte byte8 = 32;
int i = 0;
for (int l1 = 0; l1 < i4; l1++) {
if (entryInstance2.aByteArrayArray2229[l3][l1] > i) {
i = entryInstance2.aByteArrayArray2229[l3][l1];
}
if (entryInstance2.aByteArrayArray2229[l3][l1] < byte8) {
byte8 = entryInstance2.aByteArrayArray2229[l3][l1];
}
}
method1786(entryInstance2.anIntArrayArray2230[l3], entryInstance2.anIntArrayArray2218[l3], entryInstance2.anIntArrayArray2210[l3], entryInstance2.aByteArrayArray2229[l3], byte8, i, i4);
entryInstance2.anIntArray2200[l3] = byte8;
}
int l4 = entryInstance2.anInt2215 + 1;
int i5 = -1;
int j5 = 0;
for (int i2 = 0; i2 <= 255; i2++) {
entryInstance2.anIntArray2228[i2] = 0;
}
int i9 = 4095;
for (int k8 = 15; k8 >= 0; k8--) {
for (int l8 = 15; l8 >= 0; l8--) {
entryInstance2.aByteArray2204[i9] = (byte) (k8 * 16 + l8);
i9--;
}
entryInstance2.anIntArray2226[k8] = i9 + 1;
}
int l5 = 0;
if (j5 == 0) {
i5++;
j5 = 50;
byte byte12 = entryInstance2.aByteArray2219[i5];
j8 = entryInstance2.anIntArray2200[byte12];
ai = entryInstance2.anIntArrayArray2230[byte12];
ai2 = entryInstance2.anIntArrayArray2210[byte12];
ai1 = entryInstance2.anIntArrayArray2218[byte12];
}
j5--;
int l6 = j8;
int k7;
byte byte9;
for (k7 = method1790(l6, entryInstance2); k7 > ai[l6]; k7 = k7 << 1 | byte9) {
l6++;
byte9 = method1788(entryInstance2);
}
for (int k5 = ai2[k7 - ai1[l6]]; k5 != l4;) {
if (k5 == 0 || k5 == 1) {
int i6 = -1;
int j6 = 1;
do {
if (k5 == 0) {
i6 += j6;
} else if (k5 == 1) {
i6 += 2 * j6;
}
j6 *= 2;
if (j5 == 0) {
i5++;
j5 = 50;
byte byte13 = entryInstance2.aByteArray2219[i5];
j8 = entryInstance2.anIntArray2200[byte13];
ai = entryInstance2.anIntArrayArray2230[byte13];
ai2 = entryInstance2.anIntArrayArray2210[byte13];
ai1 = entryInstance2.anIntArrayArray2218[byte13];
}
j5--;
int i7 = j8;
int l7;
byte byte10;
for (l7 = method1790(i7, entryInstance2); l7 > ai[i7]; l7 = l7 << 1 | byte10) {
i7++;
byte10 = method1788(entryInstance2);
}
k5 = ai2[l7 - ai1[i7]];
} while (k5 == 0 || k5 == 1);
i6++;
byte byte5 = entryInstance2.aByteArray2211[entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[0]] & 0xff];
entryInstance2.anIntArray2228[byte5 & 0xff] += i6;
for (; i6 > 0; i6--) {
anIntArray257[l5] = byte5 & 0xff;
l5++;
}
} else {
int i11 = k5 - 1;
byte byte6;
if (i11 < 16) {
int i10 = entryInstance2.anIntArray2226[0];
byte6 = entryInstance2.aByteArray2204[i10 + i11];
for (; i11 > 3; i11 -= 4) {
int j11 = i10 + i11;
entryInstance2.aByteArray2204[j11] = entryInstance2.aByteArray2204[j11 - 1];
entryInstance2.aByteArray2204[j11 - 1] = entryInstance2.aByteArray2204[j11 - 2];
entryInstance2.aByteArray2204[j11 - 2] = entryInstance2.aByteArray2204[j11 - 3];
entryInstance2.aByteArray2204[j11 - 3] = entryInstance2.aByteArray2204[j11 - 4];
}
for (; i11 > 0; i11--) {
entryInstance2.aByteArray2204[i10 + i11] = entryInstance2.aByteArray2204[(i10 + i11) - 1];
}
entryInstance2.aByteArray2204[i10] = byte6;
} else {
int k10 = i11 / 16;
int l10 = i11 % 16;
int j10 = entryInstance2.anIntArray2226[k10] + l10;
byte6 = entryInstance2.aByteArray2204[j10];
for (; j10 > entryInstance2.anIntArray2226[k10]; j10--) {
entryInstance2.aByteArray2204[j10] = entryInstance2.aByteArray2204[j10 - 1];
}
entryInstance2.anIntArray2226[k10]++;
for (; k10 > 0; k10--) {
entryInstance2.anIntArray2226[k10]--;
entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[k10]] = entryInstance2.aByteArray2204[(entryInstance2.anIntArray2226[k10 - 1] + 16) - 1];
}
entryInstance2.anIntArray2226[0]--;
entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[0]] = byte6;
if (entryInstance2.anIntArray2226[0] == 0) {
int l9 = 4095;
for (int j9 = 15; j9 >= 0; j9--) {
for (int k9 = 15; k9 >= 0; k9--) {
entryInstance2.aByteArray2204[l9] = entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[j9] + k9];
l9--;
}
entryInstance2.anIntArray2226[j9] = l9 + 1;
}
}
}
entryInstance2.anIntArray2228[entryInstance2.aByteArray2211[byte6 & 0xff] & 0xff]++;
anIntArray257[l5] = entryInstance2.aByteArray2211[byte6 & 0xff] & 0xff;
l5++;
if (j5 == 0) {
i5++;
j5 = 50;
byte byte14 = entryInstance2.aByteArray2219[i5];
j8 = entryInstance2.anIntArray2200[byte14];
ai = entryInstance2.anIntArrayArray2230[byte14];
ai2 = entryInstance2.anIntArrayArray2210[byte14];
ai1 = entryInstance2.anIntArrayArray2218[byte14];
}
j5--;
int j7 = j8;
int i8;
byte byte11;
for (i8 = method1790(j7, entryInstance2); i8 > ai[j7]; i8 = i8 << 1 | byte11) {
j7++;
byte11 = method1788(entryInstance2);
}
k5 = ai2[i8 - ai1[j7]];
}
}
entryInstance2.anInt2222 = 0;
entryInstance2.aByte2201 = 0;
entryInstance2.anIntArray2220[0] = 0;
for (int j2 = 1; j2 <= 256; j2++) {
entryInstance2.anIntArray2220[j2] = entryInstance2.anIntArray2228[j2 - 1];
}
for (int k2 = 1; k2 <= 256; k2++) {
entryInstance2.anIntArray2220[k2] += entryInstance2.anIntArray2220[k2 - 1];
}
for (int l2 = 0; l2 < l5; l2++) {
byte byte7 = (byte) (anIntArray257[l2] & 0xff);
anIntArray257[entryInstance2.anIntArray2220[byte7 & 0xff]] |= l2 << 8;
entryInstance2.anIntArray2220[byte7 & 0xff]++;
}
entryInstance2.anInt2208 = anIntArray257[entryInstance2.anInt2223] >> 8;
entryInstance2.anInt2227 = 0;
entryInstance2.anInt2208 = anIntArray257[entryInstance2.anInt2208];
entryInstance2.anInt2221 = (byte) (entryInstance2.anInt2208 & 0xff);
entryInstance2.anInt2208 >>= 8;
entryInstance2.anInt2227++;
entryInstance2.anInt2225 = l5;
method1787(entryInstance2);
if (entryInstance2.anInt2227 == entryInstance2.anInt2225 + 1 && entryInstance2.anInt2222 == 0) {
flag18 = true;
} else {
flag18 = false;
}
}
}
}

View file

@ -4,8 +4,9 @@ import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import core.cache.Cache;
import core.cache.misc.buffer.ByteBufferUtils;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
/**
* Represents an animation's definitions.
@ -47,7 +48,7 @@ public final class AnimationDefinition {
if (defs != null) {
return defs;
}
byte[] data = Cache.getIndexes()[20].getFileData(emoteId >>> 7, emoteId & 0x7f);
byte[] data = Cache.getData(CacheIndex.SEQUENCE_CONFIGURATION, emoteId >>> 7, emoteId & 0x7f);
defs = new AnimationDefinition();
if (data != null) {
defs.readValueLoop(ByteBuffer.wrap(data));

View file

@ -1,17 +1,17 @@
package core.cache.def.impl;
import core.cache.misc.buffer.ByteBufferUtils;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import rs09.game.world.GameWorld;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import core.cache.Cache;
import core.cache.misc.buffer.ByteBufferUtils;
import rs09.game.world.GameWorld;
/**
* The CS2 mapping.
* @author Emperor
@ -104,7 +104,7 @@ public final class CS2Mapping {
return mapping;
}
mapping = new CS2Mapping(scriptId);
byte[] bs = Cache.getIndexes()[17].getFileData(scriptId >>> 8, scriptId & 0xFF);
byte[] bs = Cache.getData(CacheIndex.CLIENT_SCRIPTS, scriptId >>> 8, scriptId & 0xFF);
if (bs != null) {
mapping.load(ByteBuffer.wrap(bs));
} else {

View file

@ -4,7 +4,9 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import rs09.ServerConstants;
import core.cache.Cache;
import rs09.cache.Cache;
import rs09.cache.CacheArchive;
import rs09.cache.CacheIndex;
/**
* The definitions for player clothing/look.
@ -59,7 +61,7 @@ public final class ClothDefinition {
*/
public static ClothDefinition forId(int clothId) {
ClothDefinition def = new ClothDefinition();
byte[] bs = Cache.getIndexes()[2].getFileData(3, clothId);
byte[] bs = Cache.getData(CacheIndex.CONFIGURATION, CacheArchive.PLAYER_KIT, clothId);
if (bs != null) {
def.load(ByteBuffer.wrap(bs));
}
@ -76,7 +78,7 @@ public final class ClothDefinition {
} catch (Throwable e) {
e.printStackTrace();
}
int length = Cache.getIndexes()[2].getFilesSize(3);
int length = Cache.getArchiveCapacity(CacheIndex.CONFIGURATION, CacheArchive.PLAYER_KIT);
System.out.println("Definition size: " + length + ".");
for (int i = 0; i < length; i++) {
ClothDefinition def = forId(i);

View file

@ -1,14 +1,12 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.cache.CacheFileManager;
import core.cache.misc.Container;
import core.cache.misc.buffer.ByteBufferUtils;
import core.tools.CP1252;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import rs09.game.system.SystemLogger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -68,7 +66,7 @@ public class DataMap {
if (def != null) {
return def;
}
byte[] data = Cache.getIndexes()[17].getFileData(id >>> 8, id & 0xFF);
byte[] data = Cache.getData(CacheIndex.ENUM_CONFIGURATION, id >>> 8, id & 0xFF);
def = parse(id, data);
definitions.put(id, def);
return def;

View file

@ -1,12 +1,13 @@
package core.cache.def.impl;
import rs09.ServerConstants;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import rs09.ServerConstants;
import core.cache.Cache;
/**
* Represents a Graphic's definition.
* @author Jagex
@ -48,7 +49,7 @@ public class GraphicDefinition {
if (def != null) {
return def;
}
byte[] data = Cache.getIndexes()[21].getFileData(gfxId >>> 8, gfxId & 0xff);
byte[] data = Cache.getData(CacheIndex.SPOTANIM_CONFIGURATION, gfxId >>> 8, gfxId & 0xFF);
def = new GraphicDefinition();
def.graphicsId = gfxId;
if (data != null) {

View file

@ -1,6 +1,5 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.cache.def.Definition;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.container.Container;
@ -15,6 +14,8 @@ import core.net.packet.PacketRepository;
import core.net.packet.out.WeightUpdate;
import core.plugin.Plugin;
import core.tools.StringUtils;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import rs09.game.system.SystemLogger;
import rs09.game.system.config.ItemConfigParser;
import org.rs09.consts.Items;
@ -286,8 +287,8 @@ public class ItemDefinition extends Definition<Item> {
* Parses the item definitions.
*/
public static void parse() {
for (int itemId = 0; itemId < Cache.getItemDefinitionsSize(); itemId++) {
byte[] data = Cache.getIndexes()[19].getFileData(itemId >>> 8, itemId & 0xFF);
for (int itemId = 0; itemId < Cache.getIndexCapacity(CacheIndex.ITEM_CONFIGURATION); itemId++) {
byte[] data = Cache.getData(CacheIndex.ITEM_CONFIGURATION, itemId >>> 8, itemId & 0xFF);
if (data == null) {
ItemDefinition.getDefinitions().put(itemId, new ItemDefinition());
continue;
@ -303,6 +304,7 @@ public class ItemDefinition extends Definition<Item> {
ItemDefinition.getDefinitions().put(itemId, def);
}
ItemDefinition.defineTemplates();
SystemLogger.logCache("Loaded " + ItemDefinition.getDefinitions().size() + " Item definitions.");
}
/**
@ -485,7 +487,7 @@ public class ItemDefinition extends Definition<Item> {
*/
public static void defineTemplates() {
int equipId = 0;
for (int i = 0; i < Cache.getItemDefinitionsSize(); i++) {
for (int i = 0; i < Cache.getIndexCapacity(CacheIndex.ITEM_CONFIGURATION); i++) {
ItemDefinition def = forId(i);
if (def.noteTemplateId != -1) {
def.transferNoteDefinition(forId(def.noteId), forId(def.noteTemplateId));

View file

@ -1,6 +1,5 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.cache.def.Definition;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.interaction.OptionHandler;
@ -10,6 +9,8 @@ import core.game.node.entity.player.Player;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.tools.StringUtils;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import rs09.game.system.config.NPCConfigParser;
import rs09.game.world.GameWorld;
@ -199,7 +200,7 @@ public final class NPCDefinition extends Definition<NPC> {
NPCDefinition def = DEFINITIONS.get(id);
if (def == null) {
def = new NPCDefinition(id);
byte[] data = Cache.getIndexes()[18].getFileData(id >>> 7, id & 0x7f);
byte[] data = Cache.getData(CacheIndex.NPC_CONFIGURATION, id >>> 7, id & 0x7f);
if (data == null) {
if (id != -1) {
// System.out.println("Failed loading NPC " + id + ".");

View file

@ -1,6 +1,8 @@
package core.cache.def.impl;
import core.cache.Cache;
import rs09.cache.Cache;
import rs09.cache.CacheArchive;
import rs09.cache.CacheIndex;
import rs09.game.system.SystemLogger;
import rs09.game.world.GameWorld;
@ -67,12 +69,12 @@ public class RenderAnimationDefinition {
if (animId == -1) {
return null;
}
byte[] data = Cache.getIndexes()[2].getFileData(32, animId);
byte[] data = Cache.getData(CacheIndex.CONFIGURATION, CacheArchive.BAS_TYPE, animId);
RenderAnimationDefinition defs = new RenderAnimationDefinition();
if (data != null) {
defs.parse(ByteBuffer.wrap(data));
} else {
SystemLogger.logErr(RenderAnimationDefinition.class, "No definitions found for render animation " + animId + ", size=" + Cache.getIndexes()[2].getFilesSize(32) + "!");
SystemLogger.logErr(RenderAnimationDefinition.class, "No definitions found for render animation " + animId + ", size=" + Cache.getArchiveCapacity(CacheIndex.CONFIGURATION, CacheArchive.BAS_TYPE) + "!");
}
return defs;
}

View file

@ -1,11 +1,12 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.cache.def.Definition;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.interaction.OptionHandler;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import rs09.game.system.SystemLogger;
import rs09.game.world.GameWorld;
@ -569,8 +570,8 @@ public class SceneryDefinition extends Definition<Scenery> {
* @throws Throwable the throwable.
*/
public static void parse() throws Throwable {
for (int objectId = 0; objectId < Cache.getObjectDefinitionsSize(); objectId++) {
byte[] data = Cache.getIndexes()[16].getFileData(getContainerId(objectId), objectId & 0xff);
for (int objectId = 0; objectId < Cache.getIndexCapacity(CacheIndex.SCENERY_CONFIGURATION); objectId++) {
byte[] data = Cache.getData(CacheIndex.SCENERY_CONFIGURATION, objectId >>> 8, objectId & 0xFF);
if (data == null) {
SceneryDefinition.getDefinitions().put(objectId, new SceneryDefinition());
//SystemLogger.logErr("Could not load object definitions for id " + objectId + " - no data!");
@ -584,6 +585,7 @@ public class SceneryDefinition extends Definition<Scenery> {
SceneryDefinition.getDefinitions().put(objectId, def);
data = null;
}
SystemLogger.logCache("Loaded " + SceneryDefinition.getDefinitions().size() + " Scenery definitions.");
}
/**

View file

@ -1,9 +1,9 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.cache.CacheFileManager;
import core.cache.misc.Container;
import core.cache.misc.buffer.ByteBufferUtils;
import rs09.cache.Cache;
import rs09.cache.CacheArchive;
import rs09.cache.CacheIndex;
import rs09.game.system.SystemLogger;
import java.nio.ByteBuffer;
@ -53,7 +53,7 @@ public class Struct {
if (def != null) {
return def;
}
byte[] data = Cache.getIndexes()[2].getFileData(26, id);
byte[] data = Cache.getData(CacheIndex.CONFIGURATION, CacheArchive.STRUCT_TYPE, id);
def = parse(id, data);
definitions.put(id, def);
@ -89,10 +89,6 @@ public class Struct {
return def;
}
public static int getCount() {
return Cache.getIndexes()[2].getFilesSize(26);
}
public int getId() {
return id;
}

View file

@ -1,7 +1,8 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.game.node.entity.player.Player;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import java.nio.ByteBuffer;
import java.util.HashMap;
@ -94,7 +95,7 @@ public final class VarbitDefinition {
}
def = new VarbitDefinition(id);
byte[] bs = Cache.getIndexes()[22].getFileData(id >>> 10, id & 0x3ff);
byte[] bs = Cache.getData(CacheIndex.VARBIT_CONFIGURATION, id >>> 10, id & 0x3ff);
if (bs != null) {
ByteBuffer buffer = ByteBuffer.wrap(bs);
int opcode = 0;

View file

@ -1,47 +0,0 @@
package core.cache.gzip;
import java.nio.ByteBuffer;
import java.util.zip.Inflater;
public class GZipDecompressor {
private static final Inflater inflaterInstance = new Inflater(true);
public static final void decompress(ByteBuffer buffer, byte[] data) {
synchronized (inflaterInstance) {
if (~buffer.get(buffer.position()) != -32 || buffer.get(buffer.position() + 1) != -117) {
data = null;
// throw new RuntimeException("Invalid GZIP header!");
}
try {
inflaterInstance.setInput(buffer.array(), buffer.position() + 10, -buffer.position() - 18 + buffer.limit());
inflaterInstance.inflate(data);
} catch (Exception e) {
// inflaterInstance.reset();
data = null;
// throw new RuntimeException("Invalid GZIP compressed data!");
}
inflaterInstance.reset();
}
}
public static final boolean decompress(byte[] compressed, byte data[], int offset, int length) {
synchronized (inflaterInstance) {
if (data[offset] != 31 || data[offset + 1] != -117)
return false;
// throw new RuntimeException("Invalid GZIP header!");
try {
inflaterInstance.setInput(data, offset + 10, -offset - 18 + length);
inflaterInstance.inflate(compressed);
} catch (Exception e) {
inflaterInstance.reset();
e.printStackTrace();
return false;
// throw new RuntimeException("Invalid GZIP compressed data!");
}
inflaterInstance.reset();
return true;
}
}
}

View file

@ -1,109 +0,0 @@
package core.cache.misc;
/**
* A container.
* @author Dragonkk
*/
public class Container {
/**
* The version.
*/
private int version;
/**
* The CRC.
*/
private int crc;
/**
* The name hash.
*/
private int nameHash;
/**
* If updated.
*/
private boolean updated;
/**
* Construct a new container.
*/
public Container() {
nameHash = -1;
version = -1;
crc = -1;
}
/**
* Set the version.
* @param version
*/
public void setVersion(int version) {
this.version = version;
}
/**
* Update the version.
*/
public void updateVersion() {
version++;
updated = true;
}
/**
* Get the version.
* @return The version.
*/
public int getVersion() {
return version;
}
/**
* Get the next version.
* @return The next version.
*/
public int getNextVersion() {
return updated ? version : version + 1;
}
/**
* Set the CRC.
* @param crc The cRC.
*/
public void setCrc(int crc) {
this.crc = crc;
}
/**
* Get the CRC.
* @return The CRC.
*/
public int getCrc() {
return crc;
}
/**
* Set the name hash.
* @param nameHash The name hash.
*/
public void setNameHash(int nameHash) {
this.nameHash = nameHash;
}
/**
* Get the name hash.
* @return The name hash.
*/
public int getNameHash() {
return nameHash;
}
/**
* If is updated.
* @return If is updated.
*/
public boolean isUpdated() {
return updated;
}
}

View file

@ -1,228 +0,0 @@
package core.cache.misc;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.CRC32;
import core.cache.bzip2.BZip2Decompressor;
import core.cache.gzip.GZipDecompressor;
/**
* A class holding the containers information.
* @author Dragonkk
*/
public final class ContainersInformation {
/**
* The information container.
*/
private Container informationContainer;
/**
* The protocol.
*/
private int protocol;
/**
* The revision.
*/
private int revision;
/**
* The container indexes.
*/
private int[] containersIndexes;
/**
* The containers.
*/
private FilesContainer[] containers;
/**
* If files have to be named.
*/
private boolean filesNamed;
/**
* If it has to be whirpool.
*/
private boolean whirpool;
/**
* The data.
*/
private final byte[] data;
/**
* Construct a new containers information.
* @param informationContainerPackedData The information container data
* packed.
*/
public ContainersInformation(byte[] informationContainerPackedData) {
this.data = Arrays.copyOf(informationContainerPackedData, informationContainerPackedData.length);
informationContainer = new Container();
informationContainer.setVersion((informationContainerPackedData[informationContainerPackedData.length - 2] << 8 & 0xff00) + (informationContainerPackedData[-1 + informationContainerPackedData.length] & 0xff));
CRC32 crc32 = new CRC32();
crc32.update(informationContainerPackedData);
informationContainer.setCrc((int) crc32.getValue());
decodeContainersInformation(unpackCacheContainer(informationContainerPackedData));
}
/**
* Unpacks a container.
* @param packedData The packed container data.
* @return The unpacked data.
*/
public static final byte[] unpackCacheContainer(byte[] packedData) {
ByteBuffer buffer = ByteBuffer.wrap(packedData);
int compression = buffer.get() & 0xFF;
int containerSize = buffer.getInt();
if (containerSize < 0 || containerSize > 5000000) {
return null;
// throw new RuntimeException();
}
if (compression == 0) {
byte unpacked[] = new byte[containerSize];
buffer.get(unpacked, 0, containerSize);
return unpacked;
}
int decompressedSize = buffer.getInt();
if (decompressedSize < 0 || decompressedSize > 20000000) {
return null;
// throw new RuntimeException();
}
byte decompressedData[] = new byte[decompressedSize];
if (compression == 1) {
BZip2Decompressor.decompress(decompressedData, packedData, containerSize, 9);
} else {
GZipDecompressor.decompress(buffer, decompressedData);
}
return decompressedData;
}
/**
* Get the container indexes.
* @return The container indexes.
*/
public int[] getContainersIndexes() {
return containersIndexes;
}
/**
* Get the containers.
* @return The containers.
*/
public FilesContainer[] getContainers() {
return containers;
}
/**
* Get the information container.
* @return The information container.
*/
public Container getInformationContainer() {
return informationContainer;
}
/**
* Get the revision.
* @return The revision.
*/
public int getRevision() {
return revision;
}
/**
* Decode the containers information.
* @param data The data.
*/
public void decodeContainersInformation(byte[] data) {
ByteBuffer buffer = ByteBuffer.wrap(data);
protocol = buffer.get() & 0xFF;
if (protocol != 5 && protocol != 6) {
throw new RuntimeException();
}
revision = protocol < 6 ? 0 : buffer.getInt();
int nameHash = buffer.get() & 0xFF;
filesNamed = (0x1 & nameHash) != 0;
whirpool = (0x2 & nameHash) != 0;
containersIndexes = new int[buffer.getShort() & 0xFFFF];
int lastIndex = -1;
for (int index = 0; index < containersIndexes.length; index++) {
containersIndexes[index] = (buffer.getShort() & 0xFFFF) + (index == 0 ? 0 : containersIndexes[index - 1]);
if (containersIndexes[index] > lastIndex) {
lastIndex = containersIndexes[index];
}
}
containers = new FilesContainer[lastIndex + 1];
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]] = new FilesContainer();
}
if (filesNamed) {
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setNameHash(buffer.getInt());
}
}
byte[][] filesHashes = null;
if (whirpool) {
filesHashes = new byte[containers.length][];
for (int index = 0; index < containersIndexes.length; index++) {
filesHashes[containersIndexes[index]] = new byte[64];
buffer.get(filesHashes[containersIndexes[index]], 0, 64);
}
}
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setCrc(buffer.getInt());
}
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setVersion(buffer.getInt());
}
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setFilesIndexes(new int[buffer.getShort() & 0xFFFF]);
}
for (int index = 0; index < containersIndexes.length; index++) {
int lastFileIndex = -1;
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFilesIndexes()[fileIndex] = (buffer.getShort() & 0xFFFF) + (fileIndex == 0 ? 0 : containers[containersIndexes[index]].getFilesIndexes()[fileIndex - 1]);
if (containers[containersIndexes[index]].getFilesIndexes()[fileIndex] > lastFileIndex) {
lastFileIndex = containers[containersIndexes[index]].getFilesIndexes()[fileIndex];
}
}
containers[containersIndexes[index]].setFiles(new Container[lastFileIndex + 1]);
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]] = new Container();
}
}
if (whirpool) {
for (int index = 0; index < containersIndexes.length; index++) {
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setVersion(filesHashes[containersIndexes[index]][containers[containersIndexes[index]].getFilesIndexes()[fileIndex]]);
}
}
}
if (filesNamed) {
for (int index = 0; index < containersIndexes.length; index++) {
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setNameHash(buffer.getInt());
}
}
}
}
/**
* If is whirpool.
* @return If is whirpool {@code true}.
*/
public boolean isWhirpool() {
return whirpool;
}
/**
* Gets the data.
* @return The data.
*/
public byte[] getData() {
return data;
}
}

View file

@ -1,57 +0,0 @@
package core.cache.misc;
/**
* A class holding the file containers.
* @author Dragonkk
*/
public final class FilesContainer extends Container {
/**
* The file indexes.
*/
private int[] filesIndexes;
/**
* The files.
*/
private Container[] files;
/**
* Construct a new files container.
*/
public FilesContainer() {
}
/**
* Set the files.
* @param containers The files.
*/
public void setFiles(Container[] containers) {
this.files = containers;
}
/**
* Get the files.
* @return The files.
*/
public Container[] getFiles() {
return files;
}
/**
* Set the file indexes.
* @param containersIndexes The file indexes.
*/
public void setFilesIndexes(int[] containersIndexes) {
this.filesIndexes = containersIndexes;
}
/**
* Get the file indexes.
* @return The file indexes.
*/
public int[] getFilesIndexes() {
return filesIndexes;
}
}

View file

@ -1,17 +1,16 @@
package core.game.world.map;
import core.cache.Cache;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.music.MusicZone;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.system.communication.CommunicationInfo;
import core.game.system.task.Pulse;
import core.game.world.map.build.DynamicRegion;
import core.game.world.map.build.LandscapeParser;
import core.game.world.map.build.MapscapeParser;
import core.game.world.map.zone.RegionZone;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import rs09.game.system.SystemLogger;
import rs09.game.system.config.XteaParser;
import rs09.game.world.GameWorld;
@ -302,28 +301,34 @@ public class Region {
int regionId = dynamic ? ((DynamicRegion) r).getRegionId() : r.getId();
int regionX = regionId >> 8 & 0xFF;
int regionY = regionId & 0xFF;
int mapscapeId = Cache.getIndexes()[5].getArchiveId("m" + regionX + "_"+ regionY);
byte[][][] mapscapeData = new byte[4][SIZE][SIZE];
for (RegionPlane plane : r.planes) {
plane.getFlags().setLandscape(new boolean[SIZE][SIZE]);
//plane.getFlags().setClippingFlags(new int[SIZE][SIZE]);
//plane.getProjectileFlags().setClippingFlags(new int[SIZE][SIZE]);
}
if (mapscapeId > -1) {
ByteBuffer mapscape = ByteBuffer.wrap(Cache.getIndexes()[5].getCacheFile().getContainerUnpackedData(mapscapeId));
byte[] mData = Cache.getData(CacheIndex.MAPS, "m" + regionX + "_"+ regionY);
if (mData != null) {
ByteBuffer mapscape = ByteBuffer.wrap(mData);
MapscapeParser.parse(r, mapscapeData, mapscape);
}
r.hasFlags = dynamic;
r.setLoaded(true);
int landscapeId = Cache.getIndexes()[5].getArchiveId("l" + regionX + "_" + regionY);
if (landscapeId > -1) {
byte[] landscape = Cache.getIndexes()[5].getFileData(landscapeId, 0, XteaParser.Companion.getRegionXTEA(regionId));
if (landscape == null || landscape.length < 4) {
int[] keys = XteaParser.Companion.getRegionXTEA(regionId);
if (keys == null) {
keys = new int[]{0,0,0,0};
}
byte[] lData = Cache.getData(CacheIndex.MAPS, "l" + regionX + "_"+ regionY, keys);
if (lData == null) {
return;
} else {
if (lData.length < 4) {
return;
}
r.hasFlags = true;
try {
LandscapeParser.parse(r, mapscapeData, ByteBuffer.wrap(landscape), build);
LandscapeParser.parse(r, mapscapeData, ByteBuffer.wrap(lData), build);
} catch (Throwable t) {
new Throwable("Failed parsing region " + regionId + "!", t).printStackTrace();
}

View file

@ -105,10 +105,10 @@ public class IoSession {
*/
private final String address;
/**
* The JS-5 queue.
*/
private final JS5Queue js5Queue;
// /**
// * The JS-5 queue.
// */
// private final JS5Queue js5Queue;
/**
* The client info.
@ -126,7 +126,7 @@ public class IoSession {
this.key = key;
this.service = service;
this.address = getRemoteAddress().replaceAll("/", "").split(":")[0];
this.js5Queue = new JS5Queue(this);
// this.js5Queue = new JS5Queue(this);
}
/**
@ -417,13 +417,13 @@ public class IoSession {
this.isaacPair = isaacPair;
}
/**
* Gets the js5Queue.
* @return the js5Queue
*/
public JS5Queue getJs5Queue() {
return js5Queue;
}
// /**
// * Gets the js5Queue.
// * @return the js5Queue
// */
// public JS5Queue getJs5Queue() {
// return js5Queue;
// }
/**
* Gets the clientInfo value.

View file

@ -1,97 +0,0 @@
package core.net;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Handles the JS5 queue for a session.
* @author Techdaan
*/
public final class JS5Queue {
public static AtomicBoolean RUNNING = new AtomicBoolean(true);
private static final Js5QueueHandler handler = new Js5QueueHandler();
private static class Js5QueueHandler extends Thread {
private final LinkedBlockingDeque<Js5Request> requests = new LinkedBlockingDeque<>();
@Override
public void run() {
while (RUNNING.get()) {
try {
Js5Request request = requests.take();
JS5Queue queue = request.queue;
if (queue.session.isActive()) {
queue.session.write(new int[]{request.index, request.archive, request.priority ? 1 : 0});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
static {
try {
handler.start();
} catch (Exception e) {
e.printStackTrace();
}
}
private static class Js5Request {
private final JS5Queue queue;
private final int index;
private final int archive;
private final boolean priority;
public Js5Request(JS5Queue queue, int index, int archive, boolean priority) {
this.queue = queue;
this.index = index;
this.archive = archive;
this.priority = priority;
}
}
/**
* The I/O session.
*/
private final IoSession session;
/**
* Constructs a new {@code JS5Queue} {@code Object}.
* @param session The I/O session.
*/
public JS5Queue(IoSession session) {
this.session = session;
}
/**
* Queues a JS-5 request.
* Timers:
* 1000ms queue up files for this long
* 100ms release a file from the queue
*
* @param container The container.
* @param archive The archive.
* @param highPriority If the request is high priority.
*
*/
public void queue(int container, int archive, boolean highPriority) {
Js5Request request = new Js5Request(this, container, archive, highPriority);
handler.requests.add(request);
}
/**
* Gets the session.
* @return the session
*/
public IoSession getSession() {
return session;
}
}

View file

@ -1,81 +0,0 @@
package core.net.event;
import core.cache.misc.buffer.ByteBufferUtils;
import core.net.IoReadEvent;
import core.net.IoSession;
import java.nio.ByteBuffer;
/**
* Handles JS-5 reading events.
* @author Emperor
*/
public final class JS5ReadEvent extends IoReadEvent {
/**
* Constructs a new {@code JS5ReadEvent}.
* @param session The session.
* @param buffer The buffer.
*/
public JS5ReadEvent(IoSession session, ByteBuffer buffer) {
super(session, buffer);
}
@Override
public void read(IoSession session, ByteBuffer buffer) {
while (buffer.hasRemaining()) {
int opcode = buffer.get() & 0xFF;
//System.out.println("JS5 initiated! Opcode: " + opcode);
if (buffer.remaining() < 3) {
queueBuffer(opcode);
return;
}
switch (opcode) {
case 0:
case 1:
int request = ByteBufferUtils.getMedium(buffer);
//System.out.println("Requested file " + request);
int container = request >> 16 & 0xFF;
//System.out.println("In container " + container);
int archive = request & 0xFFFF;
//System.out.println("In archive " + archive);
session.getJs5Queue().queue(container, archive, opcode == 1);
break;
case 2: // music
case 3: // Music
buffer.get();
buffer.getShort();
break;
case 4:
session.setJs5Encryption(buffer.get());
if (buffer.getShort() != 0) {
session.disconnect();
return;
}
break;
case 5:
case 9:
if (buffer.remaining() < 4) {
queueBuffer(opcode);
return;
}
buffer.getInt();
break;
case 6:
ByteBufferUtils.getMedium(buffer); // Value should be 3
// buffer.getShort(); // Value should be 0
break;
case 7:
buffer.get();
buffer.getShort();
session.disconnect();
return;
default:
System.out.println("Unhandled JS5 opcode " + opcode + "!");
buffer.get();
buffer.getShort();
break;
}
}
}
}

View file

@ -1,71 +0,0 @@
package core.net.event;
import core.cache.Cache;
import core.net.IoSession;
import core.net.IoWriteEvent;
import java.nio.ByteBuffer;
/**
* Handles JS-5 writing events.
* @author Emperor
*/
public final class JS5WriteEvent extends IoWriteEvent {
/**
* The cached reference data.
*/
private static byte[] cachedReference;
/**
* Constructs a new {@code JS5WriteEvent}.
* @param session The session.
* @param context The event context.
*/
public JS5WriteEvent(IoSession session, Object context) {
super(session, context);
}
@Override
public void write(IoSession session, Object context) {
int[] request = (int[]) context;
int container = request[0];
int archive = request[1];
boolean priority = request[2] == 1;
if (archive == 255 && container == 255) {
session.queue(getReferenceData());
return;
}
ByteBuffer response = Cache.getArchiveData(container, archive, priority, session.getJs5Encryption());
if (response != null) {
session.queue(response);
}
}
/**
* Gets the reference data.
* @return The reference data.
*/
private static ByteBuffer getReferenceData() {
if (cachedReference == null) {
cachedReference = Cache.generateReferenceData();
}
ByteBuffer buffer = ByteBuffer.allocate(cachedReference.length << 2);
buffer.put((byte) 255);
buffer.putShort((short) 255);
buffer.put((byte) 0);
buffer.putInt(cachedReference.length);
int offset = 10;
for (int index = 0; index < cachedReference.length; index++) {
if (offset == 512) {
buffer.put((byte) 255);
offset = 1;
}
buffer.put(cachedReference[index]);
offset++;
}
buffer.flip();
return buffer;
}
}

View file

@ -1,6 +1,5 @@
package core.net.packet.in;
import core.cache.Cache;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.NPCDefinition;
import core.cache.def.impl.SceneryDefinition;
@ -8,7 +7,8 @@ import core.cache.def.impl.VarbitDefinition;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import org.rs09.consts.Items;
import rs09.cache.Cache;
import rs09.cache.CacheIndex;
import java.util.Arrays;
@ -24,7 +24,7 @@ public final class ExaminePacket implements IncomingPacket {
switch (buffer.opcode()) {
case 94: // Object examine
int id = buffer.getLEShortA();
if (id < 0 || id > Cache.getObjectDefinitionsSize()) {
if (id < 0 || id > Cache.getIndexCapacity(CacheIndex.SCENERY_CONFIGURATION)) {
break;
}
SceneryDefinition d = SceneryDefinition.forId(id);
@ -40,7 +40,7 @@ public final class ExaminePacket implements IncomingPacket {
case 235:
case 92: // Item examine
id = buffer.getLEShortA();
if (id < 0 || id > Cache.getItemDefinitionsSize()) {
if (id < 0 || id > Cache.getIndexCapacity(CacheIndex.ITEM_CONFIGURATION)) {
break;
}
ItemDefinition itemDef = ItemDefinition.forId(id);
@ -48,7 +48,7 @@ public final class ExaminePacket implements IncomingPacket {
break;
case 72: // NPC examine
id = buffer.getShort();
if (id < 0 || id > Cache.getNPCDefinitionsSize()) {
if (id < 0 || id > Cache.getIndexCapacity(CacheIndex.NPC_CONFIGURATION)) {
break;
}
player.debug("NPC id: " + id + ".");

View file

@ -4,8 +4,8 @@ import core.net.EventProducer;
import core.net.IoReadEvent;
import core.net.IoSession;
import core.net.IoWriteEvent;
import core.net.event.JS5ReadEvent;
import core.net.event.JS5WriteEvent;
import rs09.net.event.js5.JS5ReadEvent;
import rs09.net.event.js5.JS5WriteEvent;
import java.nio.ByteBuffer;

View file

@ -0,0 +1,81 @@
package rs09.cache
import com.displee.cache.CacheLibrary
import com.displee.cache.ProgressListener
import com.displee.cache.index.Index
import core.cache.def.impl.ItemDefinition
import core.cache.def.impl.SceneryDefinition
import rs09.game.system.SystemLogger
import rs09.net.event.js5.DataProvider
import java.nio.ByteBuffer
object Cache {
private lateinit var cacheLibrary: CacheLibrary
private lateinit var progressListener: ProgressListener
lateinit var versionTable: ByteArray
lateinit var provider: DataProvider
@JvmStatic
fun init(cachePath: String?) {
progressListener = SystemLogger.CreateProgressListener()
cacheLibrary = CacheLibrary(cachePath.toString(), false, progressListener)
versionTable = generateUKeys()
provider = DataProvider(cacheLibrary)
parseDefinitions()
}
private fun parseDefinitions() {
ItemDefinition.parse()
SceneryDefinition.parse()
}
private fun generateUKeys(): ByteArray {
val buffer = ByteBuffer.allocate(cacheLibrary.indices().size * 8)
for (index in cacheLibrary.indices()) {
buffer.putInt(index.crc)
buffer.putInt(index.revision)
}
return buffer.array()
}
fun getIndex(index: CacheIndex): Index {
return cacheLibrary.index(index.id)
}
@JvmStatic
fun getData(index: CacheIndex, archive: Int, file: Int): ByteArray? {
return cacheLibrary.data(index.id, archive, file, null)
}
@JvmStatic
fun getData(index: CacheIndex, archive: CacheArchive, file: Int): ByteArray? {
return cacheLibrary.data(index.id, archive.id, file, null)
}
@JvmStatic
fun getData(index: CacheIndex, archive: String): ByteArray? {
return cacheLibrary.data(index.id, archive, 0)
}
@JvmStatic
fun getData(index: CacheIndex, archive: String, xtea: IntArray): ByteArray? {
return cacheLibrary.data(index.id, archive, 0, xtea)
}
@JvmStatic
fun getArchiveId(index: CacheIndex, archive: String): Int {
return cacheLibrary.index(index.id).archiveId(archive)
}
@JvmStatic
fun getArchiveCapacity(index: CacheIndex, archive: CacheArchive): Int {
return cacheLibrary.index(index.id).archive(archive.id)?.files()?.size ?: -1
}
@JvmStatic
fun getIndexCapacity(index: CacheIndex): Int {
val lastArchive = (cacheLibrary.index(index.id).archives().last())
return (lastArchive.files().size) + (lastArchive.id * 256)
}
}

View file

@ -0,0 +1,11 @@
package rs09.cache
enum class CacheArchive(val id: Int) {
FLOOR_UNDERLAYS(1),
PLAYER_KIT(3),
FLOOR_OVERLAYS(4),
INVENTORIES(5),
PARAM_TYPE(11),
STRUCT_TYPE(26),
BAS_TYPE(32)
}

View file

@ -0,0 +1,31 @@
package rs09.cache
enum class CacheIndex(val id: Int) {
ANIMS(0),
BASES(1),
CONFIGURATION(2),
COMPONENTS(3),
SYNTH_SOUNDS(4),
MAPS(5),
MUSIC(6),
MODELS(7),
SPRITES(8),
TEXTURES(9),
HUFFMAN_ENCODING(10),
MIDI_JINGLES(11),
CLIENT_SCRIPTS(12),
FONTMETRICS(13),
VORBIS(14),
MIDI_INSTRUMENTS(15),
SCENERY_CONFIGURATION(16),
ENUM_CONFIGURATION(17),
NPC_CONFIGURATION(18),
ITEM_CONFIGURATION(19),
SEQUENCE_CONFIGURATION(20),
SPOTANIM_CONFIGURATION(21),
VARBIT_CONFIGURATION(22),
WORLD_MAP(23),
QUICKCHAT_MESSAGES(24),
QUICKCHAT_MENUS(25),
MATERIALS(26)
}

View file

@ -1,6 +1,5 @@
package rs09.game.interaction
import core.cache.Cache
import core.cache.def.impl.DataMap
import core.cache.def.impl.ItemDefinition
import core.cache.def.impl.NPCDefinition
@ -11,6 +10,8 @@ import core.game.system.task.Pulse
import core.game.world.update.flag.context.ChatMessage
import core.game.world.update.flag.player.ChatFlag
import proto.management.ClanMessage
import rs09.cache.Cache
import rs09.cache.CacheIndex
import rs09.game.node.entity.skill.slayer.SlayerManager
import rs09.game.world.GameWorld.Pulser
import rs09.net.packet.`in`.QCPacketType
@ -24,7 +25,7 @@ import java.util.*
* @author Ceikry
*/
object QCRepository {
private val quickChatIndex = Cache.getIndexes()[24]
private val quickChatIndex = Cache.getIndex(CacheIndex.QUICKCHAT_MESSAGES)
/**
* The entry method that connects to the other more specific methods
@ -315,6 +316,7 @@ object QCRepository {
}
private fun getQCString(index: Int): String {
return ByteBufferUtils.getString(ByteBuffer.wrap(quickChatIndex.getFileData(1, index)))
val data = Cache.getData(CacheIndex.QUICKCHAT_MESSAGES, 1, index)
return ByteBufferUtils.getString(ByteBuffer.wrap(data))
}
}

View file

@ -1,7 +1,8 @@
package rs09.game.system
import com.displee.cache.ProgressListener
import com.github.ajalt.mordant.rendering.TextColors
import com.github.ajalt.mordant.terminal.*
import com.github.ajalt.mordant.terminal.Terminal
import rs09.ServerConstants
import java.io.BufferedWriter
import java.io.File
@ -118,4 +119,28 @@ object SystemLogger {
fun logMS(s: String) {
if(s.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[ MS] $s")}")
}
@JvmStatic
fun logCache(message: String){
val msg = "${getTime()}: [CacheOps] $message"
if(message.isNotBlank()) {
t.println(msg)
}
}
@JvmStatic
fun logJS5(clazz: Class<*>, vararg messages: String){
for(m in messages){
val msg = "${getTime()}: [${clazz.simpleName}] $m"
if(m.isNotBlank()) {
t.println(msg)
}
}
}
class CreateProgressListener: ProgressListener {
override fun notify(progress: Double, message: String?) {
logCache(message.toString())
}
}
}

View file

@ -1,17 +1,17 @@
package rs09.game.system.command.oldsys
import api.*
import core.cache.Cache
import api.sendMessage
import api.submitWorldPulse
import core.game.container.access.InterfaceContainer
import core.game.content.quest.tutorials.tutorialisland.CharacterDesign
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.node.entity.combat.ImpactHandler.HitsplatType
import core.game.node.entity.impl.Projectile
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.audio.Audio
import core.game.node.item.Item
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.system.command.CommandSet
import core.game.system.task.Pulse
import core.game.world.map.Location
@ -23,6 +23,8 @@ import core.net.packet.context.VarbitContext
import core.net.packet.out.Varbit
import core.plugin.Initializable
import core.plugin.Plugin
import rs09.cache.Cache
import rs09.cache.CacheIndex
import rs09.game.system.command.CommandPlugin
import rs09.game.world.GameWorld
import java.awt.Toolkit
@ -205,8 +207,9 @@ class VisualCommand : CommandPlugin() {
return true
}
val componentId = toInteger(args[1]!!)
if (componentId < 0 || componentId > Cache.getInterfaceDefinitionsSize()) {
player!!.debug("Invalid component id [id=" + componentId + ", max=" + Cache.getInterfaceDefinitionsSize() + "].")
val componentArchiveSize = Cache.getIndexCapacity(CacheIndex.COMPONENTS)
if (componentId < 0 || componentId > componentArchiveSize) {
player!!.debug("Invalid component id [id=" + componentId + ", max=" + componentArchiveSize + "].")
return true
}
player!!.interfaceManager.openComponent(componentId)

View file

@ -1,11 +1,10 @@
package rs09.game.system.command.sets
import api.sendMessage
import core.cache.Cache
import core.cache.def.impl.DataMap
import core.cache.def.impl.NPCDefinition
import core.cache.def.impl.VarbitDefinition
import core.cache.def.impl.Struct
import core.cache.def.impl.VarbitDefinition
import core.game.node.entity.combat.ImpactHandler.HitsplatType
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.SpellBookManager
@ -17,12 +16,15 @@ import core.plugin.Initializable
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.rs09.consts.Items
import rs09.cache.Cache
import rs09.cache.CacheArchive
import rs09.cache.CacheIndex
import rs09.game.system.SystemLogger
import rs09.game.system.command.Privilege
import rs09.net.packet.PacketWriteQueue
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import rs09.net.packet.PacketWriteQueue
@Initializable
class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
@ -85,13 +87,11 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
define("dumpstructs", Privilege.ADMIN, "", "Dumps all the cache structs to structs.txt") {player, _ ->
val dump = File("structs.txt")
val writer = BufferedWriter(FileWriter(dump))
val index = Cache.getIndexes()[2]
val containers = index.information.containers[26].filesIndexes
for(fID in containers)
{
val file = index.getFileData(26, fID)
if(file != null){
val def = Struct.parse(fID, file)
val amount = Cache.getArchiveCapacity(CacheIndex.CONFIGURATION, CacheArchive.STRUCT_TYPE)
for (structId in 0 until amount) {
val data = Cache.getData(CacheIndex.CONFIGURATION, CacheArchive.STRUCT_TYPE, structId)
if (data != null) {
val def = Struct.parse(structId, data)
if(def.dataStore.isEmpty()) continue //no data in struct.
writer.write(def.toString())
writer.newLine()
@ -102,26 +102,21 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
}
define("dumpdatamaps", Privilege.ADMIN, "", "Dumps all the cache data maps to datamaps.txt") {player, _ ->
val index = Cache.getIndexes()[17]
val containers = index.information.containersIndexes
val amount = Cache.getIndexCapacity(CacheIndex.ENUM_CONFIGURATION)
val dump = File("datamaps.txt")
val writer = BufferedWriter(FileWriter(dump))
for(cID in containers)
{
val fileIndexes = index.information.containers[cID].filesIndexes
for(fID in fileIndexes)
{
val file = index.getFileData(cID, fID)
if(file != null){
val def = DataMap.parse((cID shl 8) or fID, file)
for (enumId in 0 until amount) {
val archiveId = enumId shl 8
val fileId = enumId and 0xFF
val data = Cache.getData(CacheIndex.ENUM_CONFIGURATION, archiveId, fileId)
if (data != null){
val def = DataMap.parse(enumId, data)
if(def.keyType == '?') continue //Empty definition - only a 0 present in the cachefile data.
writer.write(def.toString())
writer.newLine()
}
}
}
writer.flush()
writer.close()
}

View file

@ -1,14 +1,14 @@
package rs09.game.system.command.sets
import core.cache.Cache
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.node.entity.npc.NPC
import core.game.node.item.Item
import rs09.game.system.SystemLogger
import rs09.game.system.command.Command
import rs09.game.system.command.CommandPlugin
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.plugin.Initializable
import rs09.cache.Cache
import rs09.cache.CacheIndex
import rs09.game.system.SystemLogger
import rs09.game.system.command.CommandPlugin
import rs09.game.system.command.Privilege
import java.awt.Toolkit
import java.awt.datatransfer.StringSelection
@ -46,7 +46,7 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){
}
val id = args[1].toIntOrNull() ?: return@define
var amount = (args.getOrNull(2) ?: "1").toInt()
if (id > Cache.getItemDefinitionsSize()) {
if (id > Cache.getIndexCapacity(CacheIndex.ITEM_CONFIGURATION)) {
reject(player,"Item ID '$id' out of range.")
return@define
}

View file

@ -1,7 +1,6 @@
package rs09.game.world
import api.*
import core.cache.Cache
import core.cache.def.impl.SceneryDefinition
import core.game.node.entity.player.Player
import core.game.system.SystemManager
@ -16,6 +15,7 @@ import core.tools.RandomFunction
import rs09.ServerConstants
import rs09.ServerStore
import rs09.auth.AuthProvider
import rs09.cache.Cache
import rs09.game.system.Auth
import rs09.game.system.SystemLogger
import rs09.game.system.SystemLogger.logInfo
@ -27,7 +27,6 @@ import rs09.worker.MajorUpdateWorker
import java.text.SimpleDateFormat
import java.util.*
import java.util.function.Consumer
import kotlin.collections.ArrayList
/**
* Represents the game world.

View file

@ -0,0 +1,79 @@
package rs09.net
import java.nio.ByteBuffer
/* Extension methods for the Java ByteBuffer
* These are the same method names used in the client for buffer operations
*/
/**
* P1 - puts a byte to the buffer
* @param value as Byte
*/
fun ByteBuffer.p1(value: Byte) {
put(value)
}
/**
* P1 - puts a byte to the buffer
* @param value as Int
*/
fun ByteBuffer.p1(value: Int) {
put(value.toByte())
}
/**
* G1 - gets an unsigned byte from the buffer
* @return value as Int
*/
fun ByteBuffer.g1(): Int {
return get().toInt() and 0xFF
}
/**
* G1s - gets a signed byte from the buffer
* @return value as Int
*/
fun ByteBuffer.g1s(): Int {
return get().toInt()
}
/**
* P2 - puts a short to the buffer
* @param value as Int
*/
fun ByteBuffer.p2(value: Int) {
putShort(value.toShort())
}
/**
* G2 - gets an unsigned short from the buffer
* @return value as Int
*/
fun ByteBuffer.g2(): Int {
return short.toInt() and 0xFFFF
}
/**
* G2s - gets a signed short from the buffer
* @return value as Int
*/
fun ByteBuffer.g2s(): Int {
return short.toInt()
}
/**
* G3 - gets an unsigned medium (3 bytes) from the buffer
* @return value as Int
*/
fun ByteBuffer.g3(): Int {
return ((get().toInt() and 0xFF) shl 16) + ((get().toInt() and 0xFF) shl 8) + (get().toInt() and 0xFF)
}
/**
* P4 - puts an integer to the buffer
* @param value as Int
*/
fun ByteBuffer.p4(value: Int) {
putInt(value)
}

View file

@ -0,0 +1,18 @@
package rs09.net.event.js5
import com.displee.cache.CacheLibrary
interface DataProvider {
fun data(index: Int, archive: Int): ByteArray?
companion object {
operator fun invoke(cache: CacheLibrary) = object : DataProvider {
override fun data(index: Int, archive: Int) =
if (index == 255) {
cache.index255?.readArchiveSector(archive)?.data
} else {
cache.index(index).readArchiveSector(archive)?.data
}
}
}
}

View file

@ -0,0 +1,141 @@
package rs09.net.event.js5
import core.net.IoReadEvent
import core.net.IoSession
import rs09.game.system.SystemLogger
import rs09.net.g1
import rs09.net.g2
import rs09.net.g3
import java.nio.ByteBuffer
class JS5ReadEvent(session: IoSession?, buffer: ByteBuffer?) : IoReadEvent(session, buffer) {
override fun read(session: IoSession?, buffer: ByteBuffer?) {
if (session != null && buffer != null) {
while (buffer.hasRemaining()) {
when (val opcode = buffer.g1()) {
/**
* OPCODE 0 - Prefetch file request (Low priority request)
* Handler for the prefetch file request opcode for the JS5 connection
* The request information (subUID) is contained in a medium. To decode
* first get the unsigned byte which is the Cache index ID, then read an unsigned short
* which is the archive ID. (or just a medium 3 bytes)
*
* On initial connection:
* -Prefetch will NEVER be the first request on initial connection
*
* After high priority sends 255 CRC info + user cache is incomplete:
* -We will start receiving files that the client does not need immediately
*
* Buffer size 4: [(byte) 0, (medium) request.subUID as Int]
*/
PREFETCH_REQUEST -> {
val value = buffer.g3()
val index = value shr 16
val archive = value and 0xFFFF
session.write(Triple(index, archive, opcode == 0), true)
}
/**
* OPCODE 1 - High priority file request
* Handler for the high priority file request opcode for the JS5 connection
* The request information (subUID) is contained in a medium. To decode
* first get the unsigned byte which is the Cache Index ID, then read an unsigned short
* which is the archive ID.
*
* On initial connection:
* -Requests index 255, archive 255 which contains the master record of index CRC information
*
* After 255 CRC info sent + user has a brand new cache:
* -We will start to receive requests for files the client needs IMMEDIATELY, i.e. login interfaces/music/models
* The client stores and knows what files it needs upon moving past the main menu/login screen
*
* Buffer size 4: [(byte) 1, (medium) request.subUID as Int]
*/
PRIORITY_REQUEST -> {
val value = buffer.g3()
val index = value shr 16
val archive = value and 0xFFFF
session.write(Triple(index, archive, opcode == 0))
}
/**
* OPCODE 2 - Client logged in
* Handler for the client logged in opcode for the JS5 connection
* If the client gameState is NOT on stage 5 || 10 || 28 then it sends OP2
*
* Buffer size 4: [(byte) 2, (medium) 0]
*/
STATUS_LOGGED_IN -> {
buffer.g3()
}
/**
* OPCODE 3 - Client logged out
* Handler for the client logged out opcode for the JS5 connection
* If the client gameState is ON stage 5 || 10 || 28 then it sends OP3
*
* Buffer size 4: [(byte) 3, (medium) 0]
*/
STATUS_LOGGED_OUT -> {
buffer.g3()
}
/**
* OPCODE 4 - Encryption
* Handler for the encryption opcode for the JS5 connection
* The client sends a byte encryption key that we'll send out with the requests
*
* Buffer size 4: [(byte) 4, (byte) encryptionKey, (shortMirrored) 0]
*/
ENCRYPTED -> {
val value = buffer.g1()
val mark = buffer.g2()
if (mark != 0) {
SystemLogger.logErr(this::class.java, "[$opcode] mark [$mark] not 0!")
}
}
/**
* OPCODE 6 - Connection Initialized
* Handler for the initial connection opcode for the JS5 connection
* We connect the client then clear the buffer by skipping the remaining 3 bytes
*
* Buffer size 4: [(byte) 6, (medium) 3]
*/
ACKNOWLEDGE -> {
buffer.g3()
}
/**
* OPCODE 7 - Connection Disconnect
* Handler for the disconnection connection opcode for the JS5 connection
* This is only sent by request of a client command
*
* Buffer size 4: [(byte) 7, (medium) 3]
*/
DISCONNECT -> {
buffer.g3()
session.disconnect()
}
else -> {
SystemLogger.logErr(this::class.java, "What the fuck is happening [$opcode]")
}
}
}
}
}
companion object {
// Opcodes
const val PREFETCH_REQUEST = 0
const val PRIORITY_REQUEST = 1
const val STATUS_LOGGED_IN = 2
const val STATUS_LOGGED_OUT = 3
const val ENCRYPTED = 4
const val ACKNOWLEDGE = 6
const val DISCONNECT = 7
}
}

View file

@ -0,0 +1,89 @@
package rs09.net.event.js5
import core.net.IoSession
import core.net.IoWriteEvent
import rs09.cache.Cache.provider
import rs09.cache.Cache.versionTable
import rs09.game.system.SystemLogger
import rs09.net.p1
import rs09.net.p2
import rs09.net.p4
import java.nio.ByteBuffer
import kotlin.math.min
class JS5WriteEvent(session: IoSession?, context: Any?) : IoWriteEvent(session, context) {
override fun write(session: IoSession, context: Any) {
val request = context as Triple<*, *, *>
val index = request.first as Int
val archive = request.second as Int
val priority = request.third as Boolean
val data = data(index, archive) ?: return SystemLogger.logErr(this::class.java,"Unable to fulfill request $index $archive $priority.")
if (index == 255 && archive == 255) {
val buffer = serve255(data)
session.queue(buffer)
} else {
val buffer = serve(index, archive, data, priority)
session.queue(buffer)
}
return
}
/**
* @return data for an [index]'s [archive] file or [versionTable] when index and archive are both 255
*/
fun data(index: Int, archive: Int): ByteArray? {
if (index == 255 && archive == 255) {
return versionTable
}
return provider.data(index, archive)
}
/**
* Serve255 - Prepares a buffer to send the version table data
*
* @param data - The binary data retrieved from the cache
* @return buffer containing version table information
*/
private fun serve255(data: ByteArray): ByteBuffer {
val buffer = ByteBuffer.allocate(8 + data.size)
buffer.p1(255)
buffer.p2(255)
buffer.p1(0)
buffer.p4(data.size)
buffer.put(data)
buffer.flip()
return buffer
}
fun serve(index: Int, archive: Int, data: ByteArray, prefetch: Boolean): ByteBuffer {
val compression = data[0].toInt()
val size = getInt(data[1], data[2], data[3], data[4]) + if (compression != 0) 8 else 4 // 9 : 5?
val buffer = ByteBuffer.allocate((size + 5) + (size / 512) + 10)
buffer.p1(index)
buffer.p2(archive)
buffer.p1((if (prefetch) compression or 0x80 else compression))
var length = min(size, SPLIT - HEADER)
buffer.put(data, OFFSET, length)
var written = length
while (written < size) {
buffer.p1(SEPARATOR)
length = if (size - written < SPLIT) size - written else SPLIT - 1
buffer.put(data, written + OFFSET, length)
written += length
}
buffer.flip()
return buffer
}
companion object {
private fun getInt(b1: Byte, b2: Byte, b3: Byte, b4: Byte) = b1.toInt() shl 24 or (b2.toInt() and 0xff shl 16) or (b3.toInt() and 0xff shl 8) or (b4.toInt() and 0xff)
private const val SEPARATOR = 255
private const val HEADER = 4
private const val SPLIT = 512
private const val OFFSET = 1
}
}

View file

@ -1,14 +1,8 @@
import core.cache.Cache
import core.game.world.map.Region
import core.game.world.map.RegionChunk
import core.game.world.map.RegionManager
import core.game.world.map.build.DynamicRegion
import core.game.world.map.build.LandscapeParser
import org.junit.Assert
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import rs09.game.system.config.ServerConfigParser
import rs09.game.system.config.XteaParser
class RegionTests {
companion object {

View file

@ -1,4 +1,4 @@
import core.cache.Cache
import core.cache.crypto.ISAACCipher
import core.cache.crypto.ISAACPair
import core.game.node.entity.player.Player
@ -10,6 +10,7 @@ import core.net.IoSession
import core.net.packet.IoBuffer
import org.rs09.consts.Items
import rs09.ServerConstants
import rs09.cache.Cache
import rs09.game.content.global.shops.Shop
import rs09.game.content.global.shops.ShopItem
import rs09.game.system.SystemLogger
@ -18,7 +19,6 @@ import rs09.game.system.config.ServerConfigParser
import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository
import rs09.game.world.update.UpdateSequence
import java.io.File
import java.net.URI
import java.nio.ByteBuffer