Key Data Structures
Outlines common data structures and how they are stored in the replay file.
Vectors
Vectors are simply 3 floating point values packed together:

Quaternions
Quaternions consist of 4 floating point values packed together:

However, to save space, quaternions are packed into a smaller datastructure by utilising the fact that normalized quaternions always have a magnitude of 1. This way the largest component can be omitted and recalculated by subtracting all the existing components from 1. We store which component of the quaternion is missing by using a single byte:

Here are how the quarternions can be unpacked when parsing:

Half Precision
To reduce size of replays, many values are stored in half precision. This is simply a 16-bit floating point value instead of 32-bit. I perform this conversion by doing the following:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint AsUInt(float x) {
return *(uint*)&x;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe float AsFloat(uint x) {
return *(float*)&x;
}
// NOTE:: These Half <-> Float conversions do not account for Infinity or NaN!
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float HalfToFloat(ushort x) {
// IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
int e = (x & 0x7C00) >> 10; // exponent
int m = (x & 0x03FF) << 13; // mantissa
int v = (int)(AsUInt((float)m) >> 23); // evil log2 bit hack to count leading zeros in denormalized format
return AsFloat((uint)((x & 0x8000) << 16 | Convert.ToInt32(e != 0) * ((e + 112) << 23 | m) | (Convert.ToInt32(e == 0) & Convert.ToInt32(m != 0)) * ((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)))); // sign : normalized : denormalized
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort FloatToHalf(float x) {
// IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
uint b = AsUInt(x) + 0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
uint e = (b & 0x7F800000) >> 23; // exponent
uint m = b & 0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
return (ushort)((b & 0x80000000) >> 16 | Convert.ToInt32(e > 112) * ((((e - 112) << 10) & 0x7C00) | m >> 13) | (Convert.ToInt32(e < 113) & Convert.ToInt32(e > 101)) * ((((0x007FF000 + m) >> (int)(125 - e)) + 1) >> 1) | Convert.ToUInt32(e > 143) * 0x7FFF); // sign : normalized : denormalized : saturate
}
Boolean
Booleans are stored as a single byte where 1 is True and 0 is False.
Strings
Strings are stored in UTF-8 byte format where the first 2 bytes is an unsigned short
that represents the length of the string in bytes:

Identifier
Identifier is a custom data structure used to represent various types in GTFO such as enemies, gear, items and vanity.
The first component of the identifier is a single byte that represents the enum:
IdentifierType {
Unknown = 0
Gear = 1
Alias_Gear = 2
Item = 3
Enemy = 4
Vanity = 5
}
The rest of the identifier is parsed as according to its type.
Unknown
This type does not have any additional data to be parsed. It represents an unknown object.
Gear
This type represents any in game gear such as guns, melees and tools. The game constructs these using a gear builder system which is expanded upon here.
The gear builder uses a JSON string to construct each weapon, this string is what is what is stored in the replay along side an addition shorthand alias:

Alias_Gear
An extension to the Gear type which does not include the entire gear string but just its alias:

This type is always used once the alias for a given gear is defined. This is because storing the full gear JSON string is expensive in terms of space.
Item
This type has an additional unsigned short value that is the persistentID
of the item.

Enemy
This type has an additional unsigned short value that is the persistentID
of the enemy type.

Vanity
This type has an additional unsigned short value that is the persistentID
of the vanity item.

Last updated