aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-08-18 18:59:58 +0200
committerOvahlord <dreadkiller@gmx.de>2024-08-18 20:39:21 +0200
commit25ffdbc5ef0859aeaadfa132329a498e86827e68 (patch)
treed7df51da8cdc3e3df7c50e5058803f9324715ee4 /src/server/shared
parent0c98004896cb91ef2d22baa5569ff0e0d6cd15ee (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.h64
-rw-r--r--src/server/shared/Realm/RealmList.cpp341
-rw-r--r--src/server/shared/Realm/RealmList.h29
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()