Abrir menu principal

UESPWiki β

Alterações

ESO Mod:MNF File Format

11 500 bytes adicionados, 17h24min de 8 de março de 2016
Block Type 3
{{Trail|File Formats}}[[Category:ESOMod-Mods]]
The purpose of MNF files are as indexes to the sub-files stored within [[ESOMod:DAT File Format|DAT files]]. There are 3 known MNF files:
:* ''\game\client\game.mnf''
:* ''\depot\eso.mnf''
:* ''\vo_en\esoaudioen.mnf''

Each of these are matched with one or more DAT files with the similar name (game0000.mnf, eso0000.mnf, esoaudioen.mnf).


== File Format ==
The MNF files have a short header followed by one or more blocks of compressed data.

[File Header (0x0F bytes)]
[Block 0..N]
[Block Data...]

=== File Header ===
The MNF file header appears to be a fixed size of 15 (0x0F) bytes and contains a few fields:

byte MAGIC_DWORD[4] = "MES2" /* MES MAGIC WORD */
word MES_VERSION = 0x0002 /* MES FORMAT VERSION */
byte FileCount /* NUMBER OF DAT FILES THAT CORRESPOND TO THE MNF FILE */
dword MNF_TYPE = 0x0000001 (eso.mnf) || 0x0000006 (game.mnf)
dword DataSize /* DataSize is the total amount of data that follows the file header */

=== Data Blocks ===
One or more data blocks follow the MNF file header in a contiguous manner. The block format is identified by a 2 byte block id at the start of the block data. At the moment there are two known block types.

==== Block Type 3 ====
This is the most most common block type found in all three MNF files. Note that the block and data header information is all stored in big endian bit order. This block is composed of a short fixed size header followed by three data blocks with the same overall format:

[Block Header (0x12 bytes)]
[Data Block 3.1]
[Data Header (8 bytes)]
[Data (...)]
[Data Block 3.2]
[Data Header (8 bytes)]
[Data (...)]
[Data Block 3.3]
[Data Header (8 bytes)]
[Data (...)]

The block header is a fixed size of 18 (0x12) bytes:

word BlockID = 0x0003
dword FieldSize = 0x00000004 /* Size of each field of a record - Not used by the game */
dword RecordCountB1
dword RecordCountB2
dword RecordCountB3

The record counts are the number of records found in each of the three data blocks that follow (see below). If all three record counts are zero the block contains no data and should not be processed (started happening in the ZOSFT file in the Thieves Guild DLC update).

===== Data Header =====
Each of the three data blocks are preceded by an 8 byte header:

dword UncompressedSize
dword CompressedSize

The ''CompressedSize'' is the number of data in bytes that follows the data header. The data is assumed to be in the zLib format.

===== Data Block 3.1 =====
This is the first of three data blocks in a type 3 block in a MNF file. The data is compressed in a zLib format and once uncompressed it is composed of multiple fixed sized records of 4 bytes with the format:

dword Unknown1

Uncompressed_Size = RecordCountB1 * FieldSize

===== Data Block 3.2 =====
This is the second of three data blocks in a type 3 block in a MNF file. The data is compressed in a zLib format and once uncompressed it is composed of multiple fixed sized records of 8 bytes with the format:

dword Unknown1
dword Unknown2

The number of records is equal to ''RecordCountB2'' found in the block header.

Uncompressed_Size = RecordCountB2 * 2 * FieldSize

===== Data Block 3.3 =====
This is the third of three data blocks in a type 3 block in a MNF file. The data is compressed in a zLib format and once uncompressed it is composed of multiple fixed sized records of 20 (0x14) bytes with the format:

dword UncompressedSize
dword CompressedSize
dword FileHash
dword FileOffset
dword FileInfo = (Unknown (word) << 24) + (ArchiveIndex (byte) << 16) + (CompressType (byte))

The number of records is equal to ''RecordCountB3'' found in the block header.

Uncompressed_Size = RecordCountB3 * 5 * FieldSize

The size fields are simply the size of the file when compressed and uncompressed. The compressed size are the number of bytes that need to be read from the appropriate DAT file. The FileOffset is the offset from the beginning of a DAT file where the file data begins. The CompressType is one of:
:* 0 = Uncompressed
:* 1 = zLib
:* 2 = Snappy
The ArchiveIndex specifies which data file to find it in (i.e., ''ArchiveIndex=23'' in ''eso.mnf'' means look in ''eso0023.dat''). The last two bytes are unknown but take on a variety of purposes.

==== Block Type 0 ====
This block type is only found as the first block in ''eso.mnf''. Like the other block the header information here is all stored in big endian bit order. This block is composed of a short fixed size header followed by two data blocks with the same format:

[Block Header (0x04 bytes)]
[Data Header (0x08 bytes)]
[Data]
[Data Header (0x08 bytes)]
[Data]

The block header format is a small 4 bytes:

word BlockID = 0x0000
word Unknown1 = 0x0000

Like in block 3 the data is preceded by a short header:

dword UncompressedSize
dword CompressedSize

The ''CompressedSize'' is the number of data in bytes that follows the data header. The data for this block is unknown (appears to be compressed but unknown format).

=== Extra Data ===
The file ''eso.mnf'' has an unknown block of 00s at the end of the file 2497716 (0x261CB8) bytes in size.

== Notes ==
:* eso.mnf
::* RecordCount1 = 527361
::* RecordCount2 = 258797
::* RecordCount3 = 313810
::* Block 1 Size = 2109444 (/4 = 527361)
::* Block 2 Size = 2510480 (/8 = 313810)
::* Block 3 Size = 6276200 (/20 = 313810)
::* Non-Zero entries in Block 3 = 313364
:* game.mnf
::* RecordCount1 = 8241
::* RecordCount2 = 3094
::* RecordCount3 = 3094
::* Block 1 Size = 32964 (/4 = 8241)
::* Block 2 Size = 24752 (/8 = 3094)
::* Block 3 Size = 61880 (/20 = 3094)
::* Non-Zero entries in Block 3 = 3094
:* esoaudioen.mnf
::* RecordCount1 = 263681
::* RecordCount2 = 120345
::* RecordCount3 = 120345
::* Block 1 Size = 1054724 (/4 = 263681)
::* Block 2 Size = 962760 (/8 = 120345)
::* Block 3 Size = 2406900 (/20 = 120345)
::* Non-Zero entries in Block 3 = 120345
:* The patch for the 8/02/2014 beta does not appear to have changed the MNF format.

== Misc Stuff ==
Most of the below is slightly incorrect or out of date but kept here until the required information is merged to the main article above.

[MNF] - have 3 compressed blocks

0x4 - szID (always MES2)
0x15 - unknown (unique id?)
0x4 - szFilesCount (endian BIG)
0x4 - szFilesCount (endian BIG)

0x4 - szBlockSize (endian BIG)
0x4 - szBlockZSize (endian BIG)
[........Block........]

0x4 - szBlockSize (endian BIG)
0x4 - szBlockZSize (endian BIG)
[........Block........]

0x4 - szBlockSize (endian BIG)
0x4 - szBlockZSize (endian BIG)

Blocks 1 unknown tables

Block 2: 8 bytes per file?

[Block 3] - Endian Little
0x4 - szFileSize
0x4 - szFileZSize
0x4 - szUnknown01 (Hash?)
0x4 - szOffset
0x1 - szComType(0 - Not Compressed, 1 - Zlib, 2 - Snappy)
0x1 - szArchiveNum
0x2 - szUnknown02
[........Block........]


Hash Init: 0xA8396u
Use Hash.cpp from RDF-3X project (https://code.google.com/p/rdf3x/downloads/list)


unknown1 num_dat_archives EOF_offset dummy unknown2
FILENAME [02 00] [XX] 00 00 00 00 [XX XX XX XX] 00 03 [00 00 00] 04 [XX XX XX XX]
eso.mnf: [02 00] [D0] 00 00 00 00 [7B FB 4F 00] 00 03 [00 00 00] 04 [00 08 0C 01]
esoaudioen.mnf: [02 00] [04] 00 00 00 00 [2B 09 1E 00] 00 03 [00 00 00] 04 [00 04 06 01]
game.mnf: [02 00] [01] 00 00 00 00 [3A A2 00 00] 00 03 [00 00 00] 04 [00 00 10 19]

unknown1: This always has to be 2 for some reason. The files don't open otherwise.
num_dat_archives: number of DAT files
EOF_offset (little endian): After reading these 4 bytes, add EOF_offset to current offset to reach the end of the third block. This is EOF except for eso.mnf which has extra data.
unknown2 (big endian): This is 4120*(2^n)+1, with n ranging from 0 to 2. It seems n is also the number of the DAT archive containing the ZOSFT, but maybe this is just a coincidence.


More detailed stuff for reference:
<pre>
====================== FILE STRUCTURE ANALYSIS ======================
------ DAT: Decompiled ------
0x4 - ID string ('2SEP'/'PES2')
0x2 - always 1 (little endian)
0x4 - always 0
0x4 - always 0E (14 in decimal). Seems to be the absolute offset of the data start


------ MNF: Decompiled ------
0x4 - ID string ('2SEM'/'MES2')
0x2 - always 2 (little endian)
0x1 - number of DAT files
0x4 - always 0
0x4 - EOF_offset: offset after block 3

------ ZOSFT ----------------
0x5 - ID string ('ZOSFT')
0x4 - always 06 00 10 00
0x6 - unknown
0x4 - number of records, little endian
for(i=0; i<3; i++) {
0x4 - always 03 00 04 00
0x6 - unknown
0x4 - number of records
0x4 - number of records
0x4 - block size
0x4 - block zsize
[block]
0x4 - block size
0x4 - block zsize
[block]
0x4 - block size
0x4 - block zsize
[block]
}
0x4 - bytes until end of filetable
[filenames: 0-terminated strings]
0x5 - ZOSFT

====================== ZLIB BLOCKS ANALYSIS ======================
------ MNF ------------------
BLOCK 1
for(i=0; i<filecount; i++) {
(0x4 - dummy)* - 00 00 00 00, 0 or more times
0x4 (little endian) - FILE_ID = 2147483648 of 00 00 00 80 + i
(0x4 - dummy)* - 00 00 00 00, 0 or more times
}

BLOCK 2
for(i=0; i<filecount; i++) {
0x4 (little endian) - file_number
0x2 (little endian) - 00 00 or 01 00 in game, but can be anything in ESO
0x1 (little endian) - 00 80 or 00 00 in game, but can be 00 60, 00 40 or 00 20 in ESO as well!
}

BLOCK 3
for(i=0; i<filecount; i++) {
0x4 - file_size
0x4 - file_zsize
0x4 - filename_hash (http://rdf3x.googlecode.com/svn/trunk/infra/util/Hash.cpp - http://rdf3x.googlecode.com/svn/trunk/include/infra/util/Hash.hpp - init by 0xA8396u)
0x4 - file_offset
0x1 - file_comtype (0 - Not Compressed, 1 - Zlib, 2 - Snappy)
0x1 - archive_number
0x2 - unknown
}

------ ZOSFT ----------------
- blocks 1_1, 2_1 or 3_1 is list of FILE IDs
- 1772 filenames in game.zosft, EC600000!

BLOCK 1_1
for(i=0; i<record_count; i++) {
0x4 (little endian) - FILE_ID = 2147483648 or 00 00 00 80 + i
(0x4 - dummy)* - 00 00 00 00, 0 or more times
}

BLOCK 1_2
for(i=0; i<record_count; i++) {
0x8 (little endian) - complex_number
}

BLOCK 1_3 (simple count to record_count in game, but not in eso)
for(i=1; i<=record_count; i++) {
0x4 (little endian) - file_number (unique)
}

BLOCK 2_1
for(i=0; i<record_count; i++) {
0x4 (little endian) - FILE_ID = 2147483648 or 00 00 00 80 + i
(0x4 - dummy)* - 00 00 00 00, 0 or more times
}

BLOCK 2_2
same as block 1_3

BLOCK 2_3 = the most important! -------------- link to MNF block 2
for(i=0; i<record_count; i++) {
0x4 (little endian) - file_number (same as in block 1_3 and 2_2)
0x4 - filename_offset (relative, after number indicating bytes until end of filetable)
0x8 - complex_number (same as in block 1_2)
}

BLOCK 3: important for eso.mnf?
BLOCK 3_1: Empty in game.mnf
BLOCK 3_2: Not in game.mnf
BLOCK 3_3: Not in game.mnf
</pre>
12 364
edições