aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Common.h2
-rw-r--r--src/common/DataStores/DB2FileLoader.cpp91
-rw-r--r--src/common/DataStores/DB2FileLoader.h16
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp148
-rw-r--r--src/server/game/DataStores/DB2Stores.h2
-rw-r--r--src/server/game/Maps/TransportMgr.h2
-rw-r--r--src/server/game/World/World.cpp8
-rw-r--r--src/server/shared/DataStores/DB2Store.cpp20
-rw-r--r--src/server/shared/DataStores/DB2Store.h16
-rw-r--r--src/tools/map_extractor/System.cpp51
-rw-r--r--src/tools/mmaps_generator/PathGenerator.cpp32
-rw-r--r--src/tools/vmap4_extractor/gameobject_extract.cpp8
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp8
13 files changed, 232 insertions, 172 deletions
diff --git a/src/common/Common.h b/src/common/Common.h
index f35773e7c70..0a3ab68d39f 100644
--- a/src/common/Common.h
+++ b/src/common/Common.h
@@ -103,7 +103,7 @@ TC_COMMON_API LocaleConstant GetLocaleByName(std::string const& name);
constexpr inline bool IsValidLocale(LocaleConstant locale)
{
- return locale < TOTAL_LOCALES&& locale != LOCALE_none;
+ return locale < TOTAL_LOCALES && locale != LOCALE_none;
}
#pragma pack(push, 1)
diff --git a/src/common/DataStores/DB2FileLoader.cpp b/src/common/DataStores/DB2FileLoader.cpp
index 529e924e6aa..b45a425617e 100644
--- a/src/common/DataStores/DB2FileLoader.cpp
+++ b/src/common/DataStores/DB2FileLoader.cpp
@@ -21,6 +21,7 @@
#include "Errors.h"
#include "Log.h"
#include <sstream>
+#include <system_error>
enum class DB2ColumnCompression : uint32
{
@@ -1027,7 +1028,7 @@ void DB2FileLoaderSparseImpl::SetAdditionalData(std::vector<uint32> /*idTable*/,
char* DB2FileLoaderSparseImpl::AutoProduceData(uint32& indexTableSize, char**& indexTable)
{
if (_loadInfo->Meta->FieldCount != _header->FieldCount)
- return nullptr;
+ throw DB2FileLoadException(Trinity::StringFormat("Found unsupported parent index in sparse db2 %s", _fileName));
//get struct size and index pos
uint32 recordsize = _loadInfo->Meta->GetRecordSize();
@@ -1155,7 +1156,7 @@ char* DB2FileLoaderSparseImpl::AutoProduceData(uint32& indexTableSize, char**& i
char* DB2FileLoaderSparseImpl::AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale)
{
if (_loadInfo->Meta->FieldCount != _header->FieldCount)
- return nullptr;
+ throw DB2FileLoadException(Trinity::StringFormat("Found unsupported parent index in sparse db2 %s", _fileName));
if (!(_header->Locale & (1 << locale)))
{
@@ -1672,7 +1673,7 @@ void DB2Record::MakePersistent()
_fieldOffsets = _db2.RecordCreateDetachedFieldOffsets(_fieldOffsets);
}
-DB2FileLoader::DB2FileLoader() : _impl(nullptr)
+DB2FileLoader::DB2FileLoader() : _impl(nullptr), _header()
{
}
@@ -1681,13 +1682,13 @@ DB2FileLoader::~DB2FileLoader()
delete _impl;
}
-bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
+void DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
{
if (!source->IsOpen())
- return false;
+ throw std::system_error(std::make_error_code(std::errc::no_such_file_or_directory));
if (!source->Read(&_header, sizeof(DB2Header)))
- return false;
+ throw DB2FileLoadException("Failed to read header");
EndianConvert(_header.Signature);
EndianConvert(_header.RecordCount);
@@ -1710,23 +1711,27 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
EndianConvert(_header.SectionCount);
if (_header.Signature != 0x33434457) //'WDC3'
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Incorrect file signature in %s, expected 'WDC3', got %c%c%c%c", source->GetFileName(),
+ char(_header.Signature & 0xFF), char((_header.Signature >> 8) & 0xFF), char((_header.Signature >> 16) & 0xFF), char((_header.Signature >> 24) & 0xFF)));
if (loadInfo && _header.LayoutHash != loadInfo->Meta->LayoutHash)
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Incorrect layout hash in %s, expected 0x%08X, got 0x%08X (possibly wrong client version)",
+ source->GetFileName(), loadInfo->Meta->LayoutHash, _header.LayoutHash));
if (_header.ParentLookupCount > 1)
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Too many parent lookups in %s, only one is allowed, got %u",
+ source->GetFileName(), _header.ParentLookupCount));
if (loadInfo && (_header.TotalFieldCount + (loadInfo->Meta->ParentIndexField >= int32(_header.TotalFieldCount) ? 1 : 0) != loadInfo->Meta->FieldCount))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Incorrect number of fields in %s, expected %u, got %u",
+ source->GetFileName(), loadInfo->Meta->FieldCount, _header.TotalFieldCount + (loadInfo->Meta->ParentIndexField >= int32(_header.TotalFieldCount) ? 1 : 0)));
if (loadInfo && (_header.ParentLookupCount && loadInfo->Meta->ParentIndexField == -1))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unexpected parent lookup found in %s", source->GetFileName()));
std::unique_ptr<DB2SectionHeader[]> sections = std::make_unique<DB2SectionHeader[]>(_header.SectionCount);
if (_header.SectionCount && !source->Read(sections.get(), sizeof(DB2SectionHeader) * _header.SectionCount))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read section headers from %s", source->GetFileName()));
uint32 totalCopyTableSize = 0;
uint32 totalParentLookupDataSize = 0;
@@ -1742,9 +1747,9 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
sizeof(DB2Header) +
sizeof(DB2SectionHeader) * _header.SectionCount +
sizeof(DB2FieldEntry) * _header.FieldCount +
- _header.RecordCount * _header.RecordSize +
+ int64(_header.RecordSize) * _header.RecordCount +
_header.StringTableSize +
- (loadInfo->Meta->IndexField == -1 ? _header.RecordCount * sizeof(uint32) : 0) +
+ (loadInfo->Meta->IndexField == -1 ? sizeof(uint32) * _header.RecordCount : 0) +
totalCopyTableSize +
_header.ColumnMetaSize +
_header.PalletDataSize +
@@ -1752,12 +1757,12 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
totalParentLookupDataSize;
if (source->GetFileSize() != expectedFileSize)
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("%s failed size consistency check, expected " SZFMTD ", got " SZFMTD, expectedFileSize, source->GetFileSize()));
}
std::unique_ptr<DB2FieldEntry[]> fieldData = std::make_unique<DB2FieldEntry[]>(_header.FieldCount);
if (!source->Read(fieldData.get(), sizeof(DB2FieldEntry) * _header.FieldCount))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read field information from %s", source->GetFileName()));
std::unique_ptr<DB2ColumnMeta[]> columnMeta;
std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues;
@@ -1767,14 +1772,15 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
{
columnMeta = std::make_unique<DB2ColumnMeta[]>(_header.TotalFieldCount);
if (!source->Read(columnMeta.get(), _header.ColumnMetaSize))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read field metadata from %s", source->GetFileName()));
- if (loadInfo)
+ if (loadInfo && loadInfo->Meta->HasIndexFieldInData())
{
- ASSERT(!loadInfo->Meta->HasIndexFieldInData() ||
- columnMeta[loadInfo->Meta->IndexField].CompressionType == DB2ColumnCompression::None ||
- columnMeta[loadInfo->Meta->IndexField].CompressionType == DB2ColumnCompression::Immediate ||
- columnMeta[loadInfo->Meta->IndexField].CompressionType == DB2ColumnCompression::SignedImmediate);
+ if (columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::None
+ && columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::Immediate
+ && columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::SignedImmediate)
+ throw DB2FileLoadException(Trinity::StringFormat("Invalid compression type for index field in %s, expected one of None (0), Immediate (1), SignedImmediate (5), got %u",
+ source->GetFileName(), uint32(columnMeta[loadInfo->Meta->IndexField].CompressionType)));
}
palletValues = std::make_unique<std::unique_ptr<DB2PalletValue[]>[]>(_header.TotalFieldCount);
@@ -1785,7 +1791,7 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
palletValues[i] = std::make_unique<DB2PalletValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2PalletValue));
if (!source->Read(palletValues[i].get(), columnMeta[i].AdditionalDataSize))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read field pallet values from %s for field %u", source->GetFileName(), i));
}
palletArrayValues = std::make_unique<std::unique_ptr<DB2PalletValue[]>[]>(_header.TotalFieldCount);
@@ -1796,7 +1802,7 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
palletArrayValues[i] = std::make_unique<DB2PalletValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2PalletValue));
if (!source->Read(palletArrayValues[i].get(), columnMeta[i].AdditionalDataSize))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read field pallet array values from %s for field %u", source->GetFileName(), i));
}
std::unique_ptr<std::unique_ptr<DB2CommonValue[]>[]> commonData = std::make_unique<std::unique_ptr<DB2CommonValue[]>[]>(_header.TotalFieldCount);
@@ -1811,7 +1817,7 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
commonData[i] = std::make_unique<DB2CommonValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2CommonValue));
if (!source->Read(commonData[i].get(), columnMeta[i].AdditionalDataSize))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read field common values from %s for field %u", source->GetFileName(), i));
uint32 numExtraValuesForField = columnMeta[i].AdditionalDataSize / sizeof(DB2CommonValue);
for (uint32 record = 0; record < numExtraValuesForField; ++record)
@@ -1830,13 +1836,11 @@ bool DB2FileLoader::LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* lo
_impl = new DB2FileLoaderSparseImpl(source->GetFileName(), loadInfo, &_header, source);
_impl->LoadColumnData(std::move(sections), std::move(fieldData), std::move(columnMeta), std::move(palletValues), std::move(palletArrayValues), std::move(commonValues));
- return true;
}
-bool DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
+void DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
{
- if (!LoadHeaders(source, loadInfo))
- return false;
+ LoadHeaders(source, loadInfo);
std::vector<uint32> idTable;
std::vector<DB2RecordCopy> copyTable;
@@ -1872,18 +1876,24 @@ bool DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
}
if (!source->SetPosition(section.FileOffset))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to change %s read position for section %u", source->GetFileName(), i));
if (!_impl->LoadTableData(source, i))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read section table data from %s for section %u", source->GetFileName(), i));
if (!_impl->LoadCatalogData(source, i))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read section catalog data from %s for section %u", source->GetFileName(), i));
if (loadInfo)
{
- ASSERT(!loadInfo->Meta->HasIndexFieldInData() || section.IdTableSize == 0);
- ASSERT(loadInfo->Meta->HasIndexFieldInData() || section.IdTableSize == 4 * section.RecordCount);
+ if (loadInfo->Meta->HasIndexFieldInData())
+ {
+ if (section.IdTableSize != 0)
+ throw DB2FileLoadException(Trinity::StringFormat("Unexpected id table found in %s for section %u", source->GetFileName(), i));
+ }
+ else if (section.IdTableSize != 4 * section.RecordCount)
+ throw DB2FileLoadException(Trinity::StringFormat("Unexpected id table size in %s for section %u, expected %u, got %u",
+ source->GetFileName(), i, 4 * section.RecordCount, section.IdTableSize));
}
if (section.IdTableSize)
@@ -1891,7 +1901,7 @@ bool DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
std::size_t idTableSize = idTable.size();
idTable.resize(idTableSize + section.IdTableSize / sizeof(uint32));
if (!source->Read(&idTable[idTableSize], section.IdTableSize))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read non-inline record ids from %s for section %u", source->GetFileName(), i));
}
if (!(_header.Flags & 0x1) && section.CopyTableCount)
@@ -1899,7 +1909,7 @@ bool DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
std::size_t copyTableSize = copyTable.size();
copyTable.resize(copyTableSize + section.CopyTableCount);
if (!source->Read(&copyTable[copyTableSize], section.CopyTableCount * sizeof(DB2RecordCopy)))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read record copies from %s for section %u", source->GetFileName(), i));
}
if (_header.ParentLookupCount)
@@ -1909,14 +1919,14 @@ bool DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
{
DB2IndexDataInfo indexInfo;
if (!source->Read(&indexInfo, sizeof(DB2IndexDataInfo)))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read parent lookup info from %s for section %u", source->GetFileName(), i));
if (!indexInfo.NumEntries)
continue;
parentIndexesForSection[j].Entries.resize(indexInfo.NumEntries);
if (!source->Read(parentIndexesForSection[j].Entries.data(), sizeof(DB2IndexEntry) * indexInfo.NumEntries))
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("Unable to read parent lookup content from %s for section %u", source->GetFileName(), i));
}
}
}
@@ -1933,12 +1943,11 @@ bool DB2FileLoader::Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo)
}
for (uint32 f = 0; f < loadInfo->Meta->FieldCount; ++f)
{
- ASSERT(loadInfo->Fields[fieldIndex].IsSigned == _impl->IsSignedField(f), "Mismatched field signedness for field %u (%s) in %s", f, loadInfo->Fields[fieldIndex].Name, source->GetFileName());
+ ASSERT(loadInfo->Fields[fieldIndex].IsSigned == _impl->IsSignedField(f),
+ "Field %s in %s must be %s", loadInfo->Fields[fieldIndex].Name, source->GetFileName(), _impl->IsSignedField(f) ? "signed" : "unsigned");
fieldIndex += loadInfo->Meta->Fields[f].ArraySize;
}
}
-
- return true;
}
char* DB2FileLoader::AutoProduceData(uint32& indexTableSize, char**& indexTable)
diff --git a/src/common/DataStores/DB2FileLoader.h b/src/common/DataStores/DB2FileLoader.h
index 6f0bca5ee5b..72a5f66768d 100644
--- a/src/common/DataStores/DB2FileLoader.h
+++ b/src/common/DataStores/DB2FileLoader.h
@@ -19,6 +19,7 @@
#define DB2_FILE_LOADER_H
#include "Common.h"
+#include <exception>
#include <string>
#include <vector>
@@ -163,6 +164,17 @@ struct DB2RecordCopy
};
#pragma pack(pop)
+class TC_COMMON_API DB2FileLoadException : public std::exception
+{
+public:
+ DB2FileLoadException(std::string msg) : _msg(std::move(msg)) { }
+
+ char const* what() const noexcept override { return _msg.c_str(); }
+
+private:
+ std::string _msg;
+};
+
class TC_COMMON_API DB2FileLoader
{
public:
@@ -170,8 +182,8 @@ public:
~DB2FileLoader();
// loadInfo argument is required when trying to read data from the file
- bool LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* loadInfo);
- bool Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo);
+ void LoadHeaders(DB2FileSource* source, DB2FileLoadInfo const* loadInfo);
+ void Load(DB2FileSource* source, DB2FileLoadInfo const* loadInfo);
char* AutoProduceData(uint32& indexTableSize, char**& indexTable);
char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, LocaleConstant locale);
void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable);
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 85caeccd077..e37196cc3de 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -27,7 +27,9 @@
#include "Regex.h"
#include "Timer.h"
#include "Util.h"
+#include <boost/filesystem/operations.hpp>
#include <array>
+#include <bitset>
#include <numeric>
#include <sstream>
#include <cctype>
@@ -438,7 +440,7 @@ namespace
template<typename T>
constexpr std::size_t GetCppRecordSize(DB2Storage<T> const&) { return sizeof(T); }
-void LoadDB2(uint32& availableDb2Locales, std::vector<std::string>& errlist, StorageMap& stores, DB2StorageBase* storage, std::string const& db2Path,
+void LoadDB2(std::bitset<TOTAL_LOCALES>& availableDb2Locales, std::vector<std::string>& errlist, StorageMap& stores, DB2StorageBase* storage, std::string const& db2Path,
LocaleConstant defaultLocale, std::size_t cppRecordSize)
{
// validate structure
@@ -472,42 +474,53 @@ void LoadDB2(uint32& availableDb2Locales, std::vector<std::string>& errlist, Sto
storage->GetFileName().c_str(), loadInfo->Meta->GetRecordSize(), cppRecordSize);
}
- if (storage->Load(db2Path + localeNames[defaultLocale] + '/', defaultLocale))
+ try
{
- storage->LoadFromDB();
- // LoadFromDB() always loads strings into enUS locale, other locales are expected to have data in corresponding _locale tables
- // so we need to make additional call to load that data in case said locale is set as default by worldserver.conf (and we do not want to load all this data from .db2 file again)
- if (defaultLocale != LOCALE_enUS)
- storage->LoadStringsFromDB(defaultLocale);
-
- for (LocaleConstant i = LOCALE_enUS; i < TOTAL_LOCALES; i = LocaleConstant(i + 1))
+ storage->Load(db2Path + localeNames[defaultLocale] + '/', defaultLocale);
+ }
+ catch (std::system_error const& e)
+ {
+ if (e.code() == std::errc::no_such_file_or_directory)
{
- if (defaultLocale == i || i == LOCALE_none)
- continue;
-
- if (availableDb2Locales & (1 << i))
- if (!storage->LoadStringsFrom((db2Path + localeNames[i] + '/'), i))
- availableDb2Locales &= ~(1 << i); // mark as not available for speedup next checks
-
- storage->LoadStringsFromDB(i);
+ errlist.push_back(Trinity::StringFormat("File %s does not exist", db2Path + localeNames[defaultLocale] + '/' + storage->GetFileName()));
}
+ else
+ throw;
}
- else
+ catch (std::exception const& e)
{
- // sort problematic db2 to (1) non compatible and (2) nonexistent
- if (FILE* f = fopen((db2Path + localeNames[defaultLocale] + '/' + storage->GetFileName()).c_str(), "rb"))
+ errlist.emplace_back(e.what());
+ return;
+ }
+
+ // load additional data and enUS strings from db
+ storage->LoadFromDB();
+
+ for (LocaleConstant i = LOCALE_enUS; i < TOTAL_LOCALES; i = LocaleConstant(i + 1))
+ {
+ if (defaultLocale == i || !availableDb2Locales[i])
+ continue;
+
+ try
{
- std::ostringstream stream;
- stream << storage->GetFileName() << " exists, and has " << storage->GetFieldCount() << " field(s) (expected " << loadInfo->Meta->FieldCount
- << "). Extracted file might be from wrong client version.";
- std::string buf = stream.str();
- errlist.push_back(buf);
- fclose(f);
+ storage->LoadStringsFrom((db2Path + localeNames[i] + '/'), i);
+ }
+ catch (std::system_error const& e)
+ {
+ if (e.code() != std::errc::no_such_file_or_directory)
+ throw;
+
+ // locale db2 files are optional, do not error if nothing is found
+ }
+ catch (std::exception const& e)
+ {
+ errlist.emplace_back(e.what());
}
- else
- errlist.push_back(storage->GetFileName());
}
+ for (LocaleConstant i = LOCALE_koKR; i < TOTAL_LOCALES; i = LocaleConstant(i + 1))
+ storage->LoadStringsFromDB(i);
+
stores[storage->GetTableHash()] = storage;
}
@@ -517,16 +530,32 @@ DB2Manager& DB2Manager::Instance()
return instance;
}
-void DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaultLocale)
+uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaultLocale)
{
uint32 oldMSTime = getMSTime();
std::string db2Path = dataPath + "dbc/";
- std::vector<std::string> bad_db2_files;
- uint32 availableDb2Locales = 0xFF;
+ std::vector<std::string> loadErrors;
+ std::bitset<TOTAL_LOCALES> availableDb2Locales = [&]()
+ {
+ std::bitset<TOTAL_LOCALES> foundLocales;
+ boost::filesystem::directory_iterator db2PathItr(db2Path), end;
+ while (db2PathItr != end)
+ {
+ LocaleConstant locale = GetLocaleByName(db2PathItr->path().filename().string());
+ if (IsValidLocale(locale))
+ foundLocales[locale] = true;
-#define LOAD_DB2(store) LoadDB2(availableDb2Locales, bad_db2_files, _stores, &store, db2Path, defaultLocale, GetCppRecordSize(store))
+ ++db2PathItr;
+ }
+ return foundLocales;
+ }();
+
+ if (!availableDb2Locales[defaultLocale])
+ return 0;
+
+#define LOAD_DB2(store) LoadDB2(availableDb2Locales, loadErrors, _stores, &store, db2Path, defaultLocale, GetCppRecordSize(store))
LOAD_DB2(sAchievementStore);
LOAD_DB2(sAnimationDataStore);
@@ -783,6 +812,30 @@ void DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaultL
#undef LOAD_DB2
+ // error checks
+ if (!loadErrors.empty())
+ {
+ sLog->SetSynchronous(); // server will shut down after this, so set sync logging to prevent messages from getting lost
+
+ for (std::string const& error : loadErrors)
+ TC_LOG_ERROR("misc", "%s", error.c_str());
+
+ return 0;
+ }
+
+ // Check loaded DB2 files proper version
+ if (!sAreaTableStore.LookupEntry(13227) || // last area added in 8.3.0 (34769)
+ !sCharTitlesStore.LookupEntry(672) || // last char title added in 8.3.0 (34769)
+ !sGemPropertiesStore.LookupEntry(3802) || // last gem property added in 8.3.0 (34769)
+ !sItemStore.LookupEntry(175264) || // last item added in 8.3.0 (34769)
+ !sItemExtendedCostStore.LookupEntry(6716) || // last item extended cost added in 8.3.0 (34769)
+ !sMapStore.LookupEntry(2292) || // last map added in 8.3.0 (34769)
+ !sSpellNameStore.LookupEntry(319960)) // last spell added in 8.3.0 (34769)
+ {
+ TC_LOG_ERROR("misc", "You have _outdated_ DB2 files. Please extract correct versions from current using client.");
+ exit(1);
+ }
+
for (AreaGroupMemberEntry const* areaGroupMember : sAreaGroupMemberStore)
_areaGroupMembers[areaGroupMember->AreaGroupID].push_back(areaGroupMember->AreaID);
@@ -1322,36 +1375,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaultL
}
}
- // error checks
- if (bad_db2_files.size() == _stores.size())
- {
- TC_LOG_ERROR("misc", "\nIncorrect DataDir value in worldserver.conf or ALL required *.db2 files (" SZFMTD ") not found by path: %sdbc/%s/", _stores.size(), dataPath.c_str(), localeNames[defaultLocale]);
- exit(1);
- }
- else if (!bad_db2_files.empty())
- {
- std::string str;
- for (auto const& bad_db2_file : bad_db2_files)
- str += bad_db2_file + "\n";
-
- TC_LOG_ERROR("misc", "\nSome required *.db2 files (" SZFMTD " from " SZFMTD ") not found or not compatible:\n%s", bad_db2_files.size(), _stores.size(), str.c_str());
- exit(1);
- }
-
- // Check loaded DB2 files proper version
- if (!sAreaTableStore.LookupEntry(10521) || // last area added in 8.1.5 (30706)
- !sCharTitlesStore.LookupEntry(649) || // last char title added in 8.1.5 (30706)
- !sGemPropertiesStore.LookupEntry(3746) || // last gem property added in 8.1.5 (30706)
- !sItemStore.LookupEntry(168279) || // last item added in 8.1.5 (30706)
- !sItemExtendedCostStore.LookupEntry(6545) || // last item extended cost added in 8.1.5 (30706)
- !sMapStore.LookupEntry(2178) || // last map added in 8.1.5 (30706)
- !sSpellNameStore.LookupEntry(296952)) // last spell added in 8.1.5 (30706)
- {
- TC_LOG_ERROR("misc", "You have _outdated_ DB2 files. Please extract correct versions from current using client.");
- exit(1);
- }
-
TC_LOG_INFO("server.loading", ">> Initialized " SZFMTD " DB2 data stores in %u ms", _stores.size(), GetMSTimeDiffToNow(oldMSTime));
+
+ return availableDb2Locales.to_ulong();
}
DB2StorageBase const* DB2Manager::GetStorage(uint32 type) const
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index d33ba31ceac..95ac7eabf14 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -275,7 +275,7 @@ public:
static DB2Manager& Instance();
- void LoadStores(std::string const& dataPath, LocaleConstant defaultLocale);
+ uint32 LoadStores(std::string const& dataPath, LocaleConstant defaultLocale);
DB2StorageBase const* GetStorage(uint32 type) const;
void LoadHotfixData();
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
index 49f1b2b0083..0005eed85a7 100644
--- a/src/server/game/Maps/TransportMgr.h
+++ b/src/server/game/Maps/TransportMgr.h
@@ -102,8 +102,6 @@ typedef std::map<uint32, TransportAnimation> TransportAnimationContainer;
class TC_GAME_API TransportMgr
{
- friend void DB2Manager::LoadStores(std::string const&, LocaleConstant);
-
public:
static TransportMgr* instance();
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4567492bba0..3aa3fcde40b 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1571,7 +1571,13 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Initialize data stores...");
///- Load DB2s
- sDB2Manager.LoadStores(m_dataPath, m_defaultDbcLocale);
+ m_availableDbcLocaleMask = sDB2Manager.LoadStores(m_dataPath, m_defaultDbcLocale);
+ if (!(m_availableDbcLocaleMask & (1 << m_defaultDbcLocale)))
+ {
+ TC_LOG_FATAL("server.loading", "Unable to load db2 files for %s locale specified in DBC.Locale config!", localeNames[m_defaultDbcLocale]);
+ exit(1);
+ }
+
TC_LOG_INFO("misc", "Loading hotfix blobs...");
sDB2Manager.LoadHotfixBlob();
TC_LOG_INFO("misc", "Loading hotfix info...");
diff --git a/src/server/shared/DataStores/DB2Store.cpp b/src/server/shared/DataStores/DB2Store.cpp
index b33e050f644..bfa333ec448 100644
--- a/src/server/shared/DataStores/DB2Store.cpp
+++ b/src/server/shared/DataStores/DB2Store.cpp
@@ -20,6 +20,7 @@
#include "DB2DatabaseLoader.h"
#include "DB2FileSystemSource.h"
#include "DB2Meta.h"
+#include "StringFormat.h"
DB2StorageBase::DB2StorageBase(char const* fileName, DB2LoadInfo const* loadInfo)
: _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _loadInfo(loadInfo), _dataTable(nullptr), _dataTableEx(), _indexTableSize(0)
@@ -83,14 +84,13 @@ void DB2StorageBase::WriteRecordData(char const* entry, LocaleConstant locale, B
}
}
-bool DB2StorageBase::Load(std::string const& path, LocaleConstant locale, char**& indexTable)
+void DB2StorageBase::Load(std::string const& path, LocaleConstant 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;
+ db2.Load(&source, _loadInfo);
_fieldCount = db2.GetCols();
_tableHash = db2.GetTableHash();
@@ -98,37 +98,29 @@ bool DB2StorageBase::Load(std::string const& path, LocaleConstant locale, char**
// load raw non-string data
_dataTable = db2.AutoProduceData(_indexTableSize, indexTable);
- if (!_dataTable)
- return false;
// load strings from db2 data
if (char* stringBlock = db2.AutoProduceStrings(indexTable, _indexTableSize, 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, LocaleConstant locale, char** indexTable)
+void DB2StorageBase::LoadStringsFrom(std::string const& path, LocaleConstant locale, char** indexTable)
{
// DB2 must be already loaded using Load
if (!indexTable)
- return false;
+ throw DB2FileLoadException(Trinity::StringFormat("%s was not loaded properly, cannot load strings", path.c_str()));
DB2FileLoader db2;
DB2FileSystemSource source(path + _fileName);
// Check if load was successful, only then continue
- if (!db2.Load(&source, _loadInfo))
- return false;
+ db2.Load(&source, _loadInfo);
// load strings from another locale db2 data
if (_loadInfo->GetStringFieldCount(true))
if (char* stringBlock = db2.AutoProduceStrings(indexTable, _indexTableSize, locale))
_stringPool.push_back(stringBlock);
-
- return true;
}
void DB2StorageBase::LoadFromDB(char**& indexTable)
diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h
index c670d418b13..faf12428251 100644
--- a/src/server/shared/DataStores/DB2Store.h
+++ b/src/server/shared/DataStores/DB2Store.h
@@ -44,15 +44,15 @@ public:
uint32 GetFieldCount() const { return _fieldCount; }
DB2LoadInfo const* GetLoadInfo() const { return _loadInfo; }
- virtual bool Load(std::string const& path, LocaleConstant locale) = 0;
- virtual bool LoadStringsFrom(std::string const& path, LocaleConstant locale) = 0;
+ virtual void Load(std::string const& path, LocaleConstant locale) = 0;
+ virtual void LoadStringsFrom(std::string const& path, LocaleConstant locale) = 0;
virtual void LoadFromDB() = 0;
virtual void LoadStringsFromDB(LocaleConstant locale) = 0;
protected:
void WriteRecordData(char const* entry, LocaleConstant locale, ByteBuffer& buffer) const;
- bool Load(std::string const& path, LocaleConstant locale, char**& indexTable);
- bool LoadStringsFrom(std::string const& path, LocaleConstant locale, char** indexTable);
+ void Load(std::string const& path, LocaleConstant locale, char**& indexTable);
+ void LoadStringsFrom(std::string const& path, LocaleConstant locale, char** indexTable);
void LoadFromDB(char**& indexTable);
void LoadStringsFromDB(LocaleConstant locale, char** indexTable);
@@ -77,12 +77,12 @@ public:
DB2Storage(char const* fileName, DB2LoadInfo const* loadInfo) : DB2StorageBase(fileName, loadInfo)
{
- _indexTable.AsT = nullptr;
+ _indexTable.AsChar = nullptr;
}
~DB2Storage()
{
- delete[] reinterpret_cast<char*>(_indexTable.AsT);
+ delete[] _indexTable.AsChar;
}
bool HasRecord(uint32 id) const override { return id < _indexTableSize && _indexTable.AsT[id] != nullptr; }
@@ -98,12 +98,12 @@ public:
T const* operator[](uint32 id) const { return LookupEntry(id); }
uint32 GetNumRows() const { return _indexTableSize; }
- bool Load(std::string const& path, LocaleConstant locale) override
+ void Load(std::string const& path, LocaleConstant locale) override
{
return DB2StorageBase::Load(path, locale, _indexTable.AsChar);
}
- bool LoadStringsFrom(std::string const& path, LocaleConstant locale) override
+ void LoadStringsFrom(std::string const& path, LocaleConstant locale) override
{
return DB2StorageBase::LoadStringsFrom(path, locale, _indexTable.AsChar);
}
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp
index ecb4d00358e..8fb4e7f7a66 100644
--- a/src/tools/map_extractor/System.cpp
+++ b/src/tools/map_extractor/System.cpp
@@ -226,17 +226,26 @@ void HandleArgs(int argc, char* arg[])
}
}
+void TryLoadDB2(char const* name, DB2CascFileSource* source, DB2FileLoader* db2, DB2FileLoadInfo const* loadInfo)
+{
+ try
+ {
+ db2->Load(source, loadInfo);
+ }
+ catch (std::exception const& e)
+ {
+ printf("Fatal error: Invalid %s file format! %s\n%s\n", name, CASC::HumanReadableCASCError(GetLastError()), e.what());
+ exit(1);
+ }
+}
+
void ReadMapDBC()
{
printf("Read Map.db2 file...\n");
DB2CascFileSource source(CascStorage, MapLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, MapLoadInfo::Instance()))
- {
- printf("Fatal error: Invalid Map.db2 file format! %s\n", CASC::HumanReadableCASCError(GetLastError()));
- exit(1);
- }
+ TryLoadDB2("Map.db2", &source, &db2, MapLoadInfo::Instance());
map_ids.reserve(db2.GetRecordCount());
std::unordered_map<uint32, std::size_t> idToIndex;
@@ -281,11 +290,7 @@ void ReadLiquidMaterialTable()
DB2CascFileSource source(CascStorage, LiquidMaterialLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, LiquidMaterialLoadInfo::Instance()))
- {
- printf("Fatal error: Invalid LiquidMaterial.db2 file format!\n");
- exit(1);
- }
+ TryLoadDB2("LiquidMaterial.db2", &source, &db2, LiquidMaterialLoadInfo::Instance());
for (uint32 x = 0; x < db2.GetRecordCount(); ++x)
{
@@ -309,11 +314,7 @@ void ReadLiquidObjectTable()
DB2CascFileSource source(CascStorage, LiquidObjectLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, LiquidObjectLoadInfo::Instance()))
- {
- printf("Fatal error: Invalid LiquidObject.db2 file format!\n");
- exit(1);
- }
+ TryLoadDB2("LiquidObject.db2", &source, &db2, LiquidObjectLoadInfo::Instance());
for (uint32 x = 0; x < db2.GetRecordCount(); ++x)
{
@@ -337,11 +338,7 @@ void ReadLiquidTypeTable()
DB2CascFileSource source(CascStorage, LiquidTypeLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, LiquidTypeLoadInfo::Instance()))
- {
- printf("Fatal error: Invalid LiquidType.db2 file format!\n");
- exit(1);
- }
+ TryLoadDB2("LiquidType.db2", &source, &db2, LiquidTypeLoadInfo::Instance());
for (uint32 x = 0; x < db2.GetRecordCount(); ++x)
{
@@ -366,11 +363,7 @@ bool ReadCinematicCameraDBC()
DB2CascFileSource source(CascStorage, CinematicCameraLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, CinematicCameraLoadInfo::Instance()))
- {
- printf("Invalid CinematicCamera.db2 file format. Camera extract aborted. %s\n", CASC::HumanReadableCASCError(GetLastError()));
- return false;
- }
+ TryLoadDB2("CinematicCamera.db2", &source, &db2, CinematicCameraLoadInfo::Instance());
// get camera file list from DB2
for (size_t i = 0; i < db2.GetRecordCount(); ++i)
@@ -1223,9 +1216,13 @@ bool ExtractDB2File(uint32 fileDataId, char const* cascFileName, int locale, boo
}
DB2FileLoader db2;
- if (!db2.LoadHeaders(&source, nullptr))
+ try
+ {
+ db2.LoadHeaders(&source, nullptr);
+ }
+ catch (std::exception const& e)
{
- printf("Can't read DB2 headers of '%s'\n", cascFileName);
+ printf("Can't read DB2 headers of '%s': %s\n", cascFileName, e.what());
return false;
}
diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp
index 2acee4e3fbc..f9ba6a2cdb4 100644
--- a/src/tools/mmaps_generator/PathGenerator.cpp
+++ b/src/tools/mmaps_generator/PathGenerator.cpp
@@ -275,13 +275,14 @@ int finish(const char* message, int returnValue)
return returnValue;
}
-std::unordered_map<uint32, uint8> LoadLiquid(std::string const& locale)
+std::unordered_map<uint32, uint8> LoadLiquid(std::string const& locale, bool silent, int32 errorExitCode)
{
DB2FileLoader liquidDb2;
std::unordered_map<uint32, uint8> liquidData;
DB2FileSystemSource liquidTypeSource((boost::filesystem::path("dbc") / locale / "LiquidType.db2").string());
- if (liquidDb2.Load(&liquidTypeSource, LiquidTypeLoadInfo::Instance()))
+ try
{
+ liquidDb2.Load(&liquidTypeSource, LiquidTypeLoadInfo::Instance());
for (uint32 x = 0; x < liquidDb2.GetRecordCount(); ++x)
{
DB2Record record = liquidDb2.GetRecord(x);
@@ -291,17 +292,25 @@ std::unordered_map<uint32, uint8> LoadLiquid(std::string const& locale)
liquidData[record.GetId()] = record.GetUInt8("SoundBank");
}
}
+ catch (std::exception const& e)
+ {
+ if (silent)
+ exit(errorExitCode);
+
+ exit(finish(e.what(), errorExitCode));
+ }
return liquidData;
}
-std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& locale)
+std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& locale, bool silent, int32 errorExitCode)
{
DB2FileLoader mapDb2;
std::unordered_map<uint32, std::vector<uint32>> mapData;
DB2FileSystemSource mapSource((boost::filesystem::path("dbc") / locale / "Map.db2").string());
- if (mapDb2.Load(&mapSource, MapLoadInfo::Instance()))
+ try
{
+ mapDb2.Load(&mapSource, MapLoadInfo::Instance());
for (uint32 x = 0; x < mapDb2.GetRecordCount(); ++x)
{
DB2Record record = mapDb2.GetRecord(x);
@@ -314,6 +323,13 @@ std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& local
mapData[parentMapId].push_back(record.GetId());
}
}
+ catch (std::exception const& e)
+ {
+ if (silent)
+ exit(errorExitCode);
+
+ exit(finish(e.what(), errorExitCode));
+ }
return mapData;
}
@@ -360,13 +376,9 @@ int main(int argc, char** argv)
if (!checkDirectories(debugOutput, dbcLocales))
return silent ? -3 : finish("Press ENTER to close...", -3);
- _liquidTypes = LoadLiquid(dbcLocales[0]);
- if (_liquidTypes.empty())
- return silent ? -5 : finish("Failed to load LiquidType.db2", -5);
+ _liquidTypes = LoadLiquid(dbcLocales[0], silent, -5);
- std::unordered_map<uint32, std::vector<uint32>> mapData = LoadMap(dbcLocales[0]);
- if (mapData.empty())
- return silent ? -4 : finish("Failed to load Map.db2", -4);
+ std::unordered_map<uint32, std::vector<uint32>> mapData = LoadMap(dbcLocales[0], silent, -4);
static_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager())->InitializeThreadUnsafe(mapData);
static_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager())->GetLiquidFlagsPtr = [](uint32 liquidId) -> uint32
diff --git a/src/tools/vmap4_extractor/gameobject_extract.cpp b/src/tools/vmap4_extractor/gameobject_extract.cpp
index db31a26bc06..7247398dd43 100644
--- a/src/tools/vmap4_extractor/gameobject_extract.cpp
+++ b/src/tools/vmap4_extractor/gameobject_extract.cpp
@@ -80,9 +80,13 @@ void ExtractGameobjectModels()
DB2CascFileSource source(CascStorage, GameobjectDisplayInfoLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, GameobjectDisplayInfoLoadInfo::Instance()))
+ try
{
- printf("Fatal error: Invalid GameObjectDisplayInfo.db2 file format!\n");
+ db2.Load(&source, GameobjectDisplayInfoLoadInfo::Instance());
+ }
+ catch (std::exception const& e)
+ {
+ printf("Fatal error: Invalid GameObjectDisplayInfo.db2 file format!\n%s\n", e.what());
exit(1);
}
diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp
index 800819fa9af..3b4ac9aba25 100644
--- a/src/tools/vmap4_extractor/vmapexport.cpp
+++ b/src/tools/vmap4_extractor/vmapexport.cpp
@@ -478,9 +478,13 @@ int main(int argc, char ** argv)
DB2CascFileSource source(CascStorage, MapLoadInfo::Instance()->Meta->FileDataId);
DB2FileLoader db2;
- if (!db2.Load(&source, MapLoadInfo::Instance()))
+ try
{
- printf("Fatal error: Invalid Map.db2 file format! %s\n", CASC::HumanReadableCASCError(GetLastError()));
+ db2.Load(&source, MapLoadInfo::Instance());
+ }
+ catch (std::exception const& e)
+ {
+ printf("Fatal error: Invalid Map.db2 file format! %s\n%s\n", CASC::HumanReadableCASCError(GetLastError()), e.what());
exit(1);
}