Add data section + rewrite them

This commit is contained in:
PureCS 2018-07-03 05:59:44 -07:00
parent 769bdac9bf
commit 2f7502f346
12 changed files with 348 additions and 238 deletions

View File

@ -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.

View File

@ -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\]\]

View File

@ -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
View 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).

View File

@ -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

View File

@ -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.

View File

@ -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>
```

View File

@ -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;
```

View File

@ -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.

View File

@ -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`).

View File

@ -7,18 +7,20 @@
- [General disclaimer](./General-disclaimer.md)
- [DMCA policy](./DMCA-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)
- [Data-Types](./Data-Types.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)
- [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)

View File

@ -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.