Oni (folder)/persist.dat: Difference between revisions

correction to statement on free level slots, and various other clarifications
m (+retitle to preserve actual file name)
(correction to statement on free level slots, and various other clarifications)
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Retitle|persist.dat}}
{{UpdatedForOniX|1.0.0}}
As players of Oni are well aware, the game does not allow arbitrary saving ("save anywhere"), but relies on the use of fixed savepoints activated through level scripting by reaching certain places in each level. This means that by setting a maximum number of levels and savepoints for Oni, the developer could store the total state of the player's progress in a single, fixed-size file -- a 206,496 byte file, to be exact. In addition to savepoint data, persist.dat has a header which stores Oni's player settings (besides [[Oni (folder)/key_config.txt|key bindings]]). It also records whether the cheats are enabled (i.e. whether you have beaten the game), and whether you killed Griffin in {{C|13}}.
persist.dat, found next to the game application, is the save-game and preference file for Oni. It can be edited most easily with GUI tools such as [[OSGE]] for Windows and [http://mods.oni2.net/node/155 OniLib] for Mac, though [[OBD]]-style hex-based documentation of this file is given below.


The persist.dat file has nothing to do with Oni's [[Dat|instance files]] despite the ".dat" extension (it looks like Bungie West simply used .dat for every kind of file Oni read and wrote -- saved_film####.dat, ####_corpse.dat, etc., then later on added .raw and then .sep as unique suffixes when they needed to break out the level data .dats).
The persist.dat file has nothing to do with Oni's [[Dat|.dat level files]] despite the ".dat" extension (it looks like Bungie West simply used .dat for every kind of file Oni read and wrote saved_film####.dat, lvl_#_###_corpse.dat, etc. – until they later added .raw and then .sep as unique suffixes when they needed to break out some resource data from levelX_Final.dat).


The original Mac game application and the Omni Group build were for PPC Macs, thus numbers were written big-endian (e.g., the 0x08 field in the header would be 00 0C 7F 5C). This meant that the saved-game files were not interchangeable between PC and Mac versions of Oni. However, with modern Macs running a [[AE:FERAL|native Intel build]], the files are now all in little-endian format.
==Progress saving==
As players of Oni are well aware, the game does not allow arbitrary saving ("save anywhere"), but relies on the use of fixed save points activated by reaching certain places in each level, at which point the level scripting uses the [[BSL]] function <tt>save_game</tt> to mark your progress. This means that by deciding on a maximum number of levels and save points, Bungie West could store the total state of the player's progress in a fixed-size file – 206,496 bytes, to be exact.


The header of the file is 0x60=96 bytes long. It is followed by an array of 400 savepoints, 0x204=516 bytes each, grouped implicitly into 40 levels, 10 savepoints per level. The first 10 savepoints belong to level 0 and are never written to. The savepoints of the original 14 levels follow. This leaves 25 unused levels at the end of the saved-game file.
As you will see below, many aspects of the game world are ''not'' saved in persist.dat; essentially, anything not pertaining to Konoko herself, such as the position of AIs and the presence of power-ups on the ground. What <u>is</u> stored is Konoko's position, health and inventory. Everything else is determined by the level scripting and the game data, and will always be in the same place when that save point is loaded.


Only savepoint names are stored in this file (and they are all named uniformly as "Save Point x" even though they could say anything). The actual level names are taken from the [[ONLD]] files of level 0, except for Chapters 0 and 1: "TCTF Training" (level 1, savepoint 0) and "Syndicate Warehouse" (level 1 savepoint 1) are hard-coded into the engine.  
==Game preferences==
In addition to save point data, persist.dat has a header section which stores Oni's preferences as chosen on the Options screen (note that this omits key bindings since they're stored in [[key_config.txt]]). It also records whether the [[cheats]] are enabled, i.e. whether you have beaten the game (however, cheats are unlocked at all times when playing with the [[Anniversary Edition]] or [[Daodan DLL]] installed or when using the [[FERAL|Intel Mac build]]), as well as whether you killed Griffin in {{C|13}}.
 
==Endianness==
The Windows version of persist.dat stores its numbers in little-endian format. Bungie's original Mac game application and The Omni Group's Mac OS X port were built for PowerPC Macs, thus numbers were written big-endian (e.g., the 0x08 field in the header would be 00 0C 7F 5C). This meant that the save-game files were not compatible between Windows and Mac versions of Oni. However, with modern Macs running a native Intel build, the files are now saved in little-endian format and are thus interchangeable between Windows and Mac Oni.
 
==Overview==
The header of the file is 0x60=96 bytes long. It is followed by an array of 400 save points, 0x204=516 bytes each, grouped implicitly into 40 levels with 10 save points per level for a total of 206,400 bytes. The first 10 save points belong to level 0, which contains global game data rather than a specific level, thus they are never written to.
 
The save points of the game's 14 levels follow, but because the level's internal number, not its Chapter number, is used as the index into persist.dat's level slots, the save-game slots span the first 20 level slots – with 0 being unused, as well as slots 5, 7, 15, 16, and 17 because of the gaps in the numbering of the level''N''_Final.dat files. This leaves 20 unused level slots at the end of the save-game file, besides the 1 + 5 unused slots before that point.
 
Only the names of save points, not levels, are stored in this file (and they are all named uniformly as "Save Point ''n''" even though they could say anything). The level names shown in Oni's Load Game screen come from the ONLD resources in level0_Final, except for Chapter 1's name, "Syndicate Warehouse", which was hard-coded into the engine for a reason explained on the [[ONLD]] page.


==Unlocking more levels==
==Unlocking more levels==
To unlock all possible levels, fill the range 0x08 to 0x28 with "FF". So far this has caused no problems, and allows you to add more levels to the game. Levels will not be visible unless there is a corresponding LevelX_Final.dat in the GameDataFolder, and an ONLD that matches the level number in the level0_final.dat. Levels above 39 are not currently unlockable due to the 40-level savepoint limit in the persist.dat (probably reflecting an underlying engine restriction).
To unlock all possible levels, fill the range 0x08 to 0x28 with "FF". So far this has caused no problems, and allows you to add more levels to the game. Levels will not be visible unless there is a corresponding level''N''_Final.dat in the GameDataFolder and an ONLD which matches this level number is found in level0_Final.dat. Levels above 39 are not unlockable due to the 40-level save point limit in the persist.dat.


==Header==
==Header data==
[[Image:Persist_header.gif]]
[[Image:Persist_header.gif]]


Line 20: Line 32:
{{OBDtr| 0x00 | int32 |FF0000| 0F 00 00 00 | 15        | version }}
{{OBDtr| 0x00 | int32 |FF0000| 0F 00 00 00 | 15        | version }}
{{OBDtr| 0x04 | int32 |FF0000| 0E 0B D0 D0 | 0xD0D00B0E | signature }}
{{OBDtr| 0x04 | int32 |FF0000| 0E 0B D0 D0 | 0xD0D00B0E | signature }}
{{OBDtr| 0x08 | int32 |FF0000| 5C 7F 0C 00 | 0x000C7F5C | level unlock flag for levels 0-31; each level has a corresponding bit:
{{OBDtr| 0x08 | int32 |FF0000| 5C 7F 0C 00 | 0x000C7F5C | level unlock flags for levels 0-31; each level has a corresponding bit:
:0x'''01''' 00 00 00 - level 0 (always unlocked, ignored)
:0x'''01''' 00 00 00 - level 0 (ignored; always unlocked)
:0x'''02''' 00 00 00 - level 1 (always unlocked, ignored)
:0x'''02''' 00 00 00 - level 1 (ignored; always unlocked)
:0x'''04''' 00 00 00 - level 2
:0x'''04''' 00 00 00 - level 2
:...
:...
:0x00 00 '''08''' 00 - level 19 }}
:0x00 00 '''08''' 00 - level 19 }}
{{OBDtr| 0x0C | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 32-63 }}
{{OBDtr| 0x0C | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 32-63 }}
{{OBDtr| 0x10 | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 64-95 }}
{{OBDtr| 0x10 | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 64-95 }}
{{OBDtr| 0x14 | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 96-127 }}
{{OBDtr| 0x14 | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 96-127 }}
{{OBDtr| 0x18 | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 128-159 }}
{{OBDtr| 0x18 | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 128-159 }}
{{OBDtr| 0x1C | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 160-191 }}
{{OBDtr| 0x1C | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 160-191 }}
{{OBDtr| 0x20 | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 192-223 }}
{{OBDtr| 0x20 | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 192-223 }}
{{OBDtr| 0x24 | int32 |FF0000| 00 00 00 00 |      | level unlock flag for levels 224-255 }}
{{OBDtr| 0x24 | int32 |FF0000| 00 00 00 00 |      | level unlock flags for levels 224-255 }}
{{OBDtr| 0x28 | int32 |FFFF00| 01 00 00 00 |  1  | killed Griffin (0 <nowiki>=</nowiki> no, 1 <nowiki>=</nowiki> yes) }}
{{OBDtr| 0x28 | int32 |FFFF00| 01 00 00 00 |  1  | killed Griffin (0 <nowiki>=</nowiki> no, 1 <nowiki>=</nowiki> yes) }}
{{OBDtr| 0x2C |      |00FF00| FE 1B 00 00 | 7166 | unlocked weapons; one bit for each weapon; the number of corresponding bit is given by the skill index value in the primary firing mode block of each [[ONWC]] }}
{{OBDtr| 0x2C |      |00FF00| FE 1B 00 00 | 7166 | unlocked diary weapon pages, one bit for each weapon; these bits match the skill index values in the primary firing mode block of each [[ONWC]] (see 0x13E in ONWC for the weapon table) }}
{{OBDtr| 0x30 |      |00FFFF| 1F 00 00 00 |  31  | unlocked items; one bit for each item type (hypo, ammo etc.) }}
{{OBDtr| 0x30 |      |00FFFF| 1F 00 00 00 |  31  | unlocked diary item pages; one bit for each item type:
:0x'''01''' 00 00 00 - ballistic ammo
:0x'''02''' 00 00 00 - energy ammo
:0x'''04''' 00 00 00 - hypo
:0x'''08''' 00 00 00 - force shield
:0x'''10''' 00 00 00 - phase cloak
:0x'''20''' 00 00 00 - LSI (unused because LSIs are level-specific and the diary page for an LSI can only be read while it's in your inventory) }}
{{OBDtr| 0x34 |      |FF00FF| 13 00 00 00 |  19  | last read diary page (level) }}
{{OBDtr| 0x34 |      |FF00FF| 13 00 00 00 |  19  | last read diary page (level) }}
{{OBDtr| 0x38 |      |FFC8C8| 01 00 00 00 |  1  | last read diary page (page) }}
{{OBDtr| 0x38 |      |FFC8C8| 01 00 00 00 |  1  | last read diary page (page) }}
Line 49: Line 67:
:0x'''02''' 00 00 00 - invert mouse
:0x'''02''' 00 00 00 - invert mouse
:0x'''04''' 00 00 00 - game won (aka cheats enabled) }}
:0x'''04''' 00 00 00 - game won (aka cheats enabled) }}
{{OBDtr| 0x48 | int32 |FFC8FF| 02 00 00 00 | 2    | difficulty; the following values are possible:
{{OBDtr| 0x48 | int32 |FFC8FF| 02 00 00 00 | 2    | [[Difficulty modes|difficulty]]; the following values are possible:
:0 - easy
:0 - easy
:1 - medium
:1 - medium
:2 - hard }}
:2 - hard }}
{{OBDtr| 0x4C | int16 |FFC800| 20 03      | 800 | resolution: width }}
{{OBDtr| 0x4C | int16 |FFC800| 20 03      | 800 | resolution: width }}
{{OBDtr| 0x4E | int16 |FFC800| 02 58      | 800 | resolution: height }}
{{OBDtr| 0x4E | int16 |FFC800| 02 58      | 600 | resolution: height }}
{{OBDtr| 0x50 | int16 |C800C8| 20 00      | 32  | color depth }}
{{OBDtr| 0x50 | int16 |C800C8| 20 00      | 32  | color depth }}
{{OBDtr| 0x52 |      |C800C8| 00 00      |    | padding }}
{{OBDtr| 0x52 |      |C800C8| 00 00      |    | padding }}
{{OBDtr| 0x54 | float |C87C64| 00 00 00 3F | 0.5 | gamma correction; from 0.0 to 1.0, 0.5 means no correction }}
{{OBDtr| 0x54 | float |C87C64| 00 00 00 3F | 0.5 | gamma correction; from 0.0 to 1.0, 0.5 means no correction }}
{{OBDtr| 0x58 | int32 |B0C3D4| 03 00 00 00 | 3  | last loaded (saved?) level }}
{{OBDtr| 0x58 | int32 |B0C3D4| 03 00 00 00 | 3  | last saved level number (as found in ONLD, i.e., last level of the game is 19 not 14) }}
{{OBDtr| 0x5C | int32 |E7CEA5| 02 00 00 00 | 3  | last saved savepoint }}
{{OBDtr| 0x5C | int32 |E7CEA5| 02 00 00 00 | 3  | last saved save point }}
|}
|}


;Last saved level/SP
:This is the last savepoint that the player triggered while playing the game, which is not necessarily the farthest they've gotten in the game. A player who's beaten Oni and started it over could have a last saved level/SP of 1/1. As shown earlier, it's the level unlock bits at 0x08 which reflect one's total progress in the game. The "last saved" fields are used by Oni to highlight the most recent savepoint in the Load Game screen when the player resumes playing Oni.


;Killed Griffin
;Killed Griffin
:Used in Chapters 13 and 14; set with [[killed_griffen]], read with [[did_kill_griffen]].
:Accessed in Chapters 13 and 14: the flag is set in Ch. 13 with [[killed_griffen]], and it's read in Ch. 14 with [[did_kill_griffen]].
 
 
After this header is an array of 400 savepoints (40 levels, 10 savepoints per level). The size of a savepoint is 516 bytes so the array size is 206,400 bytes.


==Save point data==
After the header is an array of 400 save points (40 levels, 10 save points per level). The size of a save point is 516 bytes so the array size is 206,400 bytes. Below is a sample save point.


==Savepoint==
[[Image:Persist dat.gif]]
[[Image:Persist dat.gif]]


Line 76: Line 95:
{{Table}}
{{Table}}
{{OBDth}}
{{OBDth}}
{{OBDtr2|0x00 | char[64] |FF0000| "Save Point 2" | name of the save point in Load Game dialog }}
{{OBDtr2| 0x00 | char[64] |FF0000| "Save Point 2" | name of the save point in Load Game dialog }}
{{OBDtr| 0x40 | int32    |FFFF00| 01 00 00 00 | 1 | valid (was saved previously), i.e. "Should we display this in Load Game?" (0 <nowiki>=</nowiki> no, 1 <nowiki>=</nowiki> yes) }}
{{OBDtr | 0x40 | int32    |FFFF00| 01 00 00 00 | 1 | valid (was saved previously), i.e. "Should we display this in Load Game?" (0 <nowiki>=</nowiki> no, 1 <nowiki>=</nowiki> yes) }}
{{OBDtr| 0x44 | int32    |00FF00| BE 00 00 00 | 190        | current player health (HP) }}
{{OBDtr | 0x44 | int32    |00FF00| BE 00 00 00 | 190        | current player health (HP) }}
{{OBDtr| 0x48 | int32    |00FFFF| C8 00 00 00 | 200        | max player health (HP) }}
{{OBDtr | 0x48 | int32    |00FFFF| C8 00 00 00 | 200        | max player health (HP) }}
{{OBDtr| 0x4C | float    |FF00FF| AE 20 FB 43 | 502.255310 | x position of the player }}
{{OBDtr | 0x4C | float    |FF00FF| AE 20 FB 43 | 502.255310 | x position of the player }}
{{OBDtr| 0x50 | float    |FF00FF| 03 32 4B 42 | 50.798839  | y position of the player }}
{{OBDtr | 0x50 | float    |FF00FF| 03 32 4B 42 | 50.798839  | y position of the player }}
{{OBDtr| 0x54 | float    |FF00FF| 55 12 25 C4 | -660.286437| z position of the player }}
{{OBDtr | 0x54 | float    |FF00FF| 55 12 25 C4 | -660.286437| z position of the player }}
{{OBDtr| 0x58 | float    |FFC8C8| 80 06 C1 3F | 1.508010  | player facing direction (radians) }}
{{OBDtr | 0x58 | float    |FFC8C8| 80 06 C1 3F | 1.508010  | player facing direction (radians) }}
{{OBDtr| 0x5C | int32    |FFFFC8| 00 00 00 00 | 0          | number of ballistic ammo clips }}
{{OBDtr | 0x5C | int32    |FFFFC8| 00 00 00 00 | 0          | number of ballistic ammo clips }}
{{OBDtr| 0x60 | int32    |C8FFC8| 01 00 00 00 | 1          | number of energy cells }}
{{OBDtr | 0x60 | int32    |C8FFC8| 01 00 00 00 | 1          | number of energy cells }}
{{OBDtr| 0x64 | int32    |C8FFFF| 00 00 00 00 | 0          | shield (percent) }}
{{OBDtr | 0x64 | int32    |C8FFFF| 00 00 00 00 | 0          | shield (percent) }}
{{OBDtr| 0x68 | int32    |FFC8FF| 00 00 00 00 | 0          | invisibility (1/60 seconds) }}
{{OBDtr | 0x68 | int32    |FFC8FF| 00 00 00 00 | 0          | invisibility (1/60 seconds) }}
{{OBDtr| 0x6C | int32    |FFC800| 01 00 00 00 | 1          | number of hypos }}
{{OBDtr | 0x6C | int32    |FFC800| 01 00 00 00 | 1          | number of hypos }}
{{OBDtr| 0x70 | int32    |C800C8| 00 00 00 00 | 0          | door keys}}
{{OBDtr | 0x70 | int32    |C800C8| 00 00 00 00 | 0          | door keys}}
{{OBDtr| 0x74 | int32    |C87C64| 01 00 00 00 | 1          | whether player has [[LSI]] (0 <nowiki>=</nowiki> no, 1 <nowiki>=</nowiki> yes) }}
{{OBDtr | 0x74 | int32    |C87C64| 01 00 00 00 | 1          | whether player has [[LSI]] (0 <nowiki>=</nowiki> no, 1 <nowiki>=</nowiki> yes) }}
{{OBDtr2| 0x78 | char[128]|B0C3D4| ""                      | weapon name (unused) }}
{{OBDtr2| 0x78 | char[128]|B0C3D4| ""                      | weapon name (unused) }}
{{OBDtr | 0xF8 | int32    |FFDDDD| 00 00 00 00 | 0          | weapon ammo (unused) }}
{{OBDtr | 0xF8 | int32    |FFDDDD| 00 00 00 00 | 0          | weapon ammo (unused) }}
Line 99: Line 118:
|}
|}


;Player health
:Storing both the player's current HP and max HP allows the game to scale your health appropriately if the difficulty level is changed between saving the game and restoring from it.


;Weapon slots
;Weapon slots
:Yes, Oni does seem to support saved data for three weapons, even though the player can only carry one in the final game. Perhaps the three weapon slots were planned to allow for, say, [[:Image:Oni_box_art-front.jpg|dual-wielded guns and a holstered weapon]]....
:Yes, Virginia, Oni does seem to support saved data for three weapons, even though the player can only carry one in the final game. Perhaps the three weapon slots were planned to allow for, say, [[Fully Armed Konoko|dual-wielded guns and a holstered weapon]]....


[[Category:Oni binary data docs]]
{{OBD}}[[Category:Game directory map]]