mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-03 00:38:21 +00:00
Modularise! Also add some unit tests.
This commit is contained in:
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>apollo</groupId>
|
||||
<artifactId>org.apollo</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>cache</artifactId>
|
||||
<version>0.0.1</version>
|
||||
|
||||
<name>Apollo Cache</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main</sourceDirectory>
|
||||
<testSourceDirectory>src/test</testSourceDirectory>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>apollo</groupId>
|
||||
<artifactId>util</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.apollo.cache;
|
||||
|
||||
/**
|
||||
* A class which points to a file in the cache.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class FileDescriptor {
|
||||
|
||||
/**
|
||||
* The file id.
|
||||
*/
|
||||
private final int file;
|
||||
|
||||
/**
|
||||
* The file type.
|
||||
*/
|
||||
private final int type;
|
||||
|
||||
/**
|
||||
* Creates the file descriptor.
|
||||
*
|
||||
* @param type The file type.
|
||||
* @param file The file id.
|
||||
*/
|
||||
public FileDescriptor(int type, int file) {
|
||||
this.type = type;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file id.
|
||||
*
|
||||
* @return The file id.
|
||||
*/
|
||||
public int getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file type.
|
||||
*
|
||||
* @return The file type.
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.apollo.cache;
|
||||
|
||||
/**
|
||||
* Holds file system related constants.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class FileSystemConstants {
|
||||
|
||||
/**
|
||||
* The number of archives in cache 0.
|
||||
*/
|
||||
public static final int ARCHIVE_COUNT = 9;
|
||||
|
||||
/**
|
||||
* The size of a chunk.
|
||||
*/
|
||||
public static final int CHUNK_SIZE = 512;
|
||||
|
||||
/**
|
||||
* The size of a header.
|
||||
*/
|
||||
public static final int HEADER_SIZE = 8;
|
||||
|
||||
/**
|
||||
* The size of a block.
|
||||
*/
|
||||
public static final int BLOCK_SIZE = HEADER_SIZE + CHUNK_SIZE;
|
||||
|
||||
/**
|
||||
* The size of an index.
|
||||
*/
|
||||
public static final int INDEX_SIZE = 6;
|
||||
|
||||
/**
|
||||
* Default private constructor to prevent instantiation.
|
||||
*/
|
||||
private FileSystemConstants() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.apollo.cache;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* An {@link Index} points to a file in the {@code main_file_cache.dat} file.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class Index {
|
||||
|
||||
/**
|
||||
* Decodes a buffer into an index.
|
||||
*
|
||||
* @param buffer The buffer.
|
||||
* @return The decoded {@link Index}.
|
||||
* @throws IllegalArgumentException If the buffer length is invalid.
|
||||
*/
|
||||
public static Index decode(byte[] buffer) {
|
||||
Preconditions.checkArgument(buffer.length == FileSystemConstants.INDEX_SIZE, "Incorrect buffer length.");
|
||||
|
||||
int size = (buffer[0] & 0xFF) << 16 | (buffer[1] & 0xFF) << 8 | buffer[2] & 0xFF;
|
||||
int block = (buffer[3] & 0xFF) << 16 | (buffer[4] & 0xFF) << 8 | buffer[5] & 0xFF;
|
||||
|
||||
return new Index(size, block);
|
||||
}
|
||||
|
||||
/**
|
||||
* The first block of the file.
|
||||
*/
|
||||
private final int block;
|
||||
|
||||
/**
|
||||
* The size of the file.
|
||||
*/
|
||||
private final int size;
|
||||
|
||||
/**
|
||||
* Creates the index.
|
||||
*
|
||||
* @param size The size of the file.
|
||||
* @param block The first block of the file.
|
||||
*/
|
||||
public Index(int size, int block) {
|
||||
this.size = size;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first block of the file.
|
||||
*
|
||||
* @return The first block of the file.
|
||||
*/
|
||||
public int getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the file.
|
||||
*
|
||||
* @return The size of the file.
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
package org.apollo.cache;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* A file system based on top of the operating system's file system. It consists of a data file and index files. Index
|
||||
* files point to blocks in the data file, which contains the actual data.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class IndexedFileSystem implements Closeable {
|
||||
|
||||
/**
|
||||
* The cached CRC table.
|
||||
*/
|
||||
private ByteBuffer crcTable;
|
||||
|
||||
/**
|
||||
* The {@link #crcTable} represented as an {@code int} array.
|
||||
*/
|
||||
private int[] crcs;
|
||||
|
||||
/**
|
||||
* The data file.
|
||||
*/
|
||||
private RandomAccessFile data;
|
||||
|
||||
/**
|
||||
* The index files.
|
||||
*/
|
||||
private final RandomAccessFile[] indices = new RandomAccessFile[256];
|
||||
|
||||
/**
|
||||
* Read only flag.
|
||||
*/
|
||||
private final boolean readOnly;
|
||||
|
||||
/**
|
||||
* Creates the file system with the specified base directory.
|
||||
*
|
||||
* @param base The base directory.
|
||||
* @param readOnly Indicates whether the file system will be read only or not.
|
||||
* @throws FileNotFoundException If the data files could not be found.
|
||||
*/
|
||||
public IndexedFileSystem(Path base, boolean readOnly) throws FileNotFoundException {
|
||||
this.readOnly = readOnly;
|
||||
detectLayout(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (data != null) {
|
||||
synchronized (data) {
|
||||
data.close();
|
||||
}
|
||||
}
|
||||
|
||||
for (RandomAccessFile index : indices) {
|
||||
if (index != null) {
|
||||
synchronized (index) {
|
||||
index.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically detect the layout of the specified directory.
|
||||
*
|
||||
* @param base The base directory.
|
||||
* @throws FileNotFoundException If the data files could not be found.
|
||||
*/
|
||||
private void detectLayout(Path base) throws FileNotFoundException {
|
||||
int indexCount = 0;
|
||||
for (int index = 0; index < indices.length; index++) {
|
||||
Path idx = base.resolve("main_file_cache.idx" + index);
|
||||
if (Files.exists(idx) && !Files.isDirectory(idx)) {
|
||||
indexCount++;
|
||||
indices[index] = new RandomAccessFile(idx.toFile(), readOnly ? "r" : "rw");
|
||||
}
|
||||
}
|
||||
if (indexCount <= 0) {
|
||||
throw new FileNotFoundException("No index file(s) present.");
|
||||
}
|
||||
|
||||
Path resources = base.resolve("main_file_cache.dat");
|
||||
if (Files.exists(resources) && !Files.isDirectory(resources)) {
|
||||
data = new RandomAccessFile(resources.toFile(), readOnly ? "r" : "rw");
|
||||
} else {
|
||||
throw new FileNotFoundException("No data file present.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CRC table.
|
||||
*
|
||||
* @return The CRC table.
|
||||
* @throws IOException If there is an error accessing files to create the table.
|
||||
* @throws IllegalStateException If this file system is not read-only.
|
||||
*/
|
||||
public ByteBuffer getCrcTable() throws IOException {
|
||||
if (readOnly) {
|
||||
synchronized (this) {
|
||||
if (crcTable != null) {
|
||||
return crcTable.duplicate();
|
||||
}
|
||||
}
|
||||
|
||||
int archives = getFileCount(0);
|
||||
int hash = 1234;
|
||||
int[] crcs = new int[archives];
|
||||
|
||||
CRC32 crc32 = new CRC32();
|
||||
for (int i = 1; i < crcs.length; i++) {
|
||||
crc32.reset();
|
||||
|
||||
ByteBuffer buffer = getFile(0, i);
|
||||
byte[] bytes = new byte[buffer.remaining()];
|
||||
buffer.get(bytes, 0, bytes.length);
|
||||
crc32.update(bytes, 0, bytes.length);
|
||||
|
||||
crcs[i] = (int) crc32.getValue();
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate((crcs.length + 1) * Integer.BYTES);
|
||||
for (int crc : crcs) {
|
||||
hash = (hash << 1) + crc;
|
||||
buffer.putInt(crc);
|
||||
}
|
||||
|
||||
buffer.putInt(hash);
|
||||
buffer.flip();
|
||||
|
||||
synchronized (this) {
|
||||
crcTable = buffer.asReadOnlyBuffer();
|
||||
return crcTable.duplicate();
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Cannot get CRC table from a writable file system.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CRC table as an {@code int} array.
|
||||
*
|
||||
* @return The CRC table as an {@code int} array.
|
||||
* @throws IOException If there is an error accessing files to create the table.
|
||||
*/
|
||||
public int[] getCrcs() throws IOException {
|
||||
if (crcs != null) {
|
||||
return crcs;
|
||||
}
|
||||
|
||||
ByteBuffer buffer = getCrcTable();
|
||||
crcs = new int[(buffer.remaining() / Integer.BYTES) - 1];
|
||||
Arrays.setAll(crcs, crc -> buffer.getInt());
|
||||
return crcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a file.
|
||||
*
|
||||
* @param descriptor The {@link FileDescriptor} pointing to the file.
|
||||
* @return A {@link ByteBuffer} containing the contents of the file.
|
||||
* @throws IOException If there is an error decoding the file.
|
||||
*/
|
||||
public ByteBuffer getFile(FileDescriptor descriptor) throws IOException {
|
||||
Index index = getIndex(descriptor);
|
||||
ByteBuffer buffer = ByteBuffer.allocate(index.getSize());
|
||||
|
||||
long position = index.getBlock() * FileSystemConstants.BLOCK_SIZE;
|
||||
int read = 0;
|
||||
int size = index.getSize();
|
||||
int blocks = size / FileSystemConstants.CHUNK_SIZE;
|
||||
if (size % FileSystemConstants.CHUNK_SIZE != 0) {
|
||||
blocks++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks; i++) {
|
||||
byte[] header = new byte[FileSystemConstants.HEADER_SIZE];
|
||||
synchronized (data) {
|
||||
data.seek(position);
|
||||
data.readFully(header);
|
||||
}
|
||||
|
||||
position += FileSystemConstants.HEADER_SIZE;
|
||||
|
||||
int nextFile = (header[0] & 0xFF) << 8 | header[1] & 0xFF;
|
||||
int curChunk = (header[2] & 0xFF) << 8 | header[3] & 0xFF;
|
||||
int nextBlock = (header[4] & 0xFF) << 16 | (header[5] & 0xFF) << 8 | header[6] & 0xFF;
|
||||
int nextType = header[7] & 0xFF;
|
||||
|
||||
Preconditions.checkArgument(i == curChunk, "Chunk id mismatch.");
|
||||
|
||||
int chunkSize = size - read;
|
||||
if (chunkSize > FileSystemConstants.CHUNK_SIZE) {
|
||||
chunkSize = FileSystemConstants.CHUNK_SIZE;
|
||||
}
|
||||
|
||||
byte[] chunk = new byte[chunkSize];
|
||||
synchronized (data) {
|
||||
data.seek(position);
|
||||
data.readFully(chunk);
|
||||
}
|
||||
buffer.put(chunk);
|
||||
|
||||
read += chunkSize;
|
||||
position = (long) nextBlock * (long) FileSystemConstants.BLOCK_SIZE;
|
||||
|
||||
// if we still have more data to read, check the validity of the header
|
||||
if (size > read) {
|
||||
if (nextType != descriptor.getType() + 1) {
|
||||
throw new IOException("File type mismatch.");
|
||||
}
|
||||
|
||||
if (nextFile != descriptor.getFile()) {
|
||||
throw new IOException("File id mismatch.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a file.
|
||||
*
|
||||
* @param type The file type.
|
||||
* @param file The file id.
|
||||
* @return A {@link ByteBuffer} which contains the contents of the file.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
public ByteBuffer getFile(int type, int file) throws IOException {
|
||||
return getFile(new FileDescriptor(type, file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of files with the specified type.
|
||||
*
|
||||
* @param type The type.
|
||||
* @return The number of files.
|
||||
* @throws IOException If there is an error getting the length of the specified index file.
|
||||
* @throws IndexOutOfBoundsException If {@code type} is less than 0, or greater than or equal to the amount of
|
||||
* indices.
|
||||
*/
|
||||
private int getFileCount(int type) throws IOException {
|
||||
Preconditions.checkElementIndex(type, indices.length, "File type out of bounds.");
|
||||
|
||||
RandomAccessFile indexFile = indices[type];
|
||||
synchronized (indexFile) {
|
||||
return (int) (indexFile.length() / FileSystemConstants.INDEX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a file.
|
||||
*
|
||||
* @param descriptor The {@link FileDescriptor} which points to the file.
|
||||
* @return The {@link Index}.
|
||||
* @throws IOException If there is an error reading from the index file.
|
||||
* @throws IndexOutOfBoundsException If the descriptor type is less than 0, or greater than or equal to the amount
|
||||
* of indices.
|
||||
*/
|
||||
private Index getIndex(FileDescriptor descriptor) throws IOException {
|
||||
int index = descriptor.getType();
|
||||
Preconditions.checkElementIndex(index, indices.length, "File descriptor type out of bounds.");
|
||||
|
||||
byte[] buffer = new byte[FileSystemConstants.INDEX_SIZE];
|
||||
RandomAccessFile indexFile = indices[index];
|
||||
synchronized (indexFile) {
|
||||
long position = descriptor.getFile() * FileSystemConstants.INDEX_SIZE;
|
||||
if (position >= 0 && indexFile.length() >= position + FileSystemConstants.INDEX_SIZE) {
|
||||
indexFile.seek(position);
|
||||
indexFile.readFully(buffer);
|
||||
} else {
|
||||
throw new FileNotFoundException("Could not find find index.");
|
||||
}
|
||||
}
|
||||
|
||||
return Index.decode(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this {@link IndexedFileSystem} is read only.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package org.apollo.cache.archive;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apollo.util.BufferUtil;
|
||||
import org.apollo.util.CompressionUtil;
|
||||
|
||||
/**
|
||||
* Represents an archive.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class Archive {
|
||||
|
||||
/**
|
||||
* Decodes the archive in the specified buffer.
|
||||
*
|
||||
* @param buffer The buffer.
|
||||
* @return The archive.
|
||||
* @throws IOException If there is an error decompressing the archive.
|
||||
*/
|
||||
public static Archive decode(ByteBuffer buffer) throws IOException {
|
||||
int extractedSize = BufferUtil.readUnsignedMedium(buffer);
|
||||
int size = BufferUtil.readUnsignedMedium(buffer);
|
||||
boolean extracted = false;
|
||||
|
||||
if (size != extractedSize) {
|
||||
byte[] compressed = new byte[size];
|
||||
byte[] decompressed = new byte[extractedSize];
|
||||
buffer.get(compressed);
|
||||
CompressionUtil.debzip2(compressed, decompressed);
|
||||
buffer = ByteBuffer.wrap(decompressed);
|
||||
extracted = true;
|
||||
}
|
||||
|
||||
int entryCount = buffer.getShort() & 0xFFFF;
|
||||
int[] identifiers = new int[entryCount];
|
||||
int[] extractedSizes = new int[entryCount];
|
||||
int[] sizes = new int[entryCount];
|
||||
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
identifiers[i] = buffer.getInt();
|
||||
extractedSizes[i] = BufferUtil.readUnsignedMedium(buffer);
|
||||
sizes[i] = BufferUtil.readUnsignedMedium(buffer);
|
||||
}
|
||||
|
||||
ArchiveEntry[] entries = new ArchiveEntry[entryCount];
|
||||
for (int entry = 0; entry < entryCount; entry++) {
|
||||
ByteBuffer entryBuffer;
|
||||
if (!extracted) {
|
||||
byte[] compressed = new byte[sizes[entry]];
|
||||
byte[] decompressed = new byte[extractedSizes[entry]];
|
||||
buffer.get(compressed);
|
||||
CompressionUtil.debzip2(compressed, decompressed);
|
||||
entryBuffer = ByteBuffer.wrap(decompressed);
|
||||
} else {
|
||||
byte[] buf = new byte[extractedSizes[entry]];
|
||||
buffer.get(buf);
|
||||
entryBuffer = ByteBuffer.wrap(buf);
|
||||
}
|
||||
entries[entry] = new ArchiveEntry(identifiers[entry], entryBuffer);
|
||||
}
|
||||
return new Archive(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entries in this archive.
|
||||
*/
|
||||
private final ArchiveEntry[] entries;
|
||||
|
||||
/**
|
||||
* Creates a new archive.
|
||||
*
|
||||
* @param entries The entries in this archive.
|
||||
*/
|
||||
public Archive(ArchiveEntry[] entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link ArchiveEntry} by its name.
|
||||
*
|
||||
* @param name The name.
|
||||
* @return The entry.
|
||||
* @throws FileNotFoundException If the entry could not be found.
|
||||
*/
|
||||
public ArchiveEntry getEntry(String name) throws FileNotFoundException {
|
||||
int hash = hash(name);
|
||||
|
||||
for (ArchiveEntry entry : entries) {
|
||||
if (entry.getIdentifier() == hash) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
throw new FileNotFoundException("Could not find entry: " + name + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes the specified string into an integer used to identify an {@link ArchiveEntry}.
|
||||
*
|
||||
* @param name The name of the entry.
|
||||
* @return The hash.
|
||||
*/
|
||||
public static int hash(String name) {
|
||||
return name.toUpperCase().chars().reduce(0, (hash, character) -> hash * 61 + character - 32);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.apollo.cache.archive;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Represents a single entry in an {@link Archive}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ArchiveEntry {
|
||||
|
||||
/**
|
||||
* The buffer of this entry.
|
||||
*/
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* The identifier of this entry.
|
||||
*/
|
||||
private final int identifier;
|
||||
|
||||
/**
|
||||
* Creates a new archive entry.
|
||||
*
|
||||
* @param identifier The identifier.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public ArchiveEntry(int identifier, ByteBuffer buffer) {
|
||||
this.identifier = identifier;
|
||||
this.buffer = buffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer of this entry.
|
||||
*
|
||||
* @return This buffer of this entry.
|
||||
*/
|
||||
public ByteBuffer getBuffer() {
|
||||
return buffer.duplicate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier of this entry.
|
||||
*
|
||||
* @return The identifier of this entry.
|
||||
*/
|
||||
public int getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes which deal with archives.
|
||||
*/
|
||||
package org.apollo.cache.archive;
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.apollo.cache.decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.cache.archive.Archive;
|
||||
import org.apollo.cache.def.ItemDefinition;
|
||||
import org.apollo.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* Decodes item data from the {@code obj.dat} file into {@link ItemDefinition}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ItemDefinitionDecoder {
|
||||
|
||||
/**
|
||||
* The {@link IndexedFileSystem}.
|
||||
*/
|
||||
private final IndexedFileSystem fs;
|
||||
|
||||
/**
|
||||
* Creates the item definition decoder.
|
||||
*
|
||||
* @param fs The indexed file system.
|
||||
*/
|
||||
public ItemDefinitionDecoder(IndexedFileSystem fs) {
|
||||
this.fs = fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the item definitions.
|
||||
*
|
||||
* @return The item definitions.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
public ItemDefinition[] decode() throws IOException {
|
||||
Archive config = Archive.decode(fs.getFile(0, 2));
|
||||
ByteBuffer data = config.getEntry("obj.dat").getBuffer();
|
||||
ByteBuffer idx = config.getEntry("obj.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();
|
||||
}
|
||||
|
||||
ItemDefinition[] defs = new ItemDefinition[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
data.position(indices[i]);
|
||||
defs[i] = decode(i, data);
|
||||
}
|
||||
|
||||
return defs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a single definition.
|
||||
*
|
||||
* @param id The item's id.
|
||||
* @param buffer The buffer.
|
||||
* @return The {@link ItemDefinition}.
|
||||
*/
|
||||
private static ItemDefinition decode(int id, ByteBuffer buffer) {
|
||||
ItemDefinition definition = new ItemDefinition(id);
|
||||
while (true) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
|
||||
if (opcode == 0) {
|
||||
return definition;
|
||||
} else if (opcode == 1) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 2) {
|
||||
definition.setName(BufferUtil.readString(buffer));
|
||||
} else if (opcode == 3) {
|
||||
definition.setDescription(BufferUtil.readString(buffer));
|
||||
} else if (opcode >= 4 && opcode <= 8 || opcode == 10) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 11) {
|
||||
definition.setStackable(true);
|
||||
} else if (opcode == 12) {
|
||||
definition.setValue(buffer.getInt());
|
||||
} else if (opcode == 16) {
|
||||
definition.setMembersOnly(true);
|
||||
} else if (opcode == 23) {
|
||||
buffer.getShort();
|
||||
buffer.get();
|
||||
} else if (opcode == 24) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 25) {
|
||||
buffer.getShort();
|
||||
buffer.get();
|
||||
} else if (opcode == 26) {
|
||||
buffer.getShort();
|
||||
} else if (opcode >= 30 && opcode < 35) {
|
||||
String str = BufferUtil.readString(buffer);
|
||||
if (str.equalsIgnoreCase("hidden")) {
|
||||
str = null;
|
||||
}
|
||||
definition.setGroundAction(opcode - 30, str);
|
||||
} else if (opcode >= 35 && opcode < 40) {
|
||||
definition.setInventoryAction(opcode - 35, BufferUtil.readString(buffer));
|
||||
} else if (opcode == 40) {
|
||||
int colourCount = buffer.get() & 0xFF;
|
||||
for (int i = 0; i < colourCount; i++) {
|
||||
buffer.getShort();
|
||||
buffer.getShort();
|
||||
}
|
||||
} else if (opcode == 78 || opcode == 79 || opcode >= 90 || opcode <= 93 || opcode == 95) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 97) {
|
||||
definition.setNoteInfoId(buffer.getShort() & 0xFFFF);
|
||||
} else if (opcode == 98) {
|
||||
definition.setNoteGraphicId(buffer.getShort() & 0xFFFF);
|
||||
} else if (opcode >= 100 && opcode < 110) {
|
||||
buffer.getShort();
|
||||
buffer.getShort();
|
||||
} else if (opcode >= 110 && opcode <= 112) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 113 || opcode == 114) {
|
||||
buffer.get();
|
||||
} else if (opcode == 115) {
|
||||
definition.setTeam(buffer.get() & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package org.apollo.cache.decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.cache.archive.Archive;
|
||||
import org.apollo.cache.def.NpcDefinition;
|
||||
import org.apollo.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* Decodes npc data from the {@code npc.dat} file into {@link NpcDefinition}s.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class NpcDefinitionDecoder {
|
||||
|
||||
/**
|
||||
* The {@link IndexedFileSystem}.
|
||||
*/
|
||||
private final IndexedFileSystem fs;
|
||||
|
||||
/**
|
||||
* Creates the npc definition decoder.
|
||||
*
|
||||
* @param fs The indexed file system.
|
||||
*/
|
||||
public NpcDefinitionDecoder(IndexedFileSystem fs) {
|
||||
this.fs = fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the npc definitions.
|
||||
*
|
||||
* @return An array of all parsed npc definitions.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
public NpcDefinition[] decode() throws IOException {
|
||||
Archive config = Archive.decode(fs.getFile(0, 2));
|
||||
ByteBuffer data = config.getEntry("npc.dat").getBuffer();
|
||||
ByteBuffer idx = config.getEntry("npc.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();
|
||||
}
|
||||
|
||||
NpcDefinition[] defs = new NpcDefinition[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
data.position(indices[i]);
|
||||
defs[i] = decode(i, data);
|
||||
}
|
||||
|
||||
return defs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a single definition.
|
||||
*
|
||||
* @param id The npc's id.
|
||||
* @param buffer The buffer.
|
||||
* @return The {@link NpcDefinition}.
|
||||
*/
|
||||
private static NpcDefinition decode(int id, ByteBuffer buffer) {
|
||||
NpcDefinition definition = new NpcDefinition(id);
|
||||
|
||||
while (true) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
|
||||
if (opcode == 0) {
|
||||
return definition;
|
||||
} else if (opcode == 1) {
|
||||
int length = buffer.get() & 0xFF;
|
||||
int[] models = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
models[i] = buffer.getShort();
|
||||
}
|
||||
} else if (opcode == 2) {
|
||||
definition.setName(BufferUtil.readString(buffer));
|
||||
} else if (opcode == 3) {
|
||||
definition.setDescription(BufferUtil.readString(buffer));
|
||||
} else if (opcode == 12) {
|
||||
definition.setSize(buffer.get());
|
||||
} else if (opcode == 13) {
|
||||
definition.setStandAnimation(buffer.getShort());
|
||||
} else if (opcode == 14) {
|
||||
definition.setWalkAnimation(buffer.getShort());
|
||||
} else if (opcode == 17) {
|
||||
definition
|
||||
.setWalkAnimations(buffer.getShort(), buffer.getShort(), buffer.getShort(), buffer.getShort());
|
||||
} else if (opcode >= 30 && opcode < 40) {
|
||||
String str = BufferUtil.readString(buffer);
|
||||
if (str.equals("hidden")) {
|
||||
str = null;
|
||||
}
|
||||
definition.setInteraction(opcode - 30, str);
|
||||
} else if (opcode == 40) {
|
||||
int length = buffer.get() & 0xFF;
|
||||
int[] originalColours = new int[length];
|
||||
int[] replacementColours = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
originalColours[i] = buffer.getShort();
|
||||
replacementColours[i] = buffer.getShort();
|
||||
}
|
||||
} else if (opcode == 60) {
|
||||
int length = buffer.get() & 0xFF;
|
||||
int[] additionalModels = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
additionalModels[i] = buffer.getShort();
|
||||
}
|
||||
} else if (opcode >= 90 && opcode <= 92) {
|
||||
buffer.getShort(); // Dummy
|
||||
} else if (opcode == 95) {
|
||||
definition.setCombatLevel(buffer.getShort());
|
||||
} else if (opcode == 97 || opcode == 98) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 100 || opcode == 101) {
|
||||
buffer.get();
|
||||
} else if (opcode == 102 || opcode == 103) {
|
||||
buffer.getShort();
|
||||
} else if (opcode == 106) {
|
||||
wrap(buffer.getShort());
|
||||
wrap(buffer.getShort());
|
||||
|
||||
int count = buffer.get() & 0xFF;
|
||||
int[] morphisms = new int[count + 1];
|
||||
Arrays.setAll(morphisms, index -> wrap(buffer.getShort()));
|
||||
} else if (opcode == 107) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a morphism value around, returning -1 if the specified value is 65,535.
|
||||
*
|
||||
* @param value The value.
|
||||
* @return -1 if {@code value} is 65,535, otherwise {@code value}.
|
||||
*/
|
||||
private static int wrap(int value) {
|
||||
return value == 65_535 ? -1 : value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package org.apollo.cache.decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.cache.archive.Archive;
|
||||
import org.apollo.cache.def.ObjectDefinition;
|
||||
import org.apollo.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* Decodes object data from the {@code loc.dat} file into {@link ObjectDefinition}s.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ObjectDefinitionDecoder {
|
||||
|
||||
/**
|
||||
* The {@link IndexedFileSystem}.
|
||||
*/
|
||||
private final IndexedFileSystem fs;
|
||||
|
||||
/**
|
||||
* Creates the decoder.
|
||||
*
|
||||
* @param fs The {@link IndexedFileSystem}.
|
||||
*/
|
||||
public ObjectDefinitionDecoder(IndexedFileSystem fs) {
|
||||
this.fs = fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes all of the data into {@link ObjectDefinition}s.
|
||||
*
|
||||
* @return The definitions.
|
||||
* @throws IOException If an error occurs when decoding the archive or finding an entry.
|
||||
*/
|
||||
public ObjectDefinition[] decode() 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();
|
||||
}
|
||||
|
||||
ObjectDefinition[] defs = new ObjectDefinition[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
data.position(indices[i]);
|
||||
defs[i] = decode(i, data);
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes data from the cache into an {@link ObjectDefinition}.
|
||||
*
|
||||
* @param id The id of the object.
|
||||
* @param data The {@link ByteBuffer} containing the data.
|
||||
* @return The object definition.
|
||||
*/
|
||||
public static ObjectDefinition decode(int id, ByteBuffer data) {
|
||||
ObjectDefinition definition = new ObjectDefinition(id);
|
||||
while (true) {
|
||||
int opcode = data.get() & 0xFF;
|
||||
|
||||
if (opcode == 0) {
|
||||
return definition;
|
||||
} else if (opcode == 1) {
|
||||
int amount = data.get() & 0xFF;
|
||||
for (int i = 0; i < amount; i++) {
|
||||
data.getShort();
|
||||
data.get();
|
||||
}
|
||||
} else if (opcode == 2) {
|
||||
definition.setName(BufferUtil.readString(data));
|
||||
} else if (opcode == 3) {
|
||||
definition.setDescription(BufferUtil.readString(data));
|
||||
} else if (opcode == 5) {
|
||||
int amount = data.get() & 0xFF;
|
||||
for (int i = 0; i < amount; i++) {
|
||||
data.getShort();
|
||||
}
|
||||
} else if (opcode == 14) {
|
||||
definition.setWidth(data.get() & 0xFF);
|
||||
} else if (opcode == 15) {
|
||||
definition.setLength(data.get() & 0xFF);
|
||||
} else if (opcode == 17) {
|
||||
definition.setSolid(false);
|
||||
} else if (opcode == 18) {
|
||||
definition.setImpenetrable(false);
|
||||
} else if (opcode == 19) {
|
||||
definition.setInteractive((data.get() & 0xFF) == 1);
|
||||
} else if (opcode == 24) {
|
||||
data.getShort();
|
||||
} else if (opcode == 28 || opcode == 29) {
|
||||
data.get();
|
||||
} else if (opcode >= 30 && opcode < 39) {
|
||||
String[] actions = definition.getMenuActions();
|
||||
if (actions == null) {
|
||||
actions = new String[10];
|
||||
}
|
||||
String action = BufferUtil.readString(data);
|
||||
actions[opcode - 30] = action;
|
||||
definition.setMenuActions(actions);
|
||||
} else if (opcode == 39) {
|
||||
data.get();
|
||||
} else if (opcode == 40) {
|
||||
int amount = data.get() & 0xFF;
|
||||
for (int i = 0; i < amount; i++) {
|
||||
data.getShort();
|
||||
data.getShort();
|
||||
}
|
||||
} else if (opcode == 60 || opcode >= 65 && opcode <= 68) {
|
||||
data.getShort();
|
||||
} else if (opcode == 69) {
|
||||
data.get();
|
||||
} else if (opcode >= 70 && opcode <= 72) {
|
||||
data.getShort();
|
||||
} else if (opcode == 73) {
|
||||
definition.setObstructive(true);
|
||||
} else if (opcode == 75) {
|
||||
data.get();
|
||||
} else if (opcode == 77) {
|
||||
data.getShort();
|
||||
data.getShort();
|
||||
int count = data.get();
|
||||
for (int i = 0; i <= count; i++) {
|
||||
data.getShort();
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes which parse files within the game's cache.
|
||||
*/
|
||||
package org.apollo.cache.decoder;
|
||||
@@ -0,0 +1,309 @@
|
||||
package org.apollo.cache.def;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Represents a type of Item that may be equipped.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class EquipmentDefinition {
|
||||
|
||||
/**
|
||||
* The attack id.
|
||||
*/
|
||||
private static final int ATTACK = 0;
|
||||
|
||||
/**
|
||||
* The defence id.
|
||||
*/
|
||||
private static final int DEFENCE = 1;
|
||||
|
||||
/**
|
||||
* The strength id.
|
||||
*/
|
||||
private static final int STRENGTH = 2;
|
||||
|
||||
/**
|
||||
* The hitpoints id.
|
||||
*/
|
||||
private static final int HITPOINTS = 3;
|
||||
|
||||
/**
|
||||
* The ranged id.
|
||||
*/
|
||||
private static final int RANGED = 4;
|
||||
|
||||
/**
|
||||
* The prayer id.
|
||||
*/
|
||||
private static final int PRAYER = 5;
|
||||
|
||||
/**
|
||||
* The magic id.
|
||||
*/
|
||||
private static final int MAGIC = 6;
|
||||
|
||||
/**
|
||||
* The equipment definitions.
|
||||
*/
|
||||
private static final Map<Integer, EquipmentDefinition> definitions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Gets the total number of equipment definitions.
|
||||
*
|
||||
* @return The count.
|
||||
*/
|
||||
public static int count() {
|
||||
return definitions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the equipment definitions.
|
||||
*
|
||||
* @param definitions The definitions.
|
||||
* @throws RuntimeException If there is an id mismatch.
|
||||
*/
|
||||
public static void init(EquipmentDefinition[] definitions) {
|
||||
for (int id = 0; id < definitions.length; id++) {
|
||||
EquipmentDefinition def = definitions[id];
|
||||
if (def != null) {
|
||||
if (def.getId() != id) {
|
||||
throw new RuntimeException("Equipment definition id mismatch.");
|
||||
}
|
||||
EquipmentDefinition.definitions.put(def.getId(), def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an equipment definition by its id.
|
||||
*
|
||||
* @param id The id.
|
||||
* @return {@code null} if the item is not equipment, the definition otherwise.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public static EquipmentDefinition lookup(int id) {
|
||||
Preconditions.checkElementIndex(id, ItemDefinition.count(), "Id out of bounds.");
|
||||
return definitions.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* The item id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* The array of skill requirement levels.
|
||||
*/
|
||||
private final int[] levels = { 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
/**
|
||||
* The slot this equipment goes into.
|
||||
*/
|
||||
private int slot;
|
||||
|
||||
/**
|
||||
* Various flags.
|
||||
*/
|
||||
private boolean twoHanded, fullBody, fullHat, fullMask;
|
||||
|
||||
/**
|
||||
* Creates a new equipment definition.
|
||||
*
|
||||
* @param id The id.
|
||||
*/
|
||||
public EquipmentDefinition(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum attack level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getAttackLevel() {
|
||||
return levels[ATTACK];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum defence level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getDefenceLevel() {
|
||||
return levels[DEFENCE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum hitpoints level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getHitpointsLevel() {
|
||||
return levels[HITPOINTS];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
*
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum level required to equip this item for a specific skill.
|
||||
*
|
||||
* @param skill The skill id.
|
||||
* @return The level.
|
||||
*/
|
||||
public int getLevel(int skill) {
|
||||
Preconditions.checkArgument(skill >= ATTACK && skill <= MAGIC, "Skill id out of bounds.");
|
||||
return levels[skill];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum magic level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getMagicLevel() {
|
||||
return levels[MAGIC];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum prayer level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getPrayerLevel() {
|
||||
return levels[PRAYER];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum ranged level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getRangedLevel() {
|
||||
return levels[RANGED];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target slot.
|
||||
*
|
||||
* @return The target slot.
|
||||
*/
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum strength level required to equip this item.
|
||||
*
|
||||
* @return The level.
|
||||
*/
|
||||
public int getStrengthLevel() {
|
||||
return levels[STRENGTH];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this equipment is a full body.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isFullBody() {
|
||||
return fullBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this equipment is a full hat.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isFullHat() {
|
||||
return fullHat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this equipment is a full mask.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isFullMask() {
|
||||
return fullMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this equipment is two-handed.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isTwoHanded() {
|
||||
return twoHanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flags.
|
||||
*
|
||||
* @param twoHanded The two handed flag.
|
||||
* @param fullBody The full body flag.
|
||||
* @param fullHat The full hat flag.
|
||||
* @param fullMask The full mask flag.
|
||||
*/
|
||||
public void setFlags(boolean twoHanded, boolean fullBody, boolean fullHat, boolean fullMask) {
|
||||
this.twoHanded = twoHanded;
|
||||
this.fullBody = fullBody;
|
||||
this.fullHat = fullHat;
|
||||
this.fullMask = fullMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the required levels.
|
||||
*
|
||||
* @param attack The required attack level.
|
||||
* @param strength The required strength level.
|
||||
* @param defence The required defence level.
|
||||
* @param ranged The required ranged level.
|
||||
* @param magic The required magic level.
|
||||
*/
|
||||
public void setLevels(int attack, int strength, int defence, int ranged, int magic) {
|
||||
setLevels(attack, strength, defence, 1, ranged, 1, magic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the required levels.
|
||||
*
|
||||
* @param attack The required attack level.
|
||||
* @param strength The required strength level.
|
||||
* @param defence The required defence level.
|
||||
* @param hitpoints The required hitpoints level.
|
||||
* @param ranged The required ranged level.
|
||||
* @param prayer The required prayer level.
|
||||
* @param magic The required magic level.
|
||||
*/
|
||||
public void setLevels(int attack, int strength, int defence, int hitpoints, int ranged, int prayer, int magic) {
|
||||
levels[ATTACK] = attack;
|
||||
levels[STRENGTH] = strength;
|
||||
levels[DEFENCE] = defence;
|
||||
levels[HITPOINTS] = hitpoints;
|
||||
levels[RANGED] = ranged;
|
||||
levels[PRAYER] = prayer;
|
||||
levels[MAGIC] = magic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target slot.
|
||||
*
|
||||
* @param slot The target slot.
|
||||
*/
|
||||
public void setSlot(int slot) {
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
package org.apollo.cache.def;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
|
||||
/**
|
||||
* Represents a type of Item.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ItemDefinition {
|
||||
|
||||
/**
|
||||
* The item definitions.
|
||||
*/
|
||||
private static ItemDefinition[] definitions;
|
||||
|
||||
/**
|
||||
* A map of item ids to noted ids.
|
||||
*/
|
||||
private static final BiMap<Integer, Integer> notes = HashBiMap.create();
|
||||
|
||||
/**
|
||||
* A map of noted ids to item ids.
|
||||
*/
|
||||
private static final BiMap<Integer, Integer> notesInverse = notes.inverse();
|
||||
|
||||
/**
|
||||
* Gets the total number of item definitions.
|
||||
*
|
||||
* @return The count.
|
||||
*/
|
||||
public static int count() {
|
||||
return definitions.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of item definitions.
|
||||
*
|
||||
* @return The definitions.
|
||||
*/
|
||||
public static ItemDefinition[] getDefinitions() {
|
||||
return definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the class with the specified set of definitions.
|
||||
*
|
||||
* @param definitions The definitions.
|
||||
* @throws RuntimeException If there is an id mismatch.
|
||||
*/
|
||||
public static void init(ItemDefinition[] definitions) {
|
||||
ItemDefinition.definitions = definitions;
|
||||
for (int id = 0; id < definitions.length; id++) {
|
||||
ItemDefinition def = definitions[id];
|
||||
if (def.getId() != id) {
|
||||
throw new RuntimeException("Item definition id mismatch.");
|
||||
}
|
||||
if (def.isNote()) {
|
||||
def.toNote();
|
||||
notes.put(def.getNoteInfoId(), def.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an item id to a noted id.
|
||||
*
|
||||
* @param id The item id.
|
||||
* @return The noted id.
|
||||
*/
|
||||
public static int itemToNote(int id) {
|
||||
Integer entry = notes.get(id);
|
||||
if (entry == null) {
|
||||
return id;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item definition for the specified id.
|
||||
*
|
||||
* @param id The id.
|
||||
* @return The definition.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public static ItemDefinition lookup(int id) {
|
||||
Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds.");
|
||||
return definitions[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a noted id to the normal item id.
|
||||
*
|
||||
* @param id The note id.
|
||||
* @return The item id.
|
||||
*/
|
||||
public static int noteToItem(int id) {
|
||||
Integer entry = notesInverse.get(id);
|
||||
if (entry == null) {
|
||||
return id;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of the item.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* The ground actions array.
|
||||
*/
|
||||
private final String[] groundActions = new String[5];
|
||||
|
||||
/**
|
||||
* The item's id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* The inventory actions array.
|
||||
*/
|
||||
private final String[] inventoryActions = new String[5];
|
||||
|
||||
/**
|
||||
* A flag indicating if this item is members only.
|
||||
*/
|
||||
private boolean members = false;
|
||||
|
||||
/**
|
||||
* The name of the item.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The id of the item to copy note graphics from.
|
||||
*/
|
||||
private int noteGraphicId = -1;
|
||||
|
||||
/**
|
||||
* The id of the item to copy note info from.
|
||||
*/
|
||||
private int noteInfoId = -1;
|
||||
|
||||
/**
|
||||
* A flag indicating if this item is stackable.
|
||||
*/
|
||||
private boolean stackable = false;
|
||||
|
||||
/**
|
||||
* This item's team.
|
||||
*/
|
||||
private int team;
|
||||
|
||||
/**
|
||||
* The item's floor value.
|
||||
*/
|
||||
private int value = 1;
|
||||
|
||||
/**
|
||||
* Creates an item definition with the default values.
|
||||
*
|
||||
* @param id The item's id.
|
||||
*/
|
||||
public ItemDefinition(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of this item.
|
||||
*
|
||||
* @return The item's description.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a ground action.
|
||||
*
|
||||
* @param id The id.
|
||||
* @return The action.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public String getGroundAction(int id) {
|
||||
Preconditions.checkElementIndex(id, groundActions.length, "Ground action id is out of bounds.");
|
||||
return groundActions[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this item's id.
|
||||
*
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an inventory action.
|
||||
*
|
||||
* @param id The id.
|
||||
* @return The action.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public String getInventoryAction(int id) {
|
||||
Preconditions.checkElementIndex(id, inventoryActions.length, "Inventory action id is out of bounds.");
|
||||
return inventoryActions[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this item's name.
|
||||
*
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this item's note graphic id.
|
||||
*
|
||||
* @return The note graphic id.
|
||||
*/
|
||||
public int getNoteGraphicId() {
|
||||
return noteGraphicId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this item's note info id.
|
||||
*
|
||||
* @return The note info id.
|
||||
*/
|
||||
public int getNoteInfoId() {
|
||||
return noteInfoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this item's team.
|
||||
*
|
||||
* @return The team.
|
||||
*/
|
||||
public int getTeam() {
|
||||
return team;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this item's value.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this item is members only.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isMembersOnly() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this item is a note.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isNote() {
|
||||
return noteGraphicId != -1 && noteInfoId != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item specified by this definition is stackable.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean isStackable() {
|
||||
return stackable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's description.
|
||||
*
|
||||
* @param description The description.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a ground action.
|
||||
*
|
||||
* @param id The id.
|
||||
* @param action The action.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public void setGroundAction(int id, String action) {
|
||||
Preconditions.checkElementIndex(id, groundActions.length, "Ground action id is out of bounds.");
|
||||
groundActions[id] = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an inventory action.
|
||||
*
|
||||
* @param id The id.
|
||||
* @param action The action.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public void setInventoryAction(int id, String action) {
|
||||
Preconditions.checkElementIndex(id, inventoryActions.length, "Inventory action id is out of bounds.");
|
||||
inventoryActions[id] = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's members only flag.
|
||||
*
|
||||
* @param members The flag.
|
||||
*/
|
||||
public void setMembersOnly(boolean members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's name.
|
||||
*
|
||||
* @param name The name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's note graphic id.
|
||||
*
|
||||
* @param noteGraphicId The note graphic id.
|
||||
*/
|
||||
public void setNoteGraphicId(int noteGraphicId) {
|
||||
this.noteGraphicId = noteGraphicId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's note info id.
|
||||
*
|
||||
* @param noteInfoId The note info id.
|
||||
*/
|
||||
public void setNoteInfoId(int noteInfoId) {
|
||||
this.noteInfoId = noteInfoId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's stackable flag.
|
||||
*
|
||||
* @param stackable The stackable flag.
|
||||
*/
|
||||
public void setStackable(boolean stackable) {
|
||||
this.stackable = stackable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this item's team.
|
||||
*
|
||||
* @param team The team.
|
||||
*/
|
||||
public void setTeam(int team) {
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets this item's value.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
public void setValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this item to a note, if possible.
|
||||
*
|
||||
* @throws IllegalStateException If {@link ItemDefinition#isNote()} returns {@code false}.
|
||||
*/
|
||||
public void toNote() {
|
||||
if (isNote()) {
|
||||
if (description != null && description.startsWith("Swap this note at any bank for ")) {
|
||||
return; // already converted.
|
||||
}
|
||||
|
||||
ItemDefinition infoDef = lookup(noteInfoId);
|
||||
name = infoDef.name;
|
||||
members = infoDef.members;
|
||||
|
||||
String prefix = "a";
|
||||
char firstChar = name == null ? 'n' : name.charAt(0);
|
||||
|
||||
if (firstChar == 'A' || firstChar == 'E' || firstChar == 'I' || firstChar == 'O' || firstChar == 'U') {
|
||||
prefix = "an";
|
||||
}
|
||||
|
||||
description = "Swap this note at any bank for " + prefix + " " + name + ".";
|
||||
stackable = true;
|
||||
} else {
|
||||
throw new IllegalStateException("Item cannot be noted.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
package org.apollo.cache.def;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Represents a type of Npc.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class NpcDefinition {
|
||||
|
||||
/**
|
||||
* The npc definitions.
|
||||
*/
|
||||
private static NpcDefinition[] definitions;
|
||||
|
||||
/**
|
||||
* Gets the total number of npc definitions.
|
||||
*
|
||||
* @return The count.
|
||||
*/
|
||||
public static int count() {
|
||||
return definitions.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of npc definitions.
|
||||
*
|
||||
* @return The definitions.
|
||||
*/
|
||||
public static NpcDefinition[] getDefinitions() {
|
||||
return definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the class with the specified set of definitions.
|
||||
*
|
||||
* @param definitions The definitions.
|
||||
* @throws RuntimeException If there is an id mismatch.
|
||||
*/
|
||||
public static void init(NpcDefinition[] definitions) {
|
||||
NpcDefinition.definitions = definitions;
|
||||
for (int id = 0; id < definitions.length; id++) {
|
||||
NpcDefinition def = definitions[id];
|
||||
if (def.getId() != id) {
|
||||
throw new RuntimeException("Npc definition id mismatch.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc definition for the specified id.
|
||||
*
|
||||
* @param id The id.
|
||||
* @return The definition.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public static NpcDefinition lookup(int id) {
|
||||
Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds.");
|
||||
return definitions[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* The combat level of the npc.
|
||||
*/
|
||||
private int combatLevel = -1;
|
||||
|
||||
/**
|
||||
* The description of the npc.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* The npc id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* An array of interaction options.
|
||||
*/
|
||||
private final String[] interactions = new String[5];
|
||||
|
||||
/**
|
||||
* The name of the npc.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The npc's size, in tiles.
|
||||
*/
|
||||
private int size = 1;
|
||||
|
||||
/**
|
||||
* The various animation ids.
|
||||
*/
|
||||
private int standAnim = -1, walkAnim = -1, walkBackAnim = -1, walkLeftAnim = -1, walkRightAnim = -1;
|
||||
|
||||
/**
|
||||
* Creates a new npc definition.
|
||||
*
|
||||
* @param id The npc id.
|
||||
*/
|
||||
public NpcDefinition(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc's combat level.
|
||||
*
|
||||
* @return The combat level, or -1 if it doesn't have one.
|
||||
*/
|
||||
public int getCombatLevel() {
|
||||
return combatLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of the npc.
|
||||
*
|
||||
* @return The description.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc id.
|
||||
*
|
||||
* @return The npc id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an interaction option.
|
||||
*
|
||||
* @param slot The slot of the option.
|
||||
* @return The option, or {@code null} if there isn't any at the specified slot.
|
||||
* @throws IndexOutOfBoundsException If the slot is out of bounds.
|
||||
*/
|
||||
public String getInteraction(int slot) {
|
||||
Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds.");
|
||||
return interactions[slot];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of interaction options.
|
||||
*
|
||||
* @return The interaction options.
|
||||
*/
|
||||
public String[] getInteractions() {
|
||||
return interactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the npc.
|
||||
*
|
||||
* @return The name of the npc.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the npc's size, in tiles.
|
||||
*
|
||||
* @return The size.
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the npc's standing animation.
|
||||
*
|
||||
* @return The stand animation id, or -1 if it doesn't have one.
|
||||
*/
|
||||
public int getStandAnimation() {
|
||||
return standAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the walking animation of the npc.
|
||||
*
|
||||
* @return The walking animation.
|
||||
*/
|
||||
public int getWalkAnimation() {
|
||||
return walkAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the walk-back animation of the npc.
|
||||
*
|
||||
* @return The walk-back animation.
|
||||
*/
|
||||
public int getWalkBackAnimation() {
|
||||
return walkBackAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the walk-left animation of the npc.
|
||||
*
|
||||
* @return The walk-left animation.
|
||||
*/
|
||||
public int getWalkLeftAnimation() {
|
||||
return walkLeftAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the walk-right animation of the npc.
|
||||
*
|
||||
* @return The walk-right animation.
|
||||
*/
|
||||
public int getWalkRightAnimation() {
|
||||
return walkRightAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the npc has a combat level.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean hasCombatLevel() {
|
||||
return combatLevel != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is an interaction option present.
|
||||
*
|
||||
* @param slot The slot to check.
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
* @throws IndexOutOfBoundsException If the slot is out of bounds.
|
||||
*/
|
||||
public boolean hasInteraction(int slot) {
|
||||
Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds.");
|
||||
return interactions[slot] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the npc has a standing animation id.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean hasStandAnimation() {
|
||||
return standAnim != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the npc has a walking animation.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean hasWalkAnimation() {
|
||||
return walkAnim != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the npc has a walk-back animation.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean hasWalkBackAnimation() {
|
||||
return walkBackAnim != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the npc has a walk-left animation.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean hasWalkLeftAnimation() {
|
||||
return walkLeftAnim != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the npc has a walk-right animation.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
public boolean hasWalkRightAnimation() {
|
||||
return walkRightAnim != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the npc's combat level.
|
||||
*
|
||||
* @param combatLevel The combat level.
|
||||
*/
|
||||
public void setCombatLevel(int combatLevel) {
|
||||
this.combatLevel = combatLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description of the npc.
|
||||
*
|
||||
* @param description The description.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an interaction option.
|
||||
*
|
||||
* @param slot The slot of the option.
|
||||
* @param interaction The interaction options.
|
||||
* @throws IndexOutOfBoundsException If the slot is out of bounds.
|
||||
*/
|
||||
public void setInteraction(int slot, String interaction) {
|
||||
Preconditions.checkElementIndex(slot, interactions.length, "Npc interaction id is out of bounds.");
|
||||
interactions[slot] = interaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the npc.
|
||||
*
|
||||
* @param name The name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of the npc, in tiles.
|
||||
*
|
||||
* @param size The size.
|
||||
*/
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of the npc's standing animation.
|
||||
*
|
||||
* @param standAnim The stand animation id.
|
||||
*/
|
||||
public void setStandAnimation(int standAnim) {
|
||||
this.standAnim = standAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the walking animation of the npc.
|
||||
*
|
||||
* @param walkAnim The walking animation.
|
||||
*/
|
||||
public void setWalkAnimation(int walkAnim) {
|
||||
this.walkAnim = walkAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the various walking animations of the npc.
|
||||
*
|
||||
* @param walkAnim The walking animation.
|
||||
* @param walkBackAnim The walk-back animation.
|
||||
* @param walkLeftAnim The walk-left animation.
|
||||
* @param walkRightAnim The walk-right animation.
|
||||
*/
|
||||
public void setWalkAnimations(int walkAnim, int walkBackAnim, int walkLeftAnim, int walkRightAnim) {
|
||||
this.walkAnim = walkAnim;
|
||||
this.walkBackAnim = walkBackAnim;
|
||||
this.walkLeftAnim = walkLeftAnim;
|
||||
this.walkRightAnim = walkRightAnim;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
package org.apollo.cache.def;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Represents a type of GameObject.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ObjectDefinition {
|
||||
|
||||
/**
|
||||
* The array of game object definitions.
|
||||
*/
|
||||
private static ObjectDefinition[] definitions;
|
||||
|
||||
/**
|
||||
* Gets the total number of object definitions.
|
||||
*
|
||||
* @return The count.
|
||||
*/
|
||||
public static int count() {
|
||||
return definitions.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of object definitions.
|
||||
*
|
||||
* @return The definitions.
|
||||
*/
|
||||
public static ObjectDefinition[] getDefinitions() {
|
||||
return definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the object definitions.
|
||||
*
|
||||
* @param definitions The decoded definitions.
|
||||
* @throws RuntimeException If there is an id mismatch.
|
||||
*/
|
||||
public static void init(ObjectDefinition[] definitions) {
|
||||
ObjectDefinition.definitions = definitions;
|
||||
for (int id = 0; id < definitions.length; id++) {
|
||||
ObjectDefinition def = definitions[id];
|
||||
if (def.getId() != id) {
|
||||
throw new RuntimeException("Item definition id mismatch.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object definition for the specified id.
|
||||
*
|
||||
* @param id The id of the object.
|
||||
* @return The definition.
|
||||
* @throws IndexOutOfBoundsException If the id is out of bounds.
|
||||
*/
|
||||
public static ObjectDefinition lookup(int id) {
|
||||
Preconditions.checkElementIndex(id, definitions.length, "Id out of bounds.");
|
||||
return definitions[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* The object's description.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* The object's id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Denotes whether this object is impenetrable or not.
|
||||
*/
|
||||
private boolean impenetrable = true;
|
||||
|
||||
/**
|
||||
* Denotes whether this object has actions associated with it or not.
|
||||
*/
|
||||
private boolean interactive;
|
||||
|
||||
/**
|
||||
* Denotes whether or not this object obstructs the ground.
|
||||
*/
|
||||
private boolean obstructive;
|
||||
|
||||
/**
|
||||
* This object's length.
|
||||
*/
|
||||
private int length = 1;
|
||||
|
||||
/**
|
||||
* The object's menu actions.
|
||||
*/
|
||||
private String[] menuActions;
|
||||
|
||||
/**
|
||||
* The object's name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Denotes whether the object can be walked over or not.
|
||||
*/
|
||||
private boolean solid = true;
|
||||
|
||||
/**
|
||||
* This object's width.
|
||||
*/
|
||||
private int width = 1;
|
||||
|
||||
/**
|
||||
* Creates a new object definition.
|
||||
*
|
||||
* @param id The id of the object.
|
||||
*/
|
||||
public ObjectDefinition(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of this object.
|
||||
*
|
||||
* @return The description.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of this object.
|
||||
*
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of this object.
|
||||
*
|
||||
* @return The length.
|
||||
*/
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the menu actions of this object.
|
||||
*
|
||||
* @return The menu actions.
|
||||
*/
|
||||
public String[] getMenuActions() {
|
||||
return menuActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this object.
|
||||
*
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the with of this object.
|
||||
*
|
||||
* @return The width.
|
||||
*/
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the impenetrability of this object.
|
||||
*
|
||||
* @return {@code true} if this object is impenetrable, otherwise {@code false}.
|
||||
*/
|
||||
public boolean isImpenetrable() {
|
||||
return impenetrable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the interactivity of this object.
|
||||
*
|
||||
* @return {@code true} if the object is interactive, otherwise {@code false}.
|
||||
*/
|
||||
public boolean isInteractive() {
|
||||
return interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not this object obstructs the ground.
|
||||
*
|
||||
* @return {@code true} if the object obstructs the ground otherwise {@code false}.
|
||||
*/
|
||||
public boolean isObstructive() {
|
||||
return obstructive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the solidity of this object.
|
||||
*
|
||||
* @return {@code true} if this object is solid, otherwise {@code false}.
|
||||
*/
|
||||
public boolean isSolid() {
|
||||
return solid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description of this object.
|
||||
*
|
||||
* @param description The description.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the impenetrability of this object.
|
||||
*
|
||||
* @param impenetrable The impenetrability.
|
||||
*/
|
||||
public void setImpenetrable(boolean impenetrable) {
|
||||
this.impenetrable = impenetrable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interactivity of this object.
|
||||
*
|
||||
* @param interactive The interactivity.
|
||||
*/
|
||||
public void setInteractive(boolean interactive) {
|
||||
this.interactive = interactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of this object.
|
||||
*
|
||||
* @param length The length.
|
||||
*/
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the menu actions of this object.
|
||||
*
|
||||
* @param menuActions The menu actions.
|
||||
*/
|
||||
public void setMenuActions(String[] menuActions) {
|
||||
this.menuActions = menuActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this object.
|
||||
*
|
||||
* @param name The name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the solidity of this object.
|
||||
*
|
||||
* @param solid The solidity.
|
||||
*/
|
||||
public void setSolid(boolean solid) {
|
||||
this.solid = solid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width of this object.
|
||||
*
|
||||
* @param width The width.
|
||||
*/
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not this object is obstructive to the ground.
|
||||
*
|
||||
* @param obstructive Whether or not this object obstructs the ground.
|
||||
*/
|
||||
public void setObstructive(boolean obstructive) {
|
||||
this.obstructive = obstructive;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains definition classes which contain information about types of items, NPCs, etc.
|
||||
*/
|
||||
package org.apollo.cache.def;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes which deal with the file system that the client uses to store game data files.
|
||||
*/
|
||||
package org.apollo.cache;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains cache-related tools.
|
||||
*/
|
||||
package org.apollo.cache.tools;
|
||||
Reference in New Issue
Block a user