This is an attempt to document the file format of the rFactor 2 replay files (.vcr). The basis for this is Gerald Jacobson’s wiki and rf2ReplayOffice application source code.
All of the information is based on version 1.08 of the replay file.
This is a python script that I’m using to scan and document the format. Yes, it’s awful, but it does the job.
Description | Length | Type | Comment |
---|---|---|---|
Header text | variable | String | Read bytes until 0x0A is encountered |
Separator | 1 | Byte | 0x0A |
IRSR tag | 4 | String | “IRSR” |
Version | 4 | Float | 1.08 |
Description | Length | Type | Comment |
---|---|---|---|
RFM string length | 4 | Integer | |
RFM string | variable | String | |
Unknown | 4 | Integer | |
Mod Info length | 4 | Integer | |
Mod Info | variable | String | Info about the mod - name, version, track info, drivers, points, etc |
SCN Filename length | 4 | Integer | |
SCN Filename | variable | String | File name for the track used |
AIW Filename length | 4 | Integer | |
AIW Filename | variable | String | Filename for the AIW file (info for AI drivers) |
Mod name length | 2 | Integer | |
Mod name | variable | String | Name of the mod |
Mod version length | 2 | Integer | |
Mod version | variable | String | Version of the mod |
Mod UID length | 2 | Integer | |
Mod UID | variable | String | UID of the mod (MD5 or similar hash) |
Track path length | 2 | Integer | |
Track path | variable | String | Full path to the track file |
Unknown | 1 | Integer | |
Session Info | 1 | Integer | |
Unknown | 67 | Bytes | Unknown chunk of data |
Session Info
session_info = 10 # example - session type is race, private session is False
session_type = session_info & 0xF
private_session = session_info >> 7 & 1
session_types = {
0: 'Test Day',
1: 'Practice',
2: 'Practice',
3: 'Practice',
4: 'Practice',
5: 'Qualifying',
6: 'Qualifying',
7: 'Qualifying',
8: 'Qualifying',
9: 'Warmup',
10: 'Race',
11: 'Race',
12: 'Race',
13: 'Race',
}
Description | Length | Type | Comment |
---|---|---|---|
Driver count | 1 | Integer |
For each driver, the following structure applies
Description | Length | Type | Comment |
---|---|---|---|
Number | 1 | Integer | Driver number, used later in the file |
Name length | 1 | Integer | |
Name | variable | String | |
Co-driver name length | 1 | Integer | |
Co-driver name | variable | String | |
Vehicle name length | 2 | Integer | |
Vehicle name | variable | String | eg FSR2018 |
Vehicle version length | 2 | Integer | |
Vehicle version | variable | String | eg 1.07 |
Vehicle ID length | 1 | Integer | |
Vehicle ID | variable | String | 64 character string |
Vehicle filename | 32 | String | Read up to the first \x00 character, discard the rest |
Unknown | 48 | Unknown | Unknown chunk of data |
Entry time | 4 | Float | |
Exit time | 4 | Float |
The rest of the file describes the replay in ‘slices’ of time. These are variable length blocks of data, each one with a header that, when decoded, describes the content and size of the slice/block.
Description | Length | Type | Comment |
---|---|---|---|
Slice count | 4 | Integer | |
Total event count | 4 | Integer | The total number of events in the replay |
Start time | 4 | Float | |
End time | 4 | Float |
Each time slice uses the following structure.
Description | Length | Type | Comment |
---|---|---|---|
Slice time | 4 | Float | |
Event count | 4 | Unsigned Integer | Number of events in this slice |
Each slice then has a number of events of variable size, with an unsigned integer header at the start that describes the content and size. This header is decoded as follows:
header = 84950786 # example - size = 63, class = 0, type = 8, driver = 2
event_size = (header >> 8) & 0x1ff
event_class = (header >> 29)
event_type = (header >> 17) & 0x3f
event_driver = header & 0xff
After the header, there is a single byte between it and the event details. It is currently unknown what this byte is for.
What follows is what Gerald and I have figured out of the format, organised into class and type.
Class | Type | Link | Comment |
---|---|---|---|
0 | 7 - 16 | Link | Driver positions and info |
1 | 7 | Link | Driver enters or leaves their garage |
1 | 10 | Link | Number of lights shown |
1 | 23 | Link | Countdown to race start |
2 | 5 | Link | Penalty given to a driver |
2 | 7 | Link | Driver served a penalty |
2 | 8 | Link | Admin removed a penalty from a driver |
2 | 19 | Link | Session type (race, qualifying, etc) |
3 | 6 | Link | Checkpoint event - usually when a sector is completed |
3 | 9 | Link | When the countdown begins and ends |
3 | 48 | Link | Driver Overtake |
5 | 2 | Link | Pit lane/garage events |
The next set of classes/types is what I’ve observed, but haven’t figured out their meanings (partially or completely).
Class | Type | Link | Comment |
---|---|---|---|
0 | 1 | Link | |
0 | 3 | Link | |
0 | 4 | Link | Impacts with walls or cars |
0 | 5 | Link | Wheels removed from car |
1 | 4 | Link | |
1 | 6 | Link | Contacts between cars |
1 | 11 | Link | Same as 2-17 |
1 | 26 | Link | Something to do with passing a DRS line |
2 | 9 | Link | |
2 | 15 | Link | |
2 | 16 | Link | |
2 | 17 | Link | Incidents - collisions with cars, signs, posts, wheels, etc |
2 | 23 | Link | Engine damage events |
2 | 26 | Link | Suspension damage events |
2 | 28 | Link | Corner cut or track extension events |
2 | 29 | Link | Sector 1 events |
2 | 30 | Link | Sector 2 events |
2 | 31 | Link | Sector 3 events |
3 | 6 | Link | |
3 | 8 | Link | |
3 | 15 | Link | Driver pressed ESC |
3 | 19 | Link | |
3 | 22 | Link | Formation lap |
3 | 38 | Link | |
3 | 49 | Link | Pit events |
5 | 3 | Link |