ESO Mod:Skill Data Format
This describes the format of the file containing skill data for ESO.
Contents
Location[edit]
The file in question is contained within the depot/Eso0000.dat file. Use the Online:EsoExtractData 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[edit]
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[edit]
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[edit]
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<uint8_t> 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[edit]
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[edit]
- undocumented but extensively used both server and client side
enum class ABILITY_TYPE : unsigned int { NONE=0x0, DAMAGE=0x1, HEAL=0x2, RESURRECT=0x3, BLINK=0x4, BONUS=0x5, REGISTERTRIGGER=0x6, SETTARGET=0x7, THREAT=0x8, STUN=0x9, SNARE=0xa, SILENCE=0xb, REMOVETYPE=0xc, SETCOOLDOWN=0xd, COMBATRESOURCE=0xe, DAMAGESHIELD=0xf, MOVEPOSITION=0x10, KNOCKBACK=0x11, CHARGE=0x12, IMMUNITY=0x13, INTERCEPT=0x14, REFLECTION=0x15, AREAEFFECT=0x16, DEPRECATED2=0x17, CREATEINVENTORYITEM=0x18, DAMAGELIMIT=0x19, AREATELEPORT=0x1a, FEAR=0x1b, TRAUMA=0x1c, STEALTH=0x1d, SEESTEALTH=0x1e, FLIGHT=0x1f, DISORIENT=0x20, STAGGER=0x21, SLOWFALL=0x22, JUMP=0x23, SIEGECLUSTERAREAEFFECT=0x24, SUMMON=0x25, MOUNT=0x26, INTERACTREFUSALOVERRIDE=0x27, BLADETURN=0x28, NONEXISTENT=0x29, NOKILL=0x2a, NOAGGRO=0x2b, DISPEL=0x2c, VAMPIRE=0x2d, CREATEINTERACTABLE=0x2e, MODIFYCOOLDOWN=0x2f, LEVITATE=0x30, PACIFY=0x31, ACTIONLIST=0x32, INTERRUPT=0x33, BLOCK=0x34, OFFBALANCE=0x35, EXHAUSTED=0x36, MODIFYDURATION=0x37, DODGE=0x38, SHOWNON=0x39, MISDIRECT=0x3a, FREECAST=0x3b, SIEGECREATE=0x3c, SIEGEAREAEFFECT=0x3d, DEFEND=0x3e, FREEINTERACT=0x3f, CHANGEAPPEARANCE=0x40, ATTACKERREFLECT=0x41, ATTACKERINTERCEPT=0x42, DISARM=0x43, PARRY=0x44, PATHLINE=0x45, DOUBLEFIRE=0x46, FIREPROC=0x47, LEAP=0x48, REVEAL=0x49, SIEGEPACKUP=0x4a, RECALL=0x4b, GRANTABILITY=0x4c, HIDE=0x4d, SETHOTBAR=0x4e, NOLOCKPICK=0x4f, FILLSOULGEM=0x50, SOULGEMRESURRECT=0x51, DESPAWNOVERRIDE=0x52, UPDATEDEATHDIALOG=0x53, DEPRECATED4=0x54, CLIENTFX=0x55, AVOIDDEATH=0x56, NONCOMBATBONUS=0x57, NOSEETARGET=0x58, DEPRECATED=0x59, SETPERSONALITY=0x5a, BASIC=0x5b, REWINDTIME=0x5c, LIGHTHEAVYATTACKOVERRIDE=0x5d, DERIVEDSTATCACHE=0x5e, AVAREACH=0x5f, RANDOMBRANCH=0x60, MOUNTBLOCK=0x61, DEPRECATED3=0x62, HARDDISMOUNT=0x63, LINKTARGET=0x64, CUSTOMTARGETAREA=0x65, DAMAGETRANSFER=0x66, DISABLEITEMSETS=0x67, FOLLOWWAYPOINTPATH=0x68, SETAIMATTARGET=0x69, FACETARGET=0x6a, LOSMOVEPOSITION=0x6b, DISABLECLIENTTURNING=0x6c, DAMAGEIMMUNE=0x6d, STOPMOVING=0x6e, RESOURCETAP=0x6f }; unsigned int AbilityDef_Client::GetAbilitypeNumber() { return *(unsigned int*)(this+0x4C); }
Data Format Notes[edit]
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[edit]
-
- TestSkillFormat Project -- Test project for loading/parsing of skill data files.