TrinityCore
Loading...
Searching...
No Matches
WorldserverGameUtilitiesService.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
20#include "IpAddress.h"
21#include "Log.h"
22#include "MapUtils.h"
23#include "ProtobufJSON.h"
24#include "RealmList.h"
25#include "RealmList.pb.h"
26#include "Types.h"
27#include <zlib.h>
28
29namespace Battlenet::Services
30{
31namespace Shared
32{
33std::string_view GameUtilities::ParseParamName(std::string_view command)
34{
35 if (command.starts_with("Command_"sv))
36 {
37 size_t pos = command.rfind('_');
38 if (pos != std::string_view::npos)
39 command.remove_suffix(command.length() - pos);
40 }
41
42 return command;
43}
44
45Variant* GameUtilities::FindParamValue(std::vector<std::pair<std::string_view, Variant>>& params, std::string_view paramName)
46{
47 auto itr = std::ranges::find(params, paramName, Trinity::Containers::MapKey);
48 return itr != params.end() ? &itr->second : nullptr;
49}
50
52 std::vector<std::pair<std::string_view, Variant>>& params,
53 std::vector<std::pair<std::string_view, Variant>>& responseValues)
54{
55 auto command = std::ranges::find_if(params,
56 [](std::string_view paramName) { return paramName.starts_with("Command_"sv); },
58
59 if (command == params.end())
60 {
61 TC_LOG_ERROR("session.rpc", "{} sent ClientRequest with no command.", session->GetPlayerInfo());
63 }
64
65 switch (Trinity::HashFnv1a<>::GetHash(command->first))
66 {
67 case Trinity::HashFnv1a<>::GetHash("Command_RealmListRequest_v1"sv):
68 return GetRealmList(session, params, responseValues);
69 case Trinity::HashFnv1a<>::GetHash("Command_RealmJoinRequest_v1"sv):
70 return JoinRealm(session, params, responseValues);
71 default:
72 break;
73 }
74
75 TC_LOG_ERROR("session.rpc", "{} sent ClientRequest with unknown command {}.", session->GetPlayerInfo(), command->first);
77}
78
79uint32 GameUtilities::HandleGetAllValuesForAttribute(WorldSession const* session, std::string_view command, std::vector<Variant>& responseValues)
80{
81 switch (Trinity::HashFnv1a<>::GetHash(command))
82 {
83 case Trinity::HashFnv1a<>::GetHash("Command_RealmListRequest_v1"sv):
84 for (std::string& subRegion : sRealmList->GetSubRegions())
85 responseValues.emplace_back(std::move(subRegion));
86 return ERROR_OK;
87 default:
88 break;
89 }
90
91 TC_LOG_ERROR("session.rpc", "{} sent GetAllValuesForAttributeRequest with unknown command {}.", session->GetPlayerInfo(), command);
93}
94
96 std::vector<std::pair<std::string_view, Variant>>& params,
97 std::vector<std::pair<std::string_view, Variant>>& responseValues)
98{
99 std::string subRegionId;
100 if (Variant const* subRegion = FindParamValue(params, "Command_RealmListRequest_v1"); subRegion && std::holds_alternative<std::string>(*subRegion))
101 subRegionId = std::get<std::string>(*subRegion);
102
103 std::vector<uint8> realmListJson = sRealmList->GetRealmList(session->GetClientBuild(), session->GetSecurity(), subRegionId);
104
105 if (realmListJson.empty())
107
108 ::JSON::RealmList::RealmCharacterCountList realmCharacterCounts;
109 for (auto const& [realmAddress, count] : session->GetRealmCharacterCounts())
110 {
111 ::JSON::RealmList::RealmCharacterCountEntry* countEntry = realmCharacterCounts.add_counts();
112 countEntry->set_wowrealmaddress(realmAddress);
113 countEntry->set_count(count);
114 }
115
116 std::string json = "JSONRealmCharacterCountList:" + ::JSON::Serialize(realmCharacterCounts);
117
118 uLongf compressedLength = compressBound(json.length());
119 std::vector<uint8> characterCountsJson(4 + compressedLength);
120 *reinterpret_cast<uint32*>(characterCountsJson.data()) = json.length() + 1;
121
122 if (compress(characterCountsJson.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), json.length() + 1) != Z_OK)
124
125 responseValues.emplace_back("Param_RealmList"sv, std::move(realmListJson));
126 responseValues.emplace_back("Param_CharacterCountList"sv, std::move(characterCountsJson));
127
128 return ERROR_OK;
129}
130
132 std::vector<std::pair<std::string_view, Variant>>& params,
133 std::vector<std::pair<std::string_view, Variant>>& responseValues)
134{
135 Variant const* realmAddress = FindParamValue(params, "Param_RealmAddress");
136 if (!realmAddress || !std::holds_alternative<uint64>(*realmAddress))
138
139 RealmJoinResult result = sRealmList->JoinRealm(std::get<uint64>(*realmAddress), session->GetClientBuild(), session->GetClientBuildVariant(),
140 Trinity::Net::make_address(session->GetRemoteAddress()), session->GetRealmListSecret(), session->GetSessionDbcLocale(),
141 session->GetOS(), session->GetTimezoneOffset(), session->GetAccountName(), session->GetSecurity());
142
143 if (result.Result == ERROR_OK)
144 {
145 responseValues.emplace_back("Param_RealmJoinTicket"sv, std::move(result.JoinTicket));
146 responseValues.emplace_back("Param_ServerAddresses"sv, std::move(result.ServerAddresses));
147 responseValues.emplace_back("Param_JoinSecret"sv, std::move(result.JoinSecret));
148 }
149
150 return result.Result;
151}
152}
153
154namespace V2
155{
156Battlenet::Services::Variant FromProto(bgs::protocol::v2::Variant const& from)
157{
158 switch (from.type_case())
159 {
160 case v2::Variant::kBoolValue:
161 return from.bool_value();
162 case v2::Variant::kIntValue:
163 return from.int_value();
164 case v2::Variant::kFloatValue:
165 return from.float_value();
166 case v2::Variant::kStringValue:
167 return from.string_value();
168 case v2::Variant::kBlobValue:
169 return Variant{ std::in_place_type<std::vector<uint8>>,
170 reinterpret_cast<uint8 const*>(from.blob_value().data()),
171 reinterpret_cast<uint8 const*>(from.blob_value().data()) + from.blob_value().size() };
172 case v2::Variant::kUintValue:
173 return from.uint_value();
174 default:
175 break;
176 }
177
178 return { };
179}
180
181void ToProto(Battlenet::Services::Variant const& from, bgs::protocol::v2::Variant* to)
182{
183 std::visit([to]<typename T>(T const& value)
184 {
185 if constexpr (std::is_same_v<T, bool>)
186 to->set_bool_value(value);
187 else if constexpr (std::is_same_v<T, int64>)
188 to->set_int_value(value);
189 else if constexpr (std::is_same_v<T, double>)
190 to->set_float_value(value);
191 else if constexpr (std::is_same_v<T, std::string>)
192 to->set_string_value(value);
193 else if constexpr (std::is_same_v<T, std::vector<uint8>>)
194 to->set_blob_value(value.data(), value.size());
195 else if constexpr (std::is_same_v<T, uint64>)
196 to->set_uint_value(value);
197 else
198 static_assert(Trinity::dependant_false_v<T>);
199 }, from);
200}
201
205
206uint32 GameUtilitiesService::HandleProcessTask(game_utilities::v2::client::ProcessTaskRequest const* request, game_utilities::v2::client::ProcessTaskResponse* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& /*continuation*/)
207{
208 std::vector<std::pair<std::string_view, Variant>> params;
209 std::vector<std::pair<std::string_view, Variant>> responseValues;
210
211 for (v2::Attribute const& attribute : request->attribute())
212 {
213 if (!attribute.has_name() || !attribute.has_value())
214 continue;
215
216 params.emplace_back(Shared::GameUtilities::ParseParamName(attribute.name()), FromProto(attribute.value()));
217 }
218
220
221 for (auto&& [name, value] : responseValues)
222 {
223 v2::Attribute* attr = response->add_result();
224 attr->set_name(name.data(), name.length());
225 ToProto(value, attr->mutable_value());
226 }
227
228 return result;
229}
230
231uint32 GameUtilitiesService::HandleGetAllValuesForAttribute(game_utilities::v2::client::GetAllValuesForAttributeRequest const* request, game_utilities::v2::client::GetAllValuesForAttributeResponse* response, std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
232{
233 std::vector<Variant> responseValues;
234
236
237 for (Variant& value : responseValues)
238 ToProto(value, response->add_attribute_value());
239
240 return result;
241}
242}
243}
@ ERROR_RPC_NOT_IMPLEMENTED
@ ERROR_RPC_MALFORMED_REQUEST
@ ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE
@ ERROR_UTIL_SERVER_UNKNOWN_REALM
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
std::unordered_set< uint32 > params[2]
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define sRealmList
Definition RealmList.h:95
static Variant * FindParamValue(std::vector< std::pair< std::string_view, Variant > > &params, std::string_view paramName)
static uint32 HandleClientRequest(Session *session, std::vector< std::pair< std::string_view, Variant > > &params, std::vector< std::pair< std::string_view, Variant > > &responseValues)
static std::string_view ParseParamName(std::string_view command)
static uint32 JoinRealm(Session const *session, std::vector< std::pair< std::string_view, Variant > > &params, std::vector< std::pair< std::string_view, Variant > > &responseValues)
static uint32 GetRealmList(Session const *session, std::vector< std::pair< std::string_view, Variant > > &params, std::vector< std::pair< std::string_view, Variant > > &responseValues)
static uint32 HandleGetAllValuesForAttribute(Session const *session, std::string_view command, std::vector< Variant > &responseValues)
uint32 HandleGetAllValuesForAttribute(game_utilities::v2::client::GetAllValuesForAttributeRequest const *request, game_utilities::v2::client::GetAllValuesForAttributeResponse *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
uint32 HandleProcessTask(game_utilities::v2::client::ProcessTaskRequest const *request, game_utilities::v2::client::ProcessTaskResponse *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
Player session in the World.
AccountTypes GetSecurity() const
std::array< uint8, 32 > const & GetRealmListSecret() const
Minutes GetTimezoneOffset() const
LocaleConstant GetSessionDbcLocale() const
std::string GetPlayerInfo() const
std::string const & GetOS() const
std::string const & GetAccountName() const
ClientBuild::VariantId const & GetClientBuildVariant() const
std::string const & GetRemoteAddress() const
uint32 GetClientBuild() const
std::unordered_map< uint32, uint8 > const & GetRealmCharacterCounts() const
Battlenet::Services::Variant FromProto(bgs::protocol::v2::Variant const &from)
void ToProto(Battlenet::Services::Variant const &from, bgs::protocol::v2::Variant *to)
std::variant< bool, int64, double, std::string, std::vector< uint8 >, uint64 > Variant
TC_SHARED_API std::string Serialize(google::protobuf::Message const &message)
constexpr auto MapKey
Definition MapUtils.h:72
std::vector< uint8 > JoinSecret
Definition RealmList.h:43
std::vector< uint8 > JoinTicket
Definition RealmList.h:41
std::vector< uint8 > ServerAddresses
Definition RealmList.h:42
static constexpr T GetHash(std::span< V, Extent > data) noexcept
Definition Hash.h:132