Coypright (C) 2007 Belgabor (document), some rights reserved (see below). The file format itself has probably been designed by Frontier, so cannot and do not claim Copyright for it :-).
This document explains what I found out about the file format Frontier
used for most files that are not OVL
s, which includes
for example park files, track files and firework effects. These files all
follow basically the same scheme and come in three versions. The files that
use the respective versions have led me to suspect that the three versions
were introduced in original RCT3, Soaked! and Wild! respectively, although
I'm not fully sure about the timing of v2 and v3 as many Soaked! files have
are v3.
The first version (v1) has only two sections (Section 2, “The Variable Declaration”, Section 3, “The Data”), the header (Section 1, “The Header”) is missing. Version 2 and 3 have three sections. The versions do not match to any specific file type, for example the game has particle effects of all three versions.
All structures will be shown in C-ish pseudocode.
As written above the header is only present in v2 and v3 files. It consists of a first part that is present in both versions and a second part that's only present in v3 files.
typedef struct { uint8 nullbytes[8]; // Always 0x00 uint8 formatbyte; // 0x1F for v2 and 0x2F for v3 uint8 alwaysDA; // Always 0xDA uint8 always1E; // Always 0x1E uint8 alwaysF1; // Always 0xF1 uint32 parameters[13]; // Unknown purpose. Some seem to relate to the file coming from Soaked! or Wild! } Header1;
typedef struct { uint32 unknown; // 0x00000000 for park-ish files (parks, most scenarios and tutorials), 0xFFFFFFFF for other files uint32 ffbytes; // Always 0xFFFFFFFF uint8 nullbytes[8]; // Always 0x00 } Header2;
As the difference between a full v2 and a full v3 header are 16
(0x10) bytes, it's highly probable that
Header1.formatbyte
is an offset or length of some
kind.
This section describes the classes and structures the data part (Section 3, “The Data”) can use. Version 1 and 2 files seem to declare almost everything RCT3 can use (although the amount is not consistant). On the other hand v3 files seem to only declare what's necessary for the file type at hand.
All strings in this section are AscII long pascal style strings, essentially described by this declaration:
typedef struct { uint16 charactercount; char content[charactercount]; } DeclarationString;
To emphasize, they are not 0-terminated!
Here is how this section looks like:
uint32 classdeclarationcount; ClassDeclaration classdec[classdeclarationcount];
Here's how a ClassDeclaration
looks like:
typedef struct { DeclarationString classname; uint32 variablecount; VariableDeclaration variable[variablecount]; } ClassDeclaration;
And finally VariableDeclaration
:
typedef struct { DeclarationString variablename; DeclarationString datatypename; uint32 datatypesize; // Size of the data type in bytes uint32 subvariablecount; // Number of subvariables for some data types VariableDeclaration subvariable[subvariablecount]; } VariableDeclaration;
The datatypesize
parameter is a numerical
representation of the data type named in datatypename
.
A 0 seems to indicate a data type of variable size. Here is a list of data
types I found so far:
datatypename | datatypesize | Comment |
---|---|---|
array | 0 | Has 1+ subvariables. Seems to imply a variable amount of struct |
bool | 1 | |
graphedValue | 0 | Seems to indicate graphed coaster test data |
float32 | 4 | |
int32 | 4 | |
list | 0 | Has subvariable(s? so far only seen one). No idea what makes it different from array. |
managedobjectptr | 8 | see reference |
orientation | 12 | |
reference | 8 | In-file reference to a class data block
(ClassDataHeader.refmarker ) |
string | 0 | Strings in the data section are utf16 encoded |
struct | sum of subvariables | Has 1+ subvariables. datatypesize is 0
if any subvariables are of varible size. |
uint8 | 1 | |
vector3 | 12 |
The data section seems to be nearly identical among versions. It is separated in to class blocks and starts with the number of these blocks:
uint32 classdatablockcount;
Followed by the class data blocks themselves. Each class block starts with a header:
typedef struct { uint32 classid; // Identifies which class declaration applies (classdec[classid]) char refmarker[8]; // Used for in-file references. } ClassDataHeader;
The header is followed by the actual data as described in the class' declaration.
All data is represented as a raw little endian data type of the respective length with the following exceptions (incomplete):
array | typedef struct { uint32 arraylength; // in bytes. Includes the 4 bytes of the itemcount uint32 itemcount; // number of items in the array ArrayItem item[itemcount]; // ArrayItem as defined in the declaration section } ArrayData; An empty array has
|
managedobjectptr, reference | typedef struct { char reference[8]; // references a class data block by it's ClassDataHeader.refmarker } ReferenceData; Can in some cases be read as a 0-terminated string, but not always. |
string | typedef struct { uint32 stringlength; // in bytes. Start marker is included. uint8 startmarker[4]; // All 0xEF wchar content[(stringlength-4)/2]; // UTF16, little endian } StringData; An empty string has
|
struct | typedef struct { uint32 structlength; // in bytes. Full size of the content uint8 content[structlength]; // Data as defined as subvariables in the declaration section } StructData; |
After the data, there is a last value in v2 and v3 files:
uint32 unknownend;
The exact purpose is unknown purpose, maybe some kind of checksum. It is too big to indicate a size inside the file.
This work is licensed under a Creative
Commons Attribution-NonCommercial-NoDerivs 3.0 License.
The DocBook CSS used for the HTML version of this document is based upon the one created by Chris Karakas.
This CSS stylesheet uses QBullets in links. Thanks to Matterform Media for providing QBullets for free. If you plan to use them on your website, please observe the QBullets usage terms.