MPRL: 59832 0x0E9B8MPRR: 327744 0x50040MSHD: 32 0x00020 // M S HeaDerMSPV: 105336 0x19B78MSPI: 105832 0x19D68MSCN: 119880 0x1D448MSLK: 256400 0x3E990MSVT: 75816 0x12828MSVI: 62408 0x0F3C8MSUR: 131520 0x201C0MDOS: 200 0x000C8MDSF: 21472 0x053E0MDBH: Destructible Building HeaderMDBI: Destructible Building IMDBF: Destructible Building Filename
#include <cstdlib>#include <cstdio>#include <cassert>#include <stdint.h>struct CHUNK{ uint32_t magic; uint32_t size;};struct MVER : CHUNK{ uint32_t version;};struct MPRLentry{ uint16_t a; // 0 int16_t b; // -1 uint16_t c; uint16_t d; float position[3]; int16_t e; uint16_t f;};struct MPRL : CHUNK{ MPRLentry entries[0];};struct MDBF : CHUNK{ char name[0];};struct MDBI : CHUNK{ uint32_t index;};struct MDBH : CHUNK{ uint32_t number;};struct MSHD : CHUNK{ float unk[8];};struct MDOSentry{ uint32_t a; uint32_t b;};struct MDOS : CHUNK{ MDOSentry entries[0];};int main(int na,char** va){ assert(na == 2 && *va ); FILE* input = fopen( va[1], "rb" ); fseek( input, 0, SEEK_END ); size_t size = ftell( input ); char* file = new char[size]; fseek( input, 0, SEEK_SET ); fread( file, 1, size, input ); fclose( input ); size_t position = 0; // MVER ______________________________________________________________________ MVER* mver = ( MVER* )( file + position ); assert( mver->magic == 'MVER' && mver->size == 4 ); printf( "Build: %in", mver->version ); position += mver->size + 8; printf( "n -- %xn", position ); // MPRL ______________________________________________________________________ MPRL* mprl = ( MPRL* )( file + position ); assert( mprl->magic == 'MPRL' ); size_t nMPRLEntries = mprl->size / sizeof( MPRLentry ); printf( "MPRL entries: %ldnn", nMPRLEntries ); for( size_t i = 0; i < nMPRLEntries; ++i ) { printf( "{%f,%f,%f}:t%xt%it%xt%xt%it%xn", mprl->entries[i].position[0], mprl->entries[i].position[1], mprl->entries[i].position[2], mprl->entries[i].a, mprl->entries[i].b, mprl->entries[i].c, mprl->entries[i].d, mprl->entries[i].e, mprl->entries[i].f ); assert( mprl->entries[i].d == 0x8000 ); assert( mprl->entries[i].b == -1 ); } position += mprl->size + 8; printf( "n -- %xn", position ); // ???? ______________________________________________________________________ { CHUNK* unk = ( CHUNK* )( file + position ); printf( "Magic: %c%c%c%c, size: %in", ((char*)(&(unk->magic)))[3], ((char*)(&(unk->magic)))[2], ((char*)(&(unk->magic)))[1], ((char*)(&(unk->magic)))[0], unk->size ); position += unk->size + 8; printf( " -- %xn", position ); } // MDBH ______________________________________________________________________ MDBH* mdbh = ( MDBH* )( file + position ); assert( mdbh->magic == 'MDBH' && mdbh->size == 4 ); if( mdbh->number ) { printf("There are %i destructible buildings:n", mdbh->number ); } position += mdbh->size + 8; // MDB* ______________________________________________________________________ for( size_t i = 0; i < mdbh->number; ++i ) { MDBI* mdbi = ( MDBI* )( file + position ); assert( mdbi->magic == 'MDBI' && mdbh->size == 4 ); printf("- Building %i:n", mdbi->index ); position += mdbi->size + 8; for( size_t i = 0; i < 3; ++i ) { MDBF* mdbf = ( MDBF* )( file + position ); assert( mdbf->magic == 'MDBF' ); if( mdbf->size ) printf(" %i: %sn", i, mdbf->name ); position += mdbf->size + 8; } } // MSHD ______________________________________________________________________ /* MSHD* mshd = ( MSHD* )( file + position ); assert( mshd->magic == 'MSHD' && mshd->size == 32 ); printf("nMSHD: n"); for( size_t i = 0; i < 8; ++i ) { printf(" %i: %fn", i, mshd->unk[i] ); } position += mshd->size + 8;*/ // ???? ______________________________________________________________________ while( position < size ) { CHUNK* unk = ( CHUNK* )( file + position ); printf( "Magic: %c%c%c%c, size: %in", ((char*)(&(unk->magic)))[3], ((char*)(&(unk->magic)))[2], ((char*)(&(unk->magic)))[1], ((char*)(&(unk->magic)))[0], unk->size ); if( unk->magic == 'MShHD' && unk->size ) { float* f = ( float* )( file + position + 8 ); int* n = ( int* )( file + position + 8 ); for( size_t i = 0; i < unk->size / 4; ++i ) { printf("%x: %f %i %xn",i*4, *f, *n, *n ); f++; n++; } } position += unk->size + 8; printf( " -- %xn", position ); } delete[] file; return 0;}
//--------------------------------------//--- 010 Editor v5.0 Binary Template//// File:// Author:// Revision:// Purpose://--------------------------------------typedef struct{float x;float y;float z;} vec3f<read=readvec3f, optimize=false>;string readvec3f (vec3f& rec){string a;SPrintf (a, "(%f %f %f)", rec.x, rec.y, rec.z);return a;}typedef struct{float x;float y;float z;float w;} vec4f<read=readvec4f, optimize=false>;string readvec4f (vec4f& rec){string a;SPrintf (a, "(%f %f %f %f)", rec.x, rec.y, rec.z, rec.w);return a;}typedef struct{int x;int y;} vec2i<read=readvec2i, optimize=false>;string readvec2i (vec2i& rec){string a;SPrintf (a, "(%i %i)", rec.x, rec.y);return a;}typedef struct{int x;int y;int z;int w;} vec4i<read=readvec4i, optimize=false>;string readvec4i (vec4i& rec){string a;SPrintf (a, "(%i %i %i %i)", rec.x, rec.y, rec.z, rec.w);return a;}typedef struct { union { struct { char _0; char _1; char _2; char _3; } raw; unsigned int _; } _;} CHUNK_MAGIC<read=readCHUNK_MAGIC, optimize=false>; string readCHUNK_MAGIC(CHUNK_MAGIC& rec){string a;SPrintf(a, "%c%c%c%c", rec._.raw._3, rec._.raw._2, rec._.raw._1, rec._.raw._0);return a;}typedef struct { CHUNK_MAGIC magic; unsigned int size;} CHUNK_header <read=readCHUNK_header, optimize=false>;typedef struct { CHUNK_header header; chunk_contents (header);} CHUNK <read=readCHUNK, optimize=false>;string readCHUNK(CHUNK& rec){string a;SPrintf (a, "%s", readCHUNK_header(rec.header));return a;}string readCHUNK_header(CHUNK_header& rec){string a;SPrintf (a, "%s: %x", readCHUNK_MAGIC(rec.magic), rec.size);return a;}while (FTell() < FileSize()){ CHUNK chunk;}struct MVER{ CHUNK _; unsigned int version;};struct MDBF{ CHUNK _; char name[0];};struct MDBI{ CHUNK _; unsigned int index;};struct MDBH{ CHUNK _; unsigned int number;};struct MSHD{ CHUNK _; float unk[8];};struct MDOSentry{ CHUNK _; unsigned int a; unsigned int b;};struct MDOS { CHUNK _; MDOSentry entries[0];};void chunk_contents (CHUNK_header& header){ if (header.magic._._ == 1297499474) // MVER { unsigned int version; } else if (header.magic._._ == 1297303620) // MSHD -- s? header { int unk[header.size/4]; } else if (header.magic._._ == 1297305686) // MSPV -- s? p? vertices { vec3f unk[header.size/sizeof(vec3f)]; } else if (header.magic._._ == 1297305673) // MSPI --- s? p? indices { // todo: actual number of indices per record? struct entry_MSPI { int _[2]; } unk[header.size/sizeof(entry_MSPI)]; } else if (header.magic._._ == 1297302350) // MSCN -- s? c? normals? { vec3f unk[header.size/sizeof(vec3f)]; } else if (header.magic._._ == 1297304651) // MSLK -- s? l? k? { struct entry_MSLK { int id; int unk0; short unk1a; short unk1b; int unk2; unsigned short unk3; short unk4; } unk[header.size/sizeof (entry_MSLK)]; } else if (header.magic._._ == 1297307220) // MSVT -- s? v? t? { vec3f unk[header.size/sizeof (vec3f)]; } else if (header.magic._._ == 1297307209) // MSVI --- s? v? indices { // todo: actual number of indices per record? struct entry_MSVI { int unk[1]; } unk[header.size/sizeof (entry_MSVI)]; } else if (header.magic._._ == 1297306962) // MSUR --- s? u? r? { // todo: actual number of indices per record? struct entry_MSUR { int id; vec3f unk; float unk1; vec2i unk2; float unk3; } unk[header.size/sizeof (entry_MSUR)]; } else if (header.magic._._ == 1297109580) // MPRL --- p? r? l? { struct entry_MPRL { unsigned short a; // 0 short b; // -1 unsigned short c; unsigned short d; vec3f position; short e; unsigned short f; } unk[header.size/sizeof (entry_MPRL)]; } else if (header.magic._._ == 1297109586) // MPRR --- p? r? r? { struct entry_MPRR { short unk0; short unk1; } unk[header.size/sizeof (entry_MPRR)]; } else if (header.magic._._ == 1296319048) // MDBH --- destructible building header { unsigned int count; struct entry_MDBH { CHUNK index; CHUNK filename[3]; } entries[count]<optimize=false>; } else if (header.magic._._ == 1296319049) // MDBI --- destructible building index { unsigned int index; } else if (header.magic._._ == 1296322387) // MDOS --- d? o? s? { struct entry_MDOS { int unk0; int unk1; } unk[header.size/sizeof (entry_MDOS)]; } else if (header.magic._._ == 1296323398) // MDSF --- d? s? f? { struct entry_MDSF { int unk0; int unk1; } unk[header.size/sizeof (entry_MDSF)]; } else { char _[header.size]; }}
On the subject, sorta, do you think noggit could eventually have a way to grab all the known locations of model/wmo data, sort of in the same format as these files, so you could effectively convert a map from one version of the game, fix the offsets, and then dump the objects back into the map?
Just a thought, since you've managed to decode what I thought was just some leftover files from the internal WowEdit app. I imagine the same sort of reason for the pm4 files is because the map objects are indexed in a database and then exported to these files temporarily for the editor to use. (does that make sense?)
On another note, would it be possible to make noggit save each type of map chunk data into a set of project files, instead of a complete ADT, so that additional changes could be made without having to re-decode the ADT data every time you work on a map? Is this a design step you'd consider taking, should noggit3's development continue?
In any case, awesome work figuring this out. What other data do the files describe? I've only taken a quick look at what you've posted, but will study it a bit to fully comprehend what you've decoded from these files.