diff options
| author | Shauren <shauren.trinity@gmail.com> | 2016-07-18 23:37:19 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-07-18 23:37:19 +0200 |
| commit | fe4d11c65a512c61ccb924fbf3dc20c8cfc84dc7 (patch) | |
| tree | 86888deb22268503d70ae7259bbf17add4dcdc1f /src/tools/vmap4_extractor | |
| parent | a9a13d10f7c510bb392539608cb276435a78b688 (diff) | |
Tools: Extractor updates
* VMAP extractor does not work due to a bug in CascLib
Diffstat (limited to 'src/tools/vmap4_extractor')
| -rw-r--r-- | src/tools/vmap4_extractor/DB2.cpp | 199 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/DB2.h | 178 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/dbcfile.cpp | 120 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/dbcfile.h | 161 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/gameobject_extract.cpp | 123 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/model.cpp | 12 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/vmapexport.cpp | 132 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/wmo.cpp | 32 | ||||
| -rw-r--r-- | src/tools/vmap4_extractor/wmo.h | 7 |
9 files changed, 567 insertions, 397 deletions
diff --git a/src/tools/vmap4_extractor/DB2.cpp b/src/tools/vmap4_extractor/DB2.cpp new file mode 100644 index 00000000000..52d4a1544af --- /dev/null +++ b/src/tools/vmap4_extractor/DB2.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DB2.h" + +DB2FileLoader::DB2FileLoader() +{ + meta = nullptr; + + recordSize = 0; + recordCount = 0; + fieldCount = 0; + stringSize = 0; + tableHash = 0; + layoutHash = 0; + minIndex = 0; + maxIndex = 0; + localeMask = 0; + copyIdSize = 0; + + data = nullptr; + stringTable = nullptr; + idTable = nullptr; + idTableSize = 0; + copyTable = nullptr; + fields = nullptr; +} + +bool DB2FileLoader::Load(HANDLE db2Handle, DB2Meta const* meta) +{ + if (data) + { + delete[] data; + data = nullptr; + } + + DWORD bytesRead = 0; + this->meta = meta; + std::uint32_t header; + CascReadFile(db2Handle, &header, sizeof(header), &bytesRead); + if (bytesRead != sizeof(header)) // Signature + return false; + + EndianConvert(header); + + if (header != 0x35424457) + return false; //'WDB5' + + CascReadFile(db2Handle, &recordCount, sizeof(recordCount), &bytesRead); + if (bytesRead != sizeof(recordCount)) // Number of records + return false; + + EndianConvert(recordCount); + + CascReadFile(db2Handle, &fieldCount, sizeof(fieldCount), &bytesRead); + if (bytesRead != sizeof(fieldCount)) // Number of fields + return false; + + EndianConvert(fieldCount); + + CascReadFile(db2Handle, &recordSize, sizeof(recordSize), &bytesRead); + if (bytesRead != sizeof(recordSize)) // Size of a record + return false; + + EndianConvert(recordSize); + + CascReadFile(db2Handle, &stringSize, sizeof(stringSize), &bytesRead); + if (bytesRead != sizeof(stringSize)) // String size + return false; + + EndianConvert(stringSize); + + CascReadFile(db2Handle, &tableHash, sizeof(tableHash), &bytesRead); + if (bytesRead != sizeof(tableHash)) // Table hash + return false; + + EndianConvert(tableHash); + + CascReadFile(db2Handle, &layoutHash, sizeof(layoutHash), &bytesRead); + if (bytesRead != sizeof(layoutHash)) // Layout hash + return false; + + if (layoutHash != meta->LayoutHash) + return false; + + EndianConvert(layoutHash); + + CascReadFile(db2Handle, &minIndex, sizeof(minIndex), &bytesRead); + if (bytesRead != sizeof(minIndex)) // MinIndex WDB2 + return false; + + EndianConvert(minIndex); + + CascReadFile(db2Handle, &maxIndex, sizeof(maxIndex), &bytesRead); + if (bytesRead != sizeof(maxIndex)) // MaxIndex WDB2 + return false; + + EndianConvert(maxIndex); + + CascReadFile(db2Handle, &localeMask, sizeof(localeMask), &bytesRead); + if (bytesRead != sizeof(localeMask)) // Locales + return false; + + EndianConvert(localeMask); + + CascReadFile(db2Handle, ©IdSize, sizeof(copyIdSize), &bytesRead); + if (bytesRead != sizeof(copyIdSize)) + return false; + + EndianConvert(copyIdSize); + + CascReadFile(db2Handle, &metaFlags, sizeof(metaFlags), &bytesRead); + if (bytesRead != sizeof(metaFlags)) + return false; + + EndianConvert(metaFlags); + + ASSERT((metaFlags & 0x1) == 0); + ASSERT((meta->IndexField == -1) || (meta->IndexField == (metaFlags >> 16))); + + fields = new FieldEntry[fieldCount]; + CascReadFile(db2Handle, fields, fieldCount * sizeof(FieldEntry), &bytesRead); + if (bytesRead != fieldCount * sizeof(FieldEntry)) + return false; + + if (!meta->HasIndexFieldInData()) + idTableSize = recordCount * sizeof(std::uint32_t); + + data = new unsigned char[recordSize * recordCount + stringSize]; + stringTable = data + recordSize * recordCount; + + CascReadFile(db2Handle, data, recordSize * recordCount + stringSize, &bytesRead); + if (bytesRead != recordSize * recordCount + stringSize) + return false; + + if (idTableSize) + { + idTable = new unsigned char[idTableSize]; + CascReadFile(db2Handle, idTable, idTableSize, &bytesRead); + if (bytesRead != idTableSize) + return false; + } + + if (copyIdSize) + { + copyTable = new unsigned char[copyIdSize]; + CascReadFile(db2Handle, copyTable, copyIdSize, &bytesRead); + if (bytesRead != copyIdSize) + return false; + } + + return true; +} + +DB2FileLoader::~DB2FileLoader() +{ + delete[] data; + delete[] idTable; + delete[] copyTable; + delete[] fields; +} + +DB2FileLoader::Record DB2FileLoader::getRecord(size_t id) +{ + assert(data); + return Record(*this, data + id * recordSize); +} + +std::pair<std::uint32_t, std::uint32_t> DB2FileLoader::GetRowCopy(std::uint32_t i) const +{ + std::uint32_t* copyIds = (std::uint32_t*)copyTable; + std::uint32_t to = copyIds[i]; + std::uint32_t from = copyIds[i + 1]; + return{ from, to }; +} + +std::uint32_t DB2FileLoader::GetMaxId() const +{ + std::uint32_t j = maxIndex; + for (std::uint32_t i = 0; i < GetNumRowCopies(); ++i) + if (j < GetRowCopy(i).second) + j = GetRowCopy(i).second; + + return j; +} diff --git a/src/tools/vmap4_extractor/DB2.h b/src/tools/vmap4_extractor/DB2.h new file mode 100644 index 00000000000..0cb6c111941 --- /dev/null +++ b/src/tools/vmap4_extractor/DB2.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MapExtractor_DB2_h__ +#define MapExtractor_DB2_h__ + +#include "DB2Meta.h" +#ifdef PLATFORM_WINDOWS +#undef PLATFORM_WINDOWS +#endif +#include "CascLib.h" +#include "Utilities/ByteConverter.h" +#include "Errors.h" + +class DB2FileLoader +{ + public: + DB2FileLoader(); + ~DB2FileLoader(); + + bool Load(HANDLE db2Handle, DB2Meta const* meta); + + class Record + { + public: + float getFloat(std::uint32_t field, std::uint32_t arrayIndex) const + { + ASSERT(field < file.fieldCount); + float val = *reinterpret_cast<float*>(offset + GetOffset(field) + arrayIndex * sizeof(float)); + EndianConvert(val); + return val; + } + + std::uint32_t getUInt(std::uint32_t field, std::uint32_t arrayIndex) const + { + ASSERT(field < file.fieldCount); + return GetVarInt(field, GetByteSize(field), arrayIndex); + } + + std::uint8_t getUInt8(std::uint32_t field, std::uint32_t arrayIndex) const + { + ASSERT(field < file.fieldCount); + ASSERT(GetByteSize(field) == 1); + return *reinterpret_cast<std::uint8_t*>(offset + GetOffset(field) + arrayIndex * sizeof(std::uint8_t)); + } + + std::uint16_t getUInt16(std::uint32_t field, std::uint32_t arrayIndex) const + { + ASSERT(field < file.fieldCount); + ASSERT(GetByteSize(field) == 2); + std::uint16_t val = *reinterpret_cast<std::uint16_t*>(offset + GetOffset(field) + arrayIndex * sizeof(std::uint16_t)); + EndianConvert(val); + return val; + } + + char const* getString(std::uint32_t field, std::uint32_t arrayIndex) const + { + ASSERT(field < file.fieldCount); + std::uint32_t stringOffset = *reinterpret_cast<std::uint32_t*>(offset + GetOffset(field) + arrayIndex * sizeof(std::uint32_t)); + EndianConvert(stringOffset); + ASSERT(stringOffset < file.stringSize); + return reinterpret_cast<char*>(file.stringTable + stringOffset); + } + + private: + std::uint16_t GetOffset(std::uint32_t field) const + { + ASSERT(field < file.fieldCount); + return file.fields[field].Offset; + } + + std::uint16_t GetByteSize(std::uint32_t field) const + { + ASSERT(field < file.fieldCount); + return 4 - file.fields[field].UnusedBits / 8; + } + + std::uint32_t GetVarInt(std::uint32_t field, std::uint16_t size, std::uint32_t arrayIndex) const + { + ASSERT(field < file.fieldCount); + switch (size) + { + case 1: + { + return *reinterpret_cast<std::uint8_t*>(offset + GetOffset(field) + arrayIndex * sizeof(std::uint8_t)); + } + case 2: + { + std::uint16_t val = *reinterpret_cast<std::uint16_t*>(offset + GetOffset(field) + arrayIndex * sizeof(std::uint16_t)); + EndianConvert(val); + return val; + } + case 3: + { +#pragma pack(push, 1) + struct dbcint24 { std::uint8_t v[3]; }; +#pragma pack(pop) + dbcint24 val = *reinterpret_cast<dbcint24*>(offset + GetOffset(field) + arrayIndex * sizeof(dbcint24)); + EndianConvert(val); + return std::uint32_t(val.v[0]) | (std::uint32_t(val.v[1]) << 8) | (std::uint32_t(val.v[2]) << 16); + } + case 4: + { + std::uint32_t val = *reinterpret_cast<std::uint32_t*>(offset + GetOffset(field) + arrayIndex * sizeof(std::uint32_t)); + EndianConvert(val); + return val; + } + default: + break; + } + + ASSERT(false, "GetByteSize(field) < 4"); + return 0; + } + + Record(DB2FileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {} + unsigned char *offset; + DB2FileLoader &file; + + friend class DB2FileLoader; + }; + + // Get record by id + Record getRecord(size_t id); + std::uint32_t getId(size_t row) { return ((std::uint32_t*)idTable)[row]; } + std::pair<std::uint32_t, std::uint32_t> GetRowCopy(std::uint32_t i) const; + + std::uint32_t GetNumRows() const { return recordCount; } + std::uint32_t GetNumRowCopies() const { return copyIdSize / 8; } + std::uint32_t GetMaxId() const; + +private: +#pragma pack(push, 1) + struct FieldEntry + { + std::uint16_t UnusedBits; + std::uint16_t Offset; + }; +#pragma pack(pop) + + DB2Meta const* meta; + + // WDB2 / WCH2 fields + std::uint32_t recordSize; + std::uint32_t recordCount; + std::uint32_t fieldCount; + std::uint32_t stringSize; + std::uint32_t tableHash; + std::uint32_t layoutHash; + std::uint32_t minIndex; + std::uint32_t maxIndex; + std::uint32_t localeMask; + std::uint32_t copyIdSize; + std::uint32_t metaFlags; + + unsigned char* data; + unsigned char* stringTable; + unsigned char* idTable; + std::uint32_t idTableSize; + unsigned char* copyTable; + FieldEntry* fields; +}; + +#endif // MapExtractor_DB2_h__ diff --git a/src/tools/vmap4_extractor/dbcfile.cpp b/src/tools/vmap4_extractor/dbcfile.cpp deleted file mode 100644 index 920b08ed0e9..00000000000 --- a/src/tools/vmap4_extractor/dbcfile.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#define _CRT_SECURE_NO_DEPRECATE - -#include "dbcfile.h" - -DBCFile::DBCFile(HANDLE mpq, const char* filename) : - _mpq(mpq), _filename(filename), _file(NULL), _recordSize(0), _recordCount(0), - _fieldCount(0), _stringSize(0), _data(NULL), _stringTable(NULL) -{ -} - -bool DBCFile::open() -{ - if (!CascOpenFile(_mpq, _filename, CASC_LOCALE_NONE, 0, &_file)) - return false; - - char header[4]; - unsigned int na, nb, es, ss; - - DWORD readBytes = 0; - CascReadFile(_file, header, 4, &readBytes); - if (readBytes != 4) // Number of records - return false; - - if (header[0] != 'W' || header[1] != 'D' || header[2] != 'B' || header[3] != 'C') - return false; - - readBytes = 0; - CascReadFile(_file, &na, 4, &readBytes); - if (readBytes != 4) // Number of records - return false; - - readBytes = 0; - CascReadFile(_file, &nb, 4, &readBytes); - if (readBytes != 4) // Number of fields - return false; - - readBytes = 0; - CascReadFile(_file, &es, 4, &readBytes); - if (readBytes != 4) // Size of a record - return false; - - readBytes = 0; - CascReadFile(_file, &ss, 4, &readBytes); - if (readBytes != 4) // String size - return false; - - _recordSize = es; - _recordCount = na; - _fieldCount = nb; - _stringSize = ss; - if (_fieldCount * 4 != _recordSize) - return false; - - _data = new unsigned char[_recordSize * _recordCount + _stringSize]; - _stringTable = _data + _recordSize*_recordCount; - - size_t data_size = _recordSize * _recordCount + _stringSize; - readBytes = 0; - CascReadFile(_file, _data, data_size, &readBytes); - if (readBytes != data_size) - return false; - - return true; -} - -DBCFile::~DBCFile() -{ - delete [] _data; - if (_file != NULL) - CascCloseFile(_file); -} - -DBCFile::Record DBCFile::getRecord(size_t id) -{ - assert(_data); - return Record(*this, _data + id*_recordSize); -} - -size_t DBCFile::getMaxId() -{ - assert(_data); - - size_t maxId = 0; - for(size_t i = 0; i < getRecordCount(); ++i) - if (maxId < getRecord(i).getUInt(0)) - maxId = getRecord(i).getUInt(0); - - return maxId; -} - -DBCFile::Iterator DBCFile::begin() -{ - assert(_data); - return Iterator(*this, _data); -} - -DBCFile::Iterator DBCFile::end() -{ - assert(_data); - return Iterator(*this, _stringTable); -} - diff --git a/src/tools/vmap4_extractor/dbcfile.h b/src/tools/vmap4_extractor/dbcfile.h deleted file mode 100644 index 063ca0b70f0..00000000000 --- a/src/tools/vmap4_extractor/dbcfile.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef DBCFILE_H -#define DBCFILE_H -#include <cassert> -#include <string> -#include "CascLib.h" - -class DBCFile -{ - public: - DBCFile(HANDLE mpq, const char* filename); - ~DBCFile(); - - // Open database. It must be openened before it can be used. - bool open(); - - // Database exceptions - class Exception - { - public: - Exception(const std::string &message) : message(message) { } - virtual ~Exception() { } - const std::string &getMessage() { return message; } - private: - std::string message; - }; - - class NotFound: public Exception - { - public: - NotFound(): Exception("Key was not found") { } - }; - - // Iteration over database - class Iterator; - class Record - { - public: - float getFloat(size_t field) const - { - assert(field < file._fieldCount); - return *reinterpret_cast<float*>(offset + field * 4); - } - - unsigned int getUInt(size_t field) const - { - assert(field < file._fieldCount); - return *reinterpret_cast<unsigned int*>(offset + field * 4); - } - - int getInt(size_t field) const - { - assert(field < file._fieldCount); - return *reinterpret_cast<int*>(offset + field * 4); - } - - char const* getString(size_t field) const - { - assert(field < file._fieldCount); - size_t stringOffset = getUInt(field); - assert(stringOffset < file._stringSize); - return reinterpret_cast<char*>(file._stringTable + stringOffset); - } - - private: - Record(DBCFile& file, unsigned char* offset): file(file), offset(offset) {} - DBCFile& file; - unsigned char* offset; - - friend class DBCFile; - friend class DBCFile::Iterator; - - Record& operator=(Record const&); - Record(Record const& right) : file(right.file), offset(right.offset) - { - } - }; - /** Iterator that iterates over records - */ - class Iterator - { - public: - Iterator(DBCFile &file, unsigned char* offset) : record(file, offset) { } - - Iterator(Iterator const& right) : record(right.record) - { - } - - /// Advance (prefix only) - Iterator& operator++() - { - record.offset += record.file._recordSize; - return *this; - } - - /// Return address of current instance - Record const& operator*() const { return record; } - Record const* operator->() const { return &record; } - - /// Comparison - bool operator==(Iterator const& b) const - { - return record.offset == b.record.offset; - } - - bool operator!=(Iterator const& b) const - { - return record.offset != b.record.offset; - } - - Iterator& operator=(Iterator const& right) - { - record.offset = right.record.offset; - return *this; - } - private: - Record record; - - }; - - // Get record by id - Record getRecord(size_t id); - /// Get begin iterator over records - Iterator begin(); - /// Get begin iterator over records - Iterator end(); - /// Trivial - size_t getRecordCount() const { return _recordCount; } - size_t getFieldCount() const { return _fieldCount; } - size_t getMaxId(); - - private: - HANDLE _mpq; - const char* _filename; - HANDLE _file; - size_t _recordSize; - size_t _recordCount; - size_t _fieldCount; - size_t _stringSize; - unsigned char *_data; - unsigned char* _stringTable; -}; - -#endif diff --git a/src/tools/vmap4_extractor/gameobject_extract.cpp b/src/tools/vmap4_extractor/gameobject_extract.cpp index d8005b5ced9..8949111a5cd 100644 --- a/src/tools/vmap4_extractor/gameobject_extract.cpp +++ b/src/tools/vmap4_extractor/gameobject_extract.cpp @@ -16,28 +16,17 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "DB2.h" #include "model.h" -#include "dbcfile.h" #include "adtfile.h" #include "vmapexport.h" +#include "StringFormat.h" #include <algorithm> #include <stdio.h> -bool ExtractSingleModel(std::string& fname) +bool ExtractSingleModel(std::string& name) { - if (fname.substr(fname.length() - 4, 4) == ".mdx") - { - fname.erase(fname.length() - 2, 2); - fname.append("2"); - } - - std::string originalName = fname; - - char* name = GetPlainName((char*)fname.c_str()); - FixNameCase(name, strlen(name)); - FixNameSpaces(name, strlen(name)); - std::string output(szWorkDirWmo); output += "/"; output += name; @@ -45,7 +34,7 @@ bool ExtractSingleModel(std::string& fname) if (FileExists(output.c_str())) return true; - Model mdl(originalName); + Model mdl(name); if (!mdl.open()) return false; @@ -54,26 +43,64 @@ bool ExtractSingleModel(std::string& fname) extern HANDLE CascStorage; +struct GameObjectDisplayInfoMeta +{ + static DB2Meta const* Instance() + { + static char const* types = "ifffh"; + static uint8 const arraySizes[5] = { 1, 6, 1, 1, 1 }; + static DB2Meta instance(-1, 5, 0xDD4432B9, types, arraySizes); + return &instance; + } +}; + +struct CascFileHandleDeleter +{ + typedef HANDLE pointer; + void operator()(HANDLE handle) const { CascCloseFile(handle); } +}; + +enum ModelTypes : uint32 +{ + MODEL_MD20 = '02DM', + MODEL_MD21 = '12DM', + MODEL_WMO = 'REVM' +}; + +uint32 GetHeaderMagic(std::string const& fileName) +{ + HANDLE file; + if (!CascOpenFile(CascStorage, fileName.c_str(), CASC_LOCALE_ALL, 0, &file)) + return 0; + + std::unique_ptr<HANDLE, CascFileHandleDeleter> modelFile(file); + uint32 magic = 0; + DWORD bytesRead = 0; + if (!CascReadFile(file, &magic, 4, &bytesRead) || bytesRead != 4) + return 0; + + return magic; +} + void ExtractGameobjectModels() { printf("Extracting GameObject models..."); - DBCFile dbc(CascStorage, "DBFilesClient\\GameObjectDisplayInfo.dbc"); - if(!dbc.open()) + HANDLE dbcFile; + if (!CascOpenFile(CascStorage, "DBFilesClient\\GameObjectDisplayInfo.db2", CASC_LOCALE_NONE, 0, &dbcFile)) { - printf("Fatal error: Invalid GameObjectDisplayInfo.dbc file format!\n"); + printf("Fatal error: Cannot find GameObjectDisplayInfo.db2 in archive!\n"); exit(1); } - DBCFile fileData(CascStorage, "DBFilesClient\\FileData.dbc"); - if (!fileData.open()) + DB2FileLoader db2; + if (!db2.Load(dbcFile, GameObjectDisplayInfoMeta::Instance())) { - printf("Fatal error: Invalid FileData.dbc file format!\n"); + printf("Fatal error: Invalid GameObjectDisplayInfo.db2 file format!\n"); exit(1); } std::string basepath = szWorkDirWmo; basepath += "/"; - std::string path; std::string modelListPath = basepath + "temp_gameobject_models"; FILE* model_list = fopen(modelListPath.c_str(), "wb"); @@ -83,62 +110,30 @@ void ExtractGameobjectModels() return; } - size_t maxFileId = fileData.getMaxId() + 1; - uint32* fileDataIndex = new uint32[maxFileId]; - memset(fileDataIndex, 0, maxFileId * sizeof(uint32)); - size_t files = fileData.getRecordCount(); - for (uint32 i = 0; i < files; ++i) - fileDataIndex[fileData.getRecord(i).getUInt(0)] = i; - - for (DBCFile::Iterator it = dbc.begin(); it != dbc.end(); ++it) + for (uint32 rec = 0; rec < db2.GetNumRows(); ++rec) { - uint32 fileId = it->getUInt(1); + uint32 fileId = db2.getRecord(rec).getUInt(0, 0); if (!fileId) continue; - uint32 fileIndex = fileDataIndex[fileId]; - if (!fileIndex) - continue; - - std::string filename = fileData.getRecord(fileIndex).getString(1); - std::string filepath = fileData.getRecord(fileIndex).getString(2); - - path = filepath + filename; - - if (path.length() < 4) - continue; - - FixNameCase((char*)path.c_str(), path.size()); - char * name = GetPlainName((char*)path.c_str()); - FixNameSpaces(name, strlen(name)); - - char * ch_ext = GetExtension(name); - if (!ch_ext) - continue; - - strToLower(ch_ext); - + std::string fileName = Trinity::StringFormat("FILE%08X", fileId); bool result = false; - if (!strcmp(ch_ext, ".wmo")) - result = ExtractSingleWmo(path); - else if (!strcmp(ch_ext, ".mdl")) // TODO: extract .mdl files, if needed - continue; - else if (!strcmp(ch_ext, ".mdx") || !strcmp(ch_ext, ".m2")) - result = ExtractSingleModel(path); + if (GetHeaderMagic(fileName) == MODEL_WMO) + result = ExtractSingleWmo(fileName); + else + result = ExtractSingleModel(fileName); if (result) { - uint32 displayId = it->getUInt(0); - uint32 path_length = strlen(name); + uint32 displayId = db2.getId(rec); + uint32 path_length = fileName.length(); fwrite(&displayId, sizeof(uint32), 1, model_list); fwrite(&path_length, sizeof(uint32), 1, model_list); - fwrite(name, sizeof(char), path_length, model_list); + fwrite(fileName.c_str(), sizeof(char), path_length, model_list); } } fclose(model_list); - delete[] fileDataIndex; - printf("Done!\n"); } diff --git a/src/tools/vmap4_extractor/model.cpp b/src/tools/vmap4_extractor/model.cpp index bd2d6dc9b91..8ee7ec6202d 100644 --- a/src/tools/vmap4_extractor/model.cpp +++ b/src/tools/vmap4_extractor/model.cpp @@ -45,16 +45,24 @@ bool Model::open() _unload(); + int32 m2start = 0; + char const* ptr = f.getBuffer(); + while (m2start + 4 < f.getSize() && *reinterpret_cast<uint32 const*>(ptr) != '02DM') + { + ++m2start; + ++ptr; + } + memcpy(&header, f.getBuffer(), sizeof(ModelHeader)); if (header.nBoundingTriangles > 0) { - f.seek(0); + f.seek(m2start); f.seekRelative(header.ofsBoundingVertices); vertices = new Vec3D[header.nBoundingVertices]; f.read(vertices,header.nBoundingVertices*12); for (uint32 i=0; i<header.nBoundingVertices; i++) vertices[i] = fixCoordSystem(vertices[i]); - f.seek(0); + f.seek(m2start); f.seekRelative(header.ofsBoundingTriangles); indices = new uint16[header.nBoundingTriangles]; f.read(indices,header.nBoundingTriangles*2); diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index e4177052751..66bad76d9f0 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -44,7 +44,7 @@ //From Extractor #include "adtfile.h" #include "wdtfile.h" -#include "dbcfile.h" +#include "DB2.h" #include "wmo.h" #include "mpqfile.h" @@ -68,13 +68,35 @@ typedef struct unsigned int id; }map_id; -map_id * map_ids; -uint16 *LiqType = 0; +std::vector<map_id> map_ids; +std::vector<uint16> LiqType; uint32 map_count; char output_path[128] = "."; char input_path[1024] = "."; bool preciseVectorData = false; +struct LiquidTypeMeta +{ + static DB2Meta const* Instance() + { + static char const* types = "sifffffSifihhbbbbbi"; + static uint8 const arraySizes[19] = { 1, 1, 1, 1, 1, 1, 1, 6, 2, 18, 4, 1, 1, 1, 1, 1, 1, 6, 1 }; + static DB2Meta instance(-1, 19, 0x28B44DCB, types, arraySizes); + return &instance; + } +}; + +struct MapMeta +{ + static DB2Meta const* Instance() + { + static char const* types = "siffssshhhhhhhbbbbb"; + static uint8 const arraySizes[19] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + static DB2Meta instance(-1, 19, 0xB32E648C, types, arraySizes); + return &instance; + } +}; + // Constants //static const char * szWorkDirMaps = ".\\Maps"; @@ -228,23 +250,38 @@ void strToLower(char* str) void ReadLiquidTypeTableDBC() { printf("Read LiquidType.dbc file..."); + HANDLE dbcFile; + if (!CascOpenFile(CascStorage, "DBFilesClient\\LiquidType.db2", CASC_LOCALE_NONE, 0, &dbcFile)) + { + printf("Fatal error: Cannot find LiquidType.dbc in archive! %s\n", HumanReadableCASCError(GetLastError())); + exit(1); + } - DBCFile dbc(CascStorage, "DBFilesClient\\LiquidType.dbc"); - if(!dbc.open()) + DB2FileLoader db2; + if (!db2.Load(dbcFile, LiquidTypeMeta::Instance())) { - printf("Fatal error: Invalid LiquidType.dbc file format!\n"); + printf("Fatal error: Invalid LiquidType.db2 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)); + LiqType.resize(db2.GetMaxId(), 0xFFFF); + + for (uint32 x = 0; x < db2.GetNumRows(); ++x) + { + uint32 liquidTypeId; + if (LiquidTypeMeta::Instance()->HasIndexFieldInData()) + liquidTypeId = db2.getRecord(x).getUInt(LiquidTypeMeta::Instance()->GetIndexField(), 0); + else + liquidTypeId = db2.getId(x); + + LiqType[liquidTypeId] = db2.getRecord(x).getUInt8(13, 0); + } - for(uint32 x = 0; x < LiqType_count; ++x) - LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); + for (uint32 x = 0; x < db2.GetNumRowCopies(); ++x) + LiqType[db2.GetRowCopy(x).second] = LiqType[db2.GetRowCopy(x).first]; - printf("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count); + CascCloseFile(dbcFile); + printf("Done! (" SZFMTD " LiqTypes loaded)\n", LiqType.size()); } bool ExtractWmo() @@ -325,15 +362,12 @@ bool ExtractSingleWmo(std::string& fname) froot.ConvertToVMAPRootWmo(output); int Wmo_nVertices = 0; //printf("root has %d groups\n", froot->nGroups); - if (froot.nGroups !=0) + if (!froot.groupFileDataIDs.empty()) { - for (uint32 i = 0; i < froot.nGroups; ++i) + for (std::size_t i = 0; i < froot.groupFileDataIDs.size(); ++i) { - char temp[1024]; - strncpy(temp, fname.c_str(), 1024); - temp[fname.length()-4] = 0; char groupFileName[1024]; - sprintf(groupFileName, "%s_%03u.wmo", temp, i); + sprintf(groupFileName, "FILE%08X", froot.groupFileDataIDs[i]); //printf("Trying to open groupfile %s\n",groupFileName); std::string s = groupFileName; @@ -364,7 +398,7 @@ void ParsMapFiles() char fn[512]; //char id_filename[64]; char id[10]; - for (unsigned int i=0; i<map_count; ++i) + for (unsigned int i = 0; i < map_ids.size(); ++i) { sprintf(id, "%04u", map_ids[i].id); sprintf(fn,"World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name); @@ -538,38 +572,61 @@ int main(int argc, char ** argv) //map.dbc if (success) { - DBCFile * dbc = new DBCFile(CascStorage, "DBFilesClient\\Map.dbc"); - if (!dbc->open()) + printf("Read Map.dbc file... "); + + HANDLE dbcFile; + if (!CascOpenFile(CascStorage, "DBFilesClient\\Map.db2", CASC_LOCALE_NONE, 0, &dbcFile)) { - delete dbc; - printf("FATAL ERROR: Map.dbc not found in data file.\n"); - return 1; + printf("Fatal error: Cannot find Map.dbc in archive! %s\n", HumanReadableCASCError(GetLastError())); + exit(1); } - map_count = dbc->getRecordCount(); - map_ids = new map_id[map_count]; - for (unsigned int x = 0; x < map_count; ++x) + DB2FileLoader db2; + if (!db2.Load(dbcFile, MapMeta::Instance())) { - map_ids[x].id = dbc->getRecord(x).getUInt(0); + printf("Fatal error: Invalid Map.db2 file format! %s\n", HumanReadableCASCError(GetLastError())); + exit(1); + } - const char* map_name = dbc->getRecord(x).getString(1); + map_ids.resize(db2.GetNumRows()); + std::unordered_map<uint32, uint32> idToIndex; + for (uint32 x = 0; x < db2.GetNumRows(); ++x) + { + if (MapMeta::Instance()->HasIndexFieldInData()) + map_ids[x].id = db2.getRecord(x).getUInt(MapMeta::Instance()->GetIndexField(), 0); + else + map_ids[x].id = db2.getId(x); + + const char* map_name = db2.getRecord(x).getString(0, 0); size_t max_map_name_length = sizeof(map_ids[x].name); if (strlen(map_name) >= max_map_name_length) { - delete dbc; - delete[] map_ids; - printf("FATAL ERROR: Map name too long.\n"); - return 1; + printf("Fatal error: Map name too long!\n"); + exit(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); + idToIndex[map_ids[x].id] = x; + } + + for (uint32 x = 0; x < db2.GetNumRowCopies(); ++x) + { + uint32 from = db2.GetRowCopy(x).first; + uint32 to = db2.GetRowCopy(x).second; + auto itr = idToIndex.find(from); + if (itr != idToIndex.end()) + { + map_id id; + id.id = to; + strcpy(id.name, map_ids[itr->second].name); + map_ids.push_back(id); + } } - delete dbc; + CascCloseFile(dbcFile); + printf("Done! (" SZFMTD " maps loaded)\n", map_ids.size()); ParsMapFiles(); - delete [] map_ids; } CascCloseStorage(CascStorage); @@ -582,6 +639,5 @@ int main(int argc, char ** argv) } printf("Extract %s. Work complete. No errors.\n", versionString); - delete [] LiqType; return 0; } diff --git a/src/tools/vmap4_extractor/wmo.cpp b/src/tools/vmap4_extractor/wmo.cpp index 31ae1cb3c40..4bceebc8f0c 100644 --- a/src/tools/vmap4_extractor/wmo.cpp +++ b/src/tools/vmap4_extractor/wmo.cpp @@ -29,11 +29,11 @@ #include "mpqfile.h" using namespace std; -extern uint16 *LiqType; +extern std::vector<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) + : filename(filename), color(0), nTextures(0), nGroups(0), nPortals(0), nLights(0), + nDoodadNames(0), nDoodadDefs(0), nDoodadSets(0), RootWMOID(0), flags(0) { memset(bbcorn1, 0, sizeof(bbcorn1)); memset(bbcorn2, 0, sizeof(bbcorn2)); @@ -67,18 +67,30 @@ 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); + f.read(&flags, 4); break; } + else if (!strcmp(fourcc, "GFID")) + { + for (uint32 gp = 0; gp < nGroups; ++gp) + { + uint32 fileDataId; + f.read(&fileDataId, 4); + groupFileDataIDs.push_back(fileDataId); + + if (flags & 16) // LOD related + f.seekRelative(8); + } + } /* else if (!strcmp(fourcc,"MOTX")) { @@ -409,7 +421,7 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool precise // according to WoW.Dev Wiki: uint32 liquidEntry; - if (rootWMO->liquidType & 4) + if (rootWMO->flags & 4) liquidEntry = liquidType; else if (liquidType == 15) liquidEntry = 0; @@ -460,7 +472,7 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool precise /* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app); llog << filename; - llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->liquidType << " group:" << liquidType << ")\n"; + llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->flags << " group:" << flags << ")\n"; llog.close(); */ fwrite(hlq, sizeof(WMOLiquidHeader), 1, output); diff --git a/src/tools/vmap4_extractor/wmo.h b/src/tools/vmap4_extractor/wmo.h index 3bc5970f58f..4246dbe0e5a 100644 --- a/src/tools/vmap4_extractor/wmo.h +++ b/src/tools/vmap4_extractor/wmo.h @@ -23,6 +23,7 @@ #include <string> #include <set> +#include <vector> #include "vec3d.h" #include "mpqfile.h" @@ -47,11 +48,13 @@ 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, flags; float bbcorn1[3]; float bbcorn2[3]; + std::vector<uint32> groupFileDataIDs; + WMORoot(std::string& filename); bool open(); |
