Save file format
This page describes the save format used by Arx Fatalis as well as Arx Libertatis extensions.
See Common file format types for a description of the type names used here.
Arx save file container (.sav)
Save files are stored in a generic container that maps names (arbitrary strings) to chunks of data. Arx Libertatis adds two extensions to the vanilla Arx Fatalis .sav format. The .sav container format can be read and written using the SaveBlock
class (io/SaveBlock.h
)
Header
The file header starts at byte position 0 - there is no magic number.
Type | Description |
---|---|
u32 | File table offset |
The file table offset is the location of the file table (in bytes) relative to the first byte after the header. Add 4 bytes to get the offset relative to the start of the file.
File table
The file table starts with a file table header:
File table header
Type | Description |
---|---|
u32 | Format version |
u32 | Number of file entries |
Currently, the following version numbers are defined.
Value | Name | Description |
---|---|---|
0x00010000
|
SAV_VERSION_LEGACY
|
Legacy version |
0x00010001
|
SAV_VERSION_RELEASE
|
Current Arx Fatalis version |
0x00020000
|
SAV_VERSION_DEFLATE
|
Added support for different compression algorithms (Arx Libertatis extension) |
0x00020001
|
SAV_VERSION_NOEXT
|
Removed ".sav" suffix from internal filenames (Arx Libertatis extension) |
The file table is followed by the specified number of file entries. For save files with version SAV_VERSION_LEGACY
the first file entry should be ignored.
File table entries
Type | Description |
---|---|
c string | Filename |
Each file table entry is preceded by a null-terminated string - the file name. Versions older than SAV_VERSION_NOEXT
store file names case-insensitively and append ".sav". When loading such versions, the filename should be converted to lowercase and the ".sav" extension removed.
For versions older than SAV_VERSION_DEFLATE
:
Type | Description |
---|---|
u32 | Stored (compressed) file size - This can be ignored and calculated from chunk sizes. |
u32 | Number of chunks - 0 means 1! |
u32 | Useless data. This can be safely ignored |
For SAV_VERSION_DEFLATE
and newer:
Type | Description |
---|---|
u32 | Uncompressed file size |
u32 | Number of chunks |
u32 | Compression algorithm |
Currently, the following compression algorithms are defined.
Value | Name | Description |
---|---|---|
0
|
Stored
|
No compression. Data is stored as-is. |
1
|
ImplodeCrypt
|
Data is compressed using the PKWARE implode library. The result is bitwise negated. |
2
|
Deflate
|
Data is compressed using the ZLIB deflate format. |
Code to decompress PKWARE implode-encoded data can be found in blast.c in the contrib directory of the zlib source.
Versions older than SAV_VERSION_DEFLATE always use the ImplodeCrypt
algorithm. To allow changing save files without decompressing all data, the value 0xffffffff
may be used to indicate that the uncompressed size is not known if (and only if) the compression algorithm is ImplodeCrypt
.
The rest of the file entry is a list of as many chunk offsets as specified. For versions older than SAV_VERSION_DEFLATE
, the actual number of chunks is always 1 or more, even if the file entry says 0. The concatenation of the chunks referenced by these offsets makes up the compressed file data.
Chunk offsets
Type | Description |
---|---|
u32 | Chunk size |
u32 | Chunk offset |
The chunk offset is the location of the chunk data (in bytes) relative to the first byte after the header. Add 4 bytes to get the offset relative to the start of the file. The chunk size is given in bytes. There is no guarantee that all parts of the .sav file are used in chunks or the file table.
Saved structures
These structures are filled and parsed in src/scene/ChangeLevel.cpp
and described in src/scene/SaveFormat.h
in Arx Libertatis.
Savegame info (pld)
The savegame info file called "pld" consist of a single structure:
Type | Description |
---|---|
f32 | Savegame data version |
char[256] | Savegame name |
s32 | Current level |
u32 | Current time |
1024 B | (padding - always 0) |
Savegame data version specifies the version number of this savegame info structure. Currently this value is always 1.005f
.
The version is followed by the user-supplied name for the savegame. The special name "ARX_QUICK_ARX"
is used for quicksaves. Arx Fatalis and older Arx Libertatis versions also used "ARX_QUICK_ARX1"
for the second quicksave.
The current level specifies the number of the level in which the player resided when the savegame was last updated. This number can be padded to 3 digits with leading zeros and prepended with "lvl"
to get the level file (1
becomes "lvl001"
)
The current time is the in-game time when the savegame was last updated. This is the total number of in-game milliseconds since the game start.
Player state (player)
TODO
Global script state (globals)
TODO
Level state (lvl???)
To get the filename for the state of a level pad the level number to 3 digits with leading zeros and prepended that with "lvl"
. (1
becomes "lvl001"
)
Header
Type | Description |
---|---|
f32 | Level status version |
u32 | Game time |
s32 | Interactive object count |
s32 | Path count |
s32 | Light status count |
s32 | Ambiance data size |
gmods | Saved graphics modes |
gmods | Current graphics modes |
gmods | Desired graphics modes |
8192 B | (padding - always 0) |
Level status version
specifies the version number of this level status file. Currently this value is always 1.005f
.
Game time
is the in-game time in milliseconds when this level was last saved.
The gmods
type contains:
Type | Description |
---|---|
s32 | Flags |
rgb32f | Depth color |
f32 | Clip distance |
136 B | (padding - always 0) |
Flags
is a bitwise combination of:
Flag | Description |
---|---|
1<<0 | Use depth color |
1<<1 | Use clip distance |
Depth color
is used as the fog / background color for the level.
Clip distance
is used to adjust the camera far plane.
Current graphics modes
are the active modes and desired graphics modes
are modes that the game is fading to.
The header is followed by interactive object count
object index entries, path count
path status entries, ambiance data size
bytes of ambiance data and light status count
light status entries.
Object Index Entries
TODO
Path Status Entries
TODO
Ambiance Data
TODO
Light Status Entries
TODO
Interactive object state
TODO