Saves (GTA SA)
Contents
- 1 Introduction
- 2 Location and Format Overview
- 3 Format Details
- 3.1 Data Blocks
- 3.1.1 Block 0: Miscellaneous
- 3.1.2 Block 1: Script
- 3.1.3 Block 2: Objects
- 3.1.4 Block 3: Garages
- 3.1.5 Block 4: (Unknown)
- 3.1.6 Block 5: Disabled Pathnode Cubes
- 3.1.7 Block 6: Pickups
- 3.1.8 Block 7: (Unused)
- 3.1.9 Block 8: Restart Locations
- 3.1.10 Block 9: Radar Blips
- 3.1.11 Block 10: Zones
- 3.1.12 Block 11: Gang weapons
- 3.1.13 Block 12: Car Generators
- 3.1.14 Block 13: (Unused)
- 3.1.15 Block 14: (Unused)
- 3.1.16 Block 15: Player data
- 3.1.17 Block 16: Player Stats
- 3.1.18 Block 17: (Unknown)
- 3.1.19 Block 18: (Unknown)
- 3.1.20 Block 19: (Unknown)
- 3.1.21 Block 20: (Unknown)
- 3.1.22 Block 21: (Unknown)
- 3.1.23 Block 22: (Unknown)
- 3.1.24 Block 23: (Unknown)
- 3.1.25 Block 24: (Unknown)
- 3.1.26 Block 25: ENEX Connections
- 3.1.27 Block 26: (Unknown)
- 3.1.28 Block 27: (Unknown)
- 3.2 Padding
- 3.3 Checksum
- 3.1 Data Blocks
Introduction
This article deals with the format of a saved game file for Grand Theft Auto: San Andreas (GTASA). It is specifically geared towards the PC version(s) but much of it may be applicable to console versions too.
Location and Format Overview
By default, GTASA places its saved game files into the folder "GTA San Andreas User Files" which is located in the current user's Documents folder. The location of this folder varies depending upon the version of Windows installed. Some typical locations for a user with an account named "Fred" would be:
- C:\My Documents\GTA San Andreas User Files -- Windows 98 Example
- C:\Documents and Settings\Fred\My Documents\GTA San Andreas User Files -- Windows XP Example
- C:\Users\Fred\Documents\GTA San Andreas User Files -- Windows Vista Example
Obviously those locations can vary based upon different Windows configurations or installation options. Note also that the executable can be modified to use a different file location through the use of a hex editor and special registry key in a process outlined at GTAForums
The save files themselves are named in the format GTASAsfX.b where X represents the in-game slot number. So, the game saved in slot 1 will be stored in the save file GTASAsf1.b and the game saved in slot 5 will be stored in the save file GTASAsf5.b. There are 8 slots available in the game (1-8). GTASA save files are always 0x31800 bytes long (202,752 in decimal) and are not compressed or encoded in any way.
Format Details
A GTASA save file consists of 28 "blocks" of data followed by some duplicated data for padding and then ending with a checksum value. Each of these elements is described below.
Data Blocks
Each data block consists of the 5 characters BLOCK followed by a variable amount of data; in general, each block has its own unique internal format. The format descriptions in this article only deal with those internal block formats which follow the initial BLOCK identifier and all offsets start at the byte following the BLOCK identifier for the given block.
Block 0: Miscellaneous
Game "meta-information" giving the overall state of things. This block has a constant length of 0x138 bytes
OFFSET TYPE DESCRIPTION 0x0000 dword version ID (checksum of a string describing the time of compilation. See note 1 below) 0x0004 char[100] save name (long names are truncated on the save/load screen. See note 2 below) 0x0068 byte current mission pack 0x006C dword current town (?) 0x0070 float[3] camera coordinates (x,y,z) 0x007C dword length (ms) of in-game minute 0x0080 dword weather timer 0x0084 byte current month 0x0085 byte current month day 0x0086 byte game hour 0x0087 byte game minute 0x0088 byte weekday 0x0089 byte current month (copy) 0x008A byte current month day (copy) 0x008B byte hour (copy) 0x008C byte minute (copy) 0x008D byte time copy flag (See note 3 below) 0x008E word (unknown) 0x0090 byte has ever cheated flag 0x0094 dword global timer 0x0098 float game speed 0x009C float (unknown) (FPS?) 0x00A0 float tick time (time of an iteration of the major game loop) 0x00A4 dword (unknown) 0x00A8 word (unknown) 0x00AA word (unknown) 0x00AC word weather ID 0x00B0 dword (unknown) 0x00B4 dword (unknown) 0x00B8 dword (unknown) 0x00BC dword vehicle camera view (opcode 09AD) 0x00C0 dword onfoot camera view 0x00C4 dword current interior 0x00C8 byte (unknown) 0x00CC dword original interior color (?) 0x00D0 byte interior color flag (?) 0x00D4 dword (unknown) 0x00D8 dword changed interior color (?) 0x00DC dword (unknown) 0x00E0 byte riot mode flag (opcode 06C8) 0x00E1 byte (unknown) 0x00E4 dword max wanted level 0x00E8 dword max chaos (See note 4 below) 0x00EC byte (unknown) 0x00ED byte is german lang (?) (opcode 040C) 0x00EE byte (unknown) 0x011C byte times left to display a cinematic camera help (see note 5 below) 0x011E word SYSTEMTIME wYear 0x0120 word SYSTEMTIME wMonth 0x0122 word SYSTEMTIME wDayOfWeek 0x0124 word SYSTEMTIME wDay 0x0126 word SYSTEMTIME wHour 0x0128 word SYSTEMTIME wMinute 0x012A word SYSTEMTIME wSecond 0x012C word SYSTEMTIME wMilliseconds 0x0130 dword (unknown) 0x0134 byte is vehicle stealing help shown (See note 6 below) 0x0135 byte (unknown) 0x0136 byte (unknown)
Notes:
- Version 2.0 of GTASA will not load a save file if the Version ID String does not match its own Version ID String. Thus if a game was played on a version 1.x exe using the exact same set of mission scripts as a version 2.0 installation, the version 2.0 game will refuse to load the save unless this ID is changed. Version 1.x exes make no Version ID String check and will attempt to load any non-corrupted save. Some known Version ID String values (listed as consecutive bytes):
- 0x75 0x81 0xDA 0x35 -- Version 1.00 Unmodified EXE
- 0x83 0xE5 0xF3 0x65 -- Version 1.00 Modified EXE
- 0x58 0xBE 0x6E 0x9A -- Version 1.01 Unmodified EXE
- 0x5E 0x76 0x45 0x93 -- Version 1.01 Modified EXE
- 0xF6 0x8D 0x14 0xFD -- Version 2.00 Unmodified EXE
- While the save name can be changed here to pretty much anything, that name will not persist the next time the game is saved, even if no missions were completed during the play session. This is because each time the game is saved this name string is reset based upon the GXT entry for the Last Mission Passed key stored in Block 15.
- Time copy flag shows whether the time data was saved using opcode 0253.
- Chaos is a value need to be gained to get one more star. MaxChaos is a limit for current wanted level.
- This is a number of how much times the cinematic camera help (about switching display modes) will be shown. Initially this value equals to 2. When it reaches zero, the help does not appear on cinematic camera enabling.
- This is a flag, which is set to 1 when player first time stealing a vehicle and get a help message about it, to prevent displaying this message again.
Block 1: Script
Information pertaining to the Mission Scripts in use when the game was saved. Includes all global variables and information about running threads including thread pointers and local variables. A minor size difference between the MAIN section of the version 1 and version 2 scripts is the primary cause of incompatibility between version 1 and version 2 saves because it forces the other threads to be at slightly different memory locations. One can adjust the thread pointers in this block and (if converting from 1 to 2) the Version ID String from block 0 to convert a save between the two versions; this applies to either completely unmodded or identically-modded installations of v1 and v2.
As the first section in this block can vary in size, offsets given are from the current section.
OFFSET TYPE DESCRIPTION 0x0000 dword Size of Global Variable space 0x0004 dword[] Global Variable Space -- every var is 4 bytes; the types can vary ... 0x0000 byte[2306] (Unknown) -- Info related to various opcodes ... 0x0000 dword Number of Running Threads 0x0004 Thread[] Thread structures -- each is 0x106 bytes in size; see details below
Thread Structure: 0x00 word Index/Handle 0x02 byte[224] Thread Memory Dump -- see details below 0xE2 byte[36] Relative Addresses -- see details below
Thread Memory Dump: 0x00 dword Next Pointer 0x04 dword Previous Pointer 0x08 char[8] Thread Name 0X10 dword Absolute Base Address 0x14 dword Absolute IP 0x18 dword[8] Absolute Return Stack 0x38 word Stack Pointer 0x3C dword[32] Local Variables 0xBC dword[2] Local Timers 0xC4 byte (Unknown) 0xC5 byte 'if' statement result 0xC6 byte (Unknown) 0xC7 byte Is External Script 0xC8 byte[4] (Unknown) 0xCC dword Wakeup Time 0xD0 word 'if' paramter 0xD2 byte 'not' flag 0xD3 byte 'wb_check' flag 0xD4 byte[4] (Unknown) 0xD8 dword New script IP -- 0 if absolute IP has been calculated from this 0xdc byte Is Mission 0xdd byte[3] (Unknown)
Relative Addresses: (Necessary here because the absolute addresses used in-game depend on memory layout) 0x00 dword Relative IP 0x04 dword[8] Relative Return Stack
Block 2: Objects
Mission-script placed objects such as doors, etc.
OFFSET TYPE DESCRIPTION 0x0000 byte[552] (Unknown) 0x0228 dword Number of Objects 0x022C Object[] Object structures -- each is 0x3C bytes in size; see details below
Object Structure: 0x00 byte[4] (Unknown) 0x04 dword (Unknown) Possibly Model 0x08 byte[4] (Unknown) 0x0C float[3] Coordinates (x,y,z) 0x18 byte[36] (Unknown)
Block 3: Garages
Information defining all garages (including bomb shops, pay & sprays, etc.) and also describing the cars stored in safehouse garages. This block can vary in size although in the unmodified game it will always be 0x23C7 bytes because there are 50 garages defined. The 80 saved vehicles (4 each in 20 garages) is a fixed number and probably cannot be exceeded. Also, the arrangement of the Garage Car structures in the save is non-intuitive: they follow the pattern Garage 1/Car 1, Garage 2/Car 1, ... Garage 20/Car 1, Garage 1/Car 2, Garage 2/Car 2 ...
OFFSET TYPE DESCRIPTION 0x0000 dword Number of Garages 0x0004 byte[35] (Unknown) 0x0027 GrgCar[20][4] Garage Car structures -- each is 0x40 bytes in size; see details below 0x1427 Garage[] Garage structures -- each is 0x50 bytes in size; see details below
Garage Car Structure (GrgCar): 0x00 float[3] Coordinates (x,y,z) 0x0c byte[52] (Unknown)
Garage Structure: 0x00 byte Garage Type 0x01 byte[3] (Unknown) 0x04 float[3] Coordinates (x,y,z) Possibly Lower Left Front 0x10 float[4] Rotation (Quaternion Rx, Ry, Rz, Rw) 0x20 float Top Z Coordinate 0x24 float Width 0x28 float Depth 0x2c float (Unknown) X 0x30 float (Unknown) X 0x34 float (Unknown) Y 0x38 float (Unknown) Y 0x3c float (Unknown) 0x40 float (Unknown) 0x44 char[8] Garage Name 0x4c word (Unknown) Possibly Original Type
Block 4: (Unknown)
Unknown data. Block can vary in size depending on number of entries; number of entries may be zero.
OFFSET TYPE DESCRIPTION 0x0000 dword Number of Entries 0x0004 byte[7] (Unknown) 0x000b Blk4Entry[] Entry structures -- each is 0x10 bytes in size; details unknown
Block 5: Disabled Pathnode Cubes
0 dword count 4 entries Entry structure: 0 float[6] x1,x2,y1,y2,z1,z2 18 byte[4] bools that somehow indicate which pathtypes are enabled 1c end
Block 6: Pickups
0 Pickup[620] pickups 4d80 word 4d82 byte 4d83 dword[20] 4dd3 end
Pickup structure: 8 dword ammo 10 word[3] x,y,z, all multiplied by 8 18 word model 1c byte type 20 end
Block 7: (Unused)
(Usually empty)
Block 8: Restart Locations
---- wasted: 0 word count 2 restart structures ---- busted: 0 word count 2 restart structures ---- unknown things: 0 some bytes, floats, and dwords 37 end Restart structure: 0 float[3] coords c float heading 10 dword island 14 end
Block 9: Radar Blips
0 Blip[175] blips
Blip structure: 8 float[3] coords 28 end
Block 10: Zones
4 word count for first array 6 word count for second array 8 word count for third array a end ---- the three arrays: See structure descriptions below. First = info.zon, third = map.zon. ---- unknown: 68 end
First and third array structure: 0 char[8] zone name 8 char[8] zone group name 10 word[6] x1,y1,z1,x2,y2,z2 (rounded to ints) 1c word id 1e byte type 1f byte island 20 end Second array structure: 11 end
Block 11: Gang weapons
0 byte unused 4 dword weaponID A 8 dword weaponID B 0c dword weaponID C
Notes:
- Blocks count 10
- Data can be changed by opcode 0237
Block 12: Car Generators
0 dword count 6 car generators ---- numberplates: 0 dword num entries used 4 Numplate[15] number plates f4 end
Car generator structure: 0 word handle (0..499) 2 word model 4 byte[2] colors 6 word[3] x,y,z, all multiplied by 8 c byte heading/360*256 d byte alarm chance e byte locked chance f byte flags: bit 1 = belongs to player 12 word monetary value 16 dword timer 1c word cars to generate 22 end Numplate structure: 0 dword car generator handle 4 char[8] numberplate string 10 end
Block 13: (Unused)
(Usually Empty)
Block 14: (Unused)
(Usually Empty)
Block 15: Player data
00 dword size of block (always 28h) 04 dword money 08 word (unknown) 0A byte is wasted_or_busted flag 0C dword (unknown) 10 dword amount of money shown on screen ... 20 byte infinite run (opcode 0330) 21 byte (unknown) 22 byte fireproof (055D) ... 2c end
Block 16: Player Stats
0 float[82] float stats (numbered 0..81 in scm) 148 dword[223] int stats (numbered 120..342 in scm) 4c4 dword[32] 544 char[8] last mission passed (gxt key) 54c byte[56] 584 dword[100] 714 byte[128] 794 end
Block 17: (Unknown)
0 dword entries used 4 byte[32][210] entries 1a44 end
Block 18: (Unknown)
66cc end
Block 19: (Unknown)
280 end
Block 20: (Unknown)
0 dword size 4 bytes
Block 21: (Unknown)
0 dword 4 byte[255] 103 end
Block 22: (Unknown)
0 dword count 4 entries (8 bytes each) ---- 0 dword size 4 bytes
Block 23: (Unknown)
0 dword size of block (always 58h) 5c end
Block 24: (Unknown)
0 dword count 4 entries (68 bytes each)
Block 25: ENEX Connections
0 dword count 4 array of words ---- Followed by a weird array: 1. Read a word. 2. If it is -1, you've reached the end of this block. 3. Otherwise, it's an index. Read two more words for this entry and go back to 1.
Block 26: (Unknown)
0 Structure[14] ee0 byte[28] efc end
Structure: 0 byte[20] 14 dword[8] 34 dword[40] d4 dword[15] 110 end
Block 27: (Unknown)
0 byte[28][5] structures from opcode 0a40 8c end
Padding
Following the last data block is a variable amount of padding. Since every save file is exactly 0x31800 bytes in length this padding is necessary to fill the space between the data blocks which start the file and the checksum value which ends it. Because GTASA internally uses a buffer of 0xC800 bytes for writing a save, each byte of padding data is simply a repetition of the data located 0xC800 bytes before it. While it is not strictly necessary to follow this convention for the padding when writing a modified save file, it is consistent with the original game and makes modifications harder to detect.
Checksum
The final four bytes of a save file are an unsigned integer checksum value. This checksum is simply the sum of all the preceding 0x317FC bytes. If the checksum value does not match the calculated sum of those bytes, the game will consider the save file to be "corrupted" and refuse to load it. Thus, any time you make any changes to a save file you must remember to update the checksum when you are finished.