ESOMod:Skill Data Format

This describes the format of the file containing skill data for ESO.

Location
The file in question is contained within the depot/Eso0000.dat file. Use the  utility with the following options to extract:

         EsoExtractData.exe /path/to/eso.mnf /path/output/ --extractsubfile combined --archive 0

This should export a bunch of files looking like:

       000\807315.EsoFileData
       000\807315_Uncompressed.EsoFileData
       000\807316.EsoIdData
       000\807317.EsoFileData
       000\807317_Uncompressed.EsoFileData
       000\807318.EsoIdData
       ....

Note that the exact numbers output will likely change after each patch. The skill data file is 'usually' the first such file (smallest ID) but can also be found by searching for the textTool - Spherical Range like:

       grep 'Tool - Spherical Range' *.EsoFileData

Usually the skill data is the only such file containing that string.


Overall Format
The overall file format for the skill data is:

       Header (16 bytes)
       SkillRecords[] (variable number, variable sized)

Note that all data is in Big Endian byte order unless specified.


Header Format
The header is 16 bytes in length at the very start of the file and has the format:

       dword MagicBytes      // FA FA EB EB
       dword Unknown1        // 0x13?
       dword NumRecords      // Number of skill records that follow
       dword Unknown2        // 0x1C8?


Skill Record Format
The skill records immediately follow the header and fill the remaining file. The following format description is accurate as of update 29 (the format does change in some patches). Note that most field names given below are arbitrary.

       struct AbilityDef_Client {
       dword MagicBytes           // #### (23 23 23 23)
       dword Index                // Consecutive number starting at 1
       dword RecordLength1        // Add 32 (0x20) to get the total length of the skill record from the start of the magic bytes
       dword RecordLength2        // RecordLength1, RecordLength2, and RecordLength3 are always the same
        ----------- end of esoExtractData additions
        ----------- start of "AbilityDef(_Client)"
       dword Unknown // these are internal "Definitions ids" that you will find as linked element to other definitions
       dword Unknown // this is consequence of the game data files being a static export from actual Relational Database for development builds of the game.
       dword AbilityId1           // AbilityID (same as in-game), same as abilityId2
       dword RecordLength3
       
       dword AbilityId2


       struct ZoStringBase{
          dword NameLength   // this is not always a dword, it is packed as serialization goes. Usually it will be size in form of Big Endian Short , then string, then null terminator (not counted in size)
                             // a union with word would be pertinent there for future, or even better a variant, as this is extensively used in client code.
          std::vector  Name[NameLength]     // Does not include the terminated nul character (unless you include the following zero field)
       };
       ZoStringBase * AbilityName;

       //byte  Zero                 // Always 0 the null terminator said before. It is not really good to make object from data like that, as these are binary serialization and are quite far from that ingame.
                                    // ingame object deserialized will usually not have (unless nested struct) anything coming from serialization before this+0x10 and the usual vtable mess;
                                    // when it comes to reversing this game, taking in account the very high extent of polymorphism the game uses is crucial so you can properly design long term mimetism object s and behavior.
                                    // and when you intend to specifically describe binary data format like that, using proper tool like Katai struct is always preferable, more true and gives best outcomes.

       word  Zero                 // Always 0
       dword Zero                 // Always 0
       word  Unknown
       word  Unknown
       dword Zero                 // Always 0
       
       dword Unknown2[22]         // Contains lots of interested data (see below)
       byte  Flags[188]           // Values always 00 or 01
       
       dwordlist_t List1          // See Dword List format below (dword size + array of dwords)
       dwordlist_t List2
       dword Unknown6[6] 
       dwordlist_t List6a
       dword Unknown6a[7]
       dwordlist_t List6aa
       dwordlist_t List6ab
       dwordlist_t List3
       dwordlist_t List4
       dword Unknown7[9]
       dwordlist_t List6
       dwordlist_t List6b
       dword Unknown8[25]
       dwordlist_t List7
       dword Unknown9[4]
       dwordlist_t List8
       dword Unknown8a
       dword Unknown8b
       dwordlist_t List9
       dwordlist_t List10
       dword Unknown10[9]
       dwordlist_t List11
       dwordlist_t List12
       dword Unknown11[16]
       dwordlist2_t List13      // Note the double list size
       dword Unknown12[22]
       dwordlist2_t List14      // Note the double list size
       dword Unknown13[2]
};
Dword List Formats
Within the skill record data there are multiple lists of dwords with the following format:
 
       struct dwordlist_t {
              dword Size
              dword Data[Size]
        }

Note that an empty list is a just a dword with value 00 00 00 00. There are also lists that have elements with two dword instead of one:
       
       struct dwordlist2_t {
              dword Size
              dword Data[Size*2]
        }

The exact nature of the dword values depends from list to list. Sometimes they are skill abilityIds.
AbilityTypes
undocumented but extensively used both server and client side

  

Data Format Notes
Most of the format has not been deciphered yet but there are a number of discoveries to note:

:* Skills per class can be found in the next file (807317 in update 29pts).
:* There are some float values in some places. All of them are in Little Endian byte order.
:* In the language file skill names are found in section 198758357 and skill descriptions in 132143172.
:* Unknown2[]
::* Unknown2[0] is a time/date in time_t format.
::* Unknown2[1] is cast time*1000.
::* Unknown2[3] + Unknown2[4] are something related to tooltip values.
::* Unknown2[5] is maxRange.
::* Unknown2[6] is the ability type (ABILITY_TYPE_...). In-game this is only available in combat effect callbacks.
::* Unknown2[7] target type?
::* Values following this may depend on the ability type or something else. The skill cost is sometimes in element 14 and sometimes in element 15.
::* Unknown2[11] duration or channel time *1000
::* Unknown2[13] angleDistance *50
::* Unknown2[14] or Unknown2[15] is ability cost. Is not always the exact value (see list9 below).
::* Unknown2[16] radius *100
::* Unknown2[18] always float 100
::* Unknown2[19] usually 7000?
:* Flags
::* Always a 00 or 01 value.
::* Flags[187] is always 0
:* Unknown6a[4] is the mechanic (-2 is health)
:* List1 / List2
::* Related to linked abilities (synergy, minor/major buffs/debuffs used in skill, etc...)
::* List1 is linked type?
::* List2 is abilityId
:* List3 / List4
::* Related to tooltip values from the skill description. Should have the same number of elements as the placeholder  > values in the description (numbers start at 1).
::* List3 is some sort of type (18 = damage?, 17 = damage?)
::* List4 is abilityId (this can point back the same skill)
:* List9
::* List9[1] and List9[2] is something related to skill cost (types?)
::* List9[1] is skillCost/72 when the skill cost in Unknown2[] is not the skill cost. (not completely verified)
::* List12[4] is a float
:* Unknown8
::* Unknown8[10], Unknown2[12], Unknown2[14], Unknown2[16] are stat types (4 = magicka, 25 = spell damage, 35 = stamina, 29 = weapon damage). Possible values are:
       0: STAT_NONE
       1: STAT_BONUS_OPTION_DONT_APPLY_BONUS
       2: STAT_WEAPON_AND_SPELL_DAMAGE
       4: STAT_MAGICKA_MAX
       7: STAT_HEALTH_MAX
       8: STAT_HEALTH_REGEN_COMBAT
       22: STAT_PHYSICAL_RESIST
       25: STAT_SPELL_POWER (Spell Damage)
       29: STAT_STAMINA_MAX 
       35: STAT_POWER (Weapon Damage)
       36: STAT_DAMAGE_RESIST_START

::* Updated Exhaustive list as of 6.3.6  is as follow:

       0x0:STAT_NONE
       0x1:STAT_ATTACK_POWER
       0x2:STAT_WEAPON_AND_SPELL_DAMAGE
       0x3:STAT_ARMOR_RATING
       0x4:STAT_MAGICKA_MAX
       0x5:STAT_MAGICKA_REGEN_COMBAT
       0x6:STAT_MAGICKA_REGEN_IDLE
       0x7:STAT_HEALTH_MAX
       0x8:STAT_HEALTH_REGEN_COMBAT
       0x9:STAT_HEALTH_REGEN_IDLE
       0xa:STAT_HEALING_TAKEN
       0xb:STAT_DODGE
       0xc:STAT_HEALING_DONE
       0xd:STAT_SPELL_RESIST
       0xe:STAT_BLOCK
       0x10:STAT_CRITICAL_STRIKE
       0x14:STAT_MITIGATION
       0x16:STAT_PHYSICAL_RESIST
       0x17:STAT_SPELL_CRITICAL
       0x18:STAT_CRITICAL_RESISTANCE
       0x19:STAT_SPELL_POWER
       0x1a:STAT_SPELL_MITIGATION
       0x1b:STAT_OFFENSIVE_PENETRATION
       0x1c:STAT_CRITICAL_CHANCE
       0x1d:STAT_STAMINA_MAX
       0x1e:STAT_STAMINA_REGEN_COMBAT
       0x1f:STAT_STAMINA_REGEN_IDLE
       0x20:STAT_MISS
       0x21:STAT_PHYSICAL_PENETRATION
       0x22:STAT_SPELL_PENETRATION
       0x23:STAT_POWER
       0x24:STAT_DAMAGE_RESIST_START
       0x25:STAT_DAMAGE_RESIST_GENERIC
       0x26:STAT_DAMAGE_RESIST_PHYSICAL
       0x27:STAT_DAMAGE_RESIST_FIRE
       0x28:STAT_DAMAGE_RESIST_SHOCK
       0x29:STAT_DAMAGE_RESIST_OBLIVION
       0x2a:STAT_DAMAGE_RESIST_COLD
       0x2b:STAT_DAMAGE_RESIST_EARTH
       0x2c:STAT_DAMAGE_RESIST_MAGIC
       0x2d:STAT_DAMAGE_RESIST_DROWN
       0x2e:STAT_DAMAGE_RESIST_DISEASE
       0x2f:STAT_DAMAGE_RESIST_POISON
       0x30:STAT_MOUNT_STAMINA_MAX
       0x31:STAT_MOUNT_STAMINA_REGEN_COMBAT
       0x32:STAT_MOUNT_STAMINA_REGEN_MOVING
       0x0:STAT_MIN_VALUE
       0x32:STAT_MAX_VALUE
       0x0:STAT_ITERATION_BEGIN
       0x32:STAT_ITERATION_END
       0x0:STAT_BONUS_OPTION_APPLY_BONUS
       0x1:STAT_BONUS_OPTION_DONT_APPLY_BONUS
       0x0:STAT_BONUS_OPTION_MIN_VALUE
       0x1:STAT_BONUS_OPTION_MAX_VALUE
       0x0:STAT_BONUS_OPTION_ITERATION_BEGIN
       0x1:STAT_BONUS_OPTION_ITERATION_END

::* Unknown8[11], Unknown2[13], Unknown2[15], Unknown2[17] are float values representing the coefficient for the previous stat type.
::* Regular skills have 14/15/16/17 as 0. Ultimates have full sections. Unknown if more than 10-16 can have coefficient values.
::* For example:
        10 = 25
        11 = 0.05
        12 = 4
        13 = 0.1
        14 = 35
        15 = 0.05
        16 = 29
        17 = 0.1
:* Only one rank of active skills is stored in the data (this was changed in one update). 
::* Ranks have the same description text and most of the same data.
::* Ranks 1-3 have 3/2/1% smaller coefficients (not confirmed).
::* Some skills ranks 1-3 have increased skill cost 270/180/90 (not confirmed, unsure what controls this).

More Info
:* TestSkillFormat Project -- Test project for loading/parsing of skill data files.