11-13-2018, 04:46 AM
(This post was last modified: 06-29-2019, 02:17 PM by CHEMI6DER.
Edit Reason: Some minor edits to enhance stability and user experience
)
Hi! I'm doing RE work on Luigi's Mansion 2: Dark Moon. This post, as well as a little C# program I created, is dedicated to documenting file formats of this game.
1. data and dict files
Data contains actual data and dict files are like archive headers and contain some basic info about the files.
The basic structure of dict is this(put it in a spoiler because it's too long and messy):
Data structure is very simple. It just contains all the files "glued" together with padding to closest 8-byte boundary every time a file starts.
Dicts have some sort of mystery in that they seem to have dummy and null entries for many files. Even though we can kinda extract them, we should figure out why they exist in the first place.
2. Files inside data/dict archives
(Disclaimer: the subfiles have no file names whatsoever, so the names are used are the same as in my code)
file000 contains information about subfiles in file003, containing offset, length and type This data is usually preceded with 0x01130002 with const length of 0x18, purpose of these is unknown.
file002 probably contains meta info on files stored in file003. For now only purpose of PÓwé(or Powe as I'll be referring to these, because I don't have a way to input diacritic marks on my keyboard) sections is known, they contain info about textures(like resolution, format, mip levels)
The structure of Powe is like this:
Here are a few textures I've dumped with my tool.
3. Models
Models are stored in file003. Stuff can be organised into so called "model groups"(basically models which share the same vertex data, submesh info and other stuff). Each model group contains vertex data section (contains vertex stuff and vertex indices), submesh vertex start pointers (relative to vtx data start), submesh info (has stuff like index count/offset, vertex count, data format, etc.) and some other stuff(bones probably, but I haven't figured those out yet).
About vertex data formats: there are a whole bunch of them...and I really mean A LOT(just look at my code)...
A lot of them are kinda similar. Like most of character models use ShortFloat(IDK how this is properly called) for vertex encoding, while levels use float32. I sadly can't figure out much more than vertex coordinates (can't even find UVs in some cases), so if anyone is willing to and can actually help, please do.
I was able to write a working exporter to wavefront obj for some of the formats, here are a few models I've ripped:
Screenshot of Luigi model just as an example:
In the attached archive you can find this model and E. Gadd's in obj (and Luigi in collada, because wavefront doesn't support multiple textures per material). I didn't bother adding other stuff I've tried to rip, mainly because UVs are all over the place and a lot of stuff doesn't work properly.
lm2_test.zip (Size: 336.4 KB / Downloads: 398)
4. NLOC
NLOC - Next-level LOCalization(?) files contain text strings. You can extract these with RoadrunnerWMC's python script(look for it in his gihub gist)
5. NMLB
NMLB - Binary Luigi's Mansion N-something (reversed because little endian). IDK what it is, but I just simply came across this signature while browsing some(probably cutscene) of the files in the hex editor
6. FENL
FENL - IDK what this stands for. Looks like layout data based on where it's found
7. Audio
The audio is stored in wwiseaudio folder. You might thing that wwise-unpacker might extract these, but it fails. The reason is that despite there files being the standard .bnk and .pck variety. The reason wwise-unpacker fails is that these contain audio compressed with the same compression as BCSTM files (DSP ADPCM in case of LM2).
This is a brief writeup on what I've found. If you want to go a bit more in-depth, then go look at the code of LM2L, a tool I made for extracting files from this game. You can find the source code on GitHub. (To anyone wondering, the OGL viewer is probably not gonna be a working thing because I know nothing about OpenGL and how to program it)
P.S. Bonus: in the code.bin there is a string referring to "DS Horror". Seems like they didn't have ideas on how to name the thing or just used this name as a placeholder until they came up with "DualScream"
1. data and dict files
Data contains actual data and dict files are like archive headers and contain some basic info about the files.
The basic structure of dict is this(put it in a spoiler because it's too long and messy):
Data structure is very simple. It just contains all the files "glued" together with padding to closest 8-byte boundary every time a file starts.
Dicts have some sort of mystery in that they seem to have dummy and null entries for many files. Even though we can kinda extract them, we should figure out why they exist in the first place.
2. Files inside data/dict archives
(Disclaimer: the subfiles have no file names whatsoever, so the names are used are the same as in my code)
file000 contains information about subfiles in file003, containing offset, length and type This data is usually preceded with 0x01130002 with const length of 0x18, purpose of these is unknown.
file002 probably contains meta info on files stored in file003. For now only purpose of PÓwé(or Powe as I'll be referring to these, because I don't have a way to input diacritic marks on my keyboard) sections is known, they contain info about textures(like resolution, format, mip levels)
The structure of Powe is like this:
Here are a few textures I've dumped with my tool.
3. Models
Models are stored in file003. Stuff can be organised into so called "model groups"(basically models which share the same vertex data, submesh info and other stuff). Each model group contains vertex data section (contains vertex stuff and vertex indices), submesh vertex start pointers (relative to vtx data start), submesh info (has stuff like index count/offset, vertex count, data format, etc.) and some other stuff(bones probably, but I haven't figured those out yet).
About vertex data formats: there are a whole bunch of them...and I really mean A LOT(just look at my code)...
A lot of them are kinda similar. Like most of character models use ShortFloat(IDK how this is properly called) for vertex encoding, while levels use float32. I sadly can't figure out much more than vertex coordinates (can't even find UVs in some cases), so if anyone is willing to and can actually help, please do.
I was able to write a working exporter to wavefront obj for some of the formats, here are a few models I've ripped:
Screenshot of Luigi model just as an example:
In the attached archive you can find this model and E. Gadd's in obj (and Luigi in collada, because wavefront doesn't support multiple textures per material). I didn't bother adding other stuff I've tried to rip, mainly because UVs are all over the place and a lot of stuff doesn't work properly.
lm2_test.zip (Size: 336.4 KB / Downloads: 398)
4. NLOC
NLOC - Next-level LOCalization(?) files contain text strings. You can extract these with RoadrunnerWMC's python script(look for it in his gihub gist)
5. NMLB
NMLB - Binary Luigi's Mansion N-something (reversed because little endian). IDK what it is, but I just simply came across this signature while browsing some(probably cutscene) of the files in the hex editor
6. FENL
FENL - IDK what this stands for. Looks like layout data based on where it's found
7. Audio
The audio is stored in wwiseaudio folder. You might thing that wwise-unpacker might extract these, but it fails. The reason is that despite there files being the standard .bnk and .pck variety. The reason wwise-unpacker fails is that these contain audio compressed with the same compression as BCSTM files (DSP ADPCM in case of LM2).
This is a brief writeup on what I've found. If you want to go a bit more in-depth, then go look at the code of LM2L, a tool I made for extracting files from this game. You can find the source code on GitHub. (To anyone wondering, the OGL viewer is probably not gonna be a working thing because I know nothing about OpenGL and how to program it)
P.S. Bonus: in the code.bin there is a string referring to "DS Horror". Seems like they didn't have ideas on how to name the thing or just used this name as a placeholder until they came up with "DualScream"