-
Notifications
You must be signed in to change notification settings - Fork 0
Asobo Save Game File Format Specification
This is the save game format used in FUEL. Other games have different formats. Saves are located in %USERPROFILE%\Documents\My Games\FUEL
this directory contains one subdirectory for each GFWL profile name, where the name of the subdirectory is the same as the name of the profile. Each of these subdirectories contains a single FUEL_SAVE_V14.sav
file which is the save game for that profile. Note that save games use the Alternate CRC-32 algorithm and not the primary one. For more information about the compression used, see the Asobo Arithmetic Coding Compression entry.
The fuel-save-editor repository contains a tool for unpacking and packing FUEL save files.
struct SaveGame
{
std::uint32_t xliveHeaderSize;
// Always 4
// Written by xlive
std::uint32_t saveGameDataCRC32Checksum0;
// Alternate CRC-32 Checksum of saveGameData taken as a raw byte buffer
// Equals saveGameDataCRC32Checksum1
// Written by xlive
SaveGameData saveGameData;
// 199996 bytes
std::uint32_t saveGameDataCRC32Checksum1;
// Alternate CRC-32 Checksum of saveGameData taken as a raw byte buffer
// Equals saveGameDataCRC32Checksum0
};
struct SaveGameData
{
std::uint32_t dataCompressedSize;
// Includes the sizes of dataCompressedSize and dataDecompressedSize
std::uint32_t dataDecompressedSize;
std::uint8_t data[dataCompressedSize - 4 - 4];
// dataCompressedSize and dataDecompressedSize are part of the compressed data so we subtract their size from the data array
// Data is compressed using Asobo's Order 1 Arithmetic Coding
std::uint8_t zeros[199996 - dataCompressedSize - 1];
// Filled with 0x00
// Used to pad the SaveGameData structure size to 199996 bytes
std::uint8_t version;
// Always equals 61
};
The following is an 010 Editor template for the decompressed save data. One of the unnamed fields must be the trick count (when the guy does weird shit with his legs on bikes and quads).
struct AlignedCString
{
local int len = ReadStringLength(FTell());
char str[len];
local int a = 4;
local int x = FTell() + 1;
local int r = x % a;
FSeek(r ? x + (a - r) : x);
};
struct
{
AlignedCString SectionName;
uint32 version; // always 636
byte x[66];
int32 fuel;
int32 total_fuel_drums_found;
int32 camera_distance;
int32 y;
int32 hub_index;
int32 yy;
int32 selected_vehicle_index;
int32 unk2;
int32 head_type_index;
int32 chest_type_index;
int32 legs_type_index;
int32 head_livery_index;
int32 chest_livery_index;
int32 legs_livery_index;
int32 body_livery_index;
int32 body_color_index;
byte race_info;
byte ranking_info;
byte speed_meter;
byte gps;
byte length_uint; // miles = 1, km = 0
byte brightness; // 1 = changed, 0 = default
byte padding[2];
float xxx; // always 1
float yyy; // always 0.25
float zzz; // always 1
int32 h; // always 5
int32 distance_covered_in_free_ride_km;
float distance_covered_in_free_ride_m;
int32 distance_covered_in_race_ride_km;
float distance_covered_in_race_ride_m;
int32 distance_covered_on_road_km;
float distance_covered_on_road_m;
int32 distance_covered_off_road_km;
float distance_covered_off_road_m;
float longest_jump;
float highest_jump;
int32 unk4;
uint32 developer_flags; // 0x1 on = hide huds
int32 z;
int32 zzzzz;
int32 zzzz;
int32 sessions_played_and_finished;
int32 sessions_ranked_1st;
byte zz[12];
float max_time_spent_in_air;
float peak_speed; // stored as m/s which is 0.277778 * km/h
int32 number_of_times_heliports_used;
int32 time_played; // milliseconds
int32 ww;
int32 www;
float brightness;
int32 o;
int32 music_volume; // [0-16]
int32 sfx_volume; // [0-16]
byte g[21];
byte x_axis; // 1 = inverted, 0 = normal
short vibrations;
int32 bbbb;
byte b[12];
int32 y_axis;
} SECTION_SAVESTRUCT_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 2000
int vehicles_size;
struct
{
uint32 vehicle_crc32;
byte unlocked;
byte owned;
byte pad0;
byte pad1;
float distance;
} vehicles[vehicles_size];
} SECTION_VEHICLES_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 2344
uint32 datasizebytes;
// data begins
uint32 context_count;
struct Context
{
uint32 actions_size;
struct Action
{
uint32 primary;
uint32 secondary
uint32 controls_index;
} actions[actions_size] <optimize=false>;
} contexts[context_count] <optimize=false>;
// data ends
} SECTION_INPUT;
struct
{
AlignedCString SectionName;
uint32 version; // always 200
int actionsSize;
struct
{
int index;
byte unlocked;
byte completed;
} actions[actionsSize];
} SECTION_TUTORIAL;
struct
{
AlignedCString SectionName;
uint32 version; // always 84
int unlockeds_size;
struct
{
byte unk1;
byte unk2;
} unlockeds[unlockeds_size] <optimize=false>;
} SECTION_HUB_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 540
int hubs_size;
struct
{
int unlockeds_size;
short unlockeds[unlockeds_size] <optimize=false>;
} hubs[hubs_size] <optimize=false>;
} SECTION_VISTAPOINT_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 23440
local int editedRacesSize = 10;
struct
{
uint32 b;
uint32 c;
uint32 d;
byte e;
byte f;
byte g; // 1 if used, 0 otherwise
byte h; // -1 if slot unused
uint32 numUsedCheckpoints;
local int numCheckpoints = 32;
struct
{
float x;
float z;
float y;
uint32 a;
uint32 b;
uint32 c;
float d;
uint32 e;
uint32 f;
} checkpoints[numCheckpoints];
} editedRaces[editedRacesSize] <optimize=true>;
} SECTION_EDITEDRACE_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 21576
uint32 hubs_ssize;
struct
{
uint32 hub_index;
uint32 unk3;
uint32 careers_ssize;
struct
{
byte x[40];
} careers[careers_ssize] <optimize=false>;
uint32 challenges_size;
struct
{
byte x[40];
} challenges[challenges_size] <optimize=false>;
} hubs[hubs_ssize] <optimize=false>;
} SECTION_MISSION_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 1024
uint32 hubs_size;
struct
{
uint32 traffics_size;
struct
{
uint32 crc32;
byte spotted;
byte found;
} traffics[traffics_size] <optimize=false>;
} hubs[hubs_size] <optimize=false>;
} SECTION_TRAFFIC_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 2884
uint32 hubs_size;
struct
{
uint32 liveries_size;
struct
{
uint32 crc32;
byte spotted;
byte found;
} liveries[liveries_size] <optimize=false>;
} hubs[hubs_size] <optimize=false>;
} SECTION_VEHICLES_LIVERIES_INFOS;
struct
{
AlignedCString SectionName;
uint32 version; // always 508
int unlockeds_size;
byte unlockeds[unlockeds_size];
int selected_size;
struct
{
uint32 slot_crc32;
int32 item_index;
} selected[selected_size];
} SECTION_PILOT_LIVERIES_INFOS;
For FMTK Users and Mod Developers
For FMTK Developers
Asobo BigFile Format Specification
Asobo Classes
Animation_Z
Binary_Z
Bitmap_Z
Camera_Z
CollisionVol_Z
Fonts_Z
GameObj_Z
GenWorld_Z
GwRoad_Z
Keyframer*_Z
Light_Z
LightData_Z
Lod_Z
LodData_Z
Material_Z
MaterialAnim_Z
MaterialObj_Z
Mesh_Z
MeshData_Z
Node_Z
Omni_Z
Particles_Z
ParticlesData_Z
RotShape_Z
RotShapeData_Z
Rtc_Z
Skel_Z
Skin_Z
Sound_Z
Spline_Z
SplineGraph_Z
Surface_Z
SurfaceDatas_Z
UserDefine_Z
Warp_Z
World_Z
WorldRef_Z
Asobo File Format Idioms
Asobo CRC32
Asobo LZ Compression
Asobo Arithmetic Coding Compression
Asobo Save Game File Format Specification
Asobo Audio Formats
TotemTech/ToonTech/Zouna/ACE/BSSTech/Opal Timeline
Zouna Modding Resources
Miscellaneous