From ae8814772fa4a63d42b4f588bc99d88fd4d3d6e8 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 24 Dec 2014 22:24:32 +0100 Subject: Core/DataStores: Implemented loading hotfixes database into DB2Storage --- src/server/game/DataStores/DB2Stores.cpp | 4 +- src/server/game/Globals/ObjectMgr.cpp | 41 -- src/server/game/Globals/ObjectMgr.h | 3 - src/server/game/World/World.cpp | 3 - src/server/shared/DataStores/DB2FileLoader.cpp | 408 ---------------- src/server/shared/DataStores/DB2FileLoader.h | 107 ----- src/server/shared/DataStores/DB2StorageLoader.cpp | 513 +++++++++++++++++++++ src/server/shared/DataStores/DB2StorageLoader.h | 114 +++++ src/server/shared/DataStores/DB2Store.h | 69 ++- .../Database/Implementation/HotfixDatabase.cpp | 2 + .../Database/Implementation/HotfixDatabase.h | 1 + 11 files changed, 664 insertions(+), 601 deletions(-) delete mode 100644 src/server/shared/DataStores/DB2FileLoader.cpp delete mode 100644 src/server/shared/DataStores/DB2FileLoader.h create mode 100644 src/server/shared/DataStores/DB2StorageLoader.cpp create mode 100644 src/server/shared/DataStores/DB2StorageLoader.h (limited to 'src') diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 39e5d443871..42902e08466 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -50,7 +50,7 @@ DB2Storage sSpellRuneCostStore(SpellRuneCostEnt DB2Storage sSpellTotemsStore(SpellTotemsEntryfmt); DB2Storage sTaxiNodesStore(TaxiNodesEntryfmt); DB2Storage sTaxiPathStore(TaxiPathEntryfmt); -DB2Storage sTaxiPathNodeStore(TaxiPathNodeEntryfmt); +DB2Storage sTaxiPathNodeStore(TaxiPathNodeEntryfmt, HOTFIX_SEL_TAXI_PATH_NODE); TaxiMask sTaxiNodesMask; TaxiMask sOldContinentsNodesMask; TaxiMask sHordeTaxiNodesMask; @@ -86,6 +86,8 @@ inline void LoadDB2(uint32& availableDb2Locales, DB2StoreProblemList& errlist, D std::string db2_filename = db2_path + filename; if (storage.Load(db2_filename.c_str(), uint32(sWorld->GetDefaultDbcLocale()))) { + storage.LoadSQLData(); + for (uint32 i = 0; i < TOTAL_LOCALES; ++i) { if (!(availableDb2Locales & (1 << i))) diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index f9c532d23dd..dc326555c36 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -8675,47 +8675,6 @@ void ObjectMgr::LoadHotfixData() TC_LOG_INFO("server.loading", ">> Loaded %u hotfix info entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadMissingKeyChains() -{ - uint32 oldMSTime = getMSTime(); - - QueryResult result = WorldDatabase.Query("SELECT keyId, k1, k2, k3, k4, k5, k6, k7, k8, " - "k9, k10, k11, k12, k13, k14, k15, k16, " - "k17, k18, k19, k20, k21, k22, k23, k24, " - "k25, k26, k27, k28, k29, k30, k31, k32 " - "FROM keychain_db2 ORDER BY keyId DESC"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 KeyChain entries. DB table `keychain_db2` is empty."); - return; - } - - uint32 count = 0; - - do - { - Field* fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - - KeyChainEntry* kce = sKeyChainStore.CreateEntry(id, true); - if (!kce) - { - TC_LOG_ERROR("sql.sql", "Could not create KeyChainEntry %u, skipped.", id); - continue; - } - - kce->Id = id; - for (uint32 i = 0; i < KEYCHAIN_SIZE; ++i) - kce->Key[i] = fields[1 + i].GetUInt8(); - - ++count; - } - while (result->NextRow()); - - TC_LOG_INFO("server.loading", ">> Loaded %u KeyChain entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); -} - void ObjectMgr::LoadFactionChangeSpells() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 9b83ce27392..134e9bf7483 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1354,9 +1354,6 @@ class ObjectMgr return ret ? ret : time(NULL); } - void LoadMissingKeyChains(); - - void LoadRaceAndClassExpansionRequirements(); void LoadRealmNames(); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index a3ee2fa1265..b1e0b1795e0 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1923,9 +1923,6 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("misc", "Loading hotfix info..."); sObjectMgr->LoadHotfixData(); - TC_LOG_INFO("server.loading", "Loading missing KeyChains..."); - sObjectMgr->LoadMissingKeyChains(); - TC_LOG_INFO("server.loading", "Loading race and class expansion requirements..."); sObjectMgr->LoadRaceAndClassExpansionRequirements(); diff --git a/src/server/shared/DataStores/DB2FileLoader.cpp b/src/server/shared/DataStores/DB2FileLoader.cpp deleted file mode 100644 index 7a27072dd20..00000000000 --- a/src/server/shared/DataStores/DB2FileLoader.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (C) 2011 TrintiyCore - * - * 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 . - */ - -#include "Common.h" - -#include -#include -#include -#include "DB2FileLoader.h" - -DB2FileLoader::DB2FileLoader() -{ - data = NULL; - fieldsOffset = NULL; -} - -bool DB2FileLoader::Load(const char *filename, const char *fmt) -{ - if (data) - { - delete [] data; - data = NULL; - } - - FILE* f = fopen(filename, "rb"); - if (!f) - return false; - - uint32 header; - if (fread(&header, 4, 1, f) != 1) // Signature - { - fclose(f); - return false; - } - - EndianConvert(header); - - if (header != 0x32424457) - { - fclose(f); - return false; //'WDB2' - } - - if (fread(&recordCount, 4, 1, f) != 1) // Number of records - { - fclose(f); - return false; - } - - EndianConvert(recordCount); - - if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields - { - fclose(f); - return false; - } - - EndianConvert(fieldCount); - - if (fread(&recordSize, 4, 1, f) != 1) // Size of a record - { - fclose(f); - return false; - } - - EndianConvert(recordSize); - - if (fread(&stringSize, 4, 1, f) != 1) // String size - { - fclose(f); - return false; - } - - EndianConvert(stringSize); - - /* NEW WDB2 FIELDS*/ - if (fread(&tableHash, 4, 1, f) != 1) // Table hash - { - fclose(f); - return false; - } - - EndianConvert(tableHash); - - if (fread(&build, 4, 1, f) != 1) // Build - { - fclose(f); - return false; - } - - EndianConvert(build); - - if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2 - { - fclose(f); - return false; - } - - EndianConvert(unk1); - - if (build > 12880) - { - if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2 - { - fclose(f); - return false; - } - EndianConvert(minIndex); - - if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2 - { - fclose(f); - return false; - } - EndianConvert(maxIndex); - - if (fread(&locale, 4, 1, f) != 1) // Locales - { - fclose(f); - return false; - } - EndianConvert(locale); - - if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2 - { - fclose(f); - return false; - } - EndianConvert(unk5); - } - - if (maxIndex != 0) - { - int32 diff = maxIndex - minIndex + 1; - fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank - } - - fieldsOffset = new uint32[fieldCount]; - fieldsOffset[0] = 0; - for (uint32 i = 1; i < fieldCount; i++) - { - fieldsOffset[i] = fieldsOffset[i - 1]; - if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') - fieldsOffset[i] += 1; - else - fieldsOffset[i] += 4; - } - - data = new unsigned char[recordSize*recordCount+stringSize]; - stringTable = data + recordSize*recordCount; - - if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1) - { - fclose(f); - return false; - } - - fclose(f); - return true; -} - -DB2FileLoader::~DB2FileLoader() -{ - if (data) - delete [] data; - if (fieldsOffset) - delete [] fieldsOffset; -} - -DB2FileLoader::Record DB2FileLoader::getRecord(size_t id) -{ - assert(data); - return Record(*this, data + id*recordSize); -} - -uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos) -{ - uint32 recordsize = 0; - int32 i = -1; - for (uint32 x=0; format[x]; ++x) - { - switch (format[x]) - { - case FT_FLOAT: - case FT_INT: - recordsize += 4; - break; - case FT_STRING: - recordsize += sizeof(char*); - break; - case FT_SORT: - i = x; - break; - case FT_IND: - i = x; - recordsize += 4; - break; - case FT_BYTE: - recordsize += 1; - break; - } - } - - if (index_pos) - *index_pos = i; - - return recordsize; -} - -uint32 DB2FileLoader::GetFormatStringsFields(const char * format) -{ - uint32 stringfields = 0; - for (uint32 x=0; format[x]; ++x) - if (format[x] == FT_STRING) - ++stringfields; - - return stringfields; -} - -char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable) -{ - - typedef char * ptr; - if (strlen(format) != fieldCount) - return NULL; - - //get struct size and index pos - int32 i; - uint32 recordsize=GetFormatRecordSize(format, &i); - - if (i >= 0) - { - uint32 maxi = 0; - //find max index - for (uint32 y = 0; y < recordCount; y++) - { - uint32 ind=getRecord(y).getUInt(i); - if (ind>maxi) - maxi = ind; - } - - ++maxi; - records = maxi; - indexTable = new ptr[maxi]; - memset(indexTable, 0, maxi * sizeof(ptr)); - } - else - { - records = recordCount; - indexTable = new ptr[recordCount]; - } - - char* dataTable = new char[recordCount * recordsize]; - - uint32 offset=0; - - for (uint32 y =0; y < recordCount; y++) - { - if (i>=0) - { - indexTable[getRecord(y).getUInt(i)] = &dataTable[offset]; - } - else - indexTable[y] = &dataTable[offset]; - - for (uint32 x = 0; x < fieldCount; x++) - { - switch (format[x]) - { - case FT_FLOAT: - *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x); - offset += 4; - break; - case FT_IND: - case FT_INT: - *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x); - offset += 4; - break; - case FT_BYTE: - *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x); - offset += 1; - break; - case FT_STRING: - *((char**)(&dataTable[offset])) = NULL; // will be replaces non-empty or "" strings in AutoProduceStrings - offset += sizeof(char*); - break; - } - } - } - - return dataTable; -} - -static char const* const nullStr = ""; - -char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable) -{ - if (strlen(format) != fieldCount) - return NULL; - - // we store flat holders pool as single memory block - size_t stringFields = GetFormatStringsFields(format); - // each string field at load have array of string for each locale - size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; - size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount; - - char* stringHoldersPool = new char[stringHoldersPoolSize]; - - // DB2 strings expected to have at least empty string - for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) - ((char const**)stringHoldersPool)[i] = nullStr; - - uint32 offset=0; - - // assign string holders to string field slots - for (uint32 y = 0; y < recordCount; y++) - { - uint32 stringFieldNum = 0; - - for (uint32 x = 0; x < fieldCount; x++) - switch (format[x]) - { - case FT_FLOAT: - case FT_IND: - case FT_INT: - offset += 4; - break; - case FT_BYTE: - offset += 1; - break; - case FT_STRING: - { - // init db2 string field slots by pointers to string holders - char const*** slot = (char const***)(&dataTable[offset]); - *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringHolderSize*stringFieldNum]); - ++stringFieldNum; - offset += sizeof(char*); - break; - } - case FT_NA: - case FT_NA_BYTE: - case FT_SORT: - break; - default: - assert(false && "unknown format character"); - } - } - - //send as char* for store in char* pool list for free at unload - return stringHoldersPool; -} - -char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale) -{ - if (strlen(format) != fieldCount) - return NULL; - - char* stringPool= new char[stringSize]; - memcpy(stringPool, stringTable, stringSize); - - uint32 offset = 0; - - for (uint32 y =0; y < recordCount; y++) - { - for (uint32 x = 0; x < fieldCount; x++) - switch (format[x]) - { - case FT_FLOAT: - case FT_IND: - case FT_INT: - offset += 4; - break; - case FT_BYTE: - offset += 1; - break; - case FT_STRING: - { - // fill only not filled entries - LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]); - if (db2str->Str[locale] == nullStr) - { - const char * st = getRecord(y).getString(x); - db2str->Str[locale] = stringPool + (st - (const char*)stringTable); - } - - offset += sizeof(char*); - break; - } - } - } - - return stringPool; -} diff --git a/src/server/shared/DataStores/DB2FileLoader.h b/src/server/shared/DataStores/DB2FileLoader.h deleted file mode 100644 index 86350ebf1d6..00000000000 --- a/src/server/shared/DataStores/DB2FileLoader.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2011 TrintiyCore - * - * 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 . - */ - -#ifndef DB2_FILE_LOADER_H -#define DB2_FILE_LOADER_H - -#include "Define.h" -#include "Utilities/ByteConverter.h" -#include - -class DB2FileLoader -{ - public: - DB2FileLoader(); - ~DB2FileLoader(); - - bool Load(const char *filename, const char *fmt); - - class Record - { - public: - float getFloat(size_t field) const - { - assert(field < file.fieldCount); - float val = *reinterpret_cast(offset+file.GetOffset(field)); - EndianConvert(val); - return val; - } - uint32 getUInt(size_t field) const - { - assert(field < file.fieldCount); - uint32 val = *reinterpret_cast(offset+file.GetOffset(field)); - EndianConvert(val); - return val; - } - uint8 getUInt8(size_t field) const - { - assert(field < file.fieldCount); - return *reinterpret_cast(offset+file.GetOffset(field)); - } - - const char *getString(size_t field) const - { - assert(field < file.fieldCount); - size_t stringOffset = getUInt(field); - assert(stringOffset < file.stringSize); - return reinterpret_cast(file.stringTable + stringOffset); - } - - private: - 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); - /// Get begin iterator over records - - uint32 GetNumRows() const { return recordCount;} - uint32 GetCols() const { return fieldCount; } - uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; } - uint32 GetHash() const { return tableHash; } - bool IsLoaded() const { return (data != NULL); } - char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable); - char* AutoProduceStringsArrayHolders(const char* fmt, char* dataTable); - char* AutoProduceStrings(const char* fmt, char* dataTable, uint32 locale); - static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL); - static uint32 GetFormatStringsFields(const char * format); -private: - - uint32 recordSize; - uint32 recordCount; - uint32 fieldCount; - uint32 stringSize; - uint32 *fieldsOffset; - unsigned char *data; - unsigned char *stringTable; - - // WDB2 / WCH2 fields - uint32 tableHash; // WDB2 - uint32 build; // WDB2 - - int unk1; // WDB2 (Unix time in WCH2) - int minIndex; // WDB2 - int maxIndex; // WDB2 (index table) - int locale; // WDB2 - int unk5; // WDB2 -}; - -#endif \ No newline at end of file diff --git a/src/server/shared/DataStores/DB2StorageLoader.cpp b/src/server/shared/DataStores/DB2StorageLoader.cpp new file mode 100644 index 00000000000..1e68c4881f8 --- /dev/null +++ b/src/server/shared/DataStores/DB2StorageLoader.cpp @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2011 TrintiyCore + * + * 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 . + */ + +#include "Common.h" +#include "DB2StorageLoader.h" +#include "Database/DatabaseEnv.h" + +#include +#include +#include + +DB2FileLoader::DB2FileLoader() +{ + data = NULL; + fieldsOffset = NULL; +} + +bool DB2FileLoader::Load(const char *filename, const char *fmt) +{ + if (data) + { + delete [] data; + data = NULL; + } + + FILE* f = fopen(filename, "rb"); + if (!f) + return false; + + uint32 header; + if (fread(&header, 4, 1, f) != 1) // Signature + { + fclose(f); + return false; + } + + EndianConvert(header); + + if (header != 0x32424457) + { + fclose(f); + return false; //'WDB2' + } + + if (fread(&recordCount, 4, 1, f) != 1) // Number of records + { + fclose(f); + return false; + } + + EndianConvert(recordCount); + + if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields + { + fclose(f); + return false; + } + + EndianConvert(fieldCount); + + if (fread(&recordSize, 4, 1, f) != 1) // Size of a record + { + fclose(f); + return false; + } + + EndianConvert(recordSize); + + if (fread(&stringSize, 4, 1, f) != 1) // String size + { + fclose(f); + return false; + } + + EndianConvert(stringSize); + + /* NEW WDB2 FIELDS*/ + if (fread(&tableHash, 4, 1, f) != 1) // Table hash + { + fclose(f); + return false; + } + + EndianConvert(tableHash); + + if (fread(&build, 4, 1, f) != 1) // Build + { + fclose(f); + return false; + } + + EndianConvert(build); + + if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2 + { + fclose(f); + return false; + } + + EndianConvert(unk1); + + if (build > 12880) + { + if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2 + { + fclose(f); + return false; + } + EndianConvert(minIndex); + + if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2 + { + fclose(f); + return false; + } + EndianConvert(maxIndex); + + if (fread(&locale, 4, 1, f) != 1) // Locales + { + fclose(f); + return false; + } + EndianConvert(locale); + + if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2 + { + fclose(f); + return false; + } + EndianConvert(unk5); + } + + if (maxIndex != 0) + { + int32 diff = maxIndex - minIndex + 1; + fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank + } + + fieldsOffset = new uint32[fieldCount]; + fieldsOffset[0] = 0; + for (uint32 i = 1; i < fieldCount; i++) + { + fieldsOffset[i] = fieldsOffset[i - 1]; + if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') + fieldsOffset[i] += 1; + else + fieldsOffset[i] += 4; + } + + data = new unsigned char[recordSize*recordCount+stringSize]; + stringTable = data + recordSize*recordCount; + + if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1) + { + fclose(f); + return false; + } + + fclose(f); + return true; +} + +DB2FileLoader::~DB2FileLoader() +{ + if (data) + delete [] data; + if (fieldsOffset) + delete [] fieldsOffset; +} + +DB2FileLoader::Record DB2FileLoader::getRecord(size_t id) +{ + assert(data); + return Record(*this, data + id*recordSize); +} + +uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos) +{ + uint32 recordsize = 0; + int32 i = -1; + for (uint32 x=0; format[x]; ++x) + { + switch (format[x]) + { + case FT_FLOAT: + case FT_INT: + recordsize += 4; + break; + case FT_STRING: + recordsize += sizeof(char*); + break; + case FT_SORT: + i = x; + break; + case FT_IND: + i = x; + recordsize += 4; + break; + case FT_BYTE: + recordsize += 1; + break; + } + } + + if (index_pos) + *index_pos = i; + + return recordsize; +} + +uint32 DB2FileLoader::GetFormatStringsFields(const char * format) +{ + uint32 stringfields = 0; + for (uint32 x=0; format[x]; ++x) + if (format[x] == FT_STRING) + ++stringfields; + + return stringfields; +} + +char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable) +{ + typedef char * ptr; + if (strlen(format) != fieldCount) + return NULL; + + //get struct size and index pos + int32 indexField; + uint32 recordsize = GetFormatRecordSize(format, &indexField); + + if (indexField >= 0) + { + uint32 maxi = 0; + //find max index + for (uint32 y = 0; y < recordCount; y++) + { + uint32 ind = getRecord(y).getUInt(indexField); + if (ind > maxi) + maxi = ind; + } + + ++maxi; + records = maxi; + indexTable = new ptr[maxi]; + memset(indexTable, 0, maxi * sizeof(ptr)); + } + else + { + records = recordCount; + indexTable = new ptr[recordCount]; + } + + char* dataTable = new char[recordCount * recordsize]; + + uint32 offset = 0; + + for (uint32 y = 0; y < recordCount; y++) + { + if (indexField >= 0) + indexTable[getRecord(y).getUInt(indexField)] = &dataTable[offset]; + else + indexTable[y] = &dataTable[offset]; + + for (uint32 x = 0; x < fieldCount; x++) + { + switch (format[x]) + { + case FT_FLOAT: + *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x); + offset += 4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x); + offset += 4; + break; + case FT_BYTE: + *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x); + offset += 1; + break; + case FT_STRING: + *((char**)(&dataTable[offset])) = NULL; // will be replaces non-empty or "" strings in AutoProduceStrings + offset += sizeof(char*); + break; + } + } + } + + return dataTable; +} + +static char const* const nullStr = ""; + +char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable) +{ + if (strlen(format) != fieldCount) + return nullptr; + + // we store flat holders pool as single memory block + size_t stringFields = GetFormatStringsFields(format); + if (!stringFields) + return nullptr; + + // each string field at load have array of string for each locale + size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; + size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; + size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount; + + char* stringHoldersPool = new char[stringHoldersPoolSize]; + + // DB2 strings expected to have at least empty string + for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) + ((char const**)stringHoldersPool)[i] = nullStr; + + uint32 offset = 0; + + // assign string holders to string field slots + for (uint32 y = 0; y < recordCount; y++) + { + uint32 stringFieldNum = 0; + + for (uint32 x = 0; x < fieldCount; x++) + { + switch (format[x]) + { + case FT_FLOAT: + case FT_IND: + case FT_INT: + offset += 4; + break; + case FT_BYTE: + offset += 1; + break; + case FT_STRING: + { + // init db2 string field slots by pointers to string holders + char const*** slot = (char const***)(&dataTable[offset]); + *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringHolderSize*stringFieldNum]); + ++stringFieldNum; + offset += sizeof(char*); + break; + } + case FT_NA: + case FT_NA_BYTE: + case FT_SORT: + break; + default: + ASSERT(false, "unknown format character %c", format[x]); + } + } + } + + //send as char* for store in char* pool list for free at unload + return stringHoldersPool; +} + +char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale) +{ + if (strlen(format) != fieldCount) + return NULL; + + char* stringPool = new char[stringSize]; + memcpy(stringPool, stringTable, stringSize); + + uint32 offset = 0; + + for (uint32 y = 0; y < recordCount; y++) + { + for (uint32 x = 0; x < fieldCount; x++) + { + switch (format[x]) + { + case FT_FLOAT: + case FT_IND: + case FT_INT: + offset += 4; + break; + case FT_BYTE: + offset += 1; + break; + case FT_STRING: + { + // fill only not filled entries + LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]); + if (db2str->Str[locale] == nullStr) + { + const char * st = getRecord(y).getString(x); + db2str->Str[locale] = stringPool + (st - (const char*)stringTable); + } + + offset += sizeof(char*); + break; + } + } + } + } + + return stringPool; +} + +char* DB2DatabaseLoader::Load(const char* format, int32 preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list& stringPool) +{ + PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(preparedStatement)); + if (!result) + return nullptr; + + if (strlen(format) + 1 /*VerifiedBuild*/ != result->GetFieldCount()) + return nullptr; + + //get struct size and index pos + int32 indexField; + uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField); + + // we store flat holders pool as single memory block + size_t stringFields = DB2FileLoader::GetFormatStringsFields(format); + + // each string field at load have array of string for each locale + size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; + size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; + size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); + + if (stringFields) + stringHolders = new char[stringHoldersPoolSize]; + else + stringHolders = nullptr; + + std::unordered_map tempIndexTable; + tempIndexTable.reserve(result->GetRowCount()); + char* dataTable = new char[result->GetRowCount() * recordSize]; + uint32 offset = 0; + + uint32 oldIndexSize = records; + uint32 rec = 0; + do + { + Field* fields = result->Fetch(); + uint32 stringFieldNum = 0; + + if (indexField >= 0) + { + uint32 indexValue = fields[indexField].GetUInt32(); + tempIndexTable[indexValue] = &dataTable[offset]; + if (records <= indexValue) + records = indexValue + 1; + } + else + tempIndexTable[records++] = &dataTable[offset]; + + for (uint32 x = 0; x < result->GetFieldCount(); x++) + { + switch (format[x]) + { + case FT_FLOAT: + *((float*)(&dataTable[offset])) = fields[x].GetFloat(); + offset += 4; + break; + case FT_IND: + case FT_INT: + *((int32*)(&dataTable[offset])) = fields[x].GetInt32(); + offset += 4; + break; + case FT_BYTE: + *((int8*)(&dataTable[offset])) = fields[x].GetInt8(); + offset += 1; + break; + case FT_STRING: + { + std::string value = fields[x].GetString(); + LocalizedString** slot = (LocalizedString**)(&dataTable[offset]); + *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec++ + stringHolderSize * stringFieldNum]); + // Value in database field must be for enUS locale + char* str = new char[value.length() + 1]; + strcpy(str, value.c_str()); + stringPool.push_back(str); + (*slot)->Str[LOCALE_enUS] = str; + ++stringFieldNum; + offset += sizeof(char*); + break; + } + } + } + } while (result->NextRow()); + + // Reallocate index if needed + if (records > oldIndexSize) + { + char** tmpIdxTable = new char*[records]; + memset(tmpIdxTable, 0, records * sizeof(char*)); + memcpy(tmpIdxTable, indexTable, oldIndexSize * sizeof(char*)); + delete[] indexTable; + indexTable = tmpIdxTable; + } + + // Merge new data into index + for (auto itr = tempIndexTable.begin(); itr != tempIndexTable.end(); ++itr) + indexTable[itr->first] = itr->second; + + return dataTable; +} diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h new file mode 100644 index 00000000000..82f5ff02afe --- /dev/null +++ b/src/server/shared/DataStores/DB2StorageLoader.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 TrintiyCore + * + * 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 . + */ + +#ifndef DB2_FILE_LOADER_H +#define DB2_FILE_LOADER_H + +#include "Define.h" +#include "Utilities/ByteConverter.h" +#include + +class DB2FileLoader +{ + public: + DB2FileLoader(); + ~DB2FileLoader(); + + bool Load(const char *filename, const char *fmt); + + class Record + { + public: + float getFloat(size_t field) const + { + assert(field < file.fieldCount); + float val = *reinterpret_cast(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint32 getUInt(size_t field) const + { + assert(field < file.fieldCount); + uint32 val = *reinterpret_cast(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint8 getUInt8(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast(offset+file.GetOffset(field)); + } + + const char *getString(size_t field) const + { + assert(field < file.fieldCount); + size_t stringOffset = getUInt(field); + assert(stringOffset < file.stringSize); + return reinterpret_cast(file.stringTable + stringOffset); + } + + private: + 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); + /// Get begin iterator over records + + uint32 GetNumRows() const { return recordCount;} + uint32 GetCols() const { return fieldCount; } + uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; } + uint32 GetHash() const { return tableHash; } + bool IsLoaded() const { return (data != NULL); } + char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable); + char* AutoProduceStringsArrayHolders(const char* fmt, char* dataTable); + char* AutoProduceStrings(const char* fmt, char* dataTable, uint32 locale); + static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL); + static uint32 GetFormatStringsFields(const char * format); +private: + + uint32 recordSize; + uint32 recordCount; + uint32 fieldCount; + uint32 stringSize; + uint32 *fieldsOffset; + unsigned char *data; + unsigned char *stringTable; + + // WDB2 / WCH2 fields + uint32 tableHash; // WDB2 + uint32 build; // WDB2 + + int unk1; // WDB2 (Unix time in WCH2) + int minIndex; // WDB2 + int maxIndex; // WDB2 (index table) + int locale; // WDB2 + int unk5; // WDB2 +}; + +class DB2DatabaseLoader +{ +public: + + char* Load(const char* format, int32 preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list& stringPool); +}; + +#endif diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h index 77d6c4144e5..84134c48160 100644 --- a/src/server/shared/DataStores/DB2Store.h +++ b/src/server/shared/DataStores/DB2Store.h @@ -18,7 +18,7 @@ #ifndef DB2STORE_H #define DB2STORE_H -#include "DB2FileLoader.h" +#include "DB2StorageLoader.h" #include "Common.h" #include "ByteBuffer.h" #include @@ -101,12 +101,11 @@ template class DB2Storage : public DB2StorageBase { typedef std::list StringPoolList; - typedef std::vector DataTableEx; typedef bool(*EntryChecker)(DB2Storage const&, uint32); typedef void(*PacketWriter)(DB2Storage const&, uint32, uint32, ByteBuffer&); public: - DB2Storage(char const* f, EntryChecker checkEntry = NULL, PacketWriter writePacket = NULL) : - nCount(0), fieldCount(0), fmt(f), m_dataTable(NULL) + DB2Storage(char const* f, int32 preparedStmtIndex = -1, EntryChecker checkEntry = nullptr, PacketWriter writePacket = nullptr) + : nCount(0), fieldCount(0), fmt(f), m_dataTable(nullptr), m_dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex) { indexTable.asT = NULL; CheckEntry = checkEntry ? checkEntry : (EntryChecker)&DB2StorageHasEntry; @@ -125,30 +124,6 @@ public: WritePacket(*this, id, locale, buffer); } - T* CreateEntry(uint32 id, bool evenIfExists = false) - { - if (evenIfExists && LookupEntry(id)) - return NULL; - - if (id >= nCount) - { - // reallocate index table - char** tmpIdxTable = new char*[id + 1]; - memset(tmpIdxTable, 0, (id + 1) * sizeof(char*)); - memcpy(tmpIdxTable, indexTable.asChar, nCount * sizeof(char*)); - delete[] reinterpret_cast(indexTable.asT); - nCount = id + 1; - indexTable.asChar = tmpIdxTable; - } - - T* entryDst = new T; - m_dataTableEx.push_back(entryDst); - indexTable.asT[id] = entryDst; - return entryDst; - } - - void EraseEntry(uint32 id) { indexTable.asT[id] = NULL; } - bool Load(char const* fn, uint32 locale) { DB2FileLoader db2; @@ -163,10 +138,13 @@ public: m_dataTable = reinterpret_cast(db2.AutoProduceData(fmt, nCount, indexTable.asChar)); // create string holders for loaded string fields - m_stringPoolList.push_back(db2.AutoProduceStringsArrayHolders(fmt, (char*)m_dataTable)); + if (char* stringHolders = db2.AutoProduceStringsArrayHolders(fmt, (char*)m_dataTable)) + { + m_stringPoolList.push_back(stringHolders); - // load strings from dbc data - m_stringPoolList.push_back(db2.AutoProduceStrings(fmt, (char*)m_dataTable, locale)); + // load strings from dbc data + m_stringPoolList.push_back(db2.AutoProduceStrings(fmt, (char*)m_dataTable, locale)); + } // error in dbc file at loading if NULL return indexTable.asT != NULL; @@ -184,25 +162,39 @@ public: return false; // load strings from another locale dbc data - m_stringPoolList.push_back(db2.AutoProduceStrings(fmt, (char*)m_dataTable, locale)); + if (DB2FileLoader::GetFormatStringsFields(fmt)) + m_stringPoolList.push_back(db2.AutoProduceStrings(fmt, (char*)m_dataTable, locale)); return true; } + void LoadSQLData() + { + if (_hotfixStatement == -1) + return; + + DB2DatabaseLoader db2; + char* extraStringHolders = nullptr; + if (char* dataTable = db2.Load(fmt, _hotfixStatement, nCount, indexTable.asChar, extraStringHolders, m_stringPoolList)) + { + m_dataTableEx = reinterpret_cast(dataTable); + m_stringPoolList.push_back(extraStringHolders); + } + } + void Clear() { if (!indexTable.asT) return; delete[] reinterpret_cast(indexTable.asT); - indexTable.asT = NULL; + indexTable.asT = nullptr; delete[] reinterpret_cast(m_dataTable); - m_dataTable = NULL; + m_dataTable = nullptr; - for (typename DataTableEx::iterator itr = m_dataTableEx.begin(); itr != m_dataTableEx.end(); ++itr) - delete *itr; - m_dataTableEx.clear(); + delete[] reinterpret_cast(m_dataTableEx); + m_dataTableEx = nullptr; while (!m_stringPoolList.empty()) { @@ -226,8 +218,9 @@ private: char** asChar; } indexTable; T* m_dataTable; - DataTableEx m_dataTableEx; + T* m_dataTableEx; StringPoolList m_stringPoolList; + int32 _hotfixStatement; }; #endif diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.cpp b/src/server/shared/Database/Implementation/HotfixDatabase.cpp index f60287ef1a7..ae9ec73c9bc 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/shared/Database/Implementation/HotfixDatabase.cpp @@ -21,4 +21,6 @@ void HotfixDatabaseConnection::DoPrepareStatements() { if (!m_reconnecting) m_stmts.resize(MAX_HOTFIXDATABASE_STATEMENTS); + + PrepareStatement(HOTFIX_SEL_TAXI_PATH_NODE, "SELECT * FROM taxi_path_node", CONNECTION_SYNCH); } diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.h b/src/server/shared/Database/Implementation/HotfixDatabase.h index 13c3af6714e..5ee09ccd014 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.h +++ b/src/server/shared/Database/Implementation/HotfixDatabase.h @@ -42,6 +42,7 @@ enum HotfixDatabaseStatements name for a suiting suffix. */ + HOTFIX_SEL_TAXI_PATH_NODE, MAX_HOTFIXDATABASE_STATEMENTS }; -- cgit v1.2.3