aboutsummaryrefslogtreecommitdiff
path: root/src/tools/vmap4_extractor
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-07-18 23:37:19 +0200
committerShauren <shauren.trinity@gmail.com>2016-07-18 23:37:19 +0200
commitfe4d11c65a512c61ccb924fbf3dc20c8cfc84dc7 (patch)
tree86888deb22268503d70ae7259bbf17add4dcdc1f /src/tools/vmap4_extractor
parenta9a13d10f7c510bb392539608cb276435a78b688 (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.cpp199
-rw-r--r--src/tools/vmap4_extractor/DB2.h178
-rw-r--r--src/tools/vmap4_extractor/dbcfile.cpp120
-rw-r--r--src/tools/vmap4_extractor/dbcfile.h161
-rw-r--r--src/tools/vmap4_extractor/gameobject_extract.cpp123
-rw-r--r--src/tools/vmap4_extractor/model.cpp12
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp132
-rw-r--r--src/tools/vmap4_extractor/wmo.cpp32
-rw-r--r--src/tools/vmap4_extractor/wmo.h7
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, &copyIdSize, 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();