Skyrim Mod:Save File Format

Mod / Skyrim: Skyrim Mod: File Formats

See File Format Conventions to understand the variables and the data types this specification uses.


FormIDEdit

FormIDs in save files are stored as 3 bytes, rather than the usual 4 byte uint32 formID. These will be referred to as RefID.

RefIDEdit

The lower 22 bits represent the formID value itself, while the upper 2 bits are the type of formID.

Name Type/Size Info
byte0 uint8 The upper two bits represent the type of formID:
  • 0 = An index into the File.formIDArray. If the index value of 0 is given, the formID is 0x00000000, else, index into the array using value - 1.
  • 1 = Default (ie, came from Skyrim.esm)
  • 2 = Created (ie, plugin index of 0xFF)
  • 3 = ???
byte1 uint8
byte2 uint8

For example, the global variable "DragonsAbsorbed" (0x0001C0F2) becomes the bytes: 41 C0 F2

FileEdit

Name Type/Size Info
magic char[13] Constant: "TESV_SAVEGAME"
headerSize uint32 Size of the header.
header Header
screenshotData LE: uint8[3*shotWidth*shotHeight]
SE: uint8[4*shotWidth*shotHeight]
For LE: RGB pixel data of the image.
For SE: RGBA pixel data of the image.
uncompressedLen uint32 Uncompressed length (SE only)
compressedLen uint32 Compressed length (SE only)
formVersion uint8 current as of LE 1.9 and SE 1.5.97 is 74.
pluginInfoSize uint32 Size of the plugin information.
pluginInfo Plugin Info
lightPluginInfo Light Plugin Info Only for SE save games (and formVersion >= 78?). This contains info about ESL plugins.
fileLocationTable File Location Table
globalDataTable1 Global Data[fileLocationTable.globalDataTable1Count] Types 0 to 8.
globalDataTable2 Global Data[fileLocationTable.globalDataTable2Count] Types 100 to 114.
changeForms Change Form[fileLocationTable.changeFormCount]
globalDataTable3 Global Data[fileLocationTable.globalDataTable3Count] Types 1000 to 1005.
formIDArrayCount uint32
formIDArray formID[formIDArrayCount] Not to be confused with RefIDs. These are FormIDs, four bytes in length, little endian.
visitedWorldspaceArrayCount uint32
visitedWorldspaceArray formID[visitedWorldspaceArrayCount] A list of the FormIDs of all worldspaces visited by the player.
unknown3TableSize uint32 Size in bytes of unknown3Table.
unknown3Table Unknown 3 Table

HeaderEdit

Name Type/Size Info
version uint32 Current LE version: 9, supported: 7 - 9, for SE it will be 12. Use this to determine whether or not the save file is for LE or SE.
saveNumber uint32 Save number, used for default name of save file. Presumably this is a counter keeping track of the total number of saves you have made to date.
playerName wstring
playerLevel uint32
playerLocation wstring
gameDate wstring In-game date at the time of saving.
playerRaceEditorId wstring
playerSex uint16
  • 0 = Male
  • 1 = Female
playerCurExp float32 Experience gathered for level up.
playerLvlUpExp float32 Experience required for level up.
filetime FILETIME See the Microsoft Docs for more info on this type.
shotWidth uint32 Screenshot width (in pixels).
shotHeight uint32 Screenshot height (in pixels).
compressionType uint16 (SE only)
  • 0 = None
  • 1 = zLib (appears to not be used, see this from MO2.
  • 2 = LZ4 (Block format)

If compression is present, everything after the compression lengths is compressed.

Plugin InfoEdit

Name Type/Size Info
pluginCount uint8
plugins wstring[pluginCount]


Light Plugin InfoEdit

Note: only found in SE save games

Name Type/Size Info
pluginCount uint16
plugins wstring[pluginCount]

File Location TableEdit

Name Type/Size Info
formIDArrayCountOffset uint32 Absolute offset to the start of File.formIDArrayCount.
unknownTable3Offset uint32 Absolute offset to the start of File.unknown3TableSize.
globalDataTable1Offset uint32 Absolute offset to the start of File.globalDataTable1.
globalDataTable2Offset uint32 Absolute offset to the start of File.globalDataTable2.
changeFormsOffset uint32 Absolute offset to the start of File.changeForms.
globalDataTable3Offset uint32 Absolute offset to the start of File.globalDataTable3.
globalDataTable1Count uint32 The number of Global Data in File.globalDataTable1 (9).
globalDataTable2Count uint32 The number of Global Data in File.globalDataTable2 (15).
globalDataTable3Count uint32 The number of Global Data in File.globalDataTable3 (5 -- bugged).

Note: This count is currently bugged (as of version 112) that it does not include type 1001 (Papyrus) in the count. This causes Skyrim to never read the final type in this table, which is typically type 1005 (Main), thankfully the bug is harmless since this type never has any data.

changeFormCount uint32
unused uint32[15]

Global DataEdit

Name Type/Size Info
type uint32
length uint32
data uint8[length] Format of data depends on its type:

Change FormEdit

Note: the layout of the data section is not a Record as it is in a mod file. Work is in progress documenting changeForm structures here: changeFlags

Name Type/Size Info
formID RefID
changeFlags uint32 A combination of changeFlags that indicates which changes are included in the data.
type uint8

Upper 2 bits represent the size of the data lengths:

  • 0 = uint8
  • 1 = uint16 (> 0xFF)
  • 2 = uint32 (> 0xFFFF)

Lower 6 bits represent the type of form:

  • 0 = 63 (REFR) REFR change form
  • 1 = 64 (ACHR) ACHR change form
  • 2 = 65 (PMIS)
  • 3 = 67 (PGRE)
  • 4 = 68 (PBEA)
  • 5 = 69 (PFLA)
  • 6 = 62 (CELL)
  • 7 = 78 (INFO)
  • 8 = 79 (QUST) QUST change form
  • 9 = 45 (NPC_) NPC_ change form
  • 10 = 25 (ACTI)
  • 11 = 26 (TACT)
  • 12 = 27 (ARMO)
  • 13 = 28 (BOOK)
  • 14 = 29 (CONT)
  • 15 = 30 (DOOR)
  • 16 = 31 (INGR)
  • 17 = 32 (LIGH)
  • 18 = 33 (MISC)
  • 19 = 34 (APPA)
  • 20 = 35 (STAT)
  • 21 = 37 (MSTT)
  • 22 = 42 (FURN)
  • 23 = 43 (WEAP)
  • 24 = 44 (AMMO)
  • 25 = 47 (KEYM)
  • 26 = 48 (ALCH)
  • 27 = 49 (IDLM)
  • 28 = 50 (NOTE)
  • 29 = 105 (ECZN)
  • 30 = 10 (CLAS)
  • 31 = 11 (FACT)
  • 32 = 81 (PACK)
  • 33 = 75 (NAVM)
  • 34 = 120 (WOOP)
  • 35 = 19 (MGEF)
  • 36 = 115 (SMQN)
  • 37 = 124 (SCEN)
  • 38 = 106 (LCTN)
  • 39 = 123 (RELA)
  • 40 = 72 (PHZD)
  • 41 = 71 (PBAR)
  • 42 = 70 (PCON)
  • 43 = 93 (FLST) FLST change form
  • 44 = 46 (LVLN)
  • 45 = 55 (LVLI)
  • 46 = 84 (LVSP)
  • 47 = 66 (PARW)
  • 48 = 22 (ENCH)
version uint8 Current as of Skyrim 1.9 is 74. Older values (57, 64, 73) are also valid.
length1 depends on flags Length of following data.
length2 depends on flags If this value is non-zero, data is compressed. This value then represents the uncompressed length.
data uint8[length1]

Unknown 3 TableEdit

Name Type/Size Info
count uint32
unknown wstring[count]

Xbox 360Edit

The Xbox 360 uses a container for all of its user content. The STFS file system used for the container has been mapped out and files within them can be extracted using tools such as WxPirs or Horizon.

It is entirely possible to use Xbox 360 game saves on the PC version of Skyrim. The only draw back is that the first time a game save is used on the PC version of the game, the preview screenshot is swizzled. Saving the game again once you have it loaded will fix this.

To get your XBOX 360 save. One would use a tool like Horizon to get your game save off of a Xbox 360 formatted drive (such as a USB drive) and extract the Savegame.dat from the Xbox 360 container and rename it to anything ending in ".ess". After this one would put this new ess file in Documents\My Games\Skyrim\Saves and load it in Skyrim as usual.

It is possible to perform this in the reverse direction as well. Rename your savegame.ess to savegame.dat. Then, use Horizon to reinject the save into the save originally transferred from the Xbox 360. You must then rehash and resign your save so it can be used on your Xbox 360. The only drawback of this is the same as the other: the screenshot is swizzled, but it works. This can be used to fix quest related bugs with the console if you have access to both a PC and Xbox 360 version of the game.