aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/hotfixes/master/2020_12_20_00_hotfixes.sql15
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp98
-rw-r--r--src/server/game/DataStores/DB2Stores.h10
-rw-r--r--src/server/game/Handlers/HotfixHandler.cpp27
-rw-r--r--src/server/game/World/World.cpp2
5 files changed, 141 insertions, 11 deletions
diff --git a/sql/updates/hotfixes/master/2020_12_20_00_hotfixes.sql b/sql/updates/hotfixes/master/2020_12_20_00_hotfixes.sql
new file mode 100644
index 00000000000..dc939580db6
--- /dev/null
+++ b/sql/updates/hotfixes/master/2020_12_20_00_hotfixes.sql
@@ -0,0 +1,15 @@
+--
+-- Table structure for table `hotfix_optional_data`
+--
+DROP TABLE IF EXISTS `hotfix_optional_data`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `hotfix_optional_data` (
+ `TableHash` int(10) unsigned NOT NULL,
+ `RecordId` int(10) unsigned NOT NULL,
+ `locale` varchar(4) NOT NULL,
+ `Key` int(10) unsigned NOT NULL,
+ `Data` blob NOT NULL,
+ `VerifiedBuild` int(11) NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index d09920fb960..72b2967f832 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -361,6 +361,7 @@ typedef std::tuple<uint16, uint8, int32> WMOAreaTableKey;
typedef std::map<WMOAreaTableKey, WMOAreaTableEntry const*> WMOAreaTableLookupContainer;
typedef std::pair<uint32 /*tableHash*/, int32 /*recordId*/> HotfixBlobKey;
typedef std::map<HotfixBlobKey, std::vector<uint8>> HotfixBlobMap;
+using AllowedHotfixOptionalData = std::pair<uint32 /*optional data key*/, bool(*)(std::vector<uint8> const& data) /*validator*/>;
namespace
{
@@ -375,6 +376,8 @@ namespace
StorageMap _stores;
DB2Manager::HotfixContainer _hotfixData;
std::array<HotfixBlobMap, TOTAL_LOCALES> _hotfixBlob;
+ std::unordered_multimap<uint32 /*tableHash*/, AllowedHotfixOptionalData> _allowedHotfixOptionalData;
+ std::array<std::map<HotfixBlobKey, std::vector<DB2Manager::HotfixOptionalData>>, TOTAL_LOCALES> _hotfixOptionalData;
AreaGroupMemberContainer _areaGroupMembers;
ArtifactPowersContainer _artifactPowers;
@@ -1513,7 +1516,7 @@ void DB2Manager::LoadHotfixBlob(uint32 localeMask)
auto storeItr = _stores.find(tableHash);
if (storeItr != _stores.end())
{
- TC_LOG_ERROR("server.loading", "Table hash 0x%X points to a loaded DB2 store %s, fill related table instead of hotfix_blob",
+ TC_LOG_ERROR("sql.sql", "Table hash 0x%X points to a loaded DB2 store %s, fill related table instead of hotfix_blob",
tableHash, storeItr->second->GetFileName().c_str());
continue;
}
@@ -1524,7 +1527,7 @@ void DB2Manager::LoadHotfixBlob(uint32 localeMask)
if (!IsValidLocale(locale))
{
- TC_LOG_ERROR("server.loading", "`hotfix_blob` contains invalid locale: %s at TableHash: 0x%X and RecordID: %d", localeName.c_str(), tableHash, recordId);
+ TC_LOG_ERROR("sql.sql", "`hotfix_blob` contains invalid locale: %s at TableHash: 0x%X and RecordID: %d", localeName.c_str(), tableHash, recordId);
continue;
}
@@ -1538,6 +1541,88 @@ void DB2Manager::LoadHotfixBlob(uint32 localeMask)
TC_LOG_INFO("server.loading", ">> Loaded %d hotfix blob records in %u ms", hotfixBlobCount, GetMSTimeDiffToNow(oldMSTime));
}
+bool ValidateBroadcastTextTactKeyOptionalData(std::vector<uint8> const& data)
+{
+ return data.size() == 8 + 16;
+}
+
+void DB2Manager::LoadHotfixOptionalData(uint32 localeMask)
+{
+ // Register allowed optional data keys
+ _allowedHotfixOptionalData.emplace(sBroadcastTextStore.GetTableHash(), std::make_pair(sTactKeyStore.GetTableHash(), &ValidateBroadcastTextTactKeyOptionalData));
+
+ uint32 oldMSTime = getMSTime();
+
+ QueryResult result = HotfixDatabase.Query("SELECT TableHash, RecordId, locale, `Key`, `Data` FROM hotfix_optional_data ORDER BY TableHash");
+
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 hotfix optional data records.");
+ return;
+ }
+
+ std::bitset<TOTAL_LOCALES> availableDb2Locales = localeMask;
+ uint32 hotfixOptionalDataCount = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 tableHash = fields[0].GetUInt32();
+ auto allowedHotfixes = Trinity::Containers::MapEqualRange(_allowedHotfixOptionalData, tableHash);
+ if (allowedHotfixes.begin() == allowedHotfixes.end())
+ {
+ TC_LOG_ERROR("sql.sql", "Table `hotfix_optional_data` references DB2 store by hash 0x%X that is not allowed to have optional data", tableHash);
+ continue;
+ }
+
+ uint32 recordId = fields[1].GetInt32();
+ auto storeItr = _stores.find(tableHash);
+ if (storeItr == _stores.end())
+ {
+ TC_LOG_ERROR("sql.sql", "Table `hotfix_optional_data` references unknown DB2 store by hash 0x%X with RecordID: %u", tableHash, recordId);
+ continue;
+ }
+
+ std::string localeName = fields[2].GetString();
+ LocaleConstant locale = GetLocaleByName(localeName);
+
+ if (!IsValidLocale(locale))
+ {
+ TC_LOG_ERROR("sql.sql", "`hotfix_optional_data` contains invalid locale: %s at TableHash: 0x%X and RecordID: %u", localeName.c_str(), tableHash, recordId);
+ continue;
+ }
+
+ if (!availableDb2Locales[locale])
+ continue;
+
+ DB2Manager::HotfixOptionalData optionalData;
+ optionalData.Key = fields[3].GetUInt32();
+ auto allowedHotfixItr = std::find_if(allowedHotfixes.begin(), allowedHotfixes.end(), [&](std::pair<uint32 const, AllowedHotfixOptionalData> const& v)
+ {
+ return v.second.first == optionalData.Key;
+ });
+ if (allowedHotfixItr == allowedHotfixes.end())
+ {
+ TC_LOG_ERROR("sql.sql", "Table `hotfix_optional_data` references non-allowed optional data key 0x%X for DB2 store by hash 0x%X and RecordID: %u",
+ optionalData.Key, tableHash, recordId);
+ continue;
+ }
+
+ optionalData.Data = fields[4].GetBinary();
+ if (!allowedHotfixItr->second.second(optionalData.Data))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `hotfix_optional_data` contains invalid data for DB2 store 0x%X, RecordID: %u and Key: 0x%X",
+ tableHash, recordId, optionalData.Key);
+ continue;
+ }
+
+ _hotfixOptionalData[locale][std::make_pair(tableHash, recordId)].push_back(std::move(optionalData));
+ hotfixOptionalDataCount++;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %d hotfix optional data records in %u ms", hotfixOptionalDataCount, GetMSTimeDiffToNow(oldMSTime));
+}
+
uint32 DB2Manager::GetHotfixCount() const
{
return _hotfixData.size();
@@ -1548,13 +1633,20 @@ DB2Manager::HotfixContainer const& DB2Manager::GetHotfixData() const
return _hotfixData;
}
-std::vector<uint8> const* DB2Manager::GetHotfixBlobData(uint32 tableHash, int32 recordId, LocaleConstant locale)
+std::vector<uint8> const* DB2Manager::GetHotfixBlobData(uint32 tableHash, int32 recordId, LocaleConstant locale) const
{
ASSERT(IsValidLocale(locale), "Locale %u is invalid locale", uint32(locale));
return Trinity::Containers::MapGetValuePtr(_hotfixBlob[locale], std::make_pair(tableHash, recordId));
}
+std::vector<DB2Manager::HotfixOptionalData> const* DB2Manager::GetHotfixOptionalData(uint32 tableHash, int32 recordId, LocaleConstant locale) const
+{
+ ASSERT(IsValidLocale(locale), "Locale %u is invalid locale", uint32(locale));
+
+ return Trinity::Containers::MapGetValuePtr(_hotfixOptionalData[locale], std::make_pair(tableHash, recordId));
+}
+
uint32 DB2Manager::GetEmptyAnimStateID() const
{
return sAnimationDataStore.GetNumRows();
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index d20c58b9dd1..69acbe8ef2a 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -287,6 +287,12 @@ public:
}
};
+ struct HotfixOptionalData
+ {
+ uint32 Key;
+ std::vector<uint8> Data;
+ };
+
using HotfixContainer = std::set<HotfixRecord>;
using ItemBonusList = std::vector<ItemBonusEntry const*>;
@@ -301,9 +307,11 @@ public:
void LoadHotfixData();
void LoadHotfixBlob(uint32 localeMask);
+ void LoadHotfixOptionalData(uint32 localeMask);
uint32 GetHotfixCount() const;
HotfixContainer const& GetHotfixData() const;
- std::vector<uint8> const* GetHotfixBlobData(uint32 tableHash, int32 recordId, LocaleConstant locale);
+ std::vector<uint8> const* GetHotfixBlobData(uint32 tableHash, int32 recordId, LocaleConstant locale) const;
+ std::vector<HotfixOptionalData> const* GetHotfixOptionalData(uint32 tableHash, int32 recordId, LocaleConstant locale) const;
uint32 GetEmptyAnimStateID() const;
std::vector<uint32> GetAreasForGroup(uint32 areaGroupId) const;
diff --git a/src/server/game/Handlers/HotfixHandler.cpp b/src/server/game/Handlers/HotfixHandler.cpp
index 85880fd0786..c1a200b616e 100644
--- a/src/server/game/Handlers/HotfixHandler.cpp
+++ b/src/server/game/Handlers/HotfixHandler.cpp
@@ -28,23 +28,26 @@
void WorldSession::HandleDBQueryBulk(WorldPackets::Hotfix::DBQueryBulk& dbQuery)
{
DB2StorageBase const* store = sDB2Manager.GetStorage(dbQuery.TableHash);
- if (!store)
- {
- TC_LOG_ERROR("network", "CMSG_DB_QUERY_BULK: %s requested unsupported unknown hotfix type: %u", GetPlayerInfo().c_str(), dbQuery.TableHash);
- return;
- }
-
for (WorldPackets::Hotfix::DBQueryBulk::DBQueryRecord const& record : dbQuery.Queries)
{
WorldPackets::Hotfix::DBReply dbReply;
dbReply.TableHash = dbQuery.TableHash;
dbReply.RecordID = record.RecordID;
- if (store->HasRecord(record.RecordID))
+ if (store && store->HasRecord(record.RecordID))
{
dbReply.Status = 1;
dbReply.Timestamp = GameTime::GetGameTime();
store->WriteRecord(record.RecordID, GetSessionDbcLocale(), dbReply.Data);
+
+ if (std::vector<DB2Manager::HotfixOptionalData> const* optionalDataEntries = sDB2Manager.GetHotfixOptionalData(dbQuery.TableHash, record.RecordID, GetSessionDbcLocale()))
+ {
+ for (DB2Manager::HotfixOptionalData const& optionalData : *optionalDataEntries)
+ {
+ dbReply.Data << uint32(optionalData.Key);
+ dbReply.Data.append(optionalData.Data.data(), optionalData.Data.size());
+ }
+ }
}
else
{
@@ -78,6 +81,16 @@ void WorldSession::HandleHotfixRequest(WorldPackets::Hotfix::HotfixRequest& hotf
{
std::size_t pos = hotfixQueryResponse.HotfixContent.size();
storage->WriteRecord(uint32(hotfixRecord.RecordID), GetSessionDbcLocale(), hotfixQueryResponse.HotfixContent);
+
+ if (std::vector<DB2Manager::HotfixOptionalData> const* optionalDataEntries = sDB2Manager.GetHotfixOptionalData(hotfixRecord.TableHash, hotfixRecord.RecordID, GetSessionDbcLocale()))
+ {
+ for (DB2Manager::HotfixOptionalData const& optionalData : *optionalDataEntries)
+ {
+ hotfixQueryResponse.HotfixContent << uint32(optionalData.Key);
+ hotfixQueryResponse.HotfixContent.append(optionalData.Data.data(), optionalData.Data.size());
+ }
+ }
+
hotfixData.Size = hotfixQueryResponse.HotfixContent.size() - pos;
}
else if (std::vector<uint8> const* blobData = sDB2Manager.GetHotfixBlobData(hotfixRecord.TableHash, hotfixRecord.RecordID, GetSessionDbcLocale()))
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index b182464c063..c5c47857409 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1667,6 +1667,8 @@ void World::SetInitialWorldSettings()
sDB2Manager.LoadHotfixBlob(m_availableDbcLocaleMask);
TC_LOG_INFO("misc", "Loading hotfix info...");
sDB2Manager.LoadHotfixData();
+ TC_LOG_INFO("misc", "Loading hotfix optional data...");
+ sDB2Manager.LoadHotfixOptionalData(m_availableDbcLocaleMask);
///- Close hotfix database - it is only used during DB2 loading
HotfixDatabase.Close();
///- Load M2 fly by cameras