feat(Tools/Vmapextractor): Improved vmap detail level by extracting w… (#4922)

This commit is contained in:
UltraNix
2021-04-05 11:51:51 +02:00
committed by GitHub
parent 1b4c36ec52
commit 0528e0b485
20 changed files with 514 additions and 369 deletions

View File

@@ -17,6 +17,7 @@ add_executable(vmap4extractor ${PRIVATE_SOURCES})
target_link_libraries(vmap4extractor
PUBLIC
g3dlib
mpq)
# Group sources

View File

@@ -6,7 +6,6 @@
#include "vmapexport.h"
#include "adtfile.h"
#include <algorithm>
#include <cstdio>
@@ -34,6 +33,9 @@ char* GetPlainName(char* FileName)
void fixnamen(char* name, size_t len)
{
if (len < 3)
return;
for (size_t i = 0; i < len - 3; i++)
{
if (i > 0 && name[i] >= 'A' && name[i] <= 'Z' && isalpha(name[i - 1]))
@@ -41,6 +43,7 @@ void fixnamen(char* name, size_t len)
else if ((i == 0 || !isalpha(name[i - 1])) && name[i] >= 'a' && name[i] <= 'z')
name[i] &= ~0x20;
}
//extension in lowercase
for (size_t i = len - 3; i < len; i++)
name[i] |= 0x20;
@@ -48,11 +51,12 @@ void fixnamen(char* name, size_t len)
void fixname2(char* name, size_t len)
{
if (len < 3)
return;
for (size_t i = 0; i < len - 3; i++)
{
if (name[i] == ' ')
name[i] = '_';
}
}
char* GetExtension(char* FileName)
@@ -62,33 +66,17 @@ char* GetExtension(char* FileName)
return nullptr;
}
ADTFile::ADTFile(char* filename): ADT(filename), nWMO(0), nMDX(0), WmoInstansName(nullptr), ModelInstansName(nullptr)
ADTFile::ADTFile(char* filename): _file(filename)
{
Adtfilename.append(filename);
}
bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
{
if (ADT.isEof ())
if (_file.isEof())
return false;
uint32 size;
string xMap;
string yMap;
Adtfilename.erase(Adtfilename.find(".adt"), 4);
string TempMapNumber;
TempMapNumber = Adtfilename.substr(Adtfilename.length() - 6, 6);
xMap = TempMapNumber.substr(TempMapNumber.find("_") + 1, (TempMapNumber.find_last_of("_") - 1) - (TempMapNumber.find("_")));
yMap = TempMapNumber.substr(TempMapNumber.find_last_of("_") + 1, (TempMapNumber.length()) - (TempMapNumber.find_last_of("_")));
Adtfilename.erase((Adtfilename.length() - xMap.length() - yMap.length() - 2), (xMap.length() + yMap.length() + 2));
//string AdtMapNumber = xMap + ' ' + yMap + ' ' + GetPlainName((char*)Adtfilename.c_str());
//printf("Processing map %s...\n", AdtMapNumber.c_str());
//printf("MapNumber = %s\n", TempMapNumber.c_str());
//printf("xMap = %s\n", xMap.c_str());
//printf("yMap = %s\n", yMap.c_str());
std::string dirname = std::string(szWorkDirWmo) + "/dir_bin";
FILE* dirfile;
dirfile = fopen(dirname.c_str(), "ab");
@@ -98,15 +86,15 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
return false;
}
while (!ADT.isEof())
while (!_file.isEof())
{
char fourcc[5];
ADT.read(&fourcc, 4);
ADT.read(&size, 4);
_file.read(&fourcc, 4);
_file.read(&size, 4);
flipcc(fourcc);
fourcc[4] = 0;
size_t nextpos = ADT.getPos() + size;
size_t nextpos = _file.getPos() + size;
if (!strcmp(fourcc, "MCIN"))
{
@@ -119,17 +107,15 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
if (size)
{
char* buf = new char[size];
ADT.read(buf, size);
_file.read(buf, size);
char* p = buf;
int t = 0;
ModelInstansName = new string[size];
while (p < buf + size)
{
fixnamen(p, strlen(p));
char* s = GetPlainName(p);
fixname2(s, strlen(s));
ModelInstansName[t++] = s;
ModelInstanceNames.emplace_back(s);
string path(p);
ExtractSingleModel(path);
@@ -144,17 +130,20 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
if (size)
{
char* buf = new char[size];
ADT.read(buf, size);
_file.read(buf, size);
char* p = buf;
int q = 0;
WmoInstansName = new string[size];
while (p < buf + size)
{
std::string path(p);
char* s = GetPlainName(p);
fixnamen(s, strlen(s));
fixname2(s, strlen(s));
WmoInstanceNames.emplace_back(s);
ExtractSingleWmo(path);
p += strlen(p) + 1;
WmoInstansName[q++] = s;
}
delete[] buf;
}
@@ -164,39 +153,38 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
{
if (size)
{
nMDX = (int)size / 36;
for (int i = 0; i < nMDX; ++i)
uint32 doodadCount = size / sizeof(ADT::MDDF);
for (uint32 i = 0; i < doodadCount; ++i)
{
uint32 id;
ADT.read(&id, 4);
ModelInstance inst(ADT, ModelInstansName[id].c_str(), map_num, tileX, tileY, dirfile);
ADT::MDDF doodadDef;
_file.read(&doodadDef, sizeof(ADT::MDDF));
Doodad::Extract(doodadDef, ModelInstanceNames[doodadDef.Id].c_str(), map_num, tileX, tileY, dirfile);
}
delete[] ModelInstansName;
}
}
else if (!strcmp(fourcc, "MODF"))
{
if (size)
{
nWMO = (int)size / 64;
for (int i = 0; i < nWMO; ++i)
uint32 mapObjectCount = size / sizeof(ADT::MODF);
for (uint32 i = 0; i < mapObjectCount; ++i)
{
uint32 id;
ADT.read(&id, 4);
WMOInstance inst(ADT, WmoInstansName[id].c_str(), map_num, tileX, tileY, dirfile);
ADT::MODF mapObjDef;
_file.read(&mapObjDef, sizeof(ADT::MODF));
MapObject::Extract(mapObjDef, WmoInstanceNames[mapObjDef.Id].c_str(), map_num, tileX, tileY, dirfile);
Doodad::ExtractSet(WmoDoodads[WmoInstanceNames[mapObjDef.Id]], mapObjDef, map_num, tileX, tileY, dirfile);
}
delete[] WmoInstansName;
}
}
//======================
ADT.seek(nextpos);
_file.seek(nextpos);
}
ADT.close();
_file.close();
fclose(dirfile);
return true;
}
ADTFile::~ADTFile()
{
ADT.close();
_file.close();
}

View File

@@ -94,20 +94,45 @@ struct MapChunkHeader
uint32 effectId;
};
#pragma pack(push, 1)
namespace ADT
{
struct MDDF
{
uint32 Id;
uint32 UniqueId;
Vec3D Position;
Vec3D Rotation;
uint16 Scale;
uint16 Flags;
};
struct MODF
{
uint32 Id;
uint32 UniqueId;
Vec3D Position;
Vec3D Rotation;
AaBox3D Bounds;
uint16 Flags;
uint16 DoodadSet; // can be larger than number of doodad sets in WMO
uint16 NameSet;
uint16 Scale;
};
}
#pragma pack(pop)
class ADTFile
{
private:
//size_t mcnk_offsets[256], mcnk_sizes[256];
MPQFile ADT;
//mcell Mcell;
string Adtfilename;
MPQFile _file;
std::string Adtfilename;
public:
ADTFile(char* filename);
~ADTFile();
int nWMO;
int nMDX;
string* WmoInstansName;
string* ModelInstansName;
std::vector<std::string> WmoInstanceNames;
std::vector<std::string> ModelInstanceNames;
bool init(uint32 map_num, uint32 tileX, uint32 tileY);
//void LoadMapChunks();

View File

@@ -8,17 +8,16 @@
#include "dbcfile.h"
#include "adtfile.h"
#include "vmapexport.h"
#include <algorithm>
#include <cstdio>
bool ExtractSingleModel(std::string& fname)
{
char* name = GetPlainName((char*)fname.c_str());
char* ext = GetExtension(name);
if (fname.length() < 4)
return false;
// < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file
if (!strcmp(ext, ".mdx"))
std::string extension = fname.substr(fname.length() - 4, 4);
if (extension == ".mdx" || extension == ".MDX" || extension == ".mdl" || extension == ".MDL")
{
// replace .mdx -> .m2
fname.erase(fname.length() - 2, 2);
@@ -27,6 +26,12 @@ bool ExtractSingleModel(std::string& fname)
// >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file
// nothing do
std::string originalName = fname;
char* name = GetPlainName((char*)fname.c_str());
fixnamen(name, strlen(name));
fixname2(name, strlen(name));
std::string output(szWorkDirWmo);
output += "/";
output += name;
@@ -34,7 +39,7 @@ bool ExtractSingleModel(std::string& fname)
if (FileExists(output.c_str()))
return true;
Model mdl(fname);
Model mdl(originalName);
if (!mdl.open())
return false;
@@ -63,6 +68,8 @@ void ExtractGameobjectModels()
return;
}
fwrite(VMAP::RAW_VMAP_MAGIC, 1, 8, model_list);
for (const auto & it : dbc)
{
path = it.getString(1);
@@ -81,8 +88,10 @@ void ExtractGameobjectModels()
strToLower(ch_ext);
bool result = false;
uint8 isWmo = 0;
if (!strcmp(ch_ext, ".wmo"))
{
isWmo = 1;
result = ExtractSingleWmo(path);
}
else if (!strcmp(ch_ext, ".mdl"))
@@ -100,6 +109,7 @@ void ExtractGameobjectModels()
uint32 displayId = it.getUInt(0);
uint32 path_length = strlen(name);
fwrite(&displayId, sizeof(uint32), 1, model_list);
fwrite(&isWmo, sizeof(uint8), 1, model_list);
fwrite(&path_length, sizeof(uint32), 1, model_list);
fwrite(name, sizeof(char), path_length, model_list);
}

View File

@@ -7,14 +7,16 @@
#include "vmapexport.h"
#include "model.h"
#include "wmo.h"
#include "mpq_libmpq04.h"
#include "adtfile.h"
#include <cassert>
#include "mpq_libmpq04.h"
#include <G3D/Quat.h>
#include <algorithm>
#include <cstdio>
#include <limits>
Model::Model(std::string& filename) : filename(filename), vertices(nullptr), indices(nullptr)
Model::Model(std::string& filename) : filename(filename), header(), vertices(nullptr), indices(nullptr)
{
memset(&header, 0, sizeof(header));
}
bool Model::open()
@@ -64,7 +66,7 @@ bool Model::ConvertToVMAPModel(const char* outfilename)
printf("Can't create the output file '%s'\n", outfilename);
return false;
}
fwrite(szRawVMAPMagic, 8, 1, output);
fwrite(VMAP::RAW_VMAP_MAGIC, 8, 1, output);
uint32 nVertices = header.nBoundingVertices;
fwrite(&nVertices, sizeof(int), 1, output);
uint32 nofgroups = 1;
@@ -118,38 +120,20 @@ bool Model::ConvertToVMAPModel(const char* outfilename)
return true;
}
Vec3D fixCoordSystem(Vec3D v)
Vec3D fixCoordSystem(Vec3D const& v)
{
return Vec3D(v.x, v.z, -v.y);
}
Vec3D fixCoordSystem2(Vec3D v)
void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
{
return Vec3D(v.x, v.z, v.y);
}
ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
{
float ff[3];
f.read(&id, 4);
f.read(ff, 12);
pos = fixCoords(Vec3D(ff[0], ff[1], ff[2]));
f.read(ff, 12);
rot = Vec3D(ff[0], ff[1], ff[2]);
f.read(&scale, 2);
f.read(&flags, 2);
// scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
sc = scale / 1024.0f;
char tempname[512];
char tempname[1036];
sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);
FILE* input = fopen(tempname, "r+b");
if (!input)
{
//printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
return;
}
fseek(input, 8, SEEK_SET); // get the correct no of vertices
int nVertices;
@@ -159,37 +143,111 @@ ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID
if (count != 1 || nVertices == 0)
return;
uint16 adtId = 0;// not used for models
uint32 flags = MOD_M2;
if (tileX == 65 && tileY == 65)
flags |= MOD_WORLDSPAWN;
// scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
float sc = doodadDef.Scale / 1024.0f;
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
Vec3D position = fixCoords(doodadDef.Position);
uint16 nameSet = 0;// not used for models
uint32 uniqueId = GenerateUniqueObjectId(doodadDef.UniqueId, 0);
uint32 tcflags = MOD_M2;
if (tileX == 65 && tileY == 65)
tcflags |= MOD_WORLDSPAWN;
//write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
fwrite(&flags, sizeof(uint32), 1, pDirfile);
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
fwrite(&id, sizeof(uint32), 1, pDirfile);
fwrite(&pos, sizeof(float), 3, pDirfile);
fwrite(&rot, sizeof(float), 3, pDirfile);
fwrite(&tcflags, sizeof(uint32), 1, pDirfile);
fwrite(&nameSet, sizeof(uint16), 1, pDirfile);
fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
fwrite(&position, sizeof(Vec3D), 1, pDirfile);
fwrite(&doodadDef.Rotation, sizeof(Vec3D), 1, pDirfile);
fwrite(&sc, sizeof(float), 1, pDirfile);
uint32 nlen = strlen(ModelInstName);
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
/* int realx1 = (int) ((float) pos.x / 533.333333f);
int realy1 = (int) ((float) pos.z / 533.333333f);
int realx2 = (int) ((float) pos.x / 533.333333f);
int realy2 = (int) ((float) pos.z / 533.333333f);
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
MapName,
ModelInstName,
(float) pos.x, (float) pos.y, (float) pos.z,
(float) rot.x, (float) rot.y, (float) rot.z,
sc,
nVertices,
realx1, realy1,
realx2, realy2
); */
}
void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
{
if (wmo.DoodadSet >= doodadData.Sets.size())
return;
G3D::Vector3 wmoPosition(wmo.Position.z, wmo.Position.x, wmo.Position.y);
G3D::Matrix3 wmoRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::toRadians(wmo.Rotation.y), G3D::toRadians(wmo.Rotation.x), G3D::toRadians(wmo.Rotation.z));
uint16 doodadId = 0;
WMO::MODS const& doodadSetData = doodadData.Sets[wmo.DoodadSet];
for (uint16 doodadIndex : doodadData.References)
{
if (doodadIndex < doodadSetData.StartIndex ||
doodadIndex >= doodadSetData.StartIndex + doodadSetData.Count)
continue;
WMO::MODD const& doodad = doodadData.Spawns[doodadIndex];
char ModelInstName[1024];
sprintf(ModelInstName, "%s", GetPlainName(&doodadData.Paths[doodad.NameIndex]));
uint32 nlen = strlen(ModelInstName);
fixnamen(ModelInstName, nlen);
fixname2(ModelInstName, nlen);
if (nlen > 3)
{
char const* extension = &ModelInstName[nlen - 4];
if (!strcmp(extension, ".mdx") || !strcmp(extension, ".mdl"))
{
ModelInstName[nlen - 2] = '2';
ModelInstName[nlen - 1] = '\0';
}
}
char tempname[1036];
sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);
FILE* input = fopen(tempname, "r+b");
if (!input)
continue;
fseek(input, 8, SEEK_SET); // get the correct no of vertices
int nVertices;
int count = fread(&nVertices, sizeof(int), 1, input);
fclose(input);
if (count != 1 || nVertices == 0)
continue;
assert(doodadId < std::numeric_limits<uint16>::max());
++doodadId;
G3D::Vector3 position = wmoPosition + (wmoRotation * G3D::Vector3(doodad.Position.x, doodad.Position.y, doodad.Position.z));
Vec3D rotation;
(G3D::Quat(doodad.Rotation.X, doodad.Rotation.Y, doodad.Rotation.Z, doodad.Rotation.W)
.toRotationMatrix() * wmoRotation)
.toEulerAnglesXYZ(rotation.z, rotation.x, rotation.y);
rotation.z = G3D::toDegrees(rotation.z);
rotation.x = G3D::toDegrees(rotation.x);
rotation.y = G3D::toDegrees(rotation.y);
uint16 nameSet = 0; // not used for models
uint32 uniqueId = GenerateUniqueObjectId(wmo.UniqueId, doodadId);
uint32 tcflags = MOD_M2;
if (tileX == 65 && tileY == 65)
tcflags |= MOD_WORLDSPAWN;
//write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
fwrite(&tcflags, sizeof(uint32), 1, pDirfile);
fwrite(&nameSet, sizeof(uint16), 1, pDirfile);
fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
fwrite(&position, sizeof(Vec3D), 1, pDirfile);
fwrite(&rotation, sizeof(Vec3D), 1, pDirfile);
fwrite(&doodad.Scale, sizeof(float), 1, pDirfile);
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
}
}

View File

@@ -13,8 +13,10 @@
#include <vector>
class MPQFile;
struct WMODoodadData;
namespace ADT { struct MDDF; struct MODF; }
Vec3D fixCoordSystem(Vec3D v);
Vec3D fixCoordSystem(Vec3D const& v);
class Model
{
@@ -39,16 +41,11 @@ public:
~Model() { _unload(); }
};
class ModelInstance
namespace Doodad
{
public:
uint32 id{0};
Vec3D pos, rot;
uint16 scale{0}, flags{0};
float sc{0.0f};
void Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
ModelInstance() {}
ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
};
void ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
}
#endif

View File

@@ -126,6 +126,13 @@ public:
}
};
class AaBox3D
{
public:
Vec3D min;
Vec3D max;
};
class Vec2D
{
public:
@@ -233,4 +240,9 @@ inline void rotate(float x0, float y0, float* x, float* y, float angle)
*y = xa * sinf(angle) + ya * cosf(angle) + y0;
}
struct Quaternion
{
float X, Y, Z, W;
};
#endif

View File

@@ -9,6 +9,7 @@
#include <cstdio>
#include <iostream>
#include <list>
#include <map>
#include <vector>
#include <sys/stat.h>
@@ -51,19 +52,24 @@ typedef struct
unsigned int id;
} map_id;
map_id* map_ids;
uint16* LiqType = nullptr;
std::vector<map_id> map_ids;
uint32 map_count;
char output_path[128] = ".";
char input_path[1024] = ".";
bool hasInputPathParam = false;
bool preciseVectorData = false;
std::unordered_map<std::string, WMODoodadData> WmoDoodads;
// Constants
//static const char * szWorkDirMaps = ".\\Maps";
const char* szWorkDirWmo = "./Buildings";
const char* szRawVMAPMagic = "VMAP044";
char const* szWorkDirWmo = "./Buildings";
std::map<std::pair<uint32, uint16>, uint32> uniqueObjectIds;
uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId)
{
return uniqueObjectIds.emplace(std::make_pair(clientId, clientDoodadId), uint32(uniqueObjectIds.size() + 1)).first->second;
}
// Local testing functions
@@ -86,60 +92,16 @@ void strToLower(char* str)
}
}
// copied from contrib/extractor/System.cpp
void ReadLiquidTypeTableDBC()
{
printf("Read LiquidType.dbc file...");
DBCFile dbc("DBFilesClient\\LiquidType.dbc");
if (!dbc.open())
{
printf("Fatal error: Invalid LiquidType.dbc file format!\n");
exit(1);
}
size_t LiqType_count = dbc.getRecordCount();
size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0);
LiqType = new uint16[LiqType_maxid + 1];
memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16));
for (uint32 x = 0; x < LiqType_count; ++x)
LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
printf("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count);
}
bool ExtractWmo()
{
bool success = true;
//const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"};
for (ArchiveSet::const_iterator ar_itr = gOpenArchives.begin(); ar_itr != gOpenArchives.end() && success; ++ar_itr)
{
vector<string> filelist;
(*ar_itr)->GetFileListTo(filelist);
for (vector<string>::iterator fname = filelist.begin(); fname != filelist.end() && success; ++fname)
{
if (fname->find(".wmo") != string::npos)
success = ExtractSingleWmo(*fname);
}
}
if (success)
printf("\nExtract wmo complete (No (fatal) errors)\n");
return success;
}
bool ExtractSingleWmo(std::string& fname)
{
// Copy files from archive
std::string originalName = fname;
char szLocalFile[1024];
const char* plain_name = GetPlainName(fname.c_str());
char* plain_name = GetPlainName(&fname[0]);
fixnamen(plain_name, strlen(plain_name));
fixname2(plain_name, strlen(plain_name));
sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name);
fixnamen(szLocalFile, strlen(szLocalFile));
if (FileExists(szLocalFile))
return true;
@@ -162,12 +124,12 @@ bool ExtractSingleWmo(std::string& fname)
return true;
bool file_ok = true;
std::cout << "Extracting " << fname << std::endl;
WMORoot froot(fname);
printf("Extracting %s\n", originalName.c_str());
WMORoot froot(originalName);
if (!froot.open())
{
printf("Couldn't open RootWmo!!!\n");
return true;
return false;
}
FILE* output = fopen(szLocalFile, "wb");
if (!output)
@@ -176,6 +138,8 @@ bool ExtractSingleWmo(std::string& fname)
return false;
}
froot.ConvertToVMAPRootWmo(output);
WMODoodadData& doodads = WmoDoodads[plain_name];
std::swap(doodads, froot.DoodadData);
int Wmo_nVertices = 0;
//printf("root has %d groups\n", froot->nGroups);
if (froot.nGroups != 0)
@@ -204,6 +168,17 @@ bool ExtractSingleWmo(std::string& fname)
}
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData);
for (uint16 groupReference : fgroup.DoodadReferences)
{
if (groupReference >= doodads.Spawns.size())
continue;
uint32 doodadNameIndex = doodads.Spawns[groupReference].NameIndex;
if (froot.ValidDoodadNames.find(doodadNameIndex) == froot.ValidDoodadNames.end())
continue;
doodads.References.insert(groupReference);
}
}
}
@@ -221,13 +196,11 @@ void ParsMapFiles()
{
char fn[512];
//char id_filename[64];
char id[10];
for (unsigned int i = 0; i < map_count; ++i)
{
sprintf(id, "%03u", map_ids[i].id);
snprintf(fn, sizeof(fn), R"(World\Maps\%s\%s.wdt)", map_ids[i].name, map_ids[i].name);
WDTFile WDT(fn, map_ids[i].name);
if (WDT.init(id, map_ids[i].id))
sprintf(fn,"World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name);
WDTFile WDT(fn,map_ids[i].name);
if (WDT.init(map_ids[i].id))
{
printf("Processing Map %u\n[", map_ids[i].id);
for (int x = 0; x < 64; ++x)
@@ -490,11 +463,6 @@ int main(int argc, char** argv)
printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n", input_path);
return 1;
}
ReadLiquidTypeTableDBC();
// extract data
if (success)
success = ExtractWmo();
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//map.dbc
@@ -507,18 +475,28 @@ int main(int argc, char** argv)
printf("FATAL ERROR: Map.dbc not found in data file.\n");
return 1;
}
map_count = dbc->getRecordCount ();
map_ids = new map_id[map_count];
map_count = dbc->getRecordCount();
map_ids.resize(map_count);
for (unsigned int x = 0; x < map_count; ++x)
{
map_ids[x].id = dbc->getRecord (x).getUInt(0);
strcpy(map_ids[x].name, dbc->getRecord(x).getString(1));
map_ids[x].id = dbc->getRecord(x).getUInt(0);
char const* map_name = dbc->getRecord(x).getString(1);
size_t max_map_name_length = sizeof(map_ids[x].name);
if (strlen(map_name) >= max_map_name_length)
{
delete dbc;
printf("FATAL ERROR: Map name too long.\n");
return 1;
}
strncpy(map_ids[x].name, map_name, max_map_name_length);
map_ids[x].name[max_map_name_length - 1] = '\0';
printf("Map - %s\n", map_ids[x].name);
}
delete dbc;
ParsMapFiles();
delete [] map_ids;
//nError = ERROR_SUCCESS;
// Extract models, listed in DameObjectDisplayInfo.dbc
ExtractGameobjectModels();
@@ -532,6 +510,5 @@ int main(int argc, char** argv)
}
printf("Extract %s. Work complete. No errors.\n", versionString);
delete [] LiqType;
return 0;
}

View File

@@ -7,7 +7,15 @@
#ifndef VMAPEXPORT_H
#define VMAPEXPORT_H
#include "loadlib/loadlib.h"
#include <string>
#include <unordered_map>
namespace VMAP
{
const char VMAP_MAGIC[] = "VMAP_4.5";
const char RAW_VMAP_MAGIC[] = "VMAP045"; // used in extracted vmap files with raw data
}
enum ModelFlags
{
@@ -16,8 +24,12 @@ enum ModelFlags
MOD_HAS_BOUND = 1 << 2
};
extern const char* szWorkDirWmo;
extern const char* szRawVMAPMagic; // vmap magic string for extracted raw vmap data
struct WMODoodadData;
extern const char * szWorkDirWmo;
extern std::unordered_map<std::string, WMODoodadData> WmoDoodads;
uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId);
bool FileExists(const char* file);
void strToLower(char* str);

View File

@@ -7,6 +7,7 @@
#include "vmapexport.h"
#include "wdtfile.h"
#include "adtfile.h"
#include <cstdio>
char* wdtGetPlainName(char* FileName)
@@ -18,14 +19,14 @@ char* wdtGetPlainName(char* FileName)
return FileName;
}
WDTFile::WDTFile(char* file_name, char* file_name1) : WDT(file_name), gWmoInstansName(nullptr), gnWMO(0)
WDTFile::WDTFile(char* file_name, char* file_name1) : _file(file_name)
{
filename.append(file_name1, strlen(file_name1));
}
bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
bool WDTFile::init(uint32 mapId)
{
if (WDT.isEof())
if (_file.isEof())
{
//printf("Can't find WDT file.\n");
return false;
@@ -43,15 +44,15 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
return false;
}
while (!WDT.isEof())
while (!_file.isEof())
{
WDT.read(fourcc, 4);
WDT.read(&size, 4);
_file.read(fourcc, 4);
_file.read(&size, 4);
flipcc(fourcc);
fourcc[4] = 0;
size_t nextpos = WDT.getPos() + size;
size_t nextpos = _file.getPos() + size;
if (!strcmp(fourcc, "MAIN"))
{
@@ -62,16 +63,19 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
if (size)
{
char* buf = new char[size];
WDT.read(buf, size);
_file.read(buf, size);
char* p = buf;
int q = 0;
gWmoInstansName = new string[size];
while (p < buf + size)
{
std::string path(p);
char* s = wdtGetPlainName(p);
fixnamen(s, strlen(s));
fixname2(s, strlen(s));
p = p + strlen(p) + 1;
gWmoInstansName[q++] = s;
_wmoNames.push_back(s);
ExtractSingleWmo(path);
}
delete[] buf;
}
@@ -81,29 +85,27 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
// global wmo instance data
if (size)
{
gnWMO = (int)size / 64;
for (int i = 0; i < gnWMO; ++i)
uint32 mapObjectCount = size / sizeof(ADT::MODF);
for (uint32 i = 0; i < mapObjectCount; ++i)
{
int id;
WDT.read(&id, 4);
WMOInstance inst(WDT, gWmoInstansName[id].c_str(), mapID, 65, 65, dirfile);
ADT::MODF mapObjDef;
_file.read(&mapObjDef, sizeof(ADT::MODF));
MapObject::Extract(mapObjDef, _wmoNames[mapObjDef.Id].c_str(), mapId, 65, 65, dirfile);
Doodad::ExtractSet(WmoDoodads[_wmoNames[mapObjDef.Id]], mapObjDef, mapId, 65, 65, dirfile);
}
delete[] gWmoInstansName;
}
}
WDT.seek((int)nextpos);
_file.seek((int)nextpos);
}
WDT.close();
_file.close();
fclose(dirfile);
return true;
}
WDTFile::~WDTFile()
{
WDT.close();
_file.close();
}
ADTFile* WDTFile::GetMap(int x, int z)

View File

@@ -16,18 +16,18 @@ class ADTFile;
class WDTFile
{
private:
MPQFile WDT;
string filename;
public:
WDTFile(char* file_name, char* file_name1);
~WDTFile();
bool init(char* map_id, unsigned int mapID);
string* gWmoInstansName;
int gnWMO;
~WDTFile(void);
bool init(uint32 mapId);
ADTFile* GetMap(int x, int z);
std::vector<std::string> _wmoNames;
private:
MPQFile _file;
std::string filename;
};
#endif

View File

@@ -4,6 +4,7 @@
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#include "adtfile.h"
#include "wmo.h"
#include "vec3d.h"
#include "vmapexport.h"
@@ -17,12 +18,9 @@
#undef max
#include "mpq_libmpq04.h"
using namespace std;
extern uint16* LiqType;
WMORoot::WMORoot(std::string& filename)
: filename(filename), col(0), nTextures(0), nGroups(0), nP(0), nLights(0),
nModels(0), nDoodads(0), nDoodadSets(0), RootWMOID(0), liquidType(0)
WMORoot::WMORoot(std::string const& filename)
: filename(filename), color(0), nTextures(0), nGroups(0), nPortals(0), nLights(0),
nDoodadNames(0), nDoodadDefs(0), nDoodadSets(0), RootWMOID(0), liquidType(0)
{
memset(bbcorn1, 0, sizeof(bbcorn1));
memset(bbcorn2, 0, sizeof(bbcorn2));
@@ -54,17 +52,47 @@ bool WMORoot::open()
{
f.read(&nTextures, 4);
f.read(&nGroups, 4);
f.read(&nP, 4);
f.read(&nPortals, 4);
f.read(&nLights, 4);
f.read(&nModels, 4);
f.read(&nDoodads, 4);
f.read(&nDoodadNames, 4);
f.read(&nDoodadDefs, 4);
f.read(&nDoodadSets, 4);
f.read(&col, 4);
f.read(&color, 4);
f.read(&RootWMOID, 4);
f.read(bbcorn1, 12);
f.read(bbcorn2, 12);
f.read(&liquidType, 4);
break;
}
else if (!strcmp(fourcc, "MODS"))
{
DoodadData.Sets.resize(size / sizeof(WMO::MODS));
f.read(DoodadData.Sets.data(), size);
}
else if (!strcmp(fourcc,"MODN"))
{
char* ptr = f.getPointer();
char* end = ptr + size;
DoodadData.Paths = std::make_unique<char[]>(size);
memcpy(DoodadData.Paths.get(), ptr, size);
while (ptr < end)
{
std::string path = ptr;
char* s = GetPlainName(ptr);
fixnamen(s, strlen(s));
fixname2(s, strlen(s));
uint32 doodadNameIndex = ptr - f.getPointer();
ptr += path.length() + 1;
if (ExtractSingleModel(path))
ValidDoodadNames.insert(doodadNameIndex);
}
}
else if (!strcmp(fourcc,"MODD"))
{
DoodadData.Spawns.resize(size / sizeof(WMO::MODD));
f.read(DoodadData.Spawns.data(), size);
}
/*
else if (!strcmp(fourcc,"MOTX"))
@@ -82,15 +110,6 @@ bool WMORoot::open()
else if (!strcmp(fourcc,"MOLT"))
{
}
else if (!strcmp(fourcc,"MODN"))
{
}
else if (!strcmp(fourcc,"MODS"))
{
}
else if (!strcmp(fourcc,"MODD"))
{
}
else if (!strcmp(fourcc,"MOSB"))
{
}
@@ -117,7 +136,7 @@ bool WMORoot::ConvertToVMAPRootWmo(FILE* pOutfile)
{
//printf("Convert RootWmo...\n");
fwrite(szRawVMAPMagic, 1, 8, pOutfile);
fwrite(VMAP::RAW_VMAP_MAGIC, 1, 8, pOutfile);
unsigned int nVectors = 0;
fwrite(&nVectors, sizeof(nVectors), 1, pOutfile); // will be filled later
fwrite(&nGroups, 4, 1, pOutfile);
@@ -125,7 +144,7 @@ bool WMORoot::ConvertToVMAPRootWmo(FILE* pOutfile)
return true;
}
WMOGroup::WMOGroup(std::string filename) :
WMOGroup::WMOGroup(std::string const& filename) :
filename(std::move(filename)), MOPY(nullptr), MOVI(nullptr), MoviEx(nullptr), MOVT(nullptr), MOBA(nullptr), MobaEx(nullptr),
hlq(nullptr), LiquEx(nullptr), LiquBytes(nullptr), groupName(0), descGroupName(0), mogpFlags(0),
moprIdx(0), moprNItems(0), nBatchA(0), nBatchB(0), nBatchC(0), fogIdx(0),
@@ -206,11 +225,16 @@ bool WMOGroup::open()
moba_size = size / 2;
f.read(MOBA, size);
}
else if (!strcmp(fourcc, "MLIQ"))
else if (!strcmp(fourcc,"MODR"))
{
DoodadReferences.resize(size / sizeof(uint16));
f.read(DoodadReferences.data(), size);
}
else if (!strcmp(fourcc,"MLIQ"))
{
liquflags |= 1;
hlq = new WMOLiquidHeader();
f.read(hlq, 0x1E);
f.read(hlq, sizeof(WMOLiquidHeader));
LiquEx_size = sizeof(WMOLiquidVert) * hlq->xverts * hlq->yverts;
LiquEx = new WMOLiquidVert[hlq->xverts * hlq->yverts];
f.read(LiquEx, LiquEx_size);
@@ -391,7 +415,7 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool precise
//------LIQU------------------------
if (LiquEx_size != 0)
{
int LIQU_h[] = {0x5551494C, static_cast<int>(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles* hlq->ytiles}; // "LIQU"
int LIQU_h[] = { 0x5551494C, static_cast<int>(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles * hlq->ytiles }; // "LIQU"
fwrite(LIQU_h, 4, 2, output);
// according to WoW.Dev Wiki:
@@ -472,28 +496,16 @@ WMOGroup::~WMOGroup()
delete [] LiquBytes;
}
WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
: currx(0), curry(0), wmo(nullptr), doodadset(0), pos(), indx(0), id(0), d2(0), d3(0)
void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
{
float ff[3];
f.read(&id, 4);
f.read(ff, 12);
pos = Vec3D(ff[0], ff[1], ff[2]);
f.read(ff, 12);
rot = Vec3D(ff[0], ff[1], ff[2]);
f.read(ff, 12);
pos2 = Vec3D(ff[0], ff[1], ff[2]);
f.read(ff, 12);
pos3 = Vec3D(ff[0], ff[1], ff[2]);
f.read(&d2, 4);
uint16 trash, adtId;
f.read(&adtId, 2);
f.read(&trash, 2);
// destructible wmo, do not dump. we can handle the vmap for these
// in dynamic tree (gameobject vmaps)
if ((mapObjDef.Flags & 0x1) != 0)
return;
//-----------add_in _dir_file----------------
char tempname[512];
char tempname[1036];
sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName);
FILE* input;
input = fopen(tempname, "r+b");
@@ -512,46 +524,39 @@ WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint
if (count != 1 || nVertices == 0)
return;
Vec3D position = mapObjDef.Position;
float x, z;
x = pos.x;
z = pos.z;
x = position.x;
z = position.z;
if (x == 0 && z == 0)
{
pos.x = 533.33333f * 32;
pos.z = 533.33333f * 32;
position.x = 533.33333f * 32;
position.z = 533.33333f * 32;
}
pos = fixCoords(pos);
pos2 = fixCoords(pos2);
pos3 = fixCoords(pos3);
position = fixCoords(position);
AaBox3D bounds;
bounds.min = fixCoords(mapObjDef.Bounds.min);
bounds.max = fixCoords(mapObjDef.Bounds.max);
float scale = 1.0f;
uint32 uniqueId = GenerateUniqueObjectId(mapObjDef.UniqueId, 0);
uint32 flags = MOD_HAS_BOUND;
if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN;
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
//write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
fwrite(&flags, sizeof(uint32), 1, pDirfile);
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
fwrite(&id, sizeof(uint32), 1, pDirfile);
fwrite(&pos, sizeof(float), 3, pDirfile);
fwrite(&rot, sizeof(float), 3, pDirfile);
fwrite(&mapObjDef.NameSet, sizeof(uint16), 1, pDirfile);
fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
fwrite(&position, sizeof(Vec3D), 1, pDirfile);
fwrite(&mapObjDef.Rotation, sizeof(Vec3D), 1, pDirfile);
fwrite(&scale, sizeof(float), 1, pDirfile);
fwrite(&pos2, sizeof(float), 3, pDirfile);
fwrite(&pos3, sizeof(float), 3, pDirfile);
fwrite(&bounds, sizeof(AaBox3D), 1, pDirfile);
uint32 nlen = strlen(WmoInstName);
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
fwrite(WmoInstName, sizeof(char), nlen, pDirfile);
/* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n",
MapName,
WmoInstName,
(float) x, (float) pos.y, (float) z,
(float) rot.x, (float) rot.y, (float) rot.z,
nVertices,
realx1, realy1,
realx2, realy2
); */
// fclose(dirfile);
}

View File

@@ -6,14 +6,18 @@
#ifndef WMO_H
#define WMO_H
#define TILESIZE (533.33333f)
#define CHUNKSIZE ((TILESIZE) / 16.0f)
#include <memory>
#include <string>
#include <set>
#include <unordered_set>
#include <vector>
#include "vec3d.h"
#include "loadlib/loadlib.h"
#define TILESIZE (533.33333f)
#define CHUNKSIZE ((TILESIZE) / 16.0f)
// MOPY flags
enum MopyFlags
{
@@ -30,26 +34,60 @@ enum MopyFlags
class WMOInstance;
class WMOManager;
class MPQFile;
namespace ADT { struct MODF; }
namespace WMO
{
struct MODS
{
char Name[20];
uint32 StartIndex; // index of first doodad instance in this set
uint32 Count; // number of doodad instances in this set
char _pad[4];
};
struct MODD
{
uint32 NameIndex : 24;
Vec3D Position;
Quaternion Rotation;
float Scale;
uint32 Color;
};
}
/* for whatever reason a certain company just can't stick to one coordinate system... */
static inline Vec3D fixCoords(const Vec3D& v) { return Vec3D(v.z, v.x, v.y); }
struct WMODoodadData
{
std::vector<WMO::MODS> Sets;
std::unique_ptr<char[]> Paths;
std::vector<WMO::MODD> Spawns;
std::unordered_set<uint16> References;
};
class WMORoot
{
private:
std::string filename;
public:
unsigned int col;
uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType;
unsigned int color;
uint32 nTextures, nGroups, nPortals, nLights, nDoodadNames, nDoodadDefs, nDoodadSets, RootWMOID, liquidType;
float bbcorn1[3];
float bbcorn2[3];
WMORoot(std::string& filename);
WMODoodadData DoodadData;
std::unordered_set<uint32> ValidDoodadNames;
WMORoot(std::string const& filename);
bool open();
bool ConvertToVMAPRootWmo(FILE* output);
};
#pragma pack(push, 1)
struct WMOLiquidHeader
{
int xverts, yverts, xtiles, ytiles;
@@ -66,6 +104,8 @@ struct WMOLiquidVert
float height;
};
#pragma pack(pop)
class WMOGroup
{
private:
@@ -98,29 +138,18 @@ public:
int nTriangles; // number when loaded
uint32 liquflags;
WMOGroup(std::string filename);
std::vector<uint16> DoodadReferences;
WMOGroup(std::string const& filename);
~WMOGroup();
bool open();
int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool preciseVectorData);
};
class WMOInstance
namespace MapObject
{
static std::set<int> ids;
public:
std::string MapName;
int currx;
int curry;
WMOGroup* wmo;
int doodadset;
Vec3D pos;
Vec3D pos2, pos3, rot;
uint32 indx, id, d2, d3;
WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
static void reset();
};
void Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
}
#endif