mirror of
https://github.com/moparisthebest/rswiki-book
synced 2024-11-21 08:35:00 -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
|
||||
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).
|
||||
## Usage
|
||||
|
||||
=== 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
|
||||
Image\]
|
||||
e.g. `DATA` contains data for interfaces.
|
||||
|
||||
== 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
|
||||
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
|
||||
|
||||
== Format ==
|
||||
|
||||
tribyte uncompressedsize tribyte compressedsize
|
||||
```
|
||||
tribyte uncompressedSize
|
||||
tribyte compressedSize
|
||||
```
|
||||
|
||||
If the uncompressed and compressed sizes are equal, the whole file is
|
||||
not compressed but the individual entries are compressed using bzip2. If
|
||||
they are not equal, the entire file is compressed using bzip2 but the
|
||||
individual entries are not.
|
||||
not compressed but the individual entries are compressed using bzip2.
|
||||
If they are not equal, the entire file is compressed using bzip2 but
|
||||
the individual entries are not.
|
||||
|
||||
Also note, the magic id at the start of the bzip2 entries are not
|
||||
included in the cache. If you use an existing API to read the files and
|
||||
want to add this back, you must append the four characters: BZh1 before
|
||||
you decompress.
|
||||
Note: The magic id at the start of the bzip2 entries are not included
|
||||
in the cache.
|
||||
If you use an existing API to read the files and want to add this back,
|
||||
you must append the characters `BZh1` before you decompress.
|
||||
|
||||
short fileCount
|
||||
```short fileCount```
|
||||
|
||||
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
|
||||
file offset yourself. This psuedocode demonstrates how:
|
||||
# Extracting the data
|
||||
|
||||
int offset = buffer.getCurrentOffset() + numFiles \* 10; for(int i = 0;
|
||||
i \< numFiles; i++) { // read values int thisFileOffset = offset; offset
|
||||
+= thisFileCompressedSize; }
|
||||
If you iterate over the files using a for-loop, you need to keep track of the
|
||||
file offset.
|
||||
The following pseudo-code demonstates how:
|
||||
|
||||
To get a named file by its name, you should first hash the name using
|
||||
this method:
|
||||
```java
|
||||
int offset = buffer.getCurrentOffset() + numFiles * 10;
|
||||
|
||||
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; }
|
||||
for(int i = 0; i < numFiles; i++) {
|
||||
// read values
|
||||
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
|
||||
matching hash. Read the compressed file size from the offset. If the
|
||||
whole file is not compressed, you should decompress the individual
|
||||
entry.
|
||||
|
||||
== '''\#194 Archive Format''' ==
|
||||
## \#194 Archive Format
|
||||
|
||||
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.
|
||||
The \#194 (RuneScape 2 beta) client worked with a very simple cache
|
||||
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,
|
||||
incidentally, similar to the way player names are converted to longs.
|
||||
|
||||
public static final long gethash(String string) { string =
|
||||
string.trim(); long l = 0L; 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; }
|
||||
```java
|
||||
public static final long gethash(String string) {
|
||||
string = string.trim();
|
||||
long l = 0L;
|
||||
|
||||
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
|
||||
name.
|
||||
|
||||
=== Files ===
|
||||
### Files
|
||||
|
||||
The files in the cache were the ones used in the \[\[JAGGRAB
|
||||
Protocol\|JAGGRAB Protocol\]\] (i.e. files in cache 0 in old engine
|
||||
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.
|
||||
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),
|
||||
map (mX_Y), and landscape (lX_Y) files.
|
||||
|
||||
== '''\#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.
|
||||
|
||||
=== Data file ===
|
||||
### Data file
|
||||
|
||||
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
|
||||
megabytes..
|
||||
`main_file_cache.dat`.
|
||||
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
|
||||
then postfixed with a number. Each index file holds 'pointers' to where
|
||||
a file is located in the main cache. Each index file represents a type
|
||||
of file.
|
||||
There are several index files, named `main_file_cache.idx` and
|
||||
then post-fixed with a number.
|
||||
Each index file holds 'pointers' to where a file is located in
|
||||
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
|
||||
where a file can be located in the data file. The format of a single
|
||||
block is as follows:
|
||||
The index file is comprised of a collection of six byte blocks which hold
|
||||
information about where a file can be located in the data file.
|
||||
|
||||
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
|
||||
blocks is as follows:
|
||||
The data file is comprised of a collection of 520 byte blocks.
|
||||
|
||||
short nextFileId short currentFilePartId tribyte nextDataBlockId byte
|
||||
nextFileTypeId byte\[512\] blockData
|
||||
The format of each of these blocks is as follows:
|
||||
|
||||
=== 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
|
||||
index 17 \* 6 (102). It will then read two tribytes.
|
||||
First off, it will open the `main_file_cache.idx2` file and seek to the
|
||||
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
|
||||
index 4 \* 520 (2080). The values it reads will be:
|
||||
|
||||
nextFileId = 17 currentFilePartId = 0 nextDataBlockId = 5 nextFileTypeId
|
||||
= 2 blockData = ...
|
||||
It will then read the following:
|
||||
```
|
||||
nextFileId = 17
|
||||
currentFilePartId = 0
|
||||
nextDataBlockId = 5
|
||||
nextFileTypeId = 2
|
||||
blockData = ... // 512 bytes of data
|
||||
```
|
||||
|
||||
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
|
||||
= 2 blockData ...
|
||||
Therefore, it has to read the next block:
|
||||
```
|
||||
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
|
||||
176 bytes left. So for a final time, it will read the next block.
|
||||
176 bytes left.
|
||||
|
||||
nextFileId = 18 currentFilePartId = 2 nextDataBlockId = 7 nextFileTypeId
|
||||
= 2 blockData = ...
|
||||
So for a final time, it will read the next block:
|
||||
```
|
||||
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
|
||||
this stage) and read the final 176 bytes. The whole 1200 byte file has
|
||||
now been read.
|
||||
this stage) and read the final 176 bytes.
|
||||
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.
|
||||
\[\[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
|
||||
variety of different ways. Generally people either use big endian or
|
||||
little endian.
|
||||
variety of different ways.
|
||||
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
|
||||
the least significant byte (LSB) is stored last.
|
||||
|
||||
=== Little Endian ===
|
||||
### Little Endian
|
||||
|
||||
In little endian order, the least significant byte (LSB) is stored first
|
||||
and the most significant byte (MSB) is stored last.
|
||||
|
||||
=== Byte order in RuneScape ===
|
||||
|
||||
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). \|}
|
||||
## Bespoke Byte Orders
|
||||
|
||||
Additionally, RuneScape also uses two endian orders for integers that
|
||||
are different from a big- or low endian order. Both byte orders are
|
||||
called middle-endian.
|
||||
are different from a big- or low endian order.
|
||||
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;
|
||||
the stream needs to be prepared by setting the bit position. The bit
|
||||
position can be calculated by multiplying the current buffer position by
|
||||
8. This is because each byte is comprised of 8 bits.
|
||||
the stream needs to be prepared by setting the bit position.
|
||||
The bit position can be calculated by multiplying the current buffer
|
||||
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)
|
||||
|
||||
### Cache
|
||||
* [[JAGGRAB|JAGGRAB Protocol]]
|
||||
* [[Ondemand|Ondemand Protocol]]
|
||||
* [[Archive Format]]
|
||||
* [JAGGRAB protocol](./JAGGRAB-Protocol.html)
|
||||
* [Ondemand protocol](./Ondemand-Protocol.html)
|
||||
* [Archive format](./Archive-Format.html)
|
||||
|
||||
|
||||
### Miscellaneous
|
||||
|
@ -1,48 +1,54 @@
|
||||
\[\[Category Cache\]\]
|
||||
# JAGGGRAB protocol
|
||||
|
||||
== Introduction ==
|
||||
# Introduction
|
||||
|
||||
The JAGGRAB protocol is used to 'grab' cache files from the file server
|
||||
and download them.
|
||||
In the early days of the client, it was distributed as an embedded
|
||||
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
|
||||
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.
|
||||
|
||||
== Request format ==
|
||||
## Request format
|
||||
|
||||
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
|
||||
request.
|
||||
|
||||
JAGGRAB /path/to/file
|
||||
e.g. `JAGGRAB /path/to/file`.
|
||||
|
||||
=== New engine ===
|
||||
|
||||
In (perhaps all) new engine clients, the client prefixes the JAGGRAB
|
||||
Note: In possibly all new engine clients, the client prefixes the JAGGRAB
|
||||
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
|
||||
connection is closed.
|
||||
The response is the file bytes. Once the response is sent, the connection
|
||||
is closed.
|
||||
|
||||
== Files ==
|
||||
## Files
|
||||
|
||||
There are a number of files which map to files in the cache.
|
||||
|
||||
- '''/crc''' - the CRC table
|
||||
- '''/title''' - cache 0, file 1
|
||||
- '''/config''' - cache 0, file 2
|
||||
- '''/interface''' - cache 0, file 3
|
||||
- '''/media''' - cache 0, file 4
|
||||
- '''/versionlist''' - cache 0, file 5
|
||||
- '''/textures''' - cache 0, file 6
|
||||
- '''/wordenc''' - cache 0, file 7
|
||||
- '''/sounds''' - cache 0, file 8
|
||||
- `/crc` - the CRC table
|
||||
- `/title` - cache 0, file 1
|
||||
- `/config` - cache 0, file 2
|
||||
- `/interface` - cache 0, file 3
|
||||
- `/media` - cache 0, file 4
|
||||
- `/versionlist` - cache 0, file 5
|
||||
- `/textures` - cache 0, file 6
|
||||
- `/wordenc` - cache 0, file 7
|
||||
- `/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:
|
||||
not the whole one. This is to help avoid caches when these files are
|
||||
fetched over HTTP.<BR> NOTE: The crc is postfixed with the client
|
||||
revision
|
||||
not the whole one.
|
||||
This is to help avoid caches when these files are fetched over HTTP.
|
||||
|
||||
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
|
||||
Jagex. It is used by the RuneScape Classic engine since client version
|
||||
\#74. For the earlier version of the format see \[\[OB2\|OB2\]\].
|
||||
This page documents the `.ob3` format, a bespoke format for 3D models
|
||||
created by Jagex.
|
||||
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
|
||||
public int vertex_count;
|
||||
@ -104,26 +111,29 @@ Jagex. It is used by the RuneScape Classic engine since client version
|
||||
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
|
||||
\[http://en.wikipedia.org/wiki/Wavefront\_.obj\_file Wavefront OBJ\]
|
||||
## 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 [Wavefront OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
|
||||
format, remember that the OB3 face vertices are one less than the OBJ
|
||||
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);
|
||||
int r = i >> 10 & 0x1f;
|
||||
int g = i >> 5 & 0x1f;
|
||||
int b = i & 0x1f;
|
||||
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;
|
||||
}
|
||||
</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
|
||||
client knows which files to update from the CRC file downloaded using
|
||||
the \[\[JAGGRAB Protocol\|JAGGRAB protocol\]\].
|
||||
|
||||
== Request packet ==
|
||||
## Request format
|
||||
|
||||
The client first authenticates as an ondemand client by using the opcode
|
||||
'15' (as opposed to the game, which uses the type '14').
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
unsigned byte cacheId; unsigned short fileId; unsigned short fileSize;
|
||||
unsigned byte blockNumber; unsigned byte\[\] blockData;
|
||||
The format of a block is:
|
||||
```
|
||||
unsigned byte cacheId;
|
||||
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
|
||||
is also commonly known as the "long" data-type in programming.
|
||||
\[\[Category Data Type\]\]
|
||||
# QWord
|
||||
|
||||
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
|
||||
RuneScape protocol. <br /> The string data-type is used to hold a series
|
||||
of characters in order to form a message.
|
||||
RS String is the internal name for a custom string data-type used in the
|
||||
RuneScape protocol.
|
||||
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
|
||||
datatype is delimited by a newline character (value "\n").
|
||||
## Old Engine
|
||||
|
||||
===New Engine Protocol=== In the new-engine client, the RS String
|
||||
datatype is delimited by a null byte (value 0).
|
||||
In the old engine client, the RS String datatype is terminated by the new line
|
||||
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)
|
||||
- [DMCA policy](./DMCA-policy.md)
|
||||
- [Privacy policy](./Privacy-policy.md)
|
||||
- [Archive-Format](./Archive-Format.md)
|
||||
- [Class-Check](./Class-Check.md)
|
||||
- [Data](./Data.md)
|
||||
- [Data-Types](./Data-Types.md)
|
||||
- [Word](./Word.md)
|
||||
- [DWord](./DWord.md)
|
||||
- [JAGGRAB-Protocol](./JAGGRAB-Protocol.md)
|
||||
- [Map-Region-System](./Map-Region-System.md)
|
||||
- [OB3](./OB3.md)
|
||||
- [Ondemand-Protocol](./Ondemand-Protocol.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)
|
||||
- [Map-Region-System](./Map-Region-System.md)
|
||||
- [RS-String](./RS-String.md)
|
||||
- [Template-Packet](./Template-Packet.md)
|
||||
- [Word](./Word.md)
|
||||
- [135-Protocol](./135-Protocol.md)
|
||||
- [194-Clear-screen](./194-Clear-screen.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
|
||||
commonly known as the "short" data-type in programming. \[\[Category
|
||||
Data Type\]\]
|
||||
# Word
|
||||
|
||||
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