Saves (GTA SA)

From GTAMods Wiki
Revision as of 03:10, 2 September 2007 by Pdescobar (talk | contribs) (Block 1: Script: Additional information/explanation)
Jump to navigation Jump to search

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 String (Checksum of a string describing the time of compilation. See note 1 below)
0x0004  char[100] Save Name String (Long names are truncated on the save/load screen. See note 2 below)
0x0068  byte      Current Missionpack
0x0069  byte[7]   (Unknown)
0x0070  float[3]  Camera Coordinates (x,y,z)
0x007C  dword     Length (ms) of in-game minute
0x0080  dword     Weather Timer
0x0084  byte[2]   (Unknown)
0x0086  byte      Game Hour
0x0087  byte      Game Minute
0x0088  byte[12]  (Unknown)
0x0094  dword     Global Timer
0x0098  float     Game Speed
0x009C  byte[32]  (Unknown)
0x00BC  dword     Current Camera View
0x00C0  byte[36]  (Unknown)
0x00E4  dword     Max Wanted Level
0x00E8  dword     Possible Police Aggression Level
0x00EC  byte[50]  (Unknown)
0x011E  word      SYSTEMTIME year
0x0120  word      SYSTEMTIME month
0x0122  word      SYSTEMTIME wkday
0x0124  word      SYSTEMTIME day
0x0126  word      SYSTEMTIME hour
0x0128  word      SYSTEMTIME min
0x012A  word      SYSTEMTIME sec
0x012C  word      SYSTEMTIME ms
0x012E  byte[10]  (Unknown)

Notes:

  1. 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
  2. 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.

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  struct[]   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

  0                    unknown bytes
228                    end
---- objects
  0    dword           object count
  4                    objects

Object structure:
  4    dword           model
  c    float[3]        coords
 3c                    end

Block 3: Garages

  0    dword           garage count
 27    GrgCar[20][4]   car entries
1427                    garages
GrgCar structure:
  0    float[3]        coords
 12    word            model
 40                    end
Garage structure:
  0    byte            type
  4    float[3]        coords
 10    float[4]        rotation
 20    float[3]        top z, width, depth
 2c    float[4]
 3c    float[2]
 44    char[8]         name
 4c    word            original type ?
 50                    end

Block 4: (Unknown)

  0    dword           count
  b                    entries (16-byte structures)

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: (Unknown)

 (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: (Unknown)

  0    dword[4][10]
 a0                    end

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: (Unknown)

(Usually Empty)

Block 14: (Unknown)

(Usually Empty)

Block 15: (Unknown)

  0    dword           size of block (always 28h)
  4                    some dwords, floats and bytes from the player structure
 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.