* implemented basic ADT file loading. first step to usable map data! :D

* MapTile class still excluded from build.
This commit is contained in:
False.Genesis 2007-05-18 22:31:34 +00:00
parent d8bca94faf
commit d50ea1c7a2
8 changed files with 584 additions and 0 deletions

View File

@ -379,6 +379,28 @@
<File <File
RelativePath=".\Client\World\WorldSocket.h"> RelativePath=".\Client\World\WorldSocket.h">
</File> </File>
<Filter
Name="MapSystem"
Filter="">
<File
RelativePath=".\Client\World\MapTile.cpp">
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
</File>
<File
RelativePath=".\Client\World\MapTile.h">
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="Realm" Name="Realm"

View File

@ -261,6 +261,19 @@
RelativePath=".\shared\Network\Utility.h"> RelativePath=".\shared\Network\Utility.h">
</File> </File>
</Filter> </Filter>
<Filter
Name="Map File Classes"
Filter="">
<File
RelativePath=".\shared\ADTFile.cpp">
</File>
<File
RelativePath=".\shared\ADTFile.h">
</File>
<File
RelativePath=".\shared\ADTFileStructs.h">
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="Resource Files" Name="Resource Files"

290
src/shared/ADTFile.cpp Normal file
View File

@ -0,0 +1,290 @@
#include <fstream>
#include "common.h"
#include "ADTFile.h"
inline void flipcc(uint8 *fcc)
{
char t;
t=fcc[0];
fcc[0]=fcc[3];
fcc[3]=t;
t=fcc[1];
fcc[1]=fcc[2];
fcc[2]=t;
}
bool ADTFile::Load(std::string fn)
{
uint32 fs = GetFileSize(fn.c_str());
if(!fs)
return false;
std::fstream fh;
fh.open(fn.c_str());
if(!fh.is_open())
return false;
ByteBuffer buf(fs);
buf.resize(fs);
fh.read((char*)buf.contents(),fs);
fh.close();
LoadMem(buf);
return m_loaded;
}
bool ADTFile::LoadMem(ByteBuffer& buf)
{
uint32 texturecnt=0,modelcnt=0,wmocnt=0;
uint32 size; // used for every chunk
uint32 mcnkid=0;
uint8 *fourcc = new uint8[5]; fourcc[4]=0;
while(buf.rpos()<buf.size())
{
buf.read(fourcc,4); flipcc(fourcc);
buf.read((uint8*)&size,4);
DEBUG(printf("ADT: reading '%s' size %u\n",fourcc,size));
if(!strcmp((char*)fourcc,"MVER"))
{
buf >> _version;
}
else if(!strcmp((char*)fourcc,"MHDR"))
{
mhdr = buf.read<MHDR_chunk>();
}
else if(!strcmp((char*)fourcc,"MCIN"))
{
for(uint32 i = 0; i < CHUNKS_PER_TILE; i++)
{
mcin[i] = buf.read<MCIN_chunk>();
DEBUG(printf("ADT chunk %u at offset %u, size %u flags %X async %u\n",i,mcin[i].offset,mcin[i].size,mcin[i].flags,mcin[i].async));
}
}
else if(!strcmp((char*)fourcc,"MTEX"))
{
for(uint32 i=0;;i++)
{
std::string tex;
memcpy(fourcc,buf.contents()+buf.rpos(),4);
flipcc(fourcc);
if(!memcmp(fourcc,"MMDX",4))
break;
buf >> tex;
DEBUG(printf("MTEX offset %u \"%s\"\n",buf.rpos(),tex.c_str()));
_textures.push_back(tex);
texturecnt++;
}
}
else if(!strcmp((char*)fourcc,"MMDX"))
{
for(uint32 i=0;;i++)
{
std::string model;
memcpy(fourcc,buf.contents()+buf.rpos(),4);
flipcc(fourcc);
if(!memcmp(fourcc,"MMID",4))
break;
buf >> model;
DEBUG(printf("MMDX offset %u \"%s\"\n",buf.rpos(),model.c_str()));
_models.push_back(model);
modelcnt++;
}
}
/*else if(!strcmp((char*)fourcc,"MMID"))
{
for(uint32 i = 0; i <= modelcnt; i++)
{
uint32 offs;
buf >> offs; // we dont really need those offsets
}
}*/
else if(!strcmp((char*)fourcc,"MWMO"))
{
for(uint32 i=0;;i++)
{
std::string wmo;
memcpy(fourcc,buf.contents()+buf.rpos(),4);
flipcc(fourcc);
if(!memcmp(fourcc,"MWID",4))
break;
buf >> wmo;
DEBUG(printf("MWMO offset %u \"%s\"\n",buf.rpos(),wmo.c_str()));
_wmos.push_back(wmo);
wmocnt++;
}
}
/*else if(!strcmp((char*)fourcc,"MWID"))
{
for(uint32 i = 0; i <= wmocnt; i++)
{
uint32 offs;
buf >> offs; // we dont really need those offsets
}
}*/
else if(!strcmp((char*)fourcc,"MDDF"))
{
uint32 ndoodads = size / 36;
DEBUG(printf("ADT: Loading %u doodads.\n",ndoodads));
for(uint32 i = 0; i<ndoodads; i++)
{
_doodadsp.push_back(buf.read<MDDF_chunk>());
}
}
else if(!strcmp((char*)fourcc,"MODF"))
{
uint32 nwmos = size / 64;
DEBUG(printf("ADT: Loading %u wmos.\n",nwmos));
for(uint32 i = 0; i<nwmos; i++)
{
_wmosp.push_back(buf.read<MODF_chunk>());
}
}
else if(!strcmp((char*)fourcc,"MCNK"))
{
_chunks[mcnkid].hdr = buf.read<MapChunkHeader>();
uint8 *mfcc = new uint8[5]; mfcc[4]=0;
uint32 msize;
while(buf.rpos()<buf.size())
{
buf.read(mfcc,4); flipcc(mfcc);
buf.read((uint8*)&msize,4);
// HACKS to make it work properly
if(!msize && !strcmp((char*)mfcc,"MCAL"))
continue;
if((!msize) && !strcmp((char*)mfcc,"MCLQ"))
msize = _chunks[mcnkid].hdr.sizeLiquid;
DEBUG(printf("ADT: MCNK: reading '%s' size %u\n",mfcc,msize));
if(!strcmp((char*)mfcc,"MCVT"))
{
for(uint32 i = 0; i < 145; i++)
{
buf >>_chunks[mcnkid].vertices[i];
}
}
else if(!strcmp((char*)mfcc,"MCNR"))
{
for(uint32 i = 0; i < 145; i++)
{
_chunks[mcnkid].normalvecs[i] = buf.read<NormalVector>();
}
// HACK: skip unk junk bytes
if(msize==0x1B3)
buf.rpos(buf.rpos()+0xD);
}
else if(!strcmp((char*)mfcc,"MCLY"))
{
_chunks[mcnkid].nTextures = msize / 16;
ASSERT(msize/16 == _chunks[mcnkid].hdr.nLayers);
for(uint32 i = 0; i < _chunks[mcnkid].nTextures; i++)
{
_chunks[mcnkid].layer[i] = buf.read<MCLY_chunk>();
}
}
else if(!strcmp((char*)mfcc,"MCSH"))
{
buf.read((uint8*)&(_chunks[mcnkid].shadowmap),512);
}
else if(!strcmp((char*)mfcc,"MCAL"))
{
for(uint32 i = 0; i < (_chunks[mcnkid].hdr.sizeAlpha - 8) / 2048; i++)
{
buf.read((uint8*)(_chunks[mcnkid].alphamap[i]),2048);
}
}
else if(!strcmp((char*)mfcc,"MCLQ"))
{
uint8 *fcc1 = new uint8[5];
buf.read(fcc1,4);
flipcc(fcc1);
fcc1[4]=0;
if (!strcmp((char*)fcc1,"MCSE"))
{
_chunks[mcnkid].haswater = false;
DEBUG(printf("ADT: MCNK: MCLQ not present\n"));
buf.rpos(buf.rpos()-4);
delete [] fcc1;
continue; // next block read will be the MCSE block
}
else
{
_chunks[mcnkid].haswater = true;
float tmp;
buf.rpos(buf.rpos()-4);
uint32 bufpos=buf.rpos();
uint32 rbytes,diffbytes;
buf >> _chunks[mcnkid].waterlevel;
buf >> tmp;
DEBUG(printf("ADT: MCNK: MCLQ base floats: %f %f\n",_chunks[mcnkid].waterlevel,tmp));
//buf.rpos(buf.rpos()+4); // base height??
if(msize > 8) // just to be sure
{
for(uint32 i = 0; i < 81; i++)
{
_chunks[mcnkid].lqvertex[i] = buf.read<LiquidVertex>();
}
for(uint32 i = 0; i < 64; i++)
{
buf >> _chunks[mcnkid].lqflags[i];
}
rbytes = buf.rpos() - bufpos;
DEBUG(printf("ADT: MCNK: MCLQ block loaded. %u / %u bytes.\n",rbytes,msize));
}
else
{
DEBUG(printf("ADT: MCNK: MCLQ block has only %u bytes\n",msize));
}
// HACK: skip some unk junk bytes
diffbytes = (msize-8) - rbytes; // dont forget to skip the 8 initial bytes
buf.rpos(buf.rpos()+diffbytes);
DEBUG(printf("ADT: MCNK: MCLQ - %u junk bytes skipped\n",diffbytes));
delete [] fcc1;
}
}
else if(!strcmp((char*)mfcc,"MCSE"))
{
uint32 emm = _chunks[mcnkid].hdr.nSndEmitters;
for(uint32 i = 0; i < emm; i++)
{
_soundemm.push_back(buf.read<MCSE_chunk>());
}
break;
}
else
{
DEBUG(printf("ADT: MCNK: '%s' block unhandled, skipping %u bytes\n",mfcc,msize));
if(strcmp((char*)mfcc,"MCRF"))
{
printf("Error loading ADT file (chunk %u error).\n",mcnkid);
return false; // dont care about those few mem leaks
}
buf.rpos(buf.rpos()+msize);
}
}
delete [] mfcc;
mcnkid++;
}
else
{
DEBUG(printf("ADT: '%s' block unhandled, skipping %u bytes\n",fourcc,size));
if(strcmp((char*)fourcc,"MWID") && strcmp((char*)fourcc,"MMID"))
{
printf("Error loading ADT file.\n");
return false; // dont care about those few mem leaks
}
buf.rpos(buf.rpos()+size);
}
}
delete [] fourcc;
m_loaded = true;
return true;
}

30
src/shared/ADTFile.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef ADTFILE_H
#define ADTFILE_H
#define CHUNKS_PER_TILE 256
#include "ADTFileStructs.h"
class ADTFile
{
public:
bool Load(std::string);
bool LoadMem(ByteBuffer&);
bool Loaded(void) { return m_loaded; }
MapChunk _chunks[CHUNKS_PER_TILE]; // 16x16
std::vector<std::string> _textures;
std::vector<std::string> _wmos;
std::vector<std::string> _models;
std::vector<MDDF_chunk> _doodadsp;
std::vector<MODF_chunk> _wmosp;
std::vector<MCSE_chunk> _soundemm;
MHDR_chunk mhdr;
MCIN_chunk mcin[CHUNKS_PER_TILE];
uint32 _version;
bool m_loaded;
};
#endif

208
src/shared/ADTFileStructs.h Normal file
View File

@ -0,0 +1,208 @@
// all credit for this file goes to the guys who write the wiki article about ADT files @ wowdev.org
#ifndef ADTFILESTRUCTS_H
#define ADTFILESTRUCTS_H
struct MHDR_chunk
{
uint32 pad;
uint32 offsInfo;
uint32 offsTex;
uint32 offsModels;
uint32 offsModelsIds;
uint32 offsMapObejcts;
uint32 offsMapObejctsIds;
uint32 offsDoodsDef;
uint32 offsObjectsDef;
uint32 pad1;
uint32 pad2;
uint32 pad3;
uint32 pad4;
uint32 pad5;
uint32 pad6;
uint32 pad7;
};
struct MCIN_chunk
{
uint32 offset;
uint32 size;
uint32 flags;
uint32 async;
};
// MTEX: texture filename list. strings only!
// MMDX: M2 models filename list. strings only!
// MMID: string start offset list of the MMDX block
// MWMO: filename list for WMOs
// MWID: string start offset list of the MWMO block
struct MDDF_chunk
{
uint32 id; // position in the MMDX list
uint32 uniqueid; // unique instance id (?)
float x;
float y;
float z;
float oy;
float oz;
float ox;
uint16 flags;
uint16 scale;
};
struct MODF_chunk
{
uint32 id;
uint32 uniqueid;
float x;
float y;
float z;
float oy;
float oz;
float ox;
// unk floats (orientation?)
float ou11;
float ou12;
float ou13;
float ou21;
float ou22;
float ou23;
uint32 flags;
uint16 doodadSet;
uint16 nameSet;
};
enum MapChunkHeaderFlags
{
FLAG_SHADOW,
FLAG_IMPASS,
FLAG_LQ_RIVER,
FLAG_LQ_OCEAN,
FLAG_LQ_MAGMA,
};
struct MapChunkHeader
{
uint32 flags;
uint32 IndexX;
uint32 IndexY;
uint32 nLayers;
uint32 nDoodadRefs;
uint32 offsHeight;
uint32 offsNormal;
uint32 offsLayer;
uint32 offsRefs;
uint32 offsAlpha;
uint32 sizeAlpha;
uint32 offsShadow;
uint32 sizeShadow;
uint32 areaid;
uint32 nMapObjRefs;
uint32 holes;
uint16 unk1;
uint16 unk2;
uint32 unk3;
uint32 unk4;
uint32 unk5;
uint32 predTex;
uint32 noEffectDoodad;
uint32 offsSndEmitters;
uint32 nSndEmitters;
uint32 offsLiquid;
uint32 sizeLiquid; // includes the 8 initinal bytes ("MCLQ" and size)
float xbase;
float ybase;
float zbase;
uint32 textureId;
uint32 props;
uint32 effectId;
};
// MCNK sub-chunk
// 9x9+8x8 vertices. 145 floats, format: 9 outer, 8 inner, 9 outer, 8 inner, ... , 9 outer.
// MCNR chunk: Normal vectors for each vertex, encoded as 3 signed bytes per normal, in the same order as specified above.
struct MCLY_chunk
{
uint32 textureId; // offset in MTEX list
uint32 flags; // 0x100 means using alpha map
uint32 offAlpha;
uint32 effectId; //detail texture id (?)
};
// MCRF chunk:
// A list of indices into the parent file's MDDF chunk,
// saying which MCNK subchunk those particular MDDF doodads are drawn within.
// This MCRF list contains duplicates for map doodads that overlap areas.
// But I guess that's what the MDDF's UniqueID field is for.
// MCSH chunk: 8x8 bytes (64x64 bits) shadow map
struct MCSE_chunk
{
uint32 soundPointID;
uint32 soundNameID;
float x;
float y;
float z;
float minDistance;
float maxDistance;
float cutoffDistance;
uint16 startTime;
uint16 endTime;
uint16 groupSilenceMin;
uint16 groupSilenceMax;
uint16 playInstancesMin;
uint16 playInstancesMax;
uint16 loopCountMin;
uint16 loopCountMax;
uint16 interSoundGapMin;
uint16 interSoundGapMax;
};
struct LiquidVertex
{
uint16 unk1;
uint16 unk2;
float h;
};
struct NormalVector
{
uint8 x;
uint8 y;
uint8 z;
};
// also known as MCNK block
// 256 per adt file
struct MapChunk
{
MapChunkHeader hdr;
float vertices[145];
NormalVector normalvecs[145];
MCLY_chunk layer[4]; // can be less
uint32 nTextures;
uint8 shadowmap[512]; // 1 bit 64x64
uint8 alphamap[4][2048]; // 4 bits, 64x64. max 4, 1 per layer
bool haswater;
float waterlevel;
LiquidVertex lqvertex[81];
uint8 lqflags[64];
};
#endif

View File

@ -185,4 +185,15 @@ uint32 getMSTime(void)
return time_in_ms; return time_in_ms;
} }
uint32 GetFileSize(const char* sFileName)
{
std::ifstream f;
f.open(sFileName, std::ios_base::binary | std::ios_base::in);
if (!f.good() || f.eof() || !f.is_open()) { return 0; }
f.seekg(0, std::ios_base::beg);
std::ifstream::pos_type begin_pos = f.tellg();
f.seekg(0, std::ios_base::end);
return f.tellg() - begin_pos;
}

View File

@ -19,5 +19,6 @@ std::deque<std::string> GetFileList(std::string);
bool FileExists(std::string); bool FileExists(std::string);
bool CreateDir(const char*); bool CreateDir(const char*);
uint32 getMSTime(void); uint32 getMSTime(void);
uint32 GetFileSize(const char*);
#endif #endif

View File

@ -3,6 +3,7 @@
#include "common.h" #include "common.h"
#include "MPQHelper.h" #include "MPQHelper.h"
#include "dbcfile.h" #include "dbcfile.h"
#include "ADTFile.h"
#include "StuffExtract.h" #include "StuffExtract.h"
#include "DBCFieldData.h" #include "DBCFieldData.h"
#include "Locale.h" #include "Locale.h"
@ -268,6 +269,9 @@ void ExtractMaps(void)
} }
fh.write((char*)bb.contents(),bb.size()); fh.write((char*)bb.contents(),bb.size());
fh.close(); fh.close();
ADTFile *adt = new ADTFile();
adt->LoadMem(bb);
delete adt;
extr++; extr++;
} }
} }
@ -280,3 +284,8 @@ void ExtractMaps(void)
printf("\nDONE - %u maps extracted.\n",extrtotal); printf("\nDONE - %u maps extracted.\n",extrtotal);
} }
void DoNothingDummy(void)
{
delete [] new uint8[50];
}