Replay File Format

Any and all discussion relating to Rocket League. Post feedback and suggestions here!

Replay File Format

Postby Iago on Wed Jul 29, 2015 3:25 pm

First, to the devs, congrats on the success of RocketLeague! I could only imagine the crunch you've been under before and after launch, hopefully things are a bit smoother.

I am hoping to see if there is the possibility that the devs provide some information to help in the building of fan-made parsers of replay files. I've already started work on such a parser (https://github.com/markhildreth/rl_replay_parser). These efforts have already aided another fan in the creation of a replay database that hopefully can be used in the community (http://www.rocketleaguereplays.com/). Continuing to reverse-engineer the file as I have been doing might take a long time, and I'm hoping that with the devs help we could speed up the process. Once a parser is written, tools could be made to analyze replay files, providing stats to game commentators, metrics to players/teams attempting to improve their game, plus cool ideas we haven't even thought of yet.

Ideally, there would be a document explaining the format, although such a document might not even exist (and I wouldn't expect the devs to take the time to write that document if it didn't). Here are some things that could be of help in this endeavor that hopefully won't be too much of a distraction:

* A list of any sort of compression algorithms used in the file.
* A brief summary of the replay file strategy. I'm under the impression that the replay file is the storage of entity position/velocity vectors/other points recorded multiple times per second (each "frame"). Is this assumption correct?
* An overview of the file format ordering. For example, I know at the beginning there is a sort of "header", that when parsed looks like this:
Code: Select all
{'Date': '2015-07-07:13-23',
 'Goals': [{'PlayerName': 'Raja', 'PlayerTeam': 1, 'frame': 1784},
           {'PlayerName': 'Gerwin', 'PlayerTeam': 0, 'frame': 2324},
           {'PlayerName': 'Goose', 'PlayerTeam': 1, 'frame': 2933},
           {'PlayerName': 'Goose', 'PlayerTeam': 1, 'frame': 4010},
           {'PlayerName': 'iago', 'PlayerTeam': 1, 'frame': 5253},
           {'PlayerName': 'Junker', 'PlayerTeam': 0, 'frame': 5869}],
 'Id': 'D5FB5DD94D13A0B919C24F8E974B41E9',
 'KeyframeDelay': 10.0,
 'MapName': 'trainstation_p',
 'MatchType': 'Offline',
 'MaxChannels': 1023,
 'MaxReplaySizeMB': 10,
 'NumFrames': 7241,
 'PlayerName': 'iago',
 'PrimaryPlayerTeam': 1,
 'RecordFPS': 30.0,
 'Team0Score': 2,
 'Team1Score': 4,
 'TeamSize': 3}


However, the remainder of the file seems a bit more cryptic. I can see some structure, but I need to guess at what it represents. Does the file group all information referring to a single frame together? Or is player positioning in one section of the file, while velocity vectors in another, while boost usage in still another?

Thank you for you attention.
Iago
Acrobatic
 
Posts: 34
Joined: Mon Jul 06, 2015 10:47 pm
Steam ID: iago
Region: US
Switch Friend Code: 0

Re: Replay File Format

Postby Psyonix-Cone on Thu Jul 30, 2015 11:41 am

Hi, cool project, hope I can be of help. The layout of the network data is designed for minimal data, not for user-friendly parsing so I don't envy you trying to get useful data out of it.

The first part of the file is MetaData, which includes a CRC check, some version information, and information about the replay that we use to show in the list of replays. You seem to have that part all figured out so I'll move on to the fun stuff.

The remainder of the file is stuff serialized in this order:
- Array of strings for all of the levels that need to be loaded (array length followed by each string)
- Array of Keyframe information used for timeline scrubbing (array length followed by each keyframe struct) (Time, Frame, File Position)
- Array of bytes that is the bulk of the data. This is the raw network stream. (array length followed by a bunch of bytes)
- Array of debugging logs (strings). This reminds me that I should probably turn these off to make the replays smaller. (array length followed by each string)
- Array of information used to display the Tick marks in the replay (goal scores). (array length followed by each tick struct) (Type, Frame)
- Array of strings of replicated Packages
- Array of strings for the Object table. Whenever a persistent object gets referenced for the network stream its path gets added to this array. Then its index in this array is used in the network stream.
- Array of strings for the Name table. "Names" are commonly used strings that get assigned an integer for use in the network stream.
- Map of string, integer pairs for the Class Index Map. Whenever a class is used in the network stream it is given an integer id by this map.
- "Class Net Cache Map" maps each replicated property in a class to an integer id used in the network stream.

The network stream is pretty much just the same data that the server sends to the client, so it does have some compression going on. This is not an overall compression, it is a per-property compression (such as vector compression for velocity, location)

The network data stream is a stream of network frames. Each frame is composed like this:
- Current Time
- Delta Time (since last frame)

- Data for actors that have stopped replicating (were destroyed), which is composed like this:
- 1 bit to signal we are replicating another actor
- compressed integer for the actor's network channel ID (max value is MaxChannels)
- 1 bit to signal the channel is closing (actor was destroyed)

- Data for actors that have started replicating this frame (newly spawned), which is composed like this:
- 1 bit to signal we are replicating another actor
- compressed integer for the actor's network channel ID (max value is MaxChannels)
- 1 bit to signal the channel is open
- 1 bit to signal it is a new actor
- Some data for how to reference the actor. If it's a static actor (placed in level), then this puts his integer ID from the object table. If it's a dynamic actor, it puts the integer id for his "archetype", along with optional initial location (vector) and rotation (3 bytes for pitch, yaw, roll). Not all actors need this initial location and rotation so not all actors serialize it.

- Finally property values for each replicating actor. We only serialize property values that have changed since the last frame, unless this is a keyframe in which we serialize all replicated properties. Composed like this:
- 1 bit to signal we are replicating another actor
- compressed integer for the actor's network channel ID (max value is MaxChannels)
- 1 bit to signal the channel is open
- 1 bit to signal it is not a new actor
- A stream of properties and their values, composed like this:
- 1 bit to signal we have another property
- compressed property id (max value pulled from the Class Net Cache)
- if the property is a static array, serialize the index we are replicated in the static array
- The property's data. Whatever gets serialized here depends on the type of property. Ints, bytes, and strings are obvious. The less-obvious ones are structs, and particularly the rigid body state for each car and the ball, which is comprised of several compressed vectors and rotators.
- 1 bit to signal we are done replicating properties

- Finally 1 bit to signal we are done replicating actors
Psyonix-Cone
Psyonix Developer
User avatar
Psyonix Developer
 
Posts: 225
Joined: Fri Sep 19, 2008 2:29 pm
Switch Friend Code: 0

Re: Replay File Format

Postby Iago on Thu Jul 30, 2015 4:02 pm

Thanks so much for the info! This is exactly what I'm looking for! I'll start looking right now!

Image
Iago
Acrobatic
 
Posts: 34
Joined: Mon Jul 06, 2015 10:47 pm
Steam ID: iago
Region: US
Switch Friend Code: 0

Re: Replay File Format

Postby danielsamuels on Thu Jul 30, 2015 10:54 pm

Hi Cone, Dan from Rocket League Replays here! Thanks so much for putting this post together, I'm sure it will be instrumental in us cracking the rest of the parser.

I've got a couple of questions with regards to the information we already know about, as well as what you've posted.

  • Replay length. At the moment, both RLR and the game calculate the match length as
    Code: Select all
    NumFrames / RecordFPS
    and then converting to MM:ss. However, for most matches this seems to give a result of around 4:30, do you know why this is and how to fix it? It seems like if the match finishes at normal time (5 minutes) there's a keyframe missing, or something similar, which stops the final frames being added.

Code: Select all
rocket_league=> SELECT AVG(s.seconds) FROM (SELECT (num_frames / record_fps) AS seconds FROM replays_replay) s;
       avg
------------------
 271.765765765766
(1 row)


  • CRC check. You mentioned a CRC check at the top of the header, this isn't something we knew about before (though we could see the data). Is this check against just the header, or the whole file?
  • Player list / scoreboard. At the moment we're generating the team lists by looking at the goal scorers as well as the "player" values. This usually leads to players who haven't scored not appearing in the player list. Is the list of players and their scoreboard values available as values in the data, or will we need to manually detect those?
  • Player teams. Sometimes a player or two can appear on the wrong team both in the replay playback itself, but also in the parsed data as a result. Have you heard of this happening? Would it be useful for me to provide a replay of it occuring?

Thanks once again, I'm looking forward to finally getting this cracked! Have a great Friday!

Thanks,
Dan.
Last edited by danielsamuels on Fri Jul 31, 2015 3:02 am, edited 1 time in total.
danielsamuels
Acrobatic
User avatar
 
Posts: 53
Joined: Thu Jul 30, 2015 10:41 pm
Location: Cambridge, UK
Steam ID: posix_
Region: EU
Switch Friend Code: 0

Re: Replay File Format

Postby danielsamuels on Fri Jul 31, 2015 12:26 am

After an hour of so of work, most of the data is now being parsed (with the exception of the network stream data and the "class net cache map"). Here's how things are looking now - https://gist.github.com/danielsamuels/a ... b87502cfff
danielsamuels
Acrobatic
User avatar
 
Posts: 53
Joined: Thu Jul 30, 2015 10:41 pm
Location: Cambridge, UK
Steam ID: posix_
Region: EU
Switch Friend Code: 0

Re: Replay File Format

Postby Psyonix-Cone on Fri Jul 31, 2015 2:48 pm

There was a problem in older builds where NumFrames was not being calculated properly in conjunction with RecordFPS, so the times were off. This has been fixed though, I just tested on the current build and properly have 5 minute matches.

The CRC check is against the entire file.

The player list is in the network stream, not going to be easy to get it out.

Players showing as the wrong team is a problem I think we fixed either in the latest patch (the one that came out today) or the next patch I can't remember. As far as I know this was limited to the UI / Nameplates, I'm not aware of anything wrong in the replay data.

Good job with the parsing so far, seems to be coming along very quickly
Psyonix-Cone
Psyonix Developer
User avatar
Psyonix Developer
 
Posts: 225
Joined: Fri Sep 19, 2008 2:29 pm
Switch Friend Code: 0

Re: Replay File Format

Postby danielsamuels on Fri Jul 31, 2015 2:51 pm

Great, thanks for the updates and your help so far. I'm working my way through the network data at the moment, it's a complex beast!
danielsamuels
Acrobatic
User avatar
 
Posts: 53
Joined: Thu Jul 30, 2015 10:41 pm
Location: Cambridge, UK
Steam ID: posix_
Region: EU
Switch Friend Code: 0

Re: Replay File Format

Postby AeonLucid on Fri Jul 31, 2015 3:23 pm

Interesting project, I'm definitely following this project and that of @danielsamuels.
AeonLucid
Acrobatic
User avatar
 
Posts: 48
Joined: Thu Jul 16, 2015 8:49 am
Steam ID: AeonLucid
Region: EU
Switch Friend Code: 0

Re: Replay File Format

Postby OR3OTHUG on Fri Jul 31, 2015 4:06 pm

Don't know what any of this means but it's probably something cool.
Image
OR3OTHUG
Acrobatic
 
Posts: 95
Joined: Wed Jun 03, 2015 7:55 am
PSN ID: OR3OTHUG
Steam ID: OR3OTHUG
Region: US
Switch Friend Code: 0

Re: Replay File Format

Postby E_M_E_T on Fri Jul 31, 2015 5:16 pm

Since we're on a thread about replays, can I just ask the devs to fix the bug where the replays put the wrong names over the cars? I've figured out that the problem is rooted on the scoreboard. The scoreboard puts the people on the wrong team.
Image
E_M_E_T
Aerialistic
User avatar
Aerialistic
 
Posts: 1369
Joined: Sun Feb 02, 2014 11:33 pm
PSN ID: merc-835
Steam ID: E_M_E_T
Region: USW... but idrc
Switch Friend Code: 0

Re: Replay File Format

Postby Psyonix-Jerad on Fri Jul 31, 2015 5:33 pm

Pretty sure that one is already fixed.
Image
Got balls?
Psyonix-Jerad
Psyonix Developer
User avatar
Psyonix Developer
 
Posts: 4519
Joined: Fri Sep 19, 2008 2:26 pm
PSN ID: Psyonix-Jerad
Region: US/EU
Switch Friend Code: 0

Re: Replay File Format

Postby Psyonix-Cone on Fri Jul 31, 2015 6:22 pm

If it isn't fixed in today's patch then it's fixed in the next one, but I'm pretty sure it's fixed in today's.
Psyonix-Cone
Psyonix Developer
User avatar
Psyonix Developer
 
Posts: 225
Joined: Fri Sep 19, 2008 2:29 pm
Switch Friend Code: 0

Re: Replay File Format

Postby E_M_E_T on Fri Jul 31, 2015 8:43 pm

oh cool, I probably should have checked before posting :/
Image
E_M_E_T
Aerialistic
User avatar
Aerialistic
 
Posts: 1369
Joined: Sun Feb 02, 2014 11:33 pm
PSN ID: merc-835
Steam ID: E_M_E_T
Region: USW... but idrc
Switch Friend Code: 0

Re: Replay File Format

Postby Iago on Sat Aug 08, 2015 11:06 am

Cone,

Thanks for the all of the info. Based on this, we have been able to parse everything with the exception of the network frames. I was wondering if you could answer a few more questions:

Psyonix-Cone wrote:The network data stream is a stream of network frames. Each frame is composed like this:

- Data for actors that have stopped replicating (were destroyed), which is composed like this:
- 1 bit to signal we are replicating another actor
- compressed integer for the actor's network channel ID (max value is MaxChannels)
- 1 bit to signal the channel is closing (actor was destroyed)


* When you say "1 bit to signal we are replicating another actor", I assumed you mean that a 1 means replicating another actor. In the replay files I look at, even the very first frame has this bit as a zero. Does 1 mean "we are no longer replicating"? Or is there some reason that an actor might be destroyed in the first frame?

* Same question as above for signalling that the channel is closing, that we have more properties, etc.

* Also, the "compressed integer": just to verify, if the MaxChannels is 1023, we could do that in 10 bits. Thus, to get the actor's network channel ID, we should look at 10 bits and turn it into an unsigned integer? Is there any padding when looking at groupings of bits that don't make an entire byte?

- Data for actors that have started replicating this frame (newly spawned), which is composed like this:
...snip....
- Some data for how to reference the actor. If it's a static actor (placed in level), then this puts his integer ID from the object table. If it's a dynamic actor, it puts the integer id for his "archetype", along with optional initial location (vector) and rotation (3 bytes for pitch, yaw, roll). Not all actors need this initial location and rotation so not all actors serialize it.


* Just to verify, when you provide the "optional initial location and rotation", do you just put those in the following bits? Or do you start a whole "properties" sequence as described below? If the former, how do you know whether it needs initial location/rotation?

I'm sure I'll have more questions as I continue working on this. Thanks for any info you can provide.
Iago
Acrobatic
 
Posts: 34
Joined: Mon Jul 06, 2015 10:47 pm
Steam ID: iago
Region: US
Switch Friend Code: 0

Re: Replay File Format

Postby Psyonix-Cone on Mon Aug 10, 2015 10:59 am

For each frame, first there are 2 floats for Time and DeltaTime. Then a single bit with a value of 1 to say we have actors that were destroyed, so it is expected that the first frame of the replay would have a 0 for that bit since no actors have been destroyed yet. If an actor has been destroyed it then puts the 10 bits for the channel ID, no padding (I think). If no actors were destroyed it just moves on to the next phase (actors that were spawned).

The optional location and rotation are in the following bits, no property identifiers. It looks like actors always write their compressed vector location. The way we know if it needs initial rotation is by checking properties on the class at runtime (Actor.bNetInitialRotation), which is part of the game, not included with the replay.

Vectors are compressed over the network, and the amount of bits they take depends on the vector. The code used for serializing them is the same as in UE4's FVector_NetQuantize NetSerialize() function.
Psyonix-Cone
Psyonix Developer
User avatar
Psyonix Developer
 
Posts: 225
Joined: Fri Sep 19, 2008 2:29 pm
Switch Friend Code: 0

Re: Replay File Format

Postby danielsamuels on Mon Aug 10, 2015 11:03 am

Psyonix-Cone wrote:Vectors are compressed over the network, and the amount of bits they take depends on the vector. The code used for serializing them is the same as in UE4's FVector_NetQuantize NetSerialize() function.


Source for that function is available here.
danielsamuels
Acrobatic
User avatar
 
Posts: 53
Joined: Thu Jul 30, 2015 10:41 pm
Location: Cambridge, UK
Steam ID: posix_
Region: EU
Switch Friend Code: 0

Re: Replay File Format

Postby Iago on Tue Aug 11, 2015 8:00 am

Thanks Cone and Dan. I think the thing that really confuses me is that after a quick look last night, I had replays where the first bits after the frame's current/delta floats were 0000. That would seem to imply that for that frame:

* There were no destroyed actors
* There were no new actors created.
* There were no properties updated.
* We're done replicating actors.

...which doesn't make any sense to me at all. I'll need to have another look at it tonight.
Iago
Acrobatic
 
Posts: 34
Joined: Mon Jul 06, 2015 10:47 pm
Steam ID: iago
Region: US
Switch Friend Code: 0

Re: Replay File Format

Postby TruSolja on Tue Aug 11, 2015 8:02 am

+1 to the four of you for getting this project off of the ground. Looking forward to see what else can come out of this project in the near future.

eSports and Announcers would definitely love this! Thanks for the efforts, guys!
Image Image Image Image
TruSolja
Moderator
User avatar
Moderator
 
Posts: 1054
Joined: Tue Oct 14, 2008 6:11 pm
Location: Philadelphia, PA
PSN ID: TruSolja
Steam ID: TruSolja
GamerTag: YourHolySavior
Region: US
Switch Friend Code: 0

Re: Replay File Format

Postby danielsamuels on Tue Aug 11, 2015 8:04 am

Iago wrote:Thanks Cone and Dan. I think the thing that really confuses me is that after a quick look last night, I had replays where the first bits after the frame's current/delta floats were 0000. That would seem to imply that for that frame:

* There were no destroyed actors
* There were no new actors created.
* There were no properties updated.
* We're done replicating actors.

...which doesn't make any sense to me at all. I'll need to have another look at it tonight.


Could it be that there are frames generated as players are still loading in? (Think the "Reserved" or "Loading" status on the side at the start of the game)
danielsamuels
Acrobatic
User avatar
 
Posts: 53
Joined: Thu Jul 30, 2015 10:41 pm
Location: Cambridge, UK
Steam ID: posix_
Region: EU
Switch Friend Code: 0

Re: Replay File Format

Postby Iago on Tue Aug 11, 2015 9:45 am

danielsamuels wrote:
Iago wrote:Thanks Cone and Dan. I think the thing that really confuses me is that after a quick look last night, I had replays where the first bits after the frame's current/delta floats were 0000. That would seem to imply that for that frame:

* There were no destroyed actors
* There were no new actors created.
* There were no properties updated.
* We're done replicating actors.

...which doesn't make any sense to me at all. I'll need to have another look at it tonight.


Could it be that there are frames generated as players are still loading in? (Think the "Reserved" or "Loading" status on the side at the start of the game)


It's a good thought: I haven't really been able to consider when, exactly, the first frame is taking place. I would think it's as soon as the countdown for the game start finishes, since when you open a replay there is very little delay before the cars start moving (although the replay viewer might just be skipping these empty frames).

But I scanned the bits for any bits that look like the "current" timestamp (indicating the start of the next frame) and didn't see one for many bits later, leading me to believe that the frame itself is not simply empty.

Unfortunately I'm not at my home computer otherwise I'd give an example.
Iago
Acrobatic
 
Posts: 34
Joined: Mon Jul 06, 2015 10:47 pm
Steam ID: iago
Region: US
Switch Friend Code: 0

Next

Return to General Discussion

Who is online

Users browsing this forum: No registered users and 6 guests