diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-08-18 18:59:58 +0200 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2024-08-18 20:39:21 +0200 |
commit | 25ffdbc5ef0859aeaadfa132329a498e86827e68 (patch) | |
tree | d7df51da8cdc3e3df7c50e5058803f9324715ee4 /src/server/shared | |
parent | 0c98004896cb91ef2d22baa5569ff0e0d6cd15ee (diff) |
Core/Realms: Realmlist refactors
* Removed global realm variable from World and use RealmList everywhere
* Match auth build key with client version
* Restored allowedSecurityLevel checks for realmlist packet building
* Restored updating population field, mysteriously removed 15 years ago in f20b25d1c90f608deab28c9957b3b376ab2a0d50
(cherry picked from commit c4b710446d62c95eb8124175203fa5f394912594)
# Conflicts:
# sql/base/auth_database.sql
Diffstat (limited to 'src/server/shared')
-rw-r--r-- | src/server/shared/Realm/Realm.h | 64 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.cpp | 341 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.h | 29 |
3 files changed, 244 insertions, 190 deletions
diff --git a/src/server/shared/Realm/Realm.h b/src/server/shared/Realm/Realm.h index 45a07ebaa52..e44ff308c4f 100644 --- a/src/server/shared/Realm/Realm.h +++ b/src/server/shared/Realm/Realm.h @@ -18,12 +18,42 @@ #ifndef Realm_h__ #define Realm_h__ -#include "Common.h" #include "AsioHacksFwd.h" +#include "Common.h" +#include "EnumFlag.h" #include <compare> #include <vector> -enum RealmFlags +enum class RealmFlags : uint8 +{ + None = 0x00, + VersionMismatch = 0x01, + Hidden = 0x02, + Tournament = 0x04, + VersionBelow = 0x08, + VersionAbove = 0x10, + MobileVersionMismatch = 0x20, + MobileVersionBelow = 0x40, + MobileVersionAbove = 0x80 +}; + +DEFINE_ENUM_FLAG(RealmFlags); + +enum class RealmPopulationState : uint8 +{ + Offline = 0, + Low = 1, + Medium = 2, + High = 3, + New = 4, + Recommended = 5, + Full = 6, + Locked = 7 +}; + +namespace Trinity::Legacy +{ +enum RealmFlags : uint8 { REALM_FLAG_NONE = 0x00, REALM_FLAG_VERSION_MISMATCH = 0x01, @@ -36,6 +66,34 @@ enum RealmFlags REALM_FLAG_FULL = 0x80 }; +inline constexpr uint8 format_as(RealmFlags e) { return uint8(e); } + +inline constexpr ::RealmFlags ConvertLegacyRealmFlags(RealmFlags legacyRealmFlags) +{ + ::RealmFlags realmFlags = ::RealmFlags::None; + if (legacyRealmFlags & REALM_FLAG_VERSION_MISMATCH) + realmFlags |= ::RealmFlags::VersionMismatch; + return realmFlags; +} + +inline constexpr RealmPopulationState ConvertLegacyPopulationState(RealmFlags legacyRealmFlags, float population) +{ + if (legacyRealmFlags & REALM_FLAG_OFFLINE) + return RealmPopulationState::Offline; + if (legacyRealmFlags & REALM_FLAG_RECOMMENDED) + return RealmPopulationState::Recommended; + if (legacyRealmFlags & REALM_FLAG_NEW) + return RealmPopulationState::New; + if (legacyRealmFlags & REALM_FLAG_FULL || population > 0.95f) + return RealmPopulationState::Full; + if (population > 0.66f) + return RealmPopulationState::High; + if (population > 0.33f) + return RealmPopulationState::Medium; + return RealmPopulationState::Low; +} +} + namespace Battlenet { struct TC_SHARED_API RealmHandle @@ -89,7 +147,7 @@ struct TC_SHARED_API Realm RealmFlags Flags; uint8 Timezone; AccountTypes AllowedSecurityLevel; - float PopulationLevel; + RealmPopulationState PopulationLevel; void SetName(std::string name); diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index d4a9938476b..2568a859f88 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -20,8 +20,6 @@ #include "CryptoRandom.h" #include "DatabaseEnv.h" #include "DeadlineTimer.h" -#include "Errors.h" -#include "IoContext.h" #include "Log.h" #include "MapUtils.h" #include "ProtobufJSON.h" @@ -32,6 +30,26 @@ #include <boost/asio/ip/tcp.hpp> #include <zlib.h> +namespace +{ +bool CompressJson(std::string const& json, std::vector<uint8>* compressed) +{ + uLong uncompressedLength = uLong(json.length() + 1); + uLong compressedLength = compressBound(uLong(json.length())); + compressed->resize(compressedLength + 4); + memcpy(compressed->data(), &uncompressedLength, sizeof(uncompressedLength)); + + if (compress(compressed->data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.data()), uncompressedLength) != Z_OK) + { + compressed->clear(); + return false; + } + + compressed->resize(compressedLength + 4); // trim excess bytes + return true; +} +} + RealmList::RealmList() : _updateInterval(0) { } @@ -76,18 +94,22 @@ void RealmList::LoadBuildInfo() build.BugfixVersion = fields[2].GetUInt32(); std::string hotfixVersion = fields[3].GetString(); if (hotfixVersion.length() < build.HotfixVersion.size()) - std::copy(hotfixVersion.begin(), hotfixVersion.end(), build.HotfixVersion.begin()); + std::ranges::copy(hotfixVersion, build.HotfixVersion.begin()); else - std::fill(hotfixVersion.begin(), hotfixVersion.end(), '\0'); + build.HotfixVersion = { }; build.Build = fields[4].GetUInt32(); std::string win64AuthSeedHexStr = fields[5].GetString(); if (win64AuthSeedHexStr.length() == build.Win64AuthSeed.size() * 2) HexStrToByteArray(win64AuthSeedHexStr, build.Win64AuthSeed); + else + build.Win64AuthSeed = { }; std::string mac64AuthSeedHexStr = fields[6].GetString(); if (mac64AuthSeedHexStr.length() == build.Mac64AuthSeed.size() * 2) HexStrToByteArray(mac64AuthSeedHexStr, build.Mac64AuthSeed); + else + build.Mac64AuthSeed = { }; } while (result->NextRow()); } @@ -96,7 +118,7 @@ void RealmList::LoadBuildInfo() void RealmList::UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name, boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, - float population) + RealmPopulationState population) { realm.Id = id; realm.Build = build; @@ -122,7 +144,7 @@ void RealmList::UpdateRealms() std::map<Battlenet::RealmHandle, std::string> existingRealms; for (auto const& p : _realms) - existingRealms[p.first] = p.second.Name; + existingRealms[p.first] = p.second->Name; std::unordered_set<std::string> newSubRegions; RealmMap newRealms; @@ -132,61 +154,51 @@ void RealmList::UpdateRealms() { do { - try + Field* fields = result->Fetch(); + uint32 realmId = fields[0].GetUInt32(); + std::string name = fields[1].GetString(); + std::string externalAddressString = fields[2].GetString(); + std::string localAddressString = fields[3].GetString(); + + Optional<boost::asio::ip::tcp::endpoint> externalAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), externalAddressString, ""); + if (!externalAddress) { - Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - std::string externalAddressString = fields[2].GetString(); - std::string localAddressString = fields[3].GetString(); - - Optional<boost::asio::ip::tcp::endpoint> externalAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), externalAddressString, ""); - if (!externalAddress) - { - TC_LOG_ERROR("realmlist", "Could not resolve address {} for realm \"{}\" id {}", externalAddressString, name, realmId); - continue; - } - - Optional<boost::asio::ip::tcp::endpoint> localAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), localAddressString, ""); - if (!localAddress) - { - TC_LOG_ERROR("realmlist", "Could not resolve localAddress {} for realm \"{}\" id {}", localAddressString, name, realmId); - continue; - } - - uint16 port = fields[4].GetUInt16(); - uint8 icon = fields[5].GetUInt8(); - if (icon == REALM_TYPE_FFA_PVP) - icon = REALM_TYPE_PVP; - if (icon >= MAX_CLIENT_REALM_TYPE) - icon = REALM_TYPE_NORMAL; - RealmFlags flag = RealmFlags(fields[6].GetUInt8()); - uint8 timezone = fields[7].GetUInt8(); - uint8 allowedSecurityLevel = fields[8].GetUInt8(); - float pop = fields[9].GetFloat(); - uint32 build = fields[10].GetUInt32(); - uint8 region = fields[11].GetUInt8(); - uint8 battlegroup = fields[12].GetUInt8(); - - Battlenet::RealmHandle id{ region, battlegroup, realmId }; - - UpdateRealm(newRealms[id], id, build, name, externalAddress->address(), localAddress->address(), port, icon, - flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); - - newSubRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString()); - - if (!existingRealms.count(id)) - TC_LOG_INFO("realmlist", "Added realm \"{}\" at {}:{}.", name, externalAddressString, port); - else - TC_LOG_DEBUG("realmlist", "Updating realm \"{}\" at {}:{}.", name, externalAddressString, port); - - existingRealms.erase(id); + TC_LOG_ERROR("realmlist", "Could not resolve address {} for realm \"{}\" id {}", externalAddressString, name, realmId); + continue; } - catch (std::exception& ex) + + Optional<boost::asio::ip::tcp::endpoint> localAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), localAddressString, ""); + if (!localAddress) { - TC_LOG_ERROR("realmlist", "Realmlist::UpdateRealms has thrown an exception: {}", ex.what()); - ABORT(); + TC_LOG_ERROR("realmlist", "Could not resolve localAddress {} for realm \"{}\" id {}", localAddressString, name, realmId); + continue; } + + uint16 port = fields[4].GetUInt16(); + uint8 icon = fields[5].GetUInt8(); + if (icon == REALM_TYPE_FFA_PVP) + icon = REALM_TYPE_PVP; + if (icon >= MAX_CLIENT_REALM_TYPE) + icon = REALM_TYPE_NORMAL; + RealmFlags flag = ConvertLegacyRealmFlags(Trinity::Legacy::RealmFlags(fields[6].GetUInt8())); + uint8 timezone = fields[7].GetUInt8(); + uint8 allowedSecurityLevel = fields[8].GetUInt8(); + RealmPopulationState pop = ConvertLegacyPopulationState(Trinity::Legacy::RealmFlags(fields[6].GetUInt8()), fields[9].GetFloat()); + uint32 build = fields[10].GetUInt32(); + uint8 region = fields[11].GetUInt8(); + uint8 battlegroup = fields[12].GetUInt8(); + + Battlenet::RealmHandle id{ region, battlegroup, realmId }; + + UpdateRealm(*newRealms.try_emplace(id, std::make_shared<Realm>()).first->second, id, build, name, externalAddress->address(), localAddress->address(), port, icon, + flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); + + newSubRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString()); + + if (!existingRealms.erase(id)) + TC_LOG_INFO("realmlist", "Added realm \"{}\" at {}:{}.", name, externalAddressString, port); + else + TC_LOG_DEBUG("realmlist", "Updating realm \"{}\" at {}:{}.", name, externalAddressString, port); } while (result->NextRow()); } @@ -199,6 +211,11 @@ void RealmList::UpdateRealms() _subRegions.swap(newSubRegions); _realms.swap(newRealms); + _removedRealms.swap(existingRealms); + + if (_currentRealmId) + if (std::shared_ptr<Realm> realm = Trinity::Containers::MapGetValuePtr(_realms, *_currentRealmId)) + _currentRealmId = realm->Id; // fill other fields of realm id } if (_updateInterval) @@ -214,39 +231,38 @@ void RealmList::UpdateRealms() } } -Realm const* RealmList::GetRealm(Battlenet::RealmHandle const& id) const +std::shared_ptr<Realm const> RealmList::GetRealm(Battlenet::RealmHandle const& id) const { std::shared_lock<std::shared_mutex> lock(_realmsMutex); return Trinity::Containers::MapGetValuePtr(_realms, id); } -bool RealmList::GetRealmNames(Battlenet::RealmHandle const& id, std::string* name, std::string* normalizedName) const +Battlenet::RealmHandle RealmList::GetCurrentRealmId() const { - std::shared_lock<std::shared_mutex> lock(_realmsMutex); - Realm const* realm = Trinity::Containers::MapGetValuePtr(_realms, id); - if (!realm) - return false; - - *name = realm->Name; - *normalizedName = realm->NormalizedName; - return true; + return _currentRealmId ? *_currentRealmId : Battlenet::RealmHandle(); } -RealmBuildInfo const* RealmList::GetBuildInfo(uint32 build) const +void RealmList::SetCurrentRealmId(Battlenet::RealmHandle const& id) { - for (RealmBuildInfo const& clientBuild : _builds) - if (clientBuild.Build == build) - return &clientBuild; + _currentRealmId = id; +} +std::shared_ptr<Realm const> RealmList::GetCurrentRealm() const +{ + if (_currentRealmId) + return GetRealm(*_currentRealmId); return nullptr; } +RealmBuildInfo const* RealmList::GetBuildInfo(uint32 build) const +{ + auto buildInfo = std::ranges::find(_builds, build, &RealmBuildInfo::Build); + return buildInfo != _builds.end() ? &*buildInfo : nullptr; +} + uint32 RealmList::GetMinorMajorBugfixVersionForBuild(uint32 build) const { - auto buildInfo = std::lower_bound(_builds.begin(), _builds.end(), build, [](RealmBuildInfo const& buildInfo, uint32 value) - { - return buildInfo.Build < value; - }); + auto buildInfo = std::ranges::lower_bound(_builds, build, {}, &RealmBuildInfo::Build); return buildInfo != _builds.end() ? (buildInfo->MajorVersion * 10000 + buildInfo->MinorVersion * 100 + buildInfo->BugfixVersion) : 0; } @@ -257,127 +273,101 @@ void RealmList::WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesF response->add_attribute_value()->set_string_value(subRegion); } -std::vector<uint8> RealmList::GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const +void RealmList::FillRealmEntry(Realm const& realm, uint32 clientBuild, AccountTypes accountSecurityLevel, JSON::RealmList::RealmEntry* realmEntry) const { - std::vector<uint8> compressed; - std::shared_lock<std::shared_mutex> lock(_realmsMutex); - if (Realm const* realm = GetRealm(id)) - { - if (!(realm->Flags & REALM_FLAG_OFFLINE) && realm->Build == build) - { - JSON::RealmList::RealmEntry realmEntry; - realmEntry.set_wowrealmaddress(realm->Id.GetAddress()); - realmEntry.set_cfgtimezonesid(1); - realmEntry.set_populationstate(std::max(uint32(realm->PopulationLevel), 1u)); - realmEntry.set_cfgcategoriesid(realm->Timezone); + realmEntry->set_wowrealmaddress(realm.Id.GetAddress()); + realmEntry->set_cfgtimezonesid(1); + if (accountSecurityLevel >= realm.AllowedSecurityLevel || realm.PopulationLevel == RealmPopulationState::Offline) + realmEntry->set_populationstate(AsUnderlyingType(realm.PopulationLevel)); + else + realmEntry->set_populationstate(AsUnderlyingType(RealmPopulationState::Locked)); - JSON::RealmList::ClientVersion* version = realmEntry.mutable_version(); - if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm->Build)) - { - version->set_versionmajor(buildInfo->MajorVersion); - version->set_versionminor(buildInfo->MinorVersion); - version->set_versionrevision(buildInfo->BugfixVersion); - version->set_versionbuild(buildInfo->Build); - } - else - { - version->set_versionmajor(6); - version->set_versionminor(2); - version->set_versionrevision(4); - version->set_versionbuild(realm->Build); - } + realmEntry->set_cfgcategoriesid(realm.Timezone); - realmEntry.set_cfgrealmsid(realm->Id.Realm); - realmEntry.set_flags(realm->Flags); - realmEntry.set_name(realm->Name); - realmEntry.set_cfgconfigsid(realm->GetConfigId()); - realmEntry.set_cfglanguagesid(1); + JSON::RealmList::ClientVersion* version = realmEntry->mutable_version(); + if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm.Build)) + { + version->set_versionmajor(buildInfo->MajorVersion); + version->set_versionminor(buildInfo->MinorVersion); + version->set_versionrevision(buildInfo->BugfixVersion); + version->set_versionbuild(buildInfo->Build); + } + else + { + version->set_versionmajor(6); + version->set_versionminor(2); + version->set_versionrevision(4); + version->set_versionbuild(realm.Build); + } - lock.unlock(); + RealmFlags flag = realm.Flags; + if (realm.Build != clientBuild) + flag |= RealmFlags::VersionMismatch; - std::string json = "JamJSONRealmEntry:" + JSON::Serialize(realmEntry); + realmEntry->set_cfgrealmsid(realm.Id.Realm); + realmEntry->set_flags(AsUnderlyingType(flag)); + realmEntry->set_name(realm.Name); + realmEntry->set_cfgconfigsid(realm.GetConfigId()); + realmEntry->set_cfglanguagesid(1); +} - uLong compressedLength = compressBound(uLong(json.length())); - compressed.resize(compressedLength + 4); - *reinterpret_cast<uint32*>(compressed.data()) = uint32(json.length() + 1); +std::vector<uint8> RealmList::GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build, AccountTypes accountSecurityLevel) const +{ + std::vector<uint8> compressed; + if (std::shared_ptr<Realm const> realm = GetRealm(id)) + { + if (realm->PopulationLevel != RealmPopulationState::Offline && realm->Build == build && accountSecurityLevel >= realm->AllowedSecurityLevel) + { + JSON::RealmList::RealmEntry realmEntry; + FillRealmEntry(*realm, build, accountSecurityLevel, &realmEntry); - if (compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), uLong(json.length() + 1)) == Z_OK) - compressed.resize(compressedLength + 4); - else - compressed.clear(); + std::string json = "JamJSONRealmEntry:" + JSON::Serialize(realmEntry); + CompressJson(json, &compressed); } } return compressed; } -std::vector<uint8> RealmList::GetRealmList(uint32 build, std::string const& subRegion) const +std::vector<uint8> RealmList::GetRealmList(uint32 build, AccountTypes accountSecurityLevel, std::string const& subRegion) const { JSON::RealmList::RealmListUpdates realmList; { std::shared_lock<std::shared_mutex> lock(_realmsMutex); - for (auto const& realm : _realms) + for (auto const& [_, realm] : _realms) { - if (realm.second.Id.GetSubRegionAddress() != subRegion) + if (realm->Id.GetSubRegionAddress() != subRegion) continue; - uint32 flag = realm.second.Flags; - if (realm.second.Build != build) - flag |= REALM_FLAG_VERSION_MISMATCH; - - JSON::RealmList::RealmState* state = realmList.add_updates(); - state->mutable_update()->set_wowrealmaddress(realm.second.Id.GetAddress()); - state->mutable_update()->set_cfgtimezonesid(1); - state->mutable_update()->set_populationstate((realm.second.Flags & REALM_FLAG_OFFLINE) ? 0u : std::max(uint32(realm.second.PopulationLevel), 1u)); - state->mutable_update()->set_cfgcategoriesid(realm.second.Timezone); - - JSON::RealmList::ClientVersion* version = state->mutable_update()->mutable_version(); - if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm.second.Build)) - { - version->set_versionmajor(buildInfo->MajorVersion); - version->set_versionminor(buildInfo->MinorVersion); - version->set_versionrevision(buildInfo->BugfixVersion); - version->set_versionbuild(buildInfo->Build); - } - else - { - version->set_versionmajor(6); - version->set_versionminor(2); - version->set_versionrevision(4); - version->set_versionbuild(realm.second.Build); - } + JSON::RealmList::RealmListUpdatePart* state = realmList.add_updates(); + FillRealmEntry(*realm, build, accountSecurityLevel, state->mutable_update()); + state->set_deleting(false); + } - state->mutable_update()->set_cfgrealmsid(realm.second.Id.Realm); - state->mutable_update()->set_flags(flag); - state->mutable_update()->set_name(realm.second.Name); - state->mutable_update()->set_cfgconfigsid(realm.second.GetConfigId()); - state->mutable_update()->set_cfglanguagesid(1); + for (auto const& [id, _] : _removedRealms) + { + if (id.GetSubRegionAddress() != subRegion) + continue; - state->set_deleting(false); + JSON::RealmList::RealmListUpdatePart* state = realmList.add_updates(); + state->set_wowrealmaddress(id.GetAddress()); + state->set_deleting(true); } } std::string json = "JSONRealmListUpdates:" + JSON::Serialize(realmList); - - uLong compressedLength = compressBound(uLong(json.length())); std::vector<uint8> compressed; - compressed.resize(4 + compressedLength); - *reinterpret_cast<uint32*>(compressed.data()) = uint32(json.length() + 1); - - compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), uLong(json.length() + 1)); - - compressed.resize(compressedLength + 4); - + CompressJson(json, &compressed); return compressed; } uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, - LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const + LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, AccountTypes accountSecurityLevel, + bgs::protocol::game_utilities::v1::ClientResponse* response) const { - std::shared_lock<std::shared_mutex> lock(_realmsMutex); - if (Realm const* realm = GetRealm(Battlenet::RealmHandle(realmAddress))) + if (std::shared_ptr<Realm const> realm = GetRealm(realmAddress)) { - if (realm->Flags & REALM_FLAG_OFFLINE || realm->Build != build) + if (realm->PopulationLevel == RealmPopulationState::Offline || realm->Build != build || accountSecurityLevel < realm->AllowedSecurityLevel) return ERROR_USER_SERVER_NOT_PERMITTED_ON_REALM; JSON::RealmList::RealmListServerIPAddresses serverAddresses; @@ -388,32 +378,27 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip:: address->set_ip(realm->GetAddressForClient(clientAddress).to_string()); address->set_port(realm->Port); - lock.unlock(); - std::string json = "JSONRealmListServerIPAddresses:" + JSON::Serialize(serverAddresses); - - uLong compressedLength = compressBound(uLong(json.length())); std::vector<uint8> compressed; - compressed.resize(4 + compressedLength); - *reinterpret_cast<uint32*>(compressed.data()) = uint32(json.length() + 1); - if (compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), uLong(json.length() + 1)) != Z_OK) + if (!CompressJson(json, &compressed)) return ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE; std::array<uint8, 32> serverSecret = Trinity::Crypto::GetRandomBytes<32>(); std::array<uint8, 64> keyData; auto keyDestItr = keyData.begin(); - keyDestItr = std::copy(clientSecret.begin(), clientSecret.end(), keyDestItr); - keyDestItr = std::copy(serverSecret.begin(), serverSecret.end(), keyDestItr); + keyDestItr = std::ranges::copy(clientSecret, keyDestItr).out; + keyDestItr = std::ranges::copy(serverSecret, keyDestItr).out; LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO); stmt->setBinary(0, keyData); stmt->setString(1, clientAddress.to_string()); - stmt->setUInt8(2, locale); - stmt->setString(3, os); - stmt->setInt16(4, timezoneOffset.count()); - stmt->setString(5, accountName); + stmt->setUInt32(2, build); + stmt->setUInt8(3, locale); + stmt->setString(4, os); + stmt->setInt16(5, timezoneOffset.count()); + stmt->setString(6, accountName); LoginDatabase.DirectExecute(stmt); bgs::protocol::Attribute* attribute = response->add_attribute(); @@ -422,11 +407,11 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip:: attribute = response->add_attribute(); attribute->set_name("Param_ServerAddresses"); - attribute->mutable_value()->set_blob_value(compressed.data(), compressedLength + 4); + attribute->mutable_value()->set_blob_value(compressed.data(), compressed.size()); attribute = response->add_attribute(); attribute->set_name("Param_JoinSecret"); - attribute->mutable_value()->set_blob_value(serverSecret.data(), 32); + attribute->mutable_value()->set_blob_value(serverSecret.data(), serverSecret.size()); return ERROR_OK; } diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index 7e85cbcfd38..3cbbb97c316 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -20,6 +20,7 @@ #include "Define.h" #include "Duration.h" +#include "Optional.h" #include "Realm.h" #include <array> #include <map> @@ -47,32 +48,39 @@ class GetAllValuesForAttributeResponse; namespace JSON::RealmList { -class RealmListUpdates; +class RealmEntry; } /// Storage object for the list of realms on the server class TC_SHARED_API RealmList { public: - typedef std::map<Battlenet::RealmHandle, Realm> RealmMap; + typedef std::map<Battlenet::RealmHandle, std::shared_ptr<Realm>> RealmMap; static RealmList* Instance(); + RealmList(RealmList const&) = delete; + RealmList(RealmList&&) = delete; + RealmList& operator=(RealmList const&) = delete; + RealmList& operator=(RealmList&&) = delete; + ~RealmList(); void Initialize(Trinity::Asio::IoContext& ioContext, uint32 updateInterval); void Close(); - Realm const* GetRealm(Battlenet::RealmHandle const& id) const; - bool GetRealmNames(Battlenet::RealmHandle const& id, std::string* name, std::string* normalizedName) const; + std::shared_ptr<Realm const> GetRealm(Battlenet::RealmHandle const& id) const; + Battlenet::RealmHandle GetCurrentRealmId() const; + void SetCurrentRealmId(Battlenet::RealmHandle const& id); + std::shared_ptr<Realm const> GetCurrentRealm() const; RealmBuildInfo const* GetBuildInfo(uint32 build) const; uint32 GetMinorMajorBugfixVersionForBuild(uint32 build) const; void WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse* response) const; - std::vector<uint8> GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const; - std::vector<uint8> GetRealmList(uint32 build, std::string const& subRegion) const; + std::vector<uint8> GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build, AccountTypes accountSecurityLevel) const; + std::vector<uint8> GetRealmList(uint32 build, AccountTypes accountSecurityLevel, std::string const& subRegion) const; uint32 JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, - LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, + LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, AccountTypes accountSecurityLevel, bgs::protocol::game_utilities::v1::ClientResponse* response) const; private: @@ -80,17 +88,20 @@ private: void LoadBuildInfo(); void UpdateRealms(); - void UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name, + static void UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name, boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, - uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population); + uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, RealmPopulationState population); + void FillRealmEntry(Realm const& realm, uint32 clientBuild, AccountTypes accountSecurityLevel, JSON::RealmList::RealmEntry* realmEntry) const; std::vector<RealmBuildInfo> _builds; mutable std::shared_mutex _realmsMutex; RealmMap _realms; + std::map<Battlenet::RealmHandle, std::string> _removedRealms; std::unordered_set<std::string> _subRegions; uint32 _updateInterval; std::unique_ptr<Trinity::Asio::DeadlineTimer> _updateTimer; std::unique_ptr<Trinity::Asio::Resolver> _resolver; + Optional<Battlenet::RealmHandle> _currentRealmId; }; #define sRealmList RealmList::Instance() |