Save file format: Difference between revisions

From Arx Libertatis Wiki
Jump to navigation Jump to search
No edit summary
 
(16 intermediate revisions by the same user not shown)
Line 1: Line 1:
This page describes the save format used by Arx Fatalis as well as Arx Libertatis extensions. All integers are encoded in little-endian byte order. Types are the same as in <code>platform/Platform.h</code> - <b>s</b> (signed integer) / <b>u</b> (unsigned integer) / <b>f</b> (float), followed by the number of bits. Arrays are denoted by brackets like in c++.
This page describes the save format used by Arx Fatalis and Arx Libertatis.


== Arx save file container (.sav) ==
See [[Common file format types]] for a description of the type names used here.


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 <code>SaveBlock</code> class (<code>io/SaveBlock.h</code>)
Save files are stored in a [[Save file container format|generic container]] that maps names (arbitrary strings) to chunks of data. This page only describes the format of the files inside that container.


=== Header ===
These structures are filled and parsed in <code>src/scene/ChangeLevel.cpp</code> and described in <code>src/scene/SaveFormat.h</code> in Arx Libertatis.
 
== Savegame info (pld) ==


The file header starts at byte position 0 - there is no magic number.
The savegame info file called "pld" consist of a single structure:


{| class="wikitable"
{| class="wikitable"
! Type
! Type
! Description
! Description
|-
| <b>f32</b>
| Savegame data version
|-
| <b>char[256]</b>
| Savegame name
|-
| <b>s32</b>
| Current level
|-
|-
| <b>u32</b>
| <b>u32</b>
| File table offset
| Current time
|-
| <b>1024 B</b>
| <i>(padding - always 0)</i>
|}
|}


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.
Savegame data version specifies the version number of this savegame info structure. Currently this value is always <code><b>1.005f</b></code>.
 
The version is followed by the user-supplied name for the savegame. The special name <code>"<b>ARX_QUICK_ARX</b>"</code> is used for quicksaves. Arx Fatalis and older Arx Libertatis versions also used <code>"<b>ARX_QUICK_ARX1</b>"</code> for the second quicksave.


=== File table ===
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 <code>"lvl"</code> to get the level file (<code>1</code> becomes <code>"lvl001"</code>)


The file table starts with a file table header:
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. Game-type may be paused or slowed down/sped up by spells.


==== File table header ====
== Player state (player) ==
 
<font color=red><b>TODO</b></font>
 
== Global script state (globals) ==
 
<font color=red><b>TODO</b></font>
 
== Level state (lvl<i><number></i>) ==
 
To get the filename for the state of a level pad the level number to 3 digits with leading zeros and prepended that with <code>"lvl"</code>. (<code>1</code> becomes <code>"lvl001"</code>)
 
=== Header ===


{| class="wikitable"
{| class="wikitable"
! Type
! Type
! Description
! Description
|-
| <b>f32</b>
| Level status version
|-
|-
| <b>u32</b>
| <b>u32</b>
| Format version
| Game time
|-
| <b>s32</b>
| Interactive object count
|-
| <b>s32</b>
| Path count
|-
| <b>s32</b>
| Light status count
|-
|-
| <b>u32</b>
| <b>s32</b>
| Number of file entries
| Ambiance data size
|}
 
Currently, the following version numbers are defined.
 
{| class="wikitable"
! Value
! Name
! Description
|-
|-
| <code>0x00010000</code>
| <b>gmods</b>
| <code>SAV_VERSION_LEGACY</code>
| Saved graphics modes
| Legacy version
|-
|-
| <code>0x00010001</code>
| <b>gmods</b>
| <code>SAV_VERSION_RELEASE</code>
| Current graphics modes
| Current Arx Fatalis version
|-
|-
| <code>0x00020000</code>
| <b>gmods</b>
| <code>SAV_VERSION_DEFLATE</code>
| Desired graphics modes
| Added support for different compression algorithms (Arx Libertatis extension)
|-
|-
| <code>0x00020001</code>
| <b>8192 B</b>
| <code>SAV_VERSION_NOEXT</code>
| <i>(padding - always 0)</i>
| 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 <code>SAV_VERSION_LEGACY</code> the first file entry should be ignored.
<code>Level status version</code> specifies the version number of this level status file. Currently this value is always <code><b>1.005f</b></code>.


==== File table entries ====
<code>Game time</code> is the in-game time in milliseconds when this level was last saved.


The <code><b>gmods</b></code> type contains:
{| class="wikitable"
{| class="wikitable"
! Type
! Type
! Description
! Description
|-
|-
| null-terminated string
| <b>s32</b>
| File name
| Flags
|}
 
Each file table entry is preceded by a null-terminated string - the file name. Versions older than <code>SAV_VERSION_NOEXT</code> 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 <code>SAV_VERSION_DEFLATE</code>:
 
{| class="wikitable"
! Type
! Description
|-
|-
| <b>u32</b>
| <b>rgb32f</b>
| Stored (compressed) file size - This can be ignored and calculated from chunk sizes.
| Depth color
|-
|-
| <b>u32</b>
| <b>f32</b>
| Number of chunks - 0 means 1!
| Clip distance
|-
|-
| <b>u32</b>
| <b>136 B</b>
| Useless data. This can be safely ignored
| <i>(padding - always 0)</i>
|}
|}


For <code>SAV_VERSION_DEFLATE</code> and newer:
<code>Flags</code> is a bitwise combination of:
 
{| class="wikitable"
{| class="wikitable"
! Type
! Flag
! Description
! Description
|-
|-
| <b>u32</b>
| 1<<<b>0</b>
| Uncompressed file size
| Use depth color
|-
| <b>u32</b>
| Number of chunks
|-
|-
| <b>u32</b>
| 1<<<b>1</b>
| Compression algorithm
| Use clip distance
|}
|}


Currently, the following compression algorithms are defined.
<code>Depth color</code> is used as the fog / background color for the level.


{| class="wikitable"
<code>Clip distance</code> is used to adjust the camera far plane.
! Value
! Name
! Description
|-
| <code>0</code>
| <code>Stored</code>
| No compression. Data is stored as-is.
|-
| <code>1</code>
| <code>ImplodeCrypt</code>
| Data is compressed using the PKWARE implode library. The result is bitwise negated.
|-
| <code>2</code>
| <code>Deflate</code>
| Data is compressed using the [http://zlib.net/ ZLIB] deflate format.
|}


Code to decompress PKWARE implode-encoded data can be found in [https://github.com/madler/zlib/tree/master/contrib/blast blast.c in the contrib directory of the zlib source].
<code>Current graphics modes</code> are the active modes and <code>desired graphics modes</code> are modes that the game is fading to.


Versions older than SAV_VERSION_DEFLATE always use the <code>ImplodeCrypt</code> algorithm. To allow changing save files without decompressing all data, the value <code>0xffffffff</code> may be used to indicate that the uncompressed size is not known if (and only if) the compression algorithm is <code>ImplodeCrypt</code>.
The header is followed by <code>interactive object count</code> object index entries, <code>path count</code> path status entries, <code>ambiance data size</code> bytes of ambiance data and <code>light status count</code> light status entries.


The rest of the file entry is a list of as many chunk offsets as specified. For versions older than <code>SAV_VERSION_DEFLATE</code>, 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.
=== Object Index Entries ===


===== Chunk offsets =====
<font color=red><b>TODO</b></font>


{| class="wikitable"
=== Path Status Entries ===
! Type
! Description
|-
| <b>u32</b>
| Chunk size
|-
| <b>u32</b>
| 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.
<font color=red><b>TODO</b></font>


== Saved structures ==
=== Ambiance Data ===


These structures are filled and parsed in <code>src/scene/ChangeLevel.cpp</code> and described in <code>src/scene/SaveFormat.h</code> in Arx Libertatis.
<font color=red><b>TODO</b></font>


=== Savegame info (pld) ===
=== Light Status Entries ===


The savegame info file called "pld" consist of a single structure:
<font color=red><b>TODO</b></font>


{| class="wikitable"
== Entity state (<i><class></i>_<i><instance></i>) ==
! Type
! Description
|-
| <b>f32</b>
| Savegame data version
|-
| <b>u8[256]</b>
| Savegame name
|-
| <b>s32</b>
| Current level
|-
| <b>u32</b>
| Current time
|-
| <b>s32[32]</b>
| <i>(padding - always 0)</i>
|}


Savegame data version specifies the version number of the data structures stored in this save file (not the version number of the savefile container). Currently this value is always <code><b>1.005f</b></code>.
<font color=red><b>TODO</b></font>


The version is followed by the user-supplied name for the savegame, padded to 256 bytes with null characters. Strings longer that 256 characters are not allowed. The original Arx Fatalis code did not define an encoding for this name and presumably only allowed ASCII characters. Arx Libertatis interprets this name as an UTF-8 encoded string. The special name <code>"<b>ARX_QUICK_ARX</b>"</code> is used for quicksaves. Arx Fatalis and older Arx Libertatis versions also used <code>"<b>ARX_QUICK_ARX1</b>"</code> for the second quicksave.
= Issues =


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 zeroes and prepended with <code>"lvl"</code> to get the level file (<code>1</code> becomes <code>"lvl001"</code>)
== Unsaved state ==


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.
The following things are not included in save files:


=== Player state (player) ===
* Active spells (must be cast again in {{Event|reload}} events)
* Arrows shot by the player
* Gibs (only live for a very short duration anyway)


TODO
== Asset references ==


=== Global script state (globals) ===
=== Script timers ===


TODO
Script timers reference byte positions in [[Arx scripting language|.asl script files]]. If the scripts are modified between saving and loading the byte position is not adjusted.


=== Level state (lvl???) ===
=== Linked entities ===


TODO
For linked entities the vertex indices of the linked action points are stored instead of the action point names. If the mesh files are edited between saving and loading the indices may not refer to the intended vertices.


=== Interactive object state ===
== String length ==


TODO
Most strings are stored in fixed-length arrays. This includes entity IDs.

Latest revision as of 19:15, 24 April 2020

This page describes the save format used by Arx Fatalis and Arx Libertatis.

See Common file format types for a description of the type names used here.

Save files are stored in a generic container that maps names (arbitrary strings) to chunks of data. This page only describes the format of the files inside that container.

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. Game-type may be paused or slowed down/sped up by spells.

Player state (player)

TODO

Global script state (globals)

TODO

Level state (lvl<number>)

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

Entity state (<class>_<instance>)

TODO

Issues

Unsaved state

The following things are not included in save files:

  • Active spells (must be cast again in reload events)
  • Arrows shot by the player
  • Gibs (only live for a very short duration anyway)

Asset references

Script timers

Script timers reference byte positions in .asl script files. If the scripts are modified between saving and loading the byte position is not adjusted.

Linked entities

For linked entities the vertex indices of the linked action points are stored instead of the action point names. If the mesh files are edited between saving and loading the indices may not refer to the intended vertices.

String length

Most strings are stored in fixed-length arrays. This includes entity IDs.