raP File Format - Elite: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
(Relased to public ridicule)
m (Text replacement - ";[ ]+ " to "; ")
 
(54 intermediate revisions by 12 users not shown)
Line 1: Line 1:
==Caveat==
{{Feature|UnsupportedDoc}}
== Caveat ==


If you are researching the nitty gritty of raP encoding for [[raP File Format - OFP|OFP]] or [[raP File Format - ArmA]] you are in the wrong place. This document is specifically for Elite raPified files on the Xbox. However, if you are not too familiar with this subject, the Introduction in the [[raP File Format - OFP|OFP]] version will help you best.
If you are researching the nitty gritty of raP encoding for [[raP File Format - OFP|OFP]] you are in the wrong place. This document is specifically for Elite/Arma1 & 2 raPified files on the Xbox and beyond. However, if you are not too familiar with this subject, the Introduction in the [[raP File Format - OFP|OFP]] version will help you best.


==Changes for Elite==


#Two new entry types
== Changes from OFP ==
 
*Two new entry types


  /*extern*/ class thing;
  /*extern*/ class thing;
  /*extern*/ class thing;
  delete /*class*/ thing;


#enhanceed TokenName
*Enhanced TokenName


name= true _variable (as opposed to name="variable";)
name= RealVariable (as opposed to name="variable";) Xbox mission.par's only


Serious alterations to non-contiguous data stream. The data for class bodies is now located in a flle offset, as opposed to being directly after the class name.
*Non contiguous data file
non-contiguous data stream. Class '''bodies''' are now located 'arbitrarily' in a file offset, as opposed to being directly after the class name.
*a rarely used sha/md5
== Changes at Arma ==
*Enhanced token is not used.
*sha/md5 is not used


==Introduction==
== Introduction ==
<big>raP encoding for Xbox Files</big>
<big>raP encoding for Xbox Files</big>


===Conventions===
=== Conventions ===
asciiz: a zero terminated ascii string.
see [[Generic FileFormat Data Types]]
byte:  obvious.
 
ushort: unsigned 2 bytes Intel Order (lsb first)
=== Mandatory PreReading ===
float:  4 bytes. as in '''not''' a double
 
long:  4 bytes
==== The Human ====
BisShort: 1, or 2 bytes see below


===Mandatory PreReading===
[[BI]] use c++ class syntax to package data for almost everything. Anything configurable / alterable / makeable / editable by a player (author) involves creating a file or files consisting of class statements. The Mission Editor eg, creates several files for a mission  consisting solely of class statements. Everything is defined or declared within classes. There is no specific file extension that is or is not a rap file. an rvmat or mission.sqm can, as equally be humanly readable text, or, binarised rap. '''Any''' text file that contains class statements, is, by definition, a rapifiable file. This includes bisurf, fsm, cpp, (model).cfg, BI's world revolves around the engine's ability to work with data contained in (a series of) class {bodies}. So much so, that at run time, a file that is in humanly readable text, is automatically converted to rap binary. The engine never sees 'text'. This also applies to description.ext and some other files that cannot be SAVED as rap binary, but are, most definately, rapified by the engine before use.


====The Human====
Class anything ultimately means raP binary


Bis use c++ class syntax for almost everything connected with text (humanly readable) files. Anything configurable / alterable / makeable / editable by a player (author) involves creating a file or files consisting of class statements. The Mission Editor eg, creates several files for a mission  consisting solely of class statements. Everything is defined or declared within classes. EVEN the cfg (configuration files) have implied class statements.


Class syntax can briefly (but accurately) be described as follows:  
Class syntax can briefly (but accurately) be described as follows:  
Line 40: Line 45:
  };
  };


[:InheritedClass] is optional. It is <u>heavily</u> used in the config.cpp's of addons.
[: InheritedClass] is optional. It is <u>heavily</u> used in the config.cpp's of addons. If specified it '''must''' be referenced prior to being used.


The '''body''' of a class consists of  
The '''body''' of a class consists of  
Line 50: Line 55:
  };
  };


Any given file that contains classes, contains nothing else but classes. There aren't, classes, and ummm, err, ummm 'other' things.  
Any given file that contains classes, contains nothing else but classes. There are not, classes, and ummm, err, ummm 'other' things.  


'''The file itself is considered an implied class!'''  
'''The file itself is considered an implied class!'''  
Line 60: Line 65:
Everything within that file is embedded within the class filename {....};
Everything within that file is embedded within the class filename {....};


====The Engine====
==== The Engine ====


The class structure is used internally within the engine for all most game data and configuration. The engine holds this data in tokenised form for more efficient processing.
The class structure is used internally within the engine for all most game data and configuration. The engine holds this data in tokenised form for more efficient processing.
Line 66: Line 71:
This internal tokenised data can also be held in a file (a savegame eg). But, it is a class structure regardless.
This internal tokenised data can also be held in a file (a savegame eg). But, it is a class structure regardless.


To improve loading speed many files within the ofp tree are pre-tokenised. They were 'converted' to hold the tokenised form of the same class statements.
To improve loading speed many files within the {{ofp}} tree are pre-tokenised. They were 'converted' to hold the tokenised form of the same class statements.


In fact, the engine does not care which 'type' of file it is dealing with. A mission.sqm can be either. If it hasn't been pre-tokenised (eg contains text-readable class statements) the engine converts it on the fly.
In fact, the engine does not care which 'type' of file it is dealing with. A mission.sqm can be either. If it has not been pre-tokenised (eg contains text-readable class statements) the engine converts it on the fly.


Tokenised files have a magic signature as their first four bytes. "\0raP". The file extension is meaningless in this regard.
Tokenised files have a magic signature as their first four bytes. "\0raP". The file extension is meaningless in this regard.
Line 76: Line 81:
Various utilities (tools) arrived on the internet in an attempt to decode them (and conversely, encode them). cpp2bin, bin2cpp, Coc binview are the most well known of these.
Various utilities (tools) arrived on the internet in an attempt to decode them (and conversely, encode them). cpp2bin, bin2cpp, Coc binview are the most well known of these.


They are detaile here as 'raP' files because of their unique signature. This document refers to rapifying and de-rapifying files containing nothing but, class statements.
They are detailed here as 'raP' files because of their unique signature. This document refers to rapifying and de-rapifying files containing nothing but, class statements.


==Xbox==
== Xbox/Arma ==


Xbox raP encoding is an extension to Flashpoint PC raP encoding.
raP encoding is an extension to Flashpoint PC raP encoding.


==Overall Structure==
== Overall Structure ==
struct raP
{
  char  Signature[4];              // 4 byte raP signature (\0raP)
  byte  AuthenticationSignature[20] // XBOX ONLY NOT ARMA
  ulong  Always0;
  ulong  Always8;
  ulong  OffsetToEnums;
  ClassBody  ClassBody;              // one and one only, within which, will be more class bodies
  Enums
  {
  ulong  nEnums;  // generally always 0
  enumlist....    // optional
  };
};


4 byte raP signature (00 r a P)
''' All offsets are relative to start of file'''
20 byte Authentication Signature [not on all types of file]
=== Authentication Signature ===
8 Byte Standard Field
4 byte File Offset to #defines
...(Implied class) Body
#defines (optional)


===Authentication Signature===
Unique to Xbox, not known on ArmA.
 
Currently unique to Xbox, not known on ArmA.


Following the four byte signature "\0 r a P" is an ''optional'' 20 byte signature intended to provide a unique value to this file and to prevent tampering. This value, or 'Authentication signature' is generated from a common 'Authentication Key' plus the content of the file itself. The Authentication key for Xbox Elite is 16 bytes and not listed here.
Following the four byte signature "\0 r a P" is an ''optional'' 20 byte signature intended to provide a unique value to this file and to prevent tampering. This value, or 'Authentication signature' is generated from a common 'Authentication Key' plus the content of the file itself. The Authentication key for Xbox Elite is 16 bytes and not listed here.
Line 101: Line 116:
The signature is 'optional' '''only''' in the sense that not all types of files have it. A signature appears in '''.par''' files for example, but not in the official bis mission.sqms.
The signature is 'optional' '''only''' in the sense that not all types of files have it. A signature appears in '''.par''' files for example, but not in the official bis mission.sqms.


===8 Byte Standard Field===
=== File Offset to Enumerated list ===
The following 8 bytes appear after the Authentication Signature (or immediately after the rap signature where an Authentication Signature doesn't exist).
 
00 00 00 00 08 00 00 00
 
This is a constant, throughout all Bis raP encoded files. Purpose unknown.


===File Offset to #defines===
the offset points to points to the end of All class data and consequently the start of an enum list (if any).
a 4 byte intel long stating the file offset (from beginning of file) to the #define enumerated list (if any). Also implies location of end of all class entries and bodies. It is non-optional. If no #defines exist, it points to end of the class area.


==CLASSES==
There may well be, no enumerated list, there '''will''' be a ListCount saying so!
The first entry in a rap file is an implied class body. It is implied, because the name of the file, '''is''' the class to which this body belongs.
=== ClassBody ===
===ClassBody===
  ClassBody
  struct ClassBody
  {
  {
    Asciiz InheritedClassname; // can be zero
  Asciiz               InheritedClassname; // can be zero
    BisShort  nEntries;       // can be zero. (See below for definition of a bis short)
  [[#CompressedInteger]]  nEntries;           // can be zero.
        Entry1
  ClassEntry          ClassEntries[nEntries];
        .....
        EntryN
    ulong    AddressofNextClass;
  };
  };


There cannot be an inherited classname for the first class body, and nEntries cannot (obviously) be zero.
ClassBodies contain zero or more 'entries'. These 'entries' consist of strings, arrays, classes, etc. The 1st byte of each entry defines what 'type' of entry it is.


===AddressofNextClass===
Note that ALL classes other than the first class body above are EMBEDDED classes within this one.
This offset is used by the engine to more rapidly iterate trhu a collection of items to the Nth item in the class.


This long value refers to the location of the next class at the same indent level  or, the next outer level when no more exist at this level. Where no more classes exist at all, it will point to the #define area.
Furthermore, this unique class cannot have an inheritance (obviously), and their is no classname associated with it. In OFP raP the classname of this unique class was, the name of the file (config.cpp eg)
 
'''All offsets in raP are relative to the start of file.'''


===Bis_Short===


the value is either one, or two bytes.
== ClassEntries ==
{
int val;
  val = GetByte();
  if (val & 0x80)
  {
  int extra = GetByte();
  val += (extra - 1) * 0x80;
  }
  return val;
}


The bis short is used to declare the number of entries in the class body or nArrays
{| class="wikitable" border="0"
!align="left"|Type
!align="left"|ID
!align="left"|SubID
!align="left"|Asciiz Name
!align="left"|Value
!align="left"|Example
|-
|align="left"|class||0||-||classname||4byte OffsetToBody||class thing{...};
|-
|align="left"|string||1||0||name=||Asciiz string||thing="hello";
|-
|align="left"|float||1||1||name=||4byte float||thing=0.123;
|-
|align="left"|long||1||2||name=||4byte long||thing=123;
|-
|align="left"|Array||2||-||name[]=||{nElements Elements[nElements]}||thing[]={1,0.2,"three",{4,5,6},{"seven"}};
|-
|align="left"|extern||3||-||classname||-||class thing;
|-
|align="left"|delete||4||-||classname||-||delete thing;
|-
|align="left"|Array with flag||5||-||name[]+=||4 bytes of flag followed by {nElements Elements[nElements]}||thing[]+={1,0.2,"three",{4,5,6},{"seven"}};
|-
|-
|}


==ClassBody Entries==
== Entry Types ==


content consists of zero or more 'entries' Entries have self defining lengths according to their type. There are '''five''' types of entry possible. Two of them newly introduced to Elite.
  0 Embedded Class
 
  1 value = (string, float, integer, variable)
  0 (Asciiz-EmbeddedClassName} {4 Byte offset to class body}
  1 value = (string, float, integer,variable)
  2 array[]={....};
  2 array[]={....};
  3 extern class label;
  3 /*extern*/ class label;
  4 extern class label;
  4 delete /*class*/ label;


===EntryType 0: Emedded Class===
=== EntryType 0: RapClass ===


{0}{Asciiz-ClassName} {4 Byte offset to class body}
  RapClass
 
The offset is the location of the content for this classname. By implication, any class entry is an embedded entry to the class it is in. Thus
 
class one // -> points to it's body
  {
  {
      class two {...};// which contains a class that points to it's body
  byte                    Type;             // 0
  Asciiz                  ClassName
  ulong                    OffsetToClassBody;
  };
  };


Recall that and the end of and within each class body is a pointer to the next class body at the same level or less.
'''All offsets in raP are relative to the start of file.'''


===EntryType 1: Value Eq===
=== EntryType 1: Value Eq ===


  {01} {EqType} {Asciiz name} {more bytes....}
RapValue
        Eq Types are as follows
  {
   {01}{00} {Aname} = another (asciiz) name
  byte  Type;  //1
   {01}{01} {Aname} = xx xx xx xx an intel float  
  byte  SubType;
   {01}{02} {Aname} = xx xx xx xx an intel long
  Asciiz Aname;
  //{01}{03} {AnArray[]}= { .........}; '''not used'''
   01 00 Aname="AString";
   {01}{04} {Aname}=Asciiz Variable name; // public or private
   01 01 Aname= float;
   01 02 Aname= long;
  //01 03 AnArray[]= { .........}; '''not used'''
   01 04 Aname=Asciiz Variable name; // public or private


(01 00) is the method by which an entire exec function can be declared (inside a string)
==== SubType 4: Asciiz Variable Name ====


====EQ Type 4: Asciiz Variable Name====
XBOX only
 
This has been newly introduced to Elite (vs OFP).


A variable name (as opposed to a string constant) is as follows
A variable name (as opposed to a string constant) is as follows
Line 193: Line 206:
  Aname=_fred;    // public or private variable
  Aname=_fred;    // public or private variable


===EntryType 2: array[]===
=== EntryType 2: array[] ===
 
RapArray
{
  byte  Type;// 02
  Asciiz ArrayName;
  ArrayStruct;
};


{02} {Asciiz ArrayName} {nElements}
==== ArrayStruct ====
  [[#CompressedInteger]] nElements;ArrayElements[nElements];


nElements is a BisShort declaring how many items make up the array, zero, is a legal value
nElements is a declaring how many items make up the array, zero, is a legal value


==Array Elements==
==== ArrayElements ====
array elements contain 'Value=' entries


each element of the array consists of a single 'EqType' byte followed by appropriate data for the type. Thus
each element of the array consists of a single subtype byte followed by appropriate data for the type. Thus


  {00}{Asciiz String constant}
  0 Asciiz string constant;
  {01}{4 byte float}
  1 float
  {02}{4 byte integer}
  2 long
  {03}{recursive array}
  3 recursive array ArrayStruct;
  {04}{Asciiz String variable}
  4 Asciiz String variable


A recursive array recurses into further entries with no name attached.
A recursive array recurses into further entries with no name attached.


A recursive array is as follows
A recursive array is as follows
  AnArray[]= { {1,2} , 3,4);
  AnArray[]= { {1,2} , 3,4};


===EntryType 3:ExternClass===
=== EntryType 3: ExternClass ===
{03}{ An Asciiz Classname}
New to Elite.
This encoding is used to supply the equivalent in C++ syntax
   
   
  class Classname;
  03 Asciiz Classname; // class Classname;


===EntryType 4:ExternClass===
=== EntryType 4: Delete Class ===
  {04}{ An Asciiz Classname}
  04 Asciiz Classname; // delete Classname;
New to Elite.
This encoding is used to supply the equivalent in C++ syntax
class Classname;


I am not sure of the difference between types 3 and 4. Encoding either value *appears* to achieve same result.
=== Entry type 5: Array with flags ===
The only flag that exists is 1 which means the following array is supposed to be appended to a existing array. <br>
If such an array to append to isn't found it behaves like a normal array. <br>
It has the 4 byte long flag and after that is the same as ArrayElements. <br>
The engine itself does a binary and with 1 to check if the add flag is set. Meaning the other bits could be filled with arbitrary data.
<hr>


<hr>
== Extern Classes ==
==Extern Classes==


Unlike OFP, a valuable addition to the Token types has been the definition
Unlike OFP, a valuable addition to the Token types has been the definition
Line 250: Line 267:
  class car{}:Strategic{};
  class car{}:Strategic{};


simply to declate a car !!! has been done away with.
simply to declate a car !!! has (sometimes) been done away with.


Instead, the new types deal with all things car. (or at least the engine goes looking elsewhere, which it did, anyway, in ofp).
Instead, the new types deal with all things car. (or at least the engine goes looking elsewhere, which it did, anyway, in ofp).


One other immediate, and not immediately apparent, benefit, is you do not need to know '''anything''' about how the underlying class (eg CfgVehicles) is constructed.
The intention '''was''' that you did not need to know '''anything''' about how the underlying class (eg CfgVehicles) is constructed. The practicalities are however that you pretty much have to declare an {{ofp}} looking tree to 'get at' any of the embedded classes (or inferred, inherited, embedded classes), of the class you're inheriting. This tree structure can become quite long, and, of necessity, accurate, thus there is no real improvement to the {{ofp}} way of doing things.


In fact, the inheritence tree of OFP (for CfgVehicles) is different to Elite, and using the above OFP method of constructon would fail. It would not find, a Target class.


==#defines==
=== CompressedInteger ===
(or enumerated list)  optional


the next four bytes after all class bodie are the def count., and these defines (if any) continue until end of file.  
This is the same construct as found in [[raP File Format - OFP|OFP raP files]].


where no defines exist,  the count is zero
The value is used to declare the number of entries in the class body or nArrays


A #define list consists of an asciiz name and integer value as follows
== enumerated list (optional) ==
 
The next four bytes after all class bodies are the enumerated list count. These defines (if any) continue until end of file.
 
Where no list exists (the '''very''' normal case),  the count is zero.
 
A list consists of an asciiz name and an (implied) integer value as follows


  (manposnoweapon) {01 00 00 00}
  (manposnoweapon) {01 00 00 00}
Line 271: Line 292:
which equates in C to  
which equates in C to  


  #define manposweapon 1
  enum {
manposweapon=1,
manshower=88,
manhungry=12,
....
}
 
This list is encountered in some few 'official' config.cpp's. It's use by model makers is rare.
 
Textually, you can have as many enum lists as required. They are ultimately congregated into one, enum list at the end of a raP encoded file.
 
The order in which they are presented in this list has no bearing on their text equivalent. They  are (generally) iterated as encountered and always converted to lower case.
 
You reference enums via their stringname. Thus
 
thisValue=manposweapon;
 
and
 
thisValue="ManPosWeapon";
 
are identical in effect. Both result in an integer value of 1 being assigned at run time.
 
 


This definition list is encountered in some few 'official' config.cpp's. It's use by model makers is rare.


[[category:Operation Flashpoint Elite: Modelling]]
{{GameCategory|ofpe|Modelling}}
[[Category:BIS_File_Formats|RAP]]

Latest revision as of 00:53, 8 August 2021

bi symbol white.png
Disclaimer: This page describes internal undocumented structures of Bohemia Interactive software.

This page contains unofficial information.

Some usage of this information may constitute a violation of the rights of Bohemia Interactive and is in no way endorsed or recommended by Bohemia Interactive.
Bohemia Interactive is not willing to tolerate use of such tools if it contravenes any general licenses granted to end users of this community wiki or BI products.

Caveat

If you are researching the nitty gritty of raP encoding for OFP you are in the wrong place. This document is specifically for Elite/Arma1 & 2 raPified files on the Xbox and beyond. However, if you are not too familiar with this subject, the Introduction in the OFP version will help you best.


Changes from OFP

  • Two new entry types
/*extern*/ class thing;
delete /*class*/ thing;
  • Enhanced TokenName
name= RealVariable (as opposed to name="variable";) Xbox mission.par's only
  • Non contiguous data file
non-contiguous data stream. Class bodies are now located 'arbitrarily' in a file offset, as opposed to being directly after the class name.
  • a rarely used sha/md5

Changes at Arma

  • Enhanced token is not used.
  • sha/md5 is not used

Introduction

raP encoding for Xbox Files

Conventions

see Generic FileFormat Data Types

Mandatory PreReading

The Human

BI use c++ class syntax to package data for almost everything. Anything configurable / alterable / makeable / editable by a player (author) involves creating a file or files consisting of class statements. The Mission Editor eg, creates several files for a mission consisting solely of class statements. Everything is defined or declared within classes. There is no specific file extension that is or is not a rap file. an rvmat or mission.sqm can, as equally be humanly readable text, or, binarised rap. Any text file that contains class statements, is, by definition, a rapifiable file. This includes bisurf, fsm, cpp, (model).cfg, BI's world revolves around the engine's ability to work with data contained in (a series of) class {bodies}. So much so, that at run time, a file that is in humanly readable text, is automatically converted to rap binary. The engine never sees 'text'. This also applies to description.ext and some other files that cannot be SAVED as rap binary, but are, most definately, rapified by the engine before use.

Class anything ultimately means raP binary


Class syntax can briefly (but accurately) be described as follows:

class thing [: InheritedClass]
{
  body
};

[: InheritedClass] is optional. It is heavily used in the config.cpp's of addons. If specified it must be referenced prior to being used.

The body of a class consists of

{
 #tokens and /or
 #arrays and /or
 #(embedded) classes and /or
 #nothing at all!  class default{};  is perfectly valid eg.
};

Any given file that contains classes, contains nothing else but classes. There are not, classes, and ummm, err, ummm 'other' things.

The file itself is considered an implied class!

The very first statement of all files is

//class filename {

Everything within that file is embedded within the class filename {....};

The Engine

The class structure is used internally within the engine for all most game data and configuration. The engine holds this data in tokenised form for more efficient processing.

This internal tokenised data can also be held in a file (a savegame eg). But, it is a class structure regardless.

To improve loading speed many files within the Operation Flashpoint tree are pre-tokenised. They were 'converted' to hold the tokenised form of the same class statements.

In fact, the engine does not care which 'type' of file it is dealing with. A mission.sqm can be either. If it has not been pre-tokenised (eg contains text-readable class statements) the engine converts it on the fly.

Tokenised files have a magic signature as their first four bytes. "\0raP". The file extension is meaningless in this regard.

In the early days of ofp, when the campaign mission.sqm's came pre-tokenised, it was assumed wrongly, this was some attempt at encryption. They were also called 'binary' files because it was noticed that the tokenised form of a config.cpp was called config.bin (config.rap would have been far more appropriate). In fact, the engine will happily work with a config.cpp that is rap encoded.

Various utilities (tools) arrived on the internet in an attempt to decode them (and conversely, encode them). cpp2bin, bin2cpp, Coc binview are the most well known of these.

They are detailed here as 'raP' files because of their unique signature. This document refers to rapifying and de-rapifying files containing nothing but, class statements.

Xbox/Arma

raP encoding is an extension to Flashpoint PC raP encoding.

Overall Structure

struct raP
{
 char   Signature[4];               // 4 byte raP signature (\0raP)
 byte   AuthenticationSignature[20] // XBOX ONLY NOT ARMA
 ulong  Always0;
 ulong  Always8;
 ulong  OffsetToEnums;

 ClassBody  ClassBody;              // one and one only, within which, will be more class bodies

 Enums
 {
  ulong  nEnums;  // generally always 0
  enumlist....    // optional
 };
};

All offsets are relative to start of file

Authentication Signature

Unique to Xbox, not known on ArmA.

Following the four byte signature "\0 r a P" is an optional 20 byte signature intended to provide a unique value to this file and to prevent tampering. This value, or 'Authentication signature' is generated from a common 'Authentication Key' plus the content of the file itself. The Authentication key for Xbox Elite is 16 bytes and not listed here.

You can obtain source code for generating signatures elsewhere.

The signature is 'optional' only in the sense that not all types of files have it. A signature appears in .par files for example, but not in the official bis mission.sqms.

File Offset to Enumerated list

the offset points to points to the end of All class data and consequently the start of an enum list (if any).

There may well be, no enumerated list, there will be a ListCount saying so!

ClassBody

ClassBody
{
 Asciiz               InheritedClassname; // can be zero
 #CompressedInteger   nEntries;           // can be zero.
 ClassEntry           ClassEntries[nEntries];
};

ClassBodies contain zero or more 'entries'. These 'entries' consist of strings, arrays, classes, etc. The 1st byte of each entry defines what 'type' of entry it is.

Note that ALL classes other than the first class body above are EMBEDDED classes within this one.

Furthermore, this unique class cannot have an inheritance (obviously), and their is no classname associated with it. In OFP raP the classname of this unique class was, the name of the file (config.cpp eg)


ClassEntries

Type ID SubID Asciiz Name Value Example
class 0 - classname 4byte OffsetToBody class thing{...};
string 1 0 name= Asciiz string thing="hello";
float 1 1 name= 4byte float thing=0.123;
long 1 2 name= 4byte long thing=123;
Array 2 - name[]= {nElements Elements[nElements]} thing[]={1,0.2,"three",{4,5,6},{"seven"}};
extern 3 - classname - class thing;
delete 4 - classname - delete thing;
Array with flag 5 - name[]+= 4 bytes of flag followed by {nElements Elements[nElements]} thing[]+={1,0.2,"three",{4,5,6},{"seven"}};

Entry Types

0 Embedded Class
1 value = (string, float, integer, variable)
2 array[]={....};
3 /*extern*/ class label;
4 delete /*class*/ label;

EntryType 0: RapClass

RapClass
{
 byte                     Type;             // 0
 Asciiz                   ClassName
 ulong                    OffsetToClassBody;
};

All offsets in raP are relative to the start of file.

EntryType 1: Value Eq

RapValue
{
  byte   Type;   //1
  byte   SubType;
  Asciiz Aname;
  01 00 Aname="AString";
  01 01 Aname= float;
  01 02 Aname= long;
//01 03 AnArray[]= { .........}; not used
  01 04 Aname=Asciiz Variable name; // public or private

SubType 4: Asciiz Variable Name

XBOX only

A variable name (as opposed to a string constant) is as follows

Aname = "fred"; // constant
Aname=_fred;    // public or private variable

EntryType 2: array[]

RapArray
{
  byte   Type;// 02
  Asciiz ArrayName;
  ArrayStruct;
};

ArrayStruct

 #CompressedInteger nElements;ArrayElements[nElements];

nElements is a declaring how many items make up the array, zero, is a legal value

ArrayElements

each element of the array consists of a single subtype byte followed by appropriate data for the type. Thus

0 Asciiz string constant;
1 float
2 long
3 recursive array  ArrayStruct;
4 Asciiz String variable

A recursive array recurses into further entries with no name attached.

A recursive array is as follows

AnArray[]= { {1,2} , 3,4};

EntryType 3: ExternClass

03 Asciiz Classname; // class Classname;

EntryType 4: Delete Class

04 Asciiz Classname; // delete Classname;

Entry type 5: Array with flags

The only flag that exists is 1 which means the following array is supposed to be appended to a existing array.
If such an array to append to isn't found it behaves like a normal array.
It has the 4 byte long flag and after that is the same as ArrayElements.
The engine itself does a binary and with 1 to check if the add flag is set. Meaning the other bits could be filled with arbitrary data.


Extern Classes

Unlike OFP, a valuable addition to the Token types has been the definition

/*extern*/ class car;

class BigCar:car {...};
class RedCar:BigCar{...};

The tedious business of listing

class All:Default{};
class Vehicle:All{};
...
class Target:Vehicle{};
class Strategic:Target{};
class car{}:Strategic{};

simply to declate a car !!! has (sometimes) been done away with.

Instead, the new types deal with all things car. (or at least the engine goes looking elsewhere, which it did, anyway, in ofp).

The intention was that you did not need to know anything about how the underlying class (eg CfgVehicles) is constructed. The practicalities are however that you pretty much have to declare an Operation Flashpoint looking tree to 'get at' any of the embedded classes (or inferred, inherited, embedded classes), of the class you're inheriting. This tree structure can become quite long, and, of necessity, accurate, thus there is no real improvement to the Operation Flashpoint way of doing things.


CompressedInteger

This is the same construct as found in OFP raP files.

The value is used to declare the number of entries in the class body or nArrays

enumerated list (optional)

The next four bytes after all class bodies are the enumerated list count. These defines (if any) continue until end of file.

Where no list exists (the very normal case), the count is zero.

A list consists of an asciiz name and an (implied) integer value as follows

(manposnoweapon) {01 00 00 00}

which equates in C to

enum {
manposweapon=1,
manshower=88,
manhungry=12,
....
}

This list is encountered in some few 'official' config.cpp's. It's use by model makers is rare.

Textually, you can have as many enum lists as required. They are ultimately congregated into one, enum list at the end of a raP encoded file.

The order in which they are presented in this list has no bearing on their text equivalent. They are (generally) iterated as encountered and always converted to lower case.

You reference enums via their stringname. Thus

thisValue=manposweapon;

and

thisValue="ManPosWeapon";

are identical in effect. Both result in an integer value of 1 being assigned at run time.