mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/DataStores: Refactor DB2 loaders to be reusable by extractors
This commit is contained in:
1156
src/common/DataStores/DB2FileLoader.cpp
Normal file
1156
src/common/DataStores/DB2FileLoader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
141
src/common/DataStores/DB2FileLoader.h
Normal file
141
src/common/DataStores/DB2FileLoader.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 DB2_FILE_LOADER_H
|
||||
#define DB2_FILE_LOADER_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class DB2FileLoaderImpl;
|
||||
struct DB2FieldMeta;
|
||||
struct DB2Meta;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct DB2Header
|
||||
{
|
||||
uint32 Signature;
|
||||
uint32 RecordCount;
|
||||
uint32 FieldCount;
|
||||
uint32 RecordSize;
|
||||
uint32 StringTableSize;
|
||||
uint32 TableHash;
|
||||
uint32 LayoutHash;
|
||||
uint32 MinId;
|
||||
uint32 MaxId;
|
||||
uint32 Locale;
|
||||
uint32 CopyTableSize;
|
||||
uint16 Flags;
|
||||
int16 IndexField;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct TC_COMMON_API DB2FileLoadInfo
|
||||
{
|
||||
DB2FileLoadInfo();
|
||||
DB2FileLoadInfo(DB2FieldMeta const* fields, std::size_t fieldCount, DB2Meta const* meta);
|
||||
|
||||
uint32 GetStringFieldCount(bool localizedOnly) const;
|
||||
|
||||
DB2FieldMeta const* Fields;
|
||||
std::size_t FieldCount;
|
||||
DB2Meta const* Meta;
|
||||
std::string TypesString;
|
||||
};
|
||||
|
||||
struct TC_COMMON_API DB2FileSource
|
||||
{
|
||||
virtual ~DB2FileSource();
|
||||
|
||||
///
|
||||
/**
|
||||
* Returns true when the source is open for reading
|
||||
*/
|
||||
virtual bool IsOpen() const = 0;
|
||||
|
||||
// Reads numBytes bytes from source and places them into buffer
|
||||
// Retu
|
||||
virtual bool Read(void* buffer, std::size_t numBytes) = 0;
|
||||
virtual std::size_t GetPosition() const = 0;
|
||||
virtual char const* GetFileName() const = 0;
|
||||
};
|
||||
|
||||
class TC_COMMON_API DB2Record
|
||||
{
|
||||
public:
|
||||
DB2Record(DB2FileLoaderImpl const& db2, uint32 recordIndex, std::size_t* fieldOffsets);
|
||||
~DB2Record();
|
||||
|
||||
operator bool();
|
||||
|
||||
uint32 GetId() const;
|
||||
|
||||
uint8 GetUInt8(uint32 field, uint32 arrayIndex) const;
|
||||
uint16 GetUInt16(uint32 field, uint32 arrayIndex) const;
|
||||
uint32 GetUInt32(uint32 field, uint32 arrayIndex) const;
|
||||
int32 GetInt32(uint32 field, uint32 arrayIndex) const;
|
||||
float GetFloat(uint32 field, uint32 arrayIndex) const;
|
||||
char const* GetString(uint32 field, uint32 arrayIndex) const;
|
||||
|
||||
// Creates its own heap allocated copy of _fieldOffsets
|
||||
// by default _fieldOffets point to a shared array inside Loader to avoid heap allocations
|
||||
// meaning that only one instance of DB2Record has valid offsets if the file is sparse
|
||||
void MakePersistent();
|
||||
|
||||
private:
|
||||
DB2FileLoaderImpl const& _db2;
|
||||
uint32 _recordIndex;
|
||||
unsigned char const* _recordData;
|
||||
std::size_t* _fieldOffsets;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct DB2RecordCopy
|
||||
{
|
||||
uint32 NewRowId = 0;
|
||||
uint32 SourceRowId = 0;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class TC_COMMON_API DB2FileLoader
|
||||
{
|
||||
public:
|
||||
DB2FileLoader();
|
||||
~DB2FileLoader();
|
||||
|
||||
bool Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo);
|
||||
char* AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool);
|
||||
char* AutoProduceStrings(char* dataTable, uint32 locale);
|
||||
void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable);
|
||||
|
||||
uint32 GetCols() const { return _header.FieldCount; }
|
||||
uint32 GetRecordCount() const;
|
||||
uint32 GetRecordCopyCount() const;
|
||||
uint32 GetTableHash() const { return _header.TableHash; }
|
||||
uint32 GetLayoutHash() const { return _header.LayoutHash; }
|
||||
uint32 GetMaxId() const;
|
||||
|
||||
DB2Record GetRecord(uint32 recordNumber) const;
|
||||
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const;
|
||||
|
||||
private:
|
||||
DB2FileLoaderImpl* _impl;
|
||||
DB2Header _header;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
301
src/server/shared/DataStores/DB2DatabaseLoader.cpp
Normal file
301
src/server/shared/DataStores/DB2DatabaseLoader.cpp
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "DB2DatabaseLoader.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "DB2Meta.h"
|
||||
|
||||
DB2LoadInfo::DB2LoadInfo() : DB2FileLoadInfo()
|
||||
{
|
||||
}
|
||||
|
||||
DB2LoadInfo::DB2LoadInfo(DB2FieldMeta const* fields, std::size_t fieldCount, DB2Meta const* meta, HotfixDatabaseStatements statement)
|
||||
: DB2FileLoadInfo(fields, fieldCount, meta), Statement(statement)
|
||||
{
|
||||
}
|
||||
|
||||
static char const* nullStr = "";
|
||||
|
||||
char* DB2DatabaseLoader::Load(uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool)
|
||||
{
|
||||
// Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format
|
||||
PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(_loadInfo->Statement));
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
if (_loadInfo->Meta->GetDbFieldCount() != result->GetFieldCount())
|
||||
return nullptr;
|
||||
|
||||
// get struct size and index pos
|
||||
uint32 indexField = _loadInfo->Meta->GetDbIndexField();
|
||||
uint32 recordSize = _loadInfo->Meta->GetRecordSize();
|
||||
|
||||
// we store flat holders pool as single memory block
|
||||
std::size_t stringFields = _loadInfo->GetStringFieldCount(false);
|
||||
std::size_t localizedStringFields = _loadInfo->GetStringFieldCount(true);
|
||||
|
||||
// each string field at load have array of string for each locale
|
||||
std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
|
||||
|
||||
if (stringFields)
|
||||
{
|
||||
std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount();
|
||||
stringHolders = new char[stringHoldersPoolSize];
|
||||
|
||||
// DB2 strings expected to have at least empty string
|
||||
for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
|
||||
((char const**)stringHolders)[i] = nullStr;
|
||||
}
|
||||
else
|
||||
stringHolders = nullptr;
|
||||
|
||||
// Resize index table
|
||||
// database query *MUST* contain ORDER BY `index_field` DESC clause
|
||||
uint32 indexTableSize = (*result)[indexField].GetUInt32() + 1;
|
||||
if (indexTableSize < records)
|
||||
indexTableSize = records;
|
||||
|
||||
if (indexTableSize > records)
|
||||
{
|
||||
char** tmpIdxTable = new char*[indexTableSize];
|
||||
memset(tmpIdxTable, 0, indexTableSize * sizeof(char*));
|
||||
memcpy(tmpIdxTable, indexTable, records * sizeof(char*));
|
||||
delete[] indexTable;
|
||||
indexTable = tmpIdxTable;
|
||||
}
|
||||
|
||||
char* tempDataTable = new char[result->GetRowCount() * recordSize];
|
||||
uint32* newIndexes = new uint32[result->GetRowCount()];
|
||||
uint32 rec = 0;
|
||||
uint32 newRecords = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 offset = 0;
|
||||
uint32 stringFieldOffset = 0;
|
||||
|
||||
uint32 indexValue = fields[indexField].GetUInt32();
|
||||
|
||||
// Attempt to overwrite existing data
|
||||
char* dataValue = indexTable[indexValue];
|
||||
if (!dataValue)
|
||||
{
|
||||
newIndexes[newRecords] = indexValue;
|
||||
dataValue = &tempDataTable[newRecords++ * recordSize];
|
||||
}
|
||||
|
||||
uint32 f = 0;
|
||||
if (!_loadInfo->Meta->HasIndexFieldInData())
|
||||
{
|
||||
*((uint32*)(&dataValue[offset])) = indexValue;
|
||||
offset += 4;
|
||||
++f;
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < _loadInfo->Meta->FieldCount; ++x)
|
||||
{
|
||||
for (uint32 z = 0; z < _loadInfo->Meta->ArraySizes[x]; ++z)
|
||||
{
|
||||
switch (_loadInfo->TypesString[f])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
*((float*)(&dataValue[offset])) = fields[f].GetFloat();
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_INT:
|
||||
*((int32*)(&dataValue[offset])) = fields[f].GetInt32();
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
*((int8*)(&dataValue[offset])) = fields[f].GetInt8();
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_SHORT:
|
||||
*((int16*)(&dataValue[offset])) = fields[f].GetInt16();
|
||||
offset += 2;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
LocalizedString** slot = (LocalizedString**)(&dataValue[offset]);
|
||||
*slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]);
|
||||
ASSERT(*slot);
|
||||
|
||||
// Value in database in main table field must be for enUS locale
|
||||
if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString()))
|
||||
stringPool.push_back(str);
|
||||
|
||||
stringFieldOffset += sizeof(LocalizedString);
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
case FT_STRING_NOT_LOCALIZED:
|
||||
{
|
||||
char const** slot = (char const**)(&dataValue[offset]);
|
||||
*slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]);
|
||||
ASSERT(*slot);
|
||||
|
||||
// Value in database in main table field must be for enUS locale
|
||||
if (char* str = AddString(slot, fields[f].GetString()))
|
||||
stringPool.push_back(str);
|
||||
|
||||
stringFieldOffset += sizeof(char*);
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(false, "Unknown format character '%c' found in %s meta", _loadInfo->TypesString[x], _storageName.c_str());
|
||||
break;
|
||||
}
|
||||
++f;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(offset == recordSize);
|
||||
++rec;
|
||||
} while (result->NextRow());
|
||||
|
||||
if (!newRecords)
|
||||
{
|
||||
delete[] tempDataTable;
|
||||
delete[] newIndexes;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Compact new data table to only contain new records not previously loaded from file
|
||||
char* dataTable = new char[newRecords * recordSize];
|
||||
memcpy(dataTable, tempDataTable, newRecords * recordSize);
|
||||
|
||||
// insert new records to index table
|
||||
for (uint32 i = 0; i < newRecords; ++i)
|
||||
indexTable[newIndexes[i]] = &dataTable[i * recordSize];
|
||||
|
||||
delete[] tempDataTable;
|
||||
delete[] newIndexes;
|
||||
|
||||
records = indexTableSize;
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
void DB2DatabaseLoader::LoadStrings(uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool)
|
||||
{
|
||||
PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(HotfixDatabaseStatements(_loadInfo->Statement + 1));
|
||||
stmt->setString(0, localeNames[locale]);
|
||||
PreparedQueryResult result = HotfixDatabase.Query(stmt);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
std::size_t stringFields = _loadInfo->GetStringFieldCount(true);
|
||||
if (result->GetFieldCount() != stringFields + 1 /*ID*/)
|
||||
return;
|
||||
|
||||
uint32 fieldCount = _loadInfo->Meta->FieldCount;
|
||||
uint32 recordSize = _loadInfo->Meta->GetRecordSize();
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 offset = 0;
|
||||
uint32 stringFieldNumInRecord = 0;
|
||||
uint32 indexValue = fields[0].GetUInt32();
|
||||
|
||||
if (indexValue >= records)
|
||||
continue;
|
||||
|
||||
// Attempt to overwrite existing data
|
||||
if (char* dataValue = indexTable[indexValue])
|
||||
{
|
||||
uint32 fieldIndex = 0;
|
||||
if (!_loadInfo->Meta->HasIndexFieldInData())
|
||||
{
|
||||
offset += 4;
|
||||
++fieldIndex;
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < fieldCount; ++x)
|
||||
{
|
||||
for (uint32 z = 0; z < _loadInfo->Meta->ArraySizes[x]; ++z)
|
||||
{
|
||||
switch (_loadInfo->TypesString[fieldIndex])
|
||||
{
|
||||
case FT_FLOAT:
|
||||
case FT_INT:
|
||||
offset += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
offset += 1;
|
||||
break;
|
||||
case FT_SHORT:
|
||||
offset += 2;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
// fill only not filled entries
|
||||
LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]);
|
||||
if (db2str->Str[locale] == nullStr)
|
||||
if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString()))
|
||||
stringPool.push_back(str);
|
||||
|
||||
++stringFieldNumInRecord;
|
||||
offset += sizeof(LocalizedString*);
|
||||
break;
|
||||
}
|
||||
case FT_STRING_NOT_LOCALIZED:
|
||||
offset += sizeof(char*);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false, "Unknown format character '%c' found in %s meta", _loadInfo->TypesString[x], _storageName.c_str());
|
||||
break;
|
||||
}
|
||||
++fieldIndex;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(offset == recordSize);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u locale %s!", _storageName.c_str(), indexValue, localeNames[locale]);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char* DB2DatabaseLoader::AddString(char const** holder, std::string const& value)
|
||||
{
|
||||
if (!value.empty())
|
||||
{
|
||||
std::size_t existingLength = strlen(*holder);
|
||||
if (existingLength >= value.length())
|
||||
{
|
||||
// Reuse existing storage if there is enough space
|
||||
char* str = const_cast<char*>(*holder);
|
||||
memcpy(str, value.c_str(), value.length());
|
||||
str[value.length()] = '\0';
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* str = new char[value.length() + 1];
|
||||
memcpy(str, value.c_str(), value.length());
|
||||
str[value.length()] = '\0';
|
||||
*holder = str;
|
||||
return str;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -15,67 +15,18 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DB2_FILE_LOADER_H
|
||||
#define DB2_FILE_LOADER_H
|
||||
#ifndef DB2_DATABASE_LOADER_H
|
||||
#define DB2_DATABASE_LOADER_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "DB2FileLoader.h"
|
||||
#include "Implementation/HotfixDatabase.h"
|
||||
|
||||
class DB2FileLoaderImpl;
|
||||
struct DB2Meta;
|
||||
struct DB2FieldMeta;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct DB2Header
|
||||
{
|
||||
uint32 Signature;
|
||||
uint32 RecordCount;
|
||||
uint32 FieldCount;
|
||||
uint32 RecordSize;
|
||||
uint32 StringTableSize;
|
||||
uint32 TableHash;
|
||||
uint32 LayoutHash;
|
||||
uint32 MinId;
|
||||
uint32 MaxId;
|
||||
uint32 Locale;
|
||||
uint32 CopyTableSize;
|
||||
uint16 Flags;
|
||||
int16 IndexField;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct TC_SHARED_API DB2LoadInfo
|
||||
struct TC_SHARED_API DB2LoadInfo : public DB2FileLoadInfo
|
||||
{
|
||||
DB2LoadInfo();
|
||||
DB2LoadInfo(DB2FieldMeta const* fields, std::size_t fieldCount, DB2Meta const* meta, HotfixDatabaseStatements statement);
|
||||
|
||||
uint32 GetStringFieldCount(bool localizedOnly) const;
|
||||
|
||||
DB2FieldMeta const* Fields;
|
||||
std::size_t FieldCount;
|
||||
DB2Meta const* Meta;
|
||||
HotfixDatabaseStatements Statement;
|
||||
std::string TypesString;
|
||||
};
|
||||
|
||||
class TC_SHARED_API DB2FileLoader
|
||||
{
|
||||
public:
|
||||
DB2FileLoader();
|
||||
~DB2FileLoader();
|
||||
|
||||
bool Load(char const* filename, DB2LoadInfo const* loadInfo);
|
||||
char* AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool);
|
||||
char* AutoProduceStrings(char* dataTable, uint32 locale);
|
||||
void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable);
|
||||
|
||||
uint32 GetCols() const { return _header.FieldCount; }
|
||||
uint32 GetTableHash() const { return _header.TableHash; }
|
||||
uint32 GetLayoutHash() const { return _header.LayoutHash; }
|
||||
|
||||
private:
|
||||
DB2FileLoaderImpl* _impl;
|
||||
DB2Header _header;
|
||||
};
|
||||
|
||||
class TC_SHARED_API DB2DatabaseLoader
|
||||
File diff suppressed because it is too large
Load Diff
189
src/server/shared/DataStores/DB2Store.cpp
Normal file
189
src/server/shared/DataStores/DB2Store.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "DB2Store.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "DB2DatabaseLoader.h"
|
||||
#include "DB2Meta.h"
|
||||
|
||||
struct DB2FileSystemSource : public DB2FileSource
|
||||
{
|
||||
DB2FileSystemSource(std::string const& fileName)
|
||||
{
|
||||
_fileName = fileName;
|
||||
_file = fopen(_fileName.c_str(), "rb");
|
||||
}
|
||||
|
||||
~DB2FileSystemSource()
|
||||
{
|
||||
if (_file)
|
||||
fclose(_file);
|
||||
}
|
||||
|
||||
bool IsOpen() const override
|
||||
{
|
||||
return _file != nullptr;
|
||||
}
|
||||
|
||||
bool Read(void* buffer, std::size_t numBytes) override
|
||||
{
|
||||
return fread(buffer, numBytes, 1, _file) == 1;
|
||||
}
|
||||
|
||||
std::size_t GetPosition() const override
|
||||
{
|
||||
return ftell(_file);
|
||||
}
|
||||
|
||||
char const* GetFileName() const override
|
||||
{
|
||||
return _fileName.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _fileName;
|
||||
FILE* _file;
|
||||
};
|
||||
|
||||
DB2StorageBase::DB2StorageBase(char const* fileName, DB2LoadInfo const* loadInfo)
|
||||
: _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _loadInfo(loadInfo), _dataTable(nullptr), _dataTableEx(nullptr), _indexTableSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
DB2StorageBase::~DB2StorageBase()
|
||||
{
|
||||
delete[] _dataTable;
|
||||
delete[] _dataTableEx;
|
||||
for (char* strings : _stringPool)
|
||||
delete[] strings;
|
||||
}
|
||||
|
||||
void DB2StorageBase::WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const
|
||||
{
|
||||
std::size_t i = 0;
|
||||
if (!_loadInfo->Meta->HasIndexFieldInData())
|
||||
{
|
||||
entry += 4;
|
||||
++i;
|
||||
}
|
||||
|
||||
for (; i < _loadInfo->FieldCount; ++i)
|
||||
{
|
||||
switch (_loadInfo->TypesString[i])
|
||||
{
|
||||
case FT_INT:
|
||||
buffer << *(uint32*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_FLOAT:
|
||||
buffer << *(float*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
buffer << *(uint8*)entry;
|
||||
entry += 1;
|
||||
break;
|
||||
case FT_SHORT:
|
||||
buffer << *(uint16*)entry;
|
||||
entry += 2;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
LocalizedString* locStr = *(LocalizedString**)entry;
|
||||
if (locStr->Str[locale][0] == '\0')
|
||||
locale = 0;
|
||||
|
||||
buffer << locStr->Str[locale];
|
||||
entry += sizeof(LocalizedString*);
|
||||
break;
|
||||
}
|
||||
case FT_STRING_NOT_LOCALIZED:
|
||||
{
|
||||
buffer << *(char const**)entry;
|
||||
entry += sizeof(char const*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DB2StorageBase::Load(std::string const& path, uint32 locale, char**& indexTable)
|
||||
{
|
||||
indexTable = nullptr;
|
||||
DB2FileLoader db2;
|
||||
{
|
||||
DB2FileSystemSource source(path + _fileName);
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load(&source, _loadInfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
_fieldCount = db2.GetCols();
|
||||
_tableHash = db2.GetTableHash();
|
||||
_layoutHash = db2.GetLayoutHash();
|
||||
|
||||
// load raw non-string data
|
||||
_dataTable = db2.AutoProduceData(_indexTableSize, indexTable, _stringPool);
|
||||
|
||||
// load strings from db2 data
|
||||
if (!_stringPool.empty())
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
|
||||
db2.AutoProduceRecordCopies(_indexTableSize, indexTable, _dataTable);
|
||||
|
||||
// error in db2 file at loading if NULL
|
||||
return indexTable != nullptr;
|
||||
}
|
||||
|
||||
bool DB2StorageBase::LoadStringsFrom(std::string const& path, uint32 locale, char** indexTable)
|
||||
{
|
||||
// DB2 must be already loaded using Load
|
||||
if (!indexTable)
|
||||
return false;
|
||||
|
||||
DB2FileLoader db2;
|
||||
{
|
||||
DB2FileSystemSource source(path + _fileName);
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load(&source, _loadInfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
// load strings from another locale db2 data
|
||||
if (_loadInfo->GetStringFieldCount(true))
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DB2StorageBase::LoadFromDB(char**& indexTable)
|
||||
{
|
||||
char* extraStringHolders = nullptr;
|
||||
_dataTableEx = DB2DatabaseLoader(_fileName, _loadInfo).Load(_indexTableSize, indexTable, extraStringHolders, _stringPool);
|
||||
if (extraStringHolders)
|
||||
_stringPool.push_back(extraStringHolders);
|
||||
}
|
||||
|
||||
void DB2StorageBase::LoadStringsFromDB(uint32 locale, char** indexTable)
|
||||
{
|
||||
if (!_loadInfo->GetStringFieldCount(true))
|
||||
return;
|
||||
|
||||
DB2DatabaseLoader(_fileName, _loadInfo).LoadStrings(locale, _indexTableSize, indexTable, _stringPool);
|
||||
}
|
||||
@@ -19,41 +19,29 @@
|
||||
#define DB2STORE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DB2Meta.h"
|
||||
#include "DB2StorageLoader.h"
|
||||
#include "DBStorageIterator.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include <vector>
|
||||
|
||||
class ByteBuffer;
|
||||
struct DB2LoadInfo;
|
||||
|
||||
/// Interface class for common access
|
||||
class DB2StorageBase
|
||||
class TC_SHARED_API DB2StorageBase
|
||||
{
|
||||
public:
|
||||
DB2StorageBase(char const* fileName, DB2LoadInfo&& loadInfo)
|
||||
: _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _loadInfo(std::move(loadInfo)), _dataTable(nullptr), _dataTableEx(nullptr) { }
|
||||
|
||||
virtual ~DB2StorageBase()
|
||||
{
|
||||
delete[] _dataTable;
|
||||
delete[] _dataTableEx;
|
||||
for (char* strings : _stringPool)
|
||||
delete[] strings;
|
||||
}
|
||||
DB2StorageBase(char const* fileName, DB2LoadInfo const* loadInfo);
|
||||
virtual ~DB2StorageBase();
|
||||
|
||||
uint32 GetTableHash() const { return _tableHash; }
|
||||
|
||||
uint32 GetLayoutHash() const { return _layoutHash; }
|
||||
|
||||
virtual bool HasRecord(uint32 id) const = 0;
|
||||
|
||||
virtual void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const = 0;
|
||||
|
||||
virtual void EraseRecord(uint32 id) = 0;
|
||||
|
||||
std::string const& GetFileName() const { return _fileName; }
|
||||
|
||||
uint32 GetFieldCount() const { return _fieldCount; }
|
||||
|
||||
DB2LoadInfo const* GetLoadInfo() const { return &_loadInfo; }
|
||||
DB2LoadInfo const* GetLoadInfo() const { return _loadInfo; }
|
||||
|
||||
virtual bool Load(std::string const& path, uint32 locale) = 0;
|
||||
virtual bool LoadStringsFrom(std::string const& path, uint32 locale) = 0;
|
||||
@@ -61,63 +49,21 @@ public:
|
||||
virtual void LoadStringsFromDB(uint32 locale) = 0;
|
||||
|
||||
protected:
|
||||
void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const
|
||||
{
|
||||
std::size_t i = 0;
|
||||
if (!_loadInfo.Meta->HasIndexFieldInData())
|
||||
{
|
||||
entry += 4;
|
||||
++i;
|
||||
}
|
||||
|
||||
for (; i < _loadInfo.FieldCount; ++i)
|
||||
{
|
||||
switch (_loadInfo.TypesString[i])
|
||||
{
|
||||
case FT_INT:
|
||||
buffer << *(uint32*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_FLOAT:
|
||||
buffer << *(float*)entry;
|
||||
entry += 4;
|
||||
break;
|
||||
case FT_BYTE:
|
||||
buffer << *(uint8*)entry;
|
||||
entry += 1;
|
||||
break;
|
||||
case FT_SHORT:
|
||||
buffer << *(uint16*)entry;
|
||||
entry += 2;
|
||||
break;
|
||||
case FT_STRING:
|
||||
{
|
||||
LocalizedString* locStr = *(LocalizedString**)entry;
|
||||
if (locStr->Str[locale][0] == '\0')
|
||||
locale = 0;
|
||||
|
||||
buffer << locStr->Str[locale];
|
||||
entry += sizeof(LocalizedString*);
|
||||
break;
|
||||
}
|
||||
case FT_STRING_NOT_LOCALIZED:
|
||||
{
|
||||
buffer << *(char const**)entry;
|
||||
entry += sizeof(char const*);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const;
|
||||
bool Load(std::string const& path, uint32 locale, char**& indexTable);
|
||||
bool LoadStringsFrom(std::string const& path, uint32 locale, char** indexTable);
|
||||
void LoadFromDB(char**& indexTable);
|
||||
void LoadStringsFromDB(uint32 locale, char** indexTable);
|
||||
|
||||
uint32 _tableHash;
|
||||
uint32 _layoutHash;
|
||||
std::string _fileName;
|
||||
uint32 _fieldCount;
|
||||
DB2LoadInfo _loadInfo;
|
||||
DB2LoadInfo const* _loadInfo;
|
||||
char* _dataTable;
|
||||
char* _dataTableEx;
|
||||
std::vector<char*> _stringPool;
|
||||
uint32 _indexTableSize;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
@@ -128,10 +74,9 @@ class DB2Storage : public DB2StorageBase
|
||||
public:
|
||||
typedef DBStorageIterator<T> iterator;
|
||||
|
||||
DB2Storage(char const* fileName, DB2LoadInfo&& loadInfo) : DB2StorageBase(fileName, std::move(loadInfo)),
|
||||
_indexTableSize(0)
|
||||
DB2Storage(char const* fileName, DB2LoadInfo const* loadInfo) : DB2StorageBase(fileName, loadInfo)
|
||||
{
|
||||
_indexTable.AsT = NULL;
|
||||
_indexTable.AsT = nullptr;
|
||||
}
|
||||
|
||||
~DB2Storage()
|
||||
@@ -153,61 +98,22 @@ public:
|
||||
uint32 GetNumRows() const { return _indexTableSize; }
|
||||
bool Load(std::string const& path, uint32 locale) override
|
||||
{
|
||||
DB2FileLoader db2;
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load((path + _fileName).c_str(), &_loadInfo))
|
||||
return false;
|
||||
|
||||
_fieldCount = db2.GetCols();
|
||||
_tableHash = db2.GetTableHash();
|
||||
_layoutHash = db2.GetLayoutHash();
|
||||
|
||||
// load raw non-string data
|
||||
_dataTable = db2.AutoProduceData(_indexTableSize, _indexTable.AsChar, _stringPool);
|
||||
|
||||
// load strings from db2 data
|
||||
if (!_stringPool.empty())
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
|
||||
db2.AutoProduceRecordCopies(_indexTableSize, _indexTable.AsChar, _dataTable);
|
||||
|
||||
// error in db2 file at loading if NULL
|
||||
return _indexTable.AsT != NULL;
|
||||
return DB2StorageBase::Load(path, locale, _indexTable.AsChar);
|
||||
}
|
||||
|
||||
bool LoadStringsFrom(std::string const& path, uint32 locale) override
|
||||
{
|
||||
// DB2 must be already loaded using Load
|
||||
if (!_indexTable.AsT)
|
||||
return false;
|
||||
|
||||
DB2FileLoader db2;
|
||||
// Check if load was successful, only then continue
|
||||
if (!db2.Load((path + _fileName).c_str(), &_loadInfo))
|
||||
return false;
|
||||
|
||||
// load strings from another locale db2 data
|
||||
if (_loadInfo.GetStringFieldCount(true))
|
||||
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
|
||||
_stringPool.push_back(stringBlock);
|
||||
return true;
|
||||
return DB2StorageBase::LoadStringsFrom(path, locale, _indexTable.AsChar);
|
||||
}
|
||||
|
||||
void LoadFromDB() override
|
||||
{
|
||||
char* extraStringHolders = nullptr;
|
||||
_dataTableEx = DB2DatabaseLoader(_fileName, &_loadInfo).Load(_indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPool);
|
||||
if (extraStringHolders)
|
||||
_stringPool.push_back(extraStringHolders);
|
||||
DB2StorageBase::LoadFromDB(_indexTable.AsChar);
|
||||
}
|
||||
|
||||
void LoadStringsFromDB(uint32 locale) override
|
||||
{
|
||||
if (!_loadInfo.GetStringFieldCount(true))
|
||||
return;
|
||||
|
||||
DB2DatabaseLoader(_fileName, &_loadInfo).LoadStrings(locale, _indexTableSize, _indexTable.AsChar, _stringPool);
|
||||
DB2StorageBase::LoadStringsFromDB(locale, _indexTable.AsChar);
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(_indexTable.AsT, _indexTableSize); }
|
||||
@@ -219,7 +125,6 @@ private:
|
||||
T** AsT;
|
||||
char** AsChar;
|
||||
} _indexTable;
|
||||
uint32 _indexTableSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,7 +14,10 @@ CollectSourceFiles(
|
||||
|
||||
add_library(extractor_common STATIC ${PRIVATE_SOURCES})
|
||||
|
||||
target_link_libraries(extractor_common boost casc)
|
||||
target_link_libraries(extractor_common
|
||||
PUBLIC
|
||||
casc
|
||||
common)
|
||||
|
||||
target_include_directories(extractor_common
|
||||
PUBLIC
|
||||
|
||||
@@ -16,32 +16,29 @@
|
||||
*/
|
||||
|
||||
#include "CascHandles.h"
|
||||
#include "CascLib.h"
|
||||
#include <CascLib.h>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
namespace
|
||||
char const* CASC::HumanReadableCASCError(DWORD error)
|
||||
{
|
||||
const char* HumanReadableCASCError(int error)
|
||||
switch (error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_SUCCESS: return "SUCCESS";
|
||||
case ERROR_FILE_CORRUPT: return "FILE_CORRUPT";
|
||||
case ERROR_CAN_NOT_COMPLETE: return "CAN_NOT_COMPLETE";
|
||||
case ERROR_HANDLE_EOF: return "HANDLE_EOF";
|
||||
case ERROR_NO_MORE_FILES: return "NO_MORE_FILES";
|
||||
case ERROR_BAD_FORMAT: return "BAD_FORMAT";
|
||||
case ERROR_INSUFFICIENT_BUFFER: return "INSUFFICIENT_BUFFER";
|
||||
case ERROR_ALREADY_EXISTS: return "ALREADY_EXISTS";
|
||||
case ERROR_DISK_FULL: return "DISK_FULL";
|
||||
case ERROR_INVALID_PARAMETER: return "INVALID_PARAMETER";
|
||||
case ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
|
||||
case ERROR_NOT_ENOUGH_MEMORY: return "NOT_ENOUGH_MEMORY";
|
||||
case ERROR_INVALID_HANDLE: return "INVALID_HANDLE";
|
||||
case ERROR_ACCESS_DENIED: return "ACCESS_DENIED";
|
||||
case ERROR_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
case ERROR_SUCCESS: return "SUCCESS";
|
||||
case ERROR_FILE_CORRUPT: return "FILE_CORRUPT";
|
||||
case ERROR_CAN_NOT_COMPLETE: return "CAN_NOT_COMPLETE";
|
||||
case ERROR_HANDLE_EOF: return "HANDLE_EOF";
|
||||
case ERROR_NO_MORE_FILES: return "NO_MORE_FILES";
|
||||
case ERROR_BAD_FORMAT: return "BAD_FORMAT";
|
||||
case ERROR_INSUFFICIENT_BUFFER: return "INSUFFICIENT_BUFFER";
|
||||
case ERROR_ALREADY_EXISTS: return "ALREADY_EXISTS";
|
||||
case ERROR_DISK_FULL: return "DISK_FULL";
|
||||
case ERROR_INVALID_PARAMETER: return "INVALID_PARAMETER";
|
||||
case ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
|
||||
case ERROR_NOT_ENOUGH_MEMORY: return "NOT_ENOUGH_MEMORY";
|
||||
case ERROR_INVALID_HANDLE: return "INVALID_HANDLE";
|
||||
case ERROR_ACCESS_DENIED: return "ACCESS_DENIED";
|
||||
case ERROR_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +92,11 @@ DWORD CASC::GetFileSize(FileHandle const& file, PDWORD fileSizeHigh)
|
||||
return ::CascGetFileSize(file.get(), fileSizeHigh);
|
||||
}
|
||||
|
||||
DWORD CASC::GetFilePointer(FileHandle const& file)
|
||||
{
|
||||
return ::CascSetFilePointer(file.get(), 0, nullptr, FILE_CURRENT);
|
||||
}
|
||||
|
||||
bool CASC::ReadFile(FileHandle const& file, void* buffer, DWORD bytes, PDWORD bytesRead)
|
||||
{
|
||||
return ::CascReadFile(file.get(), buffer, bytes, bytesRead);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef CascHandles_h__
|
||||
#define CascHandles_h__
|
||||
|
||||
#include "CascPort.h"
|
||||
#include <CascPort.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
@@ -46,10 +46,13 @@ namespace CASC
|
||||
typedef std::unique_ptr<HANDLE, StorageDeleter> StorageHandle;
|
||||
typedef std::unique_ptr<HANDLE, FileDeleter> FileHandle;
|
||||
|
||||
char const* HumanReadableCASCError(DWORD error);
|
||||
|
||||
StorageHandle OpenStorage(boost::filesystem::path const& path, DWORD localeMask);
|
||||
|
||||
FileHandle OpenFile(StorageHandle const& storage, char const* fileName, DWORD localeMask, bool printErrors = false);
|
||||
DWORD GetFileSize(FileHandle const& file, PDWORD fileSizeHigh);
|
||||
DWORD GetFilePointer(FileHandle const& file);
|
||||
bool ReadFile(FileHandle const& file, void* buffer, DWORD bytes, PDWORD bytesRead);
|
||||
}
|
||||
|
||||
|
||||
46
src/tools/extractor_common/DB2CascFileSource.cpp
Normal file
46
src/tools/extractor_common/DB2CascFileSource.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "DB2CascFileSource.h"
|
||||
#include <CascLib.h>
|
||||
|
||||
DB2CascFileSource::DB2CascFileSource(CASC::StorageHandle const& storage, std::string fileName)
|
||||
{
|
||||
_fileHandle = CASC::OpenFile(storage, fileName.c_str(), CASC_LOCALE_NONE, true);
|
||||
_fileName = std::move(fileName);
|
||||
}
|
||||
|
||||
bool DB2CascFileSource::IsOpen() const
|
||||
{
|
||||
return _fileHandle != nullptr;
|
||||
}
|
||||
|
||||
bool DB2CascFileSource::Read(void* buffer, std::size_t numBytes)
|
||||
{
|
||||
DWORD bytesRead = 0;
|
||||
return CASC::ReadFile(_fileHandle, buffer, numBytes, &bytesRead) && numBytes == bytesRead;
|
||||
}
|
||||
|
||||
std::size_t DB2CascFileSource::GetPosition() const
|
||||
{
|
||||
return CASC::GetFilePointer(_fileHandle);
|
||||
}
|
||||
|
||||
char const* DB2CascFileSource::GetFileName() const
|
||||
{
|
||||
return _fileName.c_str();
|
||||
}
|
||||
38
src/tools/extractor_common/DB2CascFileSource.h
Normal file
38
src/tools/extractor_common/DB2CascFileSource.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 DB2CascFileSource_h__
|
||||
#define DB2CascFileSource_h__
|
||||
|
||||
#include "DB2FileLoader.h"
|
||||
#include "CascHandles.h"
|
||||
#include <string>
|
||||
|
||||
struct DB2CascFileSource : public DB2FileSource
|
||||
{
|
||||
DB2CascFileSource(CASC::StorageHandle const& storage, std::string fileName);
|
||||
bool IsOpen() const override;
|
||||
bool Read(void* buffer, std::size_t numBytes) override;
|
||||
std::size_t GetPosition() const override;
|
||||
char const* GetFileName() const override;
|
||||
|
||||
private:
|
||||
CASC::FileHandle _fileHandle;
|
||||
std::string _fileName;
|
||||
};
|
||||
|
||||
#endif // DB2CascFile_h__
|
||||
@@ -28,7 +28,6 @@ target_include_directories(mapextractor
|
||||
|
||||
target_link_libraries(mapextractor
|
||||
PUBLIC
|
||||
common
|
||||
extractor_common)
|
||||
|
||||
CollectIncludeDirectories(
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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"
|
||||
#include <cassert>
|
||||
|
||||
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(CASC::FileHandle const& db2Handle, DB2Meta const* meta_)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
meta = meta_;
|
||||
std::uint32_t header;
|
||||
CASC::ReadFile(db2Handle, &header, sizeof(header), &bytesRead);
|
||||
if (bytesRead != sizeof(header)) // Signature
|
||||
return false;
|
||||
|
||||
EndianConvert(header);
|
||||
|
||||
if (header != 0x35424457)
|
||||
return false; //'WDB5'
|
||||
|
||||
CASC::ReadFile(db2Handle, &recordCount, sizeof(recordCount), &bytesRead);
|
||||
if (bytesRead != sizeof(recordCount)) // Number of records
|
||||
return false;
|
||||
|
||||
EndianConvert(recordCount);
|
||||
|
||||
CASC::ReadFile(db2Handle, &fieldCount, sizeof(fieldCount), &bytesRead);
|
||||
if (bytesRead != sizeof(fieldCount)) // Number of fields
|
||||
return false;
|
||||
|
||||
EndianConvert(fieldCount);
|
||||
|
||||
CASC::ReadFile(db2Handle, &recordSize, sizeof(recordSize), &bytesRead);
|
||||
if (bytesRead != sizeof(recordSize)) // Size of a record
|
||||
return false;
|
||||
|
||||
EndianConvert(recordSize);
|
||||
|
||||
CASC::ReadFile(db2Handle, &stringSize, sizeof(stringSize), &bytesRead);
|
||||
if (bytesRead != sizeof(stringSize)) // String size
|
||||
return false;
|
||||
|
||||
EndianConvert(stringSize);
|
||||
|
||||
CASC::ReadFile(db2Handle, &tableHash, sizeof(tableHash), &bytesRead);
|
||||
if (bytesRead != sizeof(tableHash)) // Table hash
|
||||
return false;
|
||||
|
||||
EndianConvert(tableHash);
|
||||
|
||||
CASC::ReadFile(db2Handle, &layoutHash, sizeof(layoutHash), &bytesRead);
|
||||
if (bytesRead != sizeof(layoutHash)) // Layout hash
|
||||
return false;
|
||||
|
||||
if (layoutHash != meta->LayoutHash)
|
||||
return false;
|
||||
|
||||
EndianConvert(layoutHash);
|
||||
|
||||
CASC::ReadFile(db2Handle, &minIndex, sizeof(minIndex), &bytesRead);
|
||||
if (bytesRead != sizeof(minIndex)) // MinIndex WDB2
|
||||
return false;
|
||||
|
||||
EndianConvert(minIndex);
|
||||
|
||||
CASC::ReadFile(db2Handle, &maxIndex, sizeof(maxIndex), &bytesRead);
|
||||
if (bytesRead != sizeof(maxIndex)) // MaxIndex WDB2
|
||||
return false;
|
||||
|
||||
EndianConvert(maxIndex);
|
||||
|
||||
CASC::ReadFile(db2Handle, &localeMask, sizeof(localeMask), &bytesRead);
|
||||
if (bytesRead != sizeof(localeMask)) // Locales
|
||||
return false;
|
||||
|
||||
EndianConvert(localeMask);
|
||||
|
||||
CASC::ReadFile(db2Handle, ©IdSize, sizeof(copyIdSize), &bytesRead);
|
||||
if (bytesRead != sizeof(copyIdSize))
|
||||
return false;
|
||||
|
||||
EndianConvert(copyIdSize);
|
||||
|
||||
CASC::ReadFile(db2Handle, &metaFlags, sizeof(metaFlags), &bytesRead);
|
||||
if (bytesRead != sizeof(metaFlags))
|
||||
return false;
|
||||
|
||||
EndianConvert(metaFlags);
|
||||
|
||||
ASSERT((metaFlags & 0x1) == 0);
|
||||
ASSERT((meta->IndexField == -1) || (meta->IndexField == int32((metaFlags >> 16))));
|
||||
|
||||
fields = new FieldEntry[fieldCount];
|
||||
CASC::ReadFile(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;
|
||||
|
||||
CASC::ReadFile(db2Handle, data, recordSize * recordCount + stringSize, &bytesRead);
|
||||
if (bytesRead != recordSize * recordCount + stringSize)
|
||||
return false;
|
||||
|
||||
if (idTableSize)
|
||||
{
|
||||
idTable = new unsigned char[idTableSize];
|
||||
CASC::ReadFile(db2Handle, idTable, idTableSize, &bytesRead);
|
||||
if (bytesRead != idTableSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (copyIdSize)
|
||||
{
|
||||
copyTable = new unsigned char[copyIdSize];
|
||||
CASC::ReadFile(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;
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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"
|
||||
#include "CascHandles.h"
|
||||
#include "CascLib.h"
|
||||
#include "Utilities/ByteConverter.h"
|
||||
#include "Errors.h"
|
||||
|
||||
class DB2FileLoader
|
||||
{
|
||||
public:
|
||||
DB2FileLoader();
|
||||
~DB2FileLoader();
|
||||
|
||||
bool Load(CASC::FileHandle const& 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__
|
||||
@@ -17,7 +17,20 @@
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "Banner.h"
|
||||
#include "CascHandles.h"
|
||||
#include "Common.h"
|
||||
#include "DB2CascFileSource.h"
|
||||
#include "DB2Meta.h"
|
||||
#include "DBFilesClientList.h"
|
||||
#include "StringFormat.h"
|
||||
#include "adt.h"
|
||||
#include "wdt.h"
|
||||
#include <CascLib.h>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <cstdio>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
@@ -25,46 +38,6 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include "Common.h"
|
||||
#include "DBFilesClientList.h"
|
||||
#include "CascLib.h"
|
||||
#include "CascHandles.h"
|
||||
#include "DB2.h"
|
||||
#include "Banner.h"
|
||||
#include "StringFormat.h"
|
||||
|
||||
#include "adt.h"
|
||||
#include "wdt.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* HumanReadableCASCError(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_SUCCESS: return "SUCCESS";
|
||||
case ERROR_FILE_CORRUPT: return "FILE_CORRUPT";
|
||||
case ERROR_CAN_NOT_COMPLETE: return "CAN_NOT_COMPLETE";
|
||||
case ERROR_HANDLE_EOF: return "HANDLE_EOF";
|
||||
case ERROR_NO_MORE_FILES: return "NO_MORE_FILES";
|
||||
case ERROR_BAD_FORMAT: return "BAD_FORMAT";
|
||||
case ERROR_INSUFFICIENT_BUFFER: return "INSUFFICIENT_BUFFER";
|
||||
case ERROR_ALREADY_EXISTS: return "ALREADY_EXISTS";
|
||||
case ERROR_DISK_FULL: return "DISK_FULL";
|
||||
case ERROR_INVALID_PARAMETER: return "INVALID_PARAMETER";
|
||||
case ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
|
||||
case ERROR_NOT_ENOUGH_MEMORY: return "NOT_ENOUGH_MEMORY";
|
||||
case ERROR_INVALID_HANDLE: return "INVALID_HANDLE";
|
||||
case ERROR_ACCESS_DENIED: return "ACCESS_DENIED";
|
||||
case ERROR_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CASC::StorageHandle CascStorage;
|
||||
|
||||
typedef struct
|
||||
@@ -79,36 +52,128 @@ std::set<std::string> CameraFileNames;
|
||||
boost::filesystem::path input_path;
|
||||
boost::filesystem::path output_path;
|
||||
|
||||
struct CinematicCameraMeta
|
||||
struct CinematicCameraLoadInfo
|
||||
{
|
||||
static DB2Meta const* Instance()
|
||||
static DB2FileLoadInfo const* Instance()
|
||||
{
|
||||
static DB2FieldMeta const fields[] =
|
||||
{
|
||||
{ false, FT_INT, "ID" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Model" },
|
||||
{ false, FT_FLOAT, "OriginX" },
|
||||
{ false, FT_FLOAT, "OriginY" },
|
||||
{ false, FT_FLOAT, "OriginZ" },
|
||||
{ false, FT_FLOAT, "OriginFacing" },
|
||||
{ false, FT_SHORT, "SoundID" },
|
||||
};
|
||||
static char const* types = "sffh";
|
||||
static uint8 const arraySizes[4] = { 1, 3, 1, 1 };
|
||||
static DB2Meta instance(-1, 4, 0xA7B95349, types, arraySizes);
|
||||
return &instance;
|
||||
static DB2Meta const meta(-1, 4, 0xA7B95349, types, arraySizes);
|
||||
static DB2FileLoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, &meta);
|
||||
return &loadInfo;
|
||||
}
|
||||
};
|
||||
|
||||
struct LiquidTypeMeta
|
||||
struct LiquidTypeLoadInfo
|
||||
{
|
||||
static DB2Meta const* Instance()
|
||||
static DB2FileLoadInfo const* Instance()
|
||||
{
|
||||
static DB2FieldMeta const fields[] =
|
||||
{
|
||||
{ false, FT_INT, "ID" },
|
||||
{ false, FT_STRING, "Name" },
|
||||
{ false, FT_INT, "SpellID" },
|
||||
{ false, FT_FLOAT, "MaxDarkenDepth" },
|
||||
{ false, FT_FLOAT, "FogDarkenIntensity" },
|
||||
{ false, FT_FLOAT, "AmbDarkenIntensity" },
|
||||
{ false, FT_FLOAT, "DirDarkenIntensity" },
|
||||
{ false, FT_FLOAT, "ParticleScale" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Texture1" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Texture2" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Texture3" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Texture4" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Texture5" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Texture6" },
|
||||
{ false, FT_INT, "Color1" },
|
||||
{ false, FT_INT, "Color2" },
|
||||
{ false, FT_FLOAT, "Float1" },
|
||||
{ false, FT_FLOAT, "Float2" },
|
||||
{ false, FT_FLOAT, "Float3" },
|
||||
{ false, FT_FLOAT, "Float4" },
|
||||
{ false, FT_FLOAT, "Float5" },
|
||||
{ false, FT_FLOAT, "Float6" },
|
||||
{ false, FT_FLOAT, "Float7" },
|
||||
{ false, FT_FLOAT, "Float8" },
|
||||
{ false, FT_FLOAT, "Float9" },
|
||||
{ false, FT_FLOAT, "Float10" },
|
||||
{ false, FT_FLOAT, "Float11" },
|
||||
{ false, FT_FLOAT, "Float12" },
|
||||
{ false, FT_FLOAT, "Float13" },
|
||||
{ false, FT_FLOAT, "Float14" },
|
||||
{ false, FT_FLOAT, "Float15" },
|
||||
{ false, FT_FLOAT, "Float16" },
|
||||
{ false, FT_FLOAT, "Float17" },
|
||||
{ false, FT_FLOAT, "Float18" },
|
||||
{ false, FT_INT, "Int1" },
|
||||
{ false, FT_INT, "Int2" },
|
||||
{ false, FT_INT, "Int3" },
|
||||
{ false, FT_INT, "Int4" },
|
||||
{ false, FT_SHORT, "Flags" },
|
||||
{ false, FT_SHORT, "LightID" },
|
||||
{ false, FT_BYTE, "Type" },
|
||||
{ false, FT_BYTE, "ParticleMovement" },
|
||||
{ false, FT_BYTE, "ParticleTexSlots" },
|
||||
{ false, FT_BYTE, "MaterialID" },
|
||||
{ false, FT_BYTE, "DepthTexCount1" },
|
||||
{ false, FT_BYTE, "DepthTexCount2" },
|
||||
{ false, FT_BYTE, "DepthTexCount3" },
|
||||
{ false, FT_BYTE, "DepthTexCount4" },
|
||||
{ false, FT_BYTE, "DepthTexCount5" },
|
||||
{ false, FT_BYTE, "DepthTexCount6" },
|
||||
{ false, FT_INT, "SoundID" },
|
||||
};
|
||||
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, 0x99FC34E5, types, arraySizes);
|
||||
return &instance;
|
||||
static DB2Meta const meta(-1, 19, 0x99FC34E5, types, arraySizes);
|
||||
static DB2FileLoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, &meta);
|
||||
return &loadInfo;
|
||||
}
|
||||
};
|
||||
|
||||
struct MapMeta
|
||||
struct MapLoadInfo
|
||||
{
|
||||
static DB2Meta const* Instance()
|
||||
static DB2FileLoadInfo const* Instance()
|
||||
{
|
||||
static DB2FieldMeta const fields[] =
|
||||
{
|
||||
{ false, FT_INT, "ID" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Directory" },
|
||||
{ false, FT_INT, "Flags1" },
|
||||
{ false, FT_INT, "Flags2" },
|
||||
{ false, FT_FLOAT, "MinimapIconScale" },
|
||||
{ false, FT_FLOAT, "CorpsePosX" },
|
||||
{ false, FT_FLOAT, "CorpsePosY" },
|
||||
{ false, FT_STRING, "MapName" },
|
||||
{ false, FT_STRING, "MapDescription0" },
|
||||
{ false, FT_STRING, "MapDescription1" },
|
||||
{ false, FT_SHORT, "AreaTableID" },
|
||||
{ false, FT_SHORT, "LoadingScreenID" },
|
||||
{ true, FT_SHORT, "CorpseMapID" },
|
||||
{ false, FT_SHORT, "TimeOfDayOverride" },
|
||||
{ true, FT_SHORT, "ParentMapID" },
|
||||
{ true, FT_SHORT, "CosmeticParentMapID" },
|
||||
{ false, FT_SHORT, "WindSettingsID" },
|
||||
{ false, FT_BYTE, "InstanceType" },
|
||||
{ false, FT_BYTE, "unk5" },
|
||||
{ false, FT_BYTE, "ExpansionID" },
|
||||
{ false, FT_BYTE, "MaxPlayers" },
|
||||
{ false, FT_BYTE, "TimeOffset" },
|
||||
};
|
||||
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, 0xF7CF2DA2, types, arraySizes);
|
||||
return &instance;
|
||||
static DB2Meta const meta(-1, 19, 0xF7CF2DA2, types, arraySizes);
|
||||
static DB2FileLoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, &meta);
|
||||
return &loadInfo;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -306,29 +371,22 @@ void ReadMapDBC()
|
||||
{
|
||||
printf("Read Map.db2 file...\n");
|
||||
|
||||
CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, "DBFilesClient\\Map.db2", CASC_LOCALE_NONE, true);
|
||||
if (!dbcFile)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DB2CascFileSource source(CascStorage, "DBFilesClient\\Map.db2");
|
||||
DB2FileLoader db2;
|
||||
if (!db2.Load(dbcFile, MapMeta::Instance()))
|
||||
if (!db2.Load(&source, MapLoadInfo::Instance()))
|
||||
{
|
||||
printf("Fatal error: Invalid Map.db2 file format! %s\n", HumanReadableCASCError(GetLastError()));
|
||||
printf("Fatal error: Invalid Map.db2 file format! %s\n", CASC::HumanReadableCASCError(GetLastError()));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
map_ids.resize(db2.GetNumRows());
|
||||
map_ids.resize(db2.GetRecordCount());
|
||||
std::unordered_map<uint32, uint32> idToIndex;
|
||||
for (uint32 x = 0; x < db2.GetNumRows(); ++x)
|
||||
for (uint32 x = 0; x < db2.GetRecordCount(); ++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);
|
||||
DB2Record record = db2.GetRecord(x);
|
||||
map_ids[x].id = record.GetId();
|
||||
|
||||
const char* map_name = db2.getRecord(x).getString(0, 0);
|
||||
const char* map_name = record.GetString(0, 0);
|
||||
size_t max_map_name_length = sizeof(map_ids[x].name);
|
||||
if (strlen(map_name) >= max_map_name_length)
|
||||
{
|
||||
@@ -341,15 +399,14 @@ void ReadMapDBC()
|
||||
idToIndex[map_ids[x].id] = x;
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < db2.GetNumRowCopies(); ++x)
|
||||
for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x)
|
||||
{
|
||||
uint32 from = db2.GetRowCopy(x).first;
|
||||
uint32 to = db2.GetRowCopy(x).second;
|
||||
auto itr = idToIndex.find(from);
|
||||
DB2RecordCopy copy = db2.GetRecordCopy(x);
|
||||
auto itr = idToIndex.find(copy.SourceRowId);
|
||||
if (itr != idToIndex.end())
|
||||
{
|
||||
map_id id;
|
||||
id.id = to;
|
||||
id.id = copy.NewRowId;
|
||||
strcpy(id.name, map_ids[itr->second].name);
|
||||
map_ids.push_back(id);
|
||||
}
|
||||
@@ -361,14 +418,10 @@ void ReadMapDBC()
|
||||
void ReadLiquidTypeTableDBC()
|
||||
{
|
||||
printf("Read LiquidType.db2 file...\n");
|
||||
CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, "DBFilesClient\\LiquidType.db2", CASC_LOCALE_NONE, true);
|
||||
if (!dbcFile)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DB2CascFileSource source(CascStorage, "DBFilesClient\\LiquidType.db2");
|
||||
DB2FileLoader db2;
|
||||
if (!db2.Load(dbcFile, LiquidTypeMeta::Instance()))
|
||||
if (!db2.Load(&source, LiquidTypeLoadInfo::Instance()))
|
||||
{
|
||||
printf("Fatal error: Invalid LiquidType.db2 file format!\n");
|
||||
exit(1);
|
||||
@@ -376,19 +429,14 @@ void ReadLiquidTypeTableDBC()
|
||||
|
||||
LiqType.resize(db2.GetMaxId() + 1, 0xFFFF);
|
||||
|
||||
for (uint32 x = 0; x < db2.GetNumRows(); ++x)
|
||||
for (uint32 x = 0; x < db2.GetRecordCount(); ++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);
|
||||
DB2Record record = db2.GetRecord(x);
|
||||
LiqType[record.GetId()] = record.GetUInt8(13, 0);
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < db2.GetNumRowCopies(); ++x)
|
||||
LiqType[db2.GetRowCopy(x).second] = LiqType[db2.GetRowCopy(x).first];
|
||||
for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x)
|
||||
LiqType[db2.GetRecordCopy(x).NewRowId] = LiqType[db2.GetRecordCopy(x).SourceRowId];
|
||||
|
||||
printf("Done! (" SZFMTD " LiqTypes loaded)\n", LiqType.size());
|
||||
}
|
||||
@@ -397,24 +445,19 @@ bool ReadCinematicCameraDBC()
|
||||
{
|
||||
printf("Read CinematicCamera.db2 file...\n");
|
||||
|
||||
CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, "DBFilesClient\\CinematicCamera.db2", CASC_LOCALE_NONE, true);
|
||||
if (!dbcFile)
|
||||
{
|
||||
printf("Unable to open CinematicCamera.db2. Camera extract aborted.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
DB2CascFileSource source(CascStorage, "DBFilesClient\\CinematicCamera.db2");
|
||||
DB2FileLoader db2;
|
||||
if (!db2.Load(dbcFile, CinematicCameraMeta::Instance()))
|
||||
if (!db2.Load(&source, CinematicCameraLoadInfo::Instance()))
|
||||
{
|
||||
printf("Invalid CinematicCamera.db2 file format. Camera extract aborted. %s\n", HumanReadableCASCError(GetLastError()));
|
||||
printf("Invalid CinematicCamera.db2 file format. Camera extract aborted. %s\n", CASC::HumanReadableCASCError(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// get camera file list from DB2
|
||||
for (size_t i = 0; i < db2.GetNumRows(); ++i)
|
||||
for (size_t i = 0; i < db2.GetRecordCount(); ++i)
|
||||
{
|
||||
std::string camFile(db2.getRecord(i).getString(0, 0));
|
||||
DB2Record record = db2.GetRecord(i);
|
||||
std::string camFile(record.GetString(0, 0));
|
||||
size_t loc = camFile.find(".mdx");
|
||||
if (loc != std::string::npos)
|
||||
camFile.replace(loc, 4, ".m2");
|
||||
@@ -1089,23 +1132,6 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExtractWmos(ChunkedFile& file, std::set<std::string>& wmoList)
|
||||
{
|
||||
if (FileChunk* chunk = file.GetChunk("MWMO"))
|
||||
{
|
||||
file_MWMO* wmo = chunk->As<file_MWMO>();
|
||||
if (wmo->size)
|
||||
{
|
||||
char* fileName = wmo->FileList;
|
||||
while (fileName < wmo->FileList + wmo->size)
|
||||
{
|
||||
wmoList.insert(fileName);
|
||||
fileName += strlen(fileName) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractMaps(uint32 build)
|
||||
{
|
||||
std::string storagePath;
|
||||
@@ -1119,8 +1145,6 @@ void ExtractMaps(uint32 build)
|
||||
|
||||
CreateDir(output_path / "maps");
|
||||
|
||||
std::set<std::string> wmoList;
|
||||
|
||||
printf("Convert map files\n");
|
||||
for (std::size_t z = 0; z < map_ids.size(); ++z)
|
||||
{
|
||||
@@ -1131,8 +1155,6 @@ void ExtractMaps(uint32 build)
|
||||
if (!wdt.loadFile(CascStorage, storagePath, false))
|
||||
continue;
|
||||
|
||||
ExtractWmos(wdt, wmoList);
|
||||
|
||||
FileChunk* chunk = wdt.GetChunk("MAIN");
|
||||
for (uint32 y = 0; y < WDT_MAP_SIZE; ++y)
|
||||
{
|
||||
@@ -1144,11 +1166,6 @@ void ExtractMaps(uint32 build)
|
||||
storagePath = Trinity::StringFormat("World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
|
||||
outputFileName = Trinity::StringFormat("%s/maps/%04u_%02u_%02u.map", output_path.string().c_str(), map_ids[z].id, y, x);
|
||||
ConvertADT(storagePath, outputFileName, y, x, build);
|
||||
|
||||
storagePath = Trinity::StringFormat("World\\Maps\\%s\\%s_%u_%u_obj0.adt", map_ids[z].name, map_ids[z].name, x, y);
|
||||
ChunkedFile adtObj;
|
||||
if (adtObj.loadFile(CascStorage, storagePath, false))
|
||||
ExtractWmos(adtObj, wmoList);
|
||||
}
|
||||
|
||||
// draw progress bar
|
||||
@@ -1156,17 +1173,6 @@ void ExtractMaps(uint32 build)
|
||||
}
|
||||
}
|
||||
|
||||
if (!wmoList.empty())
|
||||
{
|
||||
if (FILE* wmoListFile = fopen("wmo_list.txt", "w"))
|
||||
{
|
||||
for (std::string const& wmo : wmoList)
|
||||
fprintf(wmoListFile, "%s\n", wmo.c_str());
|
||||
|
||||
fclose(wmoListFile);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -1226,7 +1232,7 @@ void ExtractDBFilesClient(int l)
|
||||
++count;
|
||||
}
|
||||
else
|
||||
printf("Unable to open file %s in the archive for locale %s: %s\n", fileName, localeNames[l], HumanReadableCASCError(GetLastError()));
|
||||
printf("Unable to open file %s in the archive for locale %s: %s\n", fileName, localeNames[l], CASC::HumanReadableCASCError(GetLastError()));
|
||||
|
||||
fileName = DBFilesClientList[++index];
|
||||
}
|
||||
@@ -1260,7 +1266,7 @@ void ExtractCameraFiles()
|
||||
++count;
|
||||
}
|
||||
else
|
||||
printf("Unable to open file %s in the archive: %s\n", cameraFileName.c_str(), HumanReadableCASCError(GetLastError()));
|
||||
printf("Unable to open file %s in the archive: %s\n", cameraFileName.c_str(), CASC::HumanReadableCASCError(GetLastError()));
|
||||
}
|
||||
|
||||
printf("Extracted %u camera files\n", count);
|
||||
@@ -1326,7 +1332,7 @@ void ExtractGameTables()
|
||||
++count;
|
||||
}
|
||||
else
|
||||
printf("Unable to open file %s in the archive: %s\n", fileName, HumanReadableCASCError(GetLastError()));
|
||||
printf("Unable to open file %s in the archive: %s\n", fileName, CASC::HumanReadableCASCError(GetLastError()));
|
||||
|
||||
fileName = GameTables[++index];
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "loadlib.h"
|
||||
#include <CascLib.h>
|
||||
|
||||
u_map_fcc MverMagic = { { 'R','E','V','M' } };
|
||||
|
||||
@@ -40,9 +41,16 @@ bool ChunkedFile::loadFile(CASC::StorageHandle const& mpq, std::string const& fi
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
data_size = CASC::GetFileSize(file, nullptr);
|
||||
DWORD fileSize = CASC::GetFileSize(file, nullptr);
|
||||
if (fileSize == CASC_INVALID_SIZE)
|
||||
return false;
|
||||
|
||||
data_size = fileSize;
|
||||
data = new uint8[data_size];
|
||||
CASC::ReadFile(file, data, data_size, nullptr/*bytesRead*/);
|
||||
DWORD bytesRead = 0;
|
||||
if (!CASC::ReadFile(file, data, data_size, &bytesRead) || bytesRead != data_size)
|
||||
return false;
|
||||
|
||||
parseChunks();
|
||||
if (prepareLoadedData())
|
||||
return true;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include "CascHandles.h"
|
||||
#include "CascLib.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ add_executable(vmap4extractor ${PRIVATE_SOURCES})
|
||||
|
||||
target_link_libraries(vmap4extractor
|
||||
PUBLIC
|
||||
common
|
||||
casc
|
||||
bzip2
|
||||
extractor_common)
|
||||
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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"
|
||||
#include <cassert>
|
||||
|
||||
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(CASC::FileHandle const& db2Handle, DB2Meta const* meta_)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
meta = meta_;
|
||||
std::uint32_t header;
|
||||
CASC::ReadFile(db2Handle, &header, sizeof(header), &bytesRead);
|
||||
if (bytesRead != sizeof(header)) // Signature
|
||||
return false;
|
||||
|
||||
EndianConvert(header);
|
||||
|
||||
if (header != 0x35424457)
|
||||
return false; //'WDB5'
|
||||
|
||||
CASC::ReadFile(db2Handle, &recordCount, sizeof(recordCount), &bytesRead);
|
||||
if (bytesRead != sizeof(recordCount)) // Number of records
|
||||
return false;
|
||||
|
||||
EndianConvert(recordCount);
|
||||
|
||||
CASC::ReadFile(db2Handle, &fieldCount, sizeof(fieldCount), &bytesRead);
|
||||
if (bytesRead != sizeof(fieldCount)) // Number of fields
|
||||
return false;
|
||||
|
||||
EndianConvert(fieldCount);
|
||||
|
||||
CASC::ReadFile(db2Handle, &recordSize, sizeof(recordSize), &bytesRead);
|
||||
if (bytesRead != sizeof(recordSize)) // Size of a record
|
||||
return false;
|
||||
|
||||
EndianConvert(recordSize);
|
||||
|
||||
CASC::ReadFile(db2Handle, &stringSize, sizeof(stringSize), &bytesRead);
|
||||
if (bytesRead != sizeof(stringSize)) // String size
|
||||
return false;
|
||||
|
||||
EndianConvert(stringSize);
|
||||
|
||||
CASC::ReadFile(db2Handle, &tableHash, sizeof(tableHash), &bytesRead);
|
||||
if (bytesRead != sizeof(tableHash)) // Table hash
|
||||
return false;
|
||||
|
||||
EndianConvert(tableHash);
|
||||
|
||||
CASC::ReadFile(db2Handle, &layoutHash, sizeof(layoutHash), &bytesRead);
|
||||
if (bytesRead != sizeof(layoutHash)) // Layout hash
|
||||
return false;
|
||||
|
||||
if (layoutHash != meta->LayoutHash)
|
||||
return false;
|
||||
|
||||
EndianConvert(layoutHash);
|
||||
|
||||
CASC::ReadFile(db2Handle, &minIndex, sizeof(minIndex), &bytesRead);
|
||||
if (bytesRead != sizeof(minIndex)) // MinIndex WDB2
|
||||
return false;
|
||||
|
||||
EndianConvert(minIndex);
|
||||
|
||||
CASC::ReadFile(db2Handle, &maxIndex, sizeof(maxIndex), &bytesRead);
|
||||
if (bytesRead != sizeof(maxIndex)) // MaxIndex WDB2
|
||||
return false;
|
||||
|
||||
EndianConvert(maxIndex);
|
||||
|
||||
CASC::ReadFile(db2Handle, &localeMask, sizeof(localeMask), &bytesRead);
|
||||
if (bytesRead != sizeof(localeMask)) // Locales
|
||||
return false;
|
||||
|
||||
EndianConvert(localeMask);
|
||||
|
||||
CASC::ReadFile(db2Handle, ©IdSize, sizeof(copyIdSize), &bytesRead);
|
||||
if (bytesRead != sizeof(copyIdSize))
|
||||
return false;
|
||||
|
||||
EndianConvert(copyIdSize);
|
||||
|
||||
CASC::ReadFile(db2Handle, &metaFlags, sizeof(metaFlags), &bytesRead);
|
||||
if (bytesRead != sizeof(metaFlags))
|
||||
return false;
|
||||
|
||||
EndianConvert(metaFlags);
|
||||
|
||||
ASSERT((metaFlags & 0x1) == 0);
|
||||
ASSERT((meta->IndexField == -1) || (meta->IndexField == int32((metaFlags >> 16))));
|
||||
|
||||
fields = new FieldEntry[fieldCount];
|
||||
CASC::ReadFile(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;
|
||||
|
||||
CASC::ReadFile(db2Handle, data, recordSize * recordCount + stringSize, &bytesRead);
|
||||
if (bytesRead != recordSize * recordCount + stringSize)
|
||||
return false;
|
||||
|
||||
if (idTableSize)
|
||||
{
|
||||
idTable = new unsigned char[idTableSize];
|
||||
CASC::ReadFile(db2Handle, idTable, idTableSize, &bytesRead);
|
||||
if (bytesRead != idTableSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (copyIdSize)
|
||||
{
|
||||
copyTable = new unsigned char[copyIdSize];
|
||||
CASC::ReadFile(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;
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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"
|
||||
#include "CascHandles.h"
|
||||
#include "CascLib.h"
|
||||
#include "Utilities/ByteConverter.h"
|
||||
#include "Errors.h"
|
||||
|
||||
class DB2FileLoader
|
||||
{
|
||||
public:
|
||||
DB2FileLoader();
|
||||
~DB2FileLoader();
|
||||
|
||||
bool Load(CASC::FileHandle const& 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__
|
||||
@@ -148,12 +148,16 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
|
||||
char* p = buf;
|
||||
while (p < buf + size)
|
||||
{
|
||||
std::string path(p);
|
||||
|
||||
char* s = GetPlainName(p);
|
||||
FixNameCase(s, strlen(s));
|
||||
FixNameSpaces(s, strlen(s));
|
||||
|
||||
WmoInstanceNames.push_back(s);
|
||||
|
||||
ExtractSingleWmo(path);
|
||||
|
||||
p += strlen(p) + 1;
|
||||
}
|
||||
delete[] buf;
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "cascfile.h"
|
||||
#include <deque>
|
||||
#include <CascLib.h>
|
||||
#include <cstdio>
|
||||
|
||||
CASCFile::CASCFile(CASC::StorageHandle const& casc, const char* filename, bool warnNoExist /*= true*/) :
|
||||
@@ -12,33 +29,34 @@ CASCFile::CASCFile(CASC::StorageHandle const& casc, const char* filename, bool w
|
||||
if (!file)
|
||||
{
|
||||
if (warnNoExist || GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
fprintf(stderr, "Can't open %s, err=%u!\n", filename, GetLastError());
|
||||
fprintf(stderr, "Can't open %s: %s\n", filename, CASC::HumanReadableCASCError(GetLastError()));
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD hi = 0;
|
||||
size = CASC::GetFileSize(file, &hi);
|
||||
|
||||
if (hi)
|
||||
DWORD fileSizeHigh = 0;
|
||||
DWORD fileSize = CASC::GetFileSize(file, &fileSizeHigh);
|
||||
if (fileSize == CASC_INVALID_SIZE)
|
||||
{
|
||||
fprintf(stderr, "Can't open %s, size[hi] = %u!\n", filename, uint32(hi));
|
||||
fprintf(stderr, "Can't open %s, failed to get size: %s!\n", filename, CASC::HumanReadableCASCError(GetLastError()));
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (size <= 1)
|
||||
if (fileSizeHigh)
|
||||
{
|
||||
fprintf(stderr, "Can't open %s, size = %u!\n", filename, uint32(size));
|
||||
fprintf(stderr, "Can't open %s, file larger than 2GB", filename);
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
|
||||
size = fileSize;
|
||||
|
||||
DWORD read = 0;
|
||||
buffer = new char[size];
|
||||
if (!CASC::ReadFile(file, buffer, size, &read) || size != read)
|
||||
{
|
||||
fprintf(stderr, "Can't read %s, size=%u read=%u!\n", filename, uint32(size), uint32(read));
|
||||
fprintf(stderr, "Can't read %s, size=%u read=%u: %s\n", filename, uint32(size), uint32(read), CASC::HumanReadableCASCError(GetLastError()));
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
@@ -46,10 +64,12 @@ CASCFile::CASCFile(CASC::StorageHandle const& casc, const char* filename, bool w
|
||||
|
||||
size_t CASCFile::read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof) return 0;
|
||||
if (eof)
|
||||
return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > size) {
|
||||
if (rpos > size)
|
||||
{
|
||||
bytes = size - pointer;
|
||||
eof = true;
|
||||
}
|
||||
@@ -75,7 +95,7 @@ void CASCFile::seekRelative(int offset)
|
||||
|
||||
void CASCFile::close()
|
||||
{
|
||||
if (buffer) delete[] buffer;
|
||||
delete[] buffer;
|
||||
buffer = 0;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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/>.
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS // fuck the police^Wwarnings
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
@@ -6,33 +23,12 @@
|
||||
#ifndef MPQ_H
|
||||
#define MPQ_H
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <cstdint>
|
||||
#include "Define.h"
|
||||
#include "CascHandles.h"
|
||||
#include "CascLib.h"
|
||||
|
||||
typedef int64_t int64;
|
||||
typedef int32_t int32;
|
||||
typedef int16_t int16;
|
||||
typedef int8_t int8;
|
||||
typedef uint64_t uint64;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint8_t uint8;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h> // mainly only HANDLE definition is required
|
||||
#else
|
||||
int GetLastError();
|
||||
#endif
|
||||
#include <utility>
|
||||
|
||||
class CASCFile
|
||||
{
|
||||
//MPQHANDLE handle;
|
||||
bool eof;
|
||||
char *buffer;
|
||||
size_t pointer,size;
|
||||
@@ -57,13 +53,8 @@ public:
|
||||
|
||||
inline void flipcc(char *fcc)
|
||||
{
|
||||
char t;
|
||||
t=fcc[0];
|
||||
fcc[0]=fcc[3];
|
||||
fcc[3]=t;
|
||||
t=fcc[1];
|
||||
fcc[1]=fcc[2];
|
||||
fcc[2]=t;
|
||||
std::swap(fcc[0], fcc[3]);
|
||||
std::swap(fcc[1], fcc[2]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,14 +16,16 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DB2.h"
|
||||
#include "model.h"
|
||||
#include "adtfile.h"
|
||||
#include "vmapexport.h"
|
||||
#include "DB2CascFileSource.h"
|
||||
#include "DB2Meta.h"
|
||||
#include "Errors.h"
|
||||
#include "model.h"
|
||||
#include "StringFormat.h"
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include <CascLib.h>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
|
||||
bool ExtractSingleModel(std::string& fname)
|
||||
{
|
||||
@@ -55,14 +57,29 @@ bool ExtractSingleModel(std::string& fname)
|
||||
|
||||
extern CASC::StorageHandle CascStorage;
|
||||
|
||||
struct GameObjectDisplayInfoMeta
|
||||
struct GameobjectDisplayInfoLoadInfo
|
||||
{
|
||||
static DB2Meta const* Instance()
|
||||
static DB2FileLoadInfo const* Instance()
|
||||
{
|
||||
static DB2FieldMeta const fields[] =
|
||||
{
|
||||
{ false, FT_INT, "ID" },
|
||||
{ false, FT_INT, "FileDataID" },
|
||||
{ false, FT_FLOAT, "GeoBoxMinX" },
|
||||
{ false, FT_FLOAT, "GeoBoxMinY" },
|
||||
{ false, FT_FLOAT, "GeoBoxMinZ" },
|
||||
{ false, FT_FLOAT, "GeoBoxMaxX" },
|
||||
{ false, FT_FLOAT, "GeoBoxMaxY" },
|
||||
{ false, FT_FLOAT, "GeoBoxMaxZ" },
|
||||
{ false, FT_FLOAT, "OverrideLootEffectScale" },
|
||||
{ false, FT_FLOAT, "OverrideNameScale" },
|
||||
{ false, FT_SHORT, "ObjectEffectPackageID" },
|
||||
};
|
||||
static char const* types = "ifffh";
|
||||
static uint8 const arraySizes[5] = { 1, 6, 1, 1, 1 };
|
||||
static DB2Meta instance(-1, 5, 0xE2D6FAB7, types, arraySizes);
|
||||
return &instance;
|
||||
static DB2Meta const meta(-1, 5, 0xE2D6FAB7, types, arraySizes);
|
||||
static DB2FileLoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, &meta);
|
||||
return &loadInfo;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,15 +106,11 @@ bool GetHeaderMagic(std::string const& fileName, uint32* magic)
|
||||
|
||||
void ExtractGameobjectModels()
|
||||
{
|
||||
printf("Extracting GameObject models...");
|
||||
CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, "DBFilesClient\\GameObjectDisplayInfo.db2", CASC_LOCALE_NONE, true);
|
||||
if (!dbcFile)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
printf("Extracting GameObject models...\n");
|
||||
|
||||
DB2CascFileSource source(CascStorage, "DBFilesClient\\GameObjectDisplayInfo.db2");
|
||||
DB2FileLoader db2;
|
||||
if (!db2.Load(dbcFile, GameObjectDisplayInfoMeta::Instance()))
|
||||
if (!db2.Load(&source, GameobjectDisplayInfoLoadInfo::Instance()))
|
||||
{
|
||||
printf("Fatal error: Invalid GameObjectDisplayInfo.db2 file format!\n");
|
||||
exit(1);
|
||||
@@ -114,9 +127,10 @@ void ExtractGameobjectModels()
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32 rec = 0; rec < db2.GetNumRows(); ++rec)
|
||||
for (uint32 rec = 0; rec < db2.GetRecordCount(); ++rec)
|
||||
{
|
||||
uint32 fileId = db2.getRecord(rec).getUInt(0, 0);
|
||||
DB2Record record = db2.GetRecord(rec);
|
||||
uint32 fileId = record.GetUInt32(0, 0);
|
||||
if (!fileId)
|
||||
continue;
|
||||
|
||||
@@ -135,7 +149,7 @@ void ExtractGameobjectModels()
|
||||
|
||||
if (result)
|
||||
{
|
||||
uint32 displayId = db2.getId(rec);
|
||||
uint32 displayId = record.GetId();
|
||||
uint32 path_length = fileName.length();
|
||||
fwrite(&displayId, sizeof(uint32), 1, model_list);
|
||||
fwrite(&path_length, sizeof(uint32), 1, model_list);
|
||||
|
||||
@@ -17,14 +17,29 @@
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include <cstdio>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "adtfile.h"
|
||||
#include "Banner.h"
|
||||
#include "Common.h"
|
||||
#include "cascfile.h"
|
||||
#include "DB2CascFileSource.h"
|
||||
#include "DB2Meta.h"
|
||||
#include "StringFormat.h"
|
||||
#include "vmapexport.h"
|
||||
#include "wdtfile.h"
|
||||
#include "wmo.h"
|
||||
#include <CascLib.h>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <errno.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <sys/stat.h>
|
||||
#include <direct.h>
|
||||
@@ -34,22 +49,6 @@
|
||||
#define ERROR_PATH_NOT_FOUND ERROR_FILE_NOT_FOUND
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
|
||||
#include "Common.h"
|
||||
//From Extractor
|
||||
#include "adtfile.h"
|
||||
#include "wdtfile.h"
|
||||
#include "DB2.h"
|
||||
#include "wmo.h"
|
||||
#include "cascfile.h"
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "Banner.h"
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
@@ -66,30 +65,44 @@ typedef struct
|
||||
}map_id;
|
||||
|
||||
std::vector<map_id> map_ids;
|
||||
std::vector<uint16> LiqType;
|
||||
uint32 map_count;
|
||||
boost::filesystem::path input_path;
|
||||
bool preciseVectorData = false;
|
||||
|
||||
struct LiquidTypeMeta
|
||||
struct MapLoadInfo
|
||||
{
|
||||
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, 0x99FC34E5, types, arraySizes);
|
||||
return &instance;
|
||||
}
|
||||
};
|
||||
|
||||
struct MapMeta
|
||||
{
|
||||
static DB2Meta const* Instance()
|
||||
static DB2FileLoadInfo const* Instance()
|
||||
{
|
||||
static DB2FieldMeta const fields[] =
|
||||
{
|
||||
{ false, FT_INT, "ID" },
|
||||
{ false, FT_STRING_NOT_LOCALIZED, "Directory" },
|
||||
{ false, FT_INT, "Flags1" },
|
||||
{ false, FT_INT, "Flags2" },
|
||||
{ false, FT_FLOAT, "MinimapIconScale" },
|
||||
{ false, FT_FLOAT, "CorpsePosX" },
|
||||
{ false, FT_FLOAT, "CorpsePosY" },
|
||||
{ false, FT_STRING, "MapName" },
|
||||
{ false, FT_STRING, "MapDescription0" },
|
||||
{ false, FT_STRING, "MapDescription1" },
|
||||
{ false, FT_SHORT, "AreaTableID" },
|
||||
{ false, FT_SHORT, "LoadingScreenID" },
|
||||
{ true, FT_SHORT, "CorpseMapID" },
|
||||
{ false, FT_SHORT, "TimeOfDayOverride" },
|
||||
{ true, FT_SHORT, "ParentMapID" },
|
||||
{ true, FT_SHORT, "CosmeticParentMapID" },
|
||||
{ false, FT_SHORT, "WindSettingsID" },
|
||||
{ false, FT_BYTE, "InstanceType" },
|
||||
{ false, FT_BYTE, "unk5" },
|
||||
{ false, FT_BYTE, "ExpansionID" },
|
||||
{ false, FT_BYTE, "MaxPlayers" },
|
||||
{ false, FT_BYTE, "TimeOffset" },
|
||||
};
|
||||
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, 0xF7CF2DA2, types, arraySizes);
|
||||
return &instance;
|
||||
static DB2Meta const meta(-1, 19, 0xF7CF2DA2, types, arraySizes);
|
||||
static DB2FileLoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, &meta);
|
||||
return &loadInfo;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -129,32 +142,6 @@ uint32 WowLocaleToCascLocaleFlags[12] =
|
||||
CASC_LOCALE_ITIT,
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* HumanReadableCASCError(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_SUCCESS: return "SUCCESS";
|
||||
case ERROR_FILE_CORRUPT: return "FILE_CORRUPT";
|
||||
case ERROR_CAN_NOT_COMPLETE: return "CAN_NOT_COMPLETE";
|
||||
case ERROR_HANDLE_EOF: return "HANDLE_EOF";
|
||||
case ERROR_NO_MORE_FILES: return "NO_MORE_FILES";
|
||||
case ERROR_BAD_FORMAT: return "BAD_FORMAT";
|
||||
case ERROR_INSUFFICIENT_BUFFER: return "INSUFFICIENT_BUFFER";
|
||||
case ERROR_ALREADY_EXISTS: return "ALREADY_EXISTS";
|
||||
case ERROR_DISK_FULL: return "DISK_FULL";
|
||||
case ERROR_INVALID_PARAMETER: return "INVALID_PARAMETER";
|
||||
case ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
|
||||
case ERROR_NOT_ENOUGH_MEMORY: return "NOT_ENOUGH_MEMORY";
|
||||
case ERROR_INVALID_HANDLE: return "INVALID_HANDLE";
|
||||
case ERROR_ACCESS_DENIED: return "ACCESS_DENIED";
|
||||
case ERROR_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ReadBuild(int locale)
|
||||
{
|
||||
// include build info file also
|
||||
@@ -241,73 +228,6 @@ void strToLower(char* str)
|
||||
}
|
||||
}
|
||||
|
||||
// copied from src\tools\map_extractor\System.cpp
|
||||
void ReadLiquidTypeTableDBC()
|
||||
{
|
||||
printf("Read LiquidType.dbc file...");
|
||||
CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, "DBFilesClient\\LiquidType.db2", CASC_LOCALE_NONE, true);
|
||||
if (!dbcFile)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DB2FileLoader db2;
|
||||
if (!db2.Load(dbcFile, LiquidTypeMeta::Instance()))
|
||||
{
|
||||
printf("Fatal error: Invalid LiquidType.db2 file format!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LiqType.resize(db2.GetMaxId() + 1, 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 < db2.GetNumRowCopies(); ++x)
|
||||
LiqType[db2.GetRowCopy(x).second] = LiqType[db2.GetRowCopy(x).first];
|
||||
|
||||
printf("Done! (" SZFMTD " LiqTypes loaded)\n", LiqType.size());
|
||||
}
|
||||
|
||||
bool ExtractWmo()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
std::ifstream wmoList("wmo_list.txt");
|
||||
if (!wmoList)
|
||||
{
|
||||
printf("\nUnable to open wmo_list.txt! Nothing extracted.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<std::string> wmos;
|
||||
for (;;)
|
||||
{
|
||||
std::string str;
|
||||
std::getline(wmoList, str);
|
||||
if (str.empty())
|
||||
break;
|
||||
|
||||
wmos.insert(std::move(str));
|
||||
}
|
||||
|
||||
for (std::string str : wmos)
|
||||
success &= ExtractSingleWmo(str);
|
||||
|
||||
if (success)
|
||||
printf("\nExtract wmo complete (No (fatal) errors)\n");
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ExtractSingleWmo(std::string& fname)
|
||||
{
|
||||
// Copy files from archive
|
||||
@@ -315,7 +235,8 @@ bool ExtractSingleWmo(std::string& fname)
|
||||
char szLocalFile[1024];
|
||||
const char * plain_name = GetPlainName(fname.c_str());
|
||||
sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name);
|
||||
FixNameCase(szLocalFile,strlen(szLocalFile));
|
||||
FixNameCase(szLocalFile, strlen(szLocalFile));
|
||||
FixNameSpaces(szLocalFile, strlen(szLocalFile));
|
||||
|
||||
if (FileExists(szLocalFile))
|
||||
return true;
|
||||
@@ -339,7 +260,7 @@ bool ExtractSingleWmo(std::string& fname)
|
||||
return true;
|
||||
|
||||
bool file_ok = true;
|
||||
std::cout << "Extracting " << fname << std::endl;
|
||||
printf("Extracting %s\n", fname.c_str());
|
||||
WMORoot froot(fname);
|
||||
if(!froot.open())
|
||||
{
|
||||
@@ -355,25 +276,18 @@ bool ExtractSingleWmo(std::string& fname)
|
||||
froot.ConvertToVMAPRootWmo(output);
|
||||
int Wmo_nVertices = 0;
|
||||
//printf("root has %d groups\n", froot->nGroups);
|
||||
if (!froot.groupFileDataIDs.empty())
|
||||
for (std::size_t i = 0; i < froot.groupFileDataIDs.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < froot.groupFileDataIDs.size(); ++i)
|
||||
std::string s = Trinity::StringFormat("FILE%08X.xxx", froot.groupFileDataIDs[i]);
|
||||
WMOGroup fgroup(s);
|
||||
if(!fgroup.open())
|
||||
{
|
||||
char groupFileName[1024];
|
||||
sprintf(groupFileName, "FILE%08X", froot.groupFileDataIDs[i]);
|
||||
//printf("Trying to open groupfile %s\n",groupFileName);
|
||||
|
||||
std::string s = groupFileName;
|
||||
WMOGroup fgroup(s);
|
||||
if(!fgroup.open())
|
||||
{
|
||||
printf("Could not open all Group file for: %s\n", plain_name);
|
||||
file_ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData);
|
||||
printf("Could not open all Group file for: %s\n", plain_name);
|
||||
file_ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData);
|
||||
}
|
||||
|
||||
fseek(output, 8, SEEK_SET); // store the correct no of vertices
|
||||
@@ -544,41 +458,28 @@ int main(int argc, char ** argv)
|
||||
// Extract models, listed in GameObjectDisplayInfo.dbc
|
||||
ExtractGameobjectModels();
|
||||
|
||||
ReadLiquidTypeTableDBC();
|
||||
|
||||
// extract data
|
||||
if (success)
|
||||
success = ExtractWmo();
|
||||
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
//map.dbc
|
||||
if (success)
|
||||
{
|
||||
printf("Read Map.dbc file... ");
|
||||
|
||||
CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, "DBFilesClient\\Map.db2", CASC_LOCALE_NONE, true);
|
||||
if (!dbcFile)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DB2CascFileSource source(CascStorage, "DBFilesClient\\Map.db2");
|
||||
DB2FileLoader db2;
|
||||
if (!db2.Load(dbcFile, MapMeta::Instance()))
|
||||
if (!db2.Load(&source, MapLoadInfo::Instance()))
|
||||
{
|
||||
printf("Fatal error: Invalid Map.db2 file format! %s\n", HumanReadableCASCError(GetLastError()));
|
||||
printf("Fatal error: Invalid Map.db2 file format! %s\n", CASC::HumanReadableCASCError(GetLastError()));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
map_ids.resize(db2.GetNumRows());
|
||||
map_ids.resize(db2.GetRecordCount());
|
||||
std::unordered_map<uint32, uint32> idToIndex;
|
||||
for (uint32 x = 0; x < db2.GetNumRows(); ++x)
|
||||
for (uint32 x = 0; x < db2.GetRecordCount(); ++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);
|
||||
DB2Record record = db2.GetRecord(x);
|
||||
map_ids[x].id = record.GetId();
|
||||
|
||||
const char* map_name = db2.getRecord(x).getString(0, 0);
|
||||
const char* map_name = record.GetString(0, 0);
|
||||
size_t max_map_name_length = sizeof(map_ids[x].name);
|
||||
if (strlen(map_name) >= max_map_name_length)
|
||||
{
|
||||
@@ -591,15 +492,14 @@ int main(int argc, char ** argv)
|
||||
idToIndex[map_ids[x].id] = x;
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < db2.GetNumRowCopies(); ++x)
|
||||
for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x)
|
||||
{
|
||||
uint32 from = db2.GetRowCopy(x).first;
|
||||
uint32 to = db2.GetRowCopy(x).second;
|
||||
auto itr = idToIndex.find(from);
|
||||
DB2RecordCopy copy = db2.GetRecordCopy(x);
|
||||
auto itr = idToIndex.find(copy.SourceRowId);
|
||||
if (itr != idToIndex.end())
|
||||
{
|
||||
map_id id;
|
||||
id.id = to;
|
||||
id.id = copy.NewRowId;
|
||||
strcpy(id.name, map_ids[itr->second].name);
|
||||
map_ids.push_back(id);
|
||||
}
|
||||
|
||||
@@ -80,10 +80,15 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
|
||||
char *p = buf;
|
||||
while (p < buf + size)
|
||||
{
|
||||
std::string path(p);
|
||||
|
||||
char* s = wdtGetPlainName(p);
|
||||
FixNameCase(s, strlen(s));
|
||||
FixNameSpaces(s, strlen(s));
|
||||
p = p + strlen(p) + 1;
|
||||
gWmoInstansName.push_back(s);
|
||||
|
||||
ExtractSingleWmo(path);
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "wmo.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
class ADTFile;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "cascfile.h"
|
||||
|
||||
using namespace std;
|
||||
extern std::vector<uint16> LiqType;
|
||||
|
||||
WMORoot::WMORoot(std::string &filename)
|
||||
: filename(filename), color(0), nTextures(0), nGroups(0), nPortals(0), nLights(0),
|
||||
|
||||
@@ -135,8 +135,6 @@ public:
|
||||
uint32 indx, id, d2, d3;
|
||||
|
||||
WMOInstance(CASCFile&f , char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
|
||||
|
||||
static void reset();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user