mirror of
https://github.com/moparisthebest/rswiki-book
synced 2024-11-21 16:45:01 -05:00
Add data section + rewrite them
This commit is contained in:
parent
769bdac9bf
commit
2f7502f346
@ -1,156 +1,217 @@
|
|||||||
\[\[Category Cache\]\]
|
# Archive format
|
||||||
|
|
||||||
== Introduction ==
|
From client revision 194 until 377, all the files in cache 0
|
||||||
|
are in an archive-like format which contains a collection of named
|
||||||
|
files (e.g. `BADENC.TXT` is a file which contains bad words in the
|
||||||
|
`wordenc` archive).
|
||||||
|
|
||||||
Since 194 all way up until 377, all the files in cache 0 have an
|
## Usage
|
||||||
archive-like format which contains a collection of named files (e.g.
|
|
||||||
'''BADENC.TXT''' is a file which contains bad words in the '''wordenc'''
|
|
||||||
archive).
|
|
||||||
|
|
||||||
=== Diagram ===
|
These files are used by the client for a variety of purpose.
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
The files themselves represent either an index, which contains
|
||||||
|
information about to where to locate data in the cache, and
|
||||||
|
the data themselves.
|
||||||
|
|
||||||
\[http://img263.imageshack.us/img263/9678/68481568.png External Diagram
|
e.g. `DATA` contains data for interfaces.
|
||||||
Image\]
|
|
||||||
|
|
||||||
== Usage ==
|
e.g. `MAP_INDEX` contains information about where to find the map and landscape files in the cache.
|
||||||
|
|
||||||
These files are used by the client for a variety of purposes. Some, such
|
## Format
|
||||||
as the '''DATA''' file contain data themselves (in this case the
|
|
||||||
interfaces). Others, such as the '''MAP\_INDEX''' file, contain
|
|
||||||
information about where to locate the map and landscape files in the
|
|
||||||
cache.
|
|
||||||
|
|
||||||
== Format ==
|
```
|
||||||
|
tribyte uncompressedSize
|
||||||
tribyte uncompressedsize tribyte compressedsize
|
tribyte compressedSize
|
||||||
|
```
|
||||||
|
|
||||||
If the uncompressed and compressed sizes are equal, the whole file is
|
If the uncompressed and compressed sizes are equal, the whole file is
|
||||||
not compressed but the individual entries are compressed using bzip2. If
|
not compressed but the individual entries are compressed using bzip2.
|
||||||
they are not equal, the entire file is compressed using bzip2 but the
|
If they are not equal, the entire file is compressed using bzip2 but
|
||||||
individual entries are not.
|
the individual entries are not.
|
||||||
|
|
||||||
Also note, the magic id at the start of the bzip2 entries are not
|
Note: The magic id at the start of the bzip2 entries are not included
|
||||||
included in the cache. If you use an existing API to read the files and
|
in the cache.
|
||||||
want to add this back, you must append the four characters: BZh1 before
|
If you use an existing API to read the files and want to add this back,
|
||||||
you decompress.
|
you must append the characters `BZh1` before you decompress.
|
||||||
|
|
||||||
short fileCount
|
```short fileCount```
|
||||||
|
|
||||||
Each file entry has the format:
|
Each file entry has the format:
|
||||||
|
|
||||||
int nameHash tribyte uncompressedSize tribyte compressedSize
|
```
|
||||||
|
int nameHash
|
||||||
|
tribyte uncompressedSize
|
||||||
|
tribyte compressedSize
|
||||||
|
```
|
||||||
|
|
||||||
When you are looping through the files, you need to keep track of the
|
# Extracting the data
|
||||||
file offset yourself. This psuedocode demonstrates how:
|
|
||||||
|
|
||||||
int offset = buffer.getCurrentOffset() + numFiles \* 10; for(int i = 0;
|
If you iterate over the files using a for-loop, you need to keep track of the
|
||||||
i \< numFiles; i++) { // read values int thisFileOffset = offset; offset
|
file offset.
|
||||||
+= thisFileCompressedSize; }
|
The following pseudo-code demonstates how:
|
||||||
|
|
||||||
To get a named file by its name, you should first hash the name using
|
```java
|
||||||
this method:
|
int offset = buffer.getCurrentOffset() + numFiles * 10;
|
||||||
|
|
||||||
public static int hash(String name) { int hash = 0; name =
|
for(int i = 0; i < numFiles; i++) {
|
||||||
name.toUpperCase(); for(int j = 0; j \< name.length(); j++) { hash =
|
// read values
|
||||||
(hash \* 61 + name.charAt(j)) - 32; } return hash; }
|
int thisFileOffset = offset;
|
||||||
|
offset += thisFileCompressedSize;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To acquire a named file using its name, hash the name as follows:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static int hash(String name) {
|
||||||
|
int hash = 0;
|
||||||
|
name = name.toUpperCase();
|
||||||
|
|
||||||
|
for(int j = 0; j < name.length(); j++) {
|
||||||
|
hash = (hash * 61 + name.charAt(j)) - 32;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Then, loop through the file entries you loaded earlier to find a
|
Then, loop through the file entries you loaded earlier to find a
|
||||||
matching hash. Read the compressed file size from the offset. If the
|
matching hash. Read the compressed file size from the offset. If the
|
||||||
whole file is not compressed, you should decompress the individual
|
whole file is not compressed, you should decompress the individual
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
== '''\#194 Archive Format''' ==
|
## \#194 Archive Format
|
||||||
|
|
||||||
The 194 (RuneScape 2 beta) client worked with a very simple cache
|
The \#194 (RuneScape 2 beta) client worked with a very simple cache
|
||||||
format. Each file in the cache was a file on the operating system.
|
format.
|
||||||
|
Each file in the cache corresponded to a file on the operating system.
|
||||||
|
|
||||||
=== Name hashing ===
|
### Name hashing
|
||||||
|
|
||||||
Every name in the cache was hashed using the following method which is,
|
Every name in the cache was hashed using the following method which is,
|
||||||
incidentally, similar to the way player names are converted to longs.
|
incidentally, similar to the way player names are converted to longs.
|
||||||
|
|
||||||
public static final long gethash(String string) { string =
|
```java
|
||||||
string.trim(); long l = 0L; for (int i = 0; i \< string.length() && i \<
|
public static final long gethash(String string) {
|
||||||
12; i++) { char c = string.charAt(i); l \*= 37L; if (c \>= 'A' && c \<=
|
string = string.trim();
|
||||||
'Z') l += (long) ('\\001' + c - 'A'); else if (c \>= 'a' && c \<= 'z') l
|
long l = 0L;
|
||||||
+= (long) ('\\001' + c - 'a'); else if (c \>= '0' && c \<= '9') l +=
|
|
||||||
(long) ('\\033' + c - '0'); } return l; }
|
for (int i = 0; i < string.length() && i < 12; i++) {
|
||||||
|
char c = string.charAt(i);
|
||||||
|
l \*= 37L;
|
||||||
|
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
l += (long) ('\\001' + c - 'A');
|
||||||
|
else if (c >= 'a' && c <= 'z')
|
||||||
|
l += (long) ('\\001' + c - 'a');
|
||||||
|
else if (c >= '0' && c <= '9')
|
||||||
|
l += (long) ('\\033' + c - '0');
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The resulting long was converted to a string and the file was given that
|
The resulting long was converted to a string and the file was given that
|
||||||
name.
|
name.
|
||||||
|
|
||||||
=== Files ===
|
### Files
|
||||||
|
|
||||||
The files in the cache were the ones used in the \[\[JAGGRAB
|
The files in the cache were the ones used in the [JAGGRAB protocol](./JAGGRAB-Protocol.html) (i.e. files in cache 0 in old engine caches),
|
||||||
Protocol\|JAGGRAB Protocol\]\] (i.e. files in cache 0 in old engine
|
map (mX_Y), and landscape (lX_Y) files.
|
||||||
caches) and map (mX\_Y) and landscape (lX\_Y) files. Incidentally, this
|
|
||||||
naming is very similar to the names of the map and landscape files in
|
|
||||||
new engine caches.
|
|
||||||
|
|
||||||
== '''\#317 Archive Format''' ==
|
Incidentally, this naming is very similar to the names of the map and
|
||||||
|
landscape files in new engine caches.
|
||||||
|
|
||||||
|
## \#317 Archive Format
|
||||||
|
|
||||||
The old engine cache is made up two types of files.
|
The old engine cache is made up two types of files.
|
||||||
|
|
||||||
=== Data file ===
|
### Data file
|
||||||
|
|
||||||
The data file holds all of the files in the cache and is named
|
The data file holds all of the files in the cache and is named
|
||||||
'''main\_file\_cache.dat'''. It is therefore very big, typically \~10-20
|
`main_file_cache.dat`.
|
||||||
megabytes..
|
It is therefore very big, typically ~10-20MB in size.
|
||||||
|
|
||||||
=== Index file ===
|
### Index file
|
||||||
|
|
||||||
There are several index files, named '''main\_file\_cache.idx''' and
|
There are several index files, named `main_file_cache.idx` and
|
||||||
then postfixed with a number. Each index file holds 'pointers' to where
|
then post-fixed with a number.
|
||||||
a file is located in the main cache. Each index file represents a type
|
Each index file holds 'pointers' to where a file is located in
|
||||||
of file.
|
the main cache.
|
||||||
|
Each index file represents a type of file.
|
||||||
|
|
||||||
=== Index file format ===
|
### Index file format
|
||||||
|
|
||||||
The index file is made up of 6 byte blocks which hold information about
|
The index file is comprised of a collection of six byte blocks which hold
|
||||||
where a file can be located in the data file. The format of a single
|
information about where a file can be located in the data file.
|
||||||
block is as follows:
|
|
||||||
|
|
||||||
tribyte fileSize tribyte initialDataBlockId
|
The format of a single block is as follows:
|
||||||
|
```
|
||||||
|
tribyte fileSize
|
||||||
|
tribyte initialDataBlockId
|
||||||
|
```
|
||||||
|
|
||||||
=== Data file format ===
|
### Data file format
|
||||||
|
|
||||||
The data file is made up of 520 byte blocks. The format of each of these
|
The data file is comprised of a collection of 520 byte blocks.
|
||||||
blocks is as follows:
|
|
||||||
|
|
||||||
short nextFileId short currentFilePartId tribyte nextDataBlockId byte
|
The format of each of these blocks is as follows:
|
||||||
nextFileTypeId byte\[512\] blockData
|
|
||||||
|
|
||||||
=== Explanation ===
|
```
|
||||||
|
short nextFileId
|
||||||
|
short currentFilePartId
|
||||||
|
tribyte nextDataBlockId
|
||||||
|
byte nextFileTypeId
|
||||||
|
byte[512] blockData
|
||||||
|
```
|
||||||
|
|
||||||
An example will be used here as it is easier to follow.
|
### Running example
|
||||||
|
|
||||||
Let us say, the client wishes to fetch file type 2, file id 17.
|
Suppose, the client wishes to fetch file type 2, file id 17.
|
||||||
|
|
||||||
First off, it will open the main\_file\_cache.idx2 file and seek to the
|
First off, it will open the `main_file_cache.idx2` file and seek to the
|
||||||
index 17 \* 6 (102). It will then read two tribytes.
|
index `17 * 6` (102).
|
||||||
|
It will then read the two tribytes:
|
||||||
|
```
|
||||||
|
fileSize = 1200
|
||||||
|
intialDataBlockId = 4
|
||||||
|
```
|
||||||
|
|
||||||
fileSize = 1200 intialDataBlockId = 4
|
The client will now open the `main_file_cache.dat` file and seek to the
|
||||||
|
index `4 * 520` (2080).
|
||||||
|
|
||||||
The client will now open the main\_file\_cache.dat file and seek to the
|
It will then read the following:
|
||||||
index 4 \* 520 (2080). The values it reads will be:
|
```
|
||||||
|
nextFileId = 17
|
||||||
nextFileId = 17 currentFilePartId = 0 nextDataBlockId = 5 nextFileTypeId
|
currentFilePartId = 0
|
||||||
= 2 blockData = ...
|
nextDataBlockId = 5
|
||||||
|
nextFileTypeId = 2
|
||||||
|
blockData = ... // 512 bytes of data
|
||||||
|
```
|
||||||
|
|
||||||
It will read the first 512 bytes of the file and then knows that there
|
It will read the first 512 bytes of the file and then knows that there
|
||||||
is 688 bytes left. Therefore, it has to read the next block.
|
is 688 bytes left.
|
||||||
|
|
||||||
nextFileId = 17 currentFilePartId = 1 nextDataBlockId = 6 nextFileTypeId
|
Therefore, it has to read the next block:
|
||||||
= 2 blockData ...
|
```
|
||||||
|
nextFileId = 17
|
||||||
|
currentFilePartId = 1
|
||||||
|
nextDataBlockId = 6
|
||||||
|
nextFileTypeId = 2
|
||||||
|
blockData ... // 512 bytes of data
|
||||||
|
```
|
||||||
|
|
||||||
It reads these next 512 bytes of the file and now knows that there are
|
It reads these next 512 bytes of the file and now knows that there are
|
||||||
176 bytes left. So for a final time, it will read the next block.
|
176 bytes left.
|
||||||
|
|
||||||
nextFileId = 18 currentFilePartId = 2 nextDataBlockId = 7 nextFileTypeId
|
So for a final time, it will read the next block:
|
||||||
= 2 blockData = ...
|
```
|
||||||
|
nextFileId = 18
|
||||||
|
currentFilePartId = 2
|
||||||
|
nextDataBlockId = 7
|
||||||
|
nextFileTypeId = 2
|
||||||
|
blockData = ... // 176 bytes of data
|
||||||
|
```
|
||||||
|
|
||||||
It can ignore most of these values (the next ones are meaningless at
|
It can ignore most of these values (the next ones are meaningless at
|
||||||
this stage) and read the final 176 bytes. The whole 1200 byte file has
|
this stage) and read the final 176 bytes.
|
||||||
now been read.
|
The whole 1200 byte file has now been read.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
A "DWord" (double-word) is a data-type that consists of 4 bytes.<br />
|
# DWord
|
||||||
|
|
||||||
|
A "DWord" (double-word) is a data-type that consists of 4 bytes.
|
||||||
It is also commonly known as the "int" data-type in programming.
|
It is also commonly known as the "int" data-type in programming.
|
||||||
\[\[Category Data Type\]\]
|
|
||||||
|
@ -1,85 +1,96 @@
|
|||||||
== Introduction ==
|
# Data types
|
||||||
|
|
||||||
RuneScape uses a number of standard and non-standard data types.
|
RuneScape uses a number of common and bespoke data types in the
|
||||||
|
process of data transmission.
|
||||||
|
|
||||||
== Byte Order ==
|
## Byte Order
|
||||||
|
|
||||||
Data types that are two bytes or larger can be stored and ordered in a
|
Data types that are two bytes or larger can be stored and ordered in a
|
||||||
variety of different ways. Generally people either use big endian or
|
variety of different ways.
|
||||||
little endian.
|
The traditional byte orders are big endian and little endian.
|
||||||
|
Generally people either use big endian or little endian.
|
||||||
|
|
||||||
=== Big Endian ===
|
RuneScape uses both little and big-endian byte orders throughout the
|
||||||
|
protocol (however, the 194 client only uses big-endian order).
|
||||||
|
This presumably to make reverse-engineering of the protocol harder.
|
||||||
|
|
||||||
|
Note: Some confusion has arisen over the byte order as the data types
|
||||||
|
are named incorrectly in Winterlove's server where little endian data
|
||||||
|
types are incorrectly named as big endian types.
|
||||||
|
|
||||||
|
### Big Endian
|
||||||
|
|
||||||
In big endian order, the most significant byte (MSB) is stored first and
|
In big endian order, the most significant byte (MSB) is stored first and
|
||||||
the least significant byte (LSB) is stored last.
|
the least significant byte (LSB) is stored last.
|
||||||
|
|
||||||
=== Little Endian ===
|
### Little Endian
|
||||||
|
|
||||||
In little endian order, the least significant byte (LSB) is stored first
|
In little endian order, the least significant byte (LSB) is stored first
|
||||||
and the most significant byte (MSB) is stored last.
|
and the most significant byte (MSB) is stored last.
|
||||||
|
|
||||||
=== Byte order in RuneScape ===
|
## Bespoke Byte Orders
|
||||||
|
|
||||||
RuneScape uses both little and big-endian byte orders throughout the
|
|
||||||
protocol (however, the 194 client only uses big-endian order),
|
|
||||||
presumably to make reverse-engineering of the protocol harder. Some
|
|
||||||
confusion has arisen over the byte order as the data types are named
|
|
||||||
incorrectly in \[\[Server Winterlove\|Winterlove\]\]'s server where
|
|
||||||
little endian data types are incorrectly named as big endian types.
|
|
||||||
|
|
||||||
== Standard data types == These datatypes can also be read/written by a
|
|
||||||
DataWriter/DataReader implementation (DataStreams and Buffers)
|
|
||||||
|
|
||||||
Naming conventions: {\| border=2 ! Official name ! Datatype name ! Jagex
|
|
||||||
name ! Encoding \|- \| Byte \| byte \| 1,1b \|- \| \[\[Word\|WORD\]\] \|
|
|
||||||
short \| 2,2b \|- \| \[\[DWord\|DWORD\]\] \| int,int32 \| 4,4b \|- \|
|
|
||||||
\[\[QWord\|QWORD\]\] \| long,int64 \| 8,8b \|- \| C style string \|
|
|
||||||
string,String,char *,char\[\] \| str,strbyte \| text bytes then '\n' or
|
|
||||||
10 \|- \| Java style string \| string,String,char *,char\[\] \| strraw
|
|
||||||
\| WORD length then text bytes \|}
|
|
||||||
|
|
||||||
Note that \[\[Jagex\]\] used to use a new line character as string
|
|
||||||
terminator, in more recent versions they use the null character \\0 or 0
|
|
||||||
to support multi-line strings.
|
|
||||||
|
|
||||||
== Non Standard Data Types ==
|
|
||||||
|
|
||||||
{\| border=2 ! Winterlove's name ! Jagex name ! Read transformation !
|
|
||||||
Write transformation \|- \| Special A \| Unknown \| value - 128 \| value
|
|
||||||
+ 128 \|- \| Special C \| Unknown \| 0 - value \| 0 - value \|- \|
|
|
||||||
Special S \| Unknown \| 128 - value \| 128 - value \|- \| SpaceSaverA \|
|
|
||||||
smarts \| (value\[0\] \< 128) ? (((value\[0\] - 128)\<\<8)+value\[1\]) :
|
|
||||||
value\[0\] \| if(value \< 128) putword(value+32768) else putbyte(value);
|
|
||||||
\|- \| SpaceSaverB \| smart \| (value\[0\] \< 128) ? value\[0\] - 64 \|
|
|
||||||
((value\[0\]\<\<8)+value\[1\]) - 49152 \| if(i \< 64 && i \>= -64)
|
|
||||||
putbyte(i + 64) else if(i \< 16384 && i \>= -16384) putword(i + 49152);
|
|
||||||
\|- \| tribyte / RGBColour / 3Byte / int3 / medium \| 3 \| (value\[0\]
|
|
||||||
\<\< 24) + (value\[1\] \<\< 16) + value\[2\] \| putbyte(value \>\>
|
|
||||||
24);putbyte(value \>\> 16);putbyte(value); \|- \| \[\[RS
|
|
||||||
String\|RS\_String\]\] \| jstr \| Old engine: read until newline
|
|
||||||
delimiter ("\n") <br />New engine: read until null byte (value 0). \|
|
|
||||||
Old engine: write and finish with newline delimiter ("\n") <br />New
|
|
||||||
engine: write and finish with null byte (value 0). \|}
|
|
||||||
|
|
||||||
Additionally, RuneScape also uses two endian orders for integers that
|
Additionally, RuneScape also uses two endian orders for integers that
|
||||||
are different from a big- or low endian order. Both byte orders are
|
are different from a big- or low endian order.
|
||||||
called middle-endian.
|
We call these byte orders middle endian.
|
||||||
|
|
||||||
Their orders could be described as following:
|
### Middle Endian Big Int
|
||||||
|
|
||||||
Middle-endian big int: C3 D4 A1 B2
|
The bytes are stored in the following order, where A1 is the smallest byte (I.e. LSB) and D4 the bigger (i.e. MSB): C3 D4 A1 B2.
|
||||||
|
|
||||||
Middle-endian small int: B2 A1 D4 C3
|
### Middle Endian Small Int
|
||||||
|
|
||||||
Where A1 is the smallest byte (LSB), and D4 the biggest byte (MSB).
|
The bytes are stored in the following order, where A1 is the smallest byte (I.e. LSB) and D4 the bigger (i.e. MSB): B2 A1 D4 C3.
|
||||||
|
|
||||||
== Bit Access ==
|
## Common data types
|
||||||
|
|
||||||
=== Initiating Bit Access ===
|
These data types are traditional, hence they can typically be written
|
||||||
|
and read by a standard DataStream, or Buffer implementation.
|
||||||
|
|
||||||
|
Naming conventions:
|
||||||
|
|
||||||
|
| Standardized name | Data-type name | Jagex name | Encoding |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Byte | byte | 1,1b | Bytes |
|
||||||
|
| [Word](./Word.md) | short | 2,2b | Bytes |
|
||||||
|
| [DWord](./DWord.md) | int, int32 | 2,2b | Bytes |
|
||||||
|
| [QWord](./QWord.md) | long, int64 | 8,8b | Bytes |
|
||||||
|
| C-style String | string, String, char*, char[] | str, strbyte | Text bytes followed by `\n` or the byte `10`. |
|
||||||
|
| Java-string String | string, String, char*, char[] | strraw | Length as a word, followed by the text bytes. |
|
||||||
|
|
||||||
|
Note: In more recent versions of the client, C-style strings are terminated with the null character (i.e. `\0`) or the byte `0` to support multi-line strings.
|
||||||
|
|
||||||
|
## Bespoke data types
|
||||||
|
|
||||||
|
These data types are bespoke, that is, they were developed with the
|
||||||
|
sole intention of only being used within Jagex products.
|
||||||
|
|
||||||
|
We presume that this is another technique employed to make
|
||||||
|
reverse-engineering and packet manipulation harder.
|
||||||
|
|
||||||
|
Naming conventions:
|
||||||
|
|
||||||
|
| Winterlove's name | Jagex name | Read transformation | Write transformation |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Special A | Unknown | value - 128 | value + 128 |
|
||||||
|
| Special C | Unknown | 0 - value | 0 - value |
|
||||||
|
| Special S | Unknown | 128 - value | 128 - value |
|
||||||
|
| SpaceSaverA | smarts | `(value[0] < 128) ? (((value[0] - 128) << 8) + value[1]) : value[0]` | `if(value < 128) putword(value+32768) else putbyte(value);` |
|
||||||
|
| SpaceSaverB | smart | `(value[0] << 24) + (value[1] << 16) + value[2] ` | `putbyte(value >> 24); putbyte(value >> 16); putbyte(value); ` |
|
||||||
|
| Tribyte, RGBColour, 3Byte, int3, medium | 3 | `(value[0] << 24) + (value[1] << 16) + value[2]` | `putbyte(value >> 24); putbyte(value >> 16); putbyte(value); ` |
|
||||||
|
| [RS String](./RS-String.md) | jstr | Old engine: read until newline terminated ("\n"). New engine: read until null byte (value 0). | Old engine: write and finish with newline delimiter ("\n"). New engine: write and finish with null byte (value 0). |
|
||||||
|
|
||||||
|
Note: The read transformation is the process which must be applied to
|
||||||
|
read data, to reconstruct the original.
|
||||||
|
The write transformation applies analogously, to when data is written.
|
||||||
|
|
||||||
|
## Bit Access
|
||||||
|
|
||||||
|
### Initiating Bit Access
|
||||||
|
|
||||||
Whenever data is to be sent to the server or to the client using bits;
|
Whenever data is to be sent to the server or to the client using bits;
|
||||||
the stream needs to be prepared by setting the bit position. The bit
|
the stream needs to be prepared by setting the bit position.
|
||||||
position can be calculated by multiplying the current buffer position by
|
The bit position can be calculated by multiplying the current buffer
|
||||||
8. This is because each byte is comprised of 8 bits.
|
position by 8. This is because each byte is comprised of 8 bits.
|
||||||
|
|
||||||
Example: int bitPos = bufferPos \* 8;
|
e.g. `int bitPos = bufferPos * 8;`
|
||||||
|
7
src/Data.md
Normal file
7
src/Data.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Data
|
||||||
|
|
||||||
|
This section covers the raw data-related facilities and systems within the Client.
|
||||||
|
|
||||||
|
This includes an overview of the [data-types](./Data-Types.md) used, as well as
|
||||||
|
protocols like [JAGGRAB Protocol](./JAGGRAB-Protocol.md) and
|
||||||
|
[Ondemand Protocol](./Ondemand-Protocol.md).
|
@ -16,9 +16,9 @@ A source of documentation for the RSC/RS2/RS3 protocols and related systems.
|
|||||||
* [[RS3|Category RS3]] (2013 - present)
|
* [[RS3|Category RS3]] (2013 - present)
|
||||||
|
|
||||||
### Cache
|
### Cache
|
||||||
* [[JAGGRAB|JAGGRAB Protocol]]
|
* [JAGGRAB protocol](./JAGGRAB-Protocol.html)
|
||||||
* [[Ondemand|Ondemand Protocol]]
|
* [Ondemand protocol](./Ondemand-Protocol.html)
|
||||||
* [[Archive Format]]
|
* [Archive format](./Archive-Format.html)
|
||||||
|
|
||||||
|
|
||||||
### Miscellaneous
|
### Miscellaneous
|
||||||
|
@ -1,48 +1,54 @@
|
|||||||
\[\[Category Cache\]\]
|
# JAGGGRAB protocol
|
||||||
|
|
||||||
== Introduction ==
|
# Introduction
|
||||||
|
|
||||||
The JAGGRAB protocol is used to 'grab' cache files from the file server
|
In the early days of the client, it was distributed as an embedded
|
||||||
and download them.
|
JAR within a web page.
|
||||||
|
So, reloading the web page would result in the user being served an up-to-date
|
||||||
|
client.
|
||||||
|
However, the cache files were stored locally and thus required a separate
|
||||||
|
mechanism for updating.
|
||||||
|
|
||||||
|
The JAGGRAB protocol addresses this by updating the client's cache files.
|
||||||
|
It does this by 'grabbing' cache files from the file server and downloading them.
|
||||||
|
|
||||||
It is a text-based protocol, similar to HTTP/0.9, and the client will
|
It is a text-based protocol, similar to HTTP/0.9, and the client will
|
||||||
fall back to HTTP if JAGGRAB is unavailable. This generally happens in
|
fall-back to HTTP if JAGGRAB is unavailable. This generally happens in
|
||||||
unsigned mode and helps users who are behind firewalls.
|
unsigned mode and helps users who are behind firewalls.
|
||||||
|
|
||||||
== Request format ==
|
## Request format
|
||||||
|
|
||||||
A request is simply the text JAGGRAB, a space, the path to the file and
|
A request is simply the text JAGGRAB, a space, the path to the file and
|
||||||
a newline character. Therefore, it is very similar to a HTTP/0.9 GET
|
a newline character. Therefore, it is very similar to a HTTP/0.9 GET
|
||||||
request.
|
request.
|
||||||
|
|
||||||
JAGGRAB /path/to/file
|
e.g. `JAGGRAB /path/to/file`.
|
||||||
|
|
||||||
=== New engine ===
|
Note: In possibly all new engine clients, the client prefixes the JAGGRAB
|
||||||
|
|
||||||
In (perhaps all) new engine clients, the client prefixes the JAGGRAB
|
|
||||||
request line with a single byte (value 17).
|
request line with a single byte (value 17).
|
||||||
|
|
||||||
== Response format ==
|
## Response format
|
||||||
|
|
||||||
The response is simply the raw file data. Once the response is sent, the
|
The response is the file bytes. Once the response is sent, the connection
|
||||||
connection is closed.
|
is closed.
|
||||||
|
|
||||||
== Files ==
|
## Files
|
||||||
|
|
||||||
There are a number of files which map to files in the cache.
|
There are a number of files which map to files in the cache.
|
||||||
|
|
||||||
- '''/crc''' - the CRC table
|
- `/crc` - the CRC table
|
||||||
- '''/title''' - cache 0, file 1
|
- `/title` - cache 0, file 1
|
||||||
- '''/config''' - cache 0, file 2
|
- `/config` - cache 0, file 2
|
||||||
- '''/interface''' - cache 0, file 3
|
- `/interface` - cache 0, file 3
|
||||||
- '''/media''' - cache 0, file 4
|
- `/media` - cache 0, file 4
|
||||||
- '''/versionlist''' - cache 0, file 5
|
- `/versionlist` - cache 0, file 5
|
||||||
- '''/textures''' - cache 0, file 6
|
- `/textures` - cache 0, file 6
|
||||||
- '''/wordenc''' - cache 0, file 7
|
- `/wordenc` - cache 0, file 7
|
||||||
- '''/sounds''' - cache 0, file 8
|
- `/sounds` - cache 0, file 8
|
||||||
|
|
||||||
NOTE: the client will usually postfix these with random numbers, so when
|
Note: the client will usually postfixes these with random numbers, so when
|
||||||
checking for the file only the start of the string should be examined:
|
checking for the file only the start of the string should be examined:
|
||||||
not the whole one. This is to help avoid caches when these files are
|
not the whole one.
|
||||||
fetched over HTTP.<BR> NOTE: The crc is postfixed with the client
|
This is to help avoid caches when these files are fetched over HTTP.
|
||||||
revision
|
|
||||||
|
Note: The crc is postfixed with the client revision.
|
||||||
|
42
src/OB3.md
42
src/OB3.md
@ -1,10 +1,17 @@
|
|||||||
\[\[Category RSC\]\]
|
# 0B3
|
||||||
|
|
||||||
This page refers to .ob3, a custom format for 3D models created by
|
This page documents the `.ob3` format, a bespoke format for 3D models
|
||||||
Jagex. It is used by the RuneScape Classic engine since client version
|
created by Jagex.
|
||||||
\#74. For the earlier version of the format see \[\[OB2\|OB2\]\].
|
It is used by the RuneScape Classic engine since client version
|
||||||
|
\#74.
|
||||||
|
|
||||||
<pre>public class OB3Model {
|
Note: There is also an earlier version of this format called `.ob2`.
|
||||||
|
|
||||||
|
## OB3 Model Class
|
||||||
|
The following is the fully renamed client code used to represent OB3 models.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class OB3Model {
|
||||||
|
|
||||||
private static final int num_seq = 0xbc614e; // 12345678
|
private static final int num_seq = 0xbc614e; // 12345678
|
||||||
public int vertex_count;
|
public int vertex_count;
|
||||||
@ -104,26 +111,29 @@ Jagex. It is used by the RuneScape Classic engine since client version
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</pre>
|
```
|
||||||
== '''Faces''' == A '''negative''' face\_fill\_back or face\_fill\_front
|
|
||||||
value indicates a '''solid colour''', whereas a'''positive''' value
|
|
||||||
indicates a '''texture'''. The texture is defined by its offset in the
|
|
||||||
client's texture array.
|
|
||||||
|
|
||||||
When converting to/from
|
## Faces
|
||||||
\[http://en.wikipedia.org/wiki/Wavefront\_.obj\_file Wavefront OBJ\]
|
|
||||||
|
A negative face_fill_back or face_fill_front value indicates a solid colour, whereas a positive value indicates a texture.
|
||||||
|
The texture is defined by its offset in the client's texture array.
|
||||||
|
|
||||||
|
When converting to/from [Wavefront OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
|
||||||
format, remember that the OB3 face vertices are one less than the OBJ
|
format, remember that the OB3 face vertices are one less than the OBJ
|
||||||
face vertices.
|
face vertices.
|
||||||
|
|
||||||
<pre>public static int decode_colour(int i) {
|
The below code will allow you to encode or decode colours in this format.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public static int decode_colour(int i) {
|
||||||
i = -(i + 1);
|
i = -(i + 1);
|
||||||
int r = i >> 10 & 0x1f;
|
int r = i >> 10 & 0x1f;
|
||||||
int g = i >> 5 & 0x1f;
|
int g = i >> 5 & 0x1f;
|
||||||
int b = i & 0x1f;
|
int b = i & 0x1f;
|
||||||
return (r << 19) + (g << 11) + (b << 3);
|
return (r << 19) + (g << 11) + (b << 3);
|
||||||
}
|
}
|
||||||
</pre>
|
|
||||||
<pre>public static int encode_colour(int r, int g, int b) {
|
public static int encode_colour(int r, int g, int b) {
|
||||||
return -1 - (r / 8) * 1024 - (g / 8) * 32 - b / 8;
|
return -1 - (r / 8) * 1024 - (g / 8) * 32 - b / 8;
|
||||||
}
|
}
|
||||||
</pre>
|
```
|
||||||
|
@ -1,28 +1,34 @@
|
|||||||
\[\[Category Cache\]\]
|
# Ondemand protocol
|
||||||
|
|
||||||
== Introduction ==
|
The Ondemand protocol is used to stream updates to the cache.
|
||||||
|
The client knows which files to update from the CRC file downloaded
|
||||||
|
using the [JAGGRAB Protocol](./JAGGRAB-Protocol.html).
|
||||||
|
|
||||||
The 'Ondemand' protocol is used to stream updates to the cache. The
|
## Request format
|
||||||
client knows which files to update from the CRC file downloaded using
|
|
||||||
the \[\[JAGGRAB Protocol\|JAGGRAB protocol\]\].
|
|
||||||
|
|
||||||
== Request packet ==
|
|
||||||
|
|
||||||
The client first authenticates as an ondemand client by using the opcode
|
The client first authenticates as an ondemand client by using the opcode
|
||||||
'15' (as opposed to the game, which uses the type '14').
|
'15' (as opposed to the game, which uses the type '14').
|
||||||
|
|
||||||
The format of the request is:
|
The format of the request is:
|
||||||
|
|
||||||
unsigned byte cacheId; unsigned short fileId; unsigned byte priority;
|
```
|
||||||
|
unsigned byte cacheId;
|
||||||
|
unsigned short fileId;
|
||||||
|
unsigned byte priority;
|
||||||
|
```
|
||||||
|
|
||||||
There can be multiple requests per session.
|
Furthermore, there can be multiple requests per session.
|
||||||
|
|
||||||
== Response packet ==
|
## Response format
|
||||||
|
|
||||||
The response is sent in blocks. The maximum size of a block is 500
|
The response is sent in blocks. The maximum size of a block is 500
|
||||||
bytes. Smaller blocks (at the end of a file) are permitted.
|
bytes. Smaller blocks (e.g. towards the end of a file) are permitted.
|
||||||
|
|
||||||
Each block has the format:
|
The format of a block is:
|
||||||
|
```
|
||||||
unsigned byte cacheId; unsigned short fileId; unsigned short fileSize;
|
unsigned byte cacheId;
|
||||||
unsigned byte blockNumber; unsigned byte\[\] blockData;
|
unsigned short fileId;
|
||||||
|
unsigned short fileSize;
|
||||||
|
unsigned byte blockNumber;
|
||||||
|
unsigned byte[] blockData;
|
||||||
|
```
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
A "QWord" (quad-word) is a data-type that consists of 8 bytes.<br /> It
|
# QWord
|
||||||
is also commonly known as the "long" data-type in programming.
|
|
||||||
\[\[Category Data Type\]\]
|
A "QWord" (quad-word) is a data-type that consists of 8 bytes.
|
||||||
|
It is also commonly known as the "long" data-type in programming.
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
== Introduction ==
|
# RS String
|
||||||
|
|
||||||
RS String is a codename for a custom string data-type used in the
|
RS String is the internal name for a custom string data-type used in the
|
||||||
RuneScape protocol. <br /> The string data-type is used to hold a series
|
RuneScape protocol.
|
||||||
of characters in order to form a message.
|
The string data-type stores a collection of characters in order to
|
||||||
|
represent a textual message.
|
||||||
|
|
||||||
===Old Engine Protocol=== In the old engine client, the RS String
|
## Old Engine
|
||||||
datatype is delimited by a newline character (value "\n").
|
|
||||||
|
|
||||||
===New Engine Protocol=== In the new-engine client, the RS String
|
In the old engine client, the RS String datatype is terminated by the new line
|
||||||
datatype is delimited by a null byte (value 0).
|
character (i.e. `\n`).
|
||||||
|
|
||||||
|
# New Engine
|
||||||
|
|
||||||
|
In the new-engine client, the RS String datatype is terminated by a null byte (i.e. `0`).
|
||||||
|
@ -7,18 +7,20 @@
|
|||||||
- [General disclaimer](./General-disclaimer.md)
|
- [General disclaimer](./General-disclaimer.md)
|
||||||
- [DMCA policy](./DMCA-policy.md)
|
- [DMCA policy](./DMCA-policy.md)
|
||||||
- [Privacy policy](./Privacy-policy.md)
|
- [Privacy policy](./Privacy-policy.md)
|
||||||
- [Archive-Format](./Archive-Format.md)
|
- [Data](./Data.md)
|
||||||
|
- [Data-Types](./Data-Types.md)
|
||||||
|
- [Word](./Word.md)
|
||||||
|
- [DWord](./DWord.md)
|
||||||
|
- [QWord](./QWord.md)
|
||||||
|
- [RS String](./RS-String.md)
|
||||||
|
- [JAGGRAB protocol](./JAGGRAB-Protocol.md)
|
||||||
|
- [Ondemand protocol](./Ondemand-Protocol.md)
|
||||||
|
- [Archive format](./Archive-Format.md)
|
||||||
|
- [OB3](./OB3.md)
|
||||||
- [Class-Check](./Class-Check.md)
|
- [Class-Check](./Class-Check.md)
|
||||||
- [Data-Types](./Data-Types.md)
|
|
||||||
- [DWord](./DWord.md)
|
|
||||||
- [JAGGRAB-Protocol](./JAGGRAB-Protocol.md)
|
|
||||||
- [Map-Region-System](./Map-Region-System.md)
|
- [Map-Region-System](./Map-Region-System.md)
|
||||||
- [OB3](./OB3.md)
|
|
||||||
- [Ondemand-Protocol](./Ondemand-Protocol.md)
|
|
||||||
- [QWord](./QWord.md)
|
|
||||||
- [RS-String](./RS-String.md)
|
- [RS-String](./RS-String.md)
|
||||||
- [Template-Packet](./Template-Packet.md)
|
- [Template-Packet](./Template-Packet.md)
|
||||||
- [Word](./Word.md)
|
|
||||||
- [135-Protocol](./135-Protocol.md)
|
- [135-Protocol](./135-Protocol.md)
|
||||||
- [194-Clear-screen](./194-Clear-screen.md)
|
- [194-Clear-screen](./194-Clear-screen.md)
|
||||||
- [194-Logout](./194-Logout.md)
|
- [194-Logout](./194-Logout.md)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
A "word" is a data-type that consists of 2 bytes. <br /> It is also
|
# Word
|
||||||
commonly known as the "short" data-type in programming. \[\[Category
|
|
||||||
Data Type\]\]
|
A "word" is a data-type that consists of 2 bytes.
|
||||||
|
It is also commonly known as the "short" data-type in programming.
|
||||||
|
Loading…
Reference in New Issue
Block a user