Skip to content

Commit

Permalink
Core/DataStores: Implement optional data in hotfix packets
Browse files Browse the repository at this point in the history
Closes #25738
  • Loading branch information
Shauren committed Dec 20, 2020
1 parent 1561181 commit fbbf409
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 11 deletions.
15 changes: 15 additions & 0 deletions sql/updates/hotfixes/master/2020_12_20_00_hotfixes.sql
Original file line number Diff line number Diff line change
@@ -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 */;
98 changes: 95 additions & 3 deletions src/server/game/DataStores/DB2Stores.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}

Expand All @@ -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();
Expand All @@ -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();
Expand Down
10 changes: 9 additions & 1 deletion src/server/game/DataStores/DB2Stores.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ class TC_GAME_API DB2Manager
}
};

struct HotfixOptionalData
{
uint32 Key;
std::vector<uint8> Data;
};

using HotfixContainer = std::set<HotfixRecord>;

using ItemBonusList = std::vector<ItemBonusEntry const*>;
Expand All @@ -301,9 +307,11 @@ class TC_GAME_API DB2Manager

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;
Expand Down
27 changes: 20 additions & 7 deletions src/server/game/Handlers/HotfixHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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()))
Expand Down
2 changes: 2 additions & 0 deletions src/server/game/World/World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit fbbf409

Please sign in to comment.